diff --git a/acinclude.m4 b/acinclude.m4 index cdfe6e43..575e526f 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -58,3 +58,19 @@ AC_DEFUN([GNUPG_CHECK_VA_COPY], AC_MSG_RESULT($gnupg_cv_must_copy_va_byval) fi ]) + +dnl LIST_MEMBER() +dnl Check wether an element ist contained in a list. Set `found' to +dnl `1' if the element is found in the list, to `0' otherwise. +AC_DEFUN([LIST_MEMBER], +[ +name=$1 +list=$2 +found=0 + +for n in $list; do + if test "x$name" = "x$n"; then + found=1 + fi +done +]) diff --git a/configure.ac b/configure.ac index 55c388eb..87b9e976 100644 --- a/configure.ac +++ b/configure.ac @@ -61,6 +61,14 @@ LIBGPGME_LT_CURRENT=25 LIBGPGME_LT_AGE=14 LIBGPGME_LT_REVISION=0 +LIBGPGMEPP_LT_CURRENT=6 +LIBGPGMEPP_LT_AGE=0 +LIBGPGMEPP_LT_REVISION=0 + +LIBQGPGME_LT_CURRENT=6 +LIBQGPGME_LT_AGE=0 +LIBQGPGME_LT_REVISION=0 + # If the API is changed in an incompatible way: increment the next counter. GPGME_CONFIG_API_VERSION=1 ############################################## @@ -104,6 +112,12 @@ AC_CHECK_PROGS(GITLOG_TO_CHANGELOG, gitlog-to-changelog, [gitlog-to-changelog]) AC_SUBST(LIBGPGME_LT_CURRENT) AC_SUBST(LIBGPGME_LT_AGE) AC_SUBST(LIBGPGME_LT_REVISION) +AC_SUBST(LIBGPGMEPP_LT_CURRENT) +AC_SUBST(LIBGPGMEPP_LT_AGE) +AC_SUBST(LIBGPGMEPP_LT_REVISION) +AC_SUBST(LIBQGPGME_LT_CURRENT) +AC_SUBST(LIBQGPGME_LT_AGE) +AC_SUBST(LIBQGPGME_LT_REVISION) AC_SUBST(PACKAGE) AC_SUBST(VERSION) @@ -146,6 +160,8 @@ have_w32_system=no have_w64_system=no build_w32_glib=no build_w32_qt=no +available_languages="cpp cl qt" +default_languages="cpp cl qt" case "${host}" in x86_64-*mingw32*) have_w64_system=yes @@ -171,20 +187,9 @@ case "${host}" in AC_ARG_ENABLE(w32-glib, AC_HELP_STRING([--enable-w32-glib], [build GPGME Glib for W32]), build_w32_glib=$enableval) - - # Check disabled, because the qt-dev packages in gpg4win do - # not provide any support for cross compilation. - # PKG_CHECK_MODULES(QT4_CORE, QtCore) - - # Use it like this: - # ./configure --enable-w32-qt QT4_CORE_CFLAGS="..." QT4_CORE_LIBS="..." - AC_SUBST(QT4_CORE_CFLAGS) - AC_SUBST(QT4_CORE_LIBS) - AC_ARG_ENABLE(w32-qt, - AC_HELP_STRING([--enable-w32-qt], [build GPGME Qt for W32]), - build_w32_qt=$enableval) - ;; + ;; *) + AC_CHECK_LIB(pthread,pthread_create,have_pthread=yes) if test "$have_pthread" = yes; then AC_DEFINE(HAVE_PTHREAD, ,[Define if we have pthread.]) @@ -230,7 +235,6 @@ fi AM_CONDITIONAL(HAVE_ANDROID_SYSTEM, test "$have_android_system" = yes) AM_CONDITIONAL(BUILD_W32_GLIB, test "$build_w32_glib" = yes) -AM_CONDITIONAL(BUILD_W32_QT, test "$build_w32_qt" = yes) AM_CONDITIONAL(HAVE_PTHREAD, test "$have_pthread" = "yes") @@ -245,6 +249,97 @@ if test x$fixed_search_path != x ; then [Locate binaries only via this PATH]) fi +AC_ARG_ENABLE([languages], + AC_HELP_STRING([--enable-languages=languages], + [enable only specific language bindings]), + [enabled_languages=`echo $enableval | \ + tr ',:' ' ' | tr '[A-Z]' '[a-z]' | \ + sed 's/c++/cpp/'`], + [enabled_languages="maybe"]) +if test "x$enabled_languages" = "x" \ + -o "$enabled_languages" = "no"; then + enabled_languages= +fi + +# If languages are explicitly set missing requirements +# for the languages are treated as errors otherwise +# there will be a warning. +explicit_languages=1 +if test "x$enabled_languages" = "xmaybe"; then + explicit_languages=0 + enabled_languages="$default_languages" +fi + +for language in $enabled_languages; do + LIST_MEMBER($language, $available_languages) + if test "$found" = "0"; then + AC_MSG_ERROR([unsupported language binding specified]) + fi +done + + + +# Enable C++ 11 if cpp language is requested +LIST_MEMBER("cpp", $enabled_languages) +if test "$found" = "1"; then + AX_CXX_COMPILE_STDCXX(11, noext, optional) + if test "$HAVE_CXX11" != "1"; then + if test "$explicit_languages" = "1"; then + AC_MSG_ERROR([[ +*** +*** A compiler with c++11 support is required for the c++ binding. +***]]) + else + enabled_languages=$(echo $enabled_languages | sed 's/cpp//') + enabled_languages=$(echo $enabled_languages | sed 's/qt//') + AC_MSG_WARN([[ +*** +*** No c++11 support detected. C++ and Qt bindings will be disabled. +***]]) + fi + fi +fi + +# Check that if qt is enabled cpp also is enabled +LIST_MEMBER("qt", $enabled_languages) +if test "$found" = "1"; then + # We need to ensure that in the langauge order qt comes after cpp + # so we remove qt first and explicitly add it as last list member. + enabled_languages=$(echo $enabled_languages | sed 's/qt//') + LIST_MEMBER("cpp", $enabled_languages) + if test "$found" = "0"; then + AC_MSG_ERROR([[ +*** +*** Qt language binding depends on cpp binding. +***]]) + fi + FIND_QT + if test "$have_qt5_libs" != "yes"; then + if test "$explicit_languages" = "1"; then + AC_MSG_ERROR([[ +*** +*** Qt5 (Qt5Core) is required for Qt binding. +***]]) + else + AC_MSG_WARN([[ +*** +*** Qt5 (Qt5Core) not found Qt Binding will be disabled. +***]]) + fi + else + enabled_languages=`echo $enabled_languages qt` + + AC_CHECK_PROGS([DOXYGEN], [doxygen]) + if test -z "$DOXYGEN"; + # This is not highlighted becase it's not really important. + then AC_MSG_WARN([Doxygen not found - Qt binding doc will not be built.]) + fi + fi +fi +AM_CONDITIONAL([HAVE_DOXYGEN], + [test -n "$DOXYGEN"]) + +AC_SUBST(ENABLED_LANGUAGES, $enabled_languages) # # Provide information about the build. @@ -632,18 +727,29 @@ AC_CONFIG_FILES(Makefile src/Makefile src/versioninfo.rc src/gpgme.h) AC_CONFIG_FILES(src/gpgme-config, chmod +x src/gpgme-config) +AC_CONFIG_FILES(lang/cpp/Makefile lang/cpp/src/Makefile) +AC_CONFIG_FILES(lang/cpp/src/GpgmeppConfig.cmake.in) +AC_CONFIG_FILES(lang/cpp/src/GpgmeppConfigVersion.cmake) +AC_CONFIG_FILES(lang/qt/Makefile lang/qt/src/Makefile) +AC_CONFIG_FILES(lang/qt/src/QGpgmeConfig.cmake.in) +AC_CONFIG_FILES(lang/qt/src/QGpgmeConfigVersion.cmake) +AC_CONFIG_FILES(lang/qt/tests/Makefile) AC_CONFIG_FILES([lang/Makefile lang/cl/Makefile lang/cl/gpgme.asd]) +AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([lang/qt/doc/Doxyfile])]) +AC_CONFIG_FILES(lang/qt/doc/Makefile) AC_OUTPUT echo " GPGME v${VERSION} has been configured as follows: - Revision: mym4_revision (mym4_revision_dec) - Platform: $host + Revision: mym4_revision (mym4_revision_dec) + Platform: $host - UI Server: $uiserver - FD Passing: $use_descriptor_passing - GPGME Pthread: $have_pthread + UI Server: $uiserver + FD Passing: $use_descriptor_passing + GPGME Pthread: $have_pthread + + Language bindings: $enabled_languages " if test "x${gpg_config_script_warn}" != x; then cat <= 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..24e0461c --- /dev/null +++ b/lang/cpp/src/Makefile.am @@ -0,0 +1,93 @@ +# 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 = @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 +#include "result_p.h" + +#include + +#include + +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 + Author: Marc Mutz + + 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 + +#include +#include +#include + +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 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 +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +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(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(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(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(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(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(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 + +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 + +#include +#include +#include +#include +#include + +using namespace GpgME; +using namespace GpgME::Configuration; + +typedef std::shared_ptr< std::remove_pointer::type > shared_gpgme_conf_opt_t; +typedef std::weak_ptr< std::remove_pointer::type > weak_gpgme_conf_opt_t; + +typedef std::shared_ptr< std::remove_pointer::type > shared_gpgme_conf_arg_t; +typedef std::weak_ptr< std::remove_pointer::type > weak_gpgme_conf_arg_t; + +typedef std::shared_ptr< std::remove_pointer::type > shared_gpgme_ctx_t; +typedef std::weak_ptr< std::remove_pointer::type > weak_gpgme_ctx_t; + +namespace +{ +struct nodelete { + template void operator()(T *) {} +}; +} + +// static +std::vector 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(); + } + 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(); + } + shared_gpgme_conf_comp_t head(conf_list_native, &gpgme_conf_release); + + // + // 3. convert to vector: + // + std::vector 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