diff --git a/CMakeLists.txt b/CMakeLists.txt
index 83c574412..712974d92 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -121,11 +121,6 @@ macro_log_feature(Boost_FOUND "Boost" "Provides free peer-reviewed portable C++
macro_optional_find_package(QCA2)
macro_log_feature(QCA2_FOUND "QCA2" "Provides encryption and signing functions required for Grooveshark resolver" "http://delta.affinix.com/qca/" FALSE "" "")
-if( NOT QTKEYCHAIN_INCLUDE_DIRS OR NOT QTKEYCHAIN_LIBRARIES )
-macro_optional_find_package(QtKeychain)
-macro_log_feature(QTKEYCHAIN_FOUND "QtKeychain" "Provides support for secure password storage" "https://github.com/frankosterfeld/qtkeychain" TRUE "" "")
-endif()
-
macro_optional_find_package(LibAttica)
macro_log_feature(LIBATTICA_FOUND "libattica" "Provides support for automatic fetching and managing of resolvers from the tomahawk website" "https://projects.kde.org/projects/kdesupport/attica" TRUE "" "")
@@ -164,6 +159,17 @@ SET( LIBPORTFWD_LIBRARY tomahawk_portfwd )
SET( LIBPORTFWD_LIBRARIES ${LIBPORTFWD_LIBRARY} )
ADD_SUBDIRECTORY( ${THIRDPARTY_DIR}/libportfwd )
+### qtkeychain
+SET( QTKEYCHAIN_INCLUDE_DIRS ${THIRDPARTY_DIR}/qtkeychain )
+SET( QTKEYCHAIN_LIBRARY qtkeychain )
+SET( QTKEYCHAIN_LIBRARIES ${QTKEYCHAIN_LIBRARY} )
+ADD_SUBDIRECTORY( ${THIRDPARTY_DIR}/qtkeychain/qtkeychain )
+
+if( NOT QTKEYCHAIN_INCLUDE_DIRS OR NOT QTKEYCHAIN_LIBRARIES )
+macro_optional_find_package(QtKeychain)
+macro_log_feature(QTKEYCHAIN_FOUND "QtKeychain" "Provides support for secure password storage" "https://github.com/frankosterfeld/qtkeychain" TRUE "" "")
+endif()
+
# we need pthreads too
#macro_optional_find_package(Threads)
#macro_log_feature(THREADS_FOUND "Threads" "Threading Library" "" TRUE "" "Platform specific library for threading")
diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt
index a9d309d64..18199c42a 100644
--- a/src/libtomahawk/CMakeLists.txt
+++ b/src/libtomahawk/CMakeLists.txt
@@ -327,8 +327,8 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.
${LIBECHONEST_INCLUDE_DIR}/..
${CLUCENE_INCLUDE_DIRS}
${PHONON_INCLUDES}
- ${QTKEYCHAIN_INCLUD_DIRS}
- ${QTKEYCHAIN_INCLUD_DIRS}/..
+ ${QTKEYCHAIN_INCLUDE_DIRS}
+ ${QTKEYCHAIN_INCLUDE_DIRS}/..
${CMAKE_BINARY_DIR}/thirdparty/liblastfm2/src
playlist
diff --git a/thirdparty/qtkeychain/CMakeLists.txt b/thirdparty/qtkeychain/CMakeLists.txt
new file mode 100644
index 000000000..46a848a8c
--- /dev/null
+++ b/thirdparty/qtkeychain/CMakeLists.txt
@@ -0,0 +1,105 @@
+cmake_minimum_required(VERSION 2.8)
+project(qtkeychain)
+
+###
+
+set(QTKEYCHAIN_VERSION 0)
+set(QTKEYCHAIN_SOVERSION 0)
+
+###
+
+set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${PROJECT_SOURCE_DIR}/cmake/Modules")
+include(GNUInstallDirs)
+
+if(UNIX AND NOT APPLE)
+ find_package(Qt4 COMPONENTS QtCore QtDBus REQUIRED)
+else()
+ find_package(Qt4 COMPONENTS QtCore REQUIRED)
+endif()
+
+include_directories(${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR})
+
+list(APPEND qtkeychain_LIBRARIES ${QT_QTCORE_LIBRARY})
+set(qtkeychain_SOURCES
+ keychain.cpp
+)
+
+
+if(WIN32)
+ list(APPEND qtkeychain_SOURCES keychain_win.cpp)
+ list(APPEND qtkeychain_LIBRARIES crypt32)
+ #FIXME: mingw bug; otherwise getting undefined refs to RtlSecureZeroMemory there
+ if(MINGW)
+ add_definitions( -O2 )
+ endif()
+endif()
+
+if(APPLE)
+ list(APPEND qtkeychain_SOURCES keychain_mac.cpp)
+
+ find_library(COREFOUNDATION_LIBRARY CoreFoundation)
+ list(APPEND qtkeychain_LIBRARIES ${COREFOUNDATION_LIBRARY})
+
+ find_library(SECURITY_LIBRARY Security)
+ list(APPEND qtkeychain_LIBRARIES ${SECURITY_LIBRARY})
+endif()
+
+if(UNIX AND NOT APPLE)
+ list(APPEND qtkeychain_SOURCES keychain_dbus.cpp)
+ qt4_add_dbus_interface(qtkeychain_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/org.kde.KWallet.xml kwallet_interface KWalletInterface)
+ list(APPEND qtkeychain_LIBRARIES ${QT_QTDBUS_LIBRARY})
+endif()
+
+QT4_WRAP_CPP(qtkeychain_MOC_OUTFILES keychain.h keychain_p.h)
+
+if(NOT QTKEYCHAIN_STATIC)
+ add_library(qtkeychain SHARED ${qtkeychain_SOURCES} ${qtkeychain_MOC_OUTFILES})
+ set_target_properties(qtkeychain PROPERTIES COMPILE_DEFINITIONS QKEYCHAIN_BUILD_QKEYCHAIN_LIB)
+ target_link_libraries(qtkeychain ${qtkeychain_LIBRARIES})
+else()
+ add_library(qtkeychain STATIC ${qtkeychain_SOURCES} ${qtkeychain_MOC_OUTFILES})
+ set_target_properties(qtkeychain PROPERTIES COMPILE_DEFINITIONS QKEYCHAIN_STATICLIB)
+endif()
+
+set_target_properties(qtkeychain PROPERTIES
+ VERSION ${QTKEYCHAIN_VERSION}
+ SOVERSION ${QTKEYCHAIN_SOVERSION}
+)
+
+install(FILES keychain.h qkeychain_export.h
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/qtkeychain/
+)
+
+install(TARGETS qtkeychain
+ EXPORT QtKeychainLibraryDepends
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+add_executable( testclient testclient.cpp )
+target_link_libraries( testclient qtkeychain)
+
+
+###
+### CMake config file
+###
+
+export(TARGETS qtkeychain FILE "${PROJECT_BINARY_DIR}/QtKeychainLibraryDepends.cmake")
+export(PACKAGE QtKeychain)
+
+configure_file(QtKeychainBuildTreeSettings.cmake.in
+ "${PROJECT_BINARY_DIR}/QtKeychainBuildTreeSettings.cmake" @ONLY)
+configure_file(QtKeychainConfig.cmake.in
+ "${PROJECT_BINARY_DIR}/QtKeychainConfig.cmake" @ONLY)
+configure_file(QtKeychainConfigVersion.cmake.in
+ "${PROJECT_BINARY_DIR}/QtKeychainConfigVersion.cmake" @ONLY)
+
+install(EXPORT QtKeychainLibraryDepends
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/QtKeychain"
+)
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/QtKeychainConfig.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/QtKeychainConfigVersion.cmake
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/QtKeychain
+)
diff --git a/thirdparty/qtkeychain/COPYING b/thirdparty/qtkeychain/COPYING
new file mode 100644
index 000000000..cca2a5c9a
--- /dev/null
+++ b/thirdparty/qtkeychain/COPYING
@@ -0,0 +1,20 @@
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/thirdparty/qtkeychain/QtKeychainBuildTreeSettings.cmake.in b/thirdparty/qtkeychain/QtKeychainBuildTreeSettings.cmake.in
new file mode 100644
index 000000000..3f9e9f66b
--- /dev/null
+++ b/thirdparty/qtkeychain/QtKeychainBuildTreeSettings.cmake.in
@@ -0,0 +1,4 @@
+set(QTKEYCHAIN_INCLUDE_DIRS
+ "@PROJECT_SOURCE_DIR@"
+ "@PROJECT_BINARY_DIR@"
+)
diff --git a/thirdparty/qtkeychain/QtKeychainConfig.cmake.in b/thirdparty/qtkeychain/QtKeychainConfig.cmake.in
new file mode 100644
index 000000000..dff5802ae
--- /dev/null
+++ b/thirdparty/qtkeychain/QtKeychainConfig.cmake.in
@@ -0,0 +1,20 @@
+# - Config file for the FooBar package
+# It defines the following variables
+# FOOBAR_INCLUDE_DIRS - include directories for FooBar
+# FOOBAR_LIBRARIES - libraries to link against
+# FOOBAR_EXECUTABLE - the bar executable
+
+# Compute paths
+get_filename_component(QTKEYCHAIN_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+if(EXISTS "${QTKEYCHAIN_CMAKE_DIR}/CMakeCache.txt")
+ # In build tree
+ include("${QTKEYCHAIN_CMAKE_DIR}/QtKeychainBuildTreeSettings.cmake")
+else()
+ set(QTKEYCHAIN_INCLUDE_DIRS "${QTKEYCHAIN_CMAKE_DIR}/../../")
+endif()
+
+# Our library dependencies (contains definitions for IMPORTED targets)
+include("${QTKEYCHAIN_CMAKE_DIR}/QtKeychainLibraryDepends.cmake")
+
+# These are IMPORTED targets created by FooBarLibraryDepends.cmake
+set(QTKEYCHAIN_LIBRARIES qtkeychain)
diff --git a/thirdparty/qtkeychain/QtKeychainConfigVersion.cmake.in b/thirdparty/qtkeychain/QtKeychainConfigVersion.cmake.in
new file mode 100644
index 000000000..fba821a64
--- /dev/null
+++ b/thirdparty/qtkeychain/QtKeychainConfigVersion.cmake.in
@@ -0,0 +1,11 @@
+set(PACKAGE_VERSION "@QTKEYCHAIN_VERSION@")
+
+# Check whether the requested PACKAGE_FIND_VERSION is compatible
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/thirdparty/qtkeychain/ReadMe.markdown b/thirdparty/qtkeychain/ReadMe.markdown
new file mode 120000
index 000000000..3cefeef2e
--- /dev/null
+++ b/thirdparty/qtkeychain/ReadMe.markdown
@@ -0,0 +1 @@
+ReadMe.txt
\ No newline at end of file
diff --git a/thirdparty/qtkeychain/ReadMe.txt b/thirdparty/qtkeychain/ReadMe.txt
new file mode 100644
index 000000000..b6388f267
--- /dev/null
+++ b/thirdparty/qtkeychain/ReadMe.txt
@@ -0,0 +1,16 @@
+QtKeychain
+==========
+
+QtKeychain is a Qt API to store passwords and other secret data securely. How the data is stored depends on the platform:
+
+ * **Mac OS X:** Passwords are stored in the OS X Keychain.
+
+ * **Linux/Unix:** If running, KWallet (via D-Bus) is used.
+Support for the GNOME Keyring via freedesktop.org's
+[Secret Storage D-Bus specification](http://freedesktop.org/wiki/Specifications/secret-storage-spec "Secret Storage specification") is planned but not yet implemented.
+
+ * **Windows:** Windows does not provide a service for secure storage. QtKeychain uses the Windows API function [CryptProtectData](http://msdn.microsoft.com/en-us/library/windows/desktop/aa380261%28v=vs.85%29.aspx "CryptProtectData function") to encrypt the password with the user's logon credentials. The encrypted data is then persisted via QSettings.
+
+In unsupported environments QtKeychain will report an error. It will never store any data unencrypted.
+
+**License:** QtKeychain is available under the [Modified BSD License](http://www.gnu.org/licenses/license-list.html#ModifiedBSD). See the file COPYING for details.
diff --git a/thirdparty/qtkeychain/cmake/Modules/GNUInstallDirs.cmake b/thirdparty/qtkeychain/cmake/Modules/GNUInstallDirs.cmake
new file mode 100644
index 000000000..0302e4bef
--- /dev/null
+++ b/thirdparty/qtkeychain/cmake/Modules/GNUInstallDirs.cmake
@@ -0,0 +1,188 @@
+# - Define GNU standard installation directories
+# Provides install directory variables as defined for GNU software:
+# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
+# Inclusion of this module defines the following variables:
+# CMAKE_INSTALL_
- destination for files of a given type
+# CMAKE_INSTALL_FULL_ - corresponding absolute path
+# where is one of:
+# BINDIR - user executables (bin)
+# SBINDIR - system admin executables (sbin)
+# LIBEXECDIR - program executables (libexec)
+# SYSCONFDIR - read-only single-machine data (etc)
+# SHAREDSTATEDIR - modifiable architecture-independent data (com)
+# LOCALSTATEDIR - modifiable single-machine data (var)
+# LIBDIR - object code libraries (lib or lib64 or lib/ on Debian)
+# INCLUDEDIR - C header files (include)
+# OLDINCLUDEDIR - C header files for non-gcc (/usr/include)
+# DATAROOTDIR - read-only architecture-independent data root (share)
+# DATADIR - read-only architecture-independent data (DATAROOTDIR)
+# INFODIR - info documentation (DATAROOTDIR/info)
+# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale)
+# MANDIR - man documentation (DATAROOTDIR/man)
+# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME)
+# Each CMAKE_INSTALL_ value may be passed to the DESTINATION options of
+# install() commands for the corresponding file type. If the includer does
+# not define a value the above-shown default will be used and the value will
+# appear in the cache for editing by the user.
+# Each CMAKE_INSTALL_FULL_ value contains an absolute path constructed
+# from the corresponding destination by prepending (if necessary) the value
+# of CMAKE_INSTALL_PREFIX.
+
+#=============================================================================
+# Copyright 2011 Nikita Krupen'ko
+# Copyright 2011 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+# Installation directories
+#
+if(NOT DEFINED CMAKE_INSTALL_BINDIR)
+ set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_SBINDIR)
+ set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR)
+ set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR)
+ set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR)
+ set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR)
+ set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
+ set(_LIBDIR_DEFAULT "lib")
+ # Override this default 'lib' with 'lib64' iff:
+ # - we are on Linux system but NOT cross-compiling
+ # - we are NOT on debian
+ # - we are on a 64 bits system
+ # reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf
+ # For Debian with multiarch, use 'lib/${CMAKE_LIBRARY_ARCHITECTURE}' if
+ # CMAKE_LIBRARY_ARCHITECTURE is set (which contains e.g. "i386-linux-gnu"
+ # See http://wiki.debian.org/Multiarch
+ if(CMAKE_SYSTEM_NAME MATCHES "Linux"
+ AND NOT CMAKE_CROSSCOMPILING)
+ if (EXISTS "/etc/debian_version") # is this a debian system ?
+ if(CMAKE_LIBRARY_ARCHITECTURE)
+ set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
+ endif()
+ else() # not debian, rely on CMAKE_SIZEOF_VOID_P:
+ if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
+ message(AUTHOR_WARNING
+ "Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
+ "Please enable at least one language before including GNUInstallDirs.")
+ else()
+ if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
+ set(_LIBDIR_DEFAULT "lib64")
+ endif()
+ endif()
+ endif()
+ endif()
+ set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
+ set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR)
+ set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)")
+endif()
+
+if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR)
+ set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)")
+endif()
+
+#-----------------------------------------------------------------------------
+# Values whose defaults are relative to DATAROOTDIR. Store empty values in
+# the cache and store the defaults in local variables if the cache values are
+# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes.
+
+if(NOT CMAKE_INSTALL_DATADIR)
+ set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)")
+ set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}")
+endif()
+
+if(NOT CMAKE_INSTALL_INFODIR)
+ set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)")
+ set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info")
+endif()
+
+if(NOT CMAKE_INSTALL_LOCALEDIR)
+ set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)")
+ set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale")
+endif()
+
+if(NOT CMAKE_INSTALL_MANDIR)
+ set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)")
+ set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man")
+endif()
+
+if(NOT CMAKE_INSTALL_DOCDIR)
+ set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)")
+ set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}")
+endif()
+
+#-----------------------------------------------------------------------------
+
+mark_as_advanced(
+ CMAKE_INSTALL_BINDIR
+ CMAKE_INSTALL_SBINDIR
+ CMAKE_INSTALL_LIBEXECDIR
+ CMAKE_INSTALL_SYSCONFDIR
+ CMAKE_INSTALL_SHAREDSTATEDIR
+ CMAKE_INSTALL_LOCALSTATEDIR
+ CMAKE_INSTALL_LIBDIR
+ CMAKE_INSTALL_INCLUDEDIR
+ CMAKE_INSTALL_OLDINCLUDEDIR
+ CMAKE_INSTALL_DATAROOTDIR
+ CMAKE_INSTALL_DATADIR
+ CMAKE_INSTALL_INFODIR
+ CMAKE_INSTALL_LOCALEDIR
+ CMAKE_INSTALL_MANDIR
+ CMAKE_INSTALL_DOCDIR
+ )
+
+# Result directories
+#
+foreach(dir
+ BINDIR
+ SBINDIR
+ LIBEXECDIR
+ SYSCONFDIR
+ SHAREDSTATEDIR
+ LOCALSTATEDIR
+ LIBDIR
+ INCLUDEDIR
+ OLDINCLUDEDIR
+ DATAROOTDIR
+ DATADIR
+ INFODIR
+ LOCALEDIR
+ MANDIR
+ DOCDIR
+ )
+ if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}})
+ set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}")
+ else()
+ set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}")
+ endif()
+endforeach()
diff --git a/thirdparty/qtkeychain/keychain.cpp b/thirdparty/qtkeychain/keychain.cpp
new file mode 100644
index 000000000..4080537c4
--- /dev/null
+++ b/thirdparty/qtkeychain/keychain.cpp
@@ -0,0 +1,173 @@
+/******************************************************************************
+ * Copyright (C) 2011 Frank Osterfeld *
+ * *
+ * This program 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. For licensing and distribution *
+ * details, check the accompanying file 'COPYING'. *
+ *****************************************************************************/
+#include "keychain.h"
+#include "keychain_p.h"
+
+using namespace QKeychain;
+
+Job::Job( const QString& service, QObject *parent )
+ : QObject( parent )
+ , d ( new Private( service ) ) {
+}
+
+Job::~Job() {
+ delete d;
+}
+
+QString Job::service() const {
+ return d->service;
+}
+
+QSettings* Job::settings() const {
+ return d->settings;
+}
+
+void Job::setSettings( QSettings* settings ) {
+ d->settings = settings;
+}
+
+void Job::start() {
+ QMetaObject::invokeMethod( this, "doStart", Qt::QueuedConnection );
+}
+
+bool Job::autoDelete() const {
+ return d->autoDelete;
+}
+
+void Job::setAutoDelete( bool autoDelete ) {
+ d->autoDelete = autoDelete;
+}
+
+bool Job::insecureFallback() const {
+ return d->insecureFallback;
+}
+
+void Job::setInsecureFallback( bool insecureFallback ) {
+ d->insecureFallback = insecureFallback;
+}
+
+void Job::emitFinished() {
+ emit finished( this );
+ if ( d->autoDelete )
+ deleteLater();
+}
+
+void Job::emitFinishedWithError( Error error, const QString& errorString ) {
+ d->error = error;
+ d->errorString = errorString;
+ emitFinished();
+}
+
+Error Job::error() const {
+ return d->error;
+}
+
+QString Job::errorString() const {
+ return d->errorString;
+}
+
+void Job::setError( Error error ) {
+ d->error = error;
+}
+
+void Job::setErrorString( const QString& errorString ) {
+ d->errorString = errorString;
+}
+
+ReadPasswordJob::ReadPasswordJob( const QString& service, QObject* parent )
+ : Job( service, parent )
+ , d( new Private( this ) )
+{}
+
+ReadPasswordJob::~ReadPasswordJob() {
+ delete d;
+}
+
+QString ReadPasswordJob::textData() const {
+ return QString::fromUtf8( d->data );
+}
+
+QByteArray ReadPasswordJob::binaryData() const {
+ return d->data;
+}
+
+QString ReadPasswordJob::key() const {
+ return d->key;
+}
+
+void ReadPasswordJob::setKey( const QString& key ) {
+ d->key = key;
+}
+
+void ReadPasswordJob::doStart() {
+ d->doStart();
+}
+
+WritePasswordJob::WritePasswordJob( const QString& service, QObject* parent )
+ : Job( service, parent )
+ , d( new Private( this ) ) {
+}
+
+WritePasswordJob::~WritePasswordJob() {
+ delete d;
+}
+
+QString WritePasswordJob::key() const {
+ return d->key;
+}
+
+void WritePasswordJob::setKey( const QString& key ) {
+ d->key = key;
+}
+
+void WritePasswordJob::setBinaryData( const QByteArray& data ) {
+ d->binaryData = data;
+ d->mode = Private::Binary;
+}
+
+void WritePasswordJob::setTextData( const QString& data ) {
+ d->textData = data;
+ d->mode = Private::Text;
+}
+
+void WritePasswordJob::doStart() {
+ d->doStart();
+}
+
+DeletePasswordJob::DeletePasswordJob( const QString& service, QObject* parent )
+ : Job( service, parent )
+ , d( new Private( this ) ) {
+}
+
+DeletePasswordJob::~DeletePasswordJob() {
+ delete d;
+}
+
+void DeletePasswordJob::doStart() {
+ //Internally, to delete a password we just execute a write job with no data set (null byte array).
+ //In all current implementations, this deletes the entry so this is sufficient
+ WritePasswordJob* job = new WritePasswordJob( service(), this );
+ connect( job, SIGNAL(finished(QKeychain::Job*)), d, SLOT(jobFinished(QKeychain::Job*)) );
+ job->setKey( d->key );
+ job->start();
+}
+
+QString DeletePasswordJob::key() const {
+ return d->key;
+}
+
+void DeletePasswordJob::setKey( const QString& key ) {
+ d->key = key;
+}
+
+void DeletePasswordJob::Private::jobFinished( Job* job ) {
+ q->setError( job->error() );
+ q->setErrorString( job->errorString() );
+ q->emitFinished();
+}
diff --git a/thirdparty/qtkeychain/keychain.h b/thirdparty/qtkeychain/keychain.h
new file mode 100644
index 000000000..6b08a6537
--- /dev/null
+++ b/thirdparty/qtkeychain/keychain.h
@@ -0,0 +1,132 @@
+/******************************************************************************
+ * Copyright (C) 2011 Frank Osterfeld *
+ * *
+ * This program 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. For licensing and distribution *
+ * details, check the accompanying file 'COPYING'. *
+ *****************************************************************************/
+#ifndef KEYCHAIN_H
+#define KEYCHAIN_H
+
+#include "qkeychain_export.h"
+
+#include
+#include
+
+class QSettings;
+
+namespace QKeychain {
+
+/**
+ * Error codes
+ */
+enum Error {
+ NoError=0, /**< No error occurred, operation was successful */
+ EntryNotFound, /**< For the given key no data was found */
+ CouldNotDeleteEntry, /**< Could not delete existing secret data */
+ AccessDeniedByUser, /**< User denied access to keychain */
+ AccessDenied, /**< Access denied for other reasons */
+ NoBackendAvailable, /**< No platform-specific keychain service available */
+ NotImplemented, /**< Not implemented on platform */
+ OtherError /**< Something else went wrong (errorString() might provide details) */
+};
+
+class QKEYCHAIN_EXPORT Job : public QObject {
+ Q_OBJECT
+public:
+ explicit Job( const QString& service, QObject* parent=0 );
+ ~Job();
+
+ QSettings* settings() const;
+ void setSettings( QSettings* settings );
+
+ void start();
+
+ QString service() const;
+
+ Error error() const;
+ QString errorString() const;
+
+ bool autoDelete() const;
+ void setAutoDelete( bool autoDelete );
+
+ bool insecureFallback() const;
+ void setInsecureFallback( bool insecureFallback );
+
+Q_SIGNALS:
+ void finished( QKeychain::Job* );
+
+protected:
+ Q_INVOKABLE virtual void doStart() = 0;
+
+ void setError( Error error );
+ void setErrorString( const QString& errorString );
+ void emitFinished();
+ void emitFinishedWithError(Error, const QString& errorString);
+
+private:
+ class Private;
+ Private* const d;
+};
+
+class QKEYCHAIN_EXPORT ReadPasswordJob : public Job {
+ Q_OBJECT
+public:
+ explicit ReadPasswordJob( const QString& service, QObject* parent=0 );
+ ~ReadPasswordJob();
+
+ QString key() const;
+ void setKey( const QString& key );
+
+ QByteArray binaryData() const;
+ QString textData() const;
+
+protected:
+ void doStart();
+
+private:
+ class Private;
+ Private* const d;
+};
+
+class QKEYCHAIN_EXPORT WritePasswordJob : public Job {
+ Q_OBJECT
+public:
+ explicit WritePasswordJob( const QString& service, QObject* parent=0 );
+ ~WritePasswordJob();
+
+ QString key() const;
+ void setKey( const QString& key );
+
+ void setBinaryData( const QByteArray& data );
+ void setTextData( const QString& data );
+
+protected:
+ void doStart();
+
+private:
+ class Private;
+ Private* const d;
+};
+
+class QKEYCHAIN_EXPORT DeletePasswordJob : public Job {
+ Q_OBJECT
+public:
+ explicit DeletePasswordJob( const QString& service, QObject* parent=0 );
+ ~DeletePasswordJob();
+
+ QString key() const;
+ void setKey( const QString& key );
+
+protected:
+ void doStart();
+
+private:
+ class Private;
+ Private* const d;
+};
+
+} // namespace QtKeychain
+
+#endif
diff --git a/thirdparty/qtkeychain/keychain_dbus.cpp b/thirdparty/qtkeychain/keychain_dbus.cpp
new file mode 100644
index 000000000..93c79f0f6
--- /dev/null
+++ b/thirdparty/qtkeychain/keychain_dbus.cpp
@@ -0,0 +1,160 @@
+/******************************************************************************
+ * Copyright (C) 2011 Frank Osterfeld *
+ * *
+ * This program 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. For licensing and distribution *
+ * details, check the accompanying file 'COPYING'. *
+ *****************************************************************************/
+#include "keychain_p.h"
+
+#include
+
+#include
+
+using namespace QKeychain;
+
+void ReadPasswordJob::Private::doStart() {
+ iface = new org::kde::KWallet( QLatin1String("org.kde.kwalletd"), QLatin1String("/modules/kwalletd"), QDBusConnection::sessionBus(), this );
+ const QDBusPendingReply reply = iface->open( QLatin1String("kdewallet"), 0, q->service() );
+ QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher( reply, this );
+ connect( watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletOpenFinished(QDBusPendingCallWatcher*)) );
+}
+
+void ReadPasswordJob::Private::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
+ watcher->deleteLater();
+ const QDBusPendingReply reply = *watcher;
+ if ( reply.isError() ) {
+ const QDBusError err = reply.error();
+
+ if ( q->insecureFallback() ) {
+ std::auto_ptr local( !q->settings() ? new QSettings( q->service() ) : 0 );
+ QSettings* actual = q->settings() ? q->settings() : local.get();
+
+ data = actual->value( key ).toByteArray();
+
+ q->emitFinished();
+ } else {
+ if ( err.type() == QDBusError::ServiceUnknown ) //KWalletd not running
+ q->emitFinishedWithError( NoBackendAvailable, tr("No keychain service available") );
+ else
+ q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
+
+ return;
+ }
+ }
+
+ walletHandle = reply.value();
+
+ if ( walletHandle < 0 ) {
+ q->emitFinishedWithError( AccessDenied, tr("Access to keychain denied") );
+ return;
+ }
+
+ const QDBusPendingReply nextReply = iface->entryType( walletHandle, q->service(), key, q->service() );
+ QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this );
+ connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletEntryTypeFinished(QDBusPendingCallWatcher*)) );
+}
+
+void ReadPasswordJob::Private::kwalletEntryTypeFinished( QDBusPendingCallWatcher* watcher ) {
+ watcher->deleteLater();
+ if ( watcher->isError() ) {
+ const QDBusError err = watcher->error();
+ q->emitFinishedWithError( OtherError, tr("Could not determine data type: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
+ return;
+ }
+
+ const QDBusPendingReply reply = *watcher;
+
+ dataType = reply.value() == 1/*Password*/ ? Text : Binary;
+
+ const QDBusPendingCall nextReply = dataType == Text
+ ? QDBusPendingCall( iface->readPassword( walletHandle, q->service(), key, q->service() ) )
+ : QDBusPendingCall( iface->readEntry( walletHandle, q->service(), key, q->service() ) );
+ QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this );
+ connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletReadFinished(QDBusPendingCallWatcher*)) );
+}
+
+void ReadPasswordJob::Private::kwalletReadFinished( QDBusPendingCallWatcher* watcher ) {
+ watcher->deleteLater();
+ if ( watcher->isError() ) {
+ const QDBusError err = watcher->error();
+ q->emitFinishedWithError( OtherError, tr("Could not read password: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
+ return;
+ }
+
+ if ( dataType == Binary ) {
+ QDBusPendingReply reply = *watcher;
+ data = reply.value();
+ } else {
+ QDBusPendingReply reply = *watcher;
+ data = reply.value().toUtf8();
+ }
+ q->emitFinished();
+}
+
+void WritePasswordJob::Private::doStart() {
+ iface = new org::kde::KWallet( QLatin1String("org.kde.kwalletd"), QLatin1String("/modules/kwalletd"), QDBusConnection::sessionBus(), this );
+ const QDBusPendingReply reply = iface->open( QLatin1String("kdewallet"), 0, q->service() );
+ QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher( reply, this );
+ connect( watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletOpenFinished(QDBusPendingCallWatcher*)) );
+}
+
+void WritePasswordJob::Private::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
+ watcher->deleteLater();
+ QDBusPendingReply reply = *watcher;
+ if ( reply.isError() ) {
+ if ( q->insecureFallback() ) {
+ std::auto_ptr local( !q->settings() ? new QSettings( q->service() ) : 0 );
+ QSettings* actual = q->settings() ? q->settings() : local.get();
+
+ if ( mode == Delete ) {
+ actual->remove( key );
+ actual->sync();
+
+ q->emitFinished();
+ return;
+ }
+ const QByteArray data = mode == Binary ? binaryData : textData.toUtf8();
+ actual->setValue( key, data );
+ actual->sync();
+
+ q->emitFinished();
+ } else {
+ const QDBusError err = reply.error();
+ q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
+ }
+ return;
+ }
+
+ const int handle = reply.value();
+
+ if ( handle < 0 ) {
+ q->emitFinishedWithError( AccessDenied, tr("Access to keychain denied") );
+ return;
+ }
+
+ QDBusPendingReply nextReply;
+
+ if ( !textData.isEmpty() )
+ nextReply = iface->writePassword( handle, q->service(), key, textData, q->service() );
+ else if ( !binaryData.isEmpty() )
+ nextReply = iface->writeEntry( handle, q->service(), key, binaryData, q->service() );
+ else
+ nextReply = iface->removeEntry( handle, q->service(), key, q->service() );
+
+ QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this );
+ connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletWriteFinished(QDBusPendingCallWatcher*)) );
+}
+
+void WritePasswordJob::Private::kwalletWriteFinished( QDBusPendingCallWatcher* watcher ) {
+ watcher->deleteLater();
+ QDBusPendingReply reply = *watcher;
+ if ( reply.isError() ) {
+ const QDBusError err = reply.error();
+ q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
+ return;
+ }
+
+ q->emitFinished();
+}
diff --git a/thirdparty/qtkeychain/keychain_mac.cpp b/thirdparty/qtkeychain/keychain_mac.cpp
new file mode 100644
index 000000000..d81ecf511
--- /dev/null
+++ b/thirdparty/qtkeychain/keychain_mac.cpp
@@ -0,0 +1,159 @@
+/******************************************************************************
+ * Copyright (C) 2011 Frank Osterfeld *
+ * *
+ * This program 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. For licensing and distribution *
+ * details, check the accompanying file 'COPYING'. *
+ *****************************************************************************/
+#include "keychain_p.h"
+
+#include
+#include
+#include
+
+using namespace QKeychain;
+
+template
+struct Releaser {
+ explicit Releaser( const T& v ) : value( v ) {}
+ ~Releaser() {
+ CFRelease( value );
+ }
+
+ const T value;
+};
+
+static QString strForStatus( OSStatus os ) {
+ const Releaser str( SecCopyErrorMessageString( os, 0 ) );
+ const char * const buf = CFStringGetCStringPtr( str.value, kCFStringEncodingUTF8 );
+ if ( !buf )
+ return QString();
+ return QString::fromUtf8( buf, strlen( buf ) );
+}
+
+static OSStatus readPw( QByteArray* pw,
+ const QString& service,
+ const QString& account,
+ SecKeychainItemRef* ref ) {
+ Q_ASSERT( pw );
+ pw->clear();
+ const QByteArray serviceData = service.toUtf8();
+ const QByteArray accountData = account.toUtf8();
+
+ void* data = 0;
+ UInt32 len = 0;
+
+ const OSStatus ret = SecKeychainFindGenericPassword( NULL, // default keychain
+ serviceData.size(),
+ serviceData.constData(),
+ accountData.size(),
+ accountData.constData(),
+ &len,
+ &data,
+ ref );
+ if ( ret == noErr ) {
+ *pw = QByteArray( reinterpret_cast( data ), len );
+ const OSStatus ret2 = SecKeychainItemFreeContent ( 0, data );
+ if ( ret2 != noErr )
+ qWarning() << "Could not free item content: " << strForStatus( ret2 );
+ }
+ return ret;
+}
+
+void ReadPasswordJob::Private::doStart()
+{
+ QString errorString;
+ Error error = NoError;
+ const OSStatus ret = readPw( &data, q->service(), q->key(), 0 );
+
+ switch ( ret ) {
+ case noErr:
+ break;
+ case errSecItemNotFound:
+ errorString = tr("Password not found");
+ error = EntryNotFound;
+ break;
+ default:
+ errorString = strForStatus( ret );
+ error = OtherError;
+ break;
+ }
+ q->emitFinishedWithError( error, errorString );
+}
+
+
+static QKeychain::Error deleteEntryImpl( const QString& service, const QString& account, QString* err ) {
+ SecKeychainItemRef ref;
+ QByteArray pw;
+ const OSStatus ret1 = readPw( &pw, service, account, &ref );
+ if ( ret1 == errSecItemNotFound )
+ return NoError; // No item stored, we're done
+ if ( ret1 != noErr ) {
+ *err = strForStatus( ret1 );
+ //TODO map error code, set errstr
+ return OtherError;
+ }
+ const Releaser releaser( ref );
+
+ const OSStatus ret2 = SecKeychainItemDelete( ref );
+
+ if ( ret2 == noErr )
+ return NoError;
+ //TODO map error code
+ *err = strForStatus( ret2 );
+ return CouldNotDeleteEntry;
+}
+
+static QKeychain::Error writeEntryImpl( const QString& service,
+ const QString& account,
+ const QByteArray& data,
+ QString* err ) {
+ Q_ASSERT( err );
+ err->clear();
+ const QByteArray serviceData = service.toUtf8();
+ const QByteArray accountData = account.toUtf8();
+ const OSStatus ret = SecKeychainAddGenericPassword( NULL, //default keychain
+ serviceData.size(),
+ serviceData.constData(),
+ accountData.size(),
+ accountData.constData(),
+ data.size(),
+ data.constData(),
+ NULL //item reference
+ );
+ if ( ret != noErr ) {
+ switch ( ret ) {
+ case errSecDuplicateItem:
+ {
+ Error derr = deleteEntryImpl( service, account, err );
+ if ( derr != NoError )
+ return CouldNotDeleteEntry;
+ else
+ return writeEntryImpl( service, account, data, err );
+ }
+ default:
+ *err = strForStatus( ret );
+ return OtherError;
+ }
+ }
+
+ return NoError;
+}
+
+void WritePasswordJob::Private::doStart()
+{
+ QString errorString;
+ Error error = NoError;
+
+ if ( mode == Delete ) {
+ const Error derr = deleteEntryImpl( q->service(), key, &errorString );
+ if ( derr != NoError )
+ error = CouldNotDeleteEntry;
+ q->emitFinishedWithError( error, errorString );
+ return;
+ }
+ const QByteArray data = mode == Text ? textData.toUtf8() : binaryData;
+ error = writeEntryImpl( q->service(), key, data, &errorString );
+ q->emitFinishedWithError( error, errorString );
+}
diff --git a/thirdparty/qtkeychain/keychain_p.h b/thirdparty/qtkeychain/keychain_p.h
new file mode 100644
index 000000000..726289703
--- /dev/null
+++ b/thirdparty/qtkeychain/keychain_p.h
@@ -0,0 +1,122 @@
+/******************************************************************************
+ * Copyright (C) 2011 Frank Osterfeld *
+ * *
+ * This program 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. For licensing and distribution *
+ * details, check the accompanying file 'COPYING'. *
+ *****************************************************************************/
+#ifndef KEYCHAIN_P_H
+#define KEYCHAIN_P_H
+
+#include
+#include
+#include
+#include
+
+#if defined(Q_OS_UNIX) && !defined(Q_WS_MAC)
+
+#include
+
+#include "kwallet_interface.h"
+#else
+
+class QDBusPendingCallWatcher;
+
+#endif
+
+#include "keychain.h"
+
+namespace QKeychain {
+
+class Job::Private : public QObject {
+ Q_OBJECT
+public:
+ Private( const QString& service_ )
+ : error( NoError )
+ , service( service_ )
+ , autoDelete( true )
+ , insecureFallback( false ) {}
+
+ QKeychain::Error error;
+ QString errorString;
+ QString service;
+ bool autoDelete;
+ bool insecureFallback;
+ QPointer settings;
+};
+
+class ReadPasswordJob::Private : public QObject {
+ Q_OBJECT
+public:
+ explicit Private( ReadPasswordJob* qq ) : q( qq ), walletHandle( 0 ), dataType( Text ) {}
+ void doStart();
+ ReadPasswordJob* const q;
+ QByteArray data;
+ QString key;
+ int walletHandle;
+ enum DataType {
+ Binary,
+ Text
+ };
+ DataType dataType;
+
+#if defined(Q_OS_UNIX) && !defined(Q_WS_MAC)
+ org::kde::KWallet* iface;
+
+private Q_SLOTS:
+ void kwalletOpenFinished( QDBusPendingCallWatcher* watcher );
+ void kwalletEntryTypeFinished( QDBusPendingCallWatcher* watcher );
+ void kwalletReadFinished( QDBusPendingCallWatcher* watcher );
+#else //moc's too dumb to respect above macros, so just define empty slot implementations
+private Q_SLOTS:
+ void kwalletOpenFinished( QDBusPendingCallWatcher* ) {}
+ void kwalletEntryTypeFinished( QDBusPendingCallWatcher* ) {}
+ void kwalletReadFinished( QDBusPendingCallWatcher* ) {}
+#endif
+
+};
+
+class WritePasswordJob::Private : public QObject {
+ Q_OBJECT
+public:
+ explicit Private( WritePasswordJob* qq ) : q( qq ), mode( Delete ) {}
+ void doStart();
+ enum Mode {
+ Delete,
+ Text,
+ Binary
+ };
+ WritePasswordJob* const q;
+ Mode mode;
+ QString key;
+ QByteArray binaryData;
+ QString textData;
+
+#if defined(Q_OS_UNIX) && !defined(Q_WS_MAC)
+ org::kde::KWallet* iface;
+
+private Q_SLOTS:
+ void kwalletOpenFinished( QDBusPendingCallWatcher* watcher );
+ void kwalletWriteFinished( QDBusPendingCallWatcher* watcher );
+#else
+private Q_SLOTS:
+ void kwalletOpenFinished( QDBusPendingCallWatcher* ) {}
+ void kwalletWriteFinished( QDBusPendingCallWatcher* ) {}
+#endif
+};
+
+class DeletePasswordJob::Private : public QObject {
+ Q_OBJECT
+public:
+ explicit Private( DeletePasswordJob* qq ) : q( qq ) {}
+ void doStart();
+ DeletePasswordJob* const q;
+ QString key;
+private Q_SLOTS:
+ void jobFinished( QKeychain::Job* );
+};
+
+}
+
+#endif // KEYCHAIN_P_H
diff --git a/thirdparty/qtkeychain/keychain_win.cpp b/thirdparty/qtkeychain/keychain_win.cpp
new file mode 100644
index 000000000..76b4116ab
--- /dev/null
+++ b/thirdparty/qtkeychain/keychain_win.cpp
@@ -0,0 +1,107 @@
+/******************************************************************************
+ * Copyright (C) 2011 Frank Osterfeld *
+ * *
+ * This program 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. For licensing and distribution *
+ * details, check the accompanying file 'COPYING'. *
+ *****************************************************************************/
+#include "keychain_p.h"
+
+#include
+
+#include
+#include
+
+#include
+
+using namespace QKeychain;
+
+void ReadPasswordJob::Private::doStart() {
+ //Use settings member if there, create local settings object if not
+ std::auto_ptr local( !q->settings() ? new QSettings( q->service() ) : 0 );
+ QSettings* actual = q->settings() ? q->settings() : local.get();
+
+ QByteArray encrypted = actual->value( key ).toByteArray();
+ if ( encrypted.isNull() ) {
+ q->emitFinishedWithError( EntryNotFound, tr("Entry not found") );
+ return;
+ }
+
+ DATA_BLOB blob_in, blob_out;
+
+ blob_in.pbData = reinterpret_cast( encrypted.data() );
+ blob_in.cbData = encrypted.size();
+
+ const BOOL ret = CryptUnprotectData( &blob_in,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ &blob_out );
+ if ( !ret ) {
+ q->emitFinishedWithError( OtherError, tr("Could not decrypt data") );
+ return;
+ }
+
+ data = QByteArray( reinterpret_cast( blob_out.pbData ), blob_out.cbData );
+ SecureZeroMemory( blob_out.pbData, blob_out.cbData );
+ LocalFree( blob_out.pbData );
+
+ q->emitFinished();
+}
+
+void WritePasswordJob::Private::doStart() {
+ if ( mode == Delete ) {
+ //Use settings member if there, create local settings object if not
+ std::auto_ptr local( !q->settings() ? new QSettings( q->service() ) : 0 );
+ QSettings* actual = q->settings() ? q->settings() : local.get();
+ actual->remove( key );
+ actual->sync();
+ if ( actual->status() != QSettings::NoError ) {
+ const QString err = actual->status() == QSettings::AccessError
+ ? tr("Could not delete encrypted data from settings: access error")
+ : tr("Could not delete encrypted data from settings: format error");
+ q->emitFinishedWithError( OtherError, err );
+ } else {
+ q->emitFinished();
+ }
+ return;
+ }
+
+ QByteArray data = mode == Binary ? binaryData : textData.toUtf8();
+ DATA_BLOB blob_in, blob_out;
+ blob_in.pbData = reinterpret_cast( data.data() );
+ blob_in.cbData = data.size();
+ const BOOL res = CryptProtectData( &blob_in,
+ L"QKeychain-encrypted data",
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ &blob_out );
+ if ( !res ) {
+ q->emitFinishedWithError( OtherError, tr("Encryption failed") ); //TODO more details available?
+ return;
+ }
+
+ const QByteArray encrypted( reinterpret_cast( blob_out.pbData ), blob_out.cbData );
+ LocalFree( blob_out.pbData );
+
+ //Use settings member if there, create local settings object if not
+ std::auto_ptr local( !q->settings() ? new QSettings( q->service() ) : 0 );
+ QSettings* actual = q->settings() ? q->settings() : local.get();
+ actual->setValue( key, encrypted );
+ actual->sync();
+ if ( actual->status() != QSettings::NoError ) {
+
+ const QString errorString = actual->status() == QSettings::AccessError
+ ? tr("Could not store encrypted data in settings: access error")
+ : tr("Could not store encrypted data in settings: format error");
+ q->emitFinishedWithError( OtherError, errorString );
+ return;
+ }
+
+ q->emitFinished();
+}
diff --git a/thirdparty/qtkeychain/org.kde.KWallet.xml b/thirdparty/qtkeychain/org.kde.KWallet.xml
new file mode 100644
index 000000000..548c2f82b
--- /dev/null
+++ b/thirdparty/qtkeychain/org.kde.KWallet.xml
@@ -0,0 +1,276 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/thirdparty/qtkeychain/qkeychain_export.h b/thirdparty/qtkeychain/qkeychain_export.h
new file mode 100644
index 000000000..1bb1669cb
--- /dev/null
+++ b/thirdparty/qtkeychain/qkeychain_export.h
@@ -0,0 +1,17 @@
+#ifndef QKEYCHAIN_EXPORT_H
+#define QKEYCHAIN_EXPORT_H
+
+#include
+
+# ifdef QKEYCHAIN_STATICLIB
+# undef QKEYCHAIN_SHAREDLIB
+# define QKEYCHAIN_EXPORT
+# else
+# ifdef QKEYCHAIN_BUILD_QKEYCHAIN_LIB
+# define QKEYCHAIN_EXPORT Q_DECL_EXPORT
+# else
+# define QKEYCHAIN_EXPORT Q_DECL_IMPORT
+# endif
+# endif
+
+#endif
diff --git a/thirdparty/qtkeychain/testclient.cpp b/thirdparty/qtkeychain/testclient.cpp
new file mode 100644
index 000000000..b38113073
--- /dev/null
+++ b/thirdparty/qtkeychain/testclient.cpp
@@ -0,0 +1,98 @@
+/******************************************************************************
+ * Copyright (C) 2011 Frank Osterfeld *
+ * *
+ * This program 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. For licensing and distribution *
+ * details, check the accompanying file 'COPYING'. *
+ *****************************************************************************/
+#include
+#include
+
+#include "keychain.h"
+#include
+
+using namespace QKeychain;
+
+static int printUsage() {
+ std::cerr << "testclient store " << std::endl;
+ std::cerr << "testclient restore " << std::endl;
+ std::cerr << "testclient delete " << std::endl;
+ return 1;
+}
+
+int main( int argc, char** argv ) {
+ QCoreApplication app( argc, argv );
+ const QStringList args = app.arguments();
+ if ( args.count() < 2 )
+ return printUsage();
+
+ QStringList::ConstIterator it = args.constBegin();
+ ++it;
+
+ if ( *it == QLatin1String("store") ) {
+ if ( ++it == args.constEnd() )
+ return printUsage();
+ const QString acc = *it;
+ if ( ++it == args.constEnd() )
+ return printUsage();
+ const QString pass = *it;
+ if ( ++it != args.constEnd() )
+ return printUsage();
+ WritePasswordJob job( QLatin1String("qtkeychain-testclient") );
+ job.setAutoDelete( false );
+ job.setKey( acc );
+ job.setTextData( pass );
+ QEventLoop loop;
+ job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()) );
+ job.start();
+ loop.exec();
+ if ( job.error() ) {
+ std::cerr << "Storing password failed: " << qPrintable(job.errorString()) << std::endl;
+ return 1;
+ }
+ std::cout << "Password stored successfully" << std::endl;
+ } else if ( *it == QLatin1String("restore") ) {
+ if ( ++it == args.constEnd() )
+ return printUsage();
+ const QString acc = *it;
+ if ( ++it != args.constEnd() )
+ return printUsage();
+ ReadPasswordJob job( QLatin1String("qtkeychain-testclient") );
+ job.setAutoDelete( false );
+ job.setKey( acc );
+ QEventLoop loop;
+ job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()) );
+ job.start();
+ loop.exec();
+
+ const QString pw = job.textData();
+ if ( job.error() ) {
+ std::cerr << "Restoring password failed: " << qPrintable(job.errorString()) << std::endl;
+ return 1;
+ }
+ std::cout << qPrintable(pw) << std::endl;
+ } else if ( *it == QLatin1String("delete") ) {
+ if ( ++it == args.constEnd() )
+ return printUsage();
+ const QString acc = *it;
+ if ( ++it != args.constEnd() )
+ return printUsage();
+ DeletePasswordJob job( QLatin1String("qtkeychain-testclient") );
+ job.setAutoDelete( false );
+ job.setKey( acc );
+ QEventLoop loop;
+ job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()) );
+ job.start();
+ loop.exec();
+
+ if ( job.error() ) {
+ std::cerr << "Deleting password failed: " << qPrintable(job.errorString()) << std::endl;
+ return 1;
+ }
+ std::cout << "Password deleted successfully" << std::endl;
+ } else {
+ return printUsage();
+ }
+}
+