From 8347f3d5fc3e476aa767fbbaf09a1310a6154280 Mon Sep 17 00:00:00 2001 From: Andre Heinecke Date: Tue, 8 Mar 2016 14:33:15 +0100 Subject: [PATCH] Add qgpgme as qt language binding * configure.ac: Add version defines. Check for qt if neccessary. * lang/README: Mention qt * lang/cpp/src/GpgmeppConfig.cmake.in.in: Remove comment. Find qgpgme. * lang/qt/src/Makefile.am: New. Build qgpgme. * lang/qt/README, lang/qt/src/Makefile.am, lang/qt/src/QGpgmeConfig.cmake.in.in, lang/qt/src/QGpgmeConfigVersion.cmake.in, lang/qt/src/dataprovider.cpp, lang/qt/src/dataprovider.h, lang/qt/src/qgpgme_export.h, m4/qt.m4: New. * lang/cpp/src/GpgmeppConfig.cmake.in.in, lang/cpp/src/Makefile.am: Fix generated config file. -- For now this is just the dataprovider which was part of the KF5 Gpgmepp QGpgme variant. This is very thin but a useful class which is used downstream. --- configure.ac | 32 ++- lang/README | 1 + lang/cpp/src/GpgmeppConfig.cmake.in.in | 21 +- lang/cpp/src/Makefile.am | 8 + lang/qt/Makefile.am | 23 ++ lang/qt/README | 27 +++ lang/qt/src/Makefile.am | 67 ++++++ lang/qt/src/QGpgmeConfig.cmake.in.in | 107 +++++++++ lang/qt/src/QGpgmeConfigVersion.cmake.in | 31 +++ lang/qt/src/dataprovider.cpp | 281 +++++++++++++++++++++++ lang/qt/src/dataprovider.h | 104 +++++++++ lang/qt/src/qgpgme_export.h | 53 +++++ m4/qt.m4 | 51 ++++ 13 files changed, 790 insertions(+), 16 deletions(-) create mode 100644 lang/qt/Makefile.am create mode 100644 lang/qt/README create mode 100644 lang/qt/src/Makefile.am create mode 100644 lang/qt/src/QGpgmeConfig.cmake.in.in create mode 100644 lang/qt/src/QGpgmeConfigVersion.cmake.in create mode 100644 lang/qt/src/dataprovider.cpp create mode 100644 lang/qt/src/dataprovider.h create mode 100644 lang/qt/src/qgpgme_export.h create mode 100644 m4/qt.m4 diff --git a/configure.ac b/configure.ac index c3a46ae7..9dd02e63 100644 --- a/configure.ac +++ b/configure.ac @@ -65,6 +65,10 @@ LIBGPGMEPP_LT_CURRENT=3 LIBGPGMEPP_LT_AGE=0 LIBGPGMEPP_LT_REVISION=0 +LIBQGPGME_LT_CURRENT=1 +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 ############################################## @@ -111,6 +115,9 @@ 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) @@ -153,8 +160,8 @@ have_w32_system=no have_w64_system=no build_w32_glib=no build_w32_qt=no -available_languages="cpp cl" -default_languages="cpp cl" +available_languages="cpp cl qt" +default_languages="cpp cl qt" case "${host}" in x86_64-*mingw32*) have_w64_system=yes @@ -259,6 +266,24 @@ for language in $enabled_languages; do AC_MSG_ERROR([unsupported language binding specified]) fi done +# Check that if qt is enabled cpp also is enabled +LIST_MEMBER("qt", $enabled_languages) +if test "$found" = "1"; then + LIST_MEMBER("cpp", $enabled_languages) + if test "$found" = "0"; then + AC_MSG_ERROR([qt binding depends on cpp language binding]) + fi + FIND_QT + if test "$have_qt5_libs" != "yes"; then + AC_MSG_ERROR([[ + *** + *** Qt5 (Qt5Core) is required for qt binding. + ***]]) + fi + # Make sure that qt comes after cpp + enabled_languages=`echo $enabled_languages | sed 's/qt//'` + enabled_languages=`echo $enabled_languages qt` +fi AC_SUBST(ENABLED_LANGUAGES, $enabled_languages) # @@ -650,6 +675,9 @@ 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/Makefile lang/cl/Makefile lang/cl/gpgme.asd]) AC_OUTPUT diff --git a/lang/README b/lang/README index 57450290..e1c04f27 100644 --- a/lang/README +++ b/lang/README @@ -11,3 +11,4 @@ Directory Language cl Common Lisp cpp C++ +qt Qt-Framework API diff --git a/lang/cpp/src/GpgmeppConfig.cmake.in.in b/lang/cpp/src/GpgmeppConfig.cmake.in.in index 4b5b905b..51218c62 100644 --- a/lang/cpp/src/GpgmeppConfig.cmake.in.in +++ b/lang/cpp/src/GpgmeppConfig.cmake.in.in @@ -37,7 +37,7 @@ set(CMAKE_IMPORT_FILE_VERSION 1) set(_targetsDefined) set(_targetsNotDefined) set(_expectedTargets) -foreach(_expectedTarget KF5::Gpgmepp KF5::QGpgme) +foreach(_expectedTarget KF5::Gpgmepp Gpgmepp) list(APPEND _expectedTargets ${_expectedTarget}) if(NOT TARGET ${_expectedTarget}) list(APPEND _targetsNotDefined ${_expectedTarget}) @@ -69,18 +69,10 @@ add_library(Gpgmepp SHARED IMPORTED) set_target_properties(Gpgmepp PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/gpgme++" - INTERFACE_LINK_LIBRARIES "@libdir@/libgpgme.dll.a;@LIBASSUAN_LIBS@;@GPG_ERROR_LIBS@" + INTERFACE_LINK_LIBRARIES "@resolved_libdir@/libgpgme@libsuffix@;@LIBASSUAN_LIBS@;@GPG_ERROR_LIBS@" + IMPORTED_LOCATION "@resolved_libdir@/libgpgmepp@libsuffix@" ) -# Create imported target QGpgme -#add_library(QGpgme SHARED IMPORTED) - -#set_target_properties(KF5::QGpgme PROPERTIES -# INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/qgpgme" - # INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX} TODO" -# INTERFACE_LINK_LIBRARIES "Qt5::Core" -#) - if(CMAKE_VERSION VERSION_LESS 2.8.12) message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.") endif() @@ -107,9 +99,10 @@ but not all the files it references. endforeach() unset(_IMPORT_CHECK_TARGETS) -# This file does not depend on other imported targets which have -# been exported from the same project but in a separate export set. - # 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/Makefile.am b/lang/cpp/src/Makefile.am index a9b7ef4c..e56b8185 100644 --- a/lang/cpp/src/Makefile.am +++ b/lang/cpp/src/Makefile.am @@ -62,8 +62,16 @@ 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 diff --git a/lang/qt/Makefile.am b/lang/qt/Makefile.am new file mode 100644 index 00000000..7fbaca8e --- /dev/null +++ b/lang/qt/Makefile.am @@ -0,0 +1,23 @@ +# 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 + +SUBDIRS = src + +EXTRA_DIST = README diff --git a/lang/qt/README b/lang/qt/README new file mode 100644 index 00000000..6aeb8765 --- /dev/null +++ b/lang/qt/README @@ -0,0 +1,27 @@ +Qt API bindings/wrapper for gpgme +---------------------------------------- +Based on KF5gpgmepp QGpgme + +QGpgme 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. + +QGpgme is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU 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. + +Overview +-------- +QGpgme provides Qt API bindings around Gpgmepp. It depends on Gpgmepp. + +Currently this is a very thin library that only provides a QByteArray +and QIODevice dataprovider. But might be extended in the future with +code that is currently part of KDE's libkleopatra. To provide an easy +to use API for Qt Applications. diff --git a/lang/qt/src/Makefile.am b/lang/qt/src/Makefile.am new file mode 100644 index 00000000..54d0530d --- /dev/null +++ b/lang/qt/src/Makefile.am @@ -0,0 +1,67 @@ +# 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 +lib_LTLIBRARIES = libqgpgme.la +EXTRA_DIST = QGpgmeConfig.cmake.in.in QGpgmeConfigVersion.cmake.in + +qgpgme_sources = \ + dataprovider.cpp + +qgpgme_headers = \ + dataprovider.h qgpgme_export.h + +qgpgmeincludedir = $(includedir)/qgpgme +qgpgmeinclude_HEADERS = $(qgpgme_headers) + +libqgpgme_la_SOURCES = $(qgpgme_sources) $(qgpgme_headers) + +AM_CPPFLAGS = @GPGME_QT_CFLAGS@ @GPG_ERROR_CFLAGS@ @LIBASSUAN_CFLAGS@ \ + -DBUILDING_QGPGME -I$(top_srcdir)/lang/cpp/src + +libqgpgme_la_LIBADD = ../../cpp/src/libgpgmepp.la ../../../src/libgpgme.la \ + @LIBASSUAN_LIBS@ @GPGME_QT_LIBS@ +libqgpgme_la_LDFLAGS = -version-info \ + @LIBQGPGME_LT_CURRENT@:@LIBQGPGME_LT_REVISION@:@LIBQGPGME_LT_AGE@ + +if HAVE_W32_SYSTEM +libsuffix=.dll.a +else +libsuffix=.so +endif + +QGpgmeConfig.cmake: QGpgmeConfig.cmake.in + sed -e 's|[@]resolved_libdir@|$(libdir)|g' < "$<" > "$@" + sed -e 's|[@]libsuffix@|$(libsuffix)|g' < "$@" > "$@".2 + mv "$@".2 "$@" + +install-cmake-files: QGpgmeConfig.cmake QGpgmeConfigVersion.cmake + -$(INSTALL) -d $(DESTDIR)$(libdir)/cmake/Gpgmepp + $(INSTALL) QGpgmeConfig.cmake \ + $(DESTDIR)$(libdir)/cmake/Gpgmepp/QGpgmeConfig.cmake + $(INSTALL) QGpgmeConfigVersion.cmake \ + $(DESTDIR)$(libdir)/cmake/Gpgmepp/QGpgmeConfigVersion.cmake + +uninstall-cmake-files: + -rm $(DESTDIR)$(libdir)/cmake/Gpgmepp/QGpgmeConfigVersion.cmake + -rm $(DESTDIR)$(libdir)/cmake/Gpgmepp/QGpgmeConfig.cmake + -rmdir $(DESTDIR)$(libdir)/cmake/Gpgmepp/ + +install-data-local: install-cmake-files + +uninstall-local: uninstall-cmake-files diff --git a/lang/qt/src/QGpgmeConfig.cmake.in.in b/lang/qt/src/QGpgmeConfig.cmake.in.in new file mode 100644 index 00000000..36ee9205 --- /dev/null +++ b/lang/qt/src/QGpgmeConfig.cmake.in.in @@ -0,0 +1,107 @@ +# CMake Config file for QGPGME. +# Copyright (C) 2016 Intevation GmbH +# +# This file is part of GPGME. +# +# 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 QGpgme KF5::QGpgme) + 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 QGpgme +add_library(QGpgme SHARED IMPORTED) + +set_target_properties(QGpgme PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/qgpgme" + INTERFACE_LINK_LIBRARIES "Gpgmepp;Qt5::Core" + IMPORTED_LOCATION "@resolved_libdir@/libqgpgme@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) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/lang/qt/src/QGpgmeConfigVersion.cmake.in b/lang/qt/src/QGpgmeConfigVersion.cmake.in new file mode 100644 index 00000000..04a12cbb --- /dev/null +++ b/lang/qt/src/QGpgmeConfigVersion.cmake.in @@ -0,0 +1,31 @@ +# CMake Version file for QGPGME. +# Copyright (C) 2016 Intevation GmbH +# +# This file is part of GPGME. +# +# 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 "@LIBQGPGME_LT_CURRENT@.@LIBQGPGME_LT_AGE@.@LIBQGPGME_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/qt/src/dataprovider.cpp b/lang/qt/src/dataprovider.cpp new file mode 100644 index 00000000..88938772 --- /dev/null +++ b/lang/qt/src/dataprovider.cpp @@ -0,0 +1,281 @@ +/* dataprovider.cpp + Copyright (C) 2004 Klar�vdalens Datakonsult AB + + This file is part of QGPGME. + + QGPGME 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. + + QGPGME is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with QGPGME; 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 + +#include + +#include +#include + +#include +#include +#include + +using namespace QGpgME; +using namespace GpgME; + +// +// +// QByteArrayDataProvider +// +// + +static bool resizeAndInit(QByteArray &ba, size_t newSize) +{ + const size_t oldSize = ba.size(); + ba.resize(newSize); + const bool ok = (newSize == static_cast(ba.size())); + if (ok) { + memset(ba.data() + oldSize, 0, newSize - oldSize); + } + return ok; +} + +QByteArrayDataProvider::QByteArrayDataProvider() + : GpgME::DataProvider(), mOff(0) {} + +QByteArrayDataProvider::QByteArrayDataProvider(const QByteArray &initialData) + : GpgME::DataProvider(), mArray(initialData), mOff(0) {} + +QByteArrayDataProvider::~QByteArrayDataProvider() {} + +ssize_t QByteArrayDataProvider::read(void *buffer, size_t bufSize) +{ +#ifndef NDEBUG + //qDebug( "QByteArrayDataProvider::read( %p, %d )", buffer, bufSize ); +#endif + if (bufSize == 0) { + return 0; + } + if (!buffer) { + Error::setSystemError(GPG_ERR_EINVAL); + return -1; + } + if (mOff >= mArray.size()) { + return 0; // EOF + } + size_t amount = qMin(bufSize, static_cast(mArray.size() - mOff)); + assert(amount > 0); + memcpy(buffer, mArray.data() + mOff, amount); + mOff += amount; + return amount; +} + +ssize_t QByteArrayDataProvider::write(const void *buffer, size_t bufSize) +{ +#ifndef NDEBUG + //qDebug( "QByteArrayDataProvider::write( %p, %lu )", buffer, static_cast( bufSize ) ); +#endif + if (bufSize == 0) { + return 0; + } + if (!buffer) { + Error::setSystemError(GPG_ERR_EINVAL); + return -1; + } + if (mOff >= mArray.size()) { + resizeAndInit(mArray, mOff + bufSize); + } + if (mOff >= mArray.size()) { + Error::setSystemError(GPG_ERR_EIO); + return -1; + } + assert(bufSize <= static_cast(mArray.size()) - mOff); + memcpy(mArray.data() + mOff, buffer, bufSize); + mOff += bufSize; + return bufSize; +} + +off_t QByteArrayDataProvider::seek(off_t offset, int whence) +{ +#ifndef NDEBUG + //qDebug( "QByteArrayDataProvider::seek( %d, %d )", int(offset), whence ); +#endif + int newOffset = mOff; + switch (whence) { + case SEEK_SET: + newOffset = offset; + break; + case SEEK_CUR: + newOffset += offset; + break; + case SEEK_END: + newOffset = mArray.size() + offset; + break; + default: + Error::setSystemError(GPG_ERR_EINVAL); + return (off_t) - 1; + } + return mOff = newOffset; +} + +void QByteArrayDataProvider::release() +{ +#ifndef NDEBUG + //qDebug( "QByteArrayDataProvider::release()" ); +#endif + mArray = QByteArray(); +} + +// +// +// QIODeviceDataProvider +// +// + +QIODeviceDataProvider::QIODeviceDataProvider(const boost::shared_ptr &io) + : GpgME::DataProvider(), + mIO(io), + mErrorOccurred(false), + mHaveQProcess(qobject_cast(io.get())) +{ + assert(mIO); +} + +QIODeviceDataProvider::~QIODeviceDataProvider() {} + +bool QIODeviceDataProvider::isSupported(Operation op) const +{ + const QProcess *const proc = qobject_cast(mIO.get()); + bool canRead = true; + if (proc) { + canRead = proc->readChannel() == QProcess::StandardOutput; + } + + switch (op) { + case Read: return mIO->isReadable() && canRead; + case Write: return mIO->isWritable(); + case Seek: return !mIO->isSequential(); + case Release: return true; + default: return false; + } +} + +static qint64 blocking_read(const boost::shared_ptr &io, char *buffer, qint64 maxSize) +{ + while (!io->bytesAvailable()) { + if (!io->waitForReadyRead(-1)) { + if (const QProcess *const p = qobject_cast(io.get())) { + if (p->error() == QProcess::UnknownError && + p->exitStatus() == QProcess::NormalExit && + p->exitCode() == 0) { + return 0; + } else { + Error::setSystemError(GPG_ERR_EIO); + return -1; + } + } else { + return 0; // assume EOF (loses error cases :/ ) + } + } + } + return io->read(buffer, maxSize); +} + +ssize_t QIODeviceDataProvider::read(void *buffer, size_t bufSize) +{ +#ifndef NDEBUG + //qDebug( "QIODeviceDataProvider::read( %p, %lu )", buffer, bufSize ); +#endif + if (bufSize == 0) { + return 0; + } + if (!buffer) { + Error::setSystemError(GPG_ERR_EINVAL); + return -1; + } + const qint64 numRead = mHaveQProcess + ? blocking_read(mIO, static_cast(buffer), bufSize) + : mIO->read(static_cast(buffer), bufSize); + + //workaround: some QIODevices (known example: QProcess) might not return 0 (EOF), but immediately -1 when finished. If no + //errno is set, gpgme doesn't detect the error and loops forever. So return 0 on the very first -1 in case errno is 0 + + ssize_t rc = numRead; + if (numRead < 0 && !Error::hasSystemError()) { + if (mErrorOccurred) { + Error::setSystemError(GPG_ERR_EIO); + } else { + rc = 0; + } + } + if (numRead < 0) { + mErrorOccurred = true; + } + return rc; +} + +ssize_t QIODeviceDataProvider::write(const void *buffer, size_t bufSize) +{ +#ifndef NDEBUG + //qDebug( "QIODeviceDataProvider::write( %p, %lu )", buffer, static_cast( bufSize ) ); +#endif + if (bufSize == 0) { + return 0; + } + if (!buffer) { + Error::setSystemError(GPG_ERR_EINVAL); + return -1; + } + + return mIO->write(static_cast(buffer), bufSize); +} + +off_t QIODeviceDataProvider::seek(off_t offset, int whence) +{ +#ifndef NDEBUG + //qDebug( "QIODeviceDataProvider::seek( %d, %d )", int(offset), whence ); +#endif + if (mIO->isSequential()) { + Error::setSystemError(GPG_ERR_ESPIPE); + return (off_t) - 1; + } + qint64 newOffset = mIO->pos(); + switch (whence) { + case SEEK_SET: + newOffset = offset; + break; + case SEEK_CUR: + newOffset += offset; + break; + case SEEK_END: + newOffset = mIO->size() + offset; + break; + default: + Error::setSystemError(GPG_ERR_EINVAL); + return (off_t) - 1; + } + if (!mIO->seek(newOffset)) { + Error::setSystemError(GPG_ERR_EINVAL); + return (off_t) - 1; + } + return newOffset; +} + +void QIODeviceDataProvider::release() +{ +#ifndef NDEBUG + //qDebug( "QIODeviceDataProvider::release()" ); +#endif + mIO->close(); +} diff --git a/lang/qt/src/dataprovider.h b/lang/qt/src/dataprovider.h new file mode 100644 index 00000000..8bc0c85a --- /dev/null +++ b/lang/qt/src/dataprovider.h @@ -0,0 +1,104 @@ +/* dataprovider.h + Copyright (C) 2004 Klarälvdalens Datakonsult AB + + This file is part of QGPGME. + + QGPGME 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. + + QGPGME is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with QGPGME; 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 __QGPGME_DATAPROVIDER_H__ +#define __QGPGME_DATAPROVIDER_H__ + +#include "qgpgme_export.h" +#include + +#include + +#include + +class QIODevice; + +namespace QGpgME +{ + +class QGPGME_EXPORT QByteArrayDataProvider : public GpgME::DataProvider +{ +public: + QByteArrayDataProvider(); + explicit QByteArrayDataProvider(const QByteArray &initialData); + ~QByteArrayDataProvider(); + + const QByteArray &data() const + { + return mArray; + } + +private: + // these shall only be accessed through the dataprovider + // interface, where they're public: + /*! \reimp */ + bool isSupported(Operation) const + { + return true; + } + /*! \reimp */ + ssize_t read(void *buffer, size_t bufSize); + /*! \reimp */ + ssize_t write(const void *buffer, size_t bufSize); + /*! \reimp */ + off_t seek(off_t offset, int whence); + /*! \reimp */ + void release(); + +private: + QByteArray mArray; + off_t mOff; +}; + +class QGPGME_EXPORT QIODeviceDataProvider : public GpgME::DataProvider +{ +public: + explicit QIODeviceDataProvider(const boost::shared_ptr &initialData); + ~QIODeviceDataProvider(); + + const boost::shared_ptr &ioDevice() const + { + return mIO; + } + +private: + // these shall only be accessed through the dataprovider + // interface, where they're public: + /*! \reimp */ + bool isSupported(Operation) const; + /*! \reimp */ + ssize_t read(void *buffer, size_t bufSize); + /*! \reimp */ + ssize_t write(const void *buffer, size_t bufSize); + /*! \reimp */ + off_t seek(off_t offset, int whence); + /*! \reimp */ + void release(); + +private: + const boost::shared_ptr mIO; + bool mErrorOccurred : 1; + bool mHaveQProcess : 1; +}; + +} // namespace QGpgME + +#endif diff --git a/lang/qt/src/qgpgme_export.h b/lang/qt/src/qgpgme_export.h new file mode 100644 index 00000000..40630d55 --- /dev/null +++ b/lang/qt/src/qgpgme_export.h @@ -0,0 +1,53 @@ + +#ifndef QGPGME_EXPORT_H +#define QGPGME_EXPORT_H + +#ifdef QGPGME_STATIC_DEFINE +# define QGPGME_EXPORT +# define QGPGME_NO_EXPORT +#else +# ifndef QGPGME_EXPORT +# ifdef BUILDING_QGPGME + /* We are building this library */ +# ifdef WIN32 +# define QGPGME_EXPORT __declspec(dllexport) +# else +# define QGPGME_EXPORT __attribute__((visibility("default"))) +# endif +# else + /* We are using this library */ +# ifdef WIN32 +# define QGPGME_EXPORT __declspec(dllimport) +# else +# define QGPGME_EXPORT __attribute__((visibility("default"))) +# endif +# endif +# endif + +# ifndef QGPGME_NO_EXPORT +# ifdef WIN32 +# define QGPGME_NO_EXPORT +# else +# define QGPGME_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +# endif +#endif + +#ifndef QGPGME_DEPRECATED +# define QGPGME_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef QGPGME_DEPRECATED_EXPORT +# define QGPGME_DEPRECATED_EXPORT QGPGME_EXPORT QGPGME_DEPRECATED +#endif + +#ifndef QGPGME_DEPRECATED_NO_EXPORT +# define QGPGME_DEPRECATED_NO_EXPORT QGPGME_NO_EXPORT QGPGME_DEPRECATED +#endif + +#define DEFINE_NO_DEPRECATED 0 +#if DEFINE_NO_DEPRECATED +# define QGPGME_NO_DEPRECATED +#endif + +#endif diff --git a/m4/qt.m4 b/m4/qt.m4 new file mode 100644 index 00000000..80e22459 --- /dev/null +++ b/m4/qt.m4 @@ -0,0 +1,51 @@ +dnl qt.m4 +dnl Copyright (C) 2016 Intevation GmbH +dnl +dnl This file is part of gpgme and is provided under the same license as gpgme + +dnl Autoconf macro to find either Qt4 or Qt5 +dnl +dnl sets GPGME_QT_LIBS and GPGME_QT_CFLAGS +dnl +dnl if QT5 was found have_qt5_libs is set to yes + +AC_DEFUN([FIND_QT], +[ + have_qt5_libs="no"; + + PKG_CHECK_MODULES(GPGME_QT, + Qt5Core >= 5.0.0, + [have_qt5_libs="yes"], + [have_qt5_libs="no"]) + + if "$PKG_CONFIG" --variable qt_config Qt5Core | grep -q "reduce_relocations"; then + GPGME_QT_CFLAGS="$GPGME_QT_CFLAGS -fpic" + fi + if test "$have_qt5_libs" = "yes"; then + AC_CHECK_TOOL(MOC, moc) + AC_MSG_CHECKING([moc version]) + mocversion=`$MOC -v 2>&1` + mocversiongrep=`echo $mocversion | grep "Qt 5\|moc 5"` + if test x"$mocversiongrep" != x"$mocversion"; then + AC_MSG_RESULT([no]) + # moc was not the qt5 one, try with moc-qt5 + AC_CHECK_TOOL(MOC2, moc-qt5) + mocversion=`$MOC2 -v 2>&1` + mocversiongrep=`echo $mocversion | grep "Qt 5\|moc-qt5 5\|moc 5"` + if test x"$mocversiongrep" != x"$mocversion"; then + AC_CHECK_TOOL(QTCHOOSER, qtchooser) + qt5tooldir=`QT_SELECT=qt5 qtchooser -print-env | grep QTTOOLDIR | cut -d '=' -f 2 | cut -d \" -f 2` + mocversion=`$qt5tooldir/moc -v 2>&1` + mocversiongrep=`echo $mocversion | grep "Qt 5\|moc 5"` + if test x"$mocversiongrep" != x"$mocversion"; then + # no valid moc found + have_qt5_libs="no"; + else + MOC=$qt5tooldir/moc + fi + else + MOC=$MOC2 + fi + fi + fi +])