Initial checkin of gpgmepp sources
authorAndre Heinecke <aheinecke@intevation.de>
Mon, 22 Feb 2016 17:28:08 +0000 (18:28 +0100)
committerAndre Heinecke <aheinecke@intevation.de>
Mon, 22 Feb 2016 18:01:37 +0000 (19:01 +0100)
Based on git.kde.org/pim/gpgmepp rev. 0e3ebc02

* lang/cpp/src/assuanresult.cpp,
 lang/cpp/src/assuanresult.h,
 lang/cpp/src/callbacks.cpp,
 lang/cpp/src/callbacks.h,
 lang/cpp/src/configuration.cpp,
 lang/cpp/src/configuration.h,
 lang/cpp/src/context.cpp,
 lang/cpp/src/context.h,
 lang/cpp/src/context_glib.cpp,
 lang/cpp/src/context_p.h,
 lang/cpp/src/context_qt.cpp,
 lang/cpp/src/context_vanilla.cpp,
 lang/cpp/src/data.cpp,
 lang/cpp/src/data.h,
 lang/cpp/src/data_p.h,
 lang/cpp/src/decryptionresult.cpp,
 lang/cpp/src/decryptionresult.h,
 lang/cpp/src/defaultassuantransaction.cpp,
 lang/cpp/src/defaultassuantransaction.h,
 lang/cpp/src/editinteractor.cpp,
 lang/cpp/src/editinteractor.h,
 lang/cpp/src/encryptionresult.cpp,
 lang/cpp/src/encryptionresult.h,
 lang/cpp/src/engineinfo.cpp,
 lang/cpp/src/engineinfo.h,
 lang/cpp/src/error.h,
 lang/cpp/src/eventloopinteractor.cpp,
 lang/cpp/src/eventloopinteractor.h,
 lang/cpp/src/exception.cpp,
 lang/cpp/src/exception.h,
 lang/cpp/src/global.h,
 lang/cpp/src/gpgadduserideditinteractor.cpp,
 lang/cpp/src/gpgadduserideditinteractor.h,
 lang/cpp/src/gpgagentgetinfoassuantransaction.cpp,
 lang/cpp/src/gpgagentgetinfoassuantransaction.h,
 lang/cpp/src/gpgmefw.h,
 lang/cpp/src/gpgmepp_export.h,
 lang/cpp/src/gpgsetexpirytimeeditinteractor.cpp,
 lang/cpp/src/gpgsetexpirytimeeditinteractor.h,
 lang/cpp/src/gpgsetownertrusteditinteractor.cpp,
 lang/cpp/src/gpgsetownertrusteditinteractor.h,
 lang/cpp/src/gpgsignkeyeditinteractor.cpp,
 lang/cpp/src/gpgsignkeyeditinteractor.h,
 lang/cpp/src/importresult.cpp,
 lang/cpp/src/importresult.h,
 lang/cpp/src/key.cpp,
 lang/cpp/src/key.h,
 lang/cpp/src/keygenerationresult.cpp,
 lang/cpp/src/keygenerationresult.h,
 lang/cpp/src/keylistresult.cpp,
 lang/cpp/src/keylistresult.h,
 lang/cpp/src/notation.h,
 lang/cpp/src/result.h,
 lang/cpp/src/result_p.h,
 lang/cpp/src/scdgetinfoassuantransaction.cpp,
 lang/cpp/src/scdgetinfoassuantransaction.h,
 lang/cpp/src/signingresult.cpp,
 lang/cpp/src/signingresult.h,
 lang/cpp/src/trustitem.cpp,
 lang/cpp/src/trustitem.h,
 lang/cpp/src/util.h,
 lang/cpp/src/verificationresult.cpp,
 lang/cpp/src/verificationresult.h,
 lang/cpp/src/vfsmountresult.cpp,
 lang/cpp/src/vfsmountresult.h,
 lang/cpp/src/interfaces/assuantransaction.h,
 lang/cpp/src/interfaces/dataprovider.h,
 lang/cpp/src/interfaces/passphraseprovider.h,
 lang/cpp/src/interfaces/progressprovider.h: New.

69 files changed:
lang/cpp/src/assuanresult.cpp [new file with mode: 0644]
lang/cpp/src/assuanresult.h [new file with mode: 0644]
lang/cpp/src/callbacks.cpp [new file with mode: 0644]
lang/cpp/src/callbacks.h [new file with mode: 0644]
lang/cpp/src/configuration.cpp [new file with mode: 0644]
lang/cpp/src/configuration.h [new file with mode: 0644]
lang/cpp/src/context.cpp [new file with mode: 0644]
lang/cpp/src/context.h [new file with mode: 0644]
lang/cpp/src/context_glib.cpp [new file with mode: 0644]
lang/cpp/src/context_p.h [new file with mode: 0644]
lang/cpp/src/context_qt.cpp [new file with mode: 0644]
lang/cpp/src/context_vanilla.cpp [new file with mode: 0644]
lang/cpp/src/data.cpp [new file with mode: 0644]
lang/cpp/src/data.h [new file with mode: 0644]
lang/cpp/src/data_p.h [new file with mode: 0644]
lang/cpp/src/decryptionresult.cpp [new file with mode: 0644]
lang/cpp/src/decryptionresult.h [new file with mode: 0644]
lang/cpp/src/defaultassuantransaction.cpp [new file with mode: 0644]
lang/cpp/src/defaultassuantransaction.h [new file with mode: 0644]
lang/cpp/src/editinteractor.cpp [new file with mode: 0644]
lang/cpp/src/editinteractor.h [new file with mode: 0644]
lang/cpp/src/encryptionresult.cpp [new file with mode: 0644]
lang/cpp/src/encryptionresult.h [new file with mode: 0644]
lang/cpp/src/engineinfo.cpp [new file with mode: 0644]
lang/cpp/src/engineinfo.h [new file with mode: 0644]
lang/cpp/src/error.h [new file with mode: 0644]
lang/cpp/src/eventloopinteractor.cpp [new file with mode: 0644]
lang/cpp/src/eventloopinteractor.h [new file with mode: 0644]
lang/cpp/src/exception.cpp [new file with mode: 0644]
lang/cpp/src/exception.h [new file with mode: 0644]
lang/cpp/src/global.h [new file with mode: 0644]
lang/cpp/src/gpgadduserideditinteractor.cpp [new file with mode: 0644]
lang/cpp/src/gpgadduserideditinteractor.h [new file with mode: 0644]
lang/cpp/src/gpgagentgetinfoassuantransaction.cpp [new file with mode: 0644]
lang/cpp/src/gpgagentgetinfoassuantransaction.h [new file with mode: 0644]
lang/cpp/src/gpgmefw.h [new file with mode: 0644]
lang/cpp/src/gpgmepp_export.h [new file with mode: 0644]
lang/cpp/src/gpgsetexpirytimeeditinteractor.cpp [new file with mode: 0644]
lang/cpp/src/gpgsetexpirytimeeditinteractor.h [new file with mode: 0644]
lang/cpp/src/gpgsetownertrusteditinteractor.cpp [new file with mode: 0644]
lang/cpp/src/gpgsetownertrusteditinteractor.h [new file with mode: 0644]
lang/cpp/src/gpgsignkeyeditinteractor.cpp [new file with mode: 0644]
lang/cpp/src/gpgsignkeyeditinteractor.h [new file with mode: 0644]
lang/cpp/src/importresult.cpp [new file with mode: 0644]
lang/cpp/src/importresult.h [new file with mode: 0644]
lang/cpp/src/interfaces/assuantransaction.h [new file with mode: 0644]
lang/cpp/src/interfaces/dataprovider.h [new file with mode: 0644]
lang/cpp/src/interfaces/passphraseprovider.h [new file with mode: 0644]
lang/cpp/src/interfaces/progressprovider.h [new file with mode: 0644]
lang/cpp/src/key.cpp [new file with mode: 0644]
lang/cpp/src/key.h [new file with mode: 0644]
lang/cpp/src/keygenerationresult.cpp [new file with mode: 0644]
lang/cpp/src/keygenerationresult.h [new file with mode: 0644]
lang/cpp/src/keylistresult.cpp [new file with mode: 0644]
lang/cpp/src/keylistresult.h [new file with mode: 0644]
lang/cpp/src/notation.h [new file with mode: 0644]
lang/cpp/src/result.h [new file with mode: 0644]
lang/cpp/src/result_p.h [new file with mode: 0644]
lang/cpp/src/scdgetinfoassuantransaction.cpp [new file with mode: 0644]
lang/cpp/src/scdgetinfoassuantransaction.h [new file with mode: 0644]
lang/cpp/src/signingresult.cpp [new file with mode: 0644]
lang/cpp/src/signingresult.h [new file with mode: 0644]
lang/cpp/src/trustitem.cpp [new file with mode: 0644]
lang/cpp/src/trustitem.h [new file with mode: 0644]
lang/cpp/src/util.h [new file with mode: 0644]
lang/cpp/src/verificationresult.cpp [new file with mode: 0644]
lang/cpp/src/verificationresult.h [new file with mode: 0644]
lang/cpp/src/vfsmountresult.cpp [new file with mode: 0644]
lang/cpp/src/vfsmountresult.h [new file with mode: 0644]

