diff options
author | Andre Heinecke <[email protected]> | 2016-02-22 17:28:08 +0000 |
---|---|---|
committer | Andre Heinecke <[email protected]> | 2016-02-22 18:01:37 +0000 |
commit | 0855a1296a1908016f011eb5e6552854ac53e63a (patch) | |
tree | ae662e7201a7d60d0e7733532ebded629cfacb94 | |
parent | Fix possible _SC_OPEN_MAX max problem on AIX. (diff) | |
download | gpgme-0855a1296a1908016f011eb5e6552854ac53e63a.tar.gz gpgme-0855a1296a1908016f011eb5e6552854ac53e63a.zip |
Initial checkin of gpgmepp sources
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, 12197 insertions, 0 deletions
diff --git a/lang/cpp/src/assuanresult.cpp b/lang/cpp/src/assuanresult.cpp new file mode 100644 index 00000000..056aefb3 --- /dev/null +++ b/lang/cpp/src/assuanresult.cpp @@ -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 index 00000000..e1dc73af --- /dev/null +++ b/lang/cpp/src/assuanresult.h @@ -0,0 +1,80 @@ +/* + assuanresult.h - wraps a gpgme assuan result + Copyright (C) 2009 Klarälvdalens Datakonsult AB <[email protected]> + Author: Marc Mutz <[email protected]> + + 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 index 00000000..091975d7 --- /dev/null +++ b/lang/cpp/src/callbacks.cpp @@ -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 index 00000000..42066379 --- /dev/null +++ b/lang/cpp/src/callbacks.h @@ -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 index 00000000..fc19020e --- /dev/null +++ b/lang/cpp/src/configuration.cpp @@ -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 index 00000000..e6e13db4 --- /dev/null +++ b/lang/cpp/src/configuration.h @@ -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 index 00000000..ab633d7a --- /dev/null +++ b/lang/cpp/src/context.cpp @@ -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 index 00000000..ee4f847e --- /dev/null +++ b/lang/cpp/src/context.h @@ -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 index 00000000..383b8eb6 --- /dev/null +++ b/lang/cpp/src/context_glib.cpp @@ -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 index 00000000..2991123a --- /dev/null +++ b/lang/cpp/src/context_p.h @@ -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 index 00000000..e6d44fa1 --- /dev/null +++ b/lang/cpp/src/context_qt.cpp @@ -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 index 00000000..30b18b46 --- /dev/null +++ b/lang/cpp/src/context_vanilla.cpp @@ -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 index 00000000..6b29aaf4 --- /dev/null +++ b/lang/cpp/src/data.cpp @@ -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 index 00000000..c8a599ed --- /dev/null +++ b/lang/cpp/src/data.h @@ -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 index 00000000..38ba55af --- /dev/null +++ b/lang/cpp/src/data_p.h @@ -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 index 00000000..88e85670 --- /dev/null +++ b/lang/cpp/src/decryptionresult.cpp @@ -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 index 00000000..2374cbba --- /dev/null +++ b/lang/cpp/src/decryptionresult.h @@ -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 index 00000000..c51050ca --- /dev/null +++ b/lang/cpp/src/defaultassuantransaction.cpp @@ -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 index 00000000..bf4b8395 --- /dev/null +++ b/lang/cpp/src/defaultassuantransaction.h @@ -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 index 00000000..0c5f7783 --- /dev/null +++ b/lang/cpp/src/editinteractor.cpp @@ -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 index 00000000..21220528 --- /dev/null +++ b/lang/cpp/src/editinteractor.h @@ -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 index 00000000..25e39229 --- /dev/null +++ b/lang/cpp/src/encryptionresult.cpp @@ -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 index 00000000..1f5d16f6 --- /dev/null +++ b/lang/cpp/src/encryptionresult.h @@ -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 index 00000000..eaff2bd6 --- /dev/null +++ b/lang/cpp/src/engineinfo.cpp @@ -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 index 00000000..94c52bd1 --- /dev/null +++ b/lang/cpp/src/engineinfo.h @@ -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 index 00000000..009fe20f --- /dev/null +++ b/lang/cpp/src/error.h @@ -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 index 00000000..4718ddc1 --- /dev/null +++ b/lang/cpp/src/eventloopinteractor.cpp @@ -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 index 00000000..94821d6d --- /dev/null +++ b/lang/cpp/src/eventloopinteractor.h @@ -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 index 00000000..c687024b --- /dev/null +++ b/lang/cpp/src/exception.cpp @@ -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 index 00000000..8f40b0e0 --- /dev/null +++ b/lang/cpp/src/exception.h @@ -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 index 00000000..f65503a1 --- /dev/null +++ b/lang/cpp/src/global.h @@ -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 index 00000000..43c8592e --- /dev/null +++ b/lang/cpp/src/gpgadduserideditinteractor.cpp @@ -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 index 00000000..12b6e46a --- /dev/null +++ b/lang/cpp/src/gpgadduserideditinteractor.h @@ -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 index 00000000..e07a8562 --- /dev/null +++ b/lang/cpp/src/gpgagentgetinfoassuantransaction.cpp @@ -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 index 00000000..9e3e9581 --- /dev/null +++ b/lang/cpp/src/gpgagentgetinfoassuantransaction.h @@ -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 index 00000000..cbdd444f --- /dev/null +++ b/lang/cpp/src/gpgmefw.h @@ -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 index 00000000..50a288de --- /dev/null +++ b/lang/cpp/src/gpgmepp_export.h @@ -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 index 00000000..8af897c3 --- /dev/null +++ b/lang/cpp/src/gpgsetexpirytimeeditinteractor.cpp @@ -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 index 00000000..670b4459 --- /dev/null +++ b/lang/cpp/src/gpgsetexpirytimeeditinteractor.h @@ -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 index 00000000..15b12699 --- /dev/null +++ b/lang/cpp/src/gpgsetownertrusteditinteractor.cpp @@ -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 index 00000000..caf29eed --- /dev/null +++ b/lang/cpp/src/gpgsetownertrusteditinteractor.h @@ -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 index 00000000..1950b2f9 --- /dev/null +++ b/lang/cpp/src/gpgsignkeyeditinteractor.cpp @@ -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 index 00000000..47ff8e55 --- /dev/null +++ b/lang/cpp/src/gpgsignkeyeditinteractor.h @@ -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 index 00000000..bd989d25 --- /dev/null +++ b/lang/cpp/src/importresult.cpp @@ -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 index 00000000..7dc0320b --- /dev/null +++ b/lang/cpp/src/importresult.h @@ -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 index 00000000..9acdf7d1 --- /dev/null +++ b/lang/cpp/src/interfaces/assuantransaction.h @@ -0,0 +1,47 @@ +/* + assuantransaction.h - Interface for ASSUAN transactions + Copyright (C) 2009 Klarälvdalens Datakonsult AB <[email protected]> + Author: Marc Mutz <[email protected]> + + 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 index 00000000..166bb4ec --- /dev/null +++ b/lang/cpp/src/interfaces/dataprovider.h @@ -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 index 00000000..5275e44b --- /dev/null +++ b/lang/cpp/src/interfaces/passphraseprovider.h @@ -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 index 00000000..78bbdd78 --- /dev/null +++ b/lang/cpp/src/interfaces/progressprovider.h @@ -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 index 00000000..5eadbdd2 --- /dev/null +++ b/lang/cpp/src/key.cpp @@ -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 index 00000000..80bf4d19 --- /dev/null +++ b/lang/cpp/src/key.h @@ -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 index 00000000..f365e432 --- /dev/null +++ b/lang/cpp/src/keygenerationresult.cpp @@ -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 index 00000000..c4aaad11 --- /dev/null +++ b/lang/cpp/src/keygenerationresult.h @@ -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 index 00000000..4aa3e11f --- /dev/null +++ b/lang/cpp/src/keylistresult.cpp @@ -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 index 00000000..618573be --- /dev/null +++ b/lang/cpp/src/keylistresult.h @@ -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 index 00000000..c53237c0 --- /dev/null +++ b/lang/cpp/src/notation.h @@ -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 ¬a); +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 index 00000000..1eae5b1d --- /dev/null +++ b/lang/cpp/src/result.h @@ -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 index 00000000..0cf73e42 --- /dev/null +++ b/lang/cpp/src/result_p.h @@ -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 index 00000000..d9b0f9d1 --- /dev/null +++ b/lang/cpp/src/scdgetinfoassuantransaction.cpp @@ -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 index 00000000..a22a0ffd --- /dev/null +++ b/lang/cpp/src/scdgetinfoassuantransaction.h @@ -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 index 00000000..f5f671b5 --- /dev/null +++ b/lang/cpp/src/signingresult.cpp @@ -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 index 00000000..1847fb0b --- /dev/null +++ b/lang/cpp/src/signingresult.h @@ -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 index 00000000..1abaf7e3 --- /dev/null +++ b/lang/cpp/src/trustitem.cpp @@ -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 index 00000000..65f109c8 --- /dev/null +++ b/lang/cpp/src/trustitem.h @@ -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 index 00000000..ed526e13 --- /dev/null +++ b/lang/cpp/src/util.h @@ -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; + } +#ifndef NDEBUG + if (newmodes & ~(GpgME::Local | GpgME::Extern | GpgME::Signatures | GpgME::SignatureNotations | GpgME::Ephemeral | GpgME::Validate)) { + //std::cerr << "GpgME::Context: keylist mode must be one of Local, " + //"Extern, Signatures, SignatureNotations, or Validate, or a combination thereof!" << std::endl; + } +#endif + return static_cast<gpgme_keylist_mode_t>(oldmode); +} + +static inline unsigned int convert_from_gpgme_keylist_mode_t(unsigned int mode) +{ + unsigned int result = 0; + if (mode & GPGME_KEYLIST_MODE_LOCAL) { + result |= GpgME::Local; + } + if (mode & GPGME_KEYLIST_MODE_EXTERN) { + result |= GpgME::Extern; + } + if (mode & GPGME_KEYLIST_MODE_SIGS) { + result |= GpgME::Signatures; + } +#ifdef HAVE_GPGME_KEYLIST_MODE_SIG_NOTATIONS + if (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS) { + result |= GpgME::SignatureNotations; + } +#endif +#ifdef HAVE_GPGME_KEYLIST_MODE_EPHEMERAL + if (mode & GPGME_KEYLIST_MODE_EPHEMERAL) { + result |= GpgME::Ephemeral; + } +#endif + if (mode & GPGME_KEYLIST_MODE_VALIDATE) { + result |= GpgME::Validate; + } +#ifndef NDEBUG + if (mode & ~(GPGME_KEYLIST_MODE_LOCAL | + GPGME_KEYLIST_MODE_EXTERN | +#ifdef HAVE_GPGME_KEYLIST_MODE_SIG_NOTATIONS + GPGME_KEYLIST_MODE_SIG_NOTATIONS | +#endif +#ifdef HAVE_GPGME_KEYLIST_MODE_EPHEMERAL + GPGME_KEYLIST_MODE_EPHEMERAL | +#endif + GPGME_KEYLIST_MODE_VALIDATE | + GPGME_KEYLIST_MODE_SIGS)) { + //std::cerr << "GpgME: WARNING: gpgme_get_keylist_mode() returned an unknown flag!" << std::endl; + } +#endif // NDEBUG + return result; +} + +static inline GpgME::Notation::Flags convert_from_gpgme_sig_notation_flags_t(unsigned int flags) +{ +#ifdef HAVE_GPGME_SIG_NOTATION_FLAGS_T + unsigned int result = 0; +#ifdef HAVE_GPGME_SIG_NOTATION_HUMAN_READABLE + if (flags & GPGME_SIG_NOTATION_HUMAN_READABLE) { + result |= GpgME::Notation::HumanReadable ; + } +#endif +#ifdef HAVE_GPGME_SIG_NOTATION_CRITICAL + if (flags & GPGME_SIG_NOTATION_CRITICAL) { + result |= GpgME::Notation::Critical ; + } +#endif + return static_cast<GpgME::Notation::Flags>(result); +#else + return GpgME::Notation::NoFlags; +#endif +} +#ifdef HAVE_GPGME_SIG_NOTATION_FLAGS_T +static inline gpgme_sig_notation_flags_t add_to_gpgme_sig_notation_flags_t(unsigned int oldflags, unsigned int newflags) +{ + unsigned int result = oldflags; + if (newflags & GpgME::Notation::HumanReadable) { +#ifdef HAVE_GPGME_SIG_NOTATION_HUMAN_READABLE + result |= GPGME_SIG_NOTATION_HUMAN_READABLE; +#elif !defined(NDEBUG) + //std::cerr << "GpgME::Context: ignoring HumanReadable signature notation flag (gpgme too old)" << std::endl; +#endif + } + if (newflags & GpgME::Notation::Critical) { +#ifdef HAVE_GPGME_SIG_NOTATION_CRITICAL + result |= GPGME_SIG_NOTATION_CRITICAL; +#elif !defined(NDEBUG) + //std::cerr << "GpgME::Context: ignoring Critical signature notation flag (gpgme too old)" << std::endl; +#endif + } + return static_cast<gpgme_sig_notation_flags_t>(result); +} +#endif + +#endif // __GPGMEPP_UTIL_H__ diff --git a/lang/cpp/src/verificationresult.cpp b/lang/cpp/src/verificationresult.cpp new file mode 100644 index 00000000..42d5ad27 --- /dev/null +++ b/lang/cpp/src/verificationresult.cpp @@ -0,0 +1,590 @@ +/* + verificationresult.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 <verificationresult.h> +#include <notation.h> +#include "result_p.h" +#include "util.h" + +#include <gpgme.h> + +#include <istream> +#include <algorithm> +#include <iterator> +#include <string> +#include <cstring> +#include <cstdlib> + +#include <string.h> + +class GpgME::VerificationResult::Private +{ +public: + explicit Private(const gpgme_verify_result_t r) + { + if (!r) { + return; + } +#ifdef HAVE_GPGME_VERIFY_RESULT_T_FILE_NAME + if (r->file_name) { + file_name = r->file_name; + } +#endif + // copy recursively, using compiler-generated copy ctor. + // We just need to handle the pointers in the structs: + for (gpgme_signature_t is = r->signatures ; is ; is = is->next) { + gpgme_signature_t scopy = new _gpgme_signature(*is); + if (is->fpr) { + scopy->fpr = strdup(is->fpr); + } +#ifdef HAVE_GPGME_SIGNATURE_T_PKA_FIELDS +// PENDING(marc) why does this crash on Windows in strdup()? +# ifndef _WIN32 + if (is->pka_address) { + scopy->pka_address = strdup(is->pka_address); + } +# else + scopy->pka_address = 0; +# endif +#endif + scopy->next = 0; + sigs.push_back(scopy); + // copy notations: + nota.push_back(std::vector<Nota>()); + purls.push_back(0); + for (gpgme_sig_notation_t in = is->notations ; in ; in = in->next) { + if (!in->name) { + if (in->value) { + purls.back() = strdup(in->value); // policy url + } + continue; + } +#ifdef HAVE_GPGME_SIG_NOTATION_FLAGS_T + Nota n = { 0, 0, in->flags }; +#else + Nota n = { 0, 0 }; +#endif + n.name = strdup(in->name); + if (in->value) { + n.value = strdup(in->value); + } + nota.back().push_back(n); + } + } + } + ~Private() + { + for (std::vector<gpgme_signature_t>::iterator it = sigs.begin() ; it != sigs.end() ; ++it) { + std::free((*it)->fpr); +#ifdef HAVE_GPGME_SIGNATURE_T_PKA_FIELDS + std::free((*it)->pka_address); +#endif + delete *it; *it = 0; + } + for (std::vector< std::vector<Nota> >::iterator it = nota.begin() ; it != nota.end() ; ++it) { + for (std::vector<Nota>::iterator jt = it->begin() ; jt != it->end() ; ++jt) { + std::free(jt->name); jt->name = 0; + std::free(jt->value); jt->value = 0; + } + } + std::for_each(purls.begin(), purls.end(), &std::free); + } + + struct Nota { + char *name; + char *value; +#ifdef HAVE_GPGME_SIG_NOTATION_FLAGS_T + gpgme_sig_notation_flags_t flags; +#endif + }; + + std::vector<gpgme_signature_t> sigs; + std::vector< std::vector<Nota> > nota; + std::vector<char *> purls; + std::string file_name; +}; + +GpgME::VerificationResult::VerificationResult(gpgme_ctx_t ctx, int error) + : GpgME::Result(error), d() +{ + init(ctx); +} + +GpgME::VerificationResult::VerificationResult(gpgme_ctx_t ctx, const Error &error) + : GpgME::Result(error), d() +{ + init(ctx); +} + +void GpgME::VerificationResult::init(gpgme_ctx_t ctx) +{ + if (!ctx) { + return; + } + gpgme_verify_result_t res = gpgme_op_verify_result(ctx); + if (!res) { + return; + } + d.reset(new Private(res)); +} + +make_standard_stuff(VerificationResult) + +const char *GpgME::VerificationResult::fileName() const +{ + return d ? d->file_name.c_str() : 0 ; +} + +unsigned int GpgME::VerificationResult::numSignatures() const +{ + return d ? d->sigs.size() : 0 ; +} + +GpgME::Signature GpgME::VerificationResult::signature(unsigned int idx) const +{ + return Signature(d, idx); +} + +std::vector<GpgME::Signature> GpgME::VerificationResult::signatures() const +{ + if (!d) { + return std::vector<Signature>(); + } + std::vector<Signature> result; + result.reserve(d->sigs.size()); + for (unsigned int i = 0 ; i < d->sigs.size() ; ++i) { + result.push_back(Signature(d, i)); + } + return result; +} + +GpgME::Signature::Signature(const boost::shared_ptr<VerificationResult::Private> &parent, unsigned int i) + : d(parent), idx(i) +{ +} + +GpgME::Signature::Signature() : d(), idx(0) {} + +bool GpgME::Signature::isNull() const +{ + return !d || idx >= d->sigs.size() ; +} + +GpgME::Signature::Summary GpgME::Signature::summary() const +{ + if (isNull()) { + return None; + } + gpgme_sigsum_t sigsum = d->sigs[idx]->summary; + unsigned int result = 0; + if (sigsum & GPGME_SIGSUM_VALID) { + result |= Valid; + } + if (sigsum & GPGME_SIGSUM_GREEN) { + result |= Green; + } + if (sigsum & GPGME_SIGSUM_RED) { + result |= Red; + } + if (sigsum & GPGME_SIGSUM_KEY_REVOKED) { + result |= KeyRevoked; + } + if (sigsum & GPGME_SIGSUM_KEY_EXPIRED) { + result |= KeyExpired; + } + if (sigsum & GPGME_SIGSUM_SIG_EXPIRED) { + result |= SigExpired; + } + if (sigsum & GPGME_SIGSUM_KEY_MISSING) { + result |= KeyMissing; + } + if (sigsum & GPGME_SIGSUM_CRL_MISSING) { + result |= CrlMissing; + } + if (sigsum & GPGME_SIGSUM_CRL_TOO_OLD) { + result |= CrlTooOld; + } + if (sigsum & GPGME_SIGSUM_BAD_POLICY) { + result |= BadPolicy; + } + if (sigsum & GPGME_SIGSUM_SYS_ERROR) { + result |= SysError; + } + return static_cast<Summary>(result); +} + +const char *GpgME::Signature::fingerprint() const +{ + return isNull() ? 0 : d->sigs[idx]->fpr ; +} + +GpgME::Error GpgME::Signature::status() const +{ + return Error(isNull() ? 0 : d->sigs[idx]->status); +} + +time_t GpgME::Signature::creationTime() const +{ + return static_cast<time_t>(isNull() ? 0 : d->sigs[idx]->timestamp); +} + +time_t GpgME::Signature::expirationTime() const +{ + return static_cast<time_t>(isNull() ? 0 : d->sigs[idx]->exp_timestamp); +} + +bool GpgME::Signature::neverExpires() const +{ + return expirationTime() == (time_t)0; +} + +bool GpgME::Signature::isWrongKeyUsage() const +{ + return !isNull() && d->sigs[idx]->wrong_key_usage; +} + +bool GpgME::Signature::isVerifiedUsingChainModel() const +{ +#ifdef HAVE_GPGME_SIGNATURE_T_CHAIN_MODEL + return !isNull() && d->sigs[idx]->chain_model; +#else + return false; +#endif +} + +GpgME::Signature::PKAStatus GpgME::Signature::pkaStatus() const +{ +#ifdef HAVE_GPGME_SIGNATURE_T_PKA_FIELDS + if (!isNull()) { + return static_cast<PKAStatus>(d->sigs[idx]->pka_trust); + } +#endif + return UnknownPKAStatus; +} + +const char *GpgME::Signature::pkaAddress() const +{ +#ifdef HAVE_GPGME_SIGNATURE_T_PKA_FIELDS + if (!isNull()) { + return d->sigs[idx]->pka_address; + } +#endif + return 0; +} + +GpgME::Signature::Validity GpgME::Signature::validity() const +{ + if (isNull()) { + return Unknown; + } + switch (d->sigs[idx]->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 GpgME::Signature::validityAsString() const +{ + if (isNull()) { + return '?'; + } + switch (d->sigs[idx]->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'; + } +} + +GpgME::Error GpgME::Signature::nonValidityReason() const +{ + return Error(isNull() ? 0 : d->sigs[idx]->validity_reason); +} + +unsigned int GpgME::Signature::publicKeyAlgorithm() const +{ +#ifdef HAVE_GPGME_SIGNATURE_T_ALGORITHM_FIELDS + if (!isNull()) { + return d->sigs[idx]->pubkey_algo; + } +#endif + return 0; +} + +const char *GpgME::Signature::publicKeyAlgorithmAsString() const +{ +#ifdef HAVE_GPGME_SIGNATURE_T_ALGORITHM_FIELDS + if (!isNull()) { + return gpgme_pubkey_algo_name(d->sigs[idx]->pubkey_algo); + } +#endif + return 0; +} + +unsigned int GpgME::Signature::hashAlgorithm() const +{ +#ifdef HAVE_GPGME_SIGNATURE_T_ALGORITHM_FIELDS + if (!isNull()) { + return d->sigs[idx]->hash_algo; + } +#endif + return 0; +} + +const char *GpgME::Signature::hashAlgorithmAsString() const +{ +#ifdef HAVE_GPGME_SIGNATURE_T_ALGORITHM_FIELDS + if (!isNull()) { + return gpgme_hash_algo_name(d->sigs[idx]->hash_algo); + } +#endif + return 0; +} + +const char *GpgME::Signature::policyURL() const +{ + return isNull() ? 0 : d->purls[idx] ; +} + +GpgME::Notation GpgME::Signature::notation(unsigned int nidx) const +{ + return GpgME::Notation(d, idx, nidx); +} + +std::vector<GpgME::Notation> GpgME::Signature::notations() const +{ + if (isNull()) { + return std::vector<GpgME::Notation>(); + } + std::vector<GpgME::Notation> result; + result.reserve(d->nota[idx].size()); + for (unsigned int i = 0 ; i < d->nota[idx].size() ; ++i) { + result.push_back(GpgME::Notation(d, idx, i)); + } + return result; +} + +class GpgME::Notation::Private +{ +public: + Private() : d(), sidx(0), nidx(0), nota(0) {} + Private(const boost::shared_ptr<VerificationResult::Private> &priv, unsigned int sindex, unsigned int nindex) + : d(priv), sidx(sindex), nidx(nindex), nota(0) + { + + } + Private(gpgme_sig_notation_t n) + : d(), sidx(0), nidx(0), nota(n ? new _gpgme_sig_notation(*n) : 0) + { + if (nota && nota->name) { + nota->name = strdup(nota->name); + } + if (nota && nota->value) { + nota->value = strdup(nota->value); + } + } + Private(const Private &other) + : d(other.d), sidx(other.sidx), nidx(other.nidx), nota(other.nota) + { + if (nota) { + nota->name = strdup(nota->name); + nota->value = strdup(nota->value); + } + } + ~Private() + { + if (nota) { + std::free(nota->name); nota->name = 0; + std::free(nota->value); nota->value = 0; + delete nota; + } + } + + boost::shared_ptr<VerificationResult::Private> d; + unsigned int sidx, nidx; + gpgme_sig_notation_t nota; +}; + +GpgME::Notation::Notation(const boost::shared_ptr<VerificationResult::Private> &parent, unsigned int sindex, unsigned int nindex) + : d(new Private(parent, sindex, nindex)) +{ + +} + +GpgME::Notation::Notation(gpgme_sig_notation_t nota) + : d(new Private(nota)) +{ + +} + +GpgME::Notation::Notation() : d() {} + +bool GpgME::Notation::isNull() const +{ + if (!d) { + return true; + } + if (d->d) { + return d->sidx >= d->d->nota.size() || d->nidx >= d->d->nota[d->sidx].size() ; + } + return !d->nota; +} + +const char *GpgME::Notation::name() const +{ + return + isNull() ? 0 : + d->d ? d->d->nota[d->sidx][d->nidx].name : + d->nota ? d->nota->name : 0 ; +} + +const char *GpgME::Notation::value() const +{ + return + isNull() ? 0 : + d->d ? d->d->nota[d->sidx][d->nidx].value : + d->nota ? d->nota->value : 0 ; +} + +GpgME::Notation::Flags GpgME::Notation::flags() const +{ + return + convert_from_gpgme_sig_notation_flags_t( +#ifdef HAVE_GPGME_SIG_NOTATION_FLAGS_T + isNull() ? 0 : + d->d ? d->d->nota[d->sidx][d->nidx].flags : + d->nota ? d->nota->flags : 0); +#else + 0); +#endif +} + +bool GpgME::Notation::isHumanReadable() const +{ + return flags() & HumanReadable; +} + +bool GpgME::Notation::isCritical() const +{ + return flags() & Critical; +} + +std::ostream &GpgME::operator<<(std::ostream &os, const VerificationResult &result) +{ + os << "GpgME::VerificationResult("; + if (!result.isNull()) { + os << "\n error: " << result.error() + << "\n fileName: " << protect(result.fileName()) + << "\n signatures:\n"; + const std::vector<Signature> sigs = result.signatures(); + std::copy(sigs.begin(), sigs.end(), + std::ostream_iterator<Signature>(os, "\n")); + } + return os << ')'; +} + +std::ostream &GpgME::operator<<(std::ostream &os, Signature::PKAStatus pkaStatus) +{ +#define OUTPUT( x ) if ( !(pkaStatus & (GpgME::Signature:: x)) ) {} else do { os << #x " "; } while(0) + os << "GpgME::Signature::PKAStatus("; + OUTPUT(UnknownPKAStatus); + OUTPUT(PKAVerificationFailed); + OUTPUT(PKAVerificationSucceeded); +#undef OUTPUT + return os << ')'; +} + +std::ostream &GpgME::operator<<(std::ostream &os, Signature::Summary summary) +{ +#define OUTPUT( x ) if ( !(summary & (GpgME::Signature:: x)) ) {} else do { os << #x " "; } while(0) + os << "GpgME::Signature::Summary("; + OUTPUT(Valid); + OUTPUT(Green); + OUTPUT(Red); + OUTPUT(KeyRevoked); + OUTPUT(KeyExpired); + OUTPUT(SigExpired); + OUTPUT(KeyMissing); + OUTPUT(CrlMissing); + OUTPUT(CrlTooOld); + OUTPUT(BadPolicy); + OUTPUT(SysError); +#undef OUTPUT + return os << ')'; +} + +std::ostream &GpgME::operator<<(std::ostream &os, const Signature &sig) +{ + os << "GpgME::Signature("; + if (!sig.isNull()) { + os << "\n Summary: " << sig.summary() + << "\n Fingerprint: " << protect(sig.fingerprint()) + << "\n Status: " << sig.status() + << "\n creationTime: " << sig.creationTime() + << "\n expirationTime: " << sig.expirationTime() + << "\n isWrongKeyUsage: " << sig.isWrongKeyUsage() + << "\n isVerifiedUsingChainModel: " << sig.isVerifiedUsingChainModel() + << "\n pkaStatus: " << sig.pkaStatus() + << "\n pkaAddress: " << protect(sig.pkaAddress()) + << "\n validity: " << sig.validityAsString() + << "\n nonValidityReason: " << sig.nonValidityReason() + << "\n publicKeyAlgorithm: " << protect(sig.publicKeyAlgorithmAsString()) + << "\n hashAlgorithm: " << protect(sig.hashAlgorithmAsString()) + << "\n policyURL: " << protect(sig.policyURL()) + << "\n notations:\n"; + const std::vector<Notation> nota = sig.notations(); + std::copy(nota.begin(), nota.end(), + std::ostream_iterator<Notation>(os, "\n")); + } + return os << ')'; +} + +std::ostream &GpgME::operator<<(std::ostream &os, Notation::Flags flags) +{ + os << "GpgME::Notation::Flags("; +#define OUTPUT( x ) if ( !(flags & (GpgME::Notation:: x)) ) {} else do { os << #x " "; } while(0) + OUTPUT(HumanReadable); + OUTPUT(Critical); +#undef OUTPUT + return os << ')'; +} + +std::ostream &GpgME::operator<<(std::ostream &os, const Notation ¬a) +{ + os << "GpgME::Signature::Notation("; + if (!nota.isNull()) { + os << "\n name: " << protect(nota.name()) + << "\n value: " << protect(nota.value()) + << "\n flags: " << nota.flags() + << '\n'; + } + return os << ")"; +} diff --git a/lang/cpp/src/verificationresult.h b/lang/cpp/src/verificationresult.h new file mode 100644 index 00000000..8372d88b --- /dev/null +++ b/lang/cpp/src/verificationresult.h @@ -0,0 +1,173 @@ +/* + verificationresult.h - 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. +*/ + +#ifndef __GPGMEPP_VERIFICATIONRESULT_H__ +#define __GPGMEPP_VERIFICATIONRESULT_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 Signature; +class Notation; + +class GPGMEPP_EXPORT VerificationResult : public Result +{ +public: + VerificationResult(); + VerificationResult(gpgme_ctx_t ctx, int error); + VerificationResult(gpgme_ctx_t ctx, const Error &error); + explicit VerificationResult(const Error &err); + + const VerificationResult &operator=(VerificationResult other) + { + swap(other); + return *this; + } + + void swap(VerificationResult &other) + { + Result::swap(other); + using std::swap; + swap(this->d, other.d); + } + + bool isNull() const; + + const char *fileName() const; + + unsigned int numSignatures() const; + Signature signature(unsigned int index) const; + std::vector<Signature> signatures() const; + + class Private; +private: + void init(gpgme_ctx_t ctx); + boost::shared_ptr<Private> d; +}; + +GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const VerificationResult &result); + +class GPGMEPP_EXPORT Signature +{ + friend class ::GpgME::VerificationResult; + Signature(const boost::shared_ptr<VerificationResult::Private> &parent, unsigned int index); +public: + typedef GPGMEPP_DEPRECATED GpgME::Notation Notation; + + Signature(); + + const Signature &operator=(Signature other) + { + swap(other); + return *this; + } + + void swap(Signature &other) + { + using std::swap; + swap(this->d, other.d); + swap(this->idx, other.idx); + } + + bool isNull() const; + + enum Summary { + None = 0x000, + Valid = 0x001, + Green = 0x002, + Red = 0x004, + KeyRevoked = 0x008, + KeyExpired = 0x010, + SigExpired = 0x020, + KeyMissing = 0x040, + CrlMissing = 0x080, + CrlTooOld = 0x100, + BadPolicy = 0x200, + SysError = 0x400 + }; + Summary summary() const; + + const char *fingerprint() const; + + Error status() const; + + time_t creationTime() const; + time_t expirationTime() const; + bool neverExpires() const; + + GPGMEPP_DEPRECATED bool wrongKeyUsage() const + { + return isWrongKeyUsage(); + } + bool isWrongKeyUsage() const; + bool isVerifiedUsingChainModel() const; + + enum PKAStatus { + UnknownPKAStatus, PKAVerificationFailed, PKAVerificationSucceeded + }; + PKAStatus pkaStatus() const; + const char *pkaAddress() const; + + enum Validity { + Unknown, Undefined, Never, Marginal, Full, Ultimate + }; + Validity validity() const; + char validityAsString() const; + Error nonValidityReason() const; + + unsigned int publicKeyAlgorithm() const; + const char *publicKeyAlgorithmAsString() const; + + unsigned int hashAlgorithm() const; + const char *hashAlgorithmAsString() const; + + const char *policyURL() const; + GpgME::Notation notation(unsigned int index) const; + std::vector<GpgME::Notation> notations() const; + +private: + boost::shared_ptr<VerificationResult::Private> d; + unsigned int idx; +}; + +GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Signature &sig); +GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Signature::PKAStatus pkaStatus); +GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Signature::Summary summary); + +} + +GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(VerificationResult) +GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Signature) + +#endif // __GPGMEPP_VERIFICATIONRESULT_H__ diff --git a/lang/cpp/src/vfsmountresult.cpp b/lang/cpp/src/vfsmountresult.cpp new file mode 100644 index 00000000..deca627f --- /dev/null +++ b/lang/cpp/src/vfsmountresult.cpp @@ -0,0 +1,98 @@ +/* + vfsmountresult.cpp - wraps a gpgme vfs mount result + Copyright (C) 2009 Klarälvdalens Datakonsult AB <[email protected]> + Author: Marc Mutz <[email protected]>, Volker Krause <[email protected]> + + 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 <vfsmountresult.h> +#include "result_p.h" + +#include <gpgme.h> + +#include <istream> +#include <string.h> + +using namespace GpgME; + +#ifdef HAVE_GPGME_G13_VFS +class VfsMountResult::Private +{ +public: + explicit Private(const gpgme_vfs_mount_result_t r) : mountDir(0) + { + if (r && r->mount_dir) { + mountDir = strdup(r->mount_dir); + } + } + + ~Private() + { + std::free(mountDir); + } + + char *mountDir; +}; +#endif + +VfsMountResult::VfsMountResult(gpgme_ctx_t ctx, const Error &error, const Error &opError) + : Result(error ? error : opError), d() +{ + init(ctx); +} + +void VfsMountResult::init(gpgme_ctx_t ctx) +{ + (void)ctx; +#ifdef HAVE_GPGME_G13_VFS + if (!ctx) { + return; + } + gpgme_vfs_mount_result_t res = gpgme_op_vfs_mount_result(ctx); + if (!res) { + return; + } + d.reset(new Private(res)); +#endif +} + +make_standard_stuff(VfsMountResult) + +const char *VfsMountResult::mountDir() const +{ +#ifdef HAVE_GPGME_G13_VFS + if (d) { + return d->mountDir; + } +#endif + return 0; +} + +std::ostream &GpgME::operator<<(std::ostream &os, const VfsMountResult &result) +{ + os << "GpgME::VfsMountResult("; + if (!result.isNull()) { + os << "\n error: " << result.error() + << "\n mount dir: " << result.mountDir() + << "\n"; + } + return os << ')'; +} diff --git a/lang/cpp/src/vfsmountresult.h b/lang/cpp/src/vfsmountresult.h new file mode 100644 index 00000000..0f06bd27 --- /dev/null +++ b/lang/cpp/src/vfsmountresult.h @@ -0,0 +1,76 @@ +/* + vfsmountresult.h - wraps a gpgme vfs mount result + Copyright (C) 2009 Klarälvdalens Datakonsult AB <[email protected]> + Author: Marc Mutz <[email protected]>, Volker Krause <[email protected]> + + 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_VFSMOUNTRESULT_H__ +#define __GPGMEPP_VFSMOUNTRESULT_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 GPGMEPP_EXPORT VfsMountResult : public Result +{ +public: + VfsMountResult(); + VfsMountResult(gpgme_ctx_t ctx, const Error &error, const Error &opError); + explicit VfsMountResult(const Error &err); + + const VfsMountResult &operator=(VfsMountResult other) + { + swap(other); + return *this; + } + + void swap(VfsMountResult &other) + { + Result::swap(other); + using std::swap; + swap(this->d, other.d); + } + + bool isNull() const; + const char *mountDir() const; + + class Private; +private: + void init(gpgme_ctx_t ctx); + boost::shared_ptr<Private> d; +}; + +GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const VfsMountResult &result); + +} + +GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(VfsMountResult) + +#endif // __GPGMEPP_ASSUANRESULT_H__ |