diff options
Diffstat (limited to 'lang/cpp/src')
72 files changed, 11866 insertions, 0 deletions
| diff --git a/lang/cpp/src/GpgmeppConfig.cmake.in.in b/lang/cpp/src/GpgmeppConfig.cmake.in.in new file mode 100644 index 00000000..d54011e9 --- /dev/null +++ b/lang/cpp/src/GpgmeppConfig.cmake.in.in @@ -0,0 +1,108 @@ +# CMake Config file for GPGMEPP. +# Copyright (C) 2016 Intevation GmbH +# +# This file is part of GPGMEPP. +# +# GPGME-CL is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME-CL is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA + +# based on a generated file from cmake. +# Generated by CMake 3.0.2 + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5) +   message(FATAL_ERROR "CMake >= 2.6.0 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.6) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_targetsDefined) +set(_targetsNotDefined) +set(_expectedTargets) +foreach(_expectedTarget KF5::Gpgmepp Gpgmepp) +  list(APPEND _expectedTargets ${_expectedTarget}) +  if(NOT TARGET ${_expectedTarget}) +    list(APPEND _targetsNotDefined ${_expectedTarget}) +  endif() +  if(TARGET ${_expectedTarget}) +    list(APPEND _targetsDefined ${_expectedTarget}) +  endif() +endforeach() +if("${_targetsDefined}" STREQUAL "${_expectedTargets}") +  set(CMAKE_IMPORT_FILE_VERSION) +  cmake_policy(POP) +  return() +endif() +if(NOT "${_targetsDefined}" STREQUAL "") +  message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n") +endif() +unset(_targetsDefined) +unset(_targetsNotDefined) +unset(_expectedTargets) + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) + +# Create imported target Gpgmepp +add_library(Gpgmepp SHARED IMPORTED) + +set_target_properties(Gpgmepp PROPERTIES +  INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/gpgme++" +  INTERFACE_LINK_LIBRARIES "pthread;@resolved_libdir@/libgpgme@libsuffix@;@LIBASSUAN_LIBS@" +  IMPORTED_LOCATION "@resolved_libdir@/libgpgmepp@libsuffix@" +) + +if(CMAKE_VERSION VERSION_LESS 2.8.12) +  message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.") +endif() + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(target ${_IMPORT_CHECK_TARGETS} ) +  foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} ) +    if(NOT EXISTS "${file}" ) +      message(FATAL_ERROR "The imported target \"${target}\" references the file +   \"${file}\" +but this file does not exist.  Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained +   \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") +    endif() +  endforeach() +  unset(_IMPORT_CHECK_FILES_FOR_${target}) +endforeach() +unset(_IMPORT_CHECK_TARGETS) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) + +get_filename_component(QGpgme_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +# Pull in QGpgme for compatibility with KF5 variant. +find_package(QGpgme CONFIG) diff --git a/lang/cpp/src/GpgmeppConfigVersion.cmake.in b/lang/cpp/src/GpgmeppConfigVersion.cmake.in new file mode 100644 index 00000000..43d65127 --- /dev/null +++ b/lang/cpp/src/GpgmeppConfigVersion.cmake.in @@ -0,0 +1,31 @@ +# CMake Version file for GPGMEPP. +# Copyright (C) 2016 Intevation GmbH +# +# This file is part of GPGMEPP. +# +# GPGME-CL is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME-CL is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA + +# based on a generated file from cmake. +set(PACKAGE_VERSION "@LIBGPGMEPP_LT_CURRENT@.@LIBGPGMEPP_LT_AGE@.@LIBGPGMEPP_LT_REVISION@.@BUILD_REVISION@") + +if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) +  set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() +  set(PACKAGE_VERSION_COMPATIBLE TRUE) +  if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}") +    set(PACKAGE_VERSION_EXACT TRUE) +  endif() +endif() diff --git a/lang/cpp/src/Makefile.am b/lang/cpp/src/Makefile.am new file mode 100644 index 00000000..d3d28ce6 --- /dev/null +++ b/lang/cpp/src/Makefile.am @@ -0,0 +1,94 @@ +# Makefile.am for GPGMEPP. +# Copyright (C) 2016 Intevation GmbH +# +# This file is part of GPGMEPP. +# +# GPGME-CL is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME-CL is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA + +EXTRA_DIST = GpgmeppConfig.cmake.in.in GpgmeppConfigVersion.cmake.in + +lib_LTLIBRARIES = libgpgmepp.la + +main_sources = \ +    exception.cpp context.cpp key.cpp trustitem.cpp data.cpp callbacks.cpp \ +    eventloopinteractor.cpp editinteractor.cpp assuanresult.cpp \ +    keylistresult.cpp keygenerationresult.cpp importresult.cpp \ +    decryptionresult.cpp verificationresult.cpp \ +    signingresult.cpp encryptionresult.cpp \ +    engineinfo.cpp gpgsetexpirytimeeditinteractor.cpp \ +    gpgsetownertrusteditinteractor.cpp gpgsignkeyeditinteractor.cpp \ +    gpgadduserideditinteractor.cpp defaultassuantransaction.cpp \ +    scdgetinfoassuantransaction.cpp gpgagentgetinfoassuantransaction.cpp \ +    vfsmountresult.cpp configuration.cpp + +gpgmepp_headers = \ +    assuanresult.h configuration.h context.h data.h decryptionresult.h \ +    defaultassuantransaction.h editinteractor.h encryptionresult.h \ +    engineinfo.h error.h eventloopinteractor.h exception.h global.h \ +    gpgadduserideditinteractor.h gpgagentgetinfoassuantransaction.h \ +    gpgmefw.h gpgsetexpirytimeeditinteractor.h \ +    gpgsetownertrusteditinteractor.h gpgsignkeyeditinteractor.h \ +    importresult.h keygenerationresult.h key.h keylistresult.h \ +    notation.h result.h scdgetinfoassuantransaction.h signingresult.h \ +    trustitem.h verificationresult.h vfsmountresult.h gpgmepp_export.h + +private_gpgmepp_headers = \ +    result_p.h context_p.h util.h callbacks.h data_p.h + +interface_headers= \ +    interfaces/assuantransaction.h interfaces/dataprovider.h \ +    interfaces/passphraseprovider.h interfaces/progressprovider.h + +gpgmeppincludedir = $(includedir)/gpgme++ +gpgmeppinclude_HEADERS = $(gpgmepp_headers) +nobase_gpgmeppinclude_HEADERS = $(interface_headers) + +libgpgmepp_la_SOURCES = $(main_sources) $(gpgmepp_headers) context_vanilla.cpp \ +                        $(interface_headers) $(private_gpgmepp_headers) + +AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@ @LIBASSUAN_CFLAGS@ \ +              -DBUILDING_GPGMEPP + +libgpgmepp_la_LIBADD = ../../../src/libgpgme.la @LIBASSUAN_LIBS@ +libgpgmepp_la_LDFLAGS = -version-info \ +    @LIBGPGMEPP_LT_CURRENT@:@LIBGPGMEPP_LT_REVISION@:@LIBGPGMEPP_LT_AGE@ + +if HAVE_W32_SYSTEM +libsuffix=.dll.a +else +libsuffix=.so +endif + +GpgmeppConfig.cmake: GpgmeppConfig.cmake.in +	sed -e 's|[@]resolved_libdir@|$(libdir)|g' < "$<" > "$@" +	sed -e 's|[@]libsuffix@|$(libsuffix)|g' < "$@" > "$@".2 +	mv "$@".2 "$@" + +install-cmake-files: GpgmeppConfig.cmake GpgmeppConfigVersion.cmake +	-$(INSTALL) -d $(DESTDIR)$(libdir)/cmake/Gpgmepp +	$(INSTALL) GpgmeppConfig.cmake \ +        $(DESTDIR)$(libdir)/cmake/Gpgmepp/GpgmeppConfig.cmake +	$(INSTALL) GpgmeppConfigVersion.cmake \ +        $(DESTDIR)$(libdir)/cmake/Gpgmepp/GpgmeppConfigVersion.cmake + +uninstall-cmake-files: +	-rm $(DESTDIR)$(libdir)/cmake/Gpgmepp/GpgmeppConfigVersion.cmake +	-rm $(DESTDIR)$(libdir)/cmake/Gpgmepp/GpgmeppConfig.cmake +	-rmdir $(DESTDIR)$(libdir)/cmake/Gpgmepp/ + +install-data-local: install-cmake-files + +uninstall-local: uninstall-cmake-files diff --git a/lang/cpp/src/assuanresult.cpp b/lang/cpp/src/assuanresult.cpp new file mode 100644 index 00000000..3d6d0a3a --- /dev/null +++ b/lang/cpp/src/assuanresult.cpp @@ -0,0 +1,90 @@ +/* +  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 <assuanresult.h> +#include "result_p.h" + +#include <gpgme.h> + +#include <istream> + +using namespace GpgME; + +class AssuanResult::Private +{ +public: +    explicit Private(const gpgme_assuan_result_t r) +    { +        if (!r) { +            return; +        } +        error = r->err; +    } + +    gpgme_error_t error; +}; + +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; +    if (!ctx) { +        return; +    } +    gpgme_assuan_result_t res = gpgme_op_assuan_result(ctx); +    if (!res) { +        return; +    } +    d.reset(new Private(res)); +} + +make_standard_stuff(AssuanResult) + +Error AssuanResult::assuanError() const +{ +    if (d) { +        return Error(d->error); +    } +    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..e59b5ac2 --- /dev/null +++ b/lang/cpp/src/assuanresult.h @@ -0,0 +1,79 @@ +/* +  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 <vector> +#include <iosfwd> +#include <memory> + +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); +    std::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..4b4dd806 --- /dev/null +++ b/lang/cpp/src/callbacks.cpp @@ -0,0 +1,149 @@ +/* +  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 "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> + +static inline gpgme_error_t make_err_from_syserror() +{ +    return gpgme_error_from_syserror(); +} + +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 { +                ssize_t now_written = gpgme_io_write(fd, passphrase + written, passphrase_length - written); +                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); +    gpgme_io_write(fd, "\n", 1); +    return err; +} + +static gpgme_ssize_t +data_read_callback(void *opaque, void *buf, size_t buflen) +{ +    DataProvider *provider = static_cast<DataProvider *>(opaque); +    if (!provider) { +        gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL)); +        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) { +        gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL)); +        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) { +        gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL)); +        return -1; +    } +    if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) { +        gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL)); +        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..7ef28836 --- /dev/null +++ b/lang/cpp/src/configuration.cpp @@ -0,0 +1,934 @@ +/* +  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 "configuration.h" +#include "error.h" +#include "util.h" + +#include <gpgme.h> + +#include <iterator> +#include <algorithm> +#include <ostream> +#include <cstring> +#include <assert.h> + +using namespace GpgME; +using namespace GpgME::Configuration; + +typedef std::shared_ptr< std::remove_pointer<gpgme_conf_opt_t>::type > shared_gpgme_conf_opt_t; +typedef std::weak_ptr< std::remove_pointer<gpgme_conf_opt_t>::type > weak_gpgme_conf_opt_t; + +typedef std::shared_ptr< std::remove_pointer<gpgme_conf_arg_t>::type > shared_gpgme_conf_arg_t; +typedef std::weak_ptr< std::remove_pointer<gpgme_conf_arg_t>::type > weak_gpgme_conf_arg_t; + +typedef std::shared_ptr< std::remove_pointer<gpgme_ctx_t>::type > shared_gpgme_ctx_t; +typedef std::weak_ptr< std::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) +{ + +    // +    // 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; +} + +Error Component::save() const +{ + +    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())); +} + +const char *Component::name() const +{ +    return comp ? comp->name : 0 ; +} + +const char *Component::description() const +{ +    return comp ? comp->description : 0 ; +} + +const char *Component::programName() const +{ +    return comp ? comp->program_name : 0 ; +} + +Option Component::option(unsigned int idx) const +{ +    gpgme_conf_opt_t opt = 0; +    if (comp) { +        opt = comp->options; +    } +    while (opt && idx) { +        opt = opt->next; +        --idx; +    } +    if (opt) { +        return Option(comp, opt); +    } +    return Option(); +} + +Option Component::option(const char *name) const +{ +    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); +    } +    return Option(); +} + +unsigned int Component::numOptions() const +{ +    unsigned int result = 0; +    for (gpgme_conf_opt_t opt = comp ? comp->options : 0 ; opt ; opt = opt->next) { +        ++result; +    } +    return result; +} + +std::vector<Option> Component::options() const +{ +    std::vector<Option> result; +    for (gpgme_conf_opt_t opt = comp ? comp->options : 0 ; opt ; opt = opt->next) { +        result.push_back(Option(comp, opt)); +    } +    return result; +} + +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; +} + +Component Option::parent() const +{ +    return Component(comp.lock()); +} + +unsigned int Option::flags() const +{ +    return isNull() ? 0 : opt->flags; +} + +Level Option::level() const +{ +    return isNull() ? Internal : static_cast<Level>(opt->level) ; +} + +const char *Option::name() const +{ +    return isNull() ? 0 : opt->name ; +} + +const char *Option::description() const +{ +    return isNull() ? 0 : opt->description ; +} + +const char *Option::argumentName() const +{ +    return isNull() ? 0 : opt->argname ; +} + +Type Option::type() const +{ +    return isNull() ? NoType : static_cast<Type>(opt->type) ; +} + +Type Option::alternateType() const +{ +    return isNull() ? NoType : static_cast<Type>(opt->alt_type) ; +} + +#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 +{ +    if (isNull()) { +        return Argument(); +    } else { +        return Argument(comp.lock(), opt, opt->default_value, false); +    } +} + +const char *Option::defaultDescription() const +{ +    return isNull() ? 0 : opt->default_description ; +} + +Argument Option::noArgumentValue() const +{ +    if (isNull()) { +        return Argument(); +    } else { +        return Argument(comp.lock(), opt, opt->no_arg_value, false); +    } +} + +const char *Option::noArgumentDescription() const +{ +    return isNull() ? 0 : opt->no_arg_description ; +} + +Argument Option::activeValue() const +{ +    if (isNull()) { +        return Argument(); +    } else { +        return Argument(comp.lock(), opt, opt->value, false); +    } +} + +Argument Option::currentValue() const +{ +    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); +} + +Argument Option::newValue() const +{ +    if (isNull()) { +        return Argument(); +    } else { +        return Argument(comp.lock(), opt, opt->new_value, false); +    } +} + +bool Option::set() const +{ +    if (isNull()) { +        return false; +    } else if (opt->change_value) { +        return opt->new_value; +    } else { +        return opt->value; +    } +} + +bool Option::dirty() const +{ +    return !isNull() && opt->change_value ; +} + +Error Option::setNewValue(const Argument &argument) +{ +    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)); +    } +} + +Error Option::resetToActiveValue() +{ +    if (isNull()) { +        return Error(make_error(GPG_ERR_INV_ARG)); +    } else { +        return Error(gpgme_conf_opt_change(opt, 1, 0)); +    } +} + +Error Option::resetToDefaultValue() +{ +    if (isNull()) { +        return Error(make_error(GPG_ERR_INV_ARG)); +    } else { +        return Error(gpgme_conf_opt_change(opt, 0, 0)); +    } +} + +static gpgme_conf_arg_t make_argument(gpgme_conf_type_t type, const void *value) +{ +    gpgme_conf_arg_t arg = 0; +    if (const gpgme_error_t err = gpgme_conf_arg_new(&arg, type, value)) { +        return 0; +    } else { +        return arg; +    } +} + +Argument Option::createNoneArgument(bool set) const +{ +    if (isNull() || alternateType() != NoType) { +        return Argument(); +    } else { +        if (set) { +            return createNoneListArgument(1); +        } +    } +    return Argument(); +} + +Argument Option::createStringArgument(const char *value) const +{ +    if (isNull() || alternateType() != StringType) { +        return Argument(); +    } else { +        return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value), true); +    } +} + +Argument Option::createStringArgument(const std::string &value) const +{ +    if (isNull() || alternateType() != StringType) { +        return Argument(); +    } else { +        return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value.c_str()), true); +    } +} + +Argument Option::createIntArgument(int value) const +{ +    if (isNull() || alternateType() != IntegerType) { +        return Argument(); +    } else { +        return Argument(comp.lock(), opt, make_argument(GPGME_CONF_INT32, &value), true); +    } +} + +Argument Option::createUIntArgument(unsigned int value) const +{ +    if (isNull() || alternateType() != UnsignedIntegerType) { +        return Argument(); +    } else { +        return Argument(comp.lock(), opt, make_argument(GPGME_CONF_UINT32, &value), true); +    } +} + +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; +} +} + +Argument Option::createNoneListArgument(unsigned int value) const +{ +    if (value) { +        return Argument(comp.lock(), opt, make_argument(GPGME_CONF_NONE, &value), true); +    } +    return Argument(); +} + +Argument Option::createStringListArgument(const std::vector<const char *> &value) const +{ +    return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value), true); +} + +Argument Option::createStringListArgument(const std::vector<std::string> &value) const +{ +    return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value), true); +} + +Argument Option::createIntListArgument(const std::vector<int> &value) const +{ +    return Argument(comp.lock(), opt, make_argument(GPGME_CONF_INT32, value), true); +} + +Argument Option::createUIntListArgument(const std::vector<unsigned int> &value) const +{ +    return Argument(comp.lock(), opt, make_argument(GPGME_CONF_UINT32, value), true); +} + +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), +      arg(owns ? arg : mygpgme_conf_arg_copy(arg, opt ? opt->alt_type : GPGME_CONF_NONE)) +{ + +} + +#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), +      arg(mygpgme_conf_arg_copy(other.arg, opt ? opt->alt_type : GPGME_CONF_NONE)) +{ + +} + +Argument::~Argument() +{ +    gpgme_conf_arg_release(arg, opt ? opt->alt_type : GPGME_CONF_NONE); +} + +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; +    for (gpgme_conf_arg_t a = arg ; a ; a = a->next) { +        ++result; +    } +    return result; +} + +const char *Argument::stringValue(unsigned int idx) const +{ +    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 ; +} + +int Argument::intValue(unsigned int idx) const +{ +    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 ; +} + +unsigned int Argument::uintValue(unsigned int idx) const +{ +    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 ; +} + +unsigned int Argument::numberOfTimesSet() const +{ +    if (isNull() || opt->alt_type != GPGME_CONF_NONE) { +        return 0; +    } +    return arg->value.count; +} + +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 +{ +    if (isNull() || opt->alt_type != GPGME_CONF_INT32) { +        return std::vector<int>(); +    } +    std::vector<int> result; +    for (gpgme_conf_arg_t a = arg ; a ; a = a->next) { +        result.push_back(a->value.int32); +    } +    return result; +} + +std::vector<unsigned int> Argument::uintValues() const +{ +    if (isNull() || opt->alt_type != GPGME_CONF_UINT32) { +        return std::vector<unsigned int>(); +    } +    std::vector<unsigned int> result; +    for (gpgme_conf_arg_t a = arg ; a ; a = a->next) { +        result.push_back(a->value.uint32); +    } +    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; +                std::for_each(v.begin(), v.end(), [&first, &os](const char *s) { +                    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..288a410d --- /dev/null +++ b/lang/cpp/src/configuration.h @@ -0,0 +1,290 @@ +/* +  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 <iosfwd> +#include <vector> +#include <string> +#include <algorithm> +#include <memory> + +namespace GpgME +{ +namespace Configuration +{ + +typedef std::shared_ptr< std::remove_pointer<gpgme_conf_comp_t>::type > shared_gpgme_conf_comp_t; +typedef std::weak_ptr< std::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..93244b41 --- /dev/null +++ b/lang/cpp/src/context.cpp @@ -0,0 +1,1494 @@ +/* +  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 <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 <istream> +#ifndef NDEBUG +#include <iostream> +using std::cerr; +using std::endl; +#endif + +#include <cassert> + +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); +} + +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); +} + +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() +{ +    return gpgme_err_code_from_syserror() == GPG_ERR_MISSING_ERRNO ; +} + +// static +void Error::setSystemError(gpg_err_code_t err) +{ +    setErrno(gpgme_err_code_to_errno(err)); +} + +// static +void Error::setErrno(int err) +{ +    gpgme_err_set_errno(err); +} + +// static +Error Error::fromSystemError(unsigned int src) +{ +    return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), gpgme_err_code_from_syserror())); +} + +// static +Error Error::fromErrno(int err, unsigned int src) +{ +    return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), gpgme_err_code_from_errno(err))); +} + +// static +Error Error::fromCode(unsigned int err, unsigned int src) +{ +    return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), static_cast<gpgme_err_code_t>(err))); +} + +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: +        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; +    case G13Engine: +        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; +    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) +{ +    gpgme_set_offline(d->ctx, int(useOfflineMode)); +} +bool Context::offline() const +{ +    return gpgme_get_offline(d->ctx); +} + +void Context::setIncludeCertificates(int which) +{ +    if (which == DefaultCertificates) { +        which = GPGME_INCLUDE_CERTS_DEFAULT; +    } +    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 +{ +    return EngineInfo(gpgme_ctx_get_engine_info(d->ctx)); +} + +Error Context::setEngineFileName(const char *filename) +{ +    const char *const home_dir = engineInfo().homeDirectory(); +    return Error(gpgme_ctx_set_engine_info(d->ctx, gpgme_get_protocol(d->ctx), filename, home_dir)); +} + +Error Context::setEngineHomeDirectory(const char *home_dir) +{ +    const char *const filename = engineInfo().fileName(); +    return Error(gpgme_ctx_set_engine_info(d->ctx, gpgme_get_protocol(d->ctx), filename, home_dir)); +} + +// +// +// 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; +    gpgme_key_t * const 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); +    shouldHaveResult = true; +    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; +        } +    } +    delete[] keys; +    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; +    gpgme_key_t * const 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; +    Error err = Error(d->lasterr = gpgme_op_import_keys_start(d->ctx, keys)); +    delete[] keys; +    return err; +} + +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; +    return Error(d->lasterr = gpgme_op_passwd(d->ctx, key.impl(), 0U)); +} + +Error Context::startPasswd(const Key &key) +{ +    d->lastop = Private::Passwd; +    return Error(d->lasterr = gpgme_op_passwd_start(d->ctx, key.impl(), 0U)); +} + +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)); +} + +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(); +} + +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))); +    } +    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()); +    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)); +    } +    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())); +} + +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)); +} + +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; +} + +Error Context::startGetAuditLog(Data &output, unsigned int flags) +{ +    d->lastop = Private::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))); +} + +Error Context::getAuditLog(Data &output, unsigned int flags) +{ +    d->lastop = Private::GetAuditLog; +    Data::Private *const odp = output.impl(); +    return Error(d->lasterr = gpgme_op_getauditlog(d->ctx, odp ? odp->data : 0, to_auditlog_flags(flags))); +} + +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() +{ +    gpgme_sig_notation_clear(d->ctx); +} + +GpgME::Error Context::addSignatureNotation(const char *name, const char *value, unsigned int flags) +{ +    return Error(gpgme_sig_notation_add(d->ctx, name, value, add_to_gpgme_sig_notation_flags_t(0, flags))); +} + +GpgME::Error Context::addSignaturePolicyURL(const char *url, bool critical) +{ +    return Error(gpgme_sig_notation_add(d->ctx, 0, url, critical ? GPGME_SIG_NOTATION_CRITICAL : 0)); +} + +const char *Context::signaturePolicyURL() const +{ +    for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) { +        if (!n->name) { +            return n->value; +        } +    } +} + +Notation Context::signatureNotation(unsigned int idx) const +{ +    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); +            } +        } +    } +    return Notation(); +} + +std::vector<Notation> Context::signatureNotations() const +{ +    std::vector<Notation> result; +    for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) { +        if (n->name) { +            result.push_back(Notation(n)); +        } +    } +    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; +    } +    if (flags & Context::NoEncryptTo) { +        result |= GPGME_ENCRYPT_NO_ENCRYPT_TO; +    } +    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; +    if (flags & NoEncryptTo) { +        return EncryptionResult(Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED))); +    } +    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; +    if (flags & NoEncryptTo) { +        return Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED)); +    } +    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; +    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); +} + +VfsMountResult Context::mountVFS(const char *containerFile, const char *mountDir) +{ +    d->lastop = Private::MountVFS; +    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)); +} + +Error Context::cancelPendingOperation() +{ +    return Error(gpgme_cancel_async(d->ctx)); +} + +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: +        return GPGME_PROTOCOL_GPGCONF; +    case GpgME::AssuanEngine: +        return GPGME_PROTOCOL_ASSUAN; +    case GpgME::G13Engine: +        return GPGME_PROTOCOL_G13; +    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 +        | GpgME::DefaultCertificateInclusionFeature +        | GpgME::GetSetEngineInfoFeature +        | GpgME::ClearAddGetSignatureNotationsFeature +        | GpgME::SetDataFileNameFeeature +        | GpgME::SignatureNotationsKeylistModeFeature +        | GpgME::KeySignatureNotationsFeature +        | GpgME::KeyIsQualifiedFeature +        | GpgME::SignatureNotationsCriticalFlagFeature +        | GpgME::SignatureNotationsFlagsFeature +        | GpgME::SignatureNotationsHumanReadableFlagFeature +        | GpgME::SubkeyIsQualifiedFeature +        | GpgME::EngineInfoHomeDirFeature +        | GpgME::DecryptionResultFileNameFeature +        | GpgME::DecryptionResultRecipientsFeature +        | GpgME::VerificationResultFileNameFeature +        | GpgME::SignaturePkaFieldsFeature +        | GpgME::SignatureAlgorithmFieldsFeature +        | GpgME::FdPointerFeature +        | GpgME::AuditLogFeature +        | GpgME::GpgConfEngineFeature +        | GpgME::CancelOperationAsyncFeature +        | GpgME::NoEncryptToEncryptionFlagFeature +        | GpgME::CardKeyFeature +        | GpgME::AssuanEngineFeature +        | GpgME::EphemeralKeylistModeFeature +        | GpgME::ImportFromKeyserverFeature +        | GpgME::G13VFSFeature +        | GpgME::PasswdFeature +        ; + +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..d9889185 --- /dev/null +++ b/lang/cpp/src/context_glib.cpp @@ -0,0 +1,35 @@ +/* +  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 <global.h> + +extern "C" GIOChannel *gpgme_get_fdptr(int); + +GIOChannel *GpgME::getGIOChannel(int fd) +{ +    return gpgme_get_fdptr(fd); +} + +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..2ce0005d --- /dev/null +++ b/lang/cpp/src/context_qt.cpp @@ -0,0 +1,35 @@ +/* +  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 <global.h> + +extern "C" QIODevice *gpgme_get_fdptr(int); + +GIOChannel *GpgME::getGIOChannel(int) +{ +    return 0; +} + +QIODevice *GpgME::getQIODevice(int fd) +{ +    return gpgme_get_fdptr(fd); +} diff --git a/lang/cpp/src/context_vanilla.cpp b/lang/cpp/src/context_vanilla.cpp new file mode 100644 index 00000000..984d41be --- /dev/null +++ b/lang/cpp/src/context_vanilla.cpp @@ -0,0 +1,33 @@ +/* +  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 <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..bf9a629f --- /dev/null +++ b/lang/cpp/src/data.cpp @@ -0,0 +1,208 @@ +/* +  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 "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)); +} + +GpgME::Data::Type GpgME::Data::type() const +{ +    if (isNull()) { +        return Invalid; +    } +    switch (gpgme_data_identify(d->data, 0)) { +    case GPGME_DATA_TYPE_INVALID:       return Invalid; +    case GPGME_DATA_TYPE_UNKNOWN:       return Unknown; +    case GPGME_DATA_TYPE_PGP_SIGNED:    return PGPSigned; +    case GPGME_DATA_TYPE_PGP_OTHER:     return PGPOther; +    case GPGME_DATA_TYPE_PGP_KEY:       return PGPKey; +    case GPGME_DATA_TYPE_CMS_SIGNED:    return CMSSigned; +    case GPGME_DATA_TYPE_CMS_ENCRYPTED: return CMSEncrypted; +    case GPGME_DATA_TYPE_CMS_OTHER:     return CMSOther; +    case GPGME_DATA_TYPE_X509_CERT:     return X509Cert; +    case GPGME_DATA_TYPE_PKCS12:        return PKCS12; +    } +    return Invalid; +} + +char *GpgME::Data::fileName() const +{ +    return gpgme_data_get_file_name(d->data); +} + +GpgME::Error GpgME::Data::setFileName(const char *name) +{ +    return Error(gpgme_data_set_file_name(d->data, name)); +} + +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..efb1e790 --- /dev/null +++ b/lang/cpp/src/data.h @@ -0,0 +1,123 @@ +/* +  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 <sys/types.h> // for size_t, off_t +#include <cstdio> // FILE +#include <algorithm> +#include <memory> + +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); + +    enum Type { +        Invalid, +        Unknown, +        PGPSigned, +        PGPOther, +        PGPKey, +        CMSSigned, +        CMSEncrypted, +        CMSOther, +        X509Cert, +        PKCS12 +    }; +    Type type() const; + +    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: +    std::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..78a2b1b6 --- /dev/null +++ b/lang/cpp/src/decryptionresult.cpp @@ -0,0 +1,240 @@ +/* +  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 <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); +        } +        if (res.file_name) { +            res.file_name = strdup(res.file_name); +        } +        //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; +    } +    ~Private() +    { +        if (res.unsupported_algorithm) { +            std::free(res.unsupported_algorithm); +        } +        res.unsupported_algorithm = 0; +        if (res.file_name) { +            std::free(res.file_name); +        } +        res.file_name = 0; +    } + +    _gpgme_op_decrypt_result res; +    std::vector<_gpgme_recipient> recipients; +}; + +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 +{ +    return d ? d->res.file_name : 0 ; +} + +unsigned int GpgME::DecryptionResult::numRecipients() const +{ +    return d ? d->recipients.size() : 0 ; +} + +GpgME::DecryptionResult::Recipient GpgME::DecryptionResult::recipient(unsigned int idx) const +{ +    if (d && idx < d->recipients.size()) { +        return Recipient(&d->recipients[idx]); +    } +    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; +    if (d) { +        result.reserve(d->recipients.size()); +        std::transform(d->recipients.begin(), d->recipients.end(), +                       std::back_inserter(result), +                       make_recipient()); +    } +    return result; +} + +class GpgME::DecryptionResult::Recipient::Private : public _gpgme_recipient +{ +public: +    Private(gpgme_recipient_t reci) : _gpgme_recipient(*reci) {} +}; + +GpgME::DecryptionResult::Recipient::Recipient() +    : d() +{ + +} + +GpgME::DecryptionResult::Recipient::Recipient(gpgme_recipient_t r) +    : d() +{ +    if (r) { +        d.reset(new Private(r)); +    } +} + +bool GpgME::DecryptionResult::Recipient::isNull() const +{ +    return !d; +} + +const char *GpgME::DecryptionResult::Recipient::keyID() const +{ +    //_keyid is internal API, but the public keyid is invalid after copying (see above) +    if (d) { +        return d->_keyid; +    } +    return 0; +} + +const char *GpgME::DecryptionResult::Recipient::shortKeyID() const +{ +    //_keyid is internal API, but the public keyid is invalid after copying (see above) +    if (d) { +        return d->_keyid + 8; +    } +    return 0; +} + +unsigned int GpgME::DecryptionResult::Recipient::publicKeyAlgorithm() const +{ +    if (d) { +        return d->pubkey_algo; +    } +    return 0; +} + +const char *GpgME::DecryptionResult::Recipient::publicKeyAlgorithmAsString() const +{ +    if (d) { +        return gpgme_pubkey_algo_name(d->pubkey_algo); +    } +    return 0; +} + +GpgME::Error GpgME::DecryptionResult::Recipient::status() const +{ +    if (d) { +        return Error(d->status); +    } +    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..60b78d9c --- /dev/null +++ b/lang/cpp/src/decryptionresult.h @@ -0,0 +1,130 @@ +/* +  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 <vector> +#include <algorithm> +#include <iosfwd> +#include <memory> + +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); +    std::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; +    std::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..5bcf9705 --- /dev/null +++ b/lang/cpp/src/defaultassuantransaction.cpp @@ -0,0 +1,78 @@ +/* +  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 "defaultassuantransaction.h" +#include "error.h" +#include "data.h" + +#include <sstream> + +using namespace GpgME; + +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..c05ccd63 --- /dev/null +++ b/lang/cpp/src/editinteractor.cpp @@ -0,0 +1,344 @@ +/* +  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 "editinteractor.h" +#include "callbacks.h" +#include "error.h" + +#include <gpgme.h> + +#ifdef _WIN32 +# include <io.h> +#include <windows.h> +#else +# include <unistd.h> +#endif + +#include <cerrno> +#include <cstring> + +#ifndef GPG_ERR_ALREADY_SIGNED +# define GPG_ERR_ALREADY_SIGNED GPG_ERR_USER_1 +#endif + +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) { +            const int n = gpgme_io_write(fd, buf, toWrite); +            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) { +                        gpgme_err_set_errno(0); +                        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; +                        } +                    } +                    gpgme_err_set_errno(0); +                    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: +    case GPGME_STATUS_PINENTRY_LAUNCHED: +        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..c4e7df51 --- /dev/null +++ b/lang/cpp/src/encryptionresult.cpp @@ -0,0 +1,159 @@ +/* +  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 <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 std::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..edc400fb --- /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 <memory> + +#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); +    std::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 std::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: +    std::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..d2600909 --- /dev/null +++ b/lang/cpp/src/engineinfo.cpp @@ -0,0 +1,83 @@ +/* +  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 "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 +{ +    return isNull() ? 0 : d->info->home_dir; +} diff --git a/lang/cpp/src/engineinfo.h b/lang/cpp/src/engineinfo.h new file mode 100644 index 00000000..4de9884f --- /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 <memory> + +#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; +    std::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..7ec258c9 --- /dev/null +++ b/lang/cpp/src/eventloopinteractor.cpp @@ -0,0 +1,199 @@ +/* +  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 <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..9be5202c --- /dev/null +++ b/lang/cpp/src/global.h @@ -0,0 +1,206 @@ +/* +  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 <cstring> + +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 + +inline int _gpgmepp_strcmp(const char *s1, const char *s2) +{ +    return s1 ? s2 ? std::strcmp(s1, s2) : 1 : s2 ? -1 : 0; +} + +#define _GPGMEPP_MAKE_STRCMP( Name, expr, cmp )                     \ +    template <template <typename U> class Op>                           \ +    struct Name {                                                       \ +        typedef bool result_type;                                       \ +        \ +        bool operator()( const char * lhs, const char * rhs ) const {   \ +            return Op<int>()( cmp, 0 );                                 \ +        }                                                               \ +        \ +        bool operator()( const std::string & lhs, const std::string & rhs ) const { \ +            return operator()( lhs.c_str(), rhs.c_str() );              \ +        }                                                               \ +        bool operator()( const char * lhs, const std::string & rhs ) const { \ +            return operator()( lhs, rhs.c_str() );                      \ +        }                                                               \ +        bool operator()( const std::string & lhs, const char * rhs ) const { \ +            return operator()( lhs.c_str(), rhs );                      \ +        }                                                               \ +        \ +        template <typename T>                                           \ +        bool operator()( const T & lhs, const T & rhs ) const {         \ +            return operator()( (lhs expr), (rhs expr) );                \ +        }                                                               \ +        template <typename T>                                           \ +        bool operator()( const T & lhs, const char * rhs ) const {      \ +            return operator()( (lhs expr), rhs );                       \ +        }                                                               \ +        template <typename T>                                           \ +        bool operator()( const char * lhs, const T & rhs ) const {      \ +            return operator()( lhs, (rhs expr) );                       \ +        }                                                               \ +        template <typename T>                                           \ +        bool operator()( const T & lhs, const std::string & rhs ) const { \ +            return operator()( (lhs expr), rhs );                       \ +        }                                                               \ +        template <typename T>                                           \ +        bool operator()( const std::string & lhs, const T & rhs ) const {    \ +            return operator()( lhs, (rhs expr) );                       \ +        }                                                               \ +    } + +#define GPGMEPP_MAKE_STRCMP( Name, expr )                          \ +    _GPGMEPP_MAKE_STRCMP( Name, expr, _gpgmepp_strcmp( lhs, rhs ) ) + + +#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..4739aa29 --- /dev/null +++ b/lang/cpp/src/gpgagentgetinfoassuantransaction.cpp @@ -0,0 +1,119 @@ +/* +  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 "gpgagentgetinfoassuantransaction.h" +#include "error.h" +#include "data.h" +#include "util.h" + +#include <assert.h> + +#include <sstream> + +using namespace GpgME; + +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", +}; + +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..c24bda02 --- /dev/null +++ b/lang/cpp/src/gpgmepp_export.h @@ -0,0 +1,53 @@ + +#ifndef GPGMEPP_EXPORT_H +#define GPGMEPP_EXPORT_H + +#ifdef GPGMEPP_STATIC_DEFINE +#  define GPGMEPP_EXPORT +#  define GPGMEPP_NO_EXPORT +#else +#  ifndef GPGMEPP_EXPORT +#    ifdef BUILDING_GPGMEPP +        /* We are building this library */ +#      ifdef WIN32 +#       define GPGMEPP_EXPORT __declspec(dllexport) +#      else +#       define GPGMEPP_EXPORT __attribute__((visibility("default"))) +#      endif +#    else +        /* We are using this library */ +#      ifdef WIN32 +#       define GPGMEPP_EXPORT __declspec(dllimport) +#      else +#       define GPGMEPP_EXPORT __attribute__((visibility("default"))) +#      endif +#    endif +#  endif + +#  ifndef GPGMEPP_NO_EXPORT +#    ifdef WIN32 +#     define GPGMEPP_NO_EXPORT +#    else +#     define GPGMEPP_NO_EXPORT __attribute__((visibility("hidden"))) +#    endif +#  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..fded90f8 --- /dev/null +++ b/lang/cpp/src/gpgsignkeyeditinteractor.cpp @@ -0,0 +1,318 @@ +/* +  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 <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 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<std::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[std::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(std::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..97e82399 --- /dev/null +++ b/lang/cpp/src/importresult.cpp @@ -0,0 +1,215 @@ +/* +  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 <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 std::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..adda80a4 --- /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 <memory> + +#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); +    std::shared_ptr<Private> d; +}; + +class GPGMEPP_EXPORT Import +{ +    friend class ::GpgME::ImportResult; +    Import(const std::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: +    std::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..a382b058 --- /dev/null +++ b/lang/cpp/src/interfaces/assuantransaction.h @@ -0,0 +1,49 @@ +/* +  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" + +#include <stddef.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..55eb0585 --- /dev/null +++ b/lang/cpp/src/key.cpp @@ -0,0 +1,828 @@ +/* +  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 <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 +{ +    return key && key->is_qualified; +} + +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; +    me->is_qualified     |= him->is_qualified; +    me->keylist_mode     |= him->keylist_mode; + +    // 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; +            } +        } +    } + +    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); +} + +std::string Subkey::algoName() const +{ +    char *gpgmeStr; +    if (subkey && (gpgmeStr = gpgme_pubkey_algo_string(subkey))) { +        std::string ret = std::string(gpgmeStr); +        gpgme_free(gpgmeStr); +        return ret; +    } +    return std::string(); +} + +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 +{ +    return subkey && subkey->is_qualified; +} + +bool Subkey::isCardKey() const +{ +    return subkey && subkey->is_cardkey; +} + +const char *Subkey::cardSerialNumber() const +{ +    return subkey ? subkey->card_number : 0 ; +} + +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(); +    } +    for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) { +        if (nota->name) { +            if (idx-- == 0) { +                return GpgME::Notation(nota); +            } +        } +    } +    return GpgME::Notation(); +} + +unsigned int UserID::Signature::numNotations() const +{ +    if (!sig) { +        return 0; +    } +    unsigned int count = 0; +    for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) { +        if (nota->name) { +            ++count; // others are policy URLs... +        } +    } +    return count; +} + +std::vector<Notation> UserID::Signature::notations() const +{ +    if (!sig) { +        return std::vector<GpgME::Notation>(); +    } +    std::vector<GpgME::Notation> v; +    v.reserve(numNotations()); +    for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) { +        if (nota->name) { +            v.push_back(GpgME::Notation(nota)); +        } +    } +    return v; +} + +const char *UserID::Signature::policyURL() const +{ +    if (!sig) { +        return 0; +    } +    for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) { +        if (!nota->name) { +            return nota->value; +        } +    } +    return 0; +} + +} // namespace GpgME diff --git a/lang/cpp/src/key.h b/lang/cpp/src/key.h new file mode 100644 index 00000000..7322f650 --- /dev/null +++ b/lang/cpp/src/key.h @@ -0,0 +1,380 @@ +/* +  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 <memory> +#include <sys/time.h> + +#include <vector> +#include <algorithm> +#include <string> + +namespace GpgME +{ + +class Context; + +class Subkey; +class UserID; + +typedef std::shared_ptr< std::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; + +    /** +      @brief Get the public key algorithm name. + +      This only works for the pre 2.1 algorithms for ECC NULL is returned. + +      @returns a statically allocated string with the name of the public +               key algorithm, or NULL if that name is not known. +    */ +    const char *publicKeyAlgorithmAsString() const; + +    /** +       @brief Get the key algo string like GnuPG 2.1 prints it. + +       This returns combinations of size and algorithm. Like +       bp512 or rsa2048 + +       @returns the key algorithm as string. Empty string on error. +    */ +    std::string algoName() 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) + +GPGMEPP_MAKE_STRCMP(ByFingerprint, .primaryFingerprint()); +GPGMEPP_MAKE_STRCMP(ByKeyID, .keyID()); +GPGMEPP_MAKE_STRCMP(ByShortKeyID, .shortKeyID()); +GPGMEPP_MAKE_STRCMP(ByChainID, .chainID()); + +#endif // __GPGMEPP_KEY_H__ diff --git a/lang/cpp/src/keygenerationresult.cpp b/lang/cpp/src/keygenerationresult.cpp new file mode 100644 index 00000000..7837e208 --- /dev/null +++ b/lang/cpp/src/keygenerationresult.cpp @@ -0,0 +1,92 @@ +/* +  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 <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..c35c5044 --- /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 <memory> + +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); +    std::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..4512d3be --- /dev/null +++ b/lang/cpp/src/keylistresult.cpp @@ -0,0 +1,107 @@ +/* +  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 <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..7dfe2d71 --- /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 <memory> + +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; +    std::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..807bdaad --- /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 <memory> + +#include <iosfwd> + +namespace GpgME +{ + +class GPGMEPP_EXPORT Notation +{ +    friend class ::GpgME::Signature; +    Notation(const std::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; +    std::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..073d7724 --- /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 "scdgetinfoassuantransaction.h" +#include "error.h" +#include "data.h" +#include "util.h" + +#include <sstream> +#include <assert.h> + +using namespace GpgME; + +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; +    std::stringstream ss(s); +    std::string tok; +    while (std::getline(ss, tok, '\n')) { +        result.push_back(tok); +    } +    return result; +} + +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", +}; +static_assert((sizeof scd_getinfo_tokens / sizeof * scd_getinfo_tokens == ScdGetInfoAssuanTransaction::LastInfoItem), +              "getinfo_tokens size mismatch"); + +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..4f2ef72e --- /dev/null +++ b/lang/cpp/src/signingresult.cpp @@ -0,0 +1,265 @@ +/* +  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 <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 std::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 std::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..2c274549 --- /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 <memory> + +#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); +    std::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 std::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: +    std::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 std::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: +    std::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..fc7e4a61 --- /dev/null +++ b/lang/cpp/src/trustitem.cpp @@ -0,0 +1,114 @@ +/* +  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 <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..8ccb0bf5 --- /dev/null +++ b/lang/cpp/src/util.h @@ -0,0 +1,146 @@ +/* +  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) { +        oldmode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS; +    } +    if (newmodes & GpgME::Ephemeral) { +        oldmode |= GPGME_KEYLIST_MODE_EPHEMERAL; +    } +    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; +    } +    if (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS) { +        result |= GpgME::SignatureNotations; +    } +    if (mode & GPGME_KEYLIST_MODE_EPHEMERAL) { +        result |= GpgME::Ephemeral; +    } +    if (mode & GPGME_KEYLIST_MODE_VALIDATE) { +        result |= GpgME::Validate; +    } +#ifndef NDEBUG +    if (mode & ~(GPGME_KEYLIST_MODE_LOCAL | +                 GPGME_KEYLIST_MODE_EXTERN | +                 GPGME_KEYLIST_MODE_SIG_NOTATIONS | +                 GPGME_KEYLIST_MODE_EPHEMERAL | +                 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) +{ +    unsigned int result = 0; +    if (flags & GPGME_SIG_NOTATION_HUMAN_READABLE) { +        result |= GpgME::Notation::HumanReadable ; +    } +    if (flags & GPGME_SIG_NOTATION_CRITICAL) { +        result |= GpgME::Notation::Critical ; +    } +    return static_cast<GpgME::Notation::Flags>(result); +} + +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) { +        result |= GPGME_SIG_NOTATION_HUMAN_READABLE; +    } +    if (newflags & GpgME::Notation::Critical) { +        result |= GPGME_SIG_NOTATION_CRITICAL; +    } +    return static_cast<gpgme_sig_notation_flags_t>(result); +} + +#endif // __GPGMEPP_UTIL_H__ diff --git a/lang/cpp/src/verificationresult.cpp b/lang/cpp/src/verificationresult.cpp new file mode 100644 index 00000000..b6fde7da --- /dev/null +++ b/lang/cpp/src/verificationresult.cpp @@ -0,0 +1,557 @@ +/* +  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 <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; +        } +        if (r->file_name) { +            file_name = r->file_name; +        } +        // 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); +            } +// 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 +            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; +                } +                Nota n = { 0, 0, in->flags }; +                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); +            std::free((*it)->pka_address); +            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; +        gpgme_sig_notation_flags_t flags; +    }; + +    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 std::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 +{ +    return !isNull() && d->sigs[idx]->chain_model; +} + +GpgME::Signature::PKAStatus GpgME::Signature::pkaStatus() const +{ +    if (!isNull()) { +        return static_cast<PKAStatus>(d->sigs[idx]->pka_trust); +    } +    return UnknownPKAStatus; +} + +const char *GpgME::Signature::pkaAddress() const +{ +    if (!isNull()) { +        return d->sigs[idx]->pka_address; +    } +    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 +{ +    if (!isNull()) { +        return d->sigs[idx]->pubkey_algo; +    } +    return 0; +} + +const char *GpgME::Signature::publicKeyAlgorithmAsString() const +{ +    if (!isNull()) { +        return gpgme_pubkey_algo_name(d->sigs[idx]->pubkey_algo); +    } +    return 0; +} + +unsigned int GpgME::Signature::hashAlgorithm() const +{ +    if (!isNull()) { +        return d->sigs[idx]->hash_algo; +    } +    return 0; +} + +const char *GpgME::Signature::hashAlgorithmAsString() const +{ +    if (!isNull()) { +        return gpgme_hash_algo_name(d->sigs[idx]->hash_algo); +    } +    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 std::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; +        } +    } + +    std::shared_ptr<VerificationResult::Private> d; +    unsigned int sidx, nidx; +    gpgme_sig_notation_t nota; +}; + +GpgME::Notation::Notation(const std::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( +            isNull() ? 0 : +            d->d ? d->d->nota[d->sidx][d->nidx].flags : +            d->nota ? d->nota->flags : 0); +} + +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..17f0568b --- /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 <memory> + +#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); +    std::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 std::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: +    std::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..c9fdd5e2 --- /dev/null +++ b/lang/cpp/src/vfsmountresult.cpp @@ -0,0 +1,90 @@ +/* +  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 <vfsmountresult.h> +#include "result_p.h" + +#include <gpgme.h> + +#include <istream> +#include <string.h> + +using namespace GpgME; + +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; +}; + +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; +    if (!ctx) { +        return; +    } +    gpgme_vfs_mount_result_t res = gpgme_op_vfs_mount_result(ctx); +    if (!res) { +        return; +    } +    d.reset(new Private(res)); +} + +make_standard_stuff(VfsMountResult) + +const char *VfsMountResult::mountDir() const +{ +    if (d) { +        return d->mountDir; +    } +    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..abdd655d --- /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 <memory> + +#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); +    std::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__ | 