diff --git a/lang/cpp/src/assuanresult.cpp b/lang/cpp/src/assuanresult.cpp
new file mode 100644 (file)
index 0000000..056aefb
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+  assuanresult.cpp - wraps a gpgme assuan result
+  Copyright (C) 2009 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include <assuanresult.h>
+#include "result_p.h"
+
+#include <gpgme.h>
+
+#include <istream>
+
+using namespace GpgME;
+
+#ifdef HAVE_GPGME_ASSUAN_ENGINE
+class AssuanResult::Private
+{
+public:
+    explicit Private(const gpgme_assuan_result_t r)
+    {
+        if (!r) {
+            return;
+        }
+        error = r->err;
+    }
+
+    gpgme_error_t error;
+};
+#endif
+
+AssuanResult::AssuanResult(gpgme_ctx_t ctx, int error)
+    : Result(error), d()
+{
+    init(ctx);
+}
+
+AssuanResult::AssuanResult(gpgme_ctx_t ctx, const Error &error)
+    : Result(error), d()
+{
+    init(ctx);
+}
+
+void AssuanResult::init(gpgme_ctx_t ctx)
+{
+    (void)ctx;
+#ifdef HAVE_GPGME_ASSUAN_ENGINE
+    if (!ctx) {
+        return;
+    }
+    gpgme_assuan_result_t res = gpgme_op_assuan_result(ctx);
+    if (!res) {
+        return;
+    }
+    d.reset(new Private(res));
+#endif
+}
+
+make_standard_stuff(AssuanResult)
+
+Error AssuanResult::assuanError() const
+{
+#ifdef HAVE_GPGME_ASSUAN_ENGINE
+    if (d) {
+        return Error(d->error);
+    }
+#endif
+    return Error();
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const AssuanResult &result)
+{
+    os << "GpgME::AssuanResult(";
+    if (!result.isNull()) {
+        os << "\n error:       " << result.error()
+           << "\n assuanError: " << result.assuanError()
+           << "\n";
+    }
+    return os << ')';
+}
diff --git a/lang/cpp/src/assuanresult.h b/lang/cpp/src/assuanresult.h
new file mode 100644 (file)
index 0000000..e1dc73a
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+  assuanresult.h - wraps a gpgme assuan result
+  Copyright (C) 2009 Klarälvdalens Datakonsult AB <info@kdab.com>
+  Author: Marc Mutz <marc@kdab.com>
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_ASSUANRESULT_H__
+#define __GPGMEPP_ASSUANRESULT_H__
+
+#include "gpgmefw.h"
+#include "result.h"
+#include "gpgmepp_export.h"
+
+#include <time.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <vector>
+#include <iosfwd>
+
+namespace GpgME
+{
+
+class Error;
+
+class GPGMEPP_EXPORT AssuanResult : public Result
+{
+public:
+    AssuanResult();
+    AssuanResult(gpgme_ctx_t ctx, int error);
+    AssuanResult(gpgme_ctx_t ctx, const Error &error);
+    explicit AssuanResult(const Error &err);
+
+    const AssuanResult &operator=(AssuanResult other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(AssuanResult &other)
+    {
+        Result::swap(other);
+        using std::swap;
+        swap(this->d, other.d);
+    }
+
+    bool isNull() const;
+
+    Error assuanError() const;
+
+    class Private;
+private:
+    void init(gpgme_ctx_t ctx);
+    boost::shared_ptr<Private> d;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const AssuanResult &result);
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(AssuanResult)
+
+#endif // __GPGMEPP_ASSUANRESULT_H__
diff --git a/lang/cpp/src/callbacks.cpp b/lang/cpp/src/callbacks.cpp
new file mode 100644 (file)
index 0000000..091975d
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+  callbacks.cpp - callback targets for internal use:
+  Copyright (C) 2003,2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include "callbacks.h"
+#include "util.h"
+
+#include <interfaces/progressprovider.h>
+#include <interfaces/passphraseprovider.h>
+#include <interfaces/dataprovider.h>
+#include <error.h>
+
+#include <gpgme.h>
+#include <gpg-error.h>
+
+#include <cassert>
+#include <cerrno>
+#include <cstring>
+#include <unistd.h>
+#include <stdlib.h>
+
+#ifndef HAVE_GPGME_SSIZE_T
+# define gpgme_ssize_t ssize_t
+#endif
+
+#ifndef HAVE_GPGME_OFF_T
+# define gpgme_off_t off_t
+#endif
+
+static inline gpgme_error_t make_err_from_syserror()
+{
+#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
+    return gpgme_error_from_syserror();
+#else
+    return gpg_error_from_syserror();
+#endif
+}
+
+using GpgME::ProgressProvider;
+using GpgME::PassphraseProvider;
+using GpgME::DataProvider;
+
+void progress_callback(void *opaque, const char *what,
+                       int type, int current, int total)
+{
+    ProgressProvider *provider = static_cast<ProgressProvider *>(opaque);
+    if (provider) {
+        provider->showProgress(what, type, current, total);
+    }
+}
+
+/* To avoid that a compiler optimizes certain memset calls away, these
+   macros may be used instead. */
+#define wipememory2(_ptr,_set,_len) do { \
+        volatile char *_vptr=(volatile char *)(_ptr); \
+        size_t _vlen=(_len); \
+        while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \
+    } while(0)
+#define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
+
+gpgme_error_t passphrase_callback(void *opaque, const char *uid_hint, const char *desc,
+                                  int prev_was_bad, int fd)
+{
+    PassphraseProvider *provider = static_cast<PassphraseProvider *>(opaque);
+    bool canceled = false;
+    gpgme_error_t err = GPG_ERR_NO_ERROR;
+    char *passphrase = provider ? provider->getPassphrase(uid_hint, desc, prev_was_bad, canceled) : 0 ;
+    if (canceled) {
+        err = make_error(GPG_ERR_CANCELED);
+    } else {
+        if (passphrase && *passphrase) {
+            size_t passphrase_length = std::strlen(passphrase);
+            size_t written = 0;
+            do {
+#ifdef HAVE_GPGME_IO_READWRITE
+                ssize_t now_written = gpgme_io_write(fd, passphrase + written, passphrase_length - written);
+#else
+                ssize_t now_written = write(fd, passphrase + written, passphrase_length - written);
+#endif
+                if (now_written < 0) {
+                    err = make_err_from_syserror();
+                    break;
+                }
+                written += now_written;
+            } while (written < passphrase_length);
+        }
+    }
+
+    if (passphrase && *passphrase) {
+        wipememory(passphrase, std::strlen(passphrase));
+    }
+    free(passphrase);
+#ifdef HAVE_GPGME_IO_READWRITE
+    gpgme_io_write(fd, "\n", 1);
+#else
+    write(fd, "\n", 1);
+#endif
+    return err;
+}
+
+static gpgme_ssize_t
+data_read_callback(void *opaque, void *buf, size_t buflen)
+{
+    DataProvider *provider = static_cast<DataProvider *>(opaque);
+    if (!provider) {
+#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
+        gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
+#else
+        gpg_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
+#endif
+        return -1;
+    }
+    return (gpgme_ssize_t)provider->read(buf, buflen);
+}
+
+static gpgme_ssize_t
+data_write_callback(void *opaque, const void *buf, size_t buflen)
+{
+    DataProvider *provider = static_cast<DataProvider *>(opaque);
+    if (!provider) {
+#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
+        gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
+#else
+        gpg_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
+#endif
+        return -1;
+    }
+    return (gpgme_ssize_t)provider->write(buf, buflen);
+}
+
+static gpgme_off_t
+data_seek_callback(void *opaque, gpgme_off_t offset, int whence)
+{
+    DataProvider *provider = static_cast<DataProvider *>(opaque);
+    if (!provider) {
+#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
+        gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
+#else
+        gpg_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
+#endif
+        return -1;
+    }
+    if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) {
+#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
+        gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
+#else
+        gpg_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
+#endif
+        return -1;
+    }
+    return provider->seek((off_t)offset, whence);
+}
+
+static void data_release_callback(void *opaque)
+{
+    DataProvider *provider = static_cast<DataProvider *>(opaque);
+    if (provider) {
+        provider->release();
+    }
+}
+
+const gpgme_data_cbs GpgME::data_provider_callbacks = {
+    &data_read_callback,
+    &data_write_callback,
+    &data_seek_callback,
+    &data_release_callback
+};
diff --git a/lang/cpp/src/callbacks.h b/lang/cpp/src/callbacks.h
new file mode 100644 (file)
index 0000000..4206637
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  callbacks.h - callback targets for internal use:
+  Copyright (C) 2003 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  This is an internal header file, subject to change without
+  notice. DO NOT USE.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_CALLBACKS_H__
+#define __GPGMEPP_CALLBACKS_H__
+
+#include <gpgme.h>
+
+extern "C" {
+
+    void progress_callback(void *opaque, const char *what,
+                           int type, int current, int total);
+    gpgme_error_t passphrase_callback(void *opaque, const char *uid_hint,
+                                      const char *desc, int prev_was_bad, int fd);
+}
+
+namespace GpgME
+{
+extern const gpgme_data_cbs data_provider_callbacks;
+extern const gpgme_edit_cb_t edit_interactor_callback;
+}
+
+#endif // __GPGME_CALLBACKS_H__
diff --git a/lang/cpp/src/configuration.cpp b/lang/cpp/src/configuration.cpp
new file mode 100644 (file)
index 0000000..fc19020
--- /dev/null
@@ -0,0 +1,1139 @@
+/*
+  configuration.cpp - wraps gpgme configuration components
+  Copyright (C) 2010 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include "configuration.h"
+#include "error.h"
+#include "util.h"
+
+#include <gpgme.h>
+
+#include <boost/foreach.hpp>
+
+#include <iterator>
+#include <algorithm>
+#include <ostream>
+#include <cstring>
+
+using namespace GpgME;
+using namespace GpgME::Configuration;
+
+typedef boost::shared_ptr< boost::remove_pointer<gpgme_conf_opt_t>::type > shared_gpgme_conf_opt_t;
+typedef boost::weak_ptr< boost::remove_pointer<gpgme_conf_opt_t>::type > weak_gpgme_conf_opt_t;
+
+typedef boost::shared_ptr< boost::remove_pointer<gpgme_conf_arg_t>::type > shared_gpgme_conf_arg_t;
+typedef boost::weak_ptr< boost::remove_pointer<gpgme_conf_arg_t>::type > weak_gpgme_conf_arg_t;
+
+typedef boost::shared_ptr< boost::remove_pointer<gpgme_ctx_t>::type > shared_gpgme_ctx_t;
+typedef boost::weak_ptr< boost::remove_pointer<gpgme_ctx_t>::type > weak_gpgme_ctx_t;
+
+namespace
+{
+struct nodelete {
+    template <typename T> void operator()(T *) {}
+};
+}
+
+// static
+std::vector<Component> Component::load(Error &returnedError)
+{
+
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    //
+    // 1. get a context:
+    //
+    gpgme_ctx_t ctx_native = 0;
+    if (const gpgme_error_t err = gpgme_new(&ctx_native)) {
+        returnedError = Error(err);
+        return std::vector<Component>();
+    }
+    const shared_gpgme_ctx_t ctx(ctx_native, &gpgme_release);
+
+    //
+    // 2. load the config:
+    //
+    gpgme_conf_comp_t conf_list_native = 0;
+    if (const gpgme_error_t err = gpgme_op_conf_load(ctx_native, &conf_list_native)) {
+        returnedError = Error(err);
+        return std::vector<Component>();
+    }
+    shared_gpgme_conf_comp_t head(conf_list_native, &gpgme_conf_release);
+
+    //
+    // 3. convert to vector<Component>:
+    //
+    std::vector<Component> result;
+
+    while (head) {
+        // secure 'head->next' (if any) against memleaks:
+        shared_gpgme_conf_comp_t next;
+        if (head->next) {
+            next.reset(head->next, &gpgme_conf_release);
+        }
+
+        // now prevent double-free of next.get() and following:
+        head->next = 0;
+
+        // now add a new Component to 'result' (may throw):
+        result.resize(result.size() + 1);
+        result.back().comp.swap(head);   // .comp = std::move( head );
+        head.swap(next);                 //  head = std::move( next );
+    }
+
+    return result;
+#else
+    returnedError = Error(make_error(GPG_ERR_NOT_SUPPORTED));
+    return std::vector<Component>();
+#endif
+}
+
+Error Component::save() const
+{
+
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull()) {
+        return Error(make_error(GPG_ERR_INV_ARG));
+    }
+
+    //
+    // 1. get a context:
+    //
+    gpgme_ctx_t ctx_native = 0;
+    if (const gpgme_error_t err = gpgme_new(&ctx_native)) {
+        return Error(err);
+    }
+    const shared_gpgme_ctx_t ctx(ctx_native, &gpgme_release);
+
+    //
+    // 2. save the config:
+    //
+    return Error(gpgme_op_conf_save(ctx.get(), comp.get()));
+#else
+    return Error(make_error(GPG_ERR_NOT_SUPPORTED));
+#endif
+}
+
+const char *Component::name() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return comp ? comp->name : 0 ;
+#else
+    return 0;
+#endif
+}
+
+const char *Component::description() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return comp ? comp->description : 0 ;
+#else
+    return 0;
+#endif
+}
+
+const char *Component::programName() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return comp ? comp->program_name : 0 ;
+#else
+    return 0;
+#endif
+}
+
+Option Component::option(unsigned int idx) const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    gpgme_conf_opt_t opt = 0;
+    if (comp) {
+        opt = comp->options;
+    }
+    while (opt && idx) {
+        opt = opt->next;
+        --idx;
+    }
+    if (opt) {
+        return Option(comp, opt);
+    } else {
+#endif
+        return Option();
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    }
+#endif
+}
+
+Option Component::option(const char *name) const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    gpgme_conf_opt_t opt = 0;
+    if (comp) {
+        opt = comp->options;
+    }
+    using namespace std; // for strcmp
+    while (opt && strcmp(name, opt->name) != 0) {
+        opt = opt->next;
+    }
+    if (opt) {
+        return Option(comp, opt);
+    } else {
+#endif
+        return Option();
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    }
+#endif
+}
+
+unsigned int Component::numOptions() const
+{
+    unsigned int result = 0;
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    for (gpgme_conf_opt_t opt = comp ? comp->options : 0 ; opt ; opt = opt->next) {
+        ++result;
+    }
+#endif
+    return result;
+}
+
+std::vector<Option> Component::options() const
+{
+    std::vector<Option> result;
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    for (gpgme_conf_opt_t opt = comp ? comp->options : 0 ; opt ; opt = opt->next) {
+        result.push_back(Option(comp, opt));
+    }
+#endif
+    return result;
+}
+
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+static gpgme_conf_arg_t mygpgme_conf_arg_copy(gpgme_conf_arg_t other, gpgme_conf_type_t type)
+{
+    gpgme_conf_arg_t result = 0, last = 0;
+    for (gpgme_conf_arg_t a = other ; a ; a = a->next) {
+        gpgme_conf_arg_t arg = 0;
+        const gpgme_error_t err
+            = gpgme_conf_arg_new(&arg, type,
+                                 a->no_arg                 ? 0 :
+                                 type == GPGME_CONF_STRING ? a->value.string :
+                                 /* else */                  static_cast<void *>(&a->value));
+        if (err) {
+            gpgme_conf_arg_release(result, type);
+            return 0;
+        }
+        assert(arg);
+        if (result) {
+            last->next = arg;
+        } else {
+            result = arg;
+        }
+        last = arg;
+    }
+    return result;
+}
+#endif
+
+Component Option::parent() const
+{
+    return Component(comp.lock());
+}
+
+unsigned int Option::flags() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return isNull() ? 0 : opt->flags;
+#else
+    return 0;
+#endif
+}
+
+Level Option::level() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return isNull() ? Internal : static_cast<Level>(opt->level) ;
+#else
+    return Internal;
+#endif
+}
+
+const char *Option::name() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return isNull() ? 0 : opt->name ;
+#else
+    return 0;
+#endif
+}
+
+const char *Option::description() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return isNull() ? 0 : opt->description ;
+#else
+    return 0;
+#endif
+}
+
+const char *Option::argumentName() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return isNull() ? 0 : opt->argname ;
+#else
+    return 0;
+#endif
+}
+
+Type Option::type() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return isNull() ? NoType : static_cast<Type>(opt->type) ;
+#else
+    return NoType;
+#endif
+}
+
+Type Option::alternateType() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return isNull() ? NoType : static_cast<Type>(opt->alt_type) ;
+#else
+    return NoType;
+#endif
+}
+
+#if 0
+static Option::Variant argument_to_variant(gpgme_conf_type_t type, bool list, gpgme_conf_arg_t arg)
+{
+    assert(arg);
+    switch (type) {
+    case GPGME_CONF_NONE:
+        if (list) {
+            // return the count (number of times set):
+            return arg->value.count;
+        } else {
+            return none;
+        }
+    case GPGME_CONF_INT32:
+        if (list) {
+            std::vector<int> result;
+            for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
+                result.push_back(a->value.int32);
+            }
+            return result;
+        } else {
+            return arg->value.int32;
+        }
+    case GPGME_CONF_UINT32:
+        if (list) {
+            std::vector<unsigned int> result;
+            for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
+                result.push_back(a->value.uint32);
+            }
+            return result;
+        } else {
+            return arg->value.uint32;
+        }
+    case GPGME_CONF_FILENAME:
+    case GPGME_CONF_LDAP_SERVER:
+    case GPGME_CONF_KEY_FPR:
+    case GPGME_CONF_PUB_KEY:
+    case GPGME_CONF_SEC_KEY:
+    case GPGME_CONF_ALIAS_LIST:
+    // these should not happen in alt_type, but fall through
+    case GPGME_CONF_STRING:
+        if (list) {
+            std::vector<const char *> result;
+            for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
+                result.push_back(a->value.string);
+            }
+            return result;
+        } else {
+            return arg->value.string;
+        }
+    }
+    assert(!"Option: unknown alt_type!");
+    return Option::Variant();
+}
+
+namespace
+{
+inline const void *to_void_star(const char *s)
+{
+    return s;
+}
+inline const void *to_void_star(const std::string &s)
+{
+    return s.c_str();
+}
+inline const void *to_void_star(const int &i)
+{
+    return &i;    // const-&: sic!
+}
+inline const void *to_void_star(const unsigned int &i)
+{
+    return &i;    // const-&: sic!
+}
+
+struct VariantToArgumentVisitor : boost::static_visitor<gpgme_conf_arg_t> {
+    static gpgme_conf_arg_t make_argument(gpgme_conf_type_t type, const void *value)
+    {
+        gpgme_conf_arg_t arg = 0;
+#ifdef HAVE_GPGME_CONF_ARG_NEW_WITH_CONST_VALUE
+        if (const gpgme_error_t err = gpgme_conf_arg_new(&arg, type, value)) {
+            return 0;
+        }
+#else
+        if (const gpgme_error_t err = gpgme_conf_arg_new(&arg, type, const_cast<void *>(value))) {
+            return 0;
+        }
+#endif
+        else {
+            return arg;
+        }
+    }
+
+    gpgme_conf_arg_t operator()(bool v) const
+    {
+        return v ? make_argument(0) : 0 ;
+    }
+
+    gpgme_conf_arg_t operator()(const char *s) const
+    {
+        return make_argument(s ? s : "");
+    }
+
+    gpgme_conf_arg_t operator()(const std::string &s) const
+    {
+        return operator()(s.c_str());
+    }
+
+    gpgme_conf_arg_t operator()(int i) const
+    {
+        return make_argument(&i);
+    }
+
+    gpgme_conf_arg_t operator()(unsigned int i) const
+    {
+        return make_argument(&i);
+    }
+
+    template <typename T>
+    gpgme_conf_arg_t operator()(const std::vector<T> &value) const
+    {
+        gpgme_conf_arg_t result = 0;
+        gpgme_conf_arg_t last = 0;
+        for (typename std::vector<T>::const_iterator it = value.begin(), end = value.end() ; it != end ; ++it) {
+            if (gpgme_conf_arg_t arg = make_argument(to_void_star(*it))) {
+                if (last) {
+                    last = last->next = arg;
+                } else {
+                    result = last = arg;
+                }
+            }
+        }
+        return result;
+    }
+
+};
+}
+
+static gpgme_conf_arg_t variant_to_argument(const Option::Variant &value)
+{
+    VariantToArgumentVisitor v;
+    return apply_visitor(v, value);
+}
+
+optional<Option::Variant> Option::defaultValue() const
+{
+    if (isNull()) {
+        return optional<Variant>();
+    } else {
+        return argument_to_variant(opt->alt_type, opt->flags & GPGME_CONF_LIST, opt->default_value);
+    }
+}
+#endif
+
+Argument Option::defaultValue() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull()) {
+        return Argument();
+    } else {
+        return Argument(comp.lock(), opt, opt->default_value, false);
+    }
+#else
+    return Argument();
+#endif
+}
+
+const char *Option::defaultDescription() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return isNull() ? 0 : opt->default_description ;
+#else
+    return 0;
+#endif
+}
+
+Argument Option::noArgumentValue() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull()) {
+        return Argument();
+    } else {
+        return Argument(comp.lock(), opt, opt->no_arg_value, false);
+    }
+#else
+    return Argument();
+#endif
+}
+
+const char *Option::noArgumentDescription() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return isNull() ? 0 : opt->no_arg_description ;
+#else
+    return 0;
+#endif
+}
+
+Argument Option::activeValue() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull()) {
+        return Argument();
+    } else {
+        return Argument(comp.lock(), opt, opt->value, false);
+    }
+#else
+    return Argument();
+#endif
+}
+
+Argument Option::currentValue() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull()) {
+        return Argument();
+    }
+    const gpgme_conf_arg_t arg =
+        opt->change_value ? opt->new_value ? opt->new_value : opt->default_value :
+        opt->value        ? opt->value :
+        /* else */          opt->default_value ;
+    return Argument(comp.lock(), opt, arg, false);
+#else
+    return Argument();
+#endif
+}
+
+Argument Option::newValue() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull()) {
+        return Argument();
+    } else {
+        return Argument(comp.lock(), opt, opt->new_value, false);
+    }
+#else
+    return Argument();
+#endif
+}
+
+bool Option::set() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull()) {
+        return false;
+    } else if (opt->change_value) {
+        return opt->new_value;
+    } else {
+        return opt->value;
+    }
+#else
+    return false;
+#endif
+}
+
+bool Option::dirty() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return !isNull() && opt->change_value ;
+#else
+    return false;
+#endif
+}
+
+Error Option::setNewValue(const Argument &argument)
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull()) {
+        return Error(make_error(GPG_ERR_INV_ARG));
+    } else if (argument.isNull()) {
+        return resetToDefaultValue();
+    } else if (const gpgme_conf_arg_t arg = mygpgme_conf_arg_copy(argument.arg, opt->alt_type)) {
+        return Error(gpgme_conf_opt_change(opt, 0, arg));
+    } else {
+        return Error(make_error(GPG_ERR_ENOMEM));
+    }
+#else
+    return Error(make_error(GPG_ERR_NOT_SUPPORTED));
+#endif
+}
+
+Error Option::resetToActiveValue()
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull()) {
+        return Error(make_error(GPG_ERR_INV_ARG));
+    } else {
+        return Error(gpgme_conf_opt_change(opt, 1, 0));
+    }
+#else
+    return Error(make_error(GPG_ERR_NOT_SUPPORTED));
+#endif
+}
+
+Error Option::resetToDefaultValue()
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull()) {
+        return Error(make_error(GPG_ERR_INV_ARG));
+    } else {
+        return Error(gpgme_conf_opt_change(opt, 0, 0));
+    }
+#else
+    return Error(make_error(GPG_ERR_NOT_SUPPORTED));
+#endif
+}
+
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+static gpgme_conf_arg_t make_argument(gpgme_conf_type_t type, const void *value)
+{
+    gpgme_conf_arg_t arg = 0;
+#ifdef HAVE_GPGME_CONF_ARG_NEW_WITH_CONST_VALUE
+    if (const gpgme_error_t err = gpgme_conf_arg_new(&arg, type, value)) {
+        return 0;
+    }
+#else
+    if (const gpgme_error_t err = gpgme_conf_arg_new(&arg, type, const_cast<void *>(value))) {
+        return 0;
+    }
+#endif
+    else {
+        return arg;
+    }
+}
+#endif
+
+Argument Option::createNoneArgument(bool set) const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull() || alternateType() != NoType) {
+        return Argument();
+    } else {
+        if (set) {
+            return createNoneListArgument(1);
+        } else {
+#endif
+            return Argument();
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+        }
+    }
+#endif
+}
+
+Argument Option::createStringArgument(const char *value) const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull() || alternateType() != StringType) {
+        return Argument();
+    } else {
+        return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value), true);
+    }
+#else
+    return Argument();
+#endif
+}
+
+Argument Option::createStringArgument(const std::string &value) const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull() || alternateType() != StringType) {
+        return Argument();
+    } else {
+        return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value.c_str()), true);
+    }
+#else
+    return Argument();
+#endif
+}
+
+Argument Option::createIntArgument(int value) const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull() || alternateType() != IntegerType) {
+        return Argument();
+    } else {
+        return Argument(comp.lock(), opt, make_argument(GPGME_CONF_INT32, &value), true);
+    }
+#else
+    return Argument();
+#endif
+}
+
+Argument Option::createUIntArgument(unsigned int value) const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull() || alternateType() != UnsignedIntegerType) {
+        return Argument();
+    } else {
+        return Argument(comp.lock(), opt, make_argument(GPGME_CONF_UINT32, &value), true);
+    }
+#else
+    return Argument();
+#endif
+}
+
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+namespace
+{
+const void *to_void_star(const char *s)
+{
+    return s;
+}
+const void *to_void_star(const std::string &s)
+{
+    return s.c_str();
+}
+const void *to_void_star(const int &i)
+{
+    return &i;    // const-&: sic!
+}
+const void *to_void_star(const unsigned int &i)
+{
+    return &i;    // const-&: sic!
+}
+
+template <typename T>
+gpgme_conf_arg_t make_argument(gpgme_conf_type_t type, const std::vector<T> &value)
+{
+    gpgme_conf_arg_t result = 0;
+    gpgme_conf_arg_t last = 0;
+    for (typename std::vector<T>::const_iterator it = value.begin(), end = value.end() ; it != end ; ++it) {
+        if (gpgme_conf_arg_t arg = make_argument(type, to_void_star(*it))) {
+            if (last) {
+                last = last->next = arg;
+            } else {
+                result = last = arg;
+            }
+        }
+    }
+    return result;
+}
+}
+#endif
+
+Argument Option::createNoneListArgument(unsigned int value) const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (value) {
+        return Argument(comp.lock(), opt, make_argument(GPGME_CONF_NONE, &value), true);
+    } else {
+#endif
+        return Argument();
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    }
+#endif
+}
+
+Argument Option::createStringListArgument(const std::vector<const char *> &value) const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value), true);
+#else
+    return Argument();
+#endif
+}
+
+Argument Option::createStringListArgument(const std::vector<std::string> &value) const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value), true);
+#else
+    return Argument();
+#endif
+}
+
+Argument Option::createIntListArgument(const std::vector<int> &value) const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return Argument(comp.lock(), opt, make_argument(GPGME_CONF_INT32, value), true);
+#else
+    return Argument();
+#endif
+}
+
+Argument Option::createUIntListArgument(const std::vector<unsigned int> &value) const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    return Argument(comp.lock(), opt, make_argument(GPGME_CONF_UINT32, value), true);
+#else
+    return Argument();
+#endif
+}
+
+Argument::Argument(const shared_gpgme_conf_comp_t &comp, gpgme_conf_opt_t opt, gpgme_conf_arg_t arg, bool owns)
+    : comp(comp),
+      opt(opt),
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+      arg(owns ? arg : mygpgme_conf_arg_copy(arg, opt ? opt->alt_type : GPGME_CONF_NONE))
+#else
+      arg(0)
+#endif
+{
+
+}
+
+#if 0
+Argument::Argument(const shared_gpgme_conf_comp_t &comp, gpgme_conf_opt_t opt, gpgme_conf_arg_t arg)
+    : comp(comp),
+      opt(opt),
+      arg(mygpgme_conf_arg_copy(arg, opt ? opt->alt_type : GPGME_CONF_NONE))
+{
+
+}
+#endif
+
+Argument::Argument(const Argument &other)
+    : comp(other.comp),
+      opt(other.opt),
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+      arg(mygpgme_conf_arg_copy(other.arg, opt ? opt->alt_type : GPGME_CONF_NONE))
+#else
+      arg(0)
+#endif
+{
+
+}
+
+Argument::~Argument()
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    gpgme_conf_arg_release(arg, opt ? opt->alt_type : GPGME_CONF_NONE);
+#endif
+}
+
+Option Argument::parent() const
+{
+    return Option(comp.lock(), opt);
+}
+
+bool Argument::boolValue() const
+{
+    return numberOfTimesSet();
+}
+
+unsigned int Argument::numElements() const
+{
+    if (isNull()) {
+        return 0;
+    }
+    unsigned int result = 0;
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
+        ++result;
+    }
+#endif
+    return result;
+}
+
+const char *Argument::stringValue(unsigned int idx) const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull() || opt->alt_type != GPGME_CONF_STRING) {
+        return 0;
+    }
+    gpgme_conf_arg_t a = arg;
+    while (a && idx) {
+        a = a->next;
+        --idx;
+    }
+    return a ? a->value.string : 0 ;
+#else
+    return 0;
+#endif
+}
+
+int Argument::intValue(unsigned int idx) const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull() || opt->alt_type != GPGME_CONF_INT32) {
+        return 0;
+    }
+    gpgme_conf_arg_t a = arg;
+    while (a && idx) {
+        a = a->next;
+        --idx;
+    }
+    return a ? a->value.int32 : 0 ;
+#else
+    return 0;
+#endif
+}
+
+unsigned int Argument::uintValue(unsigned int idx) const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull() || opt->alt_type != GPGME_CONF_UINT32) {
+        return 0;
+    }
+    gpgme_conf_arg_t a = arg;
+    while (a && idx) {
+        a = a->next;
+        --idx;
+    }
+    return a ? a->value.uint32 : 0 ;
+#else
+    return 0;
+#endif
+}
+
+unsigned int Argument::numberOfTimesSet() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull() || opt->alt_type != GPGME_CONF_NONE) {
+        return 0;
+    }
+    return arg->value.count;
+#else
+    return 0;
+#endif
+}
+
+std::vector<const char *> Argument::stringValues() const
+{
+    if (isNull() || opt->alt_type != GPGME_CONF_STRING) {
+        return std::vector<const char *>();
+    }
+    std::vector<const char *> result;
+    for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
+        result.push_back(a->value.string);
+    }
+    return result;
+}
+
+std::vector<int> Argument::intValues() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull() || opt->alt_type != GPGME_CONF_INT32) {
+        return std::vector<int>();
+    }
+#endif
+    std::vector<int> result;
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
+        result.push_back(a->value.int32);
+    }
+#endif
+    return result;
+}
+
+std::vector<unsigned int> Argument::uintValues() const
+{
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    if (isNull() || opt->alt_type != GPGME_CONF_UINT32) {
+        return std::vector<unsigned int>();
+    }
+#endif
+    std::vector<unsigned int> result;
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+    for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
+        result.push_back(a->value.uint32);
+    }
+#endif
+    return result;
+}
+
+std::ostream &Configuration::operator<<(std::ostream &os, Level level)
+{
+    switch (level) {
+    case Basic:     return os << "Basic";
+    case Advanced:  return os << "Advanced";
+    case Expert:    return os << "Expert";
+    case Invisible: return os << "Invisible";
+    case Internal:  return os << "Internal";
+    case NumLevels: ;
+    }
+    return os << "<unknown>";
+}
+
+std::ostream &Configuration::operator<<(std::ostream &os, Type type)
+{
+    switch (type) {
+    case NoType:              return os << "None";
+    case StringType:          return os << "String";
+    case IntegerType:         return os << "Integer";
+    case UnsignedIntegerType: return os << "UnsignedInteger";
+    case FilenameType:        return os << "Filename";
+    case LdapServerType:      return os << "LdapServer";
+    case KeyFingerprintType:  return os << "KeyFingerprint";
+    case PublicKeyType:       return os << "PublicKey";
+    case SecretKeyType:       return os << "SecretKey";
+    case AliasListType:       return os << "AliasList";
+    case MaxType: ;
+    }
+    return os << "<unknown>";
+}
+
+std::ostream &Configuration::operator<<(std::ostream &os, Flag f)
+{
+    unsigned int flags = f;
+    std::vector<const char *> s;
+    if (flags & Group) {
+        s.push_back("Group");
+    }
+    if (flags & Optional) {
+        s.push_back("Optional");
+    }
+    if (flags & List) {
+        s.push_back("List");
+    }
+    if (flags & Runtime) {
+        s.push_back("Runtime");
+    }
+    if (flags & Default) {
+        s.push_back("Default");
+    }
+    if (flags & DefaultDescription) {
+        s.push_back("DefaultDescription");
+    }
+    if (flags & NoArgumentDescription) {
+        s.push_back("NoArgumentDescription");
+    }
+    if (flags & NoChange) {
+        s.push_back("NoChange");
+    }
+    flags &= ~(Group | Optional | List | Runtime | Default | DefaultDescription | NoArgumentDescription | NoChange);
+    if (flags) {
+        s.push_back("other flags(");
+    }
+    std::copy(s.begin(), s.end(),
+              std::ostream_iterator<const char *>(os, "|"));
+    if (flags) {
+        os << flags << ')';
+    }
+    return os;
+}
+
+std::ostream &Configuration::operator<<(std::ostream &os, const Component &c)
+{
+    os << "Component["
+       << "\n  name       : " << protect(c.name())
+       << "\n  description: " << protect(c.description())
+       << "\n  programName: " << protect(c.programName())
+       << "\n  options    : \n";
+    const std::vector<Option> options = c.options();
+    std::copy(options.begin(), options.end(),
+              std::ostream_iterator<Option>(os, "\n"));
+    os << "\n]";
+    return os;
+}
+
+std::ostream &Configuration::operator<<(std::ostream &os, const Option &o)
+{
+    return os << "Option["
+           << "\n  name:       : " << protect(o.name())
+           << "\n  description : " << protect(o.description())
+           << "\n  argName     : " << protect(o.argumentName())
+           << "\n  flags       : " << static_cast<Flag>(o.flags())
+           << "\n  level       : " << o.level()
+           << "\n  type        : " << o.type()
+           << "\n  alt_type    : " << o.alternateType()
+           << "\n  default_val : " << o.defaultValue()
+           << "\n  default_desc: " << protect(o.defaultDescription())
+           << "\n  no_arg_value: " << o.noArgumentValue()
+           << "\n  no_arg_desc : " << protect(o.noArgumentDescription())
+           << "\n  active_value: " << o.activeValue()
+           << "\n  new_value   : " << o.newValue()
+           << "\n  --> cur_val : " << o.currentValue()
+           << "\n  set         : " << o.set()
+           << "\n  dirty       : " << o.dirty()
+           << "\n]"
+           ;
+}
+
+std::ostream &Configuration::operator<<(std::ostream &os, const Argument &a)
+{
+    const Option o = a.parent();
+    const bool list = o.flags() & List;
+    os << "Argument[";
+    if (a) {
+        switch (o.alternateType()) {
+        case NoType:
+            if (list) {
+                os << a.numberOfTimesSet() << 'x';
+            } else {
+                os << a.boolValue();
+            }
+            break;
+        default:
+        case StringType:
+            if (list) {
+                const std::vector<const char *> v = a.stringValues();
+                os << v.size() << ':';
+                // can't use std::copy + ostream_iterator here, since we need the protect() call
+                bool first = true;
+                BOOST_FOREACH(const char *s, v) {
+                    if (first) {
+                        first = false;
+                    } else {
+                        os << ',';
+                    }
+                    os << protect(s);
+                }
+            } else {
+                os << protect(a.stringValue());
+            }
+            break;
+        case IntegerType:
+            if (list) {
+                const std::vector<int> v = a.intValues();
+                os << v.size() << ':';
+                std::copy(v.begin(), v.end(),
+                          std::ostream_iterator<int>(os, ","));
+            } else {
+                os << a.intValue();
+            }
+            break;
+        case UnsignedIntegerType:
+            if (list) {
+                const std::vector<unsigned int> v = a.uintValues();
+                os << v.size() << ':';
+                std::copy(v.begin(), v.end(),
+                          std::ostream_iterator<unsigned int>(os, ","));
+            } else {
+                os << a.intValue();
+            }
+            break;
+        }
+    }
+    return os << ']';
+}
diff --git a/lang/cpp/src/configuration.h b/lang/cpp/src/configuration.h
new file mode 100644 (file)
index 0000000..e6e13db
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+  configuration.h - wraps gpgme configuration components
+  Copyright (C) 2010 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_CONFIGURATION_H__
+#define __GPGMEPP_CONFIGURATION_H__
+
+#include "global.h"
+
+#include "gpgmefw.h"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/type_traits/remove_pointer.hpp>
+#if 0
+#include <boost/variant.hpp>
+#include <boost/optional.hpp>
+#endif
+
+#include <iosfwd>
+#include <vector>
+#include <string>
+#include <algorithm>
+
+namespace GpgME
+{
+namespace Configuration
+{
+
+typedef boost::shared_ptr< boost::remove_pointer<gpgme_conf_comp_t>::type > shared_gpgme_conf_comp_t;
+typedef boost::weak_ptr< boost::remove_pointer<gpgme_conf_comp_t>::type > weak_gpgme_conf_comp_t;
+
+class Argument;
+class Option;
+class Component;
+
+enum Level {
+    Basic,
+    Advanced,
+    Expert,
+    Invisible,
+    Internal,
+
+    NumLevels
+};
+
+enum Type {
+    NoType,
+    StringType,
+    IntegerType,
+    UnsignedIntegerType,
+
+    FilenameType = 32,
+    LdapServerType,
+    KeyFingerprintType,
+    PublicKeyType,
+    SecretKeyType,
+    AliasListType,
+
+    MaxType
+};
+
+enum Flag {
+    Group    = (1 << 0),
+    Optional = (1 << 1),
+    List     = (1 << 2),
+    Runtime  = (1 << 3),
+    Default  = (1 << 4),
+    DefaultDescription = (1 << 5),
+    NoArgumentDescription = (1 << 6),
+    NoChange = (1 << 7),
+
+    LastFlag = NoChange
+};
+
+//
+// class Component
+//
+
+class GPGMEPP_EXPORT Component
+{
+public:
+    Component() : comp() {}
+    explicit Component(const shared_gpgme_conf_comp_t &comp)
+        : comp(comp) {}
+
+    // copy ctor is ok
+
+    const Component &operator=(const Component &other)
+    {
+        if (this != &other) {
+            Component(other).swap(*this);
+        }
+        return *this;
+    }
+
+    void swap(Component &other)
+    {
+        using std::swap;
+        swap(this->comp, other.comp);
+    }
+
+    bool isNull() const
+    {
+        return !comp;
+    }
+
+    static std::vector<Component> load(Error &err);
+    Error save() const;
+
+    const char *name() const;
+    const char *description() const;
+    const char *programName() const;
+
+    Option option(unsigned int index) const;
+    Option option(const char *name) const;
+
+    unsigned int numOptions() const;
+
+    std::vector<Option> options() const;
+
+    GPGMEPP_MAKE_SAFE_BOOL_OPERATOR(!isNull())
+private:
+    shared_gpgme_conf_comp_t comp;
+};
+
+//
+// class Option
+//
+
+class GPGMEPP_EXPORT Option
+{
+public:
+    Option() : comp(), opt(0) {}
+    Option(const shared_gpgme_conf_comp_t &comp, gpgme_conf_opt_t opt)
+        : comp(comp), opt(opt) {}
+
+    const Option &operator=(const Option &other)
+    {
+        if (this != &other) {
+            Option(other).swap(*this);
+        }
+        return *this;
+    }
+
+    void swap(Option &other)
+    {
+        using std::swap;
+        swap(this->comp, other.comp);
+        swap(this->opt,  other.opt);
+    }
+
+    bool isNull() const
+    {
+        return comp.expired() || !opt;
+    }
+
+    Component parent() const;
+
+    unsigned int flags() const;
+
+    Level level() const;
+
+    const char *name() const;
+    const char *description() const;
+    const char *argumentName() const;
+
+    Type type() const;
+    Type alternateType() const;
+
+    Argument defaultValue() const;
+    const char *defaultDescription() const;
+
+    Argument noArgumentValue() const;
+    const char *noArgumentDescription() const;
+
+    /*! The value that is in the config file (or null, if it's not set). */
+    Argument activeValue() const;
+    /*! The value that is in this object, ie. either activeValue(), newValue(), or defaultValue() */
+    Argument currentValue() const;
+
+    Argument newValue() const;
+    bool set() const;
+    bool dirty() const;
+
+    Error setNewValue(const Argument &argument);
+    Error resetToDefaultValue();
+    Error resetToActiveValue();
+
+    Argument createNoneArgument(bool set) const;
+    Argument createStringArgument(const char *value) const;
+    Argument createStringArgument(const std::string &value) const;
+    Argument createIntArgument(int value) const;
+    Argument createUIntArgument(unsigned int value) const;
+
+    Argument createNoneListArgument(unsigned int count) const;
+    Argument createStringListArgument(const std::vector<const char *> &value) const;
+    Argument createStringListArgument(const std::vector<std::string> &value) const;
+    Argument createIntListArgument(const std::vector<int> &values) const;
+    Argument createUIntListArgument(const std::vector<unsigned int> &values) const;
+
+    GPGMEPP_MAKE_SAFE_BOOL_OPERATOR(!isNull())
+private:
+    weak_gpgme_conf_comp_t  comp;
+    gpgme_conf_opt_t opt;
+};
+
+//
+// class Argument
+//
+
+class GPGMEPP_EXPORT Argument
+{
+    friend class ::GpgME::Configuration::Option;
+    Argument(const shared_gpgme_conf_comp_t &comp, gpgme_conf_opt_t opt, gpgme_conf_arg_t arg, bool owns);
+public:
+    Argument() : comp(), opt(0), arg(0) {}
+    //Argument( const shared_gpgme_conf_comp_t & comp, gpgme_conf_opt_t opt, gpgme_conf_arg_t arg );
+    Argument(const Argument &other);
+    ~Argument();
+
+    const Argument &operator=(const Argument &other)
+    {
+        if (this != &other) {
+            Argument(other).swap(*this);
+        }
+        return *this;
+    }
+
+    void swap(Argument &other)
+    {
+        using std::swap;
+        swap(this->comp, other.comp);
+        swap(this->opt,  other.opt);
+        swap(this->arg,  other.arg);
+    }
+
+    bool isNull() const
+    {
+        return comp.expired() || !opt || !arg;
+    }
+
+    Option parent() const;
+
+    unsigned int numElements() const;
+
+    bool boolValue() const;
+    const char *stringValue(unsigned int index = 0) const;
+    int          intValue(unsigned int index = 0) const;
+    unsigned int uintValue(unsigned int index = 0) const;
+
+    unsigned int numberOfTimesSet() const;
+    std::vector<const char *> stringValues() const;
+    std::vector<int>          intValues() const;
+    std::vector<unsigned int> uintValues() const;
+
+    GPGMEPP_MAKE_SAFE_BOOL_OPERATOR(!isNull())
+private:
+    weak_gpgme_conf_comp_t comp;
+    gpgme_conf_opt_t opt;
+    gpgme_conf_arg_t arg;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Level level);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Type type);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Flag flag);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Component &component);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Option &option);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Argument &argument);
+
+} // namespace Configuration
+} // namespace GpgME
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Configuration::Component)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Configuration::Option)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Configuration::Argument)
+
+#endif // __GPGMEPP_CONFIGURATION_H__
diff --git a/lang/cpp/src/context.cpp b/lang/cpp/src/context.cpp
new file mode 100644 (file)
index 0000000..ab633d7
--- /dev/null
@@ -0,0 +1,1707 @@
+/*
+  context.cpp - wraps a gpgme key context
+  Copyright (C) 2003, 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "config-gpgme++.h"
+
+#include <context.h>
+#include <eventloopinteractor.h>
+#include <trustitem.h>
+#include <assuanresult.h>
+#include <keylistresult.h>
+#include <keygenerationresult.h>
+#include <importresult.h>
+#include <decryptionresult.h>
+#include <verificationresult.h>
+#include <signingresult.h>
+#include <encryptionresult.h>
+#include <engineinfo.h>
+#include <editinteractor.h>
+#include <vfsmountresult.h>
+
+#include <interfaces/assuantransaction.h>
+#include <defaultassuantransaction.h>
+
+#include "callbacks.h"
+#include "data_p.h"
+#include "context_p.h"
+#include "util.h"
+
+#include <gpgme.h>
+
+#include <boost/scoped_array.hpp>
+
+#include <istream>
+#ifndef NDEBUG
+#include <iostream>
+using std::cerr;
+using std::endl;
+#endif
+
+#include <cassert>
+
+#include <qglobal.h>
+
+namespace GpgME
+{
+
+static inline unsigned int xtoi_1(const char *str)
+{
+    const unsigned int ch = *str;
+    const unsigned int result =
+        ch <= '9' ? ch - '0' :
+        ch <= 'F' ? ch - 'A' + 10 :
+        /* else */  ch - 'a' + 10 ;
+    return result < 16 ? result : 0 ;
+}
+static inline int xtoi_2(const char *str)
+{
+    return xtoi_1(str) * 16U + xtoi_1(str + 1);
+}
+
+#ifdef HAVE_GPGME_ASSUAN_ENGINE
+static void percent_unescape(std::string &s, bool plus2space)
+{
+    std::string::iterator src = s.begin(), dest = s.begin(), end = s.end();
+    while (src != end) {
+        if (*src == '%' && end - src > 2) {
+            *dest++ = xtoi_2(&*++src);
+            src += 2;
+        } else if (*src == '+' && plus2space) {
+            *dest++ = ' ';
+            ++src;
+        } else {
+            *dest++ = *src++;
+        }
+    }
+    s.erase(dest, end);
+}
+#endif
+
+void initializeLibrary()
+{
+    gpgme_check_version(0);
+}
+
+Error initializeLibrary(int)
+{
+    if (gpgme_check_version(GPGME_VERSION)) {
+        return Error();
+    } else {
+        return Error::fromCode(GPG_ERR_USER_1);
+    }
+}
+
+static void format_error(gpgme_error_t err, std::string &str)
+{
+    char buffer[ 1024 ];
+    gpgme_strerror_r(err, buffer, sizeof buffer);
+    buffer[ sizeof buffer - 1 ] = '\0';
+    str = buffer;
+}
+
+const char *Error::source() const
+{
+    return gpgme_strsource((gpgme_error_t)mErr);
+}
+
+const char *Error::asString() const
+{
+    if (mMessage.empty()) {
+        format_error(static_cast<gpgme_error_t>(mErr), mMessage);
+    }
+    return mMessage.c_str();
+}
+
+int Error::code() const
+{
+    return gpgme_err_code(mErr);
+}
+
+int Error::sourceID() const
+{
+    return gpgme_err_source(mErr);
+}
+
+bool Error::isCanceled() const
+{
+    return code() == GPG_ERR_CANCELED;
+}
+
+int Error::toErrno() const
+{
+//#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
+    return gpgme_err_code_to_errno(static_cast<gpgme_err_code_t>(code()));
+//#else
+//    return gpg_err_code_to_errno( static_cast<gpg_err_code_t>( code() ) );
+//#endif
+}
+
+// static
+bool Error::hasSystemError()
+{
+#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
+    return gpgme_err_code_from_syserror() == GPG_ERR_MISSING_ERRNO ;
+#else
+    return gpg_err_code_from_syserror() == GPG_ERR_MISSING_ERRNO ;
+#endif
+}
+
+// static
+void Error::setSystemError(gpg_err_code_t err)
+{
+    setErrno(gpgme_err_code_to_errno(err));
+}
+
+// static
+void Error::setErrno(int err)
+{
+#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
+    gpgme_err_set_errno(err);
+#else
+    gpg_err_set_errno(err);
+#endif
+}
+
+// static
+Error Error::fromSystemError(unsigned int src)
+{
+#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
+    return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), gpgme_err_code_from_syserror()));
+#else
+    return Error(gpg_err_make(static_cast<gpg_err_source_t>(src), gpg_err_code_from_syserror()));
+#endif
+}
+
+// static
+Error Error::fromErrno(int err, unsigned int src)
+{
+//#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
+    return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), gpgme_err_code_from_errno(err)));
+//#else
+//    return Error( gpg_err_make( static_cast<gpg_err_source_t>( src ), gpg_err_from_from_errno( err ) ) );
+//#endif
+}
+
+// static
+Error Error::fromCode(unsigned int err, unsigned int src)
+{
+//#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
+    return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), static_cast<gpgme_err_code_t>(err)));
+//#else
+//    return Error( gpg_err_make( static_cast<gpg_err_source_t>( src ), static_cast<gpgme_err_code_t>( err ) ) );
+//#endif
+}
+
+std::ostream &operator<<(std::ostream &os, const Error &err)
+{
+    return os << "GpgME::Error(" << err.encodedError() << " (" << err.asString() << "))";
+}
+
+Context::Context(gpgme_ctx_t ctx) : d(new Private(ctx))
+{
+}
+
+Context::~Context()
+{
+    delete d;
+}
+
+Context *Context::createForProtocol(Protocol proto)
+{
+    gpgme_ctx_t ctx = 0;
+    if (gpgme_new(&ctx) != 0) {
+        return 0;
+    }
+
+    switch (proto) {
+    case OpenPGP:
+        if (gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP) != 0) {
+            gpgme_release(ctx);
+            return 0;
+        }
+        break;
+    case CMS:
+        if (gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS) != 0) {
+            gpgme_release(ctx);
+            return 0;
+        }
+        break;
+    default:
+        return 0;
+    }
+
+    return new Context(ctx);
+}
+
+std::auto_ptr<Context> Context::createForEngine(Engine eng, Error *error)
+{
+    gpgme_ctx_t ctx = 0;
+    if (const gpgme_error_t err = gpgme_new(&ctx)) {
+        if (error) {
+            *error = Error(err);
+        }
+        return std::auto_ptr<Context>();
+    }
+
+    switch (eng) {
+    case AssuanEngine:
+#ifdef HAVE_GPGME_ASSUAN_ENGINE
+        if (const gpgme_error_t err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_ASSUAN)) {
+            gpgme_release(ctx);
+            if (error) {
+                *error = Error(err);
+            }
+            return std::auto_ptr<Context>();
+        }
+        break;
+#else
+        if (error) {
+            *error = Error::fromCode(GPG_ERR_NOT_SUPPORTED);
+        }
+        return std::auto_ptr<Context>();
+#endif
+    case G13Engine:
+#ifdef HAVE_GPGME_G13_VFS
+        if (const gpgme_error_t err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_G13)) {
+            gpgme_release(ctx);
+            if (error) {
+                *error = Error(err);
+            }
+            return std::auto_ptr<Context>();
+        }
+        break;
+#else
+        if (error) {
+            *error = Error::fromCode(GPG_ERR_NOT_SUPPORTED);
+        }
+        return std::auto_ptr<Context>();
+#endif
+    default:
+        if (error) {
+            *error = Error::fromCode(GPG_ERR_INV_ARG);
+        }
+        return std::auto_ptr<Context>();
+    }
+
+    if (error) {
+        *error = Error();
+    }
+
+    return std::auto_ptr<Context>(new Context(ctx));
+}
+
+//
+//
+// Context::Private
+//
+//
+
+Context::Private::Private(gpgme_ctx_t c)
+    : ctx(c),
+      iocbs(0),
+      lastop(None),
+      lasterr(GPG_ERR_NO_ERROR),
+      lastAssuanInquireData(Data::null),
+      lastAssuanTransaction(),
+      lastEditInteractor(),
+      lastCardEditInteractor()
+{
+
+}
+
+Context::Private::~Private()
+{
+    if (ctx) {
+        gpgme_release(ctx);
+    }
+    ctx = 0;
+    delete iocbs;
+}
+
+//
+//
+// Context attributes:
+//
+//
+
+Protocol Context::protocol() const
+{
+    gpgme_protocol_t p = gpgme_get_protocol(d->ctx);
+    switch (p) {
+    case GPGME_PROTOCOL_OpenPGP: return OpenPGP;
+    case GPGME_PROTOCOL_CMS:     return CMS;
+    default:                     return UnknownProtocol;
+    }
+}
+
+void Context::setArmor(bool useArmor)
+{
+    gpgme_set_armor(d->ctx, int(useArmor));
+}
+bool Context::armor() const
+{
+    return gpgme_get_armor(d->ctx);
+}
+
+void Context::setTextMode(bool useTextMode)
+{
+    gpgme_set_textmode(d->ctx, int(useTextMode));
+}
+bool Context::textMode() const
+{
+    return gpgme_get_textmode(d->ctx);
+}
+
+void Context::setOffline(bool useOfflineMode)
+{
+#ifdef HAVE_GPGME_CTX_OFFLINE
+    gpgme_set_offline(d->ctx, int(useOfflineMode));
+#else
+    Q_UNUSED(useOfflineMode);
+#endif
+}
+bool Context::offline() const
+{
+#ifdef HAVE_GPGME_CTX_OFFLINE
+    return gpgme_get_offline(d->ctx);
+#else
+    return false;
+#endif
+}
+
+void Context::setIncludeCertificates(int which)
+{
+    if (which == DefaultCertificates) {
+#ifdef HAVE_GPGME_INCLUDE_CERTS_DEFAULT
+        which = GPGME_INCLUDE_CERTS_DEFAULT;
+#else
+        which = 1;
+#endif
+    }
+    gpgme_set_include_certs(d->ctx, which);
+}
+
+int Context::includeCertificates() const
+{
+    return gpgme_get_include_certs(d->ctx);
+}
+
+void Context::setKeyListMode(unsigned int mode)
+{
+    gpgme_set_keylist_mode(d->ctx, add_to_gpgme_keylist_mode_t(0, mode));
+}
+
+void Context::addKeyListMode(unsigned int mode)
+{
+    const unsigned int cur = gpgme_get_keylist_mode(d->ctx);
+    gpgme_set_keylist_mode(d->ctx, add_to_gpgme_keylist_mode_t(cur, mode));
+}
+
+unsigned int Context::keyListMode() const
+{
+    return convert_from_gpgme_keylist_mode_t(gpgme_get_keylist_mode(d->ctx));
+}
+
+void Context::setProgressProvider(ProgressProvider *provider)
+{
+    gpgme_set_progress_cb(d->ctx, provider ? &progress_callback : 0, provider);
+}
+ProgressProvider *Context::progressProvider() const
+{
+    void *pp = 0;
+    gpgme_progress_cb_t pcb = &progress_callback;
+    gpgme_get_progress_cb(d->ctx, &pcb, &pp);
+    return static_cast<ProgressProvider *>(pp);
+}
+
+void Context::setPassphraseProvider(PassphraseProvider *provider)
+{
+    gpgme_set_passphrase_cb(d->ctx, provider ? &passphrase_callback : 0, provider);
+}
+
+PassphraseProvider *Context::passphraseProvider() const
+{
+    void *pp = 0;
+    gpgme_passphrase_cb_t pcb = &passphrase_callback;
+    gpgme_get_passphrase_cb(d->ctx, &pcb, &pp);
+    return static_cast<PassphraseProvider *>(pp);
+}
+
+void Context::setManagedByEventLoopInteractor(bool manage)
+{
+    if (!EventLoopInteractor::instance()) {
+#ifndef NDEBUG
+        cerr << "Context::setManagedByEventLoopInteractor(): "
+             "You must create an instance of EventLoopInteractor "
+             "before using anything that needs one." << endl;
+#endif
+        return;
+    }
+    if (manage) {
+        EventLoopInteractor::instance()->manage(this);
+    } else {
+        EventLoopInteractor::instance()->unmanage(this);
+    }
+}
+bool Context::managedByEventLoopInteractor() const
+{
+    return d->iocbs != 0;
+}
+
+void Context::installIOCallbacks(gpgme_io_cbs *iocbs)
+{
+    if (!iocbs) {
+        uninstallIOCallbacks();
+        return;
+    }
+    gpgme_set_io_cbs(d->ctx, iocbs);
+    delete d->iocbs; d->iocbs = iocbs;
+}
+
+void Context::uninstallIOCallbacks()
+{
+    static gpgme_io_cbs noiocbs = { 0, 0, 0, 0, 0 };
+    // io.add == 0 means disable io callbacks:
+    gpgme_set_io_cbs(d->ctx, &noiocbs);
+    delete d->iocbs; d->iocbs = 0;
+}
+
+Error Context::setLocale(int cat, const char *val)
+{
+    return Error(d->lasterr = gpgme_set_locale(d->ctx, cat, val));
+}
+
+EngineInfo Context::engineInfo() const
+{
+#ifdef HAVE_GPGME_CTX_GETSET_ENGINE_INFO
+    return EngineInfo(gpgme_ctx_get_engine_info(d->ctx));
+#else
+    return EngineInfo();
+#endif
+}
+
+Error Context::setEngineFileName(const char *filename)
+{
+#ifdef HAVE_GPGME_CTX_GETSET_ENGINE_INFO
+    const char *const home_dir = engineInfo().homeDirectory();
+    return Error(gpgme_ctx_set_engine_info(d->ctx, gpgme_get_protocol(d->ctx), filename, home_dir));
+#else
+    return Error::fromCode(GPG_ERR_NOT_IMPLEMENTED);
+#endif
+}
+
+Error Context::setEngineHomeDirectory(const char *home_dir)
+{
+#ifdef HAVE_GPGME_CTX_GETSET_ENGINE_INFO
+    const char *const filename = engineInfo().fileName();
+    return Error(gpgme_ctx_set_engine_info(d->ctx, gpgme_get_protocol(d->ctx), filename, home_dir));
+#else
+    return Error::fromCode(GPG_ERR_NOT_IMPLEMENTED);
+#endif
+}
+
+//
+//
+// Key Management
+//
+//
+
+Error Context::startKeyListing(const char *pattern, bool secretOnly)
+{
+    d->lastop = Private::KeyList;
+    return Error(d->lasterr = gpgme_op_keylist_start(d->ctx, pattern, int(secretOnly)));
+}
+
+Error Context::startKeyListing(const char *patterns[], bool secretOnly)
+{
+    d->lastop = Private::KeyList;
+#ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
+    if (!patterns || !patterns[0] || !patterns[1]) {
+        // max. one pattern -> use the non-ext version
+        return startKeyListing(patterns ? patterns[0] : 0, secretOnly);
+    }
+#endif
+    return Error(d->lasterr = gpgme_op_keylist_ext_start(d->ctx, patterns, int(secretOnly), 0));
+}
+
+Key Context::nextKey(GpgME::Error &e)
+{
+    d->lastop = Private::KeyList;
+    gpgme_key_t key;
+    e = Error(d->lasterr = gpgme_op_keylist_next(d->ctx, &key));
+    return Key(key, false);
+}
+
+KeyListResult Context::endKeyListing()
+{
+    d->lasterr = gpgme_op_keylist_end(d->ctx);
+    return keyListResult();
+}
+
+KeyListResult Context::keyListResult() const
+{
+    return KeyListResult(d->ctx, Error(d->lasterr));
+}
+
+Key Context::key(const char *fingerprint, GpgME::Error &e , bool secret /*, bool forceUpdate*/)
+{
+    d->lastop = Private::KeyList;
+    gpgme_key_t key;
+    e = Error(d->lasterr = gpgme_get_key(d->ctx, fingerprint, &key, int(secret)/*, int( forceUpdate )*/));
+    return Key(key, false);
+}
+
+KeyGenerationResult Context::generateKey(const char *parameters, Data &pubKey)
+{
+    d->lastop = Private::KeyGen;
+    Data::Private *const dp = pubKey.impl();
+    d->lasterr = gpgme_op_genkey(d->ctx, parameters, dp ? dp->data : 0, 0);
+    return KeyGenerationResult(d->ctx, Error(d->lasterr));
+}
+
+Error Context::startKeyGeneration(const char *parameters, Data &pubKey)
+{
+    d->lastop = Private::KeyGen;
+    Data::Private *const dp = pubKey.impl();
+    return Error(d->lasterr = gpgme_op_genkey_start(d->ctx, parameters, dp ? dp->data : 0, 0));
+}
+
+KeyGenerationResult Context::keyGenerationResult() const
+{
+    if (d->lastop & Private::KeyGen) {
+        return KeyGenerationResult(d->ctx, Error(d->lasterr));
+    } else {
+        return KeyGenerationResult();
+    }
+}
+
+Error Context::exportPublicKeys(const char *pattern, Data &keyData)
+{
+    d->lastop = Private::Export;
+    Data::Private *const dp = keyData.impl();
+    return Error(d->lasterr = gpgme_op_export(d->ctx, pattern, 0, dp ? dp->data : 0));
+}
+
+Error Context::exportPublicKeys(const char *patterns[], Data &keyData)
+{
+    d->lastop = Private::Export;
+#ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
+    if (!patterns || !patterns[0] || !patterns[1]) {
+        // max. one pattern -> use the non-ext version
+        return exportPublicKeys(patterns ? patterns[0] : 0, keyData);
+    }
+#endif
+    Data::Private *const dp = keyData.impl();
+    return Error(d->lasterr = gpgme_op_export_ext(d->ctx, patterns, 0, dp ? dp->data : 0));
+}
+
+Error Context::startPublicKeyExport(const char *pattern, Data &keyData)
+{
+    d->lastop = Private::Export;
+    Data::Private *const dp = keyData.impl();
+    return Error(d->lasterr = gpgme_op_export_start(d->ctx, pattern, 0, dp ? dp->data : 0));
+}
+
+Error Context::startPublicKeyExport(const char *patterns[], Data &keyData)
+{
+    d->lastop = Private::Export;
+#ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
+    if (!patterns || !patterns[0] || !patterns[1]) {
+        // max. one pattern -> use the non-ext version
+        return startPublicKeyExport(patterns ? patterns[0] : 0, keyData);
+    }
+#endif
+    Data::Private *const dp = keyData.impl();
+    return Error(d->lasterr = gpgme_op_export_ext_start(d->ctx, patterns, 0, dp ? dp->data : 0));
+}
+
+ImportResult Context::importKeys(const Data &data)
+{
+    d->lastop = Private::Import;
+    const Data::Private *const dp = data.impl();
+    d->lasterr = gpgme_op_import(d->ctx, dp ? dp->data : 0);
+    return ImportResult(d->ctx, Error(d->lasterr));
+}
+
+ImportResult Context::importKeys(const std::vector<Key> &kk)
+{
+    d->lastop = Private::Import;
+    d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED);
+
+    bool shouldHaveResult = false;
+#ifdef HAVE_GPGME_OP_IMPORT_KEYS
+    const boost::scoped_array<gpgme_key_t> keys(new gpgme_key_t[ kk.size() + 1 ]);
+    gpgme_key_t *keys_it = &keys[0];
+    for (std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it) {
+        if (it->impl()) {
+            *keys_it++ = it->impl();
+        }
+    }
+    *keys_it++ = 0;
+    d->lasterr = gpgme_op_import_keys(d->ctx, keys.get());
+    shouldHaveResult = true;
+#endif
+    if ((gpgme_err_code(d->lasterr) == GPG_ERR_NOT_IMPLEMENTED ||
+            gpgme_err_code(d->lasterr) == GPG_ERR_NOT_SUPPORTED) &&
+            protocol() == CMS) {
+        // ok, try the workaround (export+import):
+        std::vector<const char *> fprs;
+        for (std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it) {
+            if (const char *fpr = it->primaryFingerprint()) {
+                if (*fpr) {
+                    fprs.push_back(fpr);
+                }
+            } else if (const char *keyid = it->keyID()) {
+                if (*keyid) {
+                    fprs.push_back(keyid);
+                }
+            }
+        }
+        fprs.push_back(0);
+        Data data;
+        Data::Private *const dp = data.impl();
+        const gpgme_keylist_mode_t oldMode = gpgme_get_keylist_mode(d->ctx);
+        gpgme_set_keylist_mode(d->ctx, GPGME_KEYLIST_MODE_EXTERN);
+        d->lasterr = gpgme_op_export_ext(d->ctx, &fprs[0], 0, dp ? dp->data : 0);
+        gpgme_set_keylist_mode(d->ctx, oldMode);
+        if (!d->lasterr) {
+            data.seek(0, SEEK_SET);
+            d->lasterr = gpgme_op_import(d->ctx, dp ? dp->data : 0);
+            shouldHaveResult = true;
+        }
+    }
+    if (shouldHaveResult) {
+        return ImportResult(d->ctx, Error(d->lasterr));
+    } else {
+        return ImportResult(Error(d->lasterr));
+    }
+}
+
+Error Context::startKeyImport(const Data &data)
+{
+    d->lastop = Private::Import;
+    const Data::Private *const dp = data.impl();
+    return Error(d->lasterr = gpgme_op_import_start(d->ctx, dp ? dp->data : 0));
+}
+
+Error Context::startKeyImport(const std::vector<Key> &kk)
+{
+    d->lastop = Private::Import;
+#ifdef HAVE_GPGME_OP_IMPORT_KEYS
+    const boost::scoped_array<gpgme_key_t> keys(new gpgme_key_t[ kk.size() + 1 ]);
+    gpgme_key_t *keys_it = &keys[0];
+    for (std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it) {
+        if (it->impl()) {
+            *keys_it++ = it->impl();
+        }
+    }
+    *keys_it++ = 0;
+    return Error(d->lasterr = gpgme_op_import_keys_start(d->ctx, keys.get()));
+#else
+    (void)kk;
+    return Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED));
+#endif
+}
+
+ImportResult Context::importResult() const
+{
+    if (d->lastop & Private::Import) {
+        return ImportResult(d->ctx, Error(d->lasterr));
+    } else {
+        return ImportResult();
+    }
+}
+
+Error Context::deleteKey(const Key &key, bool allowSecretKeyDeletion)
+{
+    d->lastop = Private::Delete;
+    return Error(d->lasterr = gpgme_op_delete(d->ctx, key.impl(), int(allowSecretKeyDeletion)));
+}
+
+Error Context::startKeyDeletion(const Key &key, bool allowSecretKeyDeletion)
+{
+    d->lastop = Private::Delete;
+    return Error(d->lasterr = gpgme_op_delete_start(d->ctx, key.impl(), int(allowSecretKeyDeletion)));
+}
+
+Error Context::passwd(const Key &key)
+{
+    d->lastop = Private::Passwd;
+#ifdef HAVE_GPGME_OP_PASSWD
+    return Error(d->lasterr = gpgme_op_passwd(d->ctx, key.impl(), 0U));
+#else
+    (void)key;
+    return Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED));
+#endif
+}
+
+Error Context::startPasswd(const Key &key)
+{
+    d->lastop = Private::Passwd;
+#ifdef HAVE_GPGME_OP_PASSWD
+    return Error(d->lasterr = gpgme_op_passwd_start(d->ctx, key.impl(), 0U));
+#else
+    (void)key;
+    return Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED));
+#endif
+}
+
+Error Context::edit(const Key &key, std::auto_ptr<EditInteractor> func, Data &data)
+{
+    d->lastop = Private::Edit;
+    d->lastEditInteractor = func;
+    Data::Private *const dp = data.impl();
+    return Error(d->lasterr = gpgme_op_edit(d->ctx, key.impl(),
+                                            d->lastEditInteractor.get() ? edit_interactor_callback : 0,
+                                            d->lastEditInteractor.get() ? d->lastEditInteractor->d : 0,
+                                            dp ? dp->data : 0));
+}
+
+Error Context::startEditing(const Key &key, std::auto_ptr<EditInteractor> func, Data &data)
+{
+    d->lastop = Private::Edit;
+    d->lastEditInteractor = func;
+    Data::Private *const dp = data.impl();
+    return Error(d->lasterr = gpgme_op_edit_start(d->ctx, key.impl(),
+                              d->lastEditInteractor.get() ? edit_interactor_callback : 0,
+                              d->lastEditInteractor.get() ? d->lastEditInteractor->d : 0,
+                              dp ? dp->data : 0));
+}
+
+EditInteractor *Context::lastEditInteractor() const
+{
+    return d->lastEditInteractor.get();
+}
+
+std::auto_ptr<EditInteractor> Context::takeLastEditInteractor()
+{
+    return d->lastEditInteractor;
+}
+
+Error Context::cardEdit(const Key &key, std::auto_ptr<EditInteractor> func, Data &data)
+{
+    d->lastop = Private::CardEdit;
+    d->lastCardEditInteractor = func;
+    Data::Private *const dp = data.impl();
+    return Error(d->lasterr = gpgme_op_card_edit(d->ctx, key.impl(),
+                              d->lastCardEditInteractor.get() ? edit_interactor_callback : 0,
+                              d->lastCardEditInteractor.get() ? d->lastCardEditInteractor->d : 0,
+                              dp ? dp->data : 0));
+}
+
+Error Context::startCardEditing(const Key &key, std::auto_ptr<EditInteractor> func, Data &data)
+{
+    d->lastop = Private::CardEdit;
+    d->lastCardEditInteractor = func;
+    Data::Private *const dp = data.impl();
+    return Error(d->lasterr = gpgme_op_card_edit_start(d->ctx, key.impl(),
+                              d->lastCardEditInteractor.get() ? edit_interactor_callback : 0,
+                              d->lastCardEditInteractor.get() ? d->lastCardEditInteractor->d : 0,
+                              dp ? dp->data : 0));
+}
+
+EditInteractor *Context::lastCardEditInteractor() const
+{
+    return d->lastCardEditInteractor.get();
+}
+
+std::auto_ptr<EditInteractor> Context::takeLastCardEditInteractor()
+{
+    return d->lastCardEditInteractor;
+}
+
+Error Context::startTrustItemListing(const char *pattern, int maxLevel)
+{
+    d->lastop = Private::TrustList;
+    return Error(d->lasterr = gpgme_op_trustlist_start(d->ctx, pattern, maxLevel));
+}
+
+TrustItem Context::nextTrustItem(Error &e)
+{
+    gpgme_trust_item_t ti = 0;
+    e = Error(d->lasterr = gpgme_op_trustlist_next(d->ctx, &ti));
+    return TrustItem(ti);
+}
+
+Error Context::endTrustItemListing()
+{
+    return Error(d->lasterr = gpgme_op_trustlist_end(d->ctx));
+}
+
+#ifdef HAVE_GPGME_ASSUAN_ENGINE
+static gpgme_error_t assuan_transaction_data_callback(void *opaque, const void *data, size_t datalen)
+{
+    assert(opaque);
+    AssuanTransaction *t = static_cast<AssuanTransaction *>(opaque);
+    return t->data(static_cast<const char *>(data), datalen).encodedError();
+}
+
+static gpgme_error_t assuan_transaction_inquire_callback(void *opaque, const char *name, const char *args, gpgme_data_t *r_data)
+{
+    assert(opaque);
+    Context::Private *p = static_cast<Context::Private *>(opaque);
+    AssuanTransaction *t = p->lastAssuanTransaction.get();
+    assert(t);
+    Error err;
+    if (name) {
+        p->lastAssuanInquireData = t->inquire(name, args, err);
+    } else {
+        p->lastAssuanInquireData = Data::null;
+    }
+    if (!p->lastAssuanInquireData.isNull()) {
+        *r_data = p->lastAssuanInquireData.impl()->data;
+    }
+    return err.encodedError();
+}
+
+static gpgme_error_t assuan_transaction_status_callback(void *opaque, const char *status, const char *args)
+{
+    assert(opaque);
+    AssuanTransaction *t = static_cast<AssuanTransaction *>(opaque);
+    std::string a = args;
+    percent_unescape(a, true);   // ### why doesn't gpgme do this??
+    return t->status(status, a.c_str()).encodedError();
+}
+#endif
+
+AssuanResult Context::assuanTransact(const char *command)
+{
+    return assuanTransact(command, std::auto_ptr<AssuanTransaction>(new DefaultAssuanTransaction));
+}
+
+AssuanResult Context::assuanTransact(const char *command, std::auto_ptr<AssuanTransaction> transaction)
+{
+    d->lastop = Private::AssuanTransact;
+    d->lastAssuanTransaction = transaction;
+    if (!d->lastAssuanTransaction.get()) {
+        return AssuanResult(Error(d->lasterr = make_error(GPG_ERR_INV_ARG)));
+    }
+#ifdef HAVE_GPGME_ASSUAN_ENGINE
+    d->lasterr = gpgme_op_assuan_transact(d->ctx, command,
+                                          assuan_transaction_data_callback,
+                                          d->lastAssuanTransaction.get(),
+                                          assuan_transaction_inquire_callback,
+                                          d, // sic!
+                                          assuan_transaction_status_callback,
+                                          d->lastAssuanTransaction.get());
+#else
+    (void)command;
+    d->lasterr = make_error(GPG_ERR_NOT_SUPPORTED);
+#endif
+    return AssuanResult(d->ctx, d->lasterr);
+}
+
+Error Context::startAssuanTransaction(const char *command)
+{
+    return startAssuanTransaction(command, std::auto_ptr<AssuanTransaction>(new DefaultAssuanTransaction));
+}
+
+Error Context::startAssuanTransaction(const char *command, std::auto_ptr<AssuanTransaction> transaction)
+{
+    d->lastop = Private::AssuanTransact;
+    d->lastAssuanTransaction = transaction;
+    if (!d->lastAssuanTransaction.get()) {
+        return Error(d->lasterr = make_error(GPG_ERR_INV_ARG));
+    }
+#ifdef HAVE_GPGME_ASSUAN_ENGINE
+    return Error(d->lasterr = gpgme_op_assuan_transact_start(d->ctx, command,
+                              assuan_transaction_data_callback,
+                              d->lastAssuanTransaction.get(),
+                              assuan_transaction_inquire_callback,
+                              d, // sic!
+                              assuan_transaction_status_callback,
+                              d->lastAssuanTransaction.get()));
+#else
+    (void)command;
+    return Error(d->lasterr = make_error(GPG_ERR_NOT_SUPPORTED));
+#endif
+}
+
+AssuanResult Context::assuanResult() const
+{
+    if (d->lastop & Private::AssuanTransact) {
+        return AssuanResult(d->ctx, d->lasterr);
+    } else {
+        return AssuanResult();
+    }
+}
+
+AssuanTransaction *Context::lastAssuanTransaction() const
+{
+    return d->lastAssuanTransaction.get();
+}
+
+std::auto_ptr<AssuanTransaction> Context::takeLastAssuanTransaction()
+{
+    return d->lastAssuanTransaction;
+}
+
+DecryptionResult Context::decrypt(const Data &cipherText, Data &plainText)
+{
+    d->lastop = Private::Decrypt;
+    const Data::Private *const cdp = cipherText.impl();
+    Data::Private *const pdp = plainText.impl();
+    d->lasterr = gpgme_op_decrypt(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0);
+    return DecryptionResult(d->ctx, Error(d->lasterr));
+}
+
+Error Context::startDecryption(const Data &cipherText, Data &plainText)
+{
+    d->lastop = Private::Decrypt;
+    const Data::Private *const cdp = cipherText.impl();
+    Data::Private *const pdp = plainText.impl();
+    return Error(d->lasterr = gpgme_op_decrypt_start(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0));
+}
+
+DecryptionResult Context::decryptionResult() const
+{
+    if (d->lastop & Private::Decrypt) {
+        return DecryptionResult(d->ctx, Error(d->lasterr));
+    } else {
+        return DecryptionResult();
+    }
+}
+
+VerificationResult Context::verifyDetachedSignature(const Data &signature, const Data &signedText)
+{
+    d->lastop = Private::Verify;
+    const Data::Private *const sdp = signature.impl();
+    const Data::Private *const tdp = signedText.impl();
+    d->lasterr = gpgme_op_verify(d->ctx, sdp ? sdp->data : 0, tdp ? tdp->data : 0, 0);
+    return VerificationResult(d->ctx, Error(d->lasterr));
+}
+
+VerificationResult Context::verifyOpaqueSignature(const Data &signedData, Data &plainText)
+{
+    d->lastop = Private::Verify;
+    const Data::Private *const sdp = signedData.impl();
+    Data::Private *const pdp = plainText.impl();
+    d->lasterr = gpgme_op_verify(d->ctx, sdp ? sdp->data : 0, 0, pdp ? pdp->data : 0);
+    return VerificationResult(d->ctx, Error(d->lasterr));
+}
+
+Error Context::startDetachedSignatureVerification(const Data &signature, const Data &signedText)
+{
+    d->lastop = Private::Verify;
+    const Data::Private *const sdp = signature.impl();
+    const Data::Private *const tdp = signedText.impl();
+    return Error(d->lasterr = gpgme_op_verify_start(d->ctx, sdp ? sdp->data : 0, tdp ? tdp->data : 0, 0));
+}
+
+Error Context::startOpaqueSignatureVerification(const Data &signedData, Data &plainText)
+{
+    d->lastop = Private::Verify;
+    const Data::Private *const sdp = signedData.impl();
+    Data::Private *const pdp = plainText.impl();
+    return Error(d->lasterr = gpgme_op_verify_start(d->ctx, sdp ? sdp->data : 0, 0, pdp ? pdp->data : 0));
+}
+
+VerificationResult Context::verificationResult() const
+{
+    if (d->lastop & Private::Verify) {
+        return VerificationResult(d->ctx, Error(d->lasterr));
+    } else {
+        return VerificationResult();
+    }
+}
+
+std::pair<DecryptionResult, VerificationResult> Context::decryptAndVerify(const Data &cipherText, Data &plainText)
+{
+    d->lastop = Private::DecryptAndVerify;
+    const Data::Private *const cdp = cipherText.impl();
+    Data::Private *const pdp = plainText.impl();
+    d->lasterr = gpgme_op_decrypt_verify(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0);
+    return std::make_pair(DecryptionResult(d->ctx, Error(d->lasterr)),
+                          VerificationResult(d->ctx, Error(d->lasterr)));
+}
+
+Error Context::startCombinedDecryptionAndVerification(const Data &cipherText, Data &plainText)
+{
+    d->lastop = Private::DecryptAndVerify;
+    const Data::Private *const cdp = cipherText.impl();
+    Data::Private *const pdp = plainText.impl();
+    return Error(d->lasterr = gpgme_op_decrypt_verify_start(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0));
+}
+
+#ifdef HAVE_GPGME_OP_GETAUDITLOG
+unsigned int to_auditlog_flags(unsigned int flags)
+{
+    unsigned int result = 0;
+    if (flags & Context::HtmlAuditLog) {
+        result |= GPGME_AUDITLOG_HTML;
+    }
+    if (flags & Context::AuditLogWithHelp) {
+        result |= GPGME_AUDITLOG_WITH_HELP;
+    }
+    return result;
+}
+#endif // HAVE_GPGME_OP_GETAUDITLOG
+
+Error Context::startGetAuditLog(Data &output, unsigned int flags)
+{
+    d->lastop = Private::GetAuditLog;
+#ifdef HAVE_GPGME_OP_GETAUDITLOG
+    Data::Private *const odp = output.impl();
+    return Error(d->lasterr = gpgme_op_getauditlog_start(d->ctx, odp ? odp->data : 0, to_auditlog_flags(flags)));
+#else
+    (void)output; (void)flags;
+    return Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED));
+#endif
+}
+
+Error Context::getAuditLog(Data &output, unsigned int flags)
+{
+    d->lastop = Private::GetAuditLog;
+#ifdef HAVE_GPGME_OP_GETAUDITLOG
+    Data::Private *const odp = output.impl();
+    return Error(d->lasterr = gpgme_op_getauditlog(d->ctx, odp ? odp->data : 0, to_auditlog_flags(flags)));
+#else
+    (void)output; (void)flags;
+    return Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED));
+#endif
+}
+
+void Context::clearSigningKeys()
+{
+    gpgme_signers_clear(d->ctx);
+}
+
+Error Context::addSigningKey(const Key &key)
+{
+    return Error(d->lasterr = gpgme_signers_add(d->ctx, key.impl()));
+}
+
+Key Context::signingKey(unsigned int idx) const
+{
+    gpgme_key_t key = gpgme_signers_enum(d->ctx, idx);
+    return Key(key, false);
+}
+
+std::vector<Key> Context::signingKeys() const
+{
+    std::vector<Key> result;
+    gpgme_key_t key;
+    for (unsigned int i = 0 ; (key = gpgme_signers_enum(d->ctx, i)) ; ++i) {
+        result.push_back(Key(key, false));
+    }
+    return result;
+}
+
+void Context::clearSignatureNotations()
+{
+#ifdef HAVE_GPGME_SIG_NOTATION_CLEARADDGET
+    gpgme_sig_notation_clear(d->ctx);
+#endif
+}
+
+GpgME::Error Context::addSignatureNotation(const char *name, const char *value, unsigned int flags)
+{
+#ifdef HAVE_GPGME_SIG_NOTATION_CLEARADDGET
+    return Error(gpgme_sig_notation_add(d->ctx, name, value, add_to_gpgme_sig_notation_flags_t(0, flags)));
+#else
+    (void)name; (void)value; (void)flags;
+    return Error(make_error(GPG_ERR_NOT_IMPLEMENTED));
+#endif
+}
+
+GpgME::Error Context::addSignaturePolicyURL(const char *url, bool critical)
+{
+#ifdef HAVE_GPGME_SIG_NOTATION_CLEARADDGET
+    return Error(gpgme_sig_notation_add(d->ctx, 0, url, critical ? GPGME_SIG_NOTATION_CRITICAL : 0));
+#else
+    (void)url; (void)critical;
+    return Error(make_error(GPG_ERR_NOT_IMPLEMENTED));
+#endif
+}
+
+const char *Context::signaturePolicyURL() const
+{
+#ifdef HAVE_GPGME_SIG_NOTATION_CLEARADDGET
+    for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) {
+        if (!n->name) {
+            return n->value;
+        }
+    }
+#endif
+    return 0;
+}
+
+Notation Context::signatureNotation(unsigned int idx) const
+{
+#ifdef HAVE_GPGME_SIG_NOTATION_CLEARADDGET
+    for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) {
+        if (n->name) {
+            if (idx-- == 0) {
+                return Notation(n);
+            }
+        }
+    }
+#endif
+    return Notation();
+}
+
+std::vector<Notation> Context::signatureNotations() const
+{
+    std::vector<Notation> result;
+#ifdef HAVE_GPGME_SIG_NOTATION_CLEARADDGET
+    for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) {
+        if (n->name) {
+            result.push_back(Notation(n));
+        }
+    }
+#endif
+    return result;
+}
+
+static gpgme_sig_mode_t sigmode2sigmode(SignatureMode mode)
+{
+    switch (mode) {
+    default:
+    case NormalSignatureMode: return GPGME_SIG_MODE_NORMAL;
+    case Detached:            return GPGME_SIG_MODE_DETACH;
+    case Clearsigned:         return GPGME_SIG_MODE_CLEAR;
+    }
+}
+
+SigningResult Context::sign(const Data &plainText, Data &signature, SignatureMode mode)
+{
+    d->lastop = Private::Sign;
+    const Data::Private *const pdp = plainText.impl();
+    Data::Private *const sdp = signature.impl();
+    d->lasterr = gpgme_op_sign(d->ctx, pdp ? pdp->data : 0, sdp ? sdp->data : 0, sigmode2sigmode(mode));
+    return SigningResult(d->ctx, Error(d->lasterr));
+}
+
+Error Context::startSigning(const Data &plainText, Data &signature, SignatureMode mode)
+{
+    d->lastop = Private::Sign;
+    const Data::Private *const pdp = plainText.impl();
+    Data::Private *const sdp = signature.impl();
+    return Error(d->lasterr = gpgme_op_sign_start(d->ctx, pdp ? pdp->data : 0, sdp ? sdp->data : 0, sigmode2sigmode(mode)));
+}
+
+SigningResult Context::signingResult() const
+{
+    if (d->lastop & Private::Sign) {
+        return SigningResult(d->ctx, Error(d->lasterr));
+    } else {
+        return SigningResult();
+    }
+}
+
+static gpgme_encrypt_flags_t encryptflags2encryptflags(Context::EncryptionFlags flags)
+{
+    unsigned int result = 0;
+    if (flags & Context::AlwaysTrust) {
+        result |= GPGME_ENCRYPT_ALWAYS_TRUST;
+    }
+#ifdef HAVE_GPGME_ENCRYPT_NO_ENCRYPT_TO
+    if (flags & Context::NoEncryptTo) {
+        result |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
+    }
+#endif
+    return static_cast<gpgme_encrypt_flags_t>(result);
+}
+
+EncryptionResult Context::encrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
+{
+    d->lastop = Private::Encrypt;
+#ifndef HAVE_GPGME_ENCRYPT_NO_ENCRYPT_TO
+    if (flags & NoEncryptTo) {
+        return EncryptionResult(Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED)));
+    }
+#endif
+    const Data::Private *const pdp = plainText.impl();
+    Data::Private *const cdp = cipherText.impl();
+    gpgme_key_t *const keys = new gpgme_key_t[ recipients.size() + 1 ];
+    gpgme_key_t *keys_it = keys;
+    for (std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it) {
+        if (it->impl()) {
+            *keys_it++ = it->impl();
+        }
+    }
+    *keys_it++ = 0;
+    d->lasterr = gpgme_op_encrypt(d->ctx, keys, encryptflags2encryptflags(flags),
+                                  pdp ? pdp->data : 0, cdp ? cdp->data : 0);
+    delete[] keys;
+    return EncryptionResult(d->ctx, Error(d->lasterr));
+}
+
+Error Context::encryptSymmetrically(const Data &plainText, Data &cipherText)
+{
+    d->lastop = Private::Encrypt;
+    const Data::Private *const pdp = plainText.impl();
+    Data::Private *const cdp = cipherText.impl();
+    return Error(d->lasterr = gpgme_op_encrypt(d->ctx, 0, (gpgme_encrypt_flags_t)0,
+                              pdp ? pdp->data : 0, cdp ? cdp->data : 0));
+}
+
+Error Context::startEncryption(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
+{
+    d->lastop = Private::Encrypt;
+#ifndef HAVE_GPGME_ENCRYPT_NO_ENCRYPT_TO
+    if (flags & NoEncryptTo) {
+        return Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED));
+    }
+#endif
+    const Data::Private *const pdp = plainText.impl();
+    Data::Private *const cdp = cipherText.impl();
+    gpgme_key_t *const keys = new gpgme_key_t[ recipients.size() + 1 ];
+    gpgme_key_t *keys_it = keys;
+    for (std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it) {
+        if (it->impl()) {
+            *keys_it++ = it->impl();
+        }
+    }
+    *keys_it++ = 0;
+    d->lasterr = gpgme_op_encrypt_start(d->ctx, keys, encryptflags2encryptflags(flags),
+                                        pdp ? pdp->data : 0, cdp ? cdp->data : 0);
+    delete[] keys;
+    return Error(d->lasterr);
+}
+
+EncryptionResult Context::encryptionResult() const
+{
+    if (d->lastop & Private::Encrypt) {
+        return EncryptionResult(d->ctx, Error(d->lasterr));
+    } else {
+        return EncryptionResult();
+    }
+}
+
+std::pair<SigningResult, EncryptionResult> Context::signAndEncrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
+{
+    d->lastop = Private::SignAndEncrypt;
+    const Data::Private *const pdp = plainText.impl();
+    Data::Private *const cdp = cipherText.impl();
+    gpgme_key_t *const keys = new gpgme_key_t[ recipients.size() + 1 ];
+    gpgme_key_t *keys_it = keys;
+    for (std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it) {
+        if (it->impl()) {
+            *keys_it++ = it->impl();
+        }
+    }
+    *keys_it++ = 0;
+    d->lasterr = gpgme_op_encrypt_sign(d->ctx, keys, encryptflags2encryptflags(flags),
+                                       pdp ? pdp->data : 0, cdp ? cdp->data : 0);
+    delete[] keys;
+    return std::make_pair(SigningResult(d->ctx, Error(d->lasterr)),
+                          EncryptionResult(d->ctx, Error(d->lasterr)));
+}
+
+Error Context::startCombinedSigningAndEncryption(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
+{
+    d->lastop = Private::SignAndEncrypt;
+    const Data::Private *const pdp = plainText.impl();
+    Data::Private *const cdp = cipherText.impl();
+    gpgme_key_t *const keys = new gpgme_key_t[ recipients.size() + 1 ];
+    gpgme_key_t *keys_it = keys;
+    for (std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it) {
+        if (it->impl()) {
+            *keys_it++ = it->impl();
+        }
+    }
+    *keys_it++ = 0;
+    d->lasterr = gpgme_op_encrypt_sign_start(d->ctx, keys, encryptflags2encryptflags(flags),
+                 pdp ? pdp->data : 0, cdp ? cdp->data : 0);
+    delete[] keys;
+    return Error(d->lasterr);
+}
+
+Error Context::createVFS(const char *containerFile, const std::vector< Key > &recipients)
+{
+    d->lastop = Private::CreateVFS;
+#ifdef HAVE_GPGME_G13_VFS
+    gpgme_key_t *const keys = new gpgme_key_t[ recipients.size() + 1 ];
+    gpgme_key_t *keys_it = keys;
+    for (std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it) {
+        if (it->impl()) {
+            *keys_it++ = it->impl();
+        }
+    }
+    *keys_it++ = 0;
+
+    gpgme_error_t op_err;
+    d->lasterr = gpgme_op_vfs_create(d->ctx, keys, containerFile, 0, &op_err);
+    delete[] keys;
+    Error error(d->lasterr);
+    if (error) {
+        return error;
+    }
+    return Error(d->lasterr = op_err);
+#else
+    Q_UNUSED(containerFile);
+    Q_UNUSED(recipients);
+    return Error(d->lasterr = make_error(GPG_ERR_NOT_SUPPORTED));
+#endif
+}
+
+VfsMountResult Context::mountVFS(const char *containerFile, const char *mountDir)
+{
+    d->lastop = Private::MountVFS;
+#ifdef HAVE_GPGME_G13_VFS
+    gpgme_error_t op_err;
+    d->lasterr = gpgme_op_vfs_mount(d->ctx, containerFile, mountDir, 0, &op_err);
+    return VfsMountResult(d->ctx, Error(d->lasterr), Error(op_err));
+#else
+    Q_UNUSED(containerFile);
+    Q_UNUSED(mountDir);
+    return VfsMountResult(d->ctx, Error(d->lasterr = make_error(GPG_ERR_NOT_SUPPORTED)), Error());
+#endif
+}
+
+Error Context::cancelPendingOperation()
+{
+#ifdef HAVE_GPGME_CANCEL_ASYNC
+    return Error(gpgme_cancel_async(d->ctx));
+#else
+    return Error(gpgme_cancel(d->ctx));
+#endif
+}
+
+bool Context::poll()
+{
+    gpgme_error_t e = GPG_ERR_NO_ERROR;
+    const bool finished = gpgme_wait(d->ctx, &e, 0);
+    if (finished) {
+        d->lasterr = e;
+    }
+    return finished;
+}
+
+Error Context::wait()
+{
+    gpgme_error_t e = GPG_ERR_NO_ERROR;
+    gpgme_wait(d->ctx, &e, 1);
+    return Error(d->lasterr = e);
+}
+
+Error Context::lastError() const
+{
+    return Error(d->lasterr);
+}
+
+std::ostream &operator<<(std::ostream &os, Protocol proto)
+{
+    os << "GpgME::Protocol(";
+    switch (proto) {
+    case OpenPGP:
+        os << "OpenPGP";
+        break;
+    case CMS:
+        os << "CMS";
+        break;
+    default:
+    case UnknownProtocol:
+        os << "UnknownProtocol";
+        break;
+    }
+    return os << ')';
+}
+
+std::ostream &operator<<(std::ostream &os, Engine eng)
+{
+    os << "GpgME::Engine(";
+    switch (eng) {
+    case GpgEngine:
+        os << "GpgEngine";
+        break;
+    case GpgSMEngine:
+        os << "GpgSMEngine";
+        break;
+    case GpgConfEngine:
+        os << "GpgConfEngine";
+        break;
+    case AssuanEngine:
+        os << "AssuanEngine";
+        break;
+    default:
+    case UnknownEngine:
+        os << "UnknownEngine";
+        break;
+    }
+    return os << ')';
+}
+
+std::ostream &operator<<(std::ostream &os, Context::CertificateInclusion incl)
+{
+    os << "GpgME::Context::CertificateInclusion(" << static_cast<int>(incl);
+    switch (incl) {
+    case Context::DefaultCertificates:
+        os << "(DefaultCertificates)";
+        break;
+    case Context::AllCertificatesExceptRoot:
+        os << "(AllCertificatesExceptRoot)";
+        break;
+    case Context::AllCertificates:
+        os << "(AllCertificates)";
+        break;
+    case Context::NoCertificates:
+        os << "(NoCertificates)";
+        break;
+    case Context::OnlySenderCertificate:
+        os << "(OnlySenderCertificate)";
+        break;
+    }
+    return os << ')';
+}
+
+std::ostream &operator<<(std::ostream &os, KeyListMode mode)
+{
+    os << "GpgME::KeyListMode(";
+#define CHECK( x ) if ( !(mode & (x)) ) {} else do { os << #x " "; } while (0)
+    CHECK(Local);
+    CHECK(Extern);
+    CHECK(Signatures);
+    CHECK(Validate);
+    CHECK(Ephemeral);
+#undef CHECK
+    return os << ')';
+}
+
+std::ostream &operator<<(std::ostream &os, SignatureMode mode)
+{
+    os << "GpgME::SignatureMode(";
+    switch (mode) {
+#define CHECK( x ) case x: os << #x; break
+        CHECK(NormalSignatureMode);
+        CHECK(Detached);
+        CHECK(Clearsigned);
+#undef CHECK
+    default:
+        os << "???" "(" << static_cast<int>(mode) << ')';
+        break;
+    }
+    return os << ')';
+}
+
+std::ostream &operator<<(std::ostream &os, Context::EncryptionFlags flags)
+{
+    os << "GpgME::Context::EncryptionFlags(";
+#define CHECK( x ) if ( !(flags & (Context::x)) ) {} else do { os << #x " "; } while (0)
+    CHECK(AlwaysTrust);
+#undef CHECK
+    return os << ')';
+}
+
+std::ostream &operator<<(std::ostream &os, Context::AuditLogFlags flags)
+{
+    os << "GpgME::Context::AuditLogFlags(";
+#define CHECK( x ) if ( !(flags & (Context::x)) ) {} else do { os << #x " "; } while (0)
+    CHECK(HtmlAuditLog);
+    CHECK(AuditLogWithHelp);
+#undef CHECK
+    return os << ')';
+}
+
+} // namespace GpgME
+
+GpgME::Error GpgME::setDefaultLocale(int cat, const char *val)
+{
+    return Error(gpgme_set_locale(0, cat, val));
+}
+
+GpgME::EngineInfo GpgME::engineInfo(GpgME::Protocol proto)
+{
+    gpgme_engine_info_t ei = 0;
+    if (gpgme_get_engine_info(&ei)) {
+        return EngineInfo();
+    }
+
+    const gpgme_protocol_t p = proto == CMS ? GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP ;
+
+    for (gpgme_engine_info_t i = ei ; i ; i = i->next) {
+        if (i->protocol == p) {
+            return EngineInfo(i);
+        }
+    }
+
+    return EngineInfo();
+}
+
+GpgME::Error GpgME::checkEngine(GpgME::Protocol proto)
+{
+    const gpgme_protocol_t p = proto == CMS ? GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP ;
+
+    return Error(gpgme_engine_check_version(p));
+}
+
+static const gpgme_protocol_t UNKNOWN_PROTOCOL = static_cast<gpgme_protocol_t>(255);
+
+static gpgme_protocol_t engine2protocol(const GpgME::Engine engine)
+{
+    switch (engine) {
+    case GpgME::GpgEngine:   return GPGME_PROTOCOL_OpenPGP;
+    case GpgME::GpgSMEngine: return GPGME_PROTOCOL_CMS;
+    case GpgME::GpgConfEngine:
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+        return GPGME_PROTOCOL_GPGCONF;
+#else
+        break;
+#endif
+    case GpgME::AssuanEngine:
+#ifdef HAVE_GPGME_ASSUAN_ENGINE
+        return GPGME_PROTOCOL_ASSUAN;
+#else
+        break;
+#endif
+    case GpgME::G13Engine:
+#ifdef HAVE_GPGME_G13_VFS
+        return GPGME_PROTOCOL_G13;
+#else
+        break;
+#endif
+    case GpgME::UnknownEngine:
+        ;
+    }
+    return UNKNOWN_PROTOCOL;
+}
+
+GpgME::EngineInfo GpgME::engineInfo(GpgME::Engine engine)
+{
+    gpgme_engine_info_t ei = 0;
+    if (gpgme_get_engine_info(&ei)) {
+        return EngineInfo();
+    }
+
+    const gpgme_protocol_t p = engine2protocol(engine);
+
+    for (gpgme_engine_info_t i = ei ; i ; i = i->next) {
+        if (i->protocol == p) {
+            return EngineInfo(i);
+        }
+    }
+
+    return EngineInfo();
+}
+
+GpgME::Error GpgME::checkEngine(GpgME::Engine engine)
+{
+    const gpgme_protocol_t p = engine2protocol(engine);
+
+    return Error(gpgme_engine_check_version(p));
+}
+
+static const unsigned long supported_features = 0
+        | GpgME::ValidatingKeylistModeFeature
+        | GpgME::CancelOperationFeature
+        | GpgME::WrongKeyUsageFeature
+#ifdef HAVE_GPGME_INCLUDE_CERTS_DEFAULT
+        | GpgME::DefaultCertificateInclusionFeature
+#endif
+#ifdef HAVE_GPGME_CTX_GETSET_ENGINE_INFO
+        | GpgME::GetSetEngineInfoFeature
+#endif
+#ifdef HAVE_GPGME_SIG_NOTATION_CLEARADDGET
+        | GpgME::ClearAddGetSignatureNotationsFeature
+#endif
+#ifdef HAVE_GPGME_DATA_SET_FILE_NAME
+        | GpgME::SetDataFileNameFeeature
+#endif
+#ifdef HAVE_GPGME_KEYLIST_MODE_SIG_NOTATIONS
+        | GpgME::SignatureNotationsKeylistModeFeature
+#endif
+#ifdef HAVE_GPGME_KEY_SIG_NOTATIONS
+        | GpgME::KeySignatureNotationsFeature
+#endif
+#ifdef HAVE_GPGME_KEY_T_IS_QUALIFIED
+        | GpgME::KeyIsQualifiedFeature
+#endif
+#ifdef HAVE_GPGME_SIG_NOTATION_CRITICAL
+        | GpgME::SignatureNotationsCriticalFlagFeature
+#endif
+#ifdef HAVE_GPGME_SIG_NOTATION_FLAGS_T
+        | GpgME::SignatureNotationsFlagsFeature
+#endif
+#ifdef HAVE_GPGME_SIG_NOTATION_HUMAN_READABLE
+        | GpgME::SignatureNotationsHumanReadableFlagFeature
+#endif
+#ifdef HAVE_GPGME_SUBKEY_T_IS_QUALIFIED
+        | GpgME::SubkeyIsQualifiedFeature
+#endif
+#ifdef HAVE_GPGME_ENGINE_INFO_T_HOME_DIR
+        | GpgME::EngineInfoHomeDirFeature
+#endif
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_FILE_NAME
+        | GpgME::DecryptionResultFileNameFeature
+#endif
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_RECIPIENTS
+        | GpgME::DecryptionResultRecipientsFeature
+#endif
+#ifdef HAVE_GPGME_VERIFY_RESULT_T_FILE_NAME
+        | GpgME::VerificationResultFileNameFeature
+#endif
+#ifdef HAVE_GPGME_SIGNATURE_T_PKA_FIELDS
+        | GpgME::SignaturePkaFieldsFeature
+#endif
+#ifdef HAVE_GPGME_SIGNATURE_T_ALGORITHM_FIELDS
+        | GpgME::SignatureAlgorithmFieldsFeature
+#endif
+#ifdef HAVE_GPGME_GET_FDPTR
+        | GpgME::FdPointerFeature
+#endif
+#ifdef HAVE_GPGME_OP_GETAUDITLOG
+        | GpgME::AuditLogFeature
+#endif
+#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
+        | GpgME::GpgConfEngineFeature
+#endif
+#ifdef HAVE_GPGME_CANCEL_ASYNC
+        | GpgME::CancelOperationAsyncFeature
+#endif
+#ifdef HAVE_GPGME_ENCRYPT_NO_ENCRYPT_TO
+        | GpgME::NoEncryptToEncryptionFlagFeature
+#endif
+#ifdef HAVE_GPGME_SUBKEY_T_IS_CARDKEY
+        | GpgME::CardKeyFeature
+#endif
+#ifdef HAVE_GPGME_ASSUAN_ENGINE
+        | GpgME::AssuanEngineFeature
+#endif
+#ifdef HAVE_GPGME_KEYLIST_MODE_EPHEMERAL
+        | GpgME::EphemeralKeylistModeFeature
+#endif
+#ifdef HAVE_GPGME_OP_IMPORT_KEYS
+        | GpgME::ImportFromKeyserverFeature
+#endif
+#ifdef HAVE_GPGME_G13_VFS
+        | GpgME::G13VFSFeature
+#endif
+#ifdef HAVE_GPGME_OP_PASSWD
+        | GpgME::PasswdFeature
+#endif
+        ;
+
+static const unsigned long supported_features2 = 0
+        ;
+
+bool GpgME::hasFeature(unsigned long features)
+{
+    return features == (features & supported_features);
+}
+
+bool GpgME::hasFeature(unsigned long features, unsigned long features2)
+{
+    return features  == (features  & supported_features)
+           && features2 == (features2 & supported_features2)
+           ;
+}
diff --git a/lang/cpp/src/context.h b/lang/cpp/src/context.h
new file mode 100644 (file)
index 0000000..ee4f847
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+  context.h - wraps a gpgme key context
+  Copyright (C) 2003, 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_CONTEXT_H__
+#define __GPGMEPP_CONTEXT_H__
+
+#include "global.h"
+
+#include "error.h"
+#include "verificationresult.h" // for Signature::Notation
+
+#include <memory>
+#include <vector>
+#include <utility>
+#include <iosfwd>
+
+namespace GpgME
+{
+
+class Key;
+class Data;
+class TrustItem;
+class ProgressProvider;
+class PassphraseProvider;
+class EventLoopInteractor;
+class EditInteractor;
+class AssuanTransaction;
+
+class AssuanResult;
+class KeyListResult;
+class KeyGenerationResult;
+class ImportResult;
+class DecryptionResult;
+class VerificationResult;
+class SigningResult;
+class EncryptionResult;
+class VfsMountResult;
+
+class EngineInfo;
+
+class GPGMEPP_EXPORT Context
+{
+    explicit Context(gpgme_ctx_t);
+public:
+    //using GpgME::Protocol;
+
+    //
+    // Creation and destruction:
+    //
+
+    static Context *createForProtocol(Protocol proto);
+    static std::auto_ptr<Context> createForEngine(Engine engine, Error *err = 0);
+    virtual ~Context();
+
+    //
+    // Context Attributes
+    //
+
+    Protocol protocol() const;
+
+    void setArmor(bool useArmor);
+    bool armor() const;
+
+    void setTextMode(bool useTextMode);
+    bool textMode() const;
+
+    void setOffline(bool useOfflineMode);
+    bool offline() const;
+
+    enum CertificateInclusion {
+        DefaultCertificates = -256,
+        AllCertificatesExceptRoot = -2,
+        AllCertificates = -1,
+        NoCertificates = 0,
+        OnlySenderCertificate = 1
+    };
+    void setIncludeCertificates(int which);
+    int includeCertificates() const;
+
+    //using GpgME::KeyListMode;
+    void setKeyListMode(unsigned int keyListMode);
+    void addKeyListMode(unsigned int keyListMode);
+    unsigned int keyListMode() const;
+
+    void setPassphraseProvider(PassphraseProvider *provider);
+    PassphraseProvider *passphraseProvider() const;
+
+    void setProgressProvider(ProgressProvider *provider);
+    ProgressProvider *progressProvider() const;
+
+    void setManagedByEventLoopInteractor(bool managed);
+    bool managedByEventLoopInteractor() const;
+
+    GpgME::Error setLocale(int category, const char *value);
+
+    EngineInfo engineInfo() const;
+    GpgME::Error setEngineFileName(const char *filename);
+    GpgME::Error setEngineHomeDirectory(const char *filename);
+
+private:
+    friend class ::GpgME::EventLoopInteractor;
+    void installIOCallbacks(gpgme_io_cbs *iocbs);
+    void uninstallIOCallbacks();
+
+public:
+    //
+    //
+    // Key Management
+    //
+    //
+
+    //
+    // Key Listing
+    //
+
+    GpgME::Error startKeyListing(const char *pattern = 0, bool secretOnly = false);
+    GpgME::Error startKeyListing(const char *patterns[], bool secretOnly = false);
+
+    Key nextKey(GpgME::Error &e);
+
+    KeyListResult endKeyListing();
+    KeyListResult keyListResult() const;
+
+    Key key(const char *fingerprint, GpgME::Error &e, bool secret = false);
+
+    //
+    // Key Generation
+    //
+
+    KeyGenerationResult generateKey(const char *parameters, Data &pubKey);
+    GpgME::Error startKeyGeneration(const char *parameters, Data &pubkey);
+    KeyGenerationResult keyGenerationResult() const;
+
+    //
+    // Key Export
+    //
+
+    GpgME::Error exportPublicKeys(const char *pattern, Data &keyData);
+    GpgME::Error exportPublicKeys(const char *pattern[], Data &keyData);
+    GpgME::Error startPublicKeyExport(const char *pattern, Data &keyData);
+    GpgME::Error startPublicKeyExport(const char *pattern[], Data &keyData);
+
+    //
+    // Key Import
+    //
+
+    ImportResult importKeys(const Data &data);
+    ImportResult importKeys(const std::vector<Key> &keys);
+    GpgME::Error startKeyImport(const Data &data);
+    GpgME::Error startKeyImport(const std::vector<Key> &keys);
+    ImportResult importResult() const;
+
+    //
+    // Key Deletion
+    //
+
+    GpgME::Error deleteKey(const Key &key, bool allowSecretKeyDeletion = false);
+    GpgME::Error startKeyDeletion(const Key &key, bool allowSecretKeyDeletion = false);
+
+    //
+    // Passphrase changing
+    //
+
+    GpgME::Error passwd(const Key &key);
+    GpgME::Error startPasswd(const Key &key);
+
+    //
+    // Key Editing
+    //
+
+    GpgME::Error edit(const Key &key, std::auto_ptr<EditInteractor> function, Data &out);
+    GpgME::Error startEditing(const Key &key, std::auto_ptr<EditInteractor> function, Data &out);
+
+    EditInteractor *lastEditInteractor() const;
+    std::auto_ptr<EditInteractor> takeLastEditInteractor();
+
+    //
+    // SmartCard Editing
+    //
+
+    GpgME::Error cardEdit(const Key &key, std::auto_ptr<EditInteractor> function, Data &out);
+    GpgME::Error startCardEditing(const Key &key, std::auto_ptr<EditInteractor> function, Data &out);
+
+    EditInteractor *lastCardEditInteractor() const;
+    std::auto_ptr<EditInteractor> takeLastCardEditInteractor();
+
+    //
+    // Trust Item Management
+    //
+
+    GpgME::Error startTrustItemListing(const char *pattern, int maxLevel);
+    TrustItem nextTrustItem(GpgME::Error &e);
+    GpgME::Error endTrustItemListing();
+
+    //
+    // Assuan Transactions
+    //
+
+    AssuanResult assuanTransact(const char *command, std::auto_ptr<AssuanTransaction> transaction);
+    AssuanResult assuanTransact(const char *command);
+    GpgME::Error startAssuanTransaction(const char *command, std::auto_ptr<AssuanTransaction> transaction);
+    GpgME::Error startAssuanTransaction(const char *command);
+    AssuanResult assuanResult() const;
+
+    AssuanTransaction *lastAssuanTransaction() const;
+    std::auto_ptr<AssuanTransaction> takeLastAssuanTransaction();
+
+    //
+    //
+    // Crypto Operations
+    //
+    //
+
+    //
+    // Decryption
+    //
+
+    DecryptionResult decrypt(const Data &cipherText, Data &plainText);
+    GpgME::Error startDecryption(const Data &cipherText, Data &plainText);
+    DecryptionResult decryptionResult() const;
+
+    //
+    // Signature Verification
+    //
+
+    VerificationResult verifyDetachedSignature(const Data &signature, const Data &signedText);
+    VerificationResult verifyOpaqueSignature(const Data &signedData, Data &plainText);
+    GpgME::Error startDetachedSignatureVerification(const Data &signature, const Data &signedText);
+    GpgME::Error startOpaqueSignatureVerification(const Data &signedData, Data &plainText);
+    VerificationResult verificationResult() const;
+
+    //
+    // Combined Decryption and Signature Verification
+    //
+
+    std::pair<DecryptionResult, VerificationResult> decryptAndVerify(const Data &cipherText, Data &plainText);
+    GpgME::Error startCombinedDecryptionAndVerification(const Data &cipherText, Data &plainText);
+    // use verificationResult() and decryptionResult() to retrieve the result objects...
+
+    //
+    // Signing
+    //
+
+    void clearSigningKeys();
+    GpgME::Error addSigningKey(const Key &signer);
+    Key signingKey(unsigned int index) const;
+    std::vector<Key> signingKeys() const;
+
+    void clearSignatureNotations();
+    GpgME::Error addSignatureNotation(const char *name, const char *value, unsigned int flags = 0);
+    GpgME::Error addSignaturePolicyURL(const char *url, bool critical = false);
+    const char *signaturePolicyURL() const;
+    Notation signatureNotation(unsigned int index) const;
+    std::vector<Notation> signatureNotations() const;
+
+    //using GpgME::SignatureMode;
+    SigningResult sign(const Data &plainText, Data &signature, SignatureMode mode);
+    GpgME::Error startSigning(const Data &plainText, Data &signature, SignatureMode mode);
+    SigningResult signingResult() const;
+
+    //
+    // Encryption
+    //
+
+    enum EncryptionFlags { None = 0, AlwaysTrust = 1, NoEncryptTo = 2 };
+    EncryptionResult encrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags);
+    GpgME::Error encryptSymmetrically(const Data &plainText, Data &cipherText);
+    GpgME::Error startEncryption(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags);
+    EncryptionResult encryptionResult() const;
+
+    //
+    // Combined Signing and Encryption
+    //
+
+    std::pair<SigningResult, EncryptionResult> signAndEncrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags);
+    GpgME::Error startCombinedSigningAndEncryption(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags);
+    // use encryptionResult() and signingResult() to retrieve the result objects...
+
+    //
+    //
+    // Audit Log
+    //
+    //
+    enum AuditLogFlags {
+        HtmlAuditLog = 1,
+        AuditLogWithHelp = 128
+    };
+    GpgME::Error startGetAuditLog(Data &output, unsigned int flags = 0);
+    GpgME::Error getAuditLog(Data &output, unsigned int flags = 0);
+
+    //
+    //
+    // G13 crypto container operations
+    //
+    //
+    GpgME::Error createVFS(const char *containerFile, const std::vector<Key> &recipients);
+    VfsMountResult mountVFS(const char *containerFile, const char *mountDir);
+
+    //
+    //
+    // Run Control
+    //
+    //
+
+    bool poll();
+    GpgME::Error wait();
+    GpgME::Error lastError() const;
+    GpgME::Error cancelPendingOperation();
+
+    class Private;
+    const Private *impl() const
+    {
+        return d;
+    }
+    Private *impl()
+    {
+        return d;
+    }
+private:
+    Private *const d;
+
+private: // disable...
+    Context(const Context &);
+    const Context &operator=(const Context &);
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Context::CertificateInclusion incl);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Context::EncryptionFlags flags);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Context::AuditLogFlags flags);
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_CONTEXT_H__
diff --git a/lang/cpp/src/context_glib.cpp b/lang/cpp/src/context_glib.cpp
new file mode 100644 (file)
index 0000000..383b8eb
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  context_glib.cpp - wraps a gpgme key context, gpgme-glib-specific functions
+  Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include <global.h>
+
+#ifdef HAVE_GPGME_GET_FDPTR
+extern "C" GIOChannel *gpgme_get_fdptr(int);
+#endif
+
+GIOChannel *GpgME::getGIOChannel(int fd)
+{
+#ifdef HAVE_GPGME_GET_FDPTR
+    return gpgme_get_fdptr(fd);
+#else
+    (void)fd;
+    return 0;
+#endif
+}
+
+QIODevice *GpgME::getQIODevice(int fd)
+{
+    return 0;
+}
diff --git a/lang/cpp/src/context_p.h b/lang/cpp/src/context_p.h
new file mode 100644 (file)
index 0000000..2991123
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+  context_p.h - wraps a gpgme context (private part)
+  Copyright (C) 2003, 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_CONTEXT_P_H__
+#define __GPGMEPP_CONTEXT_P_H__
+
+#include <context.h>
+#include <data.h>
+
+#include <gpgme.h>
+
+namespace GpgME
+{
+
+class Context::Private
+{
+public:
+    enum Operation {
+        None = 0,
+
+        Encrypt   = 0x001,
+        Decrypt   = 0x002,
+        Sign      = 0x004,
+        Verify    = 0x008,
+        DecryptAndVerify = Decrypt | Verify,
+        SignAndEncrypt   = Sign | Encrypt,
+
+        Import    = 0x010,
+        Export    = 0x020, // no gpgme_export_result_t, but nevertheless...
+        Delete    = 0x040, // no gpgme_delete_result_t, but nevertheless...
+
+        KeyGen    = 0x080,
+        KeyList   = 0x100,
+        TrustList = 0x200, // no gpgme_trustlist_result_t, but nevertheless...
+
+        Edit      = 0x400, // no gpgme_edit_result_t, but nevertheless...
+        CardEdit  = 0x800, // no gpgme_card_edit_result_t, but nevertheless...
+
+        GetAuditLog = 0x1000, // no gpgme_getauditlog_result_t, but nevertheless...
+
+        AssuanTransact = 0x2000,
+        Passwd    = 0x4000, // no gpgme_passwd_result_t, but nevertheless...
+
+        CreateVFS = 0x4000,
+        MountVFS = 0x8000,
+
+        EndMarker
+    };
+
+    Private(gpgme_ctx_t c = 0);
+    ~Private();
+
+    gpgme_ctx_t ctx;
+    gpgme_io_cbs *iocbs;
+    Operation lastop;
+    gpgme_error_t lasterr;
+    Data lastAssuanInquireData;
+    std::auto_ptr<AssuanTransaction> lastAssuanTransaction;
+    std::auto_ptr<EditInteractor> lastEditInteractor, lastCardEditInteractor;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_CONTEXT_P_H__
diff --git a/lang/cpp/src/context_qt.cpp b/lang/cpp/src/context_qt.cpp
new file mode 100644 (file)
index 0000000..e6d44fa
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  context_qt.cpp - wraps a gpgme key context, gpgme-qt-specific functions
+  Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include <global.h>
+
+#ifdef HAVE_GPGME_GET_FDPTR
+extern "C" QIODevice *gpgme_get_fdptr(int);
+#endif
+
+GIOChannel *GpgME::getGIOChannel(int)
+{
+    return 0;
+}
+
+QIODevice *GpgME::getQIODevice(int fd)
+{
+#ifdef HAVE_GPGME_GET_FDPTR
+    return gpgme_get_fdptr(fd);
+#else
+    (void)fd;
+    return 0;
+#endif
+}
diff --git a/lang/cpp/src/context_vanilla.cpp b/lang/cpp/src/context_vanilla.cpp
new file mode 100644 (file)
index 0000000..30b18b4
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+  context_vanilla.cpp - wraps a gpgme key context, gpgme (vanilla)-specific functions
+  Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include <global.h>
+
+GIOChannel *GpgME::getGIOChannel(int)
+{
+    return 0;
+}
+
+QIODevice *GpgME::getQIODevice(int)
+{
+    return 0;
+}
diff --git a/lang/cpp/src/data.cpp b/lang/cpp/src/data.cpp
new file mode 100644 (file)
index 0000000..6b29aaf
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+  data.cpp - wraps a gpgme data object
+  Copyright (C) 2003 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include "data_p.h"
+#include <error.h>
+#include <interfaces/dataprovider.h>
+
+#include <gpgme.h>
+
+#ifndef NDEBUG
+#include <iostream>
+#endif
+
+GpgME::Data::Private::~Private()
+{
+    if (data) {
+        gpgme_data_release(data);
+    }
+}
+
+const GpgME::Data::Null GpgME::Data::null;
+
+GpgME::Data::Data()
+{
+    gpgme_data_t data;
+    const gpgme_error_t e = gpgme_data_new(&data);
+    d.reset(new Private(e ? 0 : data));
+}
+
+GpgME::Data::Data(const Null &)
+    : d(new Private(0))
+{
+
+}
+
+GpgME::Data::Data(gpgme_data_t data)
+    : d(new Private(data))
+{
+
+}
+
+GpgME::Data::Data(const char *buffer, size_t size, bool copy)
+{
+    gpgme_data_t data;
+    const gpgme_error_t e = gpgme_data_new_from_mem(&data, buffer, size, int(copy));
+    d.reset(new Private(e ? 0 : data));
+}
+
+GpgME::Data::Data(const char *filename)
+{
+    gpgme_data_t data;
+    const gpgme_error_t e = gpgme_data_new(&data);
+    d.reset(new Private(e ? 0 : data));
+    if (!e) {
+        setFileName(filename);
+    }
+}
+
+GpgME::Data::Data(const char *filename, off_t offset, size_t length)
+{
+    gpgme_data_t data;
+    const gpgme_error_t e = gpgme_data_new_from_filepart(&data, filename, 0, offset, length);
+    d.reset(new Private(e ? 0 : data));
+}
+
+GpgME::Data::Data(FILE *fp)
+{
+    gpgme_data_t data;
+    const gpgme_error_t e = gpgme_data_new_from_stream(&data, fp);
+    d.reset(new Private(e ? 0 : data));
+}
+
+GpgME::Data::Data(FILE *fp, off_t offset, size_t length)
+{
+    gpgme_data_t data;
+    const gpgme_error_t e = gpgme_data_new_from_filepart(&data, 0, fp, offset, length);
+    d.reset(new Private(e ? 0 : data));
+}
+
+GpgME::Data::Data(int fd)
+{
+    gpgme_data_t data;
+    const gpgme_error_t e = gpgme_data_new_from_fd(&data, fd);
+    d.reset(new Private(e ? 0 : data));
+}
+
+GpgME::Data::Data(DataProvider *dp)
+{
+    d.reset(new Private);
+    if (!dp) {
+        return;
+    }
+    if (!dp->isSupported(DataProvider::Read)) {
+        d->cbs.read = 0;
+    }
+    if (!dp->isSupported(DataProvider::Write)) {
+        d->cbs.write = 0;
+    }
+    if (!dp->isSupported(DataProvider::Seek)) {
+        d->cbs.seek = 0;
+    }
+    if (!dp->isSupported(DataProvider::Release)) {
+        d->cbs.release = 0;
+    }
+    const gpgme_error_t e = gpgme_data_new_from_cbs(&d->data, &d->cbs, dp);
+    if (e) {
+        d->data = 0;
+    }
+#ifndef NDEBUG
+    //std::cerr << "GpgME::Data(): DataProvider supports: "
+    //    << ( d->cbs.read ? "read" : "no read" ) << ", "
+    //    << ( d->cbs.write ? "write" : "no write" ) << ", "
+    //    << ( d->cbs.seek ? "seek" : "no seek" ) << ", "
+    //    << ( d->cbs.release ? "release" : "no release" ) << std::endl;
+#endif
+}
+
+bool GpgME::Data::isNull() const
+{
+    return !d || !d->data;
+}
+
+GpgME::Data::Encoding GpgME::Data::encoding() const
+{
+    switch (gpgme_data_get_encoding(d->data)) {
+    case GPGME_DATA_ENCODING_NONE:   return AutoEncoding;
+    case GPGME_DATA_ENCODING_BINARY: return BinaryEncoding;
+    case GPGME_DATA_ENCODING_BASE64: return Base64Encoding;
+    case GPGME_DATA_ENCODING_ARMOR:  return ArmorEncoding;
+    }
+    return AutoEncoding;
+}
+
+GpgME::Error GpgME::Data::setEncoding(Encoding enc)
+{
+    gpgme_data_encoding_t ge = GPGME_DATA_ENCODING_NONE;
+    switch (enc) {
+    case AutoEncoding:   ge = GPGME_DATA_ENCODING_NONE;   break;
+    case BinaryEncoding: ge = GPGME_DATA_ENCODING_BINARY; break;
+    case Base64Encoding: ge = GPGME_DATA_ENCODING_BASE64; break;
+    case ArmorEncoding:  ge = GPGME_DATA_ENCODING_ARMOR;  break;
+    }
+    return Error(gpgme_data_set_encoding(d->data, ge));
+}
+
+char *GpgME::Data::fileName() const
+{
+#ifdef HAVE_GPGME_DATA_SET_FILE_NAME
+    return gpgme_data_get_file_name(d->data);
+#else
+    return 0;
+#endif
+}
+
+GpgME::Error GpgME::Data::setFileName(const char *name)
+{
+#ifdef HAVE_GPGME_DATA_SET_FILE_NAME
+    return Error(gpgme_data_set_file_name(d->data, name));
+#else
+    (void)name;
+    return Error();
+#endif
+}
+
+ssize_t GpgME::Data::read(void *buffer, size_t length)
+{
+    return gpgme_data_read(d->data, buffer, length);
+}
+
+ssize_t GpgME::Data::write(const void *buffer, size_t length)
+{
+    return gpgme_data_write(d->data, buffer, length);
+}
+
+off_t GpgME::Data::seek(off_t offset, int whence)
+{
+    return gpgme_data_seek(d->data, offset, whence);
+}
diff --git a/lang/cpp/src/data.h b/lang/cpp/src/data.h
new file mode 100644 (file)
index 0000000..c8a599e
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+  data.h - wraps a gpgme data object
+  Copyright (C) 2003,2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_DATA_H__
+#define __GPGMEPP_DATA_H__
+
+#include "global.h"
+
+#include <boost/shared_ptr.hpp>
+
+#include <sys/types.h> // for size_t, off_t
+#include <cstdio> // FILE
+#include <algorithm>
+
+namespace GpgME
+{
+
+class DataProvider;
+class Error;
+
+class GPGMEPP_EXPORT Data
+{
+    struct Null {
+               Null() {}
+       };
+public:
+    /* implicit */ Data(const Null &);
+    Data();
+    explicit Data(gpgme_data_t data);
+
+    // Memory-Based Data Buffers:
+    Data(const char *buffer, size_t size, bool copy = true);
+    explicit Data(const char *filename);
+    Data(const char *filename, off_t offset, size_t length);
+    Data(std::FILE *fp, off_t offset, size_t length);
+    // File-Based Data Buffers:
+    explicit Data(std::FILE *fp);
+    explicit Data(int fd);
+    // Callback-Based Data Buffers:
+    explicit Data(DataProvider *provider);
+
+    static const Null null;
+
+    const Data &operator=(Data other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(Data &other)
+    {
+        using std::swap;
+        swap(this->d, other.d);
+    }
+
+    bool isNull() const;
+
+    enum Encoding {
+        AutoEncoding,
+        BinaryEncoding,
+        Base64Encoding,
+        ArmorEncoding
+    };
+    Encoding encoding() const;
+    Error setEncoding(Encoding encoding);
+
+    char *fileName() const;
+    Error setFileName(const char *name);
+
+    ssize_t read(void *buffer, size_t length);
+    ssize_t write(const void *buffer, size_t length);
+    off_t seek(off_t offset, int whence);
+
+    class Private;
+    Private *impl()
+    {
+        return d.get();
+    }
+    const Private *impl() const
+    {
+        return d.get();
+    }
+private:
+    boost::shared_ptr<Private> d;
+};
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Data)
+
+#endif // __GPGMEPP_DATA_H__
diff --git a/lang/cpp/src/data_p.h b/lang/cpp/src/data_p.h
new file mode 100644 (file)
index 0000000..38ba55a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  data_p.h - wraps a gpgme data object, private part -*- c++ -*-
+  Copyright (C) 2003,2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_DATA_P_H__
+#define __GPGMEPP_DATA_P_H__
+
+#include <data.h>
+#include "callbacks.h"
+
+class GpgME::Data::Private
+{
+public:
+    explicit Private(gpgme_data_t d = 0)
+        : data(d), cbs(data_provider_callbacks) {}
+    ~Private();
+
+    gpgme_data_t data;
+    gpgme_data_cbs cbs;
+};
+
+#endif // __GPGMEPP_DATA_P_H__
diff --git a/lang/cpp/src/decryptionresult.cpp b/lang/cpp/src/decryptionresult.cpp
new file mode 100644 (file)
index 0000000..88e8567
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+  decryptionresult.cpp - wraps a gpgme keygen result
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include <decryptionresult.h>
+#include "result_p.h"
+#include "util.h"
+
+#include <gpgme.h>
+
+#include <algorithm>
+#include <iterator>
+#include <cstring>
+#include <cstdlib>
+#include <istream>
+
+#include <string.h>
+
+class GpgME::DecryptionResult::Private
+{
+public:
+    explicit Private(const _gpgme_op_decrypt_result &r) : res(r)
+    {
+        if (res.unsupported_algorithm) {
+            res.unsupported_algorithm = strdup(res.unsupported_algorithm);
+        }
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_FILE_NAME
+        if (res.file_name) {
+            res.file_name = strdup(res.file_name);
+        }
+#endif
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_RECIPIENTS
+        //FIXME: copying gpgme_recipient_t objects invalidates the keyid member,
+        //thus we use _keyid for now (internal API)
+        for (gpgme_recipient_t r = res.recipients ; r ; r = r->next) {
+            recipients.push_back(*r);
+        }
+        res.recipients = 0;
+#endif
+    }
+    ~Private()
+    {
+        if (res.unsupported_algorithm) {
+            std::free(res.unsupported_algorithm);
+        }
+        res.unsupported_algorithm = 0;
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_FILE_NAME
+        if (res.file_name) {
+            std::free(res.file_name);
+        }
+        res.file_name = 0;
+#endif
+    }
+
+    _gpgme_op_decrypt_result res;
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_RECIPIENTS
+    std::vector<_gpgme_recipient> recipients;
+#endif
+};
+
+GpgME::DecryptionResult::DecryptionResult(gpgme_ctx_t ctx, int error)
+    : GpgME::Result(error), d()
+{
+    init(ctx);
+}
+
+GpgME::DecryptionResult::DecryptionResult(gpgme_ctx_t ctx, const Error &error)
+    : GpgME::Result(error), d()
+{
+    init(ctx);
+}
+
+void GpgME::DecryptionResult::init(gpgme_ctx_t ctx)
+{
+    if (!ctx) {
+        return;
+    }
+    gpgme_decrypt_result_t res = gpgme_op_decrypt_result(ctx);
+    if (!res) {
+        return;
+    }
+    d.reset(new Private(*res));
+}
+
+make_standard_stuff(DecryptionResult)
+
+const char *GpgME::DecryptionResult::unsupportedAlgorithm() const
+{
+    return d ? d->res.unsupported_algorithm : 0 ;
+}
+
+bool GpgME::DecryptionResult::isWrongKeyUsage() const
+{
+    return d && d->res.wrong_key_usage;
+}
+
+const char *GpgME::DecryptionResult::fileName() const
+{
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_FILE_NAME
+    return d ? d->res.file_name : 0 ;
+#else
+    return 0;
+#endif
+}
+
+unsigned int GpgME::DecryptionResult::numRecipients() const
+{
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_RECIPIENTS
+    return d ? d->recipients.size() : 0 ;
+#else
+    return 0;
+#endif
+}
+
+GpgME::DecryptionResult::Recipient GpgME::DecryptionResult::recipient(unsigned int idx) const
+{
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_RECIPIENTS
+    if (d && idx < d->recipients.size()) {
+        return Recipient(&d->recipients[idx]);
+    }
+#endif
+    return Recipient();
+}
+
+namespace
+{
+struct make_recipient {
+    GpgME::DecryptionResult::Recipient operator()(_gpgme_recipient &t)
+    {
+        return GpgME::DecryptionResult::Recipient(&t);
+    }
+};
+}
+
+std::vector<GpgME::DecryptionResult::Recipient> GpgME::DecryptionResult::recipients() const
+{
+    std::vector<Recipient> result;
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_RECIPIENTS
+    if (d) {
+        result.reserve(d->recipients.size());
+        std::transform(d->recipients.begin(), d->recipients.end(),
+                       std::back_inserter(result),
+                       make_recipient());
+    }
+#endif
+    return result;
+}
+
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_RECIPIENTS
+class GpgME::DecryptionResult::Recipient::Private : public _gpgme_recipient
+{
+public:
+    Private(gpgme_recipient_t reci) : _gpgme_recipient(*reci) {}
+};
+#endif
+
+GpgME::DecryptionResult::Recipient::Recipient()
+    : d()
+{
+
+}
+
+GpgME::DecryptionResult::Recipient::Recipient(gpgme_recipient_t r)
+    : d()
+{
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_RECIPIENTS
+    if (r) {
+        d.reset(new Private(r));
+    }
+#endif
+}
+
+bool GpgME::DecryptionResult::Recipient::isNull() const
+{
+    return !d;
+}
+
+const char *GpgME::DecryptionResult::Recipient::keyID() const
+{
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_RECIPIENTS
+    //_keyid is internal API, but the public keyid is invalid after copying (see above)
+    if (d) {
+        return d->_keyid;
+    }
+#endif
+    return 0;
+}
+
+const char *GpgME::DecryptionResult::Recipient::shortKeyID() const
+{
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_RECIPIENTS
+    //_keyid is internal API, but the public keyid is invalid after copying (see above)
+    if (d) {
+        return d->_keyid + 8;
+    }
+#endif
+    return 0;
+}
+
+unsigned int GpgME::DecryptionResult::Recipient::publicKeyAlgorithm() const
+{
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_RECIPIENTS
+    if (d) {
+        return d->pubkey_algo;
+    }
+#endif
+    return 0;
+}
+
+const char *GpgME::DecryptionResult::Recipient::publicKeyAlgorithmAsString() const
+{
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_RECIPIENTS
+    if (d) {
+        return gpgme_pubkey_algo_name(d->pubkey_algo);
+    }
+#endif
+    return 0;
+}
+
+GpgME::Error GpgME::DecryptionResult::Recipient::status() const
+{
+#ifdef HAVE_GPGME_DECRYPT_RESULT_T_RECIPIENTS
+    if (d) {
+        return Error(d->status);
+    }
+#endif
+    return Error();
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const DecryptionResult &result)
+{
+    os << "GpgME::DecryptionResult(";
+    if (!result.isNull()) {
+        os << "\n error:                " << result.error()
+           << "\n fileName:             " << protect(result.fileName())
+           << "\n unsupportedAlgorithm: " << protect(result.unsupportedAlgorithm())
+           << "\n isWrongKeyUsage:      " << result.isWrongKeyUsage()
+           << "\n recipients:\n";
+        const std::vector<DecryptionResult::Recipient> recipients = result.recipients();
+        std::copy(recipients.begin(), recipients.end(),
+                  std::ostream_iterator<DecryptionResult::Recipient>(os, "\n"));
+    }
+    return os << ')';
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const DecryptionResult::Recipient &reci)
+{
+    os << "GpgME::DecryptionResult::Recipient(";
+    if (!reci.isNull()) {
+        os << "\n keyID:              " << protect(reci.keyID())
+           << "\n shortKeyID:         " << protect(reci.shortKeyID())
+           << "\n publicKeyAlgorithm: " << protect(reci.publicKeyAlgorithmAsString())
+           << "\n status:             " << reci.status();
+    }
+    return os << ')';
+}
diff --git a/lang/cpp/src/decryptionresult.h b/lang/cpp/src/decryptionresult.h
new file mode 100644 (file)
index 0000000..2374cbb
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+  decryptionresult.h - wraps a gpgme keygen result
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_DECRYPTIONRESULT_H__
+#define __GPGMEPP_DECRYPTIONRESULT_H__
+
+#include "gpgmefw.h"
+#include "result.h"
+#include "gpgmepp_export.h"
+
+#include <boost/shared_ptr.hpp>
+
+#include <vector>
+#include <algorithm>
+#include <iosfwd>
+
+namespace GpgME
+{
+
+class Error;
+
+class GPGMEPP_EXPORT DecryptionResult : public Result
+{
+public:
+    DecryptionResult();
+    DecryptionResult(gpgme_ctx_t ctx, int error);
+    DecryptionResult(gpgme_ctx_t ctx, const Error &err);
+    explicit DecryptionResult(const Error &err);
+
+    const DecryptionResult &operator=(DecryptionResult other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(DecryptionResult &other)
+    {
+        Result::swap(other);
+        using std::swap;
+        swap(this->d, other.d);
+    }
+
+    bool isNull() const;
+
+    GPGMEPP_DEPRECATED const char *unsupportedAlgortihm() const
+    {
+        return unsupportedAlgorithm();
+    }
+    const char *unsupportedAlgorithm() const;
+
+    GPGMEPP_DEPRECATED bool wrongKeyUsage() const
+    {
+        return isWrongKeyUsage();
+    }
+    bool isWrongKeyUsage() const;
+
+    const char *fileName() const;
+
+    class Recipient;
+
+    unsigned int numRecipients() const;
+    Recipient recipient(unsigned int idx) const;
+    std::vector<Recipient> recipients() const;
+
+private:
+    class Private;
+    void init(gpgme_ctx_t ctx);
+    boost::shared_ptr<Private> d;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const DecryptionResult &result);
+
+class GPGMEPP_EXPORT DecryptionResult::Recipient
+{
+public:
+    Recipient();
+    explicit Recipient(gpgme_recipient_t reci);
+
+    const Recipient &operator=(Recipient other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(Recipient &other)
+    {
+        using std::swap;
+        swap(this->d, other.d);
+    }
+
+    bool isNull() const;
+
+    const char *keyID() const;
+    const char *shortKeyID() const;
+
+    unsigned int publicKeyAlgorithm() const;
+    const char *publicKeyAlgorithmAsString() const;
+
+    Error status() const;
+
+private:
+    class Private;
+    boost::shared_ptr<Private> d;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const DecryptionResult::Recipient &reci);
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(DecryptionResult)
+
+#endif // __GPGMEPP_DECRYPTIONRESULT_H__
diff --git a/lang/cpp/src/defaultassuantransaction.cpp b/lang/cpp/src/defaultassuantransaction.cpp
new file mode 100644 (file)
index 0000000..c51050c
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+  defaultassuantransaction.cpp - default Assuan Transaction that just stores data and status lines
+  Copyright (C) 2009 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include "defaultassuantransaction.h"
+#include "error.h"
+#include "data.h"
+
+#include <sstream>
+
+using namespace GpgME;
+using namespace boost;
+
+DefaultAssuanTransaction::DefaultAssuanTransaction()
+    : AssuanTransaction(),
+      m_status(),
+      m_data()
+{
+
+}
+
+DefaultAssuanTransaction::~DefaultAssuanTransaction() {}
+
+Error DefaultAssuanTransaction::data(const char *data, size_t len)
+{
+    m_data.append(data, len);
+    return Error();
+}
+
+Data DefaultAssuanTransaction::inquire(const char *name, const char *args, Error &err)
+{
+    (void)name; (void)args; (void)err;
+    return Data::null;
+}
+
+Error DefaultAssuanTransaction::status(const char *status, const char *args)
+{
+    m_status.push_back(std::pair<std::string, std::string>(status, args));
+    return Error();
+}
+
+std::vector<std::string> DefaultAssuanTransaction::statusLine(const char *tag) const
+{
+    std::vector<std::string> result;
+    for (std::vector< std::pair<std::string, std::string> >::const_iterator it = m_status.begin(), end = m_status.end() ; it != end ; ++it) {
+        if (it->first == tag) {
+            result.push_back(it->second);
+        }
+    }
+    return result;
+}
+
+std::string DefaultAssuanTransaction::firstStatusLine(const char *tag) const
+{
+    for (std::vector< std::pair<std::string, std::string> >::const_iterator it = m_status.begin(), end = m_status.end() ; it != end ; ++it) {
+        if (it->first == tag) {
+            return it->second;
+        }
+    }
+    return std::string();
+}
diff --git a/lang/cpp/src/defaultassuantransaction.h b/lang/cpp/src/defaultassuantransaction.h
new file mode 100644 (file)
index 0000000..bf4b839
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+  defaultassuantransaction.h - default Assuan Transaction that just stores data and status lines
+  Copyright (C) 2009 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_DEFAULTASSUANTRANSACTION_H__
+#define __GPGMEPP_DEFAULTASSUANTRANSACTION_H__
+
+#include <interfaces/assuantransaction.h>
+
+#include <string>
+#include <vector>
+#include <utility>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT DefaultAssuanTransaction : public AssuanTransaction
+{
+public:
+    explicit DefaultAssuanTransaction();
+    ~DefaultAssuanTransaction();
+
+    const std::vector< std::pair<std::string, std::string> > &statusLines() const
+    {
+        return m_status;
+    }
+    std::vector<std::string> statusLine(const char *tag) const;
+    std::string firstStatusLine(const char *tag) const;
+
+    const std::string &data() const
+    {
+        return m_data;
+    }
+
+private:
+    /* reimp */ Error data(const char *data, size_t datalen);
+    /* reimp */ Data inquire(const char *name, const char *args, Error &err);
+    /* reimp */ Error status(const char *status, const char *args);
+
+private:
+    std::vector< std::pair<std::string, std::string> > m_status;
+    std::string m_data;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_DEFAULTASSUANTRANSACTION_H__
diff --git a/lang/cpp/src/editinteractor.cpp b/lang/cpp/src/editinteractor.cpp
new file mode 100644 (file)
index 0000000..0c5f778
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+  editinteractor.cpp - Interface for edit interactors
+  Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include "editinteractor.h"
+#include "callbacks.h"
+#include "error.h"
+
+#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
+#include <gpgme.h>
+#else
+#include <gpg-error.h>
+#endif
+
+#ifdef _WIN32
+# include <io.h>
+#include <windows.h>
+#else
+# include <unistd.h>
+#endif
+
+#include <cerrno>
+#include <cstring>
+
+using namespace GpgME;
+
+static const char *status_to_string(unsigned int status);
+static Error status_to_error(unsigned int status);
+
+class EditInteractor::Private
+{
+    friend class ::GpgME::EditInteractor;
+    friend class ::GpgME::CallbackHelper;
+    EditInteractor *const q;
+public:
+    explicit Private(EditInteractor *qq);
+    ~Private();
+
+private:
+    unsigned int state;
+    Error error;
+    std::FILE *debug;
+};
+
+class GpgME::CallbackHelper
+{
+private:
+    static int writeAll(int fd, const void *buf, size_t count)
+    {
+        size_t toWrite = count;
+        while (toWrite > 0) {
+#ifdef HAVE_GPGME_IO_READWRITE
+            const int n = gpgme_io_write(fd, buf, toWrite);
+#else
+# ifdef Q_OS_WIN
+            DWORD n;
+            if (!WriteFile((HANDLE)fd, buf, toWrite, &n, NULL)) {
+                return -1;
+            }
+# else
+            const int n = write(fd, buf, toWrite);
+# endif
+#endif
+            if (n < 0) {
+                return n;
+            }
+            toWrite -= n;
+        }
+        return count;
+    }
+
+public:
+    static int edit_interactor_callback_impl(void *opaque, gpgme_status_code_t status, const char *args, int fd)
+    {
+        EditInteractor::Private *ei = (EditInteractor::Private *)opaque;
+
+        Error err = status_to_error(status);
+
+        if (!err) {
+
+            // advance to next state based on input:
+            const unsigned int oldState = ei->state;
+            ei->state = ei->q->nextState(status, args, err);
+            if (ei->debug) {
+                std::fprintf(ei->debug, "EditInteractor: %u -> nextState( %s, %s ) -> %u\n",
+                             oldState, status_to_string(status), args ? args : "<null>", ei->state);
+            }
+            if (err) {
+                ei->state = oldState;
+                goto error;
+            }
+
+            if (ei->state != oldState &&
+                    // if there was an error from before, we stop here (### this looks weird, can this happen at all?)
+                    ei->error.code() == GPG_ERR_NO_ERROR) {
+
+                // successful state change -> call action
+                if (const char *const result = ei->q->action(err)) {
+                    if (err) {
+                        goto error;
+                    }
+                    if (ei->debug) {
+                        std::fprintf(ei->debug, "EditInteractor: action result \"%s\"\n", result);
+                    }
+                    // if there's a result, write it:
+                    if (*result) {
+#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
+                        gpgme_err_set_errno(0);
+#else
+                        gpg_err_set_errno(0);
+#endif
+                        const ssize_t len = std::strlen(result);
+                        if (writeAll(fd, result, len) != len) {
+                            err = Error::fromSystemError();
+                            if (ei->debug) {
+                                std::fprintf(ei->debug, "EditInteractor: Could not write to fd %d (%s)\n", fd, err.asString());
+                            }
+                            goto error;
+                        }
+                    }
+#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
+                    gpgme_err_set_errno(0);
+#else
+                    gpg_err_set_errno(0);
+#endif
+                    if (writeAll(fd, "\n", 1) != 1) {
+                        err = Error::fromSystemError();
+                        if (ei->debug) {
+                            std::fprintf(ei->debug, "EditInteractor: Could not write to fd %d (%s)\n", fd, err.asString());
+                        }
+                        goto error;
+                    }
+                } else {
+                    if (err) {
+                        goto error;
+                    }
+                    if (ei->debug) {
+                        std::fprintf(ei->debug, "EditInteractor: no action result\n");
+                    }
+                }
+            } else {
+                if (ei->debug) {
+                    std::fprintf(ei->debug, "EditInteractor: no action executed\n");
+                }
+            }
+        }
+
+    error:
+        if (err) {
+            ei->error = err;
+            ei->state = EditInteractor::ErrorState;
+        }
+
+        if (ei->debug) {
+            std::fprintf(ei->debug, "EditInteractor: error now %u (%s)\n",
+                         ei->error.encodedError(), gpgme_strerror(ei->error.encodedError()));
+        }
+
+        return ei->error.encodedError();
+    }
+};
+
+static gpgme_error_t edit_interactor_callback(void *opaque, gpgme_status_code_t status, const char *args, int fd)
+{
+    return CallbackHelper::edit_interactor_callback_impl(opaque, status, args, fd);
+}
+
+const gpgme_edit_cb_t GpgME::edit_interactor_callback = ::edit_interactor_callback;
+
+EditInteractor::Private::Private(EditInteractor *qq)
+    : q(qq),
+      state(StartState),
+      error(),
+      debug(0)
+{
+
+}
+
+EditInteractor::Private::~Private() {}
+
+EditInteractor::EditInteractor()
+    : d(new Private(this))
+{
+
+}
+
+EditInteractor::~EditInteractor()
+{
+    delete d;
+}
+
+unsigned int EditInteractor::state() const
+{
+    return d->state;
+}
+
+Error EditInteractor::lastError() const
+{
+    return d->error;
+}
+
+bool EditInteractor::needsNoResponse(unsigned int status) const
+{
+    switch (status) {
+    case GPGME_STATUS_EOF:
+    case GPGME_STATUS_GOT_IT:
+    case GPGME_STATUS_NEED_PASSPHRASE:
+    case GPGME_STATUS_NEED_PASSPHRASE_SYM:
+    case GPGME_STATUS_GOOD_PASSPHRASE:
+    case GPGME_STATUS_BAD_PASSPHRASE:
+    case GPGME_STATUS_USERID_HINT:
+    case GPGME_STATUS_SIGEXPIRED:
+    case GPGME_STATUS_KEYEXPIRED:
+        return true;
+    default:
+        return false;
+    }
+}
+
+// static
+Error status_to_error(unsigned int status)
+{
+    switch (status) {
+    case GPGME_STATUS_MISSING_PASSPHRASE:
+        return Error::fromCode(GPG_ERR_NO_PASSPHRASE);
+    case GPGME_STATUS_ALREADY_SIGNED:
+        return Error::fromCode(GPG_ERR_ALREADY_SIGNED);
+    case GPGME_STATUS_KEYEXPIRED:
+        return Error::fromCode(GPG_ERR_CERT_EXPIRED);
+    case GPGME_STATUS_SIGEXPIRED:
+        return Error::fromCode(GPG_ERR_SIG_EXPIRED);
+    }
+    return Error();
+}
+
+void EditInteractor::setDebugChannel(std::FILE *debug)
+{
+    d->debug = debug;
+}
+
+static const char *const status_strings[] = {
+    "EOF",
+    /* mkstatus processing starts here */
+    "ENTER",
+    "LEAVE",
+    "ABORT",
+
+    "GOODSIG",
+    "BADSIG",
+    "ERRSIG",
+
+    "BADARMOR",
+
+    "RSA_OR_IDEA",
+    "KEYEXPIRED",
+    "KEYREVOKED",
+
+    "TRUST_UNDEFINED",
+    "TRUST_NEVER",
+    "TRUST_MARGINAL",
+    "TRUST_FULLY",
+    "TRUST_ULTIMATE",
+
+    "SHM_INFO",
+    "SHM_GET",
+    "SHM_GET_BOOL",
+    "SHM_GET_HIDDEN",
+
+    "NEED_PASSPHRASE",
+    "VALIDSIG",
+    "SIG_ID",
+    "ENC_TO",
+    "NODATA",
+    "BAD_PASSPHRASE",
+    "NO_PUBKEY",
+    "NO_SECKEY",
+    "NEED_PASSPHRASE_SYM",
+    "DECRYPTION_FAILED",
+    "DECRYPTION_OKAY",
+    "MISSING_PASSPHRASE",
+    "GOOD_PASSPHRASE",
+    "GOODMDC",
+    "BADMDC",
+    "ERRMDC",
+    "IMPORTED",
+    "IMPORT_OK",
+    "IMPORT_PROBLEM",
+    "IMPORT_RES",
+    "FILE_START",
+    "FILE_DONE",
+    "FILE_ERROR",
+
+    "BEGIN_DECRYPTION",
+    "END_DECRYPTION",
+    "BEGIN_ENCRYPTION",
+    "END_ENCRYPTION",
+
+    "DELETE_PROBLEM",
+    "GET_BOOL",
+    "GET_LINE",
+    "GET_HIDDEN",
+    "GOT_IT",
+    "PROGRESS",
+    "SIG_CREATED",
+    "SESSION_KEY",
+    "NOTATION_NAME",
+    "NOTATION_DATA",
+    "POLICY_URL",
+    "BEGIN_STREAM",
+    "END_STREAM",
+    "KEY_CREATED",
+    "USERID_HINT",
+    "UNEXPECTED",
+    "INV_RECP",
+    "NO_RECP",
+    "ALREADY_SIGNED",
+    "SIGEXPIRED",
+    "EXPSIG",
+    "EXPKEYSIG",
+    "TRUNCATED",
+    "ERROR",
+    "NEWSIG",
+    "REVKEYSIG",
+    "SIG_SUBPACKET",
+    "NEED_PASSPHRASE_PIN",
+    "SC_OP_FAILURE",
+    "SC_OP_SUCCESS",
+    "CARDCTRL",
+    "BACKUP_KEY_CREATED",
+    "PKA_TRUST_BAD",
+    "PKA_TRUST_GOOD",
+
+    "PLAINTEXT",
+};
+static const unsigned int num_status_strings = sizeof status_strings / sizeof * status_strings ;
+
+const char *status_to_string(unsigned int idx)
+{
+    if (idx < num_status_strings) {
+        return status_strings[idx];
+    } else {
+        return "(unknown)";
+    }
+}
diff --git a/lang/cpp/src/editinteractor.h b/lang/cpp/src/editinteractor.h
new file mode 100644 (file)
index 0000000..2122052
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+  editinteractor.h - Interface for edit interactors
+  Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_EDITINTERACTOR_H__
+#define __GPGMEPP_EDITINTERACTOR_H__
+
+#include "gpgmepp_export.h"
+
+#include <cstdio>
+
+namespace GpgME
+{
+
+class Error;
+class Context;
+class CallbackHelper;
+
+class GPGMEPP_EXPORT EditInteractor
+{
+    friend class ::GpgME::Context;
+    friend class ::GpgME::CallbackHelper;
+    EditInteractor(const EditInteractor &);
+    EditInteractor &operator=(const EditInteractor &);
+public:
+    EditInteractor();
+    virtual ~EditInteractor();
+
+    enum {
+        StartState = 0,
+        ErrorState = 0xFFFFFFFF
+    };
+
+    virtual const char *action(Error &err) const = 0;
+    virtual unsigned int nextState(unsigned int statusCode, const char *args, Error &err) const = 0;
+
+    unsigned int state() const;
+    Error lastError() const;
+    bool needsNoResponse(unsigned int statusCode) const;
+
+    void setDebugChannel(std::FILE *file);
+
+private:
+    class Private;
+    Private *const d;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_EDITINTERACTOR_H__
diff --git a/lang/cpp/src/encryptionresult.cpp b/lang/cpp/src/encryptionresult.cpp
new file mode 100644 (file)
index 0000000..25e3922
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+  encryptionresult.cpp - wraps a gpgme verify result
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include <encryptionresult.h>
+#include "result_p.h"
+#include "util.h"
+
+#include <gpgme.h>
+
+#include <cstring>
+#include <cstdlib>
+#include <istream>
+#include <algorithm>
+#include <iterator>
+
+#include <string.h>
+
+class GpgME::EncryptionResult::Private
+{
+public:
+    explicit Private(const gpgme_encrypt_result_t r)
+    {
+        if (!r) {
+            return;
+        }
+        for (gpgme_invalid_key_t ik = r->invalid_recipients ; ik ; ik = ik->next) {
+            gpgme_invalid_key_t copy = new _gpgme_invalid_key(*ik);
+            if (ik->fpr) {
+                copy->fpr = strdup(ik->fpr);
+            }
+            copy->next = 0;
+            invalid.push_back(copy);
+        }
+    }
+    ~Private()
+    {
+        for (std::vector<gpgme_invalid_key_t>::iterator it = invalid.begin() ; it != invalid.end() ; ++it) {
+            std::free((*it)->fpr);
+            delete *it; *it = 0;
+        }
+    }
+
+    std::vector<gpgme_invalid_key_t> invalid;
+};
+
+GpgME::EncryptionResult::EncryptionResult(gpgme_ctx_t ctx, int error)
+    : GpgME::Result(error), d()
+{
+    init(ctx);
+}
+
+GpgME::EncryptionResult::EncryptionResult(gpgme_ctx_t ctx, const Error &error)
+    : GpgME::Result(error), d()
+{
+    init(ctx);
+}
+
+void GpgME::EncryptionResult::init(gpgme_ctx_t ctx)
+{
+    if (!ctx) {
+        return;
+    }
+    gpgme_encrypt_result_t res = gpgme_op_encrypt_result(ctx);
+    if (!res) {
+        return;
+    }
+    d.reset(new Private(res));
+}
+
+make_standard_stuff(EncryptionResult)
+
+unsigned int GpgME::EncryptionResult::numInvalidRecipients() const
+{
+    return d ? d->invalid.size() : 0 ;
+}
+
+GpgME::InvalidRecipient GpgME::EncryptionResult::invalidEncryptionKey(unsigned int idx) const
+{
+    return InvalidRecipient(d, idx);
+}
+
+std::vector<GpgME::InvalidRecipient> GpgME::EncryptionResult::invalidEncryptionKeys() const
+{
+    if (!d) {
+        return std::vector<GpgME::InvalidRecipient>();
+    }
+    std::vector<GpgME::InvalidRecipient> result;
+    result.reserve(d->invalid.size());
+    for (unsigned int i = 0 ; i < d->invalid.size() ; ++i) {
+        result.push_back(InvalidRecipient(d, i));
+    }
+    return result;
+}
+
+GpgME::InvalidRecipient::InvalidRecipient(const boost::shared_ptr<EncryptionResult::Private> &parent, unsigned int i)
+    : d(parent), idx(i)
+{
+
+}
+
+GpgME::InvalidRecipient::InvalidRecipient() : d(), idx(0) {}
+
+bool GpgME::InvalidRecipient::isNull() const
+{
+    return !d || idx >= d->invalid.size() ;
+}
+
+const char *GpgME::InvalidRecipient::fingerprint() const
+{
+    return isNull() ? 0 : d->invalid[idx]->fpr ;
+}
+
+GpgME::Error GpgME::InvalidRecipient::reason() const
+{
+    return Error(isNull() ? 0 : d->invalid[idx]->reason);
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const EncryptionResult &result)
+{
+    os << "GpgME::EncryptionResult(";
+    if (!result.isNull()) {
+        os << "\n error:        " << result.error()
+           << "\n invalid recipients:\n";
+        const std::vector<InvalidRecipient> ir = result.invalidEncryptionKeys();
+        std::copy(ir.begin(), ir.end(),
+                  std::ostream_iterator<InvalidRecipient>(os, "\n"));
+    }
+    return os << ')';
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const InvalidRecipient &ir)
+{
+    os << "GpgME::InvalidRecipient(";
+    if (!ir.isNull()) {
+        os << "\n fingerprint: " << protect(ir.fingerprint())
+           << "\n reason:      " << ir.reason()
+           << '\n';
+    }
+    return os << ')';
+}
diff --git a/lang/cpp/src/encryptionresult.h b/lang/cpp/src/encryptionresult.h
new file mode 100644 (file)
index 0000000..1f5d16f
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+  encryptionresult.h - wraps a gpgme sign result
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_ENCRYPTIONRESULT_H__
+#define __GPGMEPP_ENCRYPTIONRESULT_H__
+
+#include "gpgmefw.h"
+#include "result.h"
+#include "gpgmepp_export.h"
+
+#include <boost/shared_ptr.hpp>
+
+#include <vector>
+#include <iosfwd>
+
+namespace GpgME
+{
+
+class Error;
+class InvalidRecipient;
+
+class GPGMEPP_EXPORT EncryptionResult : public Result
+{
+public:
+    EncryptionResult();
+    EncryptionResult(gpgme_ctx_t ctx, int error);
+    EncryptionResult(gpgme_ctx_t ctx, const Error &error);
+    EncryptionResult(const Error &err);
+
+    const EncryptionResult &operator=(EncryptionResult other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(EncryptionResult &other)
+    {
+        Result::swap(other);
+        using std::swap;
+        swap(this->d, other.d);
+    }
+
+    bool isNull() const;
+
+    unsigned int numInvalidRecipients() const;
+
+    InvalidRecipient invalidEncryptionKey(unsigned int index) const;
+    std::vector<InvalidRecipient> invalidEncryptionKeys() const;
+
+    class Private;
+private:
+    void init(gpgme_ctx_t ctx);
+    boost::shared_ptr<Private> d;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const EncryptionResult &result);
+
+class GPGMEPP_EXPORT InvalidRecipient
+{
+    friend class ::GpgME::EncryptionResult;
+    InvalidRecipient(const boost::shared_ptr<EncryptionResult::Private> &parent, unsigned int index);
+public:
+    InvalidRecipient();
+
+    const InvalidRecipient &operator=(InvalidRecipient other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(InvalidRecipient &other)
+    {
+        using std::swap;
+        swap(this->d, other.d);
+    }
+
+    bool isNull() const;
+
+    const char *fingerprint() const;
+    Error reason() const;
+
+private:
+    boost::shared_ptr<EncryptionResult::Private> d;
+    unsigned int idx;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const InvalidRecipient &recipient);
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(EncryptionResult)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(InvalidRecipient)
+
+#endif // __GPGMEPP_ENCRYPTIONRESULT_H__
diff --git a/lang/cpp/src/engineinfo.cpp b/lang/cpp/src/engineinfo.cpp
new file mode 100644 (file)
index 0000000..eaff2bd
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+  engineinfo.h
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include "engineinfo.h"
+
+#include <gpgme.h>
+
+class GpgME::EngineInfo::Private
+{
+public:
+    Private(gpgme_engine_info_t engine = 0) : info(engine) {}
+    ~Private()
+    {
+        info = 0;
+    }
+
+    gpgme_engine_info_t info;
+};
+
+GpgME::EngineInfo::EngineInfo() : d() {}
+
+GpgME::EngineInfo::EngineInfo(gpgme_engine_info_t engine)
+    : d(new Private(engine))
+{
+
+}
+
+bool GpgME::EngineInfo::isNull() const
+{
+    return !d || !d->info;
+}
+
+GpgME::Protocol GpgME::EngineInfo::protocol() const
+{
+    if (isNull()) {
+        return UnknownProtocol;
+    }
+    switch (d->info->protocol) {
+    case GPGME_PROTOCOL_OpenPGP: return OpenPGP;
+    case GPGME_PROTOCOL_CMS:     return CMS;
+    default:
+        return UnknownProtocol;
+    }
+}
+
+const char *GpgME::EngineInfo::fileName() const
+{
+    return isNull() ? 0 : d->info->file_name;
+}
+
+const char *GpgME::EngineInfo::version() const
+{
+    return isNull() ? 0 : d->info->version;
+}
+
+const char *GpgME::EngineInfo::requiredVersion() const
+{
+    return isNull() ? 0 : d->info->req_version;
+}
+
+const char *GpgME::EngineInfo::homeDirectory() const
+{
+#ifdef HAVE_GPGME_ENGINE_INFO_T_HOME_DIR
+    return isNull() ? 0 : d->info->home_dir;
+#else
+    return 0;
+#endif
+}
diff --git a/lang/cpp/src/engineinfo.h b/lang/cpp/src/engineinfo.h
new file mode 100644 (file)
index 0000000..94c52bd
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  engineinfo.h
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_ENGINEINFO_H__
+#define __GPGMEPP_ENGINEINFO_H__
+
+#include "global.h"
+
+#include <boost/shared_ptr.hpp>
+
+#include <algorithm>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT EngineInfo
+{
+public:
+    EngineInfo();
+    explicit EngineInfo(gpgme_engine_info_t engine);
+
+    const EngineInfo &operator=(EngineInfo other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(EngineInfo &other)
+    {
+        using std::swap;
+        swap(this->d, other.d);
+    }
+
+    bool isNull() const;
+
+    Protocol protocol() const;
+    const char *fileName() const;
+    const char *version() const;
+    const char *requiredVersion() const;
+    const char *homeDirectory() const;
+
+private:
+    class Private;
+    boost::shared_ptr<Private> d;
+};
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(EngineInfo)
+
+#endif // __GPGMEPP_ENGINEINFO_H__
diff --git a/lang/cpp/src/error.h b/lang/cpp/src/error.h
new file mode 100644 (file)
index 0000000..009fe20
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+  error.h - wraps a gpgme error
+  Copyright (C) 2003, 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_ERROR_H__
+#define __GPGMEPP_ERROR_H__
+
+#include "global.h"
+
+#include <string>
+#include <iosfwd>
+
+#include <gpg-error.h>
+
+#ifndef GPGMEPP_ERR_SOURCE_DEFAULT
+# define GPGMEPP_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_USER_1
+#endif
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT Error
+{
+public:
+    Error() : mErr(0), mMessage() {}
+    explicit Error(unsigned int e) : mErr(e), mMessage() {}
+
+    const char *source() const;
+    const char *asString() const;
+
+    int code() const;
+    int sourceID() const;
+
+    bool isCanceled() const;
+
+    unsigned int encodedError() const
+    {
+        return mErr;
+    }
+    int toErrno() const;
+
+    static bool hasSystemError();
+    static Error fromSystemError(unsigned int src = GPGMEPP_ERR_SOURCE_DEFAULT);
+    static void setSystemError(gpg_err_code_t err);
+    static void setErrno(int err);
+    static Error fromErrno(int err, unsigned int src = GPGMEPP_ERR_SOURCE_DEFAULT);
+    static Error fromCode(unsigned int err, unsigned int src = GPGMEPP_ERR_SOURCE_DEFAULT);
+
+    GPGMEPP_MAKE_SAFE_BOOL_OPERATOR(mErr  &&!isCanceled())
+private:
+    unsigned int mErr;
+    mutable std::string mMessage;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Error &err);
+
+} // namespace GpgME
+
+#endif /* __GPGMEPP_ERROR_H__ */
diff --git a/lang/cpp/src/eventloopinteractor.cpp b/lang/cpp/src/eventloopinteractor.cpp
new file mode 100644 (file)
index 0000000..4718ddc
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+  eventloopinteractor.cpp
+  Copyright (C) 2003,2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include <eventloopinteractor.h>
+
+#include <context.h>
+#include "context_p.h"
+#include <key.h>
+#include <trustitem.h>
+
+#include <gpgme.h>
+
+#include <vector>
+using std::vector;
+#ifndef NDEBUG
+# include <iostream>
+#endif
+#include <cassert>
+
+namespace GpgME
+{
+
+//
+// EventLoopInteractor::Private Declaration
+//
+
+class EventLoopInteractor::Private
+{
+public:
+    struct OneFD {
+        OneFD(int aFd, int aDir, gpgme_io_cb_t aFnc,
+              void *aFncData, void *aExternalTag)
+            : fd(aFd), dir(aDir), fnc(aFnc),
+              fncData(aFncData), externalTag(aExternalTag) {}
+        int fd;
+        int dir;
+        gpgme_io_cb_t fnc;
+        void *fncData;
+        void *externalTag;
+    };
+
+    vector<OneFD *> mCallbacks;
+
+    static void removeIOCb(void *tag);
+    static gpgme_error_t registerIOCb(void *data, int fd, int dir,
+                                      gpgme_io_cb_t fnc, void *fnc_data,
+                                      void **r_tag);
+    static void eventIOCb(void *, gpgme_event_io_t type, void *type_data);
+
+    static const gpgme_io_cbs iocbs;
+};
+
+const gpgme_io_cbs EventLoopInteractor::Private::iocbs = {
+    &EventLoopInteractor::Private::registerIOCb,
+    0,
+    &EventLoopInteractor::Private::removeIOCb,
+    &EventLoopInteractor::Private::eventIOCb,
+    0
+};
+
+//
+// EventLoopInteractor::Private IO Callback Implementations
+//
+
+gpgme_error_t EventLoopInteractor::Private::registerIOCb(void *, int fd, int dir,
+        gpgme_io_cb_t fnc, void *fnc_data,
+        void **r_tag)
+{
+    assert(instance()); assert(instance()->d);
+    bool ok = false;
+    void *etag = instance()->registerWatcher(fd, dir ? Read : Write, ok);
+    if (!ok) {
+        return gpgme_error(GPG_ERR_GENERAL);
+    }
+    instance()->d->mCallbacks.push_back(new OneFD(fd, dir, fnc, fnc_data, etag));
+    if (r_tag) {
+        *r_tag = instance()->d->mCallbacks.back();
+    }
+    return GPG_ERR_NO_ERROR;
+}
+
+void EventLoopInteractor::Private::removeIOCb(void *tag)
+{
+
+    if (!instance() || !instance()->d) {
+        return;
+    }
+    for (vector<OneFD *>::iterator it = instance()->d->mCallbacks.begin();
+            it != instance()->d->mCallbacks.end() ; ++it) {
+        if (*it == tag) {
+            instance()->unregisterWatcher((*it)->externalTag);
+            delete *it; *it = 0;
+            instance()->d->mCallbacks.erase(it);
+            return;
+        }
+    }
+}
+
+void EventLoopInteractor::Private::eventIOCb(void *data, gpgme_event_io_t type, void *type_data)
+{
+    assert(instance());
+    Context *ctx = static_cast<Context *>(data);
+    switch (type) {
+    case GPGME_EVENT_START: {
+        instance()->operationStartEvent(ctx);
+        // TODO: what's in type_data?
+    }
+    break;
+    case GPGME_EVENT_DONE: {
+        gpgme_error_t e = *static_cast<gpgme_error_t *>(type_data);
+        if (ctx && ctx->impl()) {
+            ctx->impl()->lasterr = e;
+        }
+        instance()->operationDoneEvent(ctx, Error(e));
+    }
+    break;
+    case GPGME_EVENT_NEXT_KEY: {
+        gpgme_key_t key = static_cast<gpgme_key_t>(type_data);
+        instance()->nextKeyEvent(ctx, Key(key, false));
+    }
+    break;
+    case GPGME_EVENT_NEXT_TRUSTITEM: {
+        gpgme_trust_item_t item = static_cast<gpgme_trust_item_t>(type_data);
+        instance()->nextTrustItemEvent(ctx, TrustItem(item));
+        gpgme_trust_item_unref(item);
+    }
+    break;
+    default: // warn
+        ;
+    }
+}
+
+//
+// EventLoopInteractor Implementation
+//
+
+EventLoopInteractor *EventLoopInteractor::mSelf = 0;
+
+EventLoopInteractor::EventLoopInteractor() : d(new Private)
+{
+    assert(!mSelf);
+    mSelf = this;
+}
+
+EventLoopInteractor::~EventLoopInteractor()
+{
+    // warn if there are still callbacks registered
+    mSelf = 0;
+    delete d;
+}
+
+void EventLoopInteractor::manage(Context *context)
+{
+    if (!context || context->managedByEventLoopInteractor()) {
+        return;
+    }
+    gpgme_io_cbs *iocbs = new gpgme_io_cbs(Private::iocbs);
+    iocbs->event_priv = context;
+    context->installIOCallbacks(iocbs);
+}
+
+void EventLoopInteractor::unmanage(Context *context)
+{
+    if (context) {
+        context->uninstallIOCallbacks();
+    }
+}
+
+void EventLoopInteractor::actOn(int fd, Direction dir)
+{
+    for (vector<Private::OneFD *>::const_iterator it = d->mCallbacks.begin();
+            it != d->mCallbacks.end() ; ++it) {
+        if ((*it)->fd == fd && ((*it)->dir ? Read : Write) == dir) {
+            (*((*it)->fnc))((*it)->fncData, fd);
+            break;
+        }
+    }
+}
+
+} // namespace GpgME
diff --git a/lang/cpp/src/eventloopinteractor.h b/lang/cpp/src/eventloopinteractor.h
new file mode 100644 (file)
index 0000000..94821d6
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+  eventloopinteractor.h
+  Copyright (C) 2003,2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_EVENTLOOPINTERACTOR_H__
+#define __GPGMEPP_EVENTLOOPINTERACTOR_H__
+
+#include "gpgmepp_export.h"
+
+namespace GpgME
+{
+
+class Context;
+class Error;
+class TrustItem;
+class Key;
+
+/*! \file eventloopinteractor.h
+    \brief Abstract base class for gpgme's external event loop support
+
+    This class does most of the work involved with hooking GpgME++
+    up with external event loops, such as the GTK or Qt ones.
+
+    It actually provides two interfaces: An interface to the gpgme
+    IO Callback handling and one for gpgme events. The IO Callback
+    interface consists of the three methods \c actOn(), \c
+    registerWatcher() and \c unregisterWatcher(). The event
+    interface consists of the three methods \c nextTrustItemEvent(),
+    \c nextKeyEvent() and \c operationDoneEvent().
+
+    \sect General Usage
+
+    \c EventLoopInteractor is designed to be used as a
+    singleton. However, in order to make any use of it, you have to
+    subclass it and reimplement it's pure virtual methods (see
+    below). We suggest you keep the constructor protected and
+    provide a static \c instance() method that returns the single
+    instance. Alternatively, you can create an instance on the
+    stack, e.g. in \c main().
+
+    If you want \c EventLoopInteractor to manage a particular \c
+    Context, just call \c manage() on the \c Context. OTOH, if you
+    want to disable IO callbacks for a \c Context, use \c unmanage().
+
+    \sect IO Callback Interface
+
+    One part of this interface is represented by \c
+    registerWatcher() and \c unregisterWatcher(), both of which are
+    pure virtual. \c registerWatcher() should do anything necessary
+    to hook up watching of file descriptor \c fd for reading (\c dir
+    = \c Read) or writing (\c dir = Write) to the event loop you use
+    and return a tag identifying that particular watching process
+    uniquely. This could be the index into an array of objects you
+    use for that purpose or the address of such an object. E.g. in
+    Qt, you'd essentially just create a new \c QSocketNotifier:
+
+    \verbatim
+    void * registerWatcher( int fd, Direction dir ) {
+      return new QSocketNotifier( fd, dir == Read ? QSocketNotifier::Read : QSocketNotifier::Write );
+      // misses connecting to the activated() signal...
+    }
+    \endverbatim
+
+    which uses the address of the created object as unique tag. The
+    tag returned by \c registerWatcher is stored by \c
+    EventLoopInteractor and passed as argument to \c
+    unregisterWatcher(). So, in the picture above, you'd implement \c
+    unregisterWatcher() like this:
+
+    \verbatim
+    void unregisterWatcher( void * tag ) {
+      delete static_cast<QSocketNotifier*>( tag );
+    }
+    \endverbatim
+
+    The other part of the IO callback interface is \c actOn(), which
+    you should call if you receive notification from your event loop
+    about activity on file descriptor \c fd in direction \c dir. In
+    the picture above, you'd call this from the slot connected to
+    the socket notifier's \c activated() signal.
+
+    \note \c registerWatcher() as well as \c unregisterWatcher() may
+    be called from within \c actOn(), so be careful with
+    e.g. locking in threaded environments and keep in mind that the
+    object you used to find the \c fd and \c dir fo the \c actOn()
+    call might be deleted when \c actOn() returns!
+
+    \sect Event Handler Interface
+
+*/
+class GPGMEPP_EXPORT EventLoopInteractor
+{
+protected:
+    EventLoopInteractor();
+public:
+    virtual ~EventLoopInteractor();
+
+    static EventLoopInteractor *instance()
+    {
+        return mSelf;
+    }
+
+    void manage(Context *context);
+    void unmanage(Context *context);
+
+    enum Direction { Read, Write };
+protected:
+    //
+    // IO Notification Interface
+    //
+
+    /** Call this if your event loop detected activity on file
+        descriptor fd, with direction dir */
+    void actOn(int fd, Direction dir);
+
+    virtual void *registerWatcher(int fd, Direction dir, bool &ok) = 0;
+    virtual void unregisterWatcher(void *tag) = 0;
+
+    //
+    // Event Handler Interface
+    //
+
+    virtual void operationStartEvent(Context *context) = 0;
+    virtual void nextTrustItemEvent(Context *context, const TrustItem &item) = 0;
+    virtual void nextKeyEvent(Context *context, const Key &key) = 0;
+    virtual void operationDoneEvent(Context *context, const Error &e) = 0;
+
+private:
+    class Private;
+    friend class Private;
+    Private *const d;
+    static EventLoopInteractor *mSelf;
+};
+
+}
+
+#endif // __GPGMEPP_EVENTLOOPINTERACTOR_H__
diff --git a/lang/cpp/src/exception.cpp b/lang/cpp/src/exception.cpp
new file mode 100644 (file)
index 0000000..c687024
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  exception.cpp - exception wrapping a gpgme error
+  Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#include "exception.h"
+
+#include <gpgme.h>
+
+#include <sstream>
+
+using namespace GpgME;
+using namespace std; // only safe b/c it's so small a file!
+
+Exception::~Exception() throw() {}
+
+// static
+string Exception::make_message(const Error &err, const string &msg)
+{
+    return make_message(err, msg, NoOptions);
+}
+
+// static
+string Exception::make_message(const Error &err, const string &msg, Options opt)
+{
+    if (opt & MessageOnly) {
+        return msg;
+    }
+    char error_string[128];
+    error_string[0] = '\0';
+    gpgme_strerror_r(err.encodedError(), error_string, sizeof error_string);
+    error_string[sizeof error_string - 1] = '\0';
+    stringstream ss;
+    ss << gpgme_strsource(err.encodedError()) << ": ";
+    if (!msg.empty()) {
+        ss << msg << ": ";
+    }
+    ss << error_string << " (" << static_cast<unsigned long>(err.encodedError()) << ')';
+    return ss.str();
+}
diff --git a/lang/cpp/src/exception.h b/lang/cpp/src/exception.h
new file mode 100644 (file)
index 0000000..8f40b0e
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+  exception.h - exception wrapping a gpgme error
+  Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_EXCEPTION_H__
+#define __GPGMEPP_EXCEPTION_H__
+
+#include "error.h"
+
+#include <stdexcept>
+#include <string>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT Exception : public std::runtime_error
+{
+public:
+    enum Options {
+        NoOptions = 0x0,
+        MessageOnly = 0x1,
+
+        AllOptions = MessageOnly
+    };
+
+    explicit Exception(const GpgME::Error &err, const std::string &msg = std::string(), Options opt = NoOptions)
+        : std::runtime_error(make_message(err, msg, opt)), m_error(err), m_message(msg) {}
+
+    ~Exception() throw();
+
+    Error error() const
+    {
+        return m_error;
+    }
+    const std::string &message() const
+    {
+        return m_message;
+    }
+private:
+    static std::string make_message(const GpgME::Error &err, const std::string &msg);
+    static std::string make_message(const GpgME::Error &err, const std::string &msg, Options opt);
+private:
+    const GpgME::Error m_error;
+    const std::string m_message;
+};
+
+} // namespace GpgME
+
+#endif /* __GPGMEPP_EXCEPTION_H__ */
diff --git a/lang/cpp/src/global.h b/lang/cpp/src/global.h
new file mode 100644 (file)
index 0000000..f65503a
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+  global.h - global gpgme functions and enums
+  Copyright (C) 2003, 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_GLOBAL_H__
+#define __GPGMEPP_GLOBAL_H__
+
+#include "gpgmefw.h"
+#include "gpgmepp_export.h"
+
+#include <iosfwd>
+#include <QByteArray>
+
+namespace GpgME
+{
+class Error;
+class EngineInfo;
+class Context;
+}
+
+struct _GIOChannel;
+typedef struct _GIOChannel      GIOChannel;
+class QIODevice;
+
+namespace GpgME
+{
+
+GPGMEPP_EXPORT void initializeLibrary();
+/*!
+  Initializes the library, returns Error::code() ==
+  GPG_ERR_USER_1 if underlying gpgme is too old.
+*/
+GPGMEPP_EXPORT Error initializeLibrary(int);
+
+enum Protocol { OpenPGP, CMS, UnknownProtocol };
+
+enum Engine { GpgEngine, GpgSMEngine, GpgConfEngine, UnknownEngine, AssuanEngine, G13Engine };
+
+enum KeyListMode {
+    Local = 0x1,
+    Extern = 0x2,
+    Signatures = 0x4,
+    SignatureNotations = 0x8,
+    Validate = 0x10,
+    Ephemeral = 0x20
+};
+
+enum SignatureMode { NormalSignatureMode, Detached, Clearsigned };
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Protocol proto);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Engine eng);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, KeyListMode mode);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, SignatureMode mode);
+
+GPGMEPP_EXPORT Error setDefaultLocale(int category, const char *value);
+
+GPGMEPP_EXPORT Context *wait(Error &e, bool hang = true);
+typedef void (*IdleFunction)(void);
+GPGMEPP_EXPORT IdleFunction registerIdleFunction(IdleFunction idleFunction);
+
+typedef void (*IOCallback)(void *data, int fd);
+
+GPGMEPP_EXPORT EngineInfo engineInfo(Protocol proto);
+GPGMEPP_EXPORT EngineInfo engineInfo(Engine engine);
+
+GPGMEPP_EXPORT Error checkEngine(Protocol proto);
+GPGMEPP_EXPORT Error checkEngine(Engine engine);
+
+GPGMEPP_EXPORT GIOChannel *getGIOChannel(int fd);
+GPGMEPP_EXPORT QIODevice   *getQIODevice(int fd);
+
+enum Feature {
+    ValidatingKeylistModeFeature               = 0x00000001,
+    CancelOperationFeature                     = 0x00000002,
+    WrongKeyUsageFeature                       = 0x00000004,
+    DefaultCertificateInclusionFeature         = 0x00000008,
+
+    GetSetEngineInfoFeature                    = 0x00000010,
+    EngineInfoHomeDirFeature                   = 0x00000020,
+    NoEncryptToEncryptionFlagFeature           = 0x00000040,
+    EphemeralKeylistModeFeature                = 0x00000080,
+
+    SetDataFileNameFeeature                    = 0x00000100,
+    VerificationResultFileNameFeature          = 0x00000200,
+    DecryptionResultFileNameFeature            = 0x00000400,
+    DecryptionResultRecipientsFeature          = 0x00000800,
+
+    AuditLogFeature                            = 0x00001000,
+    GpgConfEngineFeature                       = 0x00002000,
+    CancelOperationAsyncFeature                = 0x00004000,
+    AssuanEngineFeature                        = 0x00008000,
+
+    ClearAddGetSignatureNotationsFeature       = 0x00010000,
+    SignatureNotationsKeylistModeFeature       = 0x00020000,
+    KeySignatureNotationsFeature               = 0x00040000,
+    SignatureNotationsFlagsFeature             = 0x00080000,
+    SignatureNotationsCriticalFlagFeature      = 0x00100000,
+    SignatureNotationsHumanReadableFlagFeature = 0x00200000,
+    CardKeyFeature                             = 0x00400000,
+    ImportFromKeyserverFeature                 = 0x00800000,
+
+    KeyIsQualifiedFeature                      = 0x01000200,
+    SubkeyIsQualifiedFeature                   = 0x02000000,
+    SignaturePkaFieldsFeature                  = 0x04000000,
+    SignatureAlgorithmFieldsFeature            = 0x08000000,
+
+    FdPointerFeature                           = 0x10000000,
+    G13VFSFeature                              = 0x20000000,
+    PasswdFeature                              = 0x40000000, // gpgme >= 1.3.0
+    // unusable (max value)
+
+    FeatureMaxValue                            = 0x80000000
+};
+enum Feature2 {
+    Feature2MaxValue                           = 0x80000000
+};
+// use hasFeature( unsigned long, unsigned long ) instead
+GPGMEPP_DEPRECATED_EXPORT bool hasFeature(unsigned long feature);
+GPGMEPP_EXPORT bool hasFeature(unsigned long feature, unsigned long feature2);
+
+} // namespace GpgME
+
+# ifndef GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION
+#  define GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION( Class ) \
+    namespace std { template <> inline void swap< GpgME::Class >( GpgME::Class & lhs, GpgME::Class & rhs ) { lhs.swap( rhs ); } }
+# endif
+
+# ifndef GPGMEPP_MAKE_SAFE_BOOL_OPERATOR
+#  define GPGMEPP_MAKE_SAFE_BOOL_OPERATOR( Cond ) \
+    private: \
+    struct __safe_bool_dummy__ { void nonnull() {} }; \
+    typedef void ( __safe_bool_dummy__::*unspecified_bool_type )(); \
+    public: \
+    operator unspecified_bool_type() const { return ( Cond ) ? &__safe_bool_dummy__::nonnull : 0 ; }
+# endif
+
+#endif // __GPGMEPP_GLOBAL_H__
diff --git a/lang/cpp/src/gpgadduserideditinteractor.cpp b/lang/cpp/src/gpgadduserideditinteractor.cpp
new file mode 100644 (file)
index 0000000..43c8592
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+  gpgadduserideditinteractor.cpp - Edit Interactor to add a new UID to an OpenPGP key
+  Copyright (C) 2008 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "gpgadduserideditinteractor.h"
+
+#include "error.h"
+
+#include <gpgme.h>
+
+#include <cstring>
+
+using std::strcmp;
+
+// avoid conflict (msvc)
+#ifdef ERROR
+# undef ERROR
+#endif
+
+using namespace GpgME;
+
+GpgAddUserIDEditInteractor::GpgAddUserIDEditInteractor()
+    : EditInteractor(),
+      m_name(),
+      m_email(),
+      m_comment()
+{
+
+}
+
+GpgAddUserIDEditInteractor::~GpgAddUserIDEditInteractor() {}
+
+void GpgAddUserIDEditInteractor::setNameUtf8(const std::string &name)
+{
+    m_name = name;
+}
+
+void GpgAddUserIDEditInteractor::setEmailUtf8(const std::string &email)
+{
+    m_email = email;
+}
+
+void GpgAddUserIDEditInteractor::setCommentUtf8(const std::string &comment)
+{
+    m_comment = comment;
+}
+
+// work around --enable-final
+namespace GpgAddUserIDEditInteractor_Private
+{
+enum {
+    START = EditInteractor::StartState,
+    COMMAND,
+    NAME,
+    EMAIL,
+    COMMENT,
+    QUIT,
+    SAVE,
+
+    ERROR = EditInteractor::ErrorState
+};
+}
+
+const char *GpgAddUserIDEditInteractor::action(Error &err) const
+{
+
+    using namespace GpgAddUserIDEditInteractor_Private;
+
+    switch (state()) {
+    case COMMAND:
+        return "adduid";
+    case NAME:
+        return m_name.c_str();
+    case EMAIL:
+        return m_email.c_str();
+    case COMMENT:
+        return m_comment.c_str();
+    case QUIT:
+        return "quit";
+    case SAVE:
+        return "Y";
+    case START:
+    case ERROR:
+        return 0;
+    default:
+        err = Error::fromCode(GPG_ERR_GENERAL);
+        return 0;
+    }
+}
+
+unsigned int GpgAddUserIDEditInteractor::nextState(unsigned int status, const char *args, Error &err) const
+{
+
+    static const Error GENERAL_ERROR     = Error::fromCode(GPG_ERR_GENERAL);
+    static const Error INV_NAME_ERROR    = Error::fromCode(GPG_ERR_INV_NAME);
+    static const Error INV_EMAIL_ERROR   = Error::fromCode(GPG_ERR_INV_USER_ID);
+    static const Error INV_COMMENT_ERROR = Error::fromCode(GPG_ERR_INV_USER_ID);
+
+    if (needsNoResponse(status)) {
+        return state();
+    }
+
+    using namespace GpgAddUserIDEditInteractor_Private;
+
+    switch (state()) {
+    case START:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keyedit.prompt") == 0) {
+            return COMMAND;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case COMMAND:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keygen.name") == 0) {
+            return NAME;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case NAME:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keygen.email") == 0) {
+            return EMAIL;
+        }
+        err = GENERAL_ERROR;
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keygen.name") == 0) {
+            err = INV_NAME_ERROR;
+        }
+        return ERROR;
+    case EMAIL:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keygen.comment") == 0) {
+            return COMMENT;
+        }
+        err = GENERAL_ERROR;
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keygen.email") == 0) {
+            err = INV_EMAIL_ERROR;
+        }
+        return ERROR;
+    case COMMENT:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keyedit.prompt") == 0) {
+            return QUIT;
+        }
+        err = GENERAL_ERROR;
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keygen.comment") == 0) {
+            err = INV_COMMENT_ERROR;
+        }
+        return ERROR;
+    case QUIT:
+        if (status == GPGME_STATUS_GET_BOOL &&
+                strcmp(args, "keyedit.save.okay") == 0) {
+            return SAVE;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case ERROR:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keyedit.prompt") == 0) {
+            return QUIT;
+        }
+        err = lastError();
+        return ERROR;
+    default:
+        err = GENERAL_ERROR;
+        return ERROR;
+    }
+}
diff --git a/lang/cpp/src/gpgadduserideditinteractor.h b/lang/cpp/src/gpgadduserideditinteractor.h
new file mode 100644 (file)
index 0000000..12b6e46
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+  gpgadduserideditinteractor.h - Edit Interactor to add a new UID to an OpenPGP key
+  Copyright (C) 2008 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_GPGADDUSERIDEDITINTERACTOR_H__
+#define __GPGMEPP_GPGADDUSERIDEDITINTERACTOR_H__
+
+#include <editinteractor.h>
+
+#include <string>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT GpgAddUserIDEditInteractor : public EditInteractor
+{
+public:
+    explicit GpgAddUserIDEditInteractor();
+    ~GpgAddUserIDEditInteractor();
+
+    void setNameUtf8(const std::string &name);
+    const std::string &nameUtf8() const
+    {
+        return m_name;
+    }
+
+    void setEmailUtf8(const std::string &email);
+    const std::string &emailUtf8() const
+    {
+        return m_email;
+    }
+
+    void setCommentUtf8(const std::string &comment);
+    const std::string &commentUtf8() const
+    {
+        return m_comment;
+    }
+
+private:
+    /* reimp */ const char *action(Error &err) const;
+    /* reimp */ unsigned int nextState(unsigned int statusCode, const char *args, Error &err) const;
+
+private:
+    std::string m_name, m_email, m_comment;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_GPGADDUSERIDEDITINTERACTOR_H__
diff --git a/lang/cpp/src/gpgagentgetinfoassuantransaction.cpp b/lang/cpp/src/gpgagentgetinfoassuantransaction.cpp
new file mode 100644 (file)
index 0000000..e07a856
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+  gpgagentgetinfoassuantransaction.cpp - Assuan Transaction to get information from gpg-agent
+  Copyright (C) 2009 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include "gpgagentgetinfoassuantransaction.h"
+#include "error.h"
+#include "data.h"
+#include "util.h"
+
+#include <boost/static_assert.hpp>
+
+#include <sstream>
+
+using namespace GpgME;
+using namespace boost;
+
+GpgAgentGetInfoAssuanTransaction::GpgAgentGetInfoAssuanTransaction(InfoItem item)
+    : AssuanTransaction(),
+      m_item(item),
+      m_command(),
+      m_data()
+{
+
+}
+
+GpgAgentGetInfoAssuanTransaction::~GpgAgentGetInfoAssuanTransaction() {}
+
+std::string GpgAgentGetInfoAssuanTransaction::version() const
+{
+    if (m_item == Version) {
+        return m_data;
+    } else {
+        return std::string();
+    }
+}
+
+unsigned int GpgAgentGetInfoAssuanTransaction::pid() const
+{
+    if (m_item == Pid) {
+        return to_pid(m_data);
+    } else {
+        return 0U;
+    }
+}
+
+std::string GpgAgentGetInfoAssuanTransaction::socketName() const
+{
+    if (m_item == SocketName) {
+        return m_data;
+    } else {
+        return std::string();
+    }
+}
+
+std::string GpgAgentGetInfoAssuanTransaction::sshSocketName() const
+{
+    if (m_item == SshSocketName) {
+        return m_data;
+    } else {
+        return std::string();
+    }
+}
+
+static const char *const gpgagent_getinfo_tokens[] = {
+    "version",
+    "pid",
+    "socket_name",
+    "ssh_socket_name",
+    "scd_running",
+};
+BOOST_STATIC_ASSERT((sizeof gpgagent_getinfo_tokens / sizeof * gpgagent_getinfo_tokens == GpgAgentGetInfoAssuanTransaction::LastInfoItem));
+
+void GpgAgentGetInfoAssuanTransaction::makeCommand() const
+{
+    assert(m_item >= 0);
+    assert(m_item < LastInfoItem);
+    m_command = "GETINFO ";
+    m_command += gpgagent_getinfo_tokens[m_item];
+}
+
+const char *GpgAgentGetInfoAssuanTransaction::command() const
+{
+    makeCommand();
+    return m_command.c_str();
+}
+
+Error GpgAgentGetInfoAssuanTransaction::data(const char *data, size_t len)
+{
+    m_data.append(data, len);
+    return Error();
+}
+
+Data GpgAgentGetInfoAssuanTransaction::inquire(const char *name, const char *args, Error &err)
+{
+    (void)name; (void)args; (void)err;
+    return Data::null;
+}
+
+Error GpgAgentGetInfoAssuanTransaction::status(const char *status, const char *args)
+{
+    (void)status; (void)args;
+    return Error();
+}
diff --git a/lang/cpp/src/gpgagentgetinfoassuantransaction.h b/lang/cpp/src/gpgagentgetinfoassuantransaction.h
new file mode 100644 (file)
index 0000000..9e3e958
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+  gpgagentgetinfoassuantransaction.h - Assuan Transaction to get information from gpg-agent
+  Copyright (C) 2009 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_GPGAGENTGETINFOASSUANTRANSACTION_H__
+#define __GPGMEPP_GPGAGENTGETINFOASSUANTRANSACTION_H__
+
+#include <interfaces/assuantransaction.h>
+
+#include <string>
+#include <vector>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT GpgAgentGetInfoAssuanTransaction : public AssuanTransaction
+{
+public:
+    enum InfoItem {
+        Version,         // string
+        Pid,             // unsigned long
+        SocketName,      // string (path)
+        SshSocketName,   // string (path)
+        ScdRunning,      // (none, returns GPG_ERR_GENERAL when scdaemon isn't running)
+        //CommandHasOption, // not supported
+
+        LastInfoItem
+    };
+
+    explicit GpgAgentGetInfoAssuanTransaction(InfoItem item);
+    ~GpgAgentGetInfoAssuanTransaction();
+
+    std::string version() const;
+    unsigned int pid() const;
+    std::string socketName() const;
+    std::string sshSocketName() const;
+
+private:
+    /* reimp */ const char *command() const;
+    /* reimp */ Error data(const char *data, size_t datalen);
+    /* reimp */ Data inquire(const char *name, const char *args, Error &err);
+    /* reimp */ Error status(const char *status, const char *args);
+
+private:
+    void makeCommand() const;
+
+private:
+    InfoItem m_item;
+    mutable std::string m_command;
+    std::string m_data;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_GPGAGENTGETINFOASSUANTRANSACTION_H__
diff --git a/lang/cpp/src/gpgmefw.h b/lang/cpp/src/gpgmefw.h
new file mode 100644 (file)
index 0000000..cbdd444
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+  gpgmefw.h - Forwards declarations for gpgme (0.3 and 0.4)
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_GPGMEFW_H__
+#define __GPGMEPP_GPGMEFW_H__
+
+struct gpgme_context;
+typedef gpgme_context *gpgme_ctx_t;
+
+struct gpgme_data;
+typedef gpgme_data *gpgme_data_t;
+
+struct gpgme_io_cbs;
+
+struct _gpgme_key;
+typedef struct _gpgme_key *gpgme_key_t;
+
+struct _gpgme_trust_item;
+typedef struct _gpgme_trust_item *gpgme_trust_item_t;
+
+struct _gpgme_subkey;
+typedef struct _gpgme_subkey *gpgme_sub_key_t;
+
+struct _gpgme_user_id;
+typedef struct _gpgme_user_id *gpgme_user_id_t;
+
+struct _gpgme_key_sig;
+typedef struct _gpgme_key_sig *gpgme_key_sig_t;
+
+struct _gpgme_sig_notation;
+typedef struct _gpgme_sig_notation *gpgme_sig_notation_t;
+
+struct _gpgme_engine_info;
+typedef struct _gpgme_engine_info *gpgme_engine_info_t;
+
+struct _gpgme_op_keylist_result;
+typedef struct _gpgme_op_keylist_result *gpgme_keylist_result_t;
+
+struct _gpgme_recipient;
+typedef struct _gpgme_recipient *gpgme_recipient_t;
+
+struct gpgme_conf_opt;
+typedef struct gpgme_conf_opt *gpgme_conf_opt_t;
+
+struct gpgme_conf_comp;
+typedef struct gpgme_conf_comp *gpgme_conf_comp_t;
+
+struct gpgme_conf_arg;
+typedef struct gpgme_conf_arg *gpgme_conf_arg_t;
+
+#endif // __GPGMEPP_GPGMEFW_H__
diff --git a/lang/cpp/src/gpgmepp_export.h b/lang/cpp/src/gpgmepp_export.h
new file mode 100644 (file)
index 0000000..50a288d
--- /dev/null
@@ -0,0 +1,41 @@
+
+#ifndef GPGMEPP_EXPORT_H
+#define GPGMEPP_EXPORT_H
+
+#ifdef GPGMEPP_STATIC_DEFINE
+#  define GPGMEPP_EXPORT
+#  define GPGMEPP_NO_EXPORT
+#else
+#  ifndef GPGMEPP_EXPORT
+#    ifdef KF5Gpgmepp_EXPORTS
+        /* We are building this library */
+#      define GPGMEPP_EXPORT __attribute__((visibility("default")))
+#    else
+        /* We are using this library */
+#      define GPGMEPP_EXPORT __attribute__((visibility("default")))
+#    endif
+#  endif
+
+#  ifndef GPGMEPP_NO_EXPORT
+#    define GPGMEPP_NO_EXPORT __attribute__((visibility("hidden")))
+#  endif
+#endif
+
+#ifndef GPGMEPP_DEPRECATED
+#  define GPGMEPP_DEPRECATED __attribute__ ((__deprecated__))
+#endif
+
+#ifndef GPGMEPP_DEPRECATED_EXPORT
+#  define GPGMEPP_DEPRECATED_EXPORT GPGMEPP_EXPORT GPGMEPP_DEPRECATED
+#endif
+
+#ifndef GPGMEPP_DEPRECATED_NO_EXPORT
+#  define GPGMEPP_DEPRECATED_NO_EXPORT GPGMEPP_NO_EXPORT GPGMEPP_DEPRECATED
+#endif
+
+#define DEFINE_NO_DEPRECATED 0
+#if DEFINE_NO_DEPRECATED
+# define GPGMEPP_NO_DEPRECATED
+#endif
+
+#endif
diff --git a/lang/cpp/src/gpgsetexpirytimeeditinteractor.cpp b/lang/cpp/src/gpgsetexpirytimeeditinteractor.cpp
new file mode 100644 (file)
index 0000000..8af897c
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+  gpgsetexpirytimeeditinteractor.cpp - Edit Interactor to change the expiry time of an OpenPGP key
+  Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "gpgsetexpirytimeeditinteractor.h"
+#include "error.h"
+
+#include <gpgme.h>
+
+#include <cstring>
+
+using std::strcmp;
+
+// avoid conflict (msvc)
+#ifdef ERROR
+# undef ERROR
+#endif
+
+using namespace GpgME;
+
+GpgSetExpiryTimeEditInteractor::GpgSetExpiryTimeEditInteractor(const std::string &t)
+    : EditInteractor(),
+      m_strtime(t)
+{
+
+}
+
+GpgSetExpiryTimeEditInteractor::~GpgSetExpiryTimeEditInteractor() {}
+
+// work around --enable-final
+namespace GpgSetExpiryTimeEditInteractor_Private
+{
+enum {
+    START = EditInteractor::StartState,
+    COMMAND,
+    DATE,
+    QUIT,
+    SAVE,
+
+    ERROR = EditInteractor::ErrorState
+};
+}
+
+const char *GpgSetExpiryTimeEditInteractor::action(Error &err) const
+{
+
+    using namespace GpgSetExpiryTimeEditInteractor_Private;
+
+    switch (state()) {
+    case COMMAND:
+        return "expire";
+    case DATE:
+        return m_strtime.c_str();
+    case QUIT:
+        return "quit";
+    case SAVE:
+        return "Y";
+    case START:
+    case ERROR:
+        return 0;
+    default:
+        err = Error::fromCode(GPG_ERR_GENERAL);
+        return 0;
+    }
+}
+
+unsigned int GpgSetExpiryTimeEditInteractor::nextState(unsigned int status, const char *args, Error &err) const
+{
+
+    static const Error GENERAL_ERROR  = Error::fromCode(GPG_ERR_GENERAL);
+    static const Error INV_TIME_ERROR = Error::fromCode(GPG_ERR_INV_TIME);
+
+    if (needsNoResponse(status)) {
+        return state();
+    }
+
+    using namespace GpgSetExpiryTimeEditInteractor_Private;
+
+    switch (state()) {
+    case START:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keyedit.prompt") == 0) {
+            return COMMAND;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case COMMAND:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keygen.valid") == 0) {
+            return DATE;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case DATE:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keyedit.prompt") == 0) {
+            return QUIT;
+        } else if (status == GPGME_STATUS_GET_LINE &&
+                   strcmp(args, "keygen.valid")) {
+            err = INV_TIME_ERROR;
+            return ERROR;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case QUIT:
+        if (status == GPGME_STATUS_GET_BOOL &&
+                strcmp(args, "keyedit.save.okay") == 0) {
+            return SAVE;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case ERROR:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keyedit.prompt") == 0) {
+            return QUIT;
+        }
+        err = lastError();
+        return ERROR;
+    default:
+        err = GENERAL_ERROR;
+        return ERROR;
+    }
+}
diff --git a/lang/cpp/src/gpgsetexpirytimeeditinteractor.h b/lang/cpp/src/gpgsetexpirytimeeditinteractor.h
new file mode 100644 (file)
index 0000000..670b445
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+  gpgsetexpirytimeeditinteractor.h - Edit Interactor to change the expiry time of an OpenPGP key
+  Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_GPGSETEXPIRYTIMEEDITINTERACTOR_H__
+#define __GPGMEPP_GPGSETEXPIRYTIMEEDITINTERACTOR_H__
+
+#include <editinteractor.h>
+
+#include <string>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT GpgSetExpiryTimeEditInteractor : public EditInteractor
+{
+public:
+    explicit GpgSetExpiryTimeEditInteractor(const std::string &timeString = "0");
+    ~GpgSetExpiryTimeEditInteractor();
+
+private:
+    /* reimp */ const char *action(Error &err) const;
+    /* reimp */ unsigned int nextState(unsigned int statusCode, const char *args, Error &err) const;
+
+private:
+    const std::string m_strtime;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_GPGSETEXPIRYTIMEEDITINTERACTOR_H___
diff --git a/lang/cpp/src/gpgsetownertrusteditinteractor.cpp b/lang/cpp/src/gpgsetownertrusteditinteractor.cpp
new file mode 100644 (file)
index 0000000..15b1269
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+  gpgsetownertrusteditinteractor.cpp - Edit Interactor to change the expiry time of an OpenPGP key
+  Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "gpgsetownertrusteditinteractor.h"
+#include "error.h"
+
+#include <gpgme.h>
+
+#include <cstring>
+
+using std::strcmp;
+
+// avoid conflict (msvc)
+#ifdef ERROR
+# undef ERROR
+#endif
+
+using namespace GpgME;
+
+GpgSetOwnerTrustEditInteractor::GpgSetOwnerTrustEditInteractor(Key::OwnerTrust ot)
+    : EditInteractor(),
+      m_ownertrust(ot)
+{
+
+}
+
+GpgSetOwnerTrustEditInteractor::~GpgSetOwnerTrustEditInteractor() {}
+
+// work around --enable-final
+namespace GpgSetOwnerTrustEditInteractor_Private
+{
+enum {
+    START = EditInteractor::StartState,
+    COMMAND,
+    VALUE,
+    REALLY_ULTIMATE,
+    QUIT,
+    SAVE,
+
+    ERROR = EditInteractor::ErrorState
+};
+}
+
+const char *GpgSetOwnerTrustEditInteractor::action(Error &err) const
+{
+    static const char truststrings[][2] = { "1", "1", "2", "3", "4", "5" };
+
+    using namespace GpgSetOwnerTrustEditInteractor_Private;
+
+    switch (state()) {
+    case COMMAND:
+        return "trust";
+    case VALUE:
+        return truststrings[m_ownertrust];
+    case REALLY_ULTIMATE:
+        return "Y";
+    case QUIT:
+        return "quit";
+    case SAVE:
+        return "Y";
+    case START:
+    case ERROR:
+        return 0;
+    default:
+        err = Error::fromCode(GPG_ERR_GENERAL);
+        return 0;
+    }
+}
+
+unsigned int GpgSetOwnerTrustEditInteractor::nextState(unsigned int status, const char *args, Error &err) const
+{
+
+    static const Error GENERAL_ERROR = Error::fromCode(GPG_ERR_GENERAL);
+    //static const Error INV_TIME_ERROR = Error::fromCode( GPG_ERR_INV_TIME );
+
+    if (needsNoResponse(status)) {
+        return state();
+    }
+
+    using namespace GpgSetOwnerTrustEditInteractor_Private;
+
+    switch (state()) {
+    case START:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keyedit.prompt") == 0) {
+            return COMMAND;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case COMMAND:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "edit_ownertrust.value") == 0) {
+            return VALUE;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case VALUE:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keyedit.prompt") == 0) {
+            return QUIT;
+        } else if (status == GPGME_STATUS_GET_BOOL &&
+                   strcmp(args, "edit_ownertrust.set_ultimate.okay") == 0) {
+            return REALLY_ULTIMATE;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case REALLY_ULTIMATE:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keyedit.prompt") == 0) {
+            return QUIT;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case QUIT:
+        if (status == GPGME_STATUS_GET_BOOL &&
+                strcmp(args, "keyedit.save.okay") == 0) {
+            return SAVE;
+        }
+        err = GENERAL_ERROR;
+        return ERROR;
+    case ERROR:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keyedit.prompt") == 0) {
+            return QUIT;
+        }
+        err = lastError();
+        return ERROR;
+    default:
+        err = GENERAL_ERROR;
+        return ERROR;
+    };
+}
diff --git a/lang/cpp/src/gpgsetownertrusteditinteractor.h b/lang/cpp/src/gpgsetownertrusteditinteractor.h
new file mode 100644 (file)
index 0000000..caf29ee
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+  gpgsetownertrusteditinteractor.h - Edit Interactor to change the owner trust of an OpenPGP key
+  Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_GPGSETOWNERTRUSTEDITINTERACTOR_H__
+#define __GPGMEPP_GPGSETOWNERTRUSTEDITINTERACTOR_H__
+
+#include <editinteractor.h>
+#include <key.h>
+
+#include <string>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT GpgSetOwnerTrustEditInteractor : public EditInteractor
+{
+public:
+    explicit GpgSetOwnerTrustEditInteractor(Key::OwnerTrust ownertrust);
+    ~GpgSetOwnerTrustEditInteractor();
+
+private:
+    /* reimp */ const char *action(Error &err) const;
+    /* reimp */ unsigned int nextState(unsigned int statusCode, const char *args, Error &err) const;
+
+private:
+    const Key::OwnerTrust m_ownertrust;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_GPGSETOWNERTRUSTEDITINTERACTOR_H__
diff --git a/lang/cpp/src/gpgsignkeyeditinteractor.cpp b/lang/cpp/src/gpgsignkeyeditinteractor.cpp
new file mode 100644 (file)
index 0000000..1950b2f
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+  gpgsignkeyeditinteractor.cpp - Edit Interactor to change the expiry time of an OpenPGP key
+  Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "gpgsignkeyeditinteractor.h"
+#include "error.h"
+#include "key.h"
+
+#include <gpgme.h>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+
+#include <map>
+#include <string>
+#include <sstream>
+
+#include <cassert>
+#include <cstring>
+
+using std::strcmp;
+
+// avoid conflict (msvc)
+#ifdef ERROR
+# undef ERROR
+#endif
+
+#ifdef _MSC_VER
+#undef snprintf
+#define snprintf _snprintf
+#endif
+
+using namespace boost;
+using namespace GpgME;
+
+class GpgSignKeyEditInteractor::Private
+{
+public:
+    Private();
+
+    std::string scratch;
+    bool started;
+    int options;
+    std::vector<unsigned int> userIDs;
+    std::vector<unsigned int>::const_iterator currentId, nextId;
+    unsigned int checkLevel;
+
+    const char *command() const
+    {
+        const bool local = (options & Exportable) == 0;
+        const bool nonRevoc = options & NonRevocable;
+        const bool trust = options & Trust;
+        //TODO: check if all combinations are valid
+        if (local && nonRevoc && trust) {
+            return "ltnrsign";
+        }
+        if (local && nonRevoc) {
+            return "lnrsign";
+        }
+        if (local && trust) {
+            return "ltsign";
+        }
+        if (local) {
+            return "lsign";
+        }
+        if (nonRevoc && trust) {
+            return "tnrsign";
+        }
+        if (nonRevoc) {
+            return "nrsign";
+        }
+        if (trust) {
+            return "tsign";
+        }
+        return "sign";
+    }
+
+    bool signAll() const
+    {
+        return userIDs.empty();
+    }
+    unsigned int nextUserID()
+    {
+        assert(nextId != userIDs.end());
+        currentId = nextId++;
+        return currentUserID();
+    }
+
+    bool allUserIDsListed() const
+    {
+        return nextId == userIDs.end();
+    }
+
+    unsigned int currentUserID() const
+    {
+        assert(currentId != userIDs.end());
+        return *currentId + 1;
+    }
+
+};
+
+GpgSignKeyEditInteractor::Private::Private()
+    :
+    started(false),
+    options(0),
+    userIDs(),
+    currentId(),
+    nextId(),
+    checkLevel(0)
+{
+}
+
+GpgSignKeyEditInteractor::GpgSignKeyEditInteractor()
+    : EditInteractor(), d(new Private)
+{
+
+}
+
+GpgSignKeyEditInteractor::~GpgSignKeyEditInteractor()
+{
+    delete d;
+}
+
+// work around --enable-final
+namespace GpgSignKeyEditInteractor_Private
+{
+enum SignKeyState {
+    START = EditInteractor::StartState,
+    COMMAND,
+    UIDS_ANSWER_SIGN_ALL,
+    UIDS_LIST_SEPARATELY,
+    // all these free slots belong to UIDS_LIST_SEPARATELY, too
+    // (we increase state() by one for each UID, so that action() is called)
+    UIDS_LIST_SEPARATELY_DONE = 1000000,
+    SET_EXPIRE,
+    SET_CHECK_LEVEL,
+    SET_TRUST_VALUE,
+    SET_TRUST_DEPTH,
+    SET_TRUST_REGEXP,
+    CONFIRM,
+    QUIT,
+    SAVE,
+    ERROR = EditInteractor::ErrorState
+};
+
+typedef std::map<tuple<SignKeyState, unsigned int, std::string>, SignKeyState> TransitionMap;
+
+}
+
+static const char *answer(bool b)
+{
+    return b ? "Y" : "N";
+}
+
+static GpgSignKeyEditInteractor_Private::TransitionMap makeTable()
+{
+    using namespace GpgSignKeyEditInteractor_Private;
+    TransitionMap tab;
+    const unsigned int GET_BOOL = GPGME_STATUS_GET_BOOL;
+    const unsigned int GET_LINE = GPGME_STATUS_GET_LINE;
+#define addEntry( s1, status, str, s2 ) tab[make_tuple( s1, status, str)] = s2
+    addEntry(START, GET_LINE, "keyedit.prompt", COMMAND);
+    addEntry(COMMAND, GET_BOOL, "keyedit.sign_all.okay", UIDS_ANSWER_SIGN_ALL);
+    addEntry(COMMAND, GET_BOOL, "sign_uid.okay", CONFIRM);
+    addEntry(UIDS_ANSWER_SIGN_ALL, GET_BOOL, "sign_uid.okay", CONFIRM);
+    addEntry(UIDS_ANSWER_SIGN_ALL, GET_LINE, "sign_uid.expire", SET_EXPIRE);
+    addEntry(UIDS_ANSWER_SIGN_ALL, GET_LINE, "sign_uid.class", SET_CHECK_LEVEL);
+    addEntry(SET_TRUST_VALUE, GET_LINE, "trustsign_prompt.trust_depth", SET_TRUST_DEPTH);
+    addEntry(SET_TRUST_DEPTH, GET_LINE, "trustsign_prompt.trust_regexp", SET_TRUST_REGEXP);
+    addEntry(SET_TRUST_REGEXP, GET_LINE, "sign_uid.okay", CONFIRM);
+    addEntry(SET_CHECK_LEVEL, GET_BOOL, "sign_uid.okay", CONFIRM);
+    addEntry(SET_EXPIRE, GET_BOOL, "sign_uid.class", SET_CHECK_LEVEL);
+    addEntry(CONFIRM, GET_BOOL, "sign_uid.local_promote_okay", CONFIRM);
+    addEntry(CONFIRM, GET_BOOL, "sign_uid.okay", CONFIRM);
+    addEntry(CONFIRM, GET_LINE, "keyedit.prompt", COMMAND);
+    addEntry(CONFIRM, GET_LINE, "trustsign_prompt.trust_value", SET_TRUST_VALUE);
+    addEntry(CONFIRM, GET_LINE, "sign_uid.expire", SET_EXPIRE);
+    addEntry(CONFIRM, GET_LINE, "sign_uid.class", SET_CHECK_LEVEL);
+    addEntry(UIDS_LIST_SEPARATELY_DONE, GET_BOOL, "sign_uid.local_promote_okay", CONFIRM);
+    addEntry(UIDS_LIST_SEPARATELY_DONE, GET_LINE, "keyedit.prompt", COMMAND);
+    addEntry(UIDS_LIST_SEPARATELY_DONE, GET_LINE, "trustsign_prompt.trust_value", SET_TRUST_VALUE);
+    addEntry(UIDS_LIST_SEPARATELY_DONE, GET_LINE, "sign_uid.expire", SET_EXPIRE);
+    addEntry(UIDS_LIST_SEPARATELY_DONE, GET_LINE, "sign_uid.class", SET_CHECK_LEVEL);
+    addEntry(UIDS_LIST_SEPARATELY_DONE, GET_BOOL, "sign_uid.okay", CONFIRM);
+    addEntry(CONFIRM, GET_LINE, "keyedit.prompt", QUIT);
+    addEntry(ERROR, GET_LINE, "keyedit.prompt", QUIT);
+    addEntry(QUIT, GET_BOOL, "keyedit.save.okay", SAVE);
+#undef addEntry
+    return tab;
+}
+
+const char *GpgSignKeyEditInteractor::action(Error &err) const
+{
+    static const char check_level_strings[][2] = { "0", "1", "2", "3" };
+    using namespace GpgSignKeyEditInteractor_Private;
+    using namespace std;
+
+    switch (const unsigned int st = state()) {
+    case COMMAND:
+        return d->command();
+    case UIDS_ANSWER_SIGN_ALL:
+        return answer(d->signAll());
+    case UIDS_LIST_SEPARATELY_DONE:
+        return d->command();
+    case SET_EXPIRE:
+        return answer(true);
+    case SET_TRUST_VALUE:
+    // TODO
+    case SET_TRUST_DEPTH:
+    //TODO
+    case SET_TRUST_REGEXP:
+        //TODO
+        return 0;
+    case SET_CHECK_LEVEL:
+        return check_level_strings[d->checkLevel];
+    case CONFIRM:
+        return answer(true);
+    case QUIT:
+        return "quit";
+    case SAVE:
+        return answer(true);
+    default:
+        if (st >= UIDS_LIST_SEPARATELY && st < UIDS_LIST_SEPARATELY_DONE) {
+            std::stringstream ss;
+            ss << d->nextUserID();
+            d->scratch = ss.str();
+            return d->scratch.c_str();
+        }
+    // fall through
+    case ERROR:
+        err = Error::fromCode(GPG_ERR_GENERAL);
+        return 0;
+    }
+}
+
+unsigned int GpgSignKeyEditInteractor::nextState(unsigned int status, const char *args, Error &err) const
+{
+    d->started = true;
+    using namespace GpgSignKeyEditInteractor_Private;
+    static const Error GENERAL_ERROR = Error::fromCode(GPG_ERR_GENERAL);
+    //static const Error INV_TIME_ERROR = Error::fromCode( GPG_ERR_INV_TIME );
+    static const TransitionMap table(makeTable());
+    if (needsNoResponse(status)) {
+        return state();
+    }
+
+    using namespace GpgSignKeyEditInteractor_Private;
+
+    //lookup transition in map
+    const TransitionMap::const_iterator it = table.find(boost::make_tuple(static_cast<SignKeyState>(state()), status, std::string(args)));
+    if (it != table.end()) {
+        return it->second;
+    }
+
+    //handle cases that cannot be handled via the map
+    switch (const unsigned int st = state()) {
+    case UIDS_ANSWER_SIGN_ALL:
+        if (status == GPGME_STATUS_GET_LINE &&
+                strcmp(args, "keyedit.prompt") == 0) {
+            if (!d->signAll()) {
+                return UIDS_LIST_SEPARATELY;
+            }
+            err = Error::fromCode(GPG_ERR_UNUSABLE_PUBKEY);
+            return ERROR;
+        }
+        break;
+    default:
+        if (st >= UIDS_LIST_SEPARATELY && st < UIDS_LIST_SEPARATELY_DONE) {
+            if (status == GPGME_STATUS_GET_LINE &&
+                    strcmp(args, "keyedit.prompt") == 0) {
+                return d->allUserIDsListed() ? UIDS_LIST_SEPARATELY_DONE : st + 1 ;
+            }
+        }
+        break;
+    case CONFIRM:
+    case ERROR:
+        err = lastError();
+        return ERROR;
+    }
+
+    err = GENERAL_ERROR;
+    return ERROR;
+}
+
+void GpgSignKeyEditInteractor::setCheckLevel(unsigned int checkLevel)
+{
+    assert(!d->started);
+    assert(checkLevel <= 3);
+    d->checkLevel = checkLevel;
+}
+
+void GpgSignKeyEditInteractor::setUserIDsToSign(const std::vector<unsigned int> &userIDsToSign)
+{
+    assert(!d->started);
+    d->userIDs = userIDsToSign;
+    d->nextId = d->userIDs.begin();
+    d->currentId = d->userIDs.end();
+
+}
+void GpgSignKeyEditInteractor::setSigningOptions(int options)
+{
+    assert(!d->started);
+    d->options = options;
+}
diff --git a/lang/cpp/src/gpgsignkeyeditinteractor.h b/lang/cpp/src/gpgsignkeyeditinteractor.h
new file mode 100644 (file)
index 0000000..47ff8e5
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+  gpgsignkeyeditinteractor.h - Edit Interactor to change the owner trust of an OpenPGP key
+  Copyright (C) 2008 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_GPGSIGNKEYEDITINTERACTOR_H__
+#define __GPGMEPP_GPGSIGNKEYEDITINTERACTOR_H__
+
+#include <editinteractor.h>
+
+#include <string>
+#include <vector>
+
+namespace GpgME
+{
+
+class Key;
+class UserID;
+
+class GPGMEPP_EXPORT GpgSignKeyEditInteractor : public EditInteractor
+{
+public:
+    enum SignOption {
+        Exportable = 0x1,
+        NonRevocable = 0x2,
+        Trust = 0x4
+    };
+
+    GpgSignKeyEditInteractor();
+    ~GpgSignKeyEditInteractor();
+
+    void setCheckLevel(unsigned int checkLevel);
+    void setUserIDsToSign(const std::vector<unsigned int> &userIDsToSign);
+    void setSigningOptions(int options);
+
+private:
+    /* reimp */ const char *action(Error &err) const;
+    /* reimp */ unsigned int nextState(unsigned int statusCode, const char *args, Error &err) const;
+
+private:
+    class Private;
+    Private *const d;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_GPGSIGNKEYEDITINTERACTOR_H__
diff --git a/lang/cpp/src/importresult.cpp b/lang/cpp/src/importresult.cpp
new file mode 100644 (file)
index 0000000..bd989d2
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+  importresult.cpp - wraps a gpgme import result
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include <importresult.h>
+#include "result_p.h"
+
+#include <gpgme.h>
+#include <cstdlib>
+#include <cstring>
+
+#include <string.h>
+
+class GpgME::ImportResult::Private
+{
+public:
+    Private(const _gpgme_op_import_result &r) : res(r)
+    {
+        // copy recursively, using compiler-generated copy ctor.
+        // We just need to handle the pointers in the structs:
+        for (gpgme_import_status_t is = r.imports ; is ; is = is->next) {
+            gpgme_import_status_t copy = new _gpgme_import_status(*is);
+            copy->fpr = strdup(is->fpr);
+            copy->next = 0;
+            imports.push_back(copy);
+        }
+        res.imports = 0;
+    }
+    ~Private()
+    {
+        for (std::vector<gpgme_import_status_t>::iterator it = imports.begin() ; it != imports.end() ; ++it) {
+            std::free((*it)->fpr);
+            delete *it; *it = 0;
+        }
+    }
+
+    _gpgme_op_import_result res;
+    std::vector<gpgme_import_status_t> imports;
+};
+
+GpgME::ImportResult::ImportResult(gpgme_ctx_t ctx, int error)
+    : GpgME::Result(error), d()
+{
+    init(ctx);
+}
+
+GpgME::ImportResult::ImportResult(gpgme_ctx_t ctx, const Error &error)
+    : GpgME::Result(error), d()
+{
+    init(ctx);
+}
+
+void GpgME::ImportResult::init(gpgme_ctx_t ctx)
+{
+    if (!ctx) {
+        return;
+    }
+    gpgme_import_result_t res = gpgme_op_import_result(ctx);
+    if (!res) {
+        return;
+    }
+    d.reset(new Private(*res));
+}
+
+make_standard_stuff(ImportResult)
+
+int GpgME::ImportResult::numConsidered() const
+{
+    return d ? d->res.considered : 0 ;
+}
+
+int GpgME::ImportResult::numKeysWithoutUserID() const
+{
+    return d ? d->res.no_user_id : 0 ;
+}
+
+int GpgME::ImportResult::numImported() const
+{
+    return d ? d->res.imported : 0 ;
+}
+
+int GpgME::ImportResult::numRSAImported() const
+{
+    return d ? d->res.imported_rsa : 0 ;
+}
+
+int GpgME::ImportResult::numUnchanged() const
+{
+    return d ? d->res.unchanged : 0 ;
+}
+
+int GpgME::ImportResult::newUserIDs() const
+{
+    return d ? d->res.new_user_ids : 0 ;
+}
+
+int GpgME::ImportResult::newSubkeys() const
+{
+    return d ? d->res.new_sub_keys : 0 ;
+}
+
+int GpgME::ImportResult::newSignatures() const
+{
+    return d ? d->res.new_signatures : 0 ;
+}
+
+int GpgME::ImportResult::newRevocations() const
+{
+    return d ? d->res.new_revocations : 0 ;
+}
+
+int GpgME::ImportResult::numSecretKeysConsidered() const
+{
+    return d ? d->res.secret_read : 0 ;
+}
+
+int GpgME::ImportResult::numSecretKeysImported() const
+{
+    return d ? d->res.secret_imported : 0 ;
+}
+
+int GpgME::ImportResult::numSecretKeysUnchanged() const
+{
+    return d ? d->res.secret_unchanged : 0 ;
+}
+
+int GpgME::ImportResult::notImported() const
+{
+    return d ? d->res.not_imported : 0 ;
+}
+
+GpgME::Import GpgME::ImportResult::import(unsigned int idx) const
+{
+    return Import(d, idx);
+}
+
+std::vector<GpgME::Import> GpgME::ImportResult::imports() const
+{
+    if (!d) {
+        return std::vector<Import>();
+    }
+    std::vector<Import> result;
+    result.reserve(d->imports.size());
+    for (unsigned int i = 0 ; i < d->imports.size() ; ++i) {
+        result.push_back(Import(d, i));
+    }
+    return result;
+}
+
+GpgME::Import::Import(const boost::shared_ptr<ImportResult::Private> &parent, unsigned int i)
+    : d(parent), idx(i)
+{
+
+}
+
+GpgME::Import::Import() : d(), idx(0) {}
+
+bool GpgME::Import::isNull() const
+{
+    return !d || idx >= d->imports.size() ;
+}
+
+const char *GpgME::Import::fingerprint() const
+{
+    return isNull() ? 0 : d->imports[idx]->fpr ;
+}
+
+GpgME::Error GpgME::Import::error() const
+{
+    return Error(isNull() ? 0 : d->imports[idx]->result);
+}
+
+GpgME::Import::Status GpgME::Import::status() const
+{
+    if (isNull()) {
+        return Unknown;
+    }
+    const unsigned int s = d->imports[idx]->status;
+    unsigned int result = Unknown;
+    if (s & GPGME_IMPORT_NEW) {
+        result |= NewKey;
+    }
+    if (s & GPGME_IMPORT_UID) {
+        result |= NewUserIDs;
+    }
+    if (s & GPGME_IMPORT_SIG) {
+        result |= NewSignatures;
+    }
+    if (s & GPGME_IMPORT_SUBKEY) {
+        result |= NewSubkeys;
+    }
+    if (s & GPGME_IMPORT_SECRET) {
+        result |= ContainedSecretKey;
+    }
+    return static_cast<Status>(result);
+}
diff --git a/lang/cpp/src/importresult.h b/lang/cpp/src/importresult.h
new file mode 100644 (file)
index 0000000..7dc0320
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+  importresult.h - wraps a gpgme import result
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_IMPORTRESULT_H__
+#define __GPGMEPP_IMPORTRESULT_H__
+
+#include "gpgmefw.h"
+#include "result.h"
+#include "gpgmepp_export.h"
+
+#include <boost/shared_ptr.hpp>
+
+#include <vector>
+
+namespace GpgME
+{
+
+class Error;
+class Import;
+
+class GPGMEPP_EXPORT ImportResult : public Result
+{
+public:
+    ImportResult();
+    ImportResult(gpgme_ctx_t ctx, int error);
+    ImportResult(gpgme_ctx_t ctx, const Error &error);
+    explicit ImportResult(const Error &error);
+
+    const ImportResult &operator=(ImportResult other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(ImportResult &other)
+    {
+        Result::swap(other);
+        using std::swap;
+        swap(this->d, other.d);
+    }
+
+    bool isNull() const;
+
+    int numConsidered() const;
+    int numKeysWithoutUserID() const;
+    int numImported() const;
+    int numRSAImported() const;
+    int numUnchanged() const;
+
+    int newUserIDs() const;
+    int newSubkeys() const;
+    int newSignatures() const;
+    int newRevocations() const;
+
+    int numSecretKeysConsidered() const;
+    int numSecretKeysImported() const;
+    int numSecretKeysUnchanged() const;
+
+    int notImported() const;
+
+    Import import(unsigned int idx) const;
+    std::vector<Import> imports() const;
+
+    class Private;
+private:
+    void init(gpgme_ctx_t ctx);
+    boost::shared_ptr<Private> d;
+};
+
+class GPGMEPP_EXPORT Import
+{
+    friend class ::GpgME::ImportResult;
+    Import(const boost::shared_ptr<ImportResult::Private> &parent, unsigned int idx);
+public:
+    Import();
+
+    const Import &operator=(Import other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(Import &other)
+    {
+        using std::swap;
+        swap(this->d, other.d);
+        swap(this->idx, other.idx);
+    }
+
+    bool isNull() const;
+
+    const char *fingerprint() const;
+    Error error() const;
+
+    enum Status {
+        Unknown = 0x0,
+        NewKey = 0x1,
+        NewUserIDs = 0x2,
+        NewSignatures = 0x4,
+        NewSubkeys = 0x8,
+        ContainedSecretKey = 0x10
+    };
+    Status status() const;
+
+private:
+    boost::shared_ptr<ImportResult::Private> d;
+    unsigned int idx;
+};
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(ImportResult)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Import)
+
+#endif // __GPGMEPP_IMPORTRESULT_H__
diff --git a/lang/cpp/src/interfaces/assuantransaction.h b/lang/cpp/src/interfaces/assuantransaction.h
new file mode 100644 (file)
index 0000000..9acdf7d
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+  assuantransaction.h - Interface for ASSUAN transactions
+  Copyright (C) 2009 Klarälvdalens Datakonsult AB <info@kdab.com>
+  Author: Marc Mutz <marc@kdab.com>
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_INTERFACES_ASSUANTRANSACTION_H__
+#define __GPGMEPP_INTERFACES_ASSUANTRANSACTION_H__
+
+#include "gpgmepp_export.h"
+
+namespace GpgME
+{
+
+class Error;
+class Data;
+
+class GPGMEPP_EXPORT AssuanTransaction
+{
+public:
+    virtual ~AssuanTransaction() {}
+
+    virtual Error data(const char *data, size_t datalen) = 0;
+    virtual Data  inquire(const char *name, const char *args, Error &err) = 0;
+    virtual Error status(const char *status, const char *args) = 0;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_INTERFACES_ASSUANTRANSACTION_H__
diff --git a/lang/cpp/src/interfaces/dataprovider.h b/lang/cpp/src/interfaces/dataprovider.h
new file mode 100644 (file)
index 0000000..166bb4e
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+  interface/dataprovider.h - Interface for data sources
+  Copyright (C) 2003 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_INTERFACES_DATAPROVIDER_H__
+#define __GPGMEPP_INTERFACES_DATAPROVIDER_H__
+
+#include <sys/types.h>
+
+#include "gpgmepp_export.h"
+
+#include <gpg-error.h>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT DataProvider
+{
+public:
+    virtual ~DataProvider() {}
+
+    enum Operation {
+        Read, Write, Seek, Release
+    };
+    virtual bool isSupported(Operation op) const = 0;
+
+    virtual ssize_t read(void   *buffer, size_t bufSize) = 0;
+    virtual ssize_t write(const void *buffer, size_t bufSize) = 0;
+    virtual off_t seek(off_t offset, int whence) = 0;
+    virtual void release() = 0;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_INTERFACES_DATAPROVIDER_H__
diff --git a/lang/cpp/src/interfaces/passphraseprovider.h b/lang/cpp/src/interfaces/passphraseprovider.h
new file mode 100644 (file)
index 0000000..5275e44
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  interface/passphraseprovider.h - Interface for passphrase callbacks
+  Copyright (C) 2003,2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_INTERFACES_PASSPHRASEPROVIDER_H__
+#define __GPGMEPP_INTERFACES_PASSPHRASEPROVIDER_H__
+
+namespace GpgME
+{
+
+class PassphraseProvider
+{
+public:
+    virtual ~PassphraseProvider() {}
+
+    virtual char *getPassphrase(const char *useridHint, const char *description,
+                                bool previousWasBad, bool &canceled) = 0;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_INTERFACES_PASSPHRASEPROVIDER_H__
diff --git a/lang/cpp/src/interfaces/progressprovider.h b/lang/cpp/src/interfaces/progressprovider.h
new file mode 100644 (file)
index 0000000..78bbdd7
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  interface/progressprovider.h - Interface for progress reports
+  Copyright (C) 2003 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_INTERFACES_PROGRESSPROVIDER_H__
+#define __GPGMEPP_INTERFACES_PROGRESSPROVIDER_H__
+
+namespace GpgME
+{
+
+class ProgressProvider
+{
+public:
+    virtual ~ProgressProvider() {}
+
+    virtual void showProgress(const char *what, int type,
+                              int current, int total) = 0;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_INTERFACES_PROGRESSPROVIDER_H__
diff --git a/lang/cpp/src/key.cpp b/lang/cpp/src/key.cpp
new file mode 100644 (file)
index 0000000..5eadbdd
--- /dev/null
@@ -0,0 +1,847 @@
+/*
+  key.cpp - wraps a gpgme key
+  Copyright (C) 2003, 2005 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "config-gpgme++.h"
+
+#include <key.h>
+
+#include "util.h"
+
+#include <gpgme.h>
+
+#include <string.h>
+
+const GpgME::Key::Null GpgME::Key::null;
+
+namespace GpgME
+{
+
+Key::Key() : key() {}
+
+Key::Key(const Null &) : key() {}
+
+Key::Key(const shared_gpgme_key_t &k) : key(k) {}
+
+Key::Key(gpgme_key_t k, bool ref)
+    : key(k
+          ? shared_gpgme_key_t(k, &gpgme_key_unref)
+          : shared_gpgme_key_t())
+{
+    if (ref && impl()) {
+        gpgme_key_ref(impl());
+    }
+}
+
+UserID Key::userID(unsigned int index) const
+{
+    return UserID(key, index);
+}
+
+Subkey Key::subkey(unsigned int index) const
+{
+    return Subkey(key, index);
+}
+
+unsigned int Key::numUserIDs() const
+{
+    if (!key) {
+        return 0;
+    }
+    unsigned int count = 0;
+    for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) {
+        ++count;
+    }
+    return count;
+}
+
+unsigned int Key::numSubkeys() const
+{
+    if (!key) {
+        return 0;
+    }
+    unsigned int count = 0;
+    for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
+        ++count;
+    }
+    return count;
+}
+
+std::vector<UserID> Key::userIDs() const
+{
+    if (!key) {
+        return std::vector<UserID>();
+    }
+
+    std::vector<UserID> v;
+    v.reserve(numUserIDs());
+    for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) {
+        v.push_back(UserID(key, uid));
+    }
+    return v;
+}
+
+std::vector<Subkey> Key::subkeys() const
+{
+    if (!key) {
+        return std::vector<Subkey>();
+    }
+
+    std::vector<Subkey> v;
+    v.reserve(numSubkeys());
+    for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
+        v.push_back(Subkey(key, subkey));
+    }
+    return v;
+}
+
+Key::OwnerTrust Key::ownerTrust() const
+{
+    if (!key) {
+        return Unknown;
+    }
+    switch (key->owner_trust) {
+    default:
+    case GPGME_VALIDITY_UNKNOWN:   return Unknown;
+    case GPGME_VALIDITY_UNDEFINED: return Undefined;
+    case GPGME_VALIDITY_NEVER:     return Never;
+    case GPGME_VALIDITY_MARGINAL:  return Marginal;
+    case GPGME_VALIDITY_FULL:     return Full;
+    case GPGME_VALIDITY_ULTIMATE: return Ultimate;
+    }
+}
+char Key::ownerTrustAsString() const
+{
+    if (!key) {
+        return '?';
+    }
+    switch (key->owner_trust) {
+    default:
+    case GPGME_VALIDITY_UNKNOWN:   return '?';
+    case GPGME_VALIDITY_UNDEFINED: return 'q';
+    case GPGME_VALIDITY_NEVER:     return 'n';
+    case GPGME_VALIDITY_MARGINAL:  return 'm';
+    case GPGME_VALIDITY_FULL:     return 'f';
+    case GPGME_VALIDITY_ULTIMATE: return 'u';
+    }
+}
+
+Protocol Key::protocol() const
+{
+    if (!key) {
+        return UnknownProtocol;
+    }
+    switch (key->protocol) {
+    case GPGME_PROTOCOL_CMS:     return CMS;
+    case GPGME_PROTOCOL_OpenPGP: return OpenPGP;
+    default:                     return UnknownProtocol;
+    }
+}
+
+const char *Key::protocolAsString() const
+{
+    return key ? gpgme_get_protocol_name(key->protocol) : 0 ;
+}
+
+bool Key::isRevoked() const
+{
+    return key && key->revoked;
+}
+
+bool Key::isExpired() const
+{
+    return key && key->expired;
+}
+
+bool Key::isDisabled() const
+{
+    return key && key->disabled;
+}
+
+bool Key::isInvalid() const
+{
+    return key && key->invalid;
+}
+
+bool Key::hasSecret() const
+{
+    return key && key->secret;
+}
+
+bool Key::isRoot() const
+{
+    return key && key->subkeys && key->subkeys->fpr && key->chain_id &&
+           strcasecmp(key->subkeys->fpr, key->chain_id) == 0;
+}
+
+bool Key::canEncrypt() const
+{
+    return key && key->can_encrypt;
+}
+
+bool Key::canSign() const
+{
+#ifndef GPGME_CAN_SIGN_ON_SECRET_OPENPGP_KEYLISTING_NOT_BROKEN
+    if (key && key->protocol == GPGME_PROTOCOL_OpenPGP) {
+        return true;
+    }
+#endif
+    return canReallySign();
+}
+
+bool Key::canReallySign() const
+{
+    return key && key->can_sign;
+}
+
+bool Key::canCertify() const
+{
+    return key && key->can_certify;
+}
+
+bool Key::canAuthenticate() const
+{
+    return key && key->can_authenticate;
+}
+
+bool Key::isQualified() const
+{
+#ifdef HAVE_GPGME_KEY_T_IS_QUALIFIED
+    return key && key->is_qualified;
+#else
+    return false;
+#endif
+}
+
+const char *Key::issuerSerial() const
+{
+    return key ? key->issuer_serial : 0 ;
+}
+const char *Key::issuerName() const
+{
+    return key ? key->issuer_name : 0 ;
+}
+const char *Key::chainID() const
+{
+    return key ? key->chain_id : 0 ;
+}
+
+const char *Key::keyID() const
+{
+    return key && key->subkeys ? key->subkeys->keyid : 0 ;
+}
+
+const char *Key::shortKeyID() const
+{
+    if (!key || !key->subkeys || !key->subkeys->keyid) {
+        return 0;
+    }
+    const int len = strlen(key->subkeys->keyid);
+    if (len > 8) {
+        return key->subkeys->keyid + len - 8; // return the last 8 bytes (in hex notation)
+    } else {
+        return key->subkeys->keyid;
+    }
+}
+
+const char *Key::primaryFingerprint() const
+{
+    const char *fpr = key && key->subkeys ? key->subkeys->fpr : 0 ;
+    if (fpr) {
+        return fpr;
+    } else {
+        return keyID();
+    }
+}
+
+unsigned int Key::keyListMode() const
+{
+    return key ? convert_from_gpgme_keylist_mode_t(key->keylist_mode) : 0 ;
+}
+
+const Key &Key::mergeWith(const Key &other)
+{
+    // ### incomplete. Just merges has* and can*, nothing else atm
+    // ### detach also missing
+
+    if (!this->primaryFingerprint() ||
+            !other.primaryFingerprint() ||
+            strcasecmp(this->primaryFingerprint(), other.primaryFingerprint()) != 0) {
+        return *this; // only merge the Key object which describe the same key
+    }
+
+    const gpgme_key_t me = impl();
+    const gpgme_key_t him = other.impl();
+
+    if (!me || !him) {
+        return *this;
+    }
+
+    me->revoked          |= him->revoked;
+    me->expired          |= him->expired;
+    me->disabled         |= him->disabled;
+    me->invalid          |= him->invalid;
+    me->can_encrypt      |= him->can_encrypt;
+    me->can_sign         |= him->can_sign;
+    me->can_certify      |= him->can_certify;
+    me->secret           |= him->secret;
+    me->can_authenticate |= him->can_authenticate;
+#ifdef HAVE_GPGME_KEY_T_IS_QUALIFIED
+    me->is_qualified     |= him->is_qualified;
+#endif
+    me->keylist_mode     |= him->keylist_mode;
+
+#ifdef HAVE_GPGME_SUBKEY_T_IS_CARDKEY
+    // make sure the gpgme_sub_key_t::is_cardkey flag isn't lost:
+    for (gpgme_sub_key_t mysk = me->subkeys ; mysk ; mysk = mysk->next) {
+        for (gpgme_sub_key_t hissk = him->subkeys ; hissk ; hissk = hissk->next) {
+            if (strcmp(mysk->fpr, hissk->fpr) == 0) {
+                mysk->is_cardkey |= hissk->is_cardkey;
+                break;
+            }
+        }
+    }
+#endif
+
+    return *this;
+}
+
+//
+//
+// class Subkey
+//
+//
+
+gpgme_sub_key_t find_subkey(const shared_gpgme_key_t &key, unsigned int idx)
+{
+    if (key) {
+        for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next, --idx) {
+            if (idx == 0) {
+                return s;
+            }
+        }
+    }
+    return 0;
+}
+
+gpgme_sub_key_t verify_subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey)
+{
+    if (key) {
+        for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next) {
+            if (s == subkey) {
+                return subkey;
+            }
+        }
+    }
+    return 0;
+}
+
+Subkey::Subkey() : key(), subkey(0) {}
+
+Subkey::Subkey(const shared_gpgme_key_t &k, unsigned int idx)
+    : key(k), subkey(find_subkey(k, idx))
+{
+
+}
+
+Subkey::Subkey(const shared_gpgme_key_t &k, gpgme_sub_key_t sk)
+    : key(k), subkey(verify_subkey(k, sk))
+{
+
+}
+
+Key Subkey::parent() const
+{
+    return Key(key);
+}
+
+const char *Subkey::keyID() const
+{
+    return subkey ? subkey->keyid : 0 ;
+}
+
+const char *Subkey::fingerprint() const
+{
+    return subkey ? subkey->fpr : 0 ;
+}
+
+unsigned int Subkey::publicKeyAlgorithm() const
+{
+    return subkey ? subkey->pubkey_algo : 0 ;
+}
+
+const char *Subkey::publicKeyAlgorithmAsString() const
+{
+    return gpgme_pubkey_algo_name(subkey ? subkey->pubkey_algo : (gpgme_pubkey_algo_t)0);
+}
+
+bool Subkey::canEncrypt() const
+{
+    return subkey && subkey->can_encrypt;
+}
+
+bool Subkey::canSign() const
+{
+    return subkey && subkey->can_sign;
+}
+
+bool Subkey::canCertify() const
+{
+    return subkey && subkey->can_certify;
+}
+
+bool Subkey::canAuthenticate() const
+{
+    return subkey && subkey->can_authenticate;
+}
+
+bool Subkey::isQualified() const
+{
+#ifdef HAVE_GPGME_SUBKEY_T_IS_QUALIFIED
+    return subkey && subkey->is_qualified;
+#else
+    return false;
+#endif
+}
+
+bool Subkey::isCardKey() const
+{
+#ifdef HAVE_GPGME_SUBKEY_T_IS_CARDKEY
+    return subkey && subkey->is_cardkey;
+#else
+    return false;
+#endif
+}
+
+const char *Subkey::cardSerialNumber() const
+{
+#ifdef HAVE_GPGME_SUBKEY_T_IS_CARDKEY
+    return subkey ? subkey->card_number : 0 ;
+#else
+    return 0;
+#endif
+}
+
+bool Subkey::isSecret() const
+{
+    return subkey && subkey->secret;
+}
+
+unsigned int Subkey::length() const
+{
+    return subkey ? subkey->length : 0 ;
+}
+
+time_t Subkey::creationTime() const
+{
+    return static_cast<time_t>(subkey ? subkey->timestamp : 0);
+}
+
+time_t Subkey::expirationTime() const
+{
+    return static_cast<time_t>(subkey ? subkey->expires : 0);
+}
+
+bool Subkey::neverExpires() const
+{
+    return expirationTime() == time_t(0);
+}
+
+bool Subkey::isRevoked() const
+{
+    return subkey && subkey->revoked;
+}
+
+bool Subkey::isInvalid() const
+{
+    return subkey && subkey->invalid;
+}
+
+bool Subkey::isExpired() const
+{
+    return subkey && subkey->expired;
+}
+
+bool Subkey::isDisabled() const
+{
+    return subkey && subkey->disabled;
+}
+
+//
+//
+// class UserID
+//
+//
+
+gpgme_user_id_t find_uid(const shared_gpgme_key_t &key, unsigned int idx)
+{
+    if (key) {
+        for (gpgme_user_id_t u = key->uids ; u ; u = u->next, --idx) {
+            if (idx == 0) {
+                return u;
+            }
+        }
+    }
+    return 0;
+}
+
+gpgme_user_id_t verify_uid(const shared_gpgme_key_t &key, gpgme_user_id_t uid)
+{
+    if (key) {
+        for (gpgme_user_id_t u = key->uids ; u ; u = u->next) {
+            if (u == uid) {
+                return uid;
+            }
+        }
+    }
+    return 0;
+}
+
+UserID::UserID() : key(), uid(0) {}
+
+UserID::UserID(const shared_gpgme_key_t &k, gpgme_user_id_t u)
+    : key(k), uid(verify_uid(k, u))
+{
+
+}
+
+UserID::UserID(const shared_gpgme_key_t &k, unsigned int idx)
+    : key(k), uid(find_uid(k, idx))
+{
+
+}
+
+Key UserID::parent() const
+{
+    return Key(key);
+}
+
+UserID::Signature UserID::signature(unsigned int index) const
+{
+    return Signature(key, uid, index);
+}
+
+unsigned int UserID::numSignatures() const
+{
+    if (!uid) {
+        return 0;
+    }
+    unsigned int count = 0;
+    for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
+        ++count;
+    }
+    return count;
+}
+
+std::vector<UserID::Signature> UserID::signatures() const
+{
+    if (!uid) {
+        return std::vector<Signature>();
+    }
+
+    std::vector<Signature> v;
+    v.reserve(numSignatures());
+    for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
+        v.push_back(Signature(key, uid, sig));
+    }
+    return v;
+}
+
+const char *UserID::id() const
+{
+    return uid ? uid->uid : 0 ;
+}
+
+const char *UserID::name() const
+{
+    return uid ? uid->name : 0 ;
+}
+
+const char *UserID::email() const
+{
+    return uid ? uid->email : 0 ;
+}
+
+const char *UserID::comment() const
+{
+    return uid ? uid->comment : 0 ;
+}
+
+UserID::Validity UserID::validity() const
+{
+    if (!uid) {
+        return Unknown;
+    }
+    switch (uid->validity) {
+    default:
+    case GPGME_VALIDITY_UNKNOWN:   return Unknown;
+    case GPGME_VALIDITY_UNDEFINED: return Undefined;
+    case GPGME_VALIDITY_NEVER:     return Never;
+    case GPGME_VALIDITY_MARGINAL:  return Marginal;
+    case GPGME_VALIDITY_FULL:      return Full;
+    case GPGME_VALIDITY_ULTIMATE:  return Ultimate;
+    }
+}
+
+char UserID::validityAsString() const
+{
+    if (!uid) {
+        return '?';
+    }
+    switch (uid->validity) {
+    default:
+    case GPGME_VALIDITY_UNKNOWN:   return '?';
+    case GPGME_VALIDITY_UNDEFINED: return 'q';
+    case GPGME_VALIDITY_NEVER:     return 'n';
+    case GPGME_VALIDITY_MARGINAL:  return 'm';
+    case GPGME_VALIDITY_FULL:      return 'f';
+    case GPGME_VALIDITY_ULTIMATE:  return 'u';
+    }
+}
+
+bool UserID::isRevoked() const
+{
+    return uid && uid->revoked;
+}
+
+bool UserID::isInvalid() const
+{
+    return uid && uid->invalid;
+}
+
+//
+//
+// class Signature
+//
+//
+
+gpgme_key_sig_t find_signature(gpgme_user_id_t uid, unsigned int idx)
+{
+    if (uid) {
+        for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next, --idx) {
+            if (idx == 0) {
+                return s;
+            }
+        }
+    }
+    return 0;
+}
+
+gpgme_key_sig_t verify_signature(gpgme_user_id_t uid, gpgme_key_sig_t sig)
+{
+    if (uid) {
+        for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next) {
+            if (s == sig) {
+                return sig;
+            }
+        }
+    }
+    return 0;
+}
+
+UserID::Signature::Signature() : key(), uid(0), sig(0) {}
+
+UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, unsigned int idx)
+    : key(k), uid(verify_uid(k, u)), sig(find_signature(uid, idx))
+{
+
+}
+
+UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, gpgme_key_sig_t s)
+    : key(k), uid(verify_uid(k, u)), sig(verify_signature(uid, s))
+{
+
+}
+
+UserID UserID::Signature::parent() const
+{
+    return UserID(key, uid);
+}
+
+const char *UserID::Signature::signerKeyID() const
+{
+    return sig ? sig->keyid : 0 ;
+}
+
+const char *UserID::Signature::algorithmAsString() const
+{
+    return gpgme_pubkey_algo_name(sig ? sig->pubkey_algo : (gpgme_pubkey_algo_t)0);
+}
+
+unsigned int UserID::Signature::algorithm() const
+{
+    return sig ? sig->pubkey_algo : 0 ;
+}
+
+time_t UserID::Signature::creationTime() const
+{
+    return static_cast<time_t>(sig ? sig->timestamp : 0);
+}
+
+time_t UserID::Signature::expirationTime() const
+{
+    return static_cast<time_t>(sig ? sig->expires : 0);
+}
+
+bool UserID::Signature::neverExpires() const
+{
+    return expirationTime() == time_t(0);
+}
+
+bool UserID::Signature::isRevokation() const
+{
+    return sig && sig->revoked;
+}
+
+bool UserID::Signature::isInvalid() const
+{
+    return sig && sig->invalid;
+}
+
+bool UserID::Signature::isExpired() const
+{
+    return sig && sig->expired;
+}
+
+bool UserID::Signature::isExportable() const
+{
+    return sig && sig->exportable;
+}
+
+const char *UserID::Signature::signerUserID() const
+{
+    return sig ? sig->uid : 0 ;
+}
+
+const char *UserID::Signature::signerName() const
+{
+    return sig ? sig->name : 0 ;
+}
+
+const char *UserID::Signature::signerEmail() const
+{
+    return sig ? sig->email : 0 ;
+}
+
+const char *UserID::Signature::signerComment() const
+{
+    return sig ? sig->comment : 0 ;
+}
+
+unsigned int UserID::Signature::certClass() const
+{
+    return sig ? sig->sig_class : 0 ;
+}
+
+UserID::Signature::Status UserID::Signature::status() const
+{
+    if (!sig) {
+        return GeneralError;
+    }
+
+    switch (gpgme_err_code(sig->status)) {
+    case GPG_ERR_NO_ERROR:      return NoError;
+    case GPG_ERR_SIG_EXPIRED:   return SigExpired;
+    case GPG_ERR_KEY_EXPIRED:   return KeyExpired;
+    case GPG_ERR_BAD_SIGNATURE: return BadSignature;
+    case GPG_ERR_NO_PUBKEY:     return NoPublicKey;
+    default:
+    case GPG_ERR_GENERAL:       return GeneralError;
+    }
+}
+
+std::string UserID::Signature::statusAsString() const
+{
+    if (!sig) {
+        return std::string();
+    }
+    char buf[ 1024 ];
+    gpgme_strerror_r(sig->status, buf, sizeof buf);
+    buf[ sizeof buf - 1 ] = '\0';
+    return std::string(buf);
+}
+
+GpgME::Notation UserID::Signature::notation(unsigned int idx) const
+{
+    if (!sig) {
+        return GpgME::Notation();
+    }
+#ifdef HAVE_GPGME_KEY_SIG_NOTATIONS
+    for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
+        if (nota->name) {
+            if (idx-- == 0) {
+                return GpgME::Notation(nota);
+            }
+        }
+    }
+#endif
+    return GpgME::Notation();
+}
+
+unsigned int UserID::Signature::numNotations() const
+{
+    if (!sig) {
+        return 0;
+    }
+    unsigned int count = 0;
+#ifdef HAVE_GPGME_KEY_SIG_NOTATIONS
+    for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
+        if (nota->name) {
+            ++count; // others are policy URLs...
+        }
+    }
+#endif
+    return count;
+}
+
+std::vector<Notation> UserID::Signature::notations() const
+{
+    if (!sig) {
+        return std::vector<GpgME::Notation>();
+    }
+    std::vector<GpgME::Notation> v;
+#ifdef HAVE_GPGME_KEY_SIG_NOTATIONS
+    v.reserve(numNotations());
+    for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
+        if (nota->name) {
+            v.push_back(GpgME::Notation(nota));
+        }
+    }
+#endif
+    return v;
+}
+
+const char *UserID::Signature::policyURL() const
+{
+#ifdef HAVE_GPGME_KEY_SIG_NOTATIONS
+    if (!sig) {
+        return 0;
+    }
+    for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
+        if (!nota->name) {
+            return nota->value;
+        }
+    }
+#endif
+    return 0;
+}
+
+} // namespace GpgME
diff --git a/lang/cpp/src/key.h b/lang/cpp/src/key.h
new file mode 100644 (file)
index 0000000..80bf4d1
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+  key.h - wraps a gpgme key
+  Copyright (C) 2003, 2005 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_KEY_H__
+#define __GPGMEPP_KEY_H__
+
+#include "global.h"
+#include "notation.h"
+
+#include "gpgmefw.h"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/type_traits/remove_pointer.hpp>
+
+#include <sys/time.h>
+
+#include <vector>
+#include <algorithm>
+#include <string>
+
+namespace GpgME
+{
+
+class Context;
+
+class Subkey;
+class UserID;
+
+typedef boost::shared_ptr< boost::remove_pointer<gpgme_key_t>::type > shared_gpgme_key_t;
+
+//
+// class Key
+//
+
+class GPGMEPP_EXPORT Key
+{
+    friend class ::GpgME::Context;
+    struct Null {
+               Null() {}
+       };
+public:
+    Key();
+    /* implicit */ Key(const Null &);
+    Key(const shared_gpgme_key_t &key);
+    Key(gpgme_key_t key, bool acquireRef);
+
+    static const Null null;
+
+    const Key &operator=(Key other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    const Key &mergeWith(const Key &other);
+
+    void swap(Key &other)
+    {
+        using std::swap;
+        swap(this->key, other.key);
+    }
+
+    bool isNull() const
+    {
+        return !key;
+    }
+
+    UserID userID(unsigned int index) const;
+    Subkey subkey(unsigned int index) const;
+
+    unsigned int numUserIDs() const;
+    unsigned int numSubkeys() const;
+
+    std::vector<UserID> userIDs() const;
+    std::vector<Subkey> subkeys() const;
+
+    bool isRevoked() const;
+    bool isExpired() const;
+    bool isDisabled() const;
+    bool isInvalid() const;
+
+    bool canEncrypt() const;
+    /*!
+      This function contains a workaround for old gpgme's: all secret
+      OpenPGP keys canSign() == true, which canReallySign() doesn't
+      have. I don't have time to find what breaks when I remove this
+      workaround, but since Kleopatra merges secret into public keys,
+      the workaround is not necessary there (and actively harms), I've
+      added a new function instead.
+     */
+    bool canSign() const;
+    bool canReallySign() const;
+    bool canCertify() const;
+    bool canAuthenticate() const;
+    bool isQualified() const;
+
+    bool hasSecret() const;
+    GPGMEPP_DEPRECATED bool isSecret() const
+    {
+        return hasSecret();
+    }
+
+    /*!
+      @return true if this is a X.509 root certificate (currently
+      equivalent to something like
+      strcmp( chainID(), subkey(0).fingerprint() ) == 0 )
+    */
+    bool isRoot() const;
+
+    enum OwnerTrust { Unknown = 0, Undefined = 1, Never = 2,
+                      Marginal = 3, Full = 4, Ultimate = 5
+                    };
+
+    OwnerTrust ownerTrust() const;
+    char ownerTrustAsString() const;
+
+    Protocol protocol() const;
+    const char *protocolAsString() const;
+
+    const char *issuerSerial() const;
+    const char *issuerName() const;
+    const char *chainID() const;
+
+    const char *keyID() const;
+    const char *shortKeyID() const;
+    const char *primaryFingerprint() const;
+
+    unsigned int keyListMode() const;
+
+private:
+    gpgme_key_t impl() const
+    {
+        return key.get();
+    }
+    shared_gpgme_key_t key;
+};
+
+//
+// class Subkey
+//
+
+class GPGMEPP_EXPORT Subkey
+{
+public:
+    Subkey();
+    Subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey);
+    Subkey(const shared_gpgme_key_t &key, unsigned int idx);
+
+    const Subkey &operator=(Subkey other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(Subkey &other)
+    {
+        using std::swap;
+        swap(this->key, other.key);
+        swap(this->subkey, other.subkey);
+    }
+
+    bool isNull() const
+    {
+        return !key || !subkey;
+    }
+
+    Key parent() const;
+
+    const char *keyID() const;
+    const char *fingerprint() const;
+
+    time_t creationTime() const;
+    time_t expirationTime() const;
+    bool neverExpires() const;
+
+    bool isRevoked() const;
+    bool isExpired() const;
+    bool isInvalid() const;
+    bool isDisabled() const;
+
+    bool canEncrypt() const;
+    bool canSign() const;
+    bool canCertify() const;
+    bool canAuthenticate() const;
+    bool isQualified() const;
+    bool isCardKey() const;
+
+    bool isSecret() const;
+
+    unsigned int publicKeyAlgorithm() const;
+    const char *publicKeyAlgorithmAsString() const;
+
+    unsigned int length() const;
+
+    const char *cardSerialNumber() const;
+
+private:
+    shared_gpgme_key_t key;
+    gpgme_sub_key_t subkey;
+};
+
+//
+// class UserID
+//
+
+class GPGMEPP_EXPORT UserID
+{
+public:
+    class Signature;
+
+    UserID();
+    UserID(const shared_gpgme_key_t &key, gpgme_user_id_t uid);
+    UserID(const shared_gpgme_key_t &key, unsigned int idx);
+
+    const UserID &operator=(UserID other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(UserID &other)
+    {
+        using std::swap;
+        swap(this->key, other.key);
+        swap(this->uid, other.uid);
+    }
+
+    bool isNull() const
+    {
+        return !key || !uid;
+    }
+
+    Key parent() const;
+
+    unsigned int numSignatures() const;
+    Signature signature(unsigned int index) const;
+    std::vector<Signature> signatures() const;
+
+    const char *id() const;
+    const char *name() const;
+    const char *email() const;
+    const char *comment() const;
+
+    enum Validity { Unknown = 0, Undefined = 1, Never = 2,
+                    Marginal = 3, Full = 4, Ultimate = 5
+                  };
+
+    Validity validity() const;
+    char validityAsString() const;
+
+    bool isRevoked() const;
+    bool isInvalid() const;
+
+private:
+    shared_gpgme_key_t key;
+    gpgme_user_id_t uid;
+};
+
+//
+// class UserID::Signature
+//
+
+class GPGMEPP_EXPORT UserID::Signature
+{
+public:
+    typedef GPGMEPP_DEPRECATED GpgME::Notation Notation;
+
+    Signature();
+    Signature(const shared_gpgme_key_t &key, gpgme_user_id_t uid, gpgme_key_sig_t sig);
+    Signature(const shared_gpgme_key_t &key, gpgme_user_id_t uid, unsigned int idx);
+
+    const Signature &operator=(Signature other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(Signature &other)
+    {
+        using std::swap;
+        swap(this->key, other.key);
+        swap(this->uid, other.uid);
+        swap(this->sig, other.sig);
+    }
+
+    bool isNull() const
+    {
+        return !sig || !uid || !key ;
+    }
+
+    UserID parent() const;
+
+    const char *signerKeyID() const;
+
+    const char *algorithmAsString() const;
+    unsigned int algorithm() const;
+    time_t creationTime() const;
+    time_t expirationTime() const;
+    bool neverExpires() const;
+
+    bool isRevokation() const;
+    bool isInvalid() const;
+    bool isExpired() const;
+    bool isExportable() const;
+
+    const char *signerUserID() const;
+    const char *signerName() const;
+    const char *signerEmail() const;
+    const char *signerComment() const;
+
+    unsigned int certClass() const;
+
+    enum Status { NoError = 0, SigExpired, KeyExpired,
+                  BadSignature, NoPublicKey, GeneralError
+                };
+    Status status() const;
+    std::string statusAsString() const;
+
+    const char *policyURL() const;
+
+    unsigned int numNotations() const;
+    GpgME::Notation notation(unsigned int idx) const;
+    std::vector<GpgME::Notation> notations() const;
+
+private:
+    shared_gpgme_key_t key;
+    gpgme_user_id_t uid;
+    gpgme_key_sig_t sig;
+};
+
+} // namespace GpgME
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Key)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Subkey)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(UserID)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(UserID::Signature)
+
+#endif // __GPGMEPP_KEY_H__
diff --git a/lang/cpp/src/keygenerationresult.cpp b/lang/cpp/src/keygenerationresult.cpp
new file mode 100644 (file)
index 0000000..f365e43
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+  keygenerationresult.cpp - wraps a gpgme keygen result
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include <keygenerationresult.h>
+#include "result_p.h"
+
+#include <gpgme.h>
+
+#include <cstring>
+#include <cstdlib>
+
+#include <string.h>
+
+class GpgME::KeyGenerationResult::Private
+{
+public:
+    Private(const _gpgme_op_genkey_result &r) : res(r)
+    {
+        if (res.fpr) {
+            res.fpr = strdup(res.fpr);
+        }
+    }
+    ~Private()
+    {
+        if (res.fpr) {
+            std::free(res.fpr);
+        }
+        res.fpr = 0;
+    }
+
+    _gpgme_op_genkey_result res;
+};
+
+GpgME::KeyGenerationResult::KeyGenerationResult(gpgme_ctx_t ctx, int error)
+    : GpgME::Result(error), d()
+{
+    init(ctx);
+}
+
+GpgME::KeyGenerationResult::KeyGenerationResult(gpgme_ctx_t ctx, const Error &error)
+    : GpgME::Result(error), d()
+{
+    init(ctx);
+}
+
+void GpgME::KeyGenerationResult::init(gpgme_ctx_t ctx)
+{
+    if (!ctx) {
+        return;
+    }
+    gpgme_genkey_result_t res = gpgme_op_genkey_result(ctx);
+    if (!res) {
+        return;
+    }
+    d.reset(new Private(*res));
+}
+
+make_standard_stuff(KeyGenerationResult)
+
+bool GpgME::KeyGenerationResult::isPrimaryKeyGenerated() const
+{
+    return d && d->res.primary;
+}
+
+bool GpgME::KeyGenerationResult::isSubkeyGenerated() const
+{
+    return d && d->res.sub;
+}
+
+const char *GpgME::KeyGenerationResult::fingerprint() const
+{
+    return d ? d->res.fpr : 0 ;
+}
diff --git a/lang/cpp/src/keygenerationresult.h b/lang/cpp/src/keygenerationresult.h
new file mode 100644 (file)
index 0000000..c4aaad1
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+  keygenerationresult.h - wraps a gpgme keygen result
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_KEYGENERATIONRESULT_H__
+#define __GPGMEPP_KEYGENERATIONRESULT_H__
+
+#include "gpgmefw.h"
+#include "result.h"
+#include "gpgmepp_export.h"
+
+#include <boost/shared_ptr.hpp>
+
+namespace GpgME
+{
+
+class Error;
+
+class GPGMEPP_EXPORT KeyGenerationResult : public Result
+{
+public:
+    KeyGenerationResult();
+    KeyGenerationResult(gpgme_ctx_t ctx, int error);
+    KeyGenerationResult(gpgme_ctx_t ctx, const Error &error);
+    explicit KeyGenerationResult(const Error &err);
+
+    const KeyGenerationResult &operator=(KeyGenerationResult other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(KeyGenerationResult &other)
+    {
+        Result::swap(other);
+        using std::swap;
+        swap(this->d, other.d);
+    }
+
+    bool isNull() const;
+
+    GPGMEPP_DEPRECATED bool primaryKeyGenerated() const
+    {
+        return isPrimaryKeyGenerated();
+    }
+    GPGMEPP_DEPRECATED bool subkeyGenerated() const
+    {
+        return isSubkeyGenerated();
+    }
+    bool isPrimaryKeyGenerated() const;
+    bool isSubkeyGenerated() const;
+    const char *fingerprint() const;
+
+private:
+    class Private;
+    void init(gpgme_ctx_t ctx);
+    boost::shared_ptr<Private> d;
+};
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(KeyGenerationResult)
+
+#endif // __GPGMEPP_KEYGENERATIONRESULT_H__
diff --git a/lang/cpp/src/keylistresult.cpp b/lang/cpp/src/keylistresult.cpp
new file mode 100644 (file)
index 0000000..4aa3e11
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+  keylistresult.cpp - wraps a gpgme keylist result
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include <keylistresult.h>
+#include "result_p.h"
+
+#include <gpgme.h>
+
+#include <cstring>
+#include <cassert>
+
+class GpgME::KeyListResult::Private
+{
+public:
+    Private(const _gpgme_op_keylist_result &r) : res(r) {}
+    Private(const Private &other) : res(other.res) {}
+
+    _gpgme_op_keylist_result res;
+};
+
+GpgME::KeyListResult::KeyListResult(gpgme_ctx_t ctx, int error)
+    : GpgME::Result(error), d()
+{
+    init(ctx);
+}
+
+GpgME::KeyListResult::KeyListResult(gpgme_ctx_t ctx, const Error &error)
+    : GpgME::Result(error), d()
+{
+    init(ctx);
+}
+
+void GpgME::KeyListResult::init(gpgme_ctx_t ctx)
+{
+    if (!ctx) {
+        return;
+    }
+    gpgme_keylist_result_t res = gpgme_op_keylist_result(ctx);
+    if (!res) {
+        return;
+    }
+    d.reset(new Private(*res));
+}
+
+GpgME::KeyListResult::KeyListResult(const Error &error, const _gpgme_op_keylist_result &res)
+    : GpgME::Result(error), d(new Private(res))
+{
+
+}
+
+make_standard_stuff(KeyListResult)
+
+void GpgME::KeyListResult::detach()
+{
+    if (!d || d.unique()) {
+        return;
+    }
+    d.reset(new Private(*d));
+}
+
+void GpgME::KeyListResult::mergeWith(const KeyListResult &other)
+{
+    if (other.isNull()) {
+        return;
+    }
+    if (isNull()) {   // just assign
+        operator=(other);
+        return;
+    }
+    // merge the truncated flag (try to keep detaching to a minimum):
+    if (other.isTruncated() && !this->isTruncated()) {
+        assert(other.d);
+        detach();
+        if (!d) {
+            d.reset(new Private(*other.d));
+        } else {
+            d->res.truncated = true;
+        }
+    }
+    if (! bool(error())) {    // only merge the error when there was none yet.
+        Result::operator=(other);
+    }
+}
+
+bool GpgME::KeyListResult::isTruncated() const
+{
+    return d && d->res.truncated;
+}
diff --git a/lang/cpp/src/keylistresult.h b/lang/cpp/src/keylistresult.h
new file mode 100644 (file)
index 0000000..618573b
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+  keylistresult.h - wraps a gpgme keylist result
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_KEYLISTRESULT_H__
+#define __GPGMEPP_KEYLISTRESULT_H__
+
+#include "gpgmefw.h"
+#include "result.h"
+#include "gpgmepp_export.h"
+
+#include <boost/shared_ptr.hpp>
+
+namespace GpgME
+{
+
+class Error;
+
+class GPGMEPP_EXPORT KeyListResult : public Result
+{
+public:
+    KeyListResult();
+    KeyListResult(gpgme_ctx_t ctx, int error);
+    KeyListResult(gpgme_ctx_t ctx, const Error &error);
+    explicit KeyListResult(const Error &err);
+    KeyListResult(const Error &err, const _gpgme_op_keylist_result &res);
+
+    const KeyListResult &operator=(KeyListResult other)
+    {
+        swap(other);
+        return *this;
+    }
+    void swap(KeyListResult &other)
+    {
+        Result::swap(other);
+        using std::swap;
+        swap(this->d, other.d);
+    }
+
+    const KeyListResult &operator+=(const KeyListResult &other)
+    {
+        mergeWith(other);
+        return *this;
+    }
+
+    void mergeWith(const KeyListResult &other);
+
+    bool isNull() const;
+
+    bool isTruncated() const;
+
+private:
+    void detach();
+    void init(gpgme_ctx_t ctx);
+    class Private;
+    boost::shared_ptr<Private> d;
+};
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(KeyListResult)
+
+#endif // __GPGMEPP_KEYLISTRESULT_H__
diff --git a/lang/cpp/src/notation.h b/lang/cpp/src/notation.h
new file mode 100644 (file)
index 0000000..c53237c
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+  notation.h - wraps a gpgme verify result
+  Copyright (C) 2004, 2007 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_NOTATION_H__
+#define __GPGMEPP_NOTATION_H__
+
+#include "gpgmefw.h"
+#include "verificationresult.h"
+#include "gpgmepp_export.h"
+
+#include <boost/shared_ptr.hpp>
+
+#include <iosfwd>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT Notation
+{
+    friend class ::GpgME::Signature;
+    Notation(const boost::shared_ptr<VerificationResult::Private> &parent, unsigned int sindex, unsigned int nindex);
+public:
+    Notation();
+    explicit Notation(gpgme_sig_notation_t nota);
+
+    const Notation &operator=(Notation other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(Notation &other)
+    {
+        using std::swap;
+        swap(this->d, other.d);
+    }
+
+    bool isNull() const;
+
+    const char *name() const;
+    const char *value() const;
+
+    enum Flags {
+        NoFlags = 0,
+        HumanReadable = 1,
+        Critical = 2
+    };
+    Flags flags() const;
+
+    bool isHumanReadable() const;
+    bool isCritical() const;
+
+private:
+    class Private;
+    boost::shared_ptr<Private> d;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Notation &nota);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Notation::Flags flags);
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Notation)
+
+#endif // __GPGMEPP_NOTATION_H__
diff --git a/lang/cpp/src/result.h b/lang/cpp/src/result.h
new file mode 100644 (file)
index 0000000..1eae5b1
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  result.h - base class for results
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_RESULT_H__
+#define __GPGMEPP_RESULT_H__
+
+#include "gpgmefw.h"
+#include "error.h"
+
+#include <algorithm> // std::swap
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT Result
+{
+protected:
+    explicit Result() : mError() {}
+    explicit Result(int error) : mError(error) {}
+    explicit Result(const Error &error) : mError(error) {}
+
+    void swap(Result &other)
+    {
+        std::swap(other.mError, mError);
+    }
+
+public:
+    const Error &error() const
+    {
+        return mError;
+    }
+
+protected:
+    Error mError;
+};
+
+}
+
+#endif // __GPGMEPP_RESULT_H__
diff --git a/lang/cpp/src/result_p.h b/lang/cpp/src/result_p.h
new file mode 100644 (file)
index 0000000..0cf73e4
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+  result.h - base class for results
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_RESULT_P_H__
+#define __GPGMEPP_RESULT_P_H__
+
+#define make_default_ctor(x) \
+    GpgME::x::x() : GpgME::Result(), d() {}
+
+#define make_error_ctor(x) \
+    GpgME::x::x( const Error & error ) \
+        : GpgME::Result( error ), d() \
+    { \
+        \
+    }
+
+#define make_isNull(x) bool GpgME::x::isNull() const { return !d && !bool(error()); }
+
+#define make_standard_stuff(x) \
+    make_default_ctor(x) \
+    make_error_ctor(x) \
+    make_isNull(x)
+
+#endif // __GPGMEPP_RESULT_P_H__
diff --git a/lang/cpp/src/scdgetinfoassuantransaction.cpp b/lang/cpp/src/scdgetinfoassuantransaction.cpp
new file mode 100644 (file)
index 0000000..d9b0f9d
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+  scdgetinfoassuantransaction.cpp - Assuan Transaction to get information from scdaemon
+  Copyright (C) 2009 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include "scdgetinfoassuantransaction.h"
+#include "error.h"
+#include "data.h"
+#include "util.h"
+
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/static_assert.hpp>
+
+#include <sstream>
+
+using namespace GpgME;
+using namespace boost;
+
+ScdGetInfoAssuanTransaction::ScdGetInfoAssuanTransaction(InfoItem item)
+    : AssuanTransaction(),
+      m_item(item),
+      m_command(),
+      m_data()
+{
+
+}
+
+ScdGetInfoAssuanTransaction::~ScdGetInfoAssuanTransaction() {}
+
+static std::vector<std::string> to_reader_list(const std::string &s)
+{
+    std::vector<std::string> result;
+    return split(result, s, is_any_of("\n"), token_compress_on);
+}
+
+static std::vector<std::string> to_app_list(const std::string &s)
+{
+    return to_reader_list(s);
+}
+
+std::string ScdGetInfoAssuanTransaction::version() const
+{
+    if (m_item == Version) {
+        return m_data;
+    } else {
+        return std::string();
+    }
+}
+
+unsigned int ScdGetInfoAssuanTransaction::pid() const
+{
+    if (m_item == Pid) {
+        return to_pid(m_data);
+    } else {
+        return 0U;
+    }
+}
+
+std::string ScdGetInfoAssuanTransaction::socketName() const
+{
+    if (m_item == SocketName) {
+        return m_data;
+    } else {
+        return std::string();
+    }
+}
+
+char ScdGetInfoAssuanTransaction::status() const
+{
+    if (m_item == Status && !m_data.empty()) {
+        return m_data[0];
+    } else {
+        return '\0';
+    }
+}
+
+std::vector<std::string> ScdGetInfoAssuanTransaction::readerList() const
+{
+    if (m_item == ReaderList) {
+        return to_reader_list(m_data);
+    } else {
+        return std::vector<std::string>();
+    }
+}
+
+std::vector<std::string> ScdGetInfoAssuanTransaction::applicationList() const
+{
+    if (m_item == ApplicationList) {
+        return to_app_list(m_data);
+    } else {
+        return std::vector<std::string>();
+    }
+}
+
+static const char *const scd_getinfo_tokens[] = {
+    "version",
+    "pid",
+    "socket_name",
+    "status",
+    "reader_list",
+    "deny_admin",
+    "app_list",
+};
+BOOST_STATIC_ASSERT((sizeof scd_getinfo_tokens / sizeof * scd_getinfo_tokens == ScdGetInfoAssuanTransaction::LastInfoItem));
+
+void ScdGetInfoAssuanTransaction::makeCommand() const
+{
+    assert(m_item >= 0);
+    assert(m_item < LastInfoItem);
+    m_command = "SCD GETINFO ";
+    m_command += scd_getinfo_tokens[m_item];
+}
+
+const char *ScdGetInfoAssuanTransaction::command() const
+{
+    makeCommand();
+    return m_command.c_str();
+}
+
+Error ScdGetInfoAssuanTransaction::data(const char *data, size_t len)
+{
+    m_data.append(data, len);
+    return Error();
+}
+
+Data ScdGetInfoAssuanTransaction::inquire(const char *name, const char *args, Error &err)
+{
+    (void)name; (void)args; (void)err;
+    return Data::null;
+}
+
+Error ScdGetInfoAssuanTransaction::status(const char *status, const char *args)
+{
+    (void)status; (void)args;
+    return Error();
+}
diff --git a/lang/cpp/src/scdgetinfoassuantransaction.h b/lang/cpp/src/scdgetinfoassuantransaction.h
new file mode 100644 (file)
index 0000000..a22a0ff
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+  scdgetinfoassuantransaction.h - Assuan Transaction to get information from scdaemon
+  Copyright (C) 2009 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_SCDGETINFOASSUANTRANSACTION_H__
+#define __GPGMEPP_SCDGETINFOASSUANTRANSACTION_H__
+
+#include <interfaces/assuantransaction.h>
+
+#include <string>
+#include <vector>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT ScdGetInfoAssuanTransaction : public AssuanTransaction
+{
+public:
+    enum InfoItem {
+        Version,         // string
+        Pid,             // unsigned long
+        SocketName,      // string (path)
+        Status,          // char (status)
+        ReaderList,      // string list
+        DenyAdmin,       // (none, returns GPG_ERR_GENERAL when admin commands are allowed)
+        ApplicationList, // string list
+
+        LastInfoItem
+    };
+
+    explicit ScdGetInfoAssuanTransaction(InfoItem item);
+    ~ScdGetInfoAssuanTransaction();
+
+    std::string version() const;
+    unsigned int pid() const;
+    std::string socketName() const;
+    char status() const;
+    std::vector<std::string> readerList() const;
+    std::vector<std::string> applicationList() const;
+
+private:
+    /* reimp */ const char *command() const;
+    /* reimp */ Error data(const char *data, size_t datalen);
+    /* reimp */ Data inquire(const char *name, const char *args, Error &err);
+    /* reimp */ Error status(const char *status, const char *args);
+
+private:
+    void makeCommand() const;
+
+private:
+    InfoItem m_item;
+    mutable std::string m_command;
+    std::string m_data;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_SCDGETINFOASSUANTRANSACTION_H__
diff --git a/lang/cpp/src/signingresult.cpp b/lang/cpp/src/signingresult.cpp
new file mode 100644 (file)
index 0000000..f5f671b
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+  signingresult.cpp - wraps a gpgme verify result
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include <signingresult.h>
+#include "result_p.h"
+#include "util.h"
+
+#include <gpgme.h>
+
+#include <cstring>
+#include <cstdlib>
+#include <algorithm>
+#include <istream>
+#include <iterator>
+
+#include <string.h>
+
+class GpgME::SigningResult::Private
+{
+public:
+    Private(const gpgme_sign_result_t r)
+    {
+        if (!r) {
+            return;
+        }
+        for (gpgme_new_signature_t is = r->signatures ; is ; is = is->next) {
+            gpgme_new_signature_t copy = new _gpgme_new_signature(*is);
+            if (is->fpr) {
+                copy->fpr = strdup(is->fpr);
+            }
+            copy->next = 0;
+            created.push_back(copy);
+        }
+        for (gpgme_invalid_key_t ik = r->invalid_signers ; ik ; ik = ik->next) {
+            gpgme_invalid_key_t copy = new _gpgme_invalid_key(*ik);
+            if (ik->fpr) {
+                copy->fpr = strdup(ik->fpr);
+            }
+            copy->next = 0;
+            invalid.push_back(copy);
+        }
+    }
+    ~Private()
+    {
+        for (std::vector<gpgme_new_signature_t>::iterator it = created.begin() ; it != created.end() ; ++it) {
+            std::free((*it)->fpr);
+            delete *it; *it = 0;
+        }
+        for (std::vector<gpgme_invalid_key_t>::iterator it = invalid.begin() ; it != invalid.end() ; ++it) {
+            std::free((*it)->fpr);
+            delete *it; *it = 0;
+        }
+    }
+
+    std::vector<gpgme_new_signature_t> created;
+    std::vector<gpgme_invalid_key_t> invalid;
+};
+
+GpgME::SigningResult::SigningResult(gpgme_ctx_t ctx, int error)
+    : GpgME::Result(error), d()
+{
+    init(ctx);
+}
+
+GpgME::SigningResult::SigningResult(gpgme_ctx_t ctx, const Error &error)
+    : GpgME::Result(error), d()
+{
+    init(ctx);
+}
+
+void GpgME::SigningResult::init(gpgme_ctx_t ctx)
+{
+    if (!ctx) {
+        return;
+    }
+    gpgme_sign_result_t res = gpgme_op_sign_result(ctx);
+    if (!res) {
+        return;
+    }
+    d.reset(new Private(res));
+}
+
+make_standard_stuff(SigningResult)
+
+GpgME::CreatedSignature GpgME::SigningResult::createdSignature(unsigned int idx) const
+{
+    return CreatedSignature(d, idx);
+}
+
+std::vector<GpgME::CreatedSignature> GpgME::SigningResult::createdSignatures() const
+{
+    if (!d) {
+        return std::vector<CreatedSignature>();
+    }
+    std::vector<CreatedSignature> result;
+    result.reserve(d->created.size());
+    for (unsigned int i = 0 ; i < d->created.size() ; ++i) {
+        result.push_back(CreatedSignature(d, i));
+    }
+    return result;
+}
+
+GpgME::InvalidSigningKey GpgME::SigningResult::invalidSigningKey(unsigned int idx) const
+{
+    return InvalidSigningKey(d, idx);
+}
+
+std::vector<GpgME::InvalidSigningKey> GpgME::SigningResult::invalidSigningKeys() const
+{
+    if (!d) {
+        return std::vector<GpgME::InvalidSigningKey>();
+    }
+    std::vector<GpgME::InvalidSigningKey> result;
+    result.reserve(d->invalid.size());
+    for (unsigned int i = 0 ; i < d->invalid.size() ; ++i) {
+        result.push_back(InvalidSigningKey(d, i));
+    }
+    return result;
+}
+
+GpgME::InvalidSigningKey::InvalidSigningKey(const boost::shared_ptr<SigningResult::Private> &parent, unsigned int i)
+    : d(parent), idx(i)
+{
+
+}
+
+GpgME::InvalidSigningKey::InvalidSigningKey() : d(), idx(0) {}
+
+bool GpgME::InvalidSigningKey::isNull() const
+{
+    return !d || idx >= d->invalid.size() ;
+}
+
+const char *GpgME::InvalidSigningKey::fingerprint() const
+{
+    return isNull() ? 0 : d->invalid[idx]->fpr ;
+}
+
+GpgME::Error GpgME::InvalidSigningKey::reason() const
+{
+    return Error(isNull() ? 0 : d->invalid[idx]->reason);
+}
+
+GpgME::CreatedSignature::CreatedSignature(const boost::shared_ptr<SigningResult::Private> &parent, unsigned int i)
+    : d(parent), idx(i)
+{
+
+}
+
+GpgME::CreatedSignature::CreatedSignature() : d(), idx(0) {}
+
+bool GpgME::CreatedSignature::isNull() const
+{
+    return !d || idx >= d->created.size() ;
+}
+
+const char *GpgME::CreatedSignature::fingerprint() const
+{
+    return isNull() ? 0 : d->created[idx]->fpr ;
+}
+
+time_t GpgME::CreatedSignature::creationTime() const
+{
+    return static_cast<time_t>(isNull() ? 0 : d->created[idx]->timestamp);
+}
+
+GpgME::SignatureMode GpgME::CreatedSignature::mode() const
+{
+    if (isNull()) {
+        return NormalSignatureMode;
+    }
+    switch (d->created[idx]->type) {
+    default:
+    case GPGME_SIG_MODE_NORMAL: return NormalSignatureMode;
+    case GPGME_SIG_MODE_DETACH: return Detached;
+    case GPGME_SIG_MODE_CLEAR:  return Clearsigned;
+    }
+}
+
+unsigned int GpgME::CreatedSignature::publicKeyAlgorithm() const
+{
+    return isNull() ? 0 : d->created[idx]->pubkey_algo ;
+}
+
+const char *GpgME::CreatedSignature::publicKeyAlgorithmAsString() const
+{
+    return gpgme_pubkey_algo_name(isNull() ? (gpgme_pubkey_algo_t)0 : d->created[idx]->pubkey_algo);
+}
+
+unsigned int GpgME::CreatedSignature::hashAlgorithm() const
+{
+    return isNull() ? 0 : d->created[idx]->hash_algo ;
+}
+
+const char *GpgME::CreatedSignature::hashAlgorithmAsString() const
+{
+    return gpgme_hash_algo_name(isNull() ? (gpgme_hash_algo_t)0 : d->created[idx]->hash_algo);
+}
+
+unsigned int GpgME::CreatedSignature::signatureClass() const
+{
+    return isNull() ? 0 : d->created[idx]->sig_class ;
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const SigningResult &result)
+{
+    os << "GpgME::SigningResult(";
+    if (!result.isNull()) {
+        os << "\n error:              " << result.error()
+           << "\n createdSignatures:\n";
+        const std::vector<CreatedSignature> cs = result.createdSignatures();
+        std::copy(cs.begin(), cs.end(),
+                  std::ostream_iterator<CreatedSignature>(os, "\n"));
+        os << " invalidSigningKeys:\n";
+        const std::vector<InvalidSigningKey> isk = result.invalidSigningKeys();
+        std::copy(isk.begin(), isk.end(),
+                  std::ostream_iterator<InvalidSigningKey>(os, "\n"));
+    }
+    return os << ')';
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const CreatedSignature &sig)
+{
+    os << "GpgME::CreatedSignature(";
+    if (!sig.isNull()) {
+        os << "\n fingerprint:        " << protect(sig.fingerprint())
+           << "\n creationTime:       " << sig.creationTime()
+           << "\n mode:               " << sig.mode()
+           << "\n publicKeyAlgorithm: " << protect(sig.publicKeyAlgorithmAsString())
+           << "\n hashAlgorithm:      " << protect(sig.hashAlgorithmAsString())
+           << "\n signatureClass:     " << sig.signatureClass()
+           << '\n';
+    }
+    return os << ')';
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const InvalidSigningKey &key)
+{
+    os << "GpgME::InvalidSigningKey(";
+    if (!key.isNull()) {
+        os << "\n fingerprint: " << protect(key.fingerprint())
+           << "\n reason:      " << key.reason()
+           << '\n';
+    }
+    return os << ')';
+}
diff --git a/lang/cpp/src/signingresult.h b/lang/cpp/src/signingresult.h
new file mode 100644 (file)
index 0000000..1847fb0
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+  signingresult.h - wraps a gpgme sign result
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_SIGNINGRESULT_H__
+#define __GPGMEPP_SIGNINGRESULT_H__
+
+#include "global.h"
+#include "result.h"
+
+#include <time.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <vector>
+#include <iosfwd>
+
+namespace GpgME
+{
+
+class Error;
+class CreatedSignature;
+class InvalidSigningKey;
+
+class GPGMEPP_EXPORT SigningResult : public Result
+{
+public:
+    SigningResult();
+    SigningResult(gpgme_ctx_t ctx, int error);
+    SigningResult(gpgme_ctx_t ctx, const Error &error);
+    explicit SigningResult(const Error &err);
+
+    const SigningResult &operator=(SigningResult other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(SigningResult &other)
+    {
+        Result::swap(other);
+        using std::swap;
+        swap(this->d, other.d);
+    }
+
+    bool isNull() const;
+
+    CreatedSignature createdSignature(unsigned int index) const;
+    std::vector<CreatedSignature> createdSignatures() const;
+
+    InvalidSigningKey invalidSigningKey(unsigned int index) const;
+    std::vector<InvalidSigningKey> invalidSigningKeys() const;
+
+    class Private;
+private:
+    void init(gpgme_ctx_t ctx);
+    boost::shared_ptr<Private> d;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const SigningResult &result);
+
+class GPGMEPP_EXPORT InvalidSigningKey
+{
+    friend class ::GpgME::SigningResult;
+    InvalidSigningKey(const boost::shared_ptr<SigningResult::Private> &parent, unsigned int index);
+public:
+    InvalidSigningKey();
+
+    const InvalidSigningKey &operator=(InvalidSigningKey other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(InvalidSigningKey &other)
+    {
+        using std::swap;
+        swap(this->d, other.d);
+        swap(this->idx, other.idx);
+    }
+
+    bool isNull() const;
+
+    const char *fingerprint() const;
+    Error reason() const;
+
+private:
+    boost::shared_ptr<SigningResult::Private> d;
+    unsigned int idx;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const InvalidSigningKey &key);
+
+class GPGMEPP_EXPORT CreatedSignature
+{
+    friend class ::GpgME::SigningResult;
+    CreatedSignature(const boost::shared_ptr<SigningResult::Private> &parent, unsigned int index);
+public:
+
+    CreatedSignature();
+
+    const CreatedSignature &operator=(CreatedSignature other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(CreatedSignature &other)
+    {
+        using std::swap;
+        swap(this->d, other.d);
+        swap(this->idx, other.idx);
+    }
+
+    bool isNull() const;
+
+    const char *fingerprint() const;
+
+    time_t creationTime() const;
+
+    SignatureMode mode() const;
+
+    unsigned int publicKeyAlgorithm() const;
+    const char *publicKeyAlgorithmAsString() const;
+
+    unsigned int hashAlgorithm() const;
+    const char *hashAlgorithmAsString() const;
+
+    unsigned int signatureClass() const;
+
+private:
+    boost::shared_ptr<SigningResult::Private> d;
+    unsigned int idx;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const CreatedSignature &sig);
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(SigningResult)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(InvalidSigningKey)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(CreatedSignature)
+
+#endif // __GPGMEPP_SIGNINGRESULT_H__
diff --git a/lang/cpp/src/trustitem.cpp b/lang/cpp/src/trustitem.cpp
new file mode 100644 (file)
index 0000000..1abaf7e
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+  trustitem.cpp - wraps a gpgme trust item
+  Copyright (C) 2003 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include <config-gpgme++.h>
+
+#include <trustitem.h>
+
+#include <gpgme.h>
+
+#include <cassert>
+
+namespace GpgME
+{
+
+class TrustItem::Private
+{
+public:
+    Private(gpgme_trust_item_t aItem)
+        : item(aItem)
+    {
+    }
+
+    gpgme_trust_item_t item;
+};
+
+TrustItem::TrustItem(gpgme_trust_item_t item)
+{
+    d = new Private(item);
+    if (d->item) {
+        gpgme_trust_item_ref(d->item);
+    }
+}
+
+TrustItem::TrustItem(const TrustItem &other)
+{
+    d = new Private(other.d->item);
+    if (d->item) {
+        gpgme_trust_item_ref(d->item);
+    }
+}
+
+TrustItem::~TrustItem()
+{
+    if (d->item) {
+        gpgme_trust_item_unref(d->item);
+    }
+    delete d; d = 0;
+}
+
+bool TrustItem::isNull() const
+{
+    return !d || !d->item;
+}
+
+gpgme_trust_item_t TrustItem::impl() const
+{
+    return d->item;
+}
+
+const char *TrustItem::keyID() const
+{
+    return d->item ? d->item->keyid : 0 ;
+}
+
+const char *TrustItem::userID() const
+{
+    return d->item ? d->item->name : 0 ;
+}
+
+const char *TrustItem::ownerTrustAsString() const
+{
+    return d->item ? d->item->owner_trust : 0 ;
+}
+
+const char *TrustItem::validityAsString() const
+{
+    return d->item ? d->item->validity : 0 ;
+}
+
+int TrustItem::trustLevel() const
+{
+    return d->item ? d->item->level : 0 ;
+}
+
+TrustItem::Type TrustItem::type() const
+{
+    if (!d->item) {
+        return Unknown;
+    } else {
+        return
+            d->item->type == 1 ? Key :
+            d->item->type == 2 ? UserID :
+            Unknown ;
+    }
+}
+
+} // namespace GpgME
diff --git a/lang/cpp/src/trustitem.h b/lang/cpp/src/trustitem.h
new file mode 100644 (file)
index 0000000..65f109c
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+  trustitem.h - wraps a gpgme trust item
+  Copyright (C) 2003 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_TRUSTITEM_H__
+#define __GPGMEPP_TRUSTITEM_H__
+
+#include "gpgmefw.h"
+#include <key.h>
+#include "gpgmepp_export.h"
+
+#include <algorithm>
+
+namespace GpgME
+{
+
+class Context;
+
+class GPGMEPP_EXPORT TrustItem
+{
+    friend class ::GpgME::Context;
+public:
+    explicit TrustItem(gpgme_trust_item_t item = 0);
+    TrustItem(const TrustItem &other);
+    virtual ~TrustItem();
+
+    const TrustItem &operator=(TrustItem other)
+    {
+        swap(other);
+        return *this;
+    }
+
+    void swap(TrustItem &other)
+    {
+        using std::swap;
+        swap(this->d, other.d);
+    }
+
+    bool isNull() const;
+
+    const char *keyID() const;
+    const char *userID() const;
+
+    const char *ownerTrustAsString() const;
+    const char *validityAsString() const;
+
+    int trustLevel() const;
+
+    enum Type { Unknown = 0, Key = 1, UserID = 2 };
+    Type type() const;
+
+private:
+    gpgme_trust_item_t impl() const;
+    class Private;
+    Private *d;
+};
+
+} // namepace GpgME
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(TrustItem)
+
+#endif // __GPGMEPP_TRUSTITEM_H__
diff --git a/lang/cpp/src/util.h b/lang/cpp/src/util.h
new file mode 100644 (file)
index 0000000..ed526e1
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+  util.h - some inline helper functions
+  Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+  This file is part of GPGME++.
+
+  GPGME++ is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  GPGME++ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with GPGME++; see the file COPYING.LIB.  If not, write to the
+  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_UTIL_H__
+#define __GPGMEPP_UTIL_H__
+
+#include "global.h"
+#include "notation.h"
+
+#include <gpgme.h>
+
+#ifndef NDEBUG
+#include <iostream>
+#endif
+#include <sstream>
+#include <string>
+
+static inline const char *protect(const char *s)
+{
+    return s ? s : "<null>" ;
+}
+
+static inline gpgme_error_t make_error(gpgme_err_code_t code)
+{
+    return gpgme_err_make((gpgme_err_source_t)22, code);
+}
+
+static inline unsigned long to_pid(const std::string &s)
+{
+    std::stringstream ss(s);
+    unsigned int result;
+    if (ss >> result) {
+        return result;
+    } else {
+        return 0U;
+    }
+}
+
+static inline gpgme_keylist_mode_t add_to_gpgme_keylist_mode_t(unsigned int oldmode, unsigned int newmodes)
+{
+    if (newmodes & GpgME::Local) {
+        oldmode |= GPGME_KEYLIST_MODE_LOCAL;
+    }
+    if (newmodes & GpgME::Extern) {
+        oldmode |= GPGME_KEYLIST_MODE_EXTERN;
+    }
+    if (newmodes & GpgME::Signatures) {
+        oldmode |= GPGME_KEYLIST_MODE_SIGS;
+    }
+    if (newmodes & GpgME::SignatureNotations) {
+#ifdef HAVE_GPGME_KEYLIST_MODE_SIG_NOTATIONS
+        oldmode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
+#elif !defined(NDEBUG)
+        ;//std::cerr << "GpgME: ignoring SignatureNotations keylist flag (gpgme too old)." << std::endl;
+#endif
+    }
+    if (newmodes & GpgME::Ephemeral) {
+#ifdef HAVE_GPGME_KEYLIST_MODE_EPHEMERAL
+        oldmode |= GPGME_KEYLIST_MODE_EPHEMERAL;
+#elif !defined(NDEBUG)
+        ;//std::cerr << "GpgME: ignoring Ephemeral keylist flag (gpgme too old)." << std::endl;
+#endif
+    }
+    if (newmodes & GpgME::Validate) {
+        oldmode |= GPGME_KEYLIST_MODE_VALIDATE;
+    }