Add qgpgme as qt language binding
authorAndre Heinecke <aheinecke@intevation.de>
Tue, 8 Mar 2016 13:33:15 +0000 (14:33 +0100)
committerAndre Heinecke <aheinecke@intevation.de>
Tue, 8 Mar 2016 14:37:10 +0000 (15:37 +0100)
* 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.

13 files changed:
configure.ac
lang/README
lang/cpp/src/GpgmeppConfig.cmake.in.in
lang/cpp/src/Makefile.am
lang/qt/Makefile.am [new file with mode: 0644]
lang/qt/README [new file with mode: 0644]
lang/qt/src/Makefile.am [new file with mode: 0644]
lang/qt/src/QGpgmeConfig.cmake.in.in [new file with mode: 0644]
lang/qt/src/QGpgmeConfigVersion.cmake.in [new file with mode: 0644]
lang/qt/src/dataprovider.cpp [new file with mode: 0644]
lang/qt/src/dataprovider.h [new file with mode: 0644]
lang/qt/src/qgpgme_export.h [new file with mode: 0644]
m4/qt.m4 [new file with mode: 0644]

index c3a46ae..9dd02e6 100644 (file)
@@ -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
 
index 5745029..e1c04f2 100644 (file)
@@ -11,3 +11,4 @@ Directory     Language
 
 cl             Common Lisp
 cpp     C++
+qt      Qt-Framework API
index 4b5b905..51218c6 100644 (file)
@@ -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)
index a9b7ef4..e56b818 100644 (file)
@@ -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 (file)
index 0000000..7fbaca8
--- /dev/null
@@ -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 (file)
index 0000000..6aeb876
--- /dev/null
@@ -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 (file)
index 0000000..54d0530
--- /dev/null
@@ -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 (file)
index 0000000..36ee920
--- /dev/null
@@ -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 (file)
index 0000000..04a12cb
--- /dev/null
@@ -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 (file)
index 0000000..8893877
--- /dev/null
@@ -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 <dataprovider.h>
+
+#include <error.h>
+
+#include <QIODevice>
+#include <QProcess>
+
+#include <cstdio>
+#include <cstring>
+#include <cassert>
+
+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<size_t>(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<size_t>(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<unsigned long>( 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<size_t>(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<QIODevice> &io)
+    : GpgME::DataProvider(),
+      mIO(io),
+      mErrorOccurred(false),
+      mHaveQProcess(qobject_cast<QProcess *>(io.get()))
+{
+    assert(mIO);
+}
+
+QIODeviceDataProvider::~QIODeviceDataProvider() {}
+
+bool QIODeviceDataProvider::isSupported(Operation op) const
+{
+    const QProcess *const proc = qobject_cast<QProcess *>(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<QIODevice> &io, char *buffer, qint64 maxSize)
+{
+    while (!io->bytesAvailable()) {
+        if (!io->waitForReadyRead(-1)) {
+            if (const QProcess *const p = qobject_cast<QProcess *>(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<char *>(buffer), bufSize)
+                           : mIO->read(static_cast<char *>(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<unsigned long>( bufSize ) );
+#endif
+    if (bufSize == 0) {
+        return 0;
+    }
+    if (!buffer) {
+        Error::setSystemError(GPG_ERR_EINVAL);
+        return -1;
+    }
+
+    return mIO->write(static_cast<const char *>(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 (file)
index 0000000..8bc0c85
--- /dev/null
@@ -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 <interfaces/dataprovider.h>
+
+#include <QtCore/QByteArray>
+
+#include <boost/shared_ptr.hpp>
+
+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<QIODevice> &initialData);
+    ~QIODeviceDataProvider();
+
+    const boost::shared_ptr<QIODevice> &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<QIODevice> 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 (file)
index 0000000..40630d5
--- /dev/null
@@ -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 (file)
index 0000000..80e2245
--- /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
+])