aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/qtkeychain
diff options
context:
space:
mode:
authorMehdi Salem <mehdi.salem@qt.io>2023-09-29 18:10:44 +0200
committerMohammad Mehdi Salem Naraghi <mehdi.salem@qt.io>2023-10-02 14:32:02 +0000
commit4c746e79f0efb650b7616bcc4876228eeb4ffe59 (patch)
treeaccc0a6adbd933db67f4dce7431395c11d624485 /src/libs/3rdparty/qtkeychain
parentc74ed31d67671db0eac9c989a03c7605240a608e (diff)
integrate qtkeychain as 3rdparty lib
Change-Id: I1efe32cf4964d2c4de5205462aa4ade74eb0e3b8 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
Diffstat (limited to 'src/libs/3rdparty/qtkeychain')
-rw-r--r--src/libs/3rdparty/qtkeychain/CMakeLists.txt66
-rw-r--r--src/libs/3rdparty/qtkeychain/CMakeLists.txt.upstream198
-rw-r--r--src/libs/3rdparty/qtkeychain/COPYING23
-rw-r--r--src/libs/3rdparty/qtkeychain/ChangeLog109
-rw-r--r--src/libs/3rdparty/qtkeychain/QtKeychainConfig.cmake.in28
-rw-r--r--src/libs/3rdparty/qtkeychain/ReadMe.md29
-rw-r--r--src/libs/3rdparty/qtkeychain/cmake/Modules/ECMPackageConfigHelpers.cmake202
-rw-r--r--src/libs/3rdparty/qtkeychain/cmake/Modules/ECMQueryQt.cmake100
-rw-r--r--src/libs/3rdparty/qtkeychain/cmake/Modules/ECMSetupVersion.cmake202
-rw-r--r--src/libs/3rdparty/qtkeychain/cmake/Modules/QtVersionOption.cmake36
-rw-r--r--src/libs/3rdparty/qtkeychain/gnomekeyring.cpp86
-rw-r--r--src/libs/3rdparty/qtkeychain/gnomekeyring_p.h94
-rw-r--r--src/libs/3rdparty/qtkeychain/keychain.cpp235
-rw-r--r--src/libs/3rdparty/qtkeychain/keychain.h282
-rw-r--r--src/libs/3rdparty/qtkeychain/keychain_apple.mm263
-rw-r--r--src/libs/3rdparty/qtkeychain/keychain_p.h167
-rw-r--r--src/libs/3rdparty/qtkeychain/keychain_unix.cpp633
-rw-r--r--src/libs/3rdparty/qtkeychain/keychain_win.cpp193
-rw-r--r--src/libs/3rdparty/qtkeychain/libsecret.cpp349
-rw-r--r--src/libs/3rdparty/qtkeychain/libsecret_p.h33
-rw-r--r--src/libs/3rdparty/qtkeychain/org.kde.KWallet.xml276
-rw-r--r--src/libs/3rdparty/qtkeychain/plaintextstore.cpp110
-rw-r--r--src/libs/3rdparty/qtkeychain/plaintextstore_p.h47
-rw-r--r--src/libs/3rdparty/qtkeychain/qkeychain_export.h11
-rw-r--r--src/libs/3rdparty/qtkeychain/translations/qtkeychain_de.ts234
-rw-r--r--src/libs/3rdparty/qtkeychain/translations/qtkeychain_fr.ts226
-rw-r--r--src/libs/3rdparty/qtkeychain/translations/qtkeychain_nl.ts320
-rw-r--r--src/libs/3rdparty/qtkeychain/translations/qtkeychain_ro.ts235
-rw-r--r--src/libs/3rdparty/qtkeychain/translations/qtkeychain_ru.ts234
-rw-r--r--src/libs/3rdparty/qtkeychain/translations/qtkeychain_zh.ts234
-rw-r--r--src/libs/3rdparty/qtkeychain/translations/translations.qrc.in5
31 files changed, 5260 insertions, 0 deletions
diff --git a/src/libs/3rdparty/qtkeychain/CMakeLists.txt b/src/libs/3rdparty/qtkeychain/CMakeLists.txt
new file mode 100644
index 0000000000..d8ba7e3178
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/CMakeLists.txt
@@ -0,0 +1,66 @@
+add_qtc_library(qtkeychain
+ DEPENDS Qt::Core
+ SOURCES
+ keychain.cpp keychain.h
+ qkeychain_export.h
+ PROPERTIES
+ QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON
+)
+
+if (WIN32)
+ option(USE_CREDENTIAL_STORE "Build with windows CredentialStore support" ON)
+
+ extend_qtc_library(qtkeychain SOURCES keychain_win.cpp)
+
+ extend_qtc_library(qtkeychain
+ CONDITION USE_CREDENTIAL_STORE
+ FEATURE_INFO "CredentialStore keychain support"
+ DEFINES USE_CREDENTIAL_STORE=1
+ )
+ extend_qtc_library(qtkeychain
+ CONDITION NOT USE_CREDENTIAL_STORE
+ SOURCES plaintextstore.cpp
+ DEPENDS crypt32
+ )
+ endif()
+endif()
+
+extend_qtc_library(qtkeychain
+ CONDITION APPLE
+ SOURCES keychain_apple.mm
+ DEPENDS ${FWFoundation} ${FWSecurity}
+)
+
+if (UNIX AND NOT APPLE)
+ find_package(Qt6 COMPONENTS DBus REQUIRED)
+
+ option(LIBSECRET_SUPPORT "Build with libsecret support if available" ON)
+ if (LIBSECRET_SUPPORT)
+ find_package(PkgConfig REQUIRED)
+
+ include(FindPkgConfig)
+ pkg_check_modules(LIBSECRET libsecret-1)
+
+ extend_qtc_library(qtkeychain
+ CONDITION LIBSECRET_FOUND
+ FEATURE_INFO "libsecret keychain support"
+ DEFINES HAVE_LIBSECRET=1
+ INCLUDES ${LIBSECRET_INCLUDE_DIRS}
+ DEPENDS ${LIBSECRET_LIBRARIES}
+ )
+ endif()
+
+ qt6_add_dbus_interface(dbus_SOURCES
+ ${CMAKE_CURRENT_SOURCE_DIR}/org.kde.KWallet.xml kwallet_interface KWalletInterface)
+
+ extend_qtc_library(qtkeychain
+ DEFINES KEYCHAIN_DBUS=1
+ DEPENDS Qt::DBus
+ SOURCES
+ gnomekeyring.cpp
+ keychain_unix.cpp
+ libsecret.cpp
+ plaintextstore.cpp
+ ${dbus_SOURCES}
+ )
+endif()
diff --git a/src/libs/3rdparty/qtkeychain/CMakeLists.txt.upstream b/src/libs/3rdparty/qtkeychain/CMakeLists.txt.upstream
new file mode 100644
index 0000000000..3b4e30d129
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/CMakeLists.txt.upstream
@@ -0,0 +1,198 @@
+set(QTKEYCHAIN_VERSION 0.14.99)
+set(QTKEYCHAIN_SOVERSION 1)
+
+project(qtkeychain VERSION ${QTKEYCHAIN_VERSION} LANGUAGES CXX)
+
+include(FindPkgConfig)
+
+###
+
+set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${PROJECT_SOURCE_DIR}/cmake/Modules")
+include(GNUInstallDirs)
+include(GenerateExportHeader)
+include(CMakePackageConfigHelpers)
+include(ECMSetupVersion)
+include(CMakeDependentOption)
+
+option(BUILD_TRANSLATIONS "Build translations" ON)
+option(BUILD_SHARED_LIBS "Build dynamic library" OFF)
+
+CMAKE_DEPENDENT_OPTION(BUILD_TRANSLATIONS_AS_RESOURCES "Bundle translations with the library" OFF
+ "BUILD_TRANSLATIONS" OFF)
+
+if (WIN32)
+ option(USE_CREDENTIAL_STORE "Build with windows CredentialStore support" ON)
+
+ if (USE_CREDENTIAL_STORE)
+ add_definitions(-DUSE_CREDENTIAL_STORE=1)
+ endif()
+endif()
+
+
+find_package(Qt6 COMPONENTS Core REQUIRED)
+
+if(UNIX AND NOT APPLE)
+ find_package(Qt6 COMPONENTS DBus REQUIRED)
+ include_directories(${Qt6DBus_INCLUDE_DIRS})
+ set(QTDBUS_LIBRARIES ${Qt6DBus_LIBRARIES})
+endif()
+
+if(BUILD_TRANSLATIONS)
+ find_package(Qt6 COMPONENTS LinguistTools REQUIRED)
+endif()
+
+set(QTCORE_LIBRARIES ${Qt6Core_LIBRARIES})
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+list(APPEND qtkeychain_LIBRARIES ${QTCORE_LIBRARIES})
+set(qtkeychain_SOURCES
+ keychain.cpp
+ qkeychain_export.h
+ keychain.h
+)
+
+if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
+ # CMake < 3.15 sneaks in /W# flags for us, so we need a replacement,
+ # or we'll get a warning (cf. CMP0092)
+ if (CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
+ string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+ else()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
+ endif()
+else()
+ # MSVC's STL / Qt headers are not MSVC -Wall clean, so don't enable it there
+ add_definitions( -Wall -Werror=return-type )
+endif()
+
+if(WIN32)
+ list(APPEND qtkeychain_SOURCES keychain_win.cpp)
+ if (NOT USE_CREDENTIAL_STORE)
+ list(APPEND qtkeychain_LIBRARIES crypt32)
+ list(APPEND qtkeychain_SOURCES plaintextstore.cpp)
+ endif()
+ #FIXME: mingw bug; otherwise getting undefined refs to RtlSecureZeroMemory there
+ if(MINGW)
+ add_definitions( -O2 )
+ endif()
+endif()
+
+if(APPLE)
+ list(APPEND qtkeychain_SOURCES keychain_apple.mm)
+ list(APPEND qtkeychain_LIBRARIES "-framework Foundation" "-framework Security")
+endif()
+
+if(UNIX AND NOT APPLE)
+ option(LIBSECRET_SUPPORT "Build with libsecret support if available" ON)
+ find_package(PkgConfig REQUIRED)
+ pkg_check_modules(LIBSECRET libsecret-1)
+
+ if(LIBSECRET_SUPPORT AND LIBSECRET_FOUND)
+ add_definitions(-DHAVE_LIBSECRET=1)
+ INCLUDE_DIRECTORIES(${LIBSECRET_INCLUDE_DIRS})
+ LINK_DIRECTORIES(${LIBSECRET_LIBRARY_DIRS})
+ list(APPEND qtkeychain_LIBRARIES_PRIVATE ${LIBSECRET_LIBRARIES})
+ endif()
+
+ add_definitions(-DKEYCHAIN_DBUS=1)
+ list(APPEND qtkeychain_SOURCES keychain_unix.cpp gnomekeyring.cpp libsecret.cpp plaintextstore.cpp)
+ qt6_add_dbus_interface(qtkeychain_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/org.kde.KWallet.xml kwallet_interface KWalletInterface)
+ list(APPEND qtkeychain_LIBRARIES ${QTDBUS_LIBRARIES} )
+endif()
+
+qt6_wrap_cpp(qtkeychain_MOC_OUTFILES keychain.h keychain_p.h gnomekeyring_p.h)
+
+set(qtkeychain_TR_FILES
+ translations/qtkeychain_de.ts
+ translations/qtkeychain_fr.ts
+ translations/qtkeychain_ro.ts
+ translations/qtkeychain_ru.ts
+ translations/qtkeychain_zh.ts
+)
+
+set(QTKEYCHAIN_TARGET_NAME qtkeychain)
+add_library(${QTKEYCHAIN_TARGET_NAME} ${qtkeychain_SOURCES} ${qtkeychain_MOC_OUTFILES} ${qtkeychain_QM_FILES})
+if(WIN32)
+ set_target_properties( ${QTKEYCHAIN_TARGET_NAME} PROPERTIES DEBUG_POSTFIX "d" )
+endif()
+
+file(GLOB qtkeychain_TR_SOURCES *.cpp *.h *.ui)
+if ( BUILD_TRANSLATIONS )
+ qt6_create_translation(qtkeychain_MESSAGES ${qtkeychain_TR_SOURCES} ${qtkeychain_TR_FILES})
+ qt6_add_translation(qtkeychain_QM_FILES ${qtkeychain_TR_FILES})
+ add_custom_target(messages DEPENDS ${qtkeychain_MESSAGES})
+ add_custom_target(translations DEPENDS ${qtkeychain_QM_FILES} messages)
+ # https://github.com/frankosterfeld/qtkeychain/issues/185
+ add_dependencies(${QTKEYCHAIN_TARGET_NAME} translations)
+
+ if (BUILD_TRANSLATIONS_AS_RESOURCES)
+ set(QM_FILE_LIST "")
+ foreach(FILE ${qtkeychain_QM_FILES})
+ list(APPEND QM_FILE_LIST "<file>${FILE}</file>")
+ endforeach()
+ string(REPLACE ";" "" QM_FILE_LIST ${QM_FILE_LIST})
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/translations/translations.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
+ target_sources(${QTKEYCHAIN_TARGET_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
+ else()
+ set(QTKEYCHAIN_TRANSLATIONS_DIR
+ ${CMAKE_INSTALL_DATADIR}/qtkeychain/translations
+ CACHE PATH "The location of the QtKeychain translations" )
+ install(FILES ${qtkeychain_QM_FILES} DESTINATION ${QTKEYCHAIN_TRANSLATIONS_DIR})
+ endif()
+endif( BUILD_TRANSLATIONS )
+
+target_link_libraries(${QTKEYCHAIN_TARGET_NAME} PUBLIC ${qtkeychain_LIBRARIES} PRIVATE ${qtkeychain_LIBRARIES_PRIVATE})
+if(NOT INTERFACE_INCLUDE_SUFFIX)
+ set(INTERFACE_INCLUDE_SUFFIX include)
+endif()
+target_include_directories(${QTKEYCHAIN_TARGET_NAME} PUBLIC $<INSTALL_INTERFACE:${INTERFACE_INCLUDE_SUFFIX}/>)
+
+generate_export_header(${QTKEYCHAIN_TARGET_NAME}
+ EXPORT_FILE_NAME qkeychain_export.h
+ EXPORT_MACRO_NAME QKEYCHAIN_EXPORT
+)
+
+set_target_properties(${QTKEYCHAIN_TARGET_NAME} PROPERTIES
+ VERSION ${QTKEYCHAIN_VERSION}
+ SOVERSION ${QTKEYCHAIN_SOVERSION}
+ INSTALL_RPATH_USE_LINK_PATH TRUE
+)
+
+if (NOT APPLE)
+ set_target_properties(${QTKEYCHAIN_TARGET_NAME} PROPERTIES
+ INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}"
+ )
+endif()
+
+install(FILES keychain.h ${CMAKE_CURRENT_BINARY_DIR}/qkeychain_export.h
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/qtkeychain/
+)
+
+install(TARGETS ${QTKEYCHAIN_TARGET_NAME}
+ EXPORT QtKeychainLibraryDepends
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+###
+### CMake config file
+###
+
+configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/QtKeychainConfig.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/QtKeychainConfig.cmake"
+ INSTALL_DESTINATION QtKeychain)
+
+ecm_setup_version("${QTKEYCHAIN_VERSION}" VARIABLE_PREFIX SNORE
+ PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/QtKeychainConfigVersion.cmake"
+ SOVERSION ${QTKEYCHAIN_VERSION})
+
+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/src/libs/3rdparty/qtkeychain/COPYING b/src/libs/3rdparty/qtkeychain/COPYING
new file mode 100644
index 0000000000..69f70fff71
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/COPYING
@@ -0,0 +1,23 @@
+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.
+3. The name of the author may not be used to
+ endorse or promote products derived from this software without
+ specific prior written permission.
+
+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/src/libs/3rdparty/qtkeychain/ChangeLog b/src/libs/3rdparty/qtkeychain/ChangeLog
new file mode 100644
index 0000000000..cb383c5296
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/ChangeLog
@@ -0,0 +1,109 @@
+ChangeLog
+=========
+
+version 0.14.1 (release 2023-06-01)
+
+ - Export QKeychain::isAvailable() to make it usable in a shared build (Volker Krause <vkrause@kde.org>)
+ - Protect against creating the QtKeychain::QtKeychain alias target twice (Volker Krause <vkrause@kde.org>)
+
+version 0.14.0 (release 2023-05-12)
+
+ - Add Qt 6 Android support (Igor Bugaev <freedbrt@gmail.com>)
+ - Add QtQuick client example ((Igor Bugaev <freedbrt@gmail.com>)
+ - Added Dutch translation (Heimen Stoffels <vistausss@fastmail.com>)
+ - Fix potential freezing with Apple keychain (Claudio Cambra <developer@claudiocambra.com>)
+ - Add API to check whether a secure backend is available at all (Volker Krause <vkrause@kde.org>)
+
+version 0.13.2 (release 2021-11-18)
+
+ - CMake: Deprecate QTKEYCHAIN_STATIC in favor of BUILD_SHARED_LIBS (be@mixxx.org)
+
+version 0.13.1 (release 2021-11-08)
+
+ - KWallet: Fix deletion of entries (Issue #199)
+
+version 0.13.0 (release 2021-11-07)
+
+ - Linux: Require libsecret if not explicitly disabled
+ - Unify implementations for macOS and iOS
+ - CMake: lots of fixes
+
+version 0.12.0 (release 2020-12-16)
+
+ * Add Qt 6 support, drop Qt 4 support
+ * Require C++11
+ * Add Android support (Mathias Hasselmann)
+
+version 0.11.1 (release 2020-09-08)
+
+ * Build system fixes
+
+version 0.11.0 (release 2020-09-08)
+
+ * Important: Debug builds on Windows now get the "d" suffix
+ * Various build system fixes
+ * Add Haiku support (François Revol <revol@free.fr>)
+ * Translation: Russian (Alexander Gorishnyak <kefir500@gmail.com>)
+ * Translation: Update French (David Geiger <david.david@mageialinux-online.org>)
+
+version 0.10.0 (release 2019-12-17)
+
+ * Detect XFCE desktop correctly. (Sandro Knauß <hefee@debian.org>)
+ * Windows Use CRED_PERSIST_ENTERPRISE (Olivier Goffart <ogoffart@woboq.com>)
+ * Windows: Improve CredWrite() error handling (Christian Kamm <mail@ckamm.de>)
+ * Fix build with Qt 5.12.x (Sergey Ilinykh <rion4ik@gmail.com>)
+ * Fix Qt 4 build (Robert-André Mauchin <zebob.m@gmail.com>)
+ * Translation: Mandarin (Taiwan) (Poren Chiang <ren.chiang@gmail.com>)
+ * Translation: French (François Revol <revol@free.fr>)
+
+version 0.9.1 (release 2018-08-20)
+ * Windows Credential Store: Use CRED_PERSIST_ENTERPRISE (Olivier Goffart <ogoffart@woboq.com>)
+ * Secret: Don't match the schema name #114 (Christian Kamm <mail@ckamm.de>)
+ * Fix qmake build on Windows (Alexander Gorishnyak <kefir500@gmail.com>)
+
+version 0.9.0 (release 2018-07-13)
+ * Fall back on libsecret if kwallet is not available (Christian Kamm <mail@ckamm.de>)
+ * Only require QtLinguist if building translations (Victor Kropp <victor.kropp@jetbrains.com>)
+ * Fix building on Windows without credential store (Dmitry Ivanov <dm.vl.ivanov@gmail.com>)
+ * Fix Qt 4 build (Sandro Knauß <hefee@debian.org>)
+ * Make build of test application optional (Boris Pek <tehnick-8@yandex.ru>)
+
+version 0.8.0 (release 2017-04-19)
+ * Buildsystem improvements (Kristofer Tingdahl <kristofer.tingdahl@dgbes.com>, Hannah von Reth <hannah.vonreth@kdab.com>, Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>)
+ * Enable C++11 support for Qt >= 5.7 (Dmitry Ivanov <dm.vl.ivanov@gmail.com>)
+ * Doxygen documentation ( Elvis Angelaccio <elvis.angelaccio@kdemail.net>)
+ * Libsecret support (Armin Novak <armin.novak@thincast.com>)
+ * iOS support (Mathias Hasselmann <mathias.hasselmann@kdab.com>)
+
+version 0.7.0 (release 2016-05-23)
+ * Bump SO version due to 0.6 being binary-incompatible to previous releases
+
+version 0.6.2 (release 2016-04-04)
+ * KWallet: Fixes a crash when storing passwords, seen on Debian/KDE4
+
+version 0.6.1 (release 2016-03-31)
+ * Fix KWallet not working (regressions in 0.6.0)
+
+version 0.6.0 (release 2016-03-18)
+ * Added support for the Windows Credential Store
+
+version 0.5.0 (release 2015-05-04)
+ * Added support for KWallet5 (KDE5/KF)
+
+version 0.4.0 (release 2014-09-01)
+ * KWallet: Handle case where no wallet exists yet (Liviu Cristian Mirea Ghiban <contact@liviucmg.com>)
+ * Improved desktop environment detection at runtime (Daniel Molkentin <daniel@molkentin.de>)
+
+version 0.3.0 (release 2014-03-13)
+ * Gnome Keyring supported added (Francois Ferrand <thetypz@gmail.com>)
+ * Improved Qt 5 support
+ * KWallet: Distinguish empty passwords from non-existing entries
+ * KWallet: Do not use hardcoded wallet name
+ * German translation (Daniel Molkentin <daniel@molkentin.de>)
+ * Romanian translation (Arthur Țițeică <arthur@psw.ro>)
+
+version 0.2.0: no official release
+
+version 0.1.0 (release 2013-01-16)
+ * Initial release
+
diff --git a/src/libs/3rdparty/qtkeychain/QtKeychainConfig.cmake.in b/src/libs/3rdparty/qtkeychain/QtKeychainConfig.cmake.in
new file mode 100644
index 0000000000..084d45e57f
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/QtKeychainConfig.cmake.in
@@ -0,0 +1,28 @@
+# - Config file for the QtKeychain package
+# It defines the following variables
+# QTKEYCHAIN_INCLUDE_DIRS - include directories for QtKeychain
+# QTKEYCHAIN_LIBRARIES - libraries to link against
+# as well as the following imported targets
+# qt5keychain / qt6keychain
+# Qt5Keychain::Qt5Keychain / Qt6Keychain::Qt6Keychain
+
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/QtKeychainLibraryDepends.cmake")
+
+include(CMakeFindDependencyMacro)
+
+find_dependency(Qt6Core)
+
+if(UNIX AND NOT APPLE AND NOT ANDROID)
+ find_dependency(Qt6DBus)
+endif()
+
+set(QTKEYCHAIN_LIBRARIES "@QTKEYCHAIN_TARGET_NAME@")
+get_target_property(QTKEYCHAIN_INCLUDE_DIRS "@QTKEYCHAIN_TARGET_NAME@" INTERFACE_INCLUDE_DIRECTORIES)
+
+if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.18.0 AND NOT TARGET QtKeychain::QtKeychain)
+ add_library(QtKeychain::QtKeychain ALIAS qtkeychain)
+endif()
+
+check_required_components(QtKeychain)
diff --git a/src/libs/3rdparty/qtkeychain/ReadMe.md b/src/libs/3rdparty/qtkeychain/ReadMe.md
new file mode 100644
index 0000000000..cf0a2e1311
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/ReadMe.md
@@ -0,0 +1,29 @@
+QtKeychain
+==========
+
+QtKeychain is a Qt API to store passwords and other secret data securely. How the data is stored depends on the platform:
+
+ * **macOS:** Passwords are stored in the macOS Keychain.
+
+ * **Linux/Unix:** If running, GNOME Keyring is used, otherwise QtKeychain tries to use KWallet (via D-Bus), if available. Libsecret (common API for desktop-specific solutions)
+ is also supported.
+
+ * **Windows:** By default, the Windows Credential Store is used (requires Windows 7 or newer).
+Pass `-DUSE_CREDENTIAL_STORE=OFF` to cmake to disable it. If disabled, 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.
+
+ * **Android and iOS:** Passwords are stored in the Android keystore system and iOS keychain, respectively.
+
+In unsupported environments QtKeychain will report an error. It will not store any data unencrypted unless explicitly requested (`setInsecureFallback( true )`).
+
+
+Requirements
+------------
+
+QtKeychain 0.12 and newer supports Qt 5 and Qt 6 and requires a compiler with C++11 support. Older versions support Qt 4 and Qt 5.
+
+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/src/libs/3rdparty/qtkeychain/cmake/Modules/ECMPackageConfigHelpers.cmake b/src/libs/3rdparty/qtkeychain/cmake/Modules/ECMPackageConfigHelpers.cmake
new file mode 100644
index 0000000000..8d48772b70
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/cmake/Modules/ECMPackageConfigHelpers.cmake
@@ -0,0 +1,202 @@
+#.rst:
+# ECMPackageConfigHelpers
+# -----------------------
+#
+# Helper macros for generating CMake package config files.
+#
+# ``write_basic_package_version_file()`` is the same as the one provided by the
+# `CMakePackageConfigHelpers
+# <https://www.cmake.org/cmake/help/v2.8.12/cmake.html#module:CMakePackageConfigHelpers>`_
+# module in CMake; see that module's documentation for
+# more information.
+#
+# ::
+#
+# ecm_configure_package_config_file(<input> <output>
+# INSTALL_DESTINATION <path>
+# [PATH_VARS <var1> [<var2> [...]]
+# [NO_SET_AND_CHECK_MACRO]
+# [NO_CHECK_REQUIRED_COMPONENTS_MACRO])
+#
+#
+# This behaves in the same way as configure_package_config_file() from CMake
+# 2.8.12, except that it adds an extra helper macro: find_dependency(). It is
+# highly recommended that you read the `documentation for
+# CMakePackageConfigHelpers
+# <https://www.cmake.org/cmake/help/v2.8.12/cmake.html#module:CMakePackageConfigHelpers>`_
+# for more information, particularly with regard to the PATH_VARS argument.
+#
+# Note that there is no argument that will disable the find_dependency() macro;
+# if you do not require this macro, you should use
+# ``configure_package_config_file`` from the CMakePackageConfigHelpers module.
+#
+# CMake 3.0 includes a CMakeFindDependencyMacro module that provides the
+# find_dependency() macro (which you can ``include()`` in your package config
+# file), so this file is only useful for projects wishing to provide config
+# files that will work with CMake 2.8.12.
+#
+# Additional Config File Macros
+# =============================
+#
+# ::
+#
+# find_dependency(<dep> [<version> [EXACT]])
+#
+# find_dependency() should be used instead of find_package() to find package
+# dependencies. It forwards the correct parameters for EXACT, QUIET and
+# REQUIRED which were passed to the original find_package() call. It also sets
+# an informative diagnostic message if the dependency could not be found.
+#
+# Since pre-1.0.0.
+
+#=============================================================================
+# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kdemail.net>
+# SPDX-FileCopyrightText: 2013 Stephen Kelly <steveire@gmail.com>
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(${CMAKE_ROOT}/Modules/CMakePackageConfigHelpers.cmake)
+
+set(_ecm_package_config_helpers_included TRUE)
+
+if(NOT CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.13)
+ message(AUTHOR_WARNING "Your project already requires a version of CMake that includes the find_dependency macro via the CMakeFindDependencyMacro module. You should use CMakePackageConfigHelpers instead of ECMPackageConfigHelpers.")
+endif()
+
+function(ECM_CONFIGURE_PACKAGE_CONFIG_FILE _inputFile _outputFile)
+ set(options NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO)
+ set(oneValueArgs INSTALL_DESTINATION )
+ set(multiValueArgs PATH_VARS )
+
+ cmake_parse_arguments(CCF "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(CCF_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to CONFIGURE_PACKAGE_CONFIG_FILE(): \"${CCF_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if(NOT CCF_INSTALL_DESTINATION)
+ message(FATAL_ERROR "No INSTALL_DESTINATION given to CONFIGURE_PACKAGE_CONFIG_FILE()")
+ endif()
+
+ if(IS_ABSOLUTE "${CCF_INSTALL_DESTINATION}")
+ set(absInstallDir "${CCF_INSTALL_DESTINATION}")
+ else()
+ set(absInstallDir "${CMAKE_INSTALL_PREFIX}/${CCF_INSTALL_DESTINATION}")
+ endif()
+
+ file(RELATIVE_PATH PACKAGE_RELATIVE_PATH "${absInstallDir}" "${CMAKE_INSTALL_PREFIX}" )
+
+ foreach(var ${CCF_PATH_VARS})
+ if(NOT DEFINED ${var})
+ message(FATAL_ERROR "Variable ${var} does not exist")
+ else()
+ if(IS_ABSOLUTE "${${var}}")
+ string(REPLACE "${CMAKE_INSTALL_PREFIX}" "\${PACKAGE_PREFIX_DIR}"
+ PACKAGE_${var} "${${var}}")
+ else()
+ set(PACKAGE_${var} "\${PACKAGE_PREFIX_DIR}/${${var}}")
+ endif()
+ endif()
+ endforeach()
+
+ get_filename_component(inputFileName "${_inputFile}" NAME)
+
+ set(PACKAGE_INIT "
+####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() (ECM variant) #######
+####### Any changes to this file will be overwritten by the next CMake run #######
+####### The input file was ${inputFileName} #######
+
+get_filename_component(PACKAGE_PREFIX_DIR \"\${CMAKE_CURRENT_LIST_DIR}/${PACKAGE_RELATIVE_PATH}\" ABSOLUTE)
+")
+
+ if("${absInstallDir}" MATCHES "^(/usr)?/lib(64)?/.+")
+ # Handle "/usr move" symlinks created by some Linux distros.
+ set(PACKAGE_INIT "${PACKAGE_INIT}
+# Use original install prefix when loaded through a \"/usr move\"
+# cross-prefix symbolic link such as /lib -> /usr/lib.
+get_filename_component(_realCurr \"\${CMAKE_CURRENT_LIST_DIR}\" REALPATH)
+get_filename_component(_realOrig \"${absInstallDir}\" REALPATH)
+if(_realCurr STREQUAL _realOrig)
+ set(PACKAGE_PREFIX_DIR \"${CMAKE_INSTALL_PREFIX}\")
+endif()
+unset(_realOrig)
+unset(_realCurr)
+")
+ endif()
+
+ if(NOT CCF_NO_SET_AND_CHECK_MACRO)
+ set(PACKAGE_INIT "${PACKAGE_INIT}
+macro(set_and_check _var _file)
+ set(\${_var} \"\${_file}\")
+ if(NOT EXISTS \"\${_file}\")
+ message(FATAL_ERROR \"File or directory \${_file} referenced by variable \${_var} does not exist !\")
+ endif()
+endmacro()
+
+include(CMakeFindDependencyMacro OPTIONAL RESULT_VARIABLE _CMakeFindDependencyMacro_FOUND)
+
+if (NOT _CMakeFindDependencyMacro_FOUND)
+ macro(find_dependency dep)
+ if (NOT \${dep}_FOUND)
+
+ set(ecm_fd_version)
+ if (\${ARGC} GREATER 1)
+ set(ecm_fd_version \${ARGV1})
+ endif()
+ set(ecm_fd_exact_arg)
+ if(\${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION_EXACT)
+ set(ecm_fd_exact_arg EXACT)
+ endif()
+ set(ecm_fd_quiet_arg)
+ if(\${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
+ set(ecm_fd_quiet_arg QUIET)
+ endif()
+ set(ecm_fd_required_arg)
+ if(\${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
+ set(ecm_fd_required_arg REQUIRED)
+ endif()
+
+ find_package(\${dep} \${ecm_fd_version}
+ \${ecm_fd_exact_arg}
+ \${ecm_fd_quiet_arg}
+ \${ecm_fd_required_arg}
+ )
+
+ if (NOT \${dep}_FOUND)
+ set(\${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE \"\${CMAKE_FIND_PACKAGE_NAME} could not be found because dependency \${dep} could not be found.\")
+ set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND False)
+ return()
+ endif()
+
+ set(ecm_fd_version)
+ set(ecm_fd_required_arg)
+ set(ecm_fd_quiet_arg)
+ set(ecm_fd_exact_arg)
+ endif()
+ endmacro()
+endif()
+
+")
+ endif()
+
+
+ if(NOT CCF_NO_CHECK_REQUIRED_COMPONENTS_MACRO)
+ set(PACKAGE_INIT "${PACKAGE_INIT}
+macro(check_required_components _NAME)
+ foreach(comp \${\${_NAME}_FIND_COMPONENTS})
+ if(NOT \${_NAME}_\${comp}_FOUND)
+ if(\${_NAME}_FIND_REQUIRED_\${comp})
+ set(\${_NAME}_FOUND FALSE)
+ endif()
+ endif()
+ endforeach()
+endmacro()
+")
+ endif()
+
+ set(PACKAGE_INIT "${PACKAGE_INIT}
+####################################################################################")
+
+ configure_file("${_inputFile}" "${_outputFile}" @ONLY)
+
+endfunction()
diff --git a/src/libs/3rdparty/qtkeychain/cmake/Modules/ECMQueryQt.cmake b/src/libs/3rdparty/qtkeychain/cmake/Modules/ECMQueryQt.cmake
new file mode 100644
index 0000000000..98eb50089e
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/cmake/Modules/ECMQueryQt.cmake
@@ -0,0 +1,100 @@
+# SPDX-FileCopyrightText: 2014 Rohan Garg <rohan16garg@gmail.com>
+# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
+# SPDX-FileCopyrightText: 2014-2016 Aleix Pol <aleixpol@kde.org>
+# SPDX-FileCopyrightText: 2017 Friedrich W. H. Kossebau <kossebau@kde.org>
+# SPDX-FileCopyrightText: 2022 Ahmad Samir <a.samir78@gmail.com>
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#[=======================================================================[.rst:
+ECMQueryQt
+---------------
+This module can be used to query the installation paths used by Qt.
+
+For Qt5 this uses ``qmake``, and for Qt6 this used ``qtpaths`` (the latter has built-in
+support to query the paths of a target platform when cross-compiling).
+
+This module defines the following function:
+::
+
+ ecm_query_qt(<result_variable> <qt_variable> [TRY])
+
+Passing ``TRY`` will result in the method not making the build fail if the executable
+used for querying has not been found, but instead simply print a warning message and
+return an empty string.
+
+Example usage:
+
+.. code-block:: cmake
+
+ include(ECMQueryQt)
+ ecm_query_qt(bin_dir QT_INSTALL_BINS)
+
+If the call succeeds ``${bin_dir}`` will be set to ``<prefix>/path/to/bin/dir`` (e.g.
+``/usr/lib64/qt/bin/``).
+
+Since: 5.93
+#]=======================================================================]
+
+include(${CMAKE_CURRENT_LIST_DIR}/QtVersionOption.cmake)
+include(CheckLanguage)
+check_language(CXX)
+if (CMAKE_CXX_COMPILER)
+ # Enable the CXX language to let CMake look for config files in library dirs.
+ # See: https://gitlab.kitware.com/cmake/cmake/-/issues/23266
+ enable_language(CXX)
+endif()
+
+if (QT_MAJOR_VERSION STREQUAL "5")
+ # QUIET to accommodate the TRY option
+ find_package(Qt${QT_MAJOR_VERSION}Core QUIET)
+ if(TARGET Qt5::qmake)
+ get_target_property(_qmake_executable_default Qt5::qmake LOCATION)
+
+ set(QUERY_EXECUTABLE ${_qmake_executable_default}
+ CACHE FILEPATH "Location of the Qt5 qmake executable")
+ set(_exec_name_text "Qt5 qmake")
+ set(_cli_option "-query")
+ endif()
+elseif(QT_MAJOR_VERSION STREQUAL "6")
+ # QUIET to accommodate the TRY option
+ find_package(Qt6 COMPONENTS CoreTools QUIET CONFIG)
+ if (TARGET Qt6::qtpaths)
+ get_target_property(_qtpaths_executable Qt6::qtpaths LOCATION)
+
+ set(QUERY_EXECUTABLE ${_qtpaths_executable}
+ CACHE FILEPATH "Location of the Qt6 qtpaths executable")
+ set(_exec_name_text "Qt6 qtpaths")
+ set(_cli_option "--query")
+ endif()
+endif()
+
+function(ecm_query_qt result_variable qt_variable)
+ set(options TRY)
+ set(oneValueArgs)
+ set(multiValueArgs)
+
+ cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(NOT QUERY_EXECUTABLE)
+ if(ARGS_TRY)
+ set(${result_variable} "" PARENT_SCOPE)
+ message(STATUS "No ${_exec_name_text} executable found. Can't check ${qt_variable}")
+ return()
+ else()
+ message(FATAL_ERROR "No ${_exec_name_text} executable found. Can't check ${qt_variable} as required")
+ endif()
+ endif()
+ execute_process(
+ COMMAND ${QUERY_EXECUTABLE} ${_cli_option} "${qt_variable}"
+ RESULT_VARIABLE return_code
+ OUTPUT_VARIABLE output
+ )
+ if(return_code EQUAL 0)
+ string(STRIP "${output}" output)
+ file(TO_CMAKE_PATH "${output}" output_path)
+ set(${result_variable} "${output_path}" PARENT_SCOPE)
+ else()
+ message(WARNING "Failed call: ${_command} \"${qt_variable}\"")
+ message(FATAL_ERROR "${_exec_name_text} call failed: ${return_code}")
+ endif()
+endfunction()
diff --git a/src/libs/3rdparty/qtkeychain/cmake/Modules/ECMSetupVersion.cmake b/src/libs/3rdparty/qtkeychain/cmake/Modules/ECMSetupVersion.cmake
new file mode 100644
index 0000000000..65c1688ab0
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/cmake/Modules/ECMSetupVersion.cmake
@@ -0,0 +1,202 @@
+#.rst:
+# ECMSetupVersion
+# ---------------
+#
+# Handle library version information.
+#
+# ::
+#
+# ecm_setup_version(<version>
+# VARIABLE_PREFIX <prefix>
+# [SOVERSION <soversion>]
+# [VERSION_HEADER <filename>]
+# [PACKAGE_VERSION_FILE <filename> [COMPATIBILITY <compat>]] )
+#
+# This parses a version string and sets up a standard set of version variables.
+# It can optionally also create a C version header file and a CMake package
+# version file to install along with the library.
+#
+# If the ``<version>`` argument is of the form ``<major>.<minor>.<patch>``
+# (or ``<major>.<minor>.<patch>.<tweak>``), The following CMake variables are
+# set::
+#
+# <prefix>_VERSION_MAJOR - <major>
+# <prefix>_VERSION_MINOR - <minor>
+# <prefix>_VERSION_PATCH - <patch>
+# <prefix>_VERSION - <version>
+# <prefix>_VERSION_STRING - <version> (for compatibility: use <prefix>_VERSION instead)
+# <prefix>_SOVERSION - <soversion>, or <major> if SOVERSION was not given
+#
+# If CMake policy CMP0048 is not NEW, the following CMake variables will also
+# be set::
+#
+# PROJECT_VERSION_MAJOR - <major>
+# PROJECT_VERSION_MINOR - <minor>
+# PROJECT_VERSION_PATCH - <patch>
+# PROJECT_VERSION - <version>
+# PROJECT_VERSION_STRING - <version> (for compatibility: use PROJECT_VERSION instead)
+#
+# If the VERSION_HEADER option is used, a simple C header is generated with the
+# given filename. If filename is a relative path, it is interpreted as relative
+# to CMAKE_CURRENT_BINARY_DIR. The generated header contains the following
+# macros::
+#
+# <prefix>_VERSION_MAJOR - <major> as an integer
+# <prefix>_VERSION_MINOR - <minor> as an integer
+# <prefix>_VERSION_PATCH - <patch> as an integer
+# <prefix>_VERSION_STRING - <version> as a C string
+# <prefix>_VERSION - the version as an integer
+#
+# ``<prefix>_VERSION`` has ``<patch>`` in the bottom 8 bits, ``<minor>`` in the
+# next 8 bits and ``<major>`` in the remaining bits. Note that ``<patch>`` and
+# ``<minor>`` must be less than 256.
+#
+# If the PACKAGE_VERSION_FILE option is used, a simple CMake package version
+# file is created using the write_basic_package_version_file() macro provided by
+# CMake. It should be installed in the same location as the Config.cmake file of
+# the library so that it can be found by find_package(). If the filename is a
+# relative path, it is interpreted as relative to CMAKE_CURRENT_BINARY_DIR. The
+# optional COMPATIBILITY option is forwarded to
+# write_basic_package_version_file(), and defaults to AnyNewerVersion.
+#
+# If CMake policy CMP0048 is NEW, an alternative form of the command is
+# available::
+#
+# ecm_setup_version(PROJECT
+# [VARIABLE_PREFIX <prefix>]
+# [SOVERSION <soversion>]
+# [VERSION_HEADER <filename>]
+# [PACKAGE_VERSION_FILE <filename>] )
+#
+# This will use the version information set by the project() command.
+# VARIABLE_PREFIX defaults to the project name. Note that PROJECT must be the
+# first argument. In all other respects, it behaves like the other form of the
+# command.
+#
+# Since pre-1.0.0.
+#
+# COMPATIBILITY option available since 1.6.0.
+
+#=============================================================================
+# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
+# SPDX-FileCopyrightText: 2012 Alexander Neundorf <neundorf@kde.org>
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(CMakePackageConfigHelpers)
+
+# save the location of the header template while CMAKE_CURRENT_LIST_DIR
+# has the value we want
+set(_ECM_SETUP_VERSION_HEADER_TEMPLATE "${CMAKE_CURRENT_LIST_DIR}/ECMVersionHeader.h.in")
+
+function(ecm_setup_version _version)
+ set(options )
+ set(oneValueArgs VARIABLE_PREFIX SOVERSION VERSION_HEADER PACKAGE_VERSION_FILE COMPATIBILITY)
+ set(multiValueArgs )
+
+ cmake_parse_arguments(ESV "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ if(ESV_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to ECM_SETUP_VERSION(): \"${ESV_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ set(project_manages_version FALSE)
+ set(use_project_version FALSE)
+ # CMP0048 only exists in CMake 3.0.0 and later
+ if(CMAKE_VERSION VERSION_LESS 3.0.0)
+ set(project_version_policy "OLD")
+ else()
+ cmake_policy(GET CMP0048 project_version_policy)
+ endif()
+ if(project_version_policy STREQUAL "NEW")
+ set(project_manages_version TRUE)
+ if(_version STREQUAL "PROJECT")
+ set(use_project_version TRUE)
+ endif()
+ elseif(_version STREQUAL "PROJECT")
+ message(FATAL_ERROR "ecm_setup_version given PROJECT argument, but CMP0048 is not NEW")
+ endif()
+
+ set(should_set_prefixed_vars TRUE)
+ if(NOT ESV_VARIABLE_PREFIX)
+ if(use_project_version)
+ set(ESV_VARIABLE_PREFIX "${PROJECT_NAME}")
+ set(should_set_prefixed_vars FALSE)
+ else()
+ message(FATAL_ERROR "Required argument PREFIX missing in ECM_SETUP_VERSION() call")
+ endif()
+ endif()
+
+ if(use_project_version)
+ set(_version "${PROJECT_VERSION}")
+ set(_major "${PROJECT_VERSION_MAJOR}")
+ set(_minor "${PROJECT_VERSION_MINOR}")
+ set(_patch "${PROJECT_VERSION_PATCH}")
+ else()
+ string(REGEX REPLACE "^0*([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" _major "${_version}")
+ string(REGEX REPLACE "^[0-9]+\\.0*([0-9]+)\\.[0-9]+.*" "\\1" _minor "${_version}")
+ string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.0*([0-9]+).*" "\\1" _patch "${_version}")
+ endif()
+
+ if(NOT ESV_SOVERSION)
+ set(ESV_SOVERSION ${_major})
+ endif()
+
+ if(should_set_prefixed_vars)
+ set(${ESV_VARIABLE_PREFIX}_VERSION "${_version}")
+ set(${ESV_VARIABLE_PREFIX}_VERSION_MAJOR ${_major})
+ set(${ESV_VARIABLE_PREFIX}_VERSION_MINOR ${_minor})
+ set(${ESV_VARIABLE_PREFIX}_VERSION_PATCH ${_patch})
+ endif()
+
+ set(${ESV_VARIABLE_PREFIX}_SOVERSION ${ESV_SOVERSION})
+
+ if(NOT project_manages_version)
+ set(PROJECT_VERSION "${_version}")
+ set(PROJECT_VERSION_MAJOR "${_major}")
+ set(PROJECT_VERSION_MINOR "${_minor}")
+ set(PROJECT_VERSION_PATCH "${_patch}")
+ endif()
+
+ # compat
+ set(PROJECT_VERSION_STRING "${PROJECT_VERSION}")
+ set(${ESV_VARIABLE_PREFIX}_VERSION_STRING "${${ESV_VARIABLE_PREFIX}_VERSION}")
+
+ if(ESV_VERSION_HEADER)
+ set(HEADER_PREFIX "${ESV_VARIABLE_PREFIX}")
+ set(HEADER_VERSION "${_version}")
+ set(HEADER_VERSION_MAJOR "${_major}")
+ set(HEADER_VERSION_MINOR "${_minor}")
+ set(HEADER_VERSION_PATCH "${_patch}")
+ configure_file("${_ECM_SETUP_VERSION_HEADER_TEMPLATE}" "${ESV_VERSION_HEADER}")
+ endif()
+
+ if(ESV_PACKAGE_VERSION_FILE)
+ if(NOT ESV_COMPATIBILITY)
+ set(ESV_COMPATIBILITY AnyNewerVersion)
+ endif()
+ write_basic_package_version_file("${ESV_PACKAGE_VERSION_FILE}" VERSION ${_version} COMPATIBILITY ${ESV_COMPATIBILITY})
+ endif()
+
+ if(should_set_prefixed_vars)
+ set(${ESV_VARIABLE_PREFIX}_VERSION_MAJOR "${${ESV_VARIABLE_PREFIX}_VERSION_MAJOR}" PARENT_SCOPE)
+ set(${ESV_VARIABLE_PREFIX}_VERSION_MINOR "${${ESV_VARIABLE_PREFIX}_VERSION_MINOR}" PARENT_SCOPE)
+ set(${ESV_VARIABLE_PREFIX}_VERSION_PATCH "${${ESV_VARIABLE_PREFIX}_VERSION_PATCH}" PARENT_SCOPE)
+ set(${ESV_VARIABLE_PREFIX}_VERSION "${${ESV_VARIABLE_PREFIX}_VERSION}" PARENT_SCOPE)
+ endif()
+
+ # always set the soversion
+ set(${ESV_VARIABLE_PREFIX}_SOVERSION "${${ESV_VARIABLE_PREFIX}_SOVERSION}" PARENT_SCOPE)
+
+ if(NOT project_manages_version)
+ set(PROJECT_VERSION "${PROJECT_VERSION}" PARENT_SCOPE)
+ set(PROJECT_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}" PARENT_SCOPE)
+ set(PROJECT_VERSION_MINOR "${PROJECT_VERSION_MINOR}" PARENT_SCOPE)
+ set(PROJECT_VERSION_PATCH "${PROJECT_VERSION_PATCH}" PARENT_SCOPE)
+ endif()
+
+ # always set the compatibility variables
+ set(PROJECT_VERSION_STRING "${PROJECT_VERSION_STRING}" PARENT_SCOPE)
+ set(${ESV_VARIABLE_PREFIX}_VERSION_STRING "${${ESV_VARIABLE_PREFIX}_VERSION}" PARENT_SCOPE)
+
+endfunction()
diff --git a/src/libs/3rdparty/qtkeychain/cmake/Modules/QtVersionOption.cmake b/src/libs/3rdparty/qtkeychain/cmake/Modules/QtVersionOption.cmake
new file mode 100644
index 0000000000..ea37da22de
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/cmake/Modules/QtVersionOption.cmake
@@ -0,0 +1,36 @@
+# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+#[=======================================================================[.rst:
+QtVersionOption
+---------------
+
+Adds a build option to select the major Qt version if necessary,
+that is, if the major Qt version has not yet been determined otherwise
+(e.g. by a corresponding ``find_package()`` call).
+This module is typically included by other modules requiring knowledge
+about the major Qt version.
+
+``QT_MAJOR_VERSION`` is defined to either be "5" or "6".
+
+Since 5.82.0.
+#]=======================================================================]
+
+if (DEFINED QT_MAJOR_VERSION)
+ return()
+endif()
+
+if (TARGET Qt5::Core)
+ set(QT_MAJOR_VERSION 5)
+elseif (TARGET Qt6::Core)
+ set(QT_MAJOR_VERSION 6)
+else()
+ option(BUILD_WITH_QT6 "Build against Qt 6" OFF)
+
+ if (BUILD_WITH_QT6)
+ set(QT_MAJOR_VERSION 6)
+ else()
+ set(QT_MAJOR_VERSION 5)
+ endif()
+endif()
diff --git a/src/libs/3rdparty/qtkeychain/gnomekeyring.cpp b/src/libs/3rdparty/qtkeychain/gnomekeyring.cpp
new file mode 100644
index 0000000000..6347052dcb
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/gnomekeyring.cpp
@@ -0,0 +1,86 @@
+#include "gnomekeyring_p.h"
+
+const char* GnomeKeyring::GNOME_KEYRING_DEFAULT = nullptr;
+
+bool GnomeKeyring::isAvailable()
+{
+ const GnomeKeyring& keyring = instance();
+ return keyring.isLoaded() &&
+ keyring.NETWORK_PASSWORD &&
+ keyring.is_available &&
+ keyring.find_password &&
+ keyring.store_password &&
+ keyring.delete_password &&
+ keyring.is_available();
+}
+
+GnomeKeyring::gpointer GnomeKeyring::store_network_password(
+ const gchar* keyring,
+ const gchar* display_name,
+ const gchar* user,
+ const gchar* server,
+ const gchar* type,
+ const gchar* password,
+ OperationDoneCallback callback,
+ gpointer data,
+ GDestroyNotify destroy_data )
+{
+ if ( !isAvailable() )
+ return 0;
+ return instance().store_password( instance().NETWORK_PASSWORD,
+ keyring, display_name, password, callback,
+ data, destroy_data,
+ "user", user,
+ "server", server,
+ "type", type,
+ static_cast<char*>(0) );
+}
+
+GnomeKeyring::gpointer GnomeKeyring::find_network_password(
+ const gchar* user, const gchar* server, const gchar* type,
+ OperationGetStringCallback callback, gpointer data, GDestroyNotify destroy_data )
+{
+ if ( !isAvailable() )
+ return 0;
+
+ return instance().find_password( instance().NETWORK_PASSWORD,
+ callback, data, destroy_data,
+ "user", user, "server", server, "type", type,
+ static_cast<char*>(0) );
+}
+
+GnomeKeyring::gpointer GnomeKeyring::delete_network_password( const gchar* user,
+ const gchar* server,
+ OperationDoneCallback callback,
+ gpointer data,
+ GDestroyNotify destroy_data )
+{
+ if ( !isAvailable() )
+ return 0;
+ return instance().delete_password( instance().NETWORK_PASSWORD,
+ callback, data, destroy_data,
+ "user", user, "server", server, static_cast<char*>(0) );
+}
+
+GnomeKeyring::GnomeKeyring()
+ : QLibrary(QLatin1String("gnome-keyring"), 0)
+{
+ static const PasswordSchema schema = {
+ ITEM_NETWORK_PASSWORD,
+ {{ "user", ATTRIBUTE_TYPE_STRING },
+ { "server", ATTRIBUTE_TYPE_STRING },
+ { "type", ATTRIBUTE_TYPE_STRING },
+ { 0, static_cast<AttributeType>( 0 ) }}
+ };
+
+ NETWORK_PASSWORD = &schema;
+ is_available = reinterpret_cast<is_available_fn*>( resolve( "gnome_keyring_is_available" ) );
+ find_password = reinterpret_cast<find_password_fn*>( resolve( "gnome_keyring_find_password" ) );
+ store_password = reinterpret_cast<store_password_fn*>( resolve( "gnome_keyring_store_password" ) );
+ delete_password = reinterpret_cast<delete_password_fn*>( resolve( "gnome_keyring_delete_password" ) );
+}
+
+GnomeKeyring& GnomeKeyring::instance() {
+ static GnomeKeyring keyring;
+ return keyring;
+}
diff --git a/src/libs/3rdparty/qtkeychain/gnomekeyring_p.h b/src/libs/3rdparty/qtkeychain/gnomekeyring_p.h
new file mode 100644
index 0000000000..87c062c375
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/gnomekeyring_p.h
@@ -0,0 +1,94 @@
+#ifndef QTKEYCHAIN_GNOME_P_H
+#define QTKEYCHAIN_GNOME_P_H
+
+#include <QLibrary>
+
+class GnomeKeyring : private QLibrary {
+ Q_OBJECT
+
+public:
+ enum Result {
+ RESULT_OK,
+ RESULT_DENIED,
+ RESULT_NO_KEYRING_DAEMON,
+ RESULT_ALREADY_UNLOCKED,
+ RESULT_NO_SUCH_KEYRING,
+ RESULT_BAD_ARGUMENTS,
+ RESULT_IO_ERROR,
+ RESULT_CANCELLED,
+ RESULT_KEYRING_ALREADY_EXISTS,
+ RESULT_NO_MATCH
+ };
+
+ enum ItemType {
+ ITEM_GENERIC_SECRET = 0,
+ ITEM_NETWORK_PASSWORD,
+ ITEM_NOTE,
+ ITEM_CHAINED_KEYRING_PASSWORD,
+ ITEM_ENCRYPTION_KEY_PASSWORD,
+ ITEM_PK_STORAGE = 0x100
+ };
+
+ enum AttributeType {
+ ATTRIBUTE_TYPE_STRING,
+ ATTRIBUTE_TYPE_UINT32
+ };
+
+ typedef char gchar;
+ typedef void* gpointer;
+ typedef bool gboolean;
+ typedef struct {
+ ItemType item_type;
+ struct {
+ const gchar* name;
+ AttributeType type;
+ } attributes[32];
+ } PasswordSchema;
+
+ typedef void ( *OperationGetStringCallback )( Result result, bool binary,
+ const char* string, gpointer data );
+ typedef void ( *OperationDoneCallback )( Result result, gpointer data );
+ typedef void ( *GDestroyNotify )( gpointer data );
+
+ static const char* GNOME_KEYRING_DEFAULT;
+
+ static bool isAvailable();
+
+ static gpointer store_network_password( const gchar* keyring, const gchar* display_name,
+ const gchar* user, const gchar* server,
+ const gchar* type, const gchar* password,
+ OperationDoneCallback callback, gpointer data, GDestroyNotify destroy_data );
+
+ static gpointer find_network_password( const gchar* user, const gchar* server,
+ const gchar* type,
+ OperationGetStringCallback callback,
+ gpointer data, GDestroyNotify destroy_data );
+
+ static gpointer delete_network_password( const gchar* user, const gchar* server,
+ OperationDoneCallback callback, gpointer data, GDestroyNotify destroy_data );
+private:
+ GnomeKeyring();
+
+ static GnomeKeyring& instance();
+
+ const PasswordSchema* NETWORK_PASSWORD;
+ typedef gboolean ( is_available_fn )( void );
+ typedef gpointer ( store_password_fn )( const PasswordSchema* schema, const gchar* keyring,
+ const gchar* display_name, const gchar* password,
+ OperationDoneCallback callback, gpointer data, GDestroyNotify destroy_data,
+ ... );
+ typedef gpointer ( find_password_fn )( const PasswordSchema* schema,
+ OperationGetStringCallback callback, gpointer data, GDestroyNotify destroy_data,
+ ... );
+ typedef gpointer ( delete_password_fn )( const PasswordSchema* schema,
+ OperationDoneCallback callback, gpointer data, GDestroyNotify destroy_data,
+ ... );
+
+ is_available_fn* is_available;
+ find_password_fn* find_password;
+ store_password_fn* store_password;
+ delete_password_fn* delete_password;
+};
+
+
+#endif
diff --git a/src/libs/3rdparty/qtkeychain/keychain.cpp b/src/libs/3rdparty/qtkeychain/keychain.cpp
new file mode 100644
index 0000000000..90ee4eb502
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/keychain.cpp
@@ -0,0 +1,235 @@
+/******************************************************************************
+ * Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
+ * *
+ * 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( JobPrivate *q, QObject *parent )
+ : QObject( parent )
+ , d ( q ) {
+}
+
+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::doStart() {
+ JobExecutor::instance()->enqueue( this );
+}
+
+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();
+}
+
+void Job::scheduledStart() {
+ d->scheduledStart();
+}
+
+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( new ReadPasswordJobPrivate( service, this ), parent ) {
+
+}
+
+ReadPasswordJob::~ReadPasswordJob() {
+}
+
+QString ReadPasswordJob::textData() const {
+ return QString::fromUtf8( d->data );
+}
+
+QByteArray ReadPasswordJob::binaryData() const {
+ return d->data;
+}
+
+QString Job::key() const {
+ return d->key;
+}
+
+void Job::setKey( const QString& key_ ) {
+ d->key = key_;
+}
+
+WritePasswordJob::WritePasswordJob( const QString& service, QObject* parent )
+ : Job( new WritePasswordJobPrivate( service, this ), parent ) {
+}
+
+WritePasswordJob::~WritePasswordJob() {
+}
+
+void WritePasswordJob::setBinaryData( const QByteArray& data ) {
+ d->data = data;
+ d->mode = JobPrivate::Binary;
+}
+
+void WritePasswordJob::setTextData( const QString& data ) {
+ d->data = data.toUtf8();
+ d->mode = JobPrivate::Text;
+}
+
+DeletePasswordJob::DeletePasswordJob( const QString& service, QObject* parent )
+ : Job( new DeletePasswordJobPrivate( service, this ), parent ) {
+}
+
+DeletePasswordJob::~DeletePasswordJob() {
+}
+
+DeletePasswordJobPrivate::DeletePasswordJobPrivate(const QString &service_, DeletePasswordJob *qq) :
+ JobPrivate(service_, qq) {
+
+}
+
+JobExecutor::JobExecutor()
+ : QObject( 0 )
+ , m_jobRunning( false ) {
+}
+
+void JobExecutor::enqueue( Job* job ) {
+ m_queue.enqueue( job );
+ startNextIfNoneRunning();
+}
+
+void JobExecutor::startNextIfNoneRunning() {
+ if ( m_queue.isEmpty() || m_jobRunning )
+ return;
+ QPointer<Job> next;
+ while ( !next && !m_queue.isEmpty() ) {
+ next = m_queue.dequeue();
+ }
+ if ( next ) {
+ connect( next, SIGNAL(finished(QKeychain::Job*)), this, SLOT(jobFinished(QKeychain::Job*)) );
+ connect( next, SIGNAL(destroyed(QObject*)), this, SLOT(jobDestroyed(QObject*)) );
+ m_jobRunning = true;
+ next->scheduledStart();
+ }
+}
+
+void JobExecutor::jobDestroyed( QObject* object ) {
+ Job* job = static_cast<Job*>(object);
+ Q_UNUSED( object ) // for release mode
+ job->disconnect( this );
+ m_jobRunning = false;
+ startNextIfNoneRunning();
+}
+
+void JobExecutor::jobFinished( Job* job ) {
+ Q_UNUSED( job ) // for release mode
+ job->disconnect( this );
+ m_jobRunning = false;
+ startNextIfNoneRunning();
+}
+
+JobExecutor* JobExecutor::s_instance = 0;
+
+JobExecutor* JobExecutor::instance() {
+ if ( !s_instance )
+ s_instance = new JobExecutor;
+ return s_instance;
+}
+
+ReadPasswordJobPrivate::ReadPasswordJobPrivate(const QString &service_, ReadPasswordJob *qq) :
+ JobPrivate(service_, qq) {
+
+}
+
+JobPrivate::JobPrivate(const QString &service_, Job *qq)
+ : q(qq)
+ , mode( Text )
+ , error( NoError )
+ , service( service_ )
+ , autoDelete( true )
+ , insecureFallback( false )
+{
+}
+
+QString JobPrivate::modeToString(Mode m)
+{
+ switch (m) {
+ case Text:
+ return QLatin1String("Text");
+ case Binary:
+ return QLatin1String("Binary");
+ }
+
+ Q_ASSERT_X(false, Q_FUNC_INFO, "Unhandled Mode value");
+ return QString();
+}
+
+JobPrivate::Mode JobPrivate::stringToMode(const QString& s)
+{
+ if (s == QLatin1String("Text") || s == QLatin1String("1"))
+ return Text;
+ if (s == QLatin1String("Binary") || s == QLatin1String("2"))
+ return Binary;
+
+ qCritical("Unexpected mode string '%s'", qPrintable(s));
+
+ return Text;
+}
+
+WritePasswordJobPrivate::WritePasswordJobPrivate(const QString &service_, WritePasswordJob *qq) :
+ JobPrivate(service_, qq) {
+
+}
diff --git a/src/libs/3rdparty/qtkeychain/keychain.h b/src/libs/3rdparty/qtkeychain/keychain.h
new file mode 100644
index 0000000000..8c006cbcdd
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/keychain.h
@@ -0,0 +1,282 @@
+/******************************************************************************
+ * Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
+ * *
+ * 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
+
+#if !defined(QTKEYCHAIN_NO_EXPORT)
+#include "qkeychain_export.h"
+#else
+#define QKEYCHAIN_EXPORT
+#endif
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+
+class QSettings;
+
+#define QTKEYCHAIN_VERSION 0x000100
+
+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 JobExecutor;
+class JobPrivate;
+
+/**
+ * @brief Abstract base class for all QKeychain jobs.
+ */
+class QKEYCHAIN_EXPORT Job : public QObject {
+ Q_OBJECT
+public:
+ ~Job() override;
+
+ /**
+ * @return The QSettings instance used as plaintext storage if insecureFallback() is true.
+ * @see setSettings()
+ * @see insecureFallback()
+ */
+ QSettings* settings() const;
+
+ /**
+ * @return Set the QSettings instance that will be used as plaintext storage if insecureFallback() is true.
+ * @see settings()
+ * @see insecureFallback()
+ */
+ void setSettings( QSettings* settings );
+
+ /**
+ * Call this method to start the job.
+ * Typically you want to connect some slot to the finished() signal first:
+ *
+ * \code
+ * SomeClass::startJob()
+ * {
+ * connect(job, &Job::finished, this, &SomeClass::slotJobFinished);
+ * job->start();
+ * }
+ *
+ * SomeClass::slotJobFinished(Job *job)
+ * {
+ * if (job->error()) {
+ * // handle error
+ * } else {
+ * // do job-specific stuff
+ * }
+ * }
+ * \endcode
+ *
+ * @see finished()
+ */
+ void start();
+
+ QString service() const;
+
+ /**
+ * @note Call this method only after finished() has been emitted.
+ * @return The error code of the job (0 if no error).
+ */
+ Error error() const;
+
+ /**
+ * @return An error message that might provide details if error() returns OtherError.
+ */
+ QString errorString() const;
+
+ /**
+ * @return Whether this job autodeletes itself once finished() has been emitted. Default is true.
+ * @see setAutoDelete()
+ */
+ bool autoDelete() const;
+
+ /**
+ * Set whether this job should autodelete itself once finished() has been emitted.
+ * @see autoDelete()
+ */
+ void setAutoDelete( bool autoDelete );
+
+ /**
+ * @return Whether this job will use plaintext storage on unsupported platforms. Default is false.
+ * @see setInsecureFallback()
+ */
+ bool insecureFallback() const;
+
+ /**
+ * Set whether this job should use plaintext storage on unsupported platforms.
+ * @see insecureFallback()
+ */
+ void setInsecureFallback( bool insecureFallback );
+
+ /**
+ * @return The string used as key by this job.
+ * @see setKey()
+ */
+ QString key() const;
+
+ /**
+ * Set the @p key that this job will use to read or write data from/to the keychain.
+ * The key can be an empty string.
+ * @see key()
+ */
+ void setKey( const QString& key );
+
+ void emitFinished();
+ void emitFinishedWithError(Error, const QString& errorString);
+
+Q_SIGNALS:
+ /**
+ * Emitted when this job is finished.
+ * You can connect to this signal to be notified about the job's completion.
+ * @see start()
+ */
+ void finished( QKeychain::Job* );
+
+protected:
+ explicit Job( JobPrivate *q, QObject* parent=nullptr );
+ Q_INVOKABLE void doStart();
+
+private:
+ void setError( Error error );
+ void setErrorString( const QString& errorString );
+
+ void scheduledStart();
+
+protected:
+ JobPrivate* const d;
+
+friend class JobExecutor;
+friend class JobPrivate;
+friend class ReadPasswordJobPrivate;
+friend class WritePasswordJobPrivate;
+friend class DeletePasswordJobPrivate;
+};
+
+class ReadPasswordJobPrivate;
+
+/**
+ * @brief Job for reading secrets from the keychain.
+ * You can use a ReadPasswordJob to read passwords or binary data from the keychain.
+ * This job requires a "service" string, which is basically a namespace of keys within the keychain.
+ * This means that you can read all the pairs <key, secret> stored in the same service string.
+ */
+class QKEYCHAIN_EXPORT ReadPasswordJob : public Job {
+ Q_OBJECT
+public:
+ /**
+ * Create a new ReadPasswordJob.
+ * @param service The service string used by this job (can be empty).
+ * @param parent The parent of this job.
+ */
+ explicit ReadPasswordJob( const QString& service, QObject* parent=nullptr );
+ ~ReadPasswordJob() override;
+
+ /**
+ * @return The binary data stored as value of this job's key().
+ * @see Job::key()
+ */
+ QByteArray binaryData() const;
+
+ /**
+ * @return The string stored as value of this job's key().
+ * @see Job::key()
+ * @warning Returns meaningless data if the data was stored as binary data.
+ * @see WritePasswordJob::setTextData()
+ */
+ QString textData() const;
+
+private:
+ friend class QKeychain::ReadPasswordJobPrivate;
+};
+
+class WritePasswordJobPrivate;
+
+/**
+ * @brief Job for writing secrets to the keychain.
+ * You can use a WritePasswordJob to store passwords or binary data in the keychain.
+ * This job requires a "service" string, which is basically a namespace of keys within the keychain.
+ * This means that you can store different pairs <key, secret> under the same service string.
+ */
+class QKEYCHAIN_EXPORT WritePasswordJob : public Job {
+ Q_OBJECT
+public:
+ /**
+ * Create a new WritePasswordJob.
+ * @param service The service string used by this job (can be empty).
+ * @param parent The parent of this job.
+ */
+ explicit WritePasswordJob( const QString& service, QObject* parent=nullptr );
+ ~WritePasswordJob() override;
+
+ /**
+ * Set the @p data that the job will store in the keychain as binary data.
+ * @warning setBinaryData() and setTextData() are mutually exclusive.
+ */
+ void setBinaryData( const QByteArray& data );
+
+ /**
+ * Set the @p data that the job will store in the keychain as string.
+ * Typically @p data is a password.
+ * @warning setBinaryData() and setTextData() are mutually exclusive.
+ */
+ void setTextData( const QString& data );
+
+private:
+
+ friend class QKeychain::WritePasswordJobPrivate;
+};
+
+class DeletePasswordJobPrivate;
+
+/**
+ * @brief Job for deleting secrets from the keychain.
+ * You can use a DeletePasswordJob to delete passwords or binary data from the keychain.
+ * This job requires a "service" string, which is basically a namespace of keys within the keychain.
+ * This means that you can delete all the pairs <key, secret> stored in the same service string.
+ */
+class QKEYCHAIN_EXPORT DeletePasswordJob : public Job {
+ Q_OBJECT
+public:
+ /**
+ * Create a new DeletePasswordJob.
+ * @param service The service string used by this job (can be empty).
+ * @param parent The parent of this job.
+ */
+ explicit DeletePasswordJob( const QString& service, QObject* parent=nullptr );
+ ~DeletePasswordJob() override;
+
+private:
+ friend class QKeychain::DeletePasswordJobPrivate;
+};
+
+/**
+ * Checks whether there is a viable secure backend available.
+ * This particularly matters on UNIX platforms where multiple different backends
+ * exist and none might be available.
+ *
+ * Note that using the insecure fallback will work even if no secure backend is available.
+ *
+ * @since 0.14.0
+ */
+QKEYCHAIN_EXPORT bool isAvailable();
+
+} // namespace QtKeychain
+
+#endif
diff --git a/src/libs/3rdparty/qtkeychain/keychain_apple.mm b/src/libs/3rdparty/qtkeychain/keychain_apple.mm
new file mode 100644
index 0000000000..f9a8266be0
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/keychain_apple.mm
@@ -0,0 +1,263 @@
+/******************************************************************************
+ * Copyright (C) 2016 Mathias Hasselmann <mathias.hasselmann@kdab.com> *
+ * *
+ * 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"
+
+#import <Foundation/Foundation.h>
+#import <Security/Security.h>
+
+using namespace QKeychain;
+
+struct ErrorDescription
+{
+ QKeychain::Error code;
+ QString message;
+
+ ErrorDescription(QKeychain::Error code, const QString &message)
+ : code(code), message(message) {}
+
+ static ErrorDescription fromStatus(OSStatus status)
+ {
+ switch(status) {
+ case errSecSuccess:
+ return ErrorDescription(QKeychain::NoError, Job::tr("No error"));
+ case errSecItemNotFound:
+ return ErrorDescription(QKeychain::EntryNotFound, Job::tr("The specified item could not be found in the keychain"));
+ case errSecUserCanceled:
+ return ErrorDescription(QKeychain::AccessDeniedByUser, Job::tr("User canceled the operation"));
+ case errSecInteractionNotAllowed:
+ return ErrorDescription(QKeychain::AccessDenied, Job::tr("User interaction is not allowed"));
+ case errSecNotAvailable:
+ return ErrorDescription(QKeychain::AccessDenied, Job::tr("No keychain is available. You may need to restart your computer"));
+ case errSecAuthFailed:
+ return ErrorDescription(QKeychain::AccessDenied, Job::tr("The user name or passphrase you entered is not correct"));
+ case errSecVerifyFailed:
+ return ErrorDescription(QKeychain::AccessDenied, Job::tr("A cryptographic verification failure has occurred"));
+ case errSecUnimplemented:
+ return ErrorDescription(QKeychain::NotImplemented, Job::tr("Function or operation not implemented"));
+ case errSecIO:
+ return ErrorDescription(QKeychain::OtherError, Job::tr("I/O error"));
+ case errSecOpWr:
+ return ErrorDescription(QKeychain::OtherError, Job::tr("Already open with with write permission"));
+ case errSecParam:
+ return ErrorDescription(QKeychain::OtherError, Job::tr("Invalid parameters passed to a function"));
+ case errSecAllocate:
+ return ErrorDescription(QKeychain::OtherError, Job::tr("Failed to allocate memory"));
+ case errSecBadReq:
+ return ErrorDescription(QKeychain::OtherError, Job::tr("Bad parameter or invalid state for operation"));
+ case errSecInternalComponent:
+ return ErrorDescription(QKeychain::OtherError, Job::tr("An internal component failed"));
+ case errSecDuplicateItem:
+ return ErrorDescription(QKeychain::OtherError, Job::tr("The specified item already exists in the keychain"));
+ case errSecDecode:
+ return ErrorDescription(QKeychain::OtherError, Job::tr("Unable to decode the provided data"));
+ }
+
+ return ErrorDescription(QKeychain::OtherError, Job::tr("Unknown error"));
+ }
+};
+
+@interface AppleKeychainInterface : NSObject
+
+- (instancetype)initWithJob:(Job *)job andPrivateJob:(JobPrivate *)privateJob;
+- (void)keychainTaskFinished;
+- (void)keychainReadTaskFinished:(NSData *)retrievedData;
+- (void)keychainTaskFinishedWithError:(OSStatus)status descriptiveMessage:(NSString *)descriptiveMessage;
+
+@end
+
+@interface AppleKeychainInterface()
+{
+ QPointer<Job> _job;
+ QPointer<JobPrivate> _privateJob;
+}
+@end
+
+@implementation AppleKeychainInterface
+
+- (instancetype)initWithJob:(Job *)job andPrivateJob:(JobPrivate *)privateJob
+{
+ self = [super init];
+ if (self) {
+ _job = job;
+ _privateJob = privateJob;
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ [NSNotificationCenter.defaultCenter removeObserver:self];
+ [super dealloc];
+}
+
+- (void)keychainTaskFinished
+{
+ if (_job) {
+ _job->emitFinished();
+ }
+}
+
+- (void)keychainReadTaskFinished:(NSData *)retrievedData
+{
+ _privateJob->data.clear();
+ _privateJob->mode = JobPrivate::Binary;
+
+ if (retrievedData != nil) {
+ if (_privateJob) {
+ _privateJob->data = QByteArray::fromNSData(retrievedData);
+ }
+ }
+
+ if (_job) {
+ _job->emitFinished();
+ }
+}
+
+- (void)keychainTaskFinishedWithError:(OSStatus)status descriptiveMessage:(NSString *)descriptiveMessage
+{
+ const auto localisedDescriptiveMessage = Job::tr([descriptiveMessage UTF8String]);
+
+ const ErrorDescription error = ErrorDescription::fromStatus(status);
+ const auto fullMessage = localisedDescriptiveMessage.isEmpty() ? error.message : QStringLiteral("%1: %2").arg(localisedDescriptiveMessage, error.message);
+
+ if (_job) {
+ _job->emitFinishedWithError(error.code, fullMessage);
+ }
+}
+
+@end
+
+
+static void StartReadPassword(const QString &service, const QString &key, AppleKeychainInterface * const interface)
+{
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
+ NSDictionary * const query = @{
+ (__bridge NSString *)kSecClass: (__bridge NSString *)kSecClassGenericPassword,
+ (__bridge NSString *)kSecAttrService: service.toNSString(),
+ (__bridge NSString *)kSecAttrAccount: key.toNSString(),
+ (__bridge NSString *)kSecReturnData: @YES,
+ };
+
+ CFTypeRef dataRef = nil;
+ const OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &dataRef);
+
+ if (status == errSecSuccess) {
+ const CFDataRef castedDataRef = (CFDataRef)dataRef;
+ NSData * const data = (__bridge NSData *)castedDataRef;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [interface keychainReadTaskFinished:data];
+ [interface release];
+ });
+ } else {
+ NSString * const descriptiveErrorString = @"Could not retrieve private key from keystore";
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [interface keychainTaskFinishedWithError:status descriptiveMessage:descriptiveErrorString];
+ [interface release];
+ });
+ }
+
+ if (dataRef) {
+ CFRelease(dataRef);
+ }
+ });
+}
+
+static void StartWritePassword(const QString &service, const QString &key, const QByteArray &data, AppleKeychainInterface * const interface)
+{
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
+ NSDictionary * const query = @{
+ (__bridge NSString *)kSecClass: (__bridge NSString *)kSecClassGenericPassword,
+ (__bridge NSString *)kSecAttrService: service.toNSString(),
+ (__bridge NSString *)kSecAttrAccount: key.toNSString(),
+ };
+
+ OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, nil);
+
+ if (status == errSecSuccess) {
+ NSDictionary * const update = @{
+ (__bridge NSString *)kSecValueData: data.toNSData(),
+ };
+
+ status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update);
+ } else {
+ NSDictionary * const insert = @{
+ (__bridge NSString *)kSecClass: (__bridge NSString *)kSecClassGenericPassword,
+ (__bridge NSString *)kSecAttrService: service.toNSString(),
+ (__bridge NSString *)kSecAttrAccount: key.toNSString(),
+ (__bridge NSString *)kSecValueData: data.toNSData(),
+ };
+
+ status = SecItemAdd((__bridge const CFDictionaryRef)insert, nil);
+ }
+
+ if (status == errSecSuccess) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [interface keychainTaskFinished];
+ [interface release];
+ });
+ } else {
+ NSString * const descriptiveErrorString = @"Could not store data in settings";
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [interface keychainTaskFinishedWithError:status descriptiveMessage:descriptiveErrorString];
+ [interface release];
+ });
+ }
+ });
+}
+
+static void StartDeletePassword(const QString &service, const QString &key, AppleKeychainInterface * const interface)
+{
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
+ NSDictionary * const query = @{
+ (__bridge NSString *)kSecClass: (__bridge NSString *)kSecClassGenericPassword,
+ (__bridge NSString *)kSecAttrService: service.toNSString(),
+ (__bridge NSString *)kSecAttrAccount: key.toNSString(),
+ };
+
+ const OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
+
+ if (status == errSecSuccess) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [interface keychainTaskFinished];
+ [interface release];
+ });
+ } else {
+ NSString * const descriptiveErrorString = @"Could not remove private key from keystore";
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [interface keychainTaskFinishedWithError:status descriptiveMessage:descriptiveErrorString];
+ [interface release];
+ });
+ }
+ });
+}
+
+void ReadPasswordJobPrivate::scheduledStart()
+{
+ AppleKeychainInterface * const interface = [[AppleKeychainInterface alloc] initWithJob:q andPrivateJob:this];
+ StartReadPassword(service, key, interface);
+}
+
+void WritePasswordJobPrivate::scheduledStart()
+{
+ AppleKeychainInterface * const interface = [[AppleKeychainInterface alloc] initWithJob:q andPrivateJob:this];
+ StartWritePassword(service, key, data, interface);
+}
+
+void DeletePasswordJobPrivate::scheduledStart()
+{
+ AppleKeychainInterface * const interface = [[AppleKeychainInterface alloc] initWithJob:q andPrivateJob:this];
+ StartDeletePassword(service, key, interface);
+}
+
+bool QKeychain::isAvailable()
+{
+ return true;
+}
diff --git a/src/libs/3rdparty/qtkeychain/keychain_p.h b/src/libs/3rdparty/qtkeychain/keychain_p.h
new file mode 100644
index 0000000000..a66cb423d1
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/keychain_p.h
@@ -0,0 +1,167 @@
+/******************************************************************************
+ * Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
+ * *
+ * 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 <QCoreApplication>
+#include <QObject>
+#include <QPointer>
+#include <QSettings>
+#include <QQueue>
+
+#if defined(KEYCHAIN_DBUS)
+
+#include <QDBusPendingCallWatcher>
+
+#include "kwallet_interface.h"
+#else
+
+class QDBusPendingCallWatcher;
+
+#endif
+
+#include "keychain.h"
+
+namespace QKeychain {
+
+class JobExecutor;
+
+class JobPrivate : public QObject {
+ Q_OBJECT
+public:
+ enum Mode {
+ Text,
+ Binary
+ };
+
+ virtual void scheduledStart() = 0;
+
+ static QString modeToString(Mode m);
+ static Mode stringToMode(const QString& s);
+
+ Job* const q;
+ Mode mode;
+ QByteArray data;
+
+#if defined(KEYCHAIN_DBUS)
+ org::kde::KWallet* iface;
+ int walletHandle;
+
+ static void gnomeKeyring_readCb( int result, const char* string, JobPrivate* data );
+ static void gnomeKeyring_writeCb( int result, JobPrivate* self );
+
+ virtual void fallbackOnError(const QDBusError& err) = 0;
+
+protected Q_SLOTS:
+ void kwalletWalletFound( QDBusPendingCallWatcher* watcher );
+ virtual void kwalletFinished( QDBusPendingCallWatcher* watcher );
+ virtual void kwalletOpenFinished( QDBusPendingCallWatcher* watcher );
+#else
+ void kwalletWalletFound( QDBusPendingCallWatcher* ) {}
+ virtual void kwalletFinished( QDBusPendingCallWatcher* ) {}
+ virtual void kwalletOpenFinished( QDBusPendingCallWatcher* ) {}
+#endif
+
+protected:
+ JobPrivate( const QString& service_, Job *q );
+
+protected:
+ QKeychain::Error error;
+ QString errorString;
+ QString service;
+ bool autoDelete;
+ bool insecureFallback;
+ QPointer<QSettings> settings;
+ QString key;
+
+friend class Job;
+friend class JobExecutor;
+friend class ReadPasswordJob;
+friend class WritePasswordJob;
+friend class PlainTextStore;
+};
+
+class ReadPasswordJobPrivate : public JobPrivate {
+ Q_OBJECT
+public:
+ explicit ReadPasswordJobPrivate( const QString &service_, ReadPasswordJob* qq );
+ void scheduledStart() override;
+
+#if defined(KEYCHAIN_DBUS)
+ void fallbackOnError(const QDBusError& err) override;
+
+private Q_SLOTS:
+ void kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) override;
+ void kwalletEntryTypeFinished( QDBusPendingCallWatcher* watcher );
+ void kwalletFinished( QDBusPendingCallWatcher* watcher ) override;
+#else //moc's too dumb to respect above macros, so just define empty slot implementations
+private Q_SLOTS:
+ void kwalletOpenFinished( QDBusPendingCallWatcher* ) override {}
+ void kwalletEntryTypeFinished( QDBusPendingCallWatcher* ) {}
+ void kwalletFinished( QDBusPendingCallWatcher* ) override {}
+#endif
+
+ friend class ReadPasswordJob;
+};
+
+class WritePasswordJobPrivate : public JobPrivate {
+ Q_OBJECT
+public:
+ explicit WritePasswordJobPrivate( const QString &service_, WritePasswordJob* qq );
+ void scheduledStart() override;
+
+#if defined(KEYCHAIN_DBUS)
+ void fallbackOnError(const QDBusError& err) override;
+#endif
+
+ friend class WritePasswordJob;
+};
+
+class DeletePasswordJobPrivate : public JobPrivate {
+ Q_OBJECT
+public:
+ explicit DeletePasswordJobPrivate( const QString &service_, DeletePasswordJob* qq );
+
+ void scheduledStart() override;
+
+#if defined(KEYCHAIN_DBUS)
+ void fallbackOnError(const QDBusError& err) override;
+#endif
+
+protected:
+ void doStart();
+
+ friend class DeletePasswordJob;
+};
+
+class JobExecutor : public QObject {
+ Q_OBJECT
+public:
+
+ static JobExecutor* instance();
+
+ void enqueue( Job* job );
+
+private:
+ explicit JobExecutor();
+ void startNextIfNoneRunning();
+
+private Q_SLOTS:
+ void jobFinished( QKeychain::Job* );
+ void jobDestroyed( QObject* object );
+
+private:
+ static JobExecutor* s_instance;
+ QQueue<QPointer<Job> > m_queue;
+ bool m_jobRunning;
+};
+
+}
+
+#endif // KEYCHAIN_P_H
diff --git a/src/libs/3rdparty/qtkeychain/keychain_unix.cpp b/src/libs/3rdparty/qtkeychain/keychain_unix.cpp
new file mode 100644
index 0000000000..a3e83a9687
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/keychain_unix.cpp
@@ -0,0 +1,633 @@
+/******************************************************************************
+ * Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
+ * *
+ * 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 "gnomekeyring_p.h"
+#include "libsecret_p.h"
+#include "plaintextstore_p.h"
+
+#include <QScopedPointer>
+
+using namespace QKeychain;
+
+enum KeyringBackend {
+ Backend_LibSecretKeyring,
+ Backend_GnomeKeyring,
+ Backend_Kwallet4,
+ Backend_Kwallet5,
+ Backend_Kwallet6,
+};
+
+enum DesktopEnvironment {
+ DesktopEnv_Gnome,
+ DesktopEnv_Kde4,
+ DesktopEnv_Plasma5,
+ DesktopEnv_Plasma6,
+ DesktopEnv_Unity,
+ DesktopEnv_Xfce,
+ DesktopEnv_Other
+};
+
+static constexpr const char KWALLET6_DBUS_IFACE[] = "org.kde.kwalletd6";
+static constexpr const char KWALLET6_DBUS_PATH[] = "/modules/kwalletd6";
+static constexpr const char KWALLET5_DBUS_IFACE[] = "org.kde.kwalletd5";
+static constexpr const char KWALLET5_DBUS_PATH[] = "/modules/kwalletd5";
+static constexpr const char KWALLET4_DBUS_IFACE[] = "org.kde.kwalletd";
+static constexpr const char KWALLET4_DBUS_PATH[] = "/modules/kwalletd";
+
+// the following detection algorithm is derived from chromium,
+// licensed under BSD, see base/nix/xdg_util.cc
+
+static DesktopEnvironment getKdeVersion() {
+ QByteArray value = qgetenv("KDE_SESSION_VERSION");
+ if ( value == "6" ) {
+ return DesktopEnv_Plasma6;
+ } else if ( value == "5" ) {
+ return DesktopEnv_Plasma5;
+ } else if (value == "4" ) {
+ return DesktopEnv_Kde4;
+ } else {
+ // most likely KDE3
+ return DesktopEnv_Other;
+ }
+}
+
+static DesktopEnvironment detectDesktopEnvironment() {
+ QByteArray xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP");
+ if ( xdgCurrentDesktop == "GNOME" ) {
+ return DesktopEnv_Gnome;
+ } else if ( xdgCurrentDesktop == "Unity" ) {
+ return DesktopEnv_Unity;
+ } else if ( xdgCurrentDesktop == "KDE" ) {
+ return getKdeVersion();
+ } else if ( xdgCurrentDesktop == "XFCE" ) {
+ return DesktopEnv_Xfce;
+ }
+
+ QByteArray desktopSession = qgetenv("DESKTOP_SESSION");
+ if ( desktopSession == "gnome" ) {
+ return DesktopEnv_Gnome;
+ } else if ( desktopSession == "kde" ) {
+ return getKdeVersion();
+ } else if ( desktopSession == "kde4" ) {
+ return DesktopEnv_Kde4;
+ } else if ( desktopSession.contains("xfce") || desktopSession == "xubuntu" ) {
+ return DesktopEnv_Xfce;
+ }
+
+ if ( !qgetenv("GNOME_DESKTOP_SESSION_ID").isEmpty() ) {
+ return DesktopEnv_Gnome;
+ } else if ( !qgetenv("KDE_FULL_SESSION").isEmpty() ) {
+ return getKdeVersion();
+ }
+
+ return DesktopEnv_Other;
+}
+
+static bool isKwalletAvailable(const char *dbusIface, const char *dbusPath)
+{
+ if (!QDBusConnection::sessionBus().isConnected())
+ return false;
+
+ org::kde::KWallet iface(
+ QLatin1String(dbusIface),
+ QLatin1String(dbusPath),
+ QDBusConnection::sessionBus());
+
+ // At this point iface.isValid() can return false even though the
+ // interface is activatable by making a call. Hence we check whether
+ // a wallet can be opened.
+
+ iface.setTimeout(500);
+ QDBusMessage reply = iface.call(QLatin1String("networkWallet"));
+ return reply.type() == QDBusMessage::ReplyMessage;
+}
+
+static KeyringBackend detectKeyringBackend()
+{
+ /* The secret service dbus api, accessible through libsecret, is supposed
+ * to unify password services.
+ *
+ * Unfortunately at the time of Kubuntu 18.04 the secret service backend
+ * in KDE is gnome-keyring-daemon - using it has several complications:
+ * - the default collection isn't opened on session start, so users need
+ * to manually unlock it when the first application uses it
+ * - it's separate from the kwallet5 keyring, so switching to it means the
+ * existing keyring data can't be accessed anymore
+ *
+ * Thus we still prefer kwallet backends on KDE even if libsecret is
+ * available.
+ */
+
+ switch (detectDesktopEnvironment()) {
+ case DesktopEnv_Kde4:
+ return Backend_Kwallet4;
+
+ case DesktopEnv_Plasma5:
+ if (isKwalletAvailable(KWALLET5_DBUS_IFACE, KWALLET5_DBUS_PATH)) {
+ return Backend_Kwallet5;
+ }
+ if (LibSecretKeyring::isAvailable()) {
+ return Backend_LibSecretKeyring;
+ }
+ if (GnomeKeyring::isAvailable()) {
+ return Backend_GnomeKeyring;
+ }
+ // During startup the keychain backend might just not have started yet
+ return Backend_Kwallet5;
+
+ case DesktopEnv_Plasma6:
+ if (isKwalletAvailable(KWALLET6_DBUS_IFACE, KWALLET6_DBUS_PATH)) {
+ return Backend_Kwallet6;
+ }
+ if (LibSecretKeyring::isAvailable()) {
+ return Backend_LibSecretKeyring;
+ }
+ if (GnomeKeyring::isAvailable()) {
+ return Backend_GnomeKeyring;
+ }
+ // During startup the keychain backend might just not have started yet
+ return Backend_Kwallet6;
+
+ case DesktopEnv_Gnome:
+ case DesktopEnv_Unity:
+ case DesktopEnv_Xfce:
+ case DesktopEnv_Other:
+ default:
+ if (LibSecretKeyring::isAvailable()) {
+ return Backend_LibSecretKeyring;
+ }
+ if (GnomeKeyring::isAvailable()) {
+ return Backend_GnomeKeyring;
+ }
+ if (isKwalletAvailable(KWALLET6_DBUS_IFACE, KWALLET6_DBUS_PATH)) {
+ return Backend_Kwallet6;
+ }
+ if (isKwalletAvailable(KWALLET5_DBUS_IFACE, KWALLET5_DBUS_PATH)) {
+ return Backend_Kwallet5;
+ }
+ // During startup the keychain backend might just not have started yet
+ //
+ // This doesn't need to be libsecret because LibSecretKeyring::isAvailable()
+ // only fails if the libsecret shared library couldn't be loaded. In contrast
+ // to that GnomeKeyring::isAvailable() can return false if the shared library
+ // *was* loaded but its libgnome_keyring::is_available() returned false.
+ //
+ // In the future there should be a difference between "API available" and
+ // "keychain available".
+ return Backend_GnomeKeyring;
+ }
+
+}
+
+static KeyringBackend getKeyringBackend()
+{
+ static KeyringBackend backend = detectKeyringBackend();
+ return backend;
+}
+
+static void kwalletReadPasswordScheduledStartImpl(const char * service, const char * path, ReadPasswordJobPrivate * priv) {
+ if ( QDBusConnection::sessionBus().isConnected() )
+ {
+ priv->iface = new org::kde::KWallet( QLatin1String(service), QLatin1String(path), QDBusConnection::sessionBus(), priv );
+ const QDBusPendingReply<QString> reply = priv->iface->networkWallet();
+ QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher( reply, priv );
+ priv->connect( watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), priv, SLOT(kwalletWalletFound(QDBusPendingCallWatcher*)) );
+ }
+ else
+ {
+ // D-Bus is not reachable so none can tell us something about KWalletd
+ QDBusError err( QDBusError::NoServer, ReadPasswordJobPrivate::tr("D-Bus is not running") );
+ priv->fallbackOnError( err );
+ }
+}
+
+void ReadPasswordJobPrivate::scheduledStart() {
+ switch ( getKeyringBackend() ) {
+ case Backend_LibSecretKeyring: {
+ if ( !LibSecretKeyring::findPassword(key, q->service(), this) ) {
+ q->emitFinishedWithError( OtherError, tr("Unknown error") );
+ }
+ } break;
+ case Backend_GnomeKeyring:
+ this->mode = JobPrivate::Text;
+ if ( !GnomeKeyring::find_network_password( key.toUtf8().constData(),
+ q->service().toUtf8().constData(),
+ "plaintext",
+ reinterpret_cast<GnomeKeyring::OperationGetStringCallback>( &JobPrivate::gnomeKeyring_readCb ),
+ this, 0 ) )
+ q->emitFinishedWithError( OtherError, tr("Unknown error") );
+ break;
+
+ case Backend_Kwallet4:
+ kwalletReadPasswordScheduledStartImpl(KWALLET4_DBUS_IFACE, KWALLET4_DBUS_PATH, this);
+ break;
+ case Backend_Kwallet5:
+ kwalletReadPasswordScheduledStartImpl(KWALLET5_DBUS_IFACE, KWALLET5_DBUS_PATH, this);
+ break;
+ case Backend_Kwallet6:
+ kwalletReadPasswordScheduledStartImpl(KWALLET6_DBUS_IFACE, KWALLET6_DBUS_PATH, this);
+ break;
+ }
+}
+
+void JobPrivate::kwalletWalletFound(QDBusPendingCallWatcher *watcher)
+{
+ watcher->deleteLater();
+ const QDBusPendingReply<QString> reply = *watcher;
+ const QDBusPendingReply<int> pendingReply = iface->open( reply.value(), 0, q->service() );
+ QDBusPendingCallWatcher* pendingWatcher = new QDBusPendingCallWatcher( pendingReply, this );
+ connect( pendingWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
+ this, SLOT(kwalletOpenFinished(QDBusPendingCallWatcher*)) );
+}
+
+static QPair<Error, QString> mapGnomeKeyringError( int result )
+{
+ Q_ASSERT( result != GnomeKeyring::RESULT_OK );
+
+ switch ( result ) {
+ case GnomeKeyring::RESULT_DENIED:
+ return qMakePair( AccessDenied, QObject::tr("Access to keychain denied") );
+ case GnomeKeyring::RESULT_NO_KEYRING_DAEMON:
+ return qMakePair( NoBackendAvailable, QObject::tr("No keyring daemon") );
+ case GnomeKeyring::RESULT_ALREADY_UNLOCKED:
+ return qMakePair( OtherError, QObject::tr("Already unlocked") );
+ case GnomeKeyring::RESULT_NO_SUCH_KEYRING:
+ return qMakePair( OtherError, QObject::tr("No such keyring") );
+ case GnomeKeyring::RESULT_BAD_ARGUMENTS:
+ return qMakePair( OtherError, QObject::tr("Bad arguments") );
+ case GnomeKeyring::RESULT_IO_ERROR:
+ return qMakePair( OtherError, QObject::tr("I/O error") );
+ case GnomeKeyring::RESULT_CANCELLED:
+ return qMakePair( OtherError, QObject::tr("Cancelled") );
+ case GnomeKeyring::RESULT_KEYRING_ALREADY_EXISTS:
+ return qMakePair( OtherError, QObject::tr("Keyring already exists") );
+ case GnomeKeyring::RESULT_NO_MATCH:
+ return qMakePair( EntryNotFound, QObject::tr("No match") );
+ default:
+ break;
+ }
+
+ return qMakePair( OtherError, QObject::tr("Unknown error") );
+}
+
+void JobPrivate::gnomeKeyring_readCb( int result, const char* string, JobPrivate* self )
+{
+ if ( result == GnomeKeyring::RESULT_OK ) {
+ if (self->mode == JobPrivate::Text)
+ self->data = QByteArray(string);
+ else
+ self->data = QByteArray::fromBase64(string);
+
+ self->q->emitFinished();
+ } else if (self->mode == JobPrivate::Text) {
+ self->mode = JobPrivate::Binary;
+ if ( !GnomeKeyring::find_network_password( self->key.toUtf8().constData(),
+ self->q->service().toUtf8().constData(),
+ "base64",
+ reinterpret_cast<GnomeKeyring::OperationGetStringCallback>( &JobPrivate::gnomeKeyring_readCb ),
+ self, 0 ) )
+ self->q->emitFinishedWithError( OtherError, tr("Unknown error") );
+ } else {
+ const QPair<Error, QString> errorResult = mapGnomeKeyringError( result );
+ self->q->emitFinishedWithError( errorResult.first, errorResult.second );
+ }
+}
+
+void ReadPasswordJobPrivate::fallbackOnError(const QDBusError& err )
+{
+ PlainTextStore plainTextStore( q->service(), q->settings() );
+
+ if ( q->insecureFallback() && plainTextStore.contains( key ) ) {
+ mode = plainTextStore.readMode( key );
+ data = plainTextStore.readData( key );
+
+ if ( plainTextStore.error() != NoError )
+ q->emitFinishedWithError( plainTextStore.error(), plainTextStore.errorString() );
+ else
+ 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() ) );
+ }
+}
+
+void ReadPasswordJobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
+ watcher->deleteLater();
+ const QDBusPendingReply<int> reply = *watcher;
+
+ if ( reply.isError() ) {
+ fallbackOnError( reply.error() );
+ return;
+ }
+
+ PlainTextStore plainTextStore( q->service(), q->settings() );
+
+ if ( plainTextStore.contains( key ) ) {
+ // We previously stored data in the insecure QSettings, but now have KWallet available.
+ // Do the migration
+
+ data = plainTextStore.readData( key );
+ const WritePasswordJobPrivate::Mode mode = plainTextStore.readMode( key );
+ plainTextStore.remove( key );
+
+ q->emitFinished();
+
+
+ WritePasswordJob* j = new WritePasswordJob( q->service(), 0 );
+ j->setSettings( q->settings() );
+ j->setKey( key );
+ j->setAutoDelete( true );
+ if ( mode == WritePasswordJobPrivate::Binary )
+ j->setBinaryData( data );
+ else if ( mode == WritePasswordJobPrivate::Text )
+ j->setTextData( QString::fromUtf8( data ) );
+ else
+ Q_ASSERT( false );
+
+ j->start();
+
+ return;
+ }
+
+ walletHandle = reply.value();
+
+ if ( walletHandle < 0 ) {
+ q->emitFinishedWithError( AccessDenied, tr("Access to keychain denied") );
+ return;
+ }
+
+ const QDBusPendingReply<int> nextReply = iface->entryType( walletHandle, q->service(), key, q->service() );
+ QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this );
+ connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletEntryTypeFinished(QDBusPendingCallWatcher*)) );
+}
+
+//Must be in sync with KWallet::EntryType (kwallet.h)
+enum KWalletEntryType {
+ Unknown=0,
+ Password,
+ Stream,
+ Map
+};
+
+void ReadPasswordJobPrivate::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<int> reply = *watcher;
+ const int value = reply.value();
+
+ switch ( value ) {
+ case Unknown:
+ q->emitFinishedWithError( EntryNotFound, tr("Entry not found") );
+ return;
+ case Password:
+ mode = Text;
+ break;
+ case Stream:
+ mode = Binary;
+ break;
+ case Map:
+ q->emitFinishedWithError( EntryNotFound, tr("Unsupported entry type 'Map'") );
+ return;
+ default:
+ q->emitFinishedWithError( OtherError, tr("Unknown kwallet entry type '%1'").arg( value ) );
+ return;
+ }
+
+ const QDBusPendingCall nextReply = (mode == 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(kwalletFinished(QDBusPendingCallWatcher*)) );
+}
+
+void ReadPasswordJobPrivate::kwalletFinished( QDBusPendingCallWatcher* watcher ) {
+ if ( !watcher->isError() ) {
+ if ( mode == Binary ) {
+ QDBusPendingReply<QByteArray> reply = *watcher;
+ if (reply.isValid()) {
+ data = reply.value();
+ }
+ } else {
+ QDBusPendingReply<QString> reply = *watcher;
+ if (reply.isValid()) {
+ data = reply.value().toUtf8();
+ }
+ }
+ }
+
+ JobPrivate::kwalletFinished(watcher);
+}
+
+static void kwalletWritePasswordScheduledStart( const char * service, const char * path, JobPrivate * priv ) {
+ if ( QDBusConnection::sessionBus().isConnected() )
+ {
+ priv->iface = new org::kde::KWallet( QLatin1String(service), QLatin1String(path), QDBusConnection::sessionBus(), priv );
+ const QDBusPendingReply<QString> reply = priv->iface->networkWallet();
+ QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher( reply, priv );
+ priv->connect( watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), priv, SLOT(kwalletWalletFound(QDBusPendingCallWatcher*)) );
+ }
+ else
+ {
+ // D-Bus is not reachable so none can tell us something about KWalletd
+ QDBusError err( QDBusError::NoServer, WritePasswordJobPrivate::tr("D-Bus is not running") );
+ priv->fallbackOnError( err );
+ }
+}
+
+void WritePasswordJobPrivate::scheduledStart() {
+ switch ( getKeyringBackend() ) {
+ case Backend_LibSecretKeyring: {
+ if ( !LibSecretKeyring::writePassword(service, key, service, mode,
+ data, this) ) {
+ q->emitFinishedWithError( OtherError, tr("Unknown error") );
+ }
+ } break;
+ case Backend_GnomeKeyring: {
+ QString type;
+ QByteArray password;
+
+ switch(mode) {
+ case JobPrivate::Text:
+ type = QLatin1String("plaintext");
+ password = data;
+ break;
+ default:
+ type = QLatin1String("base64");
+ password = data.toBase64();
+ break;
+ }
+
+ QByteArray service = q->service().toUtf8();
+ if ( !GnomeKeyring::store_network_password( GnomeKeyring::GNOME_KEYRING_DEFAULT,
+ service.constData(),
+ key.toUtf8().constData(),
+ service.constData(),
+ type.toUtf8().constData(),
+ password.constData(),
+ reinterpret_cast<GnomeKeyring::OperationDoneCallback>( &JobPrivate::gnomeKeyring_writeCb ),
+ this, 0 ) )
+ q->emitFinishedWithError( OtherError, tr("Unknown error") );
+ }
+ break;
+
+ case Backend_Kwallet4:
+ kwalletWritePasswordScheduledStart(KWALLET4_DBUS_IFACE, KWALLET4_DBUS_PATH, this);
+ break;
+ case Backend_Kwallet5:
+ kwalletWritePasswordScheduledStart(KWALLET5_DBUS_IFACE, KWALLET5_DBUS_PATH, this);
+ break;
+ case Backend_Kwallet6:
+ kwalletWritePasswordScheduledStart(KWALLET6_DBUS_IFACE, KWALLET6_DBUS_PATH, this);
+ break;
+ }
+}
+
+void WritePasswordJobPrivate::fallbackOnError(const QDBusError &err)
+{
+ if ( !q->insecureFallback() ) {
+ q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
+ return;
+ }
+
+ PlainTextStore plainTextStore( q->service(), q->settings() );
+ plainTextStore.write( key, data, mode );
+
+ if ( plainTextStore.error() != NoError )
+ q->emitFinishedWithError( plainTextStore.error(), plainTextStore.errorString() );
+ else
+ q->emitFinished();
+}
+
+void JobPrivate::gnomeKeyring_writeCb(int result, JobPrivate* self )
+{
+ if ( result == GnomeKeyring::RESULT_OK ) {
+ self->q->emitFinished();
+ } else {
+ const QPair<Error, QString> errorResult = mapGnomeKeyringError( result );
+ self->q->emitFinishedWithError( errorResult.first, errorResult.second );
+ }
+}
+
+void JobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
+ watcher->deleteLater();
+ QDBusPendingReply<int> reply = *watcher;
+
+ if ( reply.isError() ) {
+ fallbackOnError( reply.error() );
+ return;
+ }
+
+ PlainTextStore plainTextStore( q->service(), q->settings() );
+ if ( plainTextStore.contains( key ) ) {
+ // If we had previously written to QSettings, but we now have a kwallet available, migrate and delete old insecure data
+ plainTextStore.remove( key );
+ }
+
+ const int handle = reply.value();
+
+ if ( handle < 0 ) {
+ q->emitFinishedWithError( AccessDenied, tr("Access to keychain denied") );
+ return;
+ }
+
+ QDBusPendingReply<int> nextReply;
+
+ if ( !data.isNull() ) {
+ if ( mode == Text ) {
+ nextReply = iface->writePassword( handle, q->service(), key, QString::fromUtf8(data), q->service() );
+ } else {
+ Q_ASSERT( mode == Binary );
+ nextReply = iface->writeEntry( handle, q->service(), key, data, 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(kwalletFinished(QDBusPendingCallWatcher*)) );
+}
+
+void JobPrivate::kwalletFinished( QDBusPendingCallWatcher* watcher ) {
+ if ( !watcher->isError() ) {
+ if ( mode == Binary ) {
+ QDBusPendingReply<QByteArray> reply = *watcher;
+ if (reply.isValid()) {
+ data = reply.value();
+ }
+ } else {
+ QDBusPendingReply<QString> reply = *watcher;
+ if (reply.isValid()) {
+ data = reply.value().toUtf8();
+ }
+ }
+ }
+
+ q->emitFinished();
+}
+
+void DeletePasswordJobPrivate::scheduledStart() {
+ switch ( getKeyringBackend() ) {
+ case Backend_LibSecretKeyring: {
+ if ( !LibSecretKeyring::deletePassword(key, q->service(), this) ) {
+ q->emitFinishedWithError( OtherError, tr("Unknown error") );
+ }
+ } break;
+ case Backend_GnomeKeyring: {
+ if ( !GnomeKeyring::delete_network_password(
+ key.toUtf8().constData(), q->service().toUtf8().constData(),
+ reinterpret_cast<GnomeKeyring::OperationDoneCallback>( &JobPrivate::gnomeKeyring_writeCb ),
+ this, 0 ) )
+ q->emitFinishedWithError( OtherError, tr("Unknown error") );
+ }
+ break;
+
+ case Backend_Kwallet4:
+ kwalletWritePasswordScheduledStart(KWALLET4_DBUS_IFACE, KWALLET4_DBUS_PATH, this);
+ break;
+ case Backend_Kwallet5:
+ kwalletWritePasswordScheduledStart(KWALLET5_DBUS_IFACE, KWALLET5_DBUS_PATH, this);
+ break;
+ case Backend_Kwallet6:
+ kwalletWritePasswordScheduledStart(KWALLET6_DBUS_IFACE, KWALLET6_DBUS_PATH, this);
+ break;
+ }
+}
+
+void DeletePasswordJobPrivate::fallbackOnError(const QDBusError &err) {
+ QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
+ QSettings* actual = q->settings() ? q->settings() : local.data();
+
+ if ( !q->insecureFallback() ) {
+ q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2")
+ .arg( QDBusError::errorString( err.type() ), err.message() ) );
+ return;
+ }
+
+ actual->remove( key );
+ actual->sync();
+
+ q->emitFinished();
+
+
+ q->emitFinished();
+}
+
+bool QKeychain::isAvailable()
+{
+ return LibSecretKeyring::isAvailable() || GnomeKeyring::isAvailable()
+ || isKwalletAvailable(KWALLET6_DBUS_IFACE, KWALLET6_DBUS_PATH)
+ || isKwalletAvailable(KWALLET5_DBUS_IFACE, KWALLET5_DBUS_PATH);
+}
diff --git a/src/libs/3rdparty/qtkeychain/keychain_win.cpp b/src/libs/3rdparty/qtkeychain/keychain_win.cpp
new file mode 100644
index 0000000000..98dd34cbab
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/keychain_win.cpp
@@ -0,0 +1,193 @@
+/******************************************************************************
+ * Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
+ * *
+ * 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 "plaintextstore_p.h"
+
+#include <windows.h>
+#include <wincrypt.h>
+
+#include <memory>
+
+using namespace QKeychain;
+
+#if defined(USE_CREDENTIAL_STORE)
+#include <wincred.h>
+
+void ReadPasswordJobPrivate::scheduledStart() {
+ LPCWSTR name = (LPCWSTR)key.utf16();
+ PCREDENTIALW cred;
+
+ if (!CredReadW(name, CRED_TYPE_GENERIC, 0, &cred)) {
+ Error err;
+ QString msg;
+ switch(GetLastError()) {
+ case ERROR_NOT_FOUND:
+ err = EntryNotFound;
+ msg = tr("Password entry not found");
+ break;
+ default:
+ err = OtherError;
+ msg = tr("Could not decrypt data");
+ break;
+ }
+
+ q->emitFinishedWithError( err, msg );
+ return;
+ }
+
+ data = QByteArray((char*)cred->CredentialBlob, cred->CredentialBlobSize);
+ CredFree(cred);
+
+ q->emitFinished();
+}
+
+void WritePasswordJobPrivate::scheduledStart() {
+ CREDENTIALW cred;
+ char *pwd = data.data();
+ LPWSTR name = (LPWSTR)key.utf16();
+
+ memset(&cred, 0, sizeof(cred));
+ cred.Comment = const_cast<wchar_t*>(L"QtKeychain");
+ cred.Type = CRED_TYPE_GENERIC;
+ cred.TargetName = name;
+ cred.CredentialBlobSize = data.size();
+ cred.CredentialBlob = (LPBYTE)pwd;
+ cred.Persist = CRED_PERSIST_ENTERPRISE;
+
+ if (CredWriteW(&cred, 0)) {
+ q->emitFinished();
+ return;
+ }
+
+ DWORD err = GetLastError();
+
+ // Detect size-exceeded errors and provide nicer messages.
+ // Unfortunately these error codes aren't documented.
+ // Found empirically on Win10 1803 build 17134.523.
+ if (err == RPC_X_BAD_STUB_DATA) {
+ const size_t maxBlob = CRED_MAX_CREDENTIAL_BLOB_SIZE;
+ if (cred.CredentialBlobSize > maxBlob) {
+ q->emitFinishedWithError(
+ OtherError,
+ tr("Credential size exceeds maximum size of %1").arg(maxBlob));
+ return;
+ }
+ }
+ if (err == RPC_S_INVALID_BOUND) {
+ const size_t maxTargetName = CRED_MAX_GENERIC_TARGET_NAME_LENGTH;
+ if (key.size() > maxTargetName) {
+ q->emitFinishedWithError(
+ OtherError,
+ tr("Credential key exceeds maximum size of %1").arg(maxTargetName));
+ return;
+ }
+ }
+
+ q->emitFinishedWithError( OtherError, tr("Writing credentials failed: Win32 error code %1").arg(err) );
+}
+
+void DeletePasswordJobPrivate::scheduledStart() {
+ LPCWSTR name = (LPCWSTR)key.utf16();
+
+ if (!CredDeleteW(name, CRED_TYPE_GENERIC, 0)) {
+ Error err;
+ QString msg;
+ switch(GetLastError()) {
+ case ERROR_NOT_FOUND:
+ err = EntryNotFound;
+ msg = tr("Password entry not found");
+ break;
+ default:
+ err = OtherError;
+ msg = tr("Could not decrypt data");
+ break;
+ }
+
+ q->emitFinishedWithError( err, msg );
+ } else {
+ q->emitFinished();
+ }
+}
+#else
+void ReadPasswordJobPrivate::scheduledStart() {
+ PlainTextStore plainTextStore( q->service(), q->settings() );
+ QByteArray encrypted = plainTextStore.readData( key );
+ if ( plainTextStore.error() != NoError ) {
+ q->emitFinishedWithError( plainTextStore.error(), plainTextStore.errorString() );
+ return;
+ }
+
+ DATA_BLOB blob_in, blob_out;
+
+ blob_in.pbData = reinterpret_cast<BYTE*>( encrypted.data() );
+ blob_in.cbData = encrypted.size();
+
+ const BOOL ret = CryptUnprotectData( &blob_in,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ 0,
+ &blob_out );
+ if ( !ret ) {
+ q->emitFinishedWithError( OtherError, tr("Could not decrypt data") );
+ return;
+ }
+
+ data = QByteArray( reinterpret_cast<char*>( blob_out.pbData ), blob_out.cbData );
+ SecureZeroMemory( blob_out.pbData, blob_out.cbData );
+ LocalFree( blob_out.pbData );
+
+ q->emitFinished();
+}
+
+void WritePasswordJobPrivate::scheduledStart() {
+ DATA_BLOB blob_in, blob_out;
+ blob_in.pbData = reinterpret_cast<BYTE*>( data.data() );
+ blob_in.cbData = data.size();
+ const BOOL res = CryptProtectData( &blob_in,
+ L"QKeychain-encrypted data",
+ nullptr,
+ nullptr,
+ nullptr,
+ 0,
+ &blob_out );
+ if ( !res ) {
+ q->emitFinishedWithError( OtherError, tr("Encryption failed") ); //TODO more details available?
+ return;
+ }
+
+ const QByteArray encrypted( reinterpret_cast<char*>( blob_out.pbData ), blob_out.cbData );
+ LocalFree( blob_out.pbData );
+
+ PlainTextStore plainTextStore( q->service(), q->settings() );
+ plainTextStore.write( key, encrypted, Binary );
+ if ( plainTextStore.error() != NoError ) {
+ q->emitFinishedWithError( plainTextStore.error(), plainTextStore.errorString() );
+ return;
+ }
+
+ q->emitFinished();
+}
+
+void DeletePasswordJobPrivate::scheduledStart() {
+ PlainTextStore plainTextStore( q->service(), q->settings() );
+ plainTextStore.remove( key );
+ if ( plainTextStore.error() != NoError ) {
+ q->emitFinishedWithError( plainTextStore.error(), plainTextStore.errorString() );
+ } else {
+ q->emitFinished();
+ }
+}
+#endif
+
+bool QKeychain::isAvailable()
+{
+ return true;
+}
diff --git a/src/libs/3rdparty/qtkeychain/libsecret.cpp b/src/libs/3rdparty/qtkeychain/libsecret.cpp
new file mode 100644
index 0000000000..6ee024989e
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/libsecret.cpp
@@ -0,0 +1,349 @@
+#if defined(HAVE_LIBSECRET)
+
+#undef signals
+#include <libsecret/secret.h>
+#define signals
+
+#endif
+
+#include "libsecret_p.h"
+
+
+#include <QLibrary>
+
+#if defined(HAVE_LIBSECRET)
+const SecretSchema* qtkeychainSchema(void) {
+ static const SecretSchema schema = {
+ "org.qt.keychain", SECRET_SCHEMA_DONT_MATCH_NAME,
+ {
+ { "user", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "server", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "type", SECRET_SCHEMA_ATTRIBUTE_STRING }
+ }
+ };
+
+ return &schema;
+}
+
+typedef struct {
+ QKeychain::JobPrivate *self;
+ QString user;
+ QString server;
+} callbackArg;
+
+typedef void (*secret_password_lookup_t) (const SecretSchema *schema,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ ...) G_GNUC_NULL_TERMINATED;
+typedef gchar *(*secret_password_lookup_finish_t) (GAsyncResult *result,
+ GError **error);
+typedef void (*secret_password_store_t) (const SecretSchema *schema,
+ const gchar *collection,
+ const gchar *label,
+ const gchar *password,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ ...) G_GNUC_NULL_TERMINATED;
+typedef gboolean (*secret_password_store_finish_t) (GAsyncResult *result,
+ GError **error);
+typedef void (*secret_password_clear_t) (const SecretSchema *schema,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ ...) G_GNUC_NULL_TERMINATED;
+typedef gboolean (*secret_password_clear_finish_t) (GAsyncResult *result,
+ GError **error);
+typedef void (*secret_password_free_t) (gchar *password);
+typedef GQuark (*secret_error_get_quark_t) (void) G_GNUC_CONST;
+
+static secret_password_lookup_t secret_password_lookup_fn = nullptr;
+static secret_password_lookup_finish_t secret_password_lookup_finish_fn = nullptr;
+static secret_password_store_t secret_password_store_fn = nullptr;
+static secret_password_store_finish_t secret_password_store_finish_fn = nullptr;
+static secret_password_clear_t secret_password_clear_fn = nullptr;
+static secret_password_clear_finish_t secret_password_clear_finish_fn = nullptr;
+static secret_password_free_t secret_password_free_fn = nullptr;
+static secret_error_get_quark_t secret_error_get_quark_fn = nullptr;
+
+static QKeychain::Error gerrorToCode(const GError *error) {
+ if (error->domain != secret_error_get_quark_fn()) {
+ return QKeychain::OtherError;
+ }
+
+ switch(error->code) {
+ case SECRET_ERROR_NO_SUCH_OBJECT:
+ return QKeychain::EntryNotFound;
+ case SECRET_ERROR_IS_LOCKED:
+ return QKeychain::AccessDenied;
+ default:
+ return QKeychain::OtherError;
+ }
+}
+
+static void
+on_password_lookup (GObject *source,
+ GAsyncResult *result,
+ gpointer inst)
+{
+ GError *error = nullptr;
+ callbackArg *arg = (callbackArg*)inst;
+ gchar *password = secret_password_lookup_finish_fn (result, &error);
+
+ Q_UNUSED(source);
+
+ if (arg) {
+ if (error) {
+ QKeychain::Error code = gerrorToCode(error);
+
+ arg->self->q->emitFinishedWithError( code, QString::fromUtf8(error->message) );
+ } else {
+ if (password) {
+ QByteArray raw = QByteArray(password);
+ switch(arg->self->mode) {
+ case QKeychain::JobPrivate::Binary:
+ arg->self->data = QByteArray::fromBase64(raw);
+ break;
+ case QKeychain::JobPrivate::Text:
+ default:
+ arg->self->data = raw;
+ }
+
+ arg->self->q->emitFinished();
+ } else if (arg->self->mode == QKeychain::JobPrivate::Text) {
+ arg->self->mode = QKeychain::JobPrivate::Binary;
+ secret_password_lookup_fn (qtkeychainSchema(), nullptr,
+ on_password_lookup, arg,
+ "user", arg->user.toUtf8().constData(),
+ "server", arg->server.toUtf8().constData(),
+ "type", "base64",
+ nullptr);
+ return;
+ } else {
+ arg->self->q->emitFinishedWithError( QKeychain::EntryNotFound, QObject::tr("Entry not found") );
+ }
+ }
+ }
+ if (error) {
+ g_error_free (error);
+ }
+
+ if (password) {
+ secret_password_free_fn (password);
+ }
+
+ if (arg) {
+ delete arg;
+ }
+}
+
+static void
+on_password_stored (GObject *source,
+ GAsyncResult *result,
+ gpointer inst)
+{
+ GError *error = nullptr;
+ QKeychain::JobPrivate *self = (QKeychain::JobPrivate*)inst;
+
+ Q_UNUSED(source);
+
+ secret_password_store_finish_fn (result, &error);
+
+ if (self) {
+ if (error) {
+ self->q->emitFinishedWithError( gerrorToCode(error),
+ QString::fromUtf8(error->message) );
+ } else {
+ self->q->emitFinished();
+ }
+ }
+ if (error) {
+ g_error_free (error);
+ }
+}
+
+static void
+on_password_cleared (GObject *source,
+ GAsyncResult *result,
+ gpointer inst)
+{
+ GError *error = nullptr;
+ QKeychain::JobPrivate *self = (QKeychain::JobPrivate*)inst;
+ gboolean removed = secret_password_clear_finish_fn (result, &error);
+
+ Q_UNUSED(source);
+ if (self) {
+ if ( error ) {
+ self->q->emitFinishedWithError( gerrorToCode(error),
+ QString::fromUtf8(error->message) );
+ } else {
+ Q_UNUSED(removed);
+ self->q->emitFinished();
+ }
+ }
+ if (error) {
+ g_error_free (error);
+ }
+}
+
+static QString modeToString(QKeychain::JobPrivate::Mode mode) {
+ switch(mode) {
+ case QKeychain::JobPrivate::Binary:
+ return "base64";
+ default:
+ return "plaintext";
+ }
+}
+#endif
+
+bool LibSecretKeyring::isAvailable() {
+#if defined(HAVE_LIBSECRET)
+ const LibSecretKeyring& keyring = instance();
+ if (!keyring.isLoaded())
+ return false;
+ if (secret_password_lookup_fn == nullptr)
+ return false;
+ if (secret_password_lookup_finish_fn == nullptr)
+ return false;
+ if (secret_password_store_fn == nullptr)
+ return false;
+ if (secret_password_store_finish_fn == nullptr)
+ return false;
+ if (secret_password_clear_fn == nullptr)
+ return false;
+ if (secret_password_clear_finish_fn == nullptr)
+ return false;
+ if (secret_password_free_fn == nullptr)
+ return false;
+ if (secret_error_get_quark_fn == nullptr)
+ return false;
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool LibSecretKeyring::findPassword(const QString &user, const QString &server,
+ QKeychain::JobPrivate *self)
+{
+#if defined(HAVE_LIBSECRET)
+ if (!isAvailable()) {
+ return false;
+ }
+
+ self->mode = QKeychain::JobPrivate::Text;
+ self->data = QByteArray();
+
+ callbackArg *arg = new callbackArg;
+ arg->self = self;
+ arg->user = user;
+ arg->server = server;
+
+ secret_password_lookup_fn (qtkeychainSchema(), nullptr, on_password_lookup, arg,
+ "user", user.toUtf8().constData(),
+ "server", server.toUtf8().constData(),
+ "type", "plaintext",
+ nullptr);
+ return true;
+#else
+ Q_UNUSED(user)
+ Q_UNUSED(server)
+ Q_UNUSED(self)
+ return false;
+#endif
+}
+
+bool LibSecretKeyring::writePassword(const QString &display_name,
+ const QString &user,
+ const QString &server,
+ const QKeychain::JobPrivate::Mode mode,
+ const QByteArray &password,
+ QKeychain::JobPrivate *self)
+{
+#if defined(HAVE_LIBSECRET)
+ if (!isAvailable()) {
+ return false;
+ }
+
+ QString type = modeToString(mode);
+ QByteArray pwd;
+ switch(mode) {
+ case QKeychain::JobPrivate::Binary:
+ pwd = password.toBase64();
+ break;
+ default:
+ pwd = password;
+ break;
+ }
+
+ secret_password_store_fn (qtkeychainSchema(), SECRET_COLLECTION_DEFAULT,
+ display_name.toUtf8().constData(),
+ pwd.constData(), nullptr, on_password_stored, self,
+ "user", user.toUtf8().constData(),
+ "server", server.toUtf8().constData(),
+ "type", type.toUtf8().constData(),
+ nullptr);
+ return true;
+#else
+ Q_UNUSED(display_name)
+ Q_UNUSED(user)
+ Q_UNUSED(server)
+ Q_UNUSED(mode)
+ Q_UNUSED(password)
+ Q_UNUSED(self)
+ return false;
+#endif
+}
+
+bool LibSecretKeyring::deletePassword(const QString &key, const QString &service,
+ QKeychain::JobPrivate* self)
+{
+#if defined(HAVE_LIBSECRET)
+ if (!isAvailable()) {
+ return false;
+ }
+
+ secret_password_clear_fn (qtkeychainSchema(), nullptr, on_password_cleared, self,
+ "user", key.toUtf8().constData(),
+ "server", service.toUtf8().constData(),
+ nullptr);
+ return true;
+#else
+ Q_UNUSED(key)
+ Q_UNUSED(service)
+ Q_UNUSED(self)
+ return false;
+#endif
+}
+
+LibSecretKeyring::LibSecretKeyring()
+ : QLibrary(QLatin1String("secret-1"), 0)
+{
+#ifdef HAVE_LIBSECRET
+ if (load()) {
+ secret_password_lookup_fn =
+ (secret_password_lookup_t)resolve("secret_password_lookup");
+ secret_password_lookup_finish_fn =
+ (secret_password_lookup_finish_t)resolve("secret_password_lookup_finish");
+ secret_password_store_fn =
+ (secret_password_store_t)resolve("secret_password_store");
+ secret_password_store_finish_fn =
+ (secret_password_store_finish_t)resolve("secret_password_store_finish");
+ secret_password_clear_fn =
+ (secret_password_clear_t)resolve("secret_password_clear");
+ secret_password_clear_finish_fn =
+ (secret_password_clear_finish_t)resolve("secret_password_clear_finish");
+ secret_password_free_fn =
+ (secret_password_free_t)resolve("secret_password_free");
+ secret_error_get_quark_fn =
+ (secret_error_get_quark_t)resolve("secret_error_get_quark");
+ }
+#endif
+}
+
+LibSecretKeyring &LibSecretKeyring::instance() {
+ static LibSecretKeyring instance;
+
+ return instance;
+}
diff --git a/src/libs/3rdparty/qtkeychain/libsecret_p.h b/src/libs/3rdparty/qtkeychain/libsecret_p.h
new file mode 100644
index 0000000000..bd966fe0f7
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/libsecret_p.h
@@ -0,0 +1,33 @@
+#ifndef QTKEYCHAIN_LIBSECRET_P_H
+#define QTKEYCHAIN_LIBSECRET_P_H
+
+#include <QLibrary>
+
+#include "keychain_p.h"
+
+class LibSecretKeyring : public QLibrary {
+public:
+ static bool isAvailable();
+
+ static bool findPassword(const QString& user,
+ const QString& server,
+ QKeychain::JobPrivate* self);
+
+ static bool writePassword(const QString& display_name,
+ const QString& user,
+ const QString& server,
+ const QKeychain::JobPrivate::Mode type,
+ const QByteArray& password,
+ QKeychain::JobPrivate* self);
+
+ static bool deletePassword(const QString &key, const QString &service,
+ QKeychain::JobPrivate* self);
+
+private:
+ LibSecretKeyring();
+
+ static LibSecretKeyring &instance();
+};
+
+
+#endif
diff --git a/src/libs/3rdparty/qtkeychain/org.kde.KWallet.xml b/src/libs/3rdparty/qtkeychain/org.kde.KWallet.xml
new file mode 100644
index 0000000000..ec4bd6e9c3
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/org.kde.KWallet.xml
@@ -0,0 +1,276 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.kde.KWallet">
+ <signal name="walletListDirty">
+ </signal>
+ <signal name="walletCreated">
+ <arg name="wallet" type="s" direction="out"/>
+ </signal>
+ <signal name="walletOpened">
+ <arg name="wallet" type="s" direction="out"/>
+ </signal>
+ <signal name="walletAsyncOpened">
+ <arg name="tId" type="i" direction="out"/>
+ <arg name="handle" type="i" direction="out"/>
+ </signal>
+ <signal name="walletDeleted">
+ <arg name="wallet" type="s" direction="out"/>
+ </signal>
+ <signal name="walletClosed">
+ <arg name="wallet" type="s" direction="out"/>
+ </signal>
+ <signal name="walletClosed">
+ <arg name="handle" type="i" direction="out"/>
+ </signal>
+ <signal name="allWalletsClosed">
+ </signal>
+ <signal name="folderListUpdated">
+ <arg name="wallet" type="s" direction="out"/>
+ </signal>
+ <signal name="folderUpdated">
+ <arg type="s" direction="out"/>
+ <arg type="s" direction="out"/>
+ </signal>
+ <signal name="applicationDisconnected">
+ <arg name="wallet" type="s" direction="out"/>
+ <arg name="application" type="s" direction="out"/>
+ </signal>
+ <method name="isEnabled">
+ <arg type="b" direction="out"/>
+ </method>
+ <method name="open">
+ <arg type="i" direction="out"/>
+ <arg name="wallet" type="s" direction="in"/>
+ <arg name="wId" type="x" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="openPath">
+ <arg type="i" direction="out"/>
+ <arg name="path" type="s" direction="in"/>
+ <arg name="wId" type="x" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="openAsync">
+ <arg type="i" direction="out"/>
+ <arg name="wallet" type="s" direction="in"/>
+ <arg name="wId" type="x" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ <arg name="handleSession" type="b" direction="in"/>
+ </method>
+ <method name="openPathAsync">
+ <arg type="i" direction="out"/>
+ <arg name="path" type="s" direction="in"/>
+ <arg name="wId" type="x" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ <arg name="handleSession" type="b" direction="in"/>
+ </method>
+ <method name="close">
+ <arg type="i" direction="out"/>
+ <arg name="wallet" type="s" direction="in"/>
+ <arg name="force" type="b" direction="in"/>
+ </method>
+ <method name="close">
+ <arg type="i" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="force" type="b" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="sync">
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ <annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
+ </method>
+ <method name="deleteWallet">
+ <arg type="i" direction="out"/>
+ <arg name="wallet" type="s" direction="in"/>
+ </method>
+ <method name="isOpen">
+ <arg type="b" direction="out"/>
+ <arg name="wallet" type="s" direction="in"/>
+ </method>
+ <method name="isOpen">
+ <arg type="b" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ </method>
+ <method name="users">
+ <arg type="as" direction="out"/>
+ <arg name="wallet" type="s" direction="in"/>
+ </method>
+ <method name="changePassword">
+ <arg name="wallet" type="s" direction="in"/>
+ <arg name="wId" type="x" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="wallets">
+ <arg type="as" direction="out"/>
+ </method>
+ <method name="folderList">
+ <arg type="as" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="hasFolder">
+ <arg type="b" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="createFolder">
+ <arg type="b" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="removeFolder">
+ <arg type="b" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="entryList">
+ <arg type="as" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="readEntry">
+ <arg type="ay" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="key" type="s" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="readMap">
+ <arg type="ay" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="key" type="s" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="readPassword">
+ <arg type="s" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="key" type="s" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="readEntryList">
+ <arg type="a{sv}" direction="out"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="key" type="s" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="readMapList">
+ <arg type="a{sv}" direction="out"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="key" type="s" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="readPasswordList">
+ <arg type="a{sv}" direction="out"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="key" type="s" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="renameEntry">
+ <arg type="i" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="oldName" type="s" direction="in"/>
+ <arg name="newName" type="s" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="writeEntry">
+ <arg type="i" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="key" type="s" direction="in"/>
+ <arg name="value" type="ay" direction="in"/>
+ <arg name="entryType" type="i" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="writeEntry">
+ <arg type="i" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="key" type="s" direction="in"/>
+ <arg name="value" type="ay" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="writeMap">
+ <arg type="i" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="key" type="s" direction="in"/>
+ <arg name="value" type="ay" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="writePassword">
+ <arg type="i" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="key" type="s" direction="in"/>
+ <arg name="value" type="s" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="hasEntry">
+ <arg type="b" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="key" type="s" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="entryType">
+ <arg type="i" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="key" type="s" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="removeEntry">
+ <arg type="i" direction="out"/>
+ <arg name="handle" type="i" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="key" type="s" direction="in"/>
+ <arg name="appid" type="s" direction="in"/>
+ </method>
+ <method name="disconnectApplication">
+ <arg type="b" direction="out"/>
+ <arg name="wallet" type="s" direction="in"/>
+ <arg name="application" type="s" direction="in"/>
+ </method>
+ <method name="reconfigure">
+ </method>
+ <method name="folderDoesNotExist">
+ <arg type="b" direction="out"/>
+ <arg name="wallet" type="s" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ </method>
+ <method name="keyDoesNotExist">
+ <arg type="b" direction="out"/>
+ <arg name="wallet" type="s" direction="in"/>
+ <arg name="folder" type="s" direction="in"/>
+ <arg name="key" type="s" direction="in"/>
+ </method>
+ <method name="closeAllWallets">
+ </method>
+ <method name="networkWallet">
+ <arg type="s" direction="out"/>
+ </method>
+ <method name="localWallet">
+ <arg type="s" direction="out"/>
+ </method>
+ <method name="pamOpen">
+ <arg name="wallet" type="s" direction="in"/>
+ <arg name="passwordHash" type="ay" direction="in"/>
+ <arg name="sessionTimeout" type="i" direction="in"/>
+ <annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
+ </method>
+ </interface>
+</node>
diff --git a/src/libs/3rdparty/qtkeychain/plaintextstore.cpp b/src/libs/3rdparty/qtkeychain/plaintextstore.cpp
new file mode 100644
index 0000000000..b9d027264d
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/plaintextstore.cpp
@@ -0,0 +1,110 @@
+/******************************************************************************
+ * Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
+ * Copyright (C) 2016 Mathias Hasselmann <mathias.hasselmann@kdab.com> *
+ * *
+ * 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 "plaintextstore_p.h"
+
+using namespace QKeychain;
+
+namespace {
+#ifdef Q_OS_WIN
+inline QString dataKey(const QString &key) { return key; }
+#else // Q_OS_WIN
+inline QString dataKey(const QString &key) { return key + QLatin1String("/data"); }
+inline QString typeKey(const QString &key) { return key + QLatin1String("/type"); }
+#endif // Q_OS_WIN
+}
+
+
+PlainTextStore::PlainTextStore(const QString &service, QSettings *settings)
+ : m_localSettings(settings ? 0 : new QSettings(service))
+ , m_actualSettings(settings ? settings : m_localSettings.data())
+ , m_error(NoError)
+{
+}
+
+bool PlainTextStore::contains(const QString &key) const
+{
+ return m_actualSettings->contains(dataKey(key));
+}
+
+QByteArray PlainTextStore::readData(const QString &key)
+{
+ return read(dataKey(key)).toByteArray();
+}
+
+#ifndef Q_OS_WIN
+
+JobPrivate::Mode PlainTextStore::readMode(const QString &key)
+{
+ return JobPrivate::stringToMode(read(typeKey(key)).toString());
+}
+
+#endif // Q_OS_WIN
+
+void PlainTextStore::write(const QString &key, const QByteArray &data, JobPrivate::Mode mode)
+{
+ if (m_actualSettings->status() != QSettings::NoError)
+ return;
+
+#ifndef Q_OS_WIN
+ m_actualSettings->setValue(typeKey(key), JobPrivate::modeToString(mode));
+#else // Q_OS_WIN
+ Q_UNUSED(mode);
+#endif // Q_OS_WIN
+ m_actualSettings->setValue(dataKey(key), data);
+ m_actualSettings->sync();
+
+ if (m_actualSettings->status() == QSettings::AccessError) {
+ setError(AccessDenied, tr("Could not store data in settings: access error"));
+ } else if (m_actualSettings->status() != QSettings::NoError) {
+ setError(OtherError, tr("Could not store data in settings: format error"));
+ } else {
+ setError(NoError, QString());
+ }
+}
+
+void PlainTextStore::remove(const QString &key)
+{
+ if (m_actualSettings->status() != QSettings::NoError)
+ return;
+
+#ifndef Q_OS_WIN
+ m_actualSettings->remove(typeKey(key));
+#endif // Q_OS_WIN
+ m_actualSettings->remove(dataKey(key));
+ m_actualSettings->sync();
+
+ if (m_actualSettings->status() == QSettings::AccessError) {
+ setError(AccessDenied, tr("Could not delete data from settings: access error"));
+ } else if (m_actualSettings->status() != QSettings::NoError) {
+ setError(OtherError, tr("Could not delete data from settings: format error"));
+ } else {
+ setError(NoError, QString());
+ }
+}
+
+void PlainTextStore::setError(Error error, const QString &errorString)
+{
+ m_error = error;
+ m_errorString = errorString;
+}
+
+QVariant PlainTextStore::read(const QString &key)
+{
+ const QVariant value = m_actualSettings->value(key);
+
+ if (value.isNull()) {
+ setError(EntryNotFound, tr("Entry not found"));
+ } else {
+ setError(NoError, QString());
+ }
+
+ return value;
+}
diff --git a/src/libs/3rdparty/qtkeychain/plaintextstore_p.h b/src/libs/3rdparty/qtkeychain/plaintextstore_p.h
new file mode 100644
index 0000000000..7ec05aaca1
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/plaintextstore_p.h
@@ -0,0 +1,47 @@
+/******************************************************************************
+ * Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
+ * Copyright (C) 2016 Mathias Hasselmann <mathias.hasselmann@kdab.com> *
+ * *
+ * 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 QTKEYCHAIN_PLAINTEXTSTORE_P_H
+#define QTKEYCHAIN_PLAINTEXTSTORE_P_H
+
+#include "keychain_p.h"
+
+namespace QKeychain {
+
+class PlainTextStore {
+ Q_DECLARE_TR_FUNCTIONS(QKeychain::PlainTextStore)
+
+public:
+ explicit PlainTextStore(const QString &service, QSettings *settings);
+
+ Error error() const { return m_error; }
+ QString errorString() const { return m_errorString; }
+
+ bool contains(const QString &key) const;
+
+ QByteArray readData(const QString &key);
+ JobPrivate::Mode readMode(const QString &key);
+
+ void write(const QString &key, const QByteArray &data, JobPrivate::Mode mode);
+ void remove(const QString &key);
+
+private:
+ void setError(Error error, const QString &errorString);
+ QVariant read(const QString &key);
+
+ const QScopedPointer<QSettings> m_localSettings;
+ QSettings *const m_actualSettings;
+ QString m_errorString;
+ Error m_error;
+};
+
+}
+
+#endif // QTKEYCHAIN_PLAINTEXTSTORE_P_H
diff --git a/src/libs/3rdparty/qtkeychain/qkeychain_export.h b/src/libs/3rdparty/qtkeychain/qkeychain_export.h
new file mode 100644
index 0000000000..14dc72287f
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/qkeychain_export.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <qglobal.h>
+
+#if defined(QTKEYCHAIN_LIBRARY)
+# define QKEYCHAIN_EXPORT Q_DECL_EXPORT
+#elif defined(QTKEYCHAIN_STATIC_LIBRARY)
+# define QKEYCHAIN_EXPORT
+#else
+# define QKEYCHAIN_EXPORT Q_DECL_IMPORT
+#endif
diff --git a/src/libs/3rdparty/qtkeychain/translations/qtkeychain_de.ts b/src/libs/3rdparty/qtkeychain/translations/qtkeychain_de.ts
new file mode 100644
index 0000000000..59ed992ed1
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/translations/qtkeychain_de.ts
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>QKeychain::DeletePasswordJobPrivate</name>
+ <message>
+ <location filename="../keychain_win.cpp" line="104"/>
+ <source>Password entry not found</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="108"/>
+ <source>Could not decrypt data</source>
+ <translation type="unfinished">Kann Daten nicht entschlüsseln</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="585"/>
+ <location filename="../keychain_unix.cpp" line="593"/>
+ <source>Unknown error</source>
+ <translation type="unfinished">Unbekannter Fehler</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="614"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation type="unfinished">Konnte Brieftasche nicht öffnen: %1; %2</translation>
+ </message>
+ <message>
+ <source>Password not found</source>
+ <translation type="obsolete">Passwort nicht gefunden</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::JobPrivate</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="295"/>
+ <source>Unknown error</source>
+ <translation type="unfinished">Unbekannter Fehler</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="542"/>
+ <source>Access to keychain denied</source>
+ <translation type="unfinished">Zugriff auf Schlüsselbund verweigert</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::PlainTextStore</name>
+ <message>
+ <location filename="../plaintextstore.cpp" line="65"/>
+ <source>Could not store data in settings: access error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="67"/>
+ <source>Could not store data in settings: format error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="85"/>
+ <source>Could not delete data from settings: access error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="87"/>
+ <source>Could not delete data from settings: format error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="104"/>
+ <source>Entry not found</source>
+ <translation type="unfinished">Eintrag nicht gefunden</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::ReadPasswordJobPrivate</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="214"/>
+ <location filename="../keychain_unix.cpp" line="224"/>
+ <source>Unknown error</source>
+ <translation>Unbekannter Fehler</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="205"/>
+ <source>D-Bus is not running</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="316"/>
+ <source>No keychain service available</source>
+ <translation>Kein Schlüsselbund-Dienst verfügbar</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="318"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation>Konnte Brieftasche nicht öffnen: %1; %2</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="363"/>
+ <source>Access to keychain denied</source>
+ <translation>Zugriff auf Schlüsselbund verweigert</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="384"/>
+ <source>Could not determine data type: %1; %2</source>
+ <translation>Datentyp kann nicht ermittelt werden: %1: %2</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="402"/>
+ <source>Unsupported entry type &apos;Map&apos;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="405"/>
+ <source>Unknown kwallet entry type &apos;%1&apos;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="393"/>
+ <source>Entry not found</source>
+ <translation>Eintrag nicht gefunden</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="32"/>
+ <source>Password entry not found</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="36"/>
+ <location filename="../keychain_win.cpp" line="139"/>
+ <source>Could not decrypt data</source>
+ <translation>Kann Daten nicht entschlüsseln</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::WritePasswordJobPrivate</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="455"/>
+ <location filename="../keychain_unix.cpp" line="482"/>
+ <source>Unknown error</source>
+ <translation>Unbekannter Fehler</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="445"/>
+ <source>D-Bus is not running</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="501"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation>Konnte Brieftasche nicht öffnen: %1; %2</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="78"/>
+ <source>Credential size exceeds maximum size of %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="87"/>
+ <source>Credential key exceeds maximum size of %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="92"/>
+ <source>Writing credentials failed: Win32 error code %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="162"/>
+ <source>Encryption failed</source>
+ <translation>Verschlüsselung fehlgeschlagen</translation>
+ </message>
+ <message>
+ <source>Password not found</source>
+ <translation type="obsolete">Passwort nicht gefunden</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="255"/>
+ <source>Access to keychain denied</source>
+ <translation>Zugriff auf Schlüsselbund verweigert</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="257"/>
+ <source>No keyring daemon</source>
+ <translation>Kein Schlüsselbund-Dienst </translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="259"/>
+ <source>Already unlocked</source>
+ <translation>Bereits entsperrt</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="261"/>
+ <source>No such keyring</source>
+ <translation>Kein solcher Schlüsselbund</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="263"/>
+ <source>Bad arguments</source>
+ <translation>Ungültige Argumente</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="265"/>
+ <source>I/O error</source>
+ <translation>Ein-/Ausgabe-Fehler</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="267"/>
+ <source>Cancelled</source>
+ <translation>Abgebrochen</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="269"/>
+ <source>Keyring already exists</source>
+ <translation>Schlüsselbund existiert bereits</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="271"/>
+ <source>No match</source>
+ <translation>Kein Treffer</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="276"/>
+ <source>Unknown error</source>
+ <translation>Unbekannter Fehler</translation>
+ </message>
+ <message>
+ <location filename="../libsecret.cpp" line="119"/>
+ <source>Entry not found</source>
+ <translation type="unfinished">Eintrag nicht gefunden</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/libs/3rdparty/qtkeychain/translations/qtkeychain_fr.ts b/src/libs/3rdparty/qtkeychain/translations/qtkeychain_fr.ts
new file mode 100644
index 0000000000..5eee2e34da
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/translations/qtkeychain_fr.ts
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="fr_FR">
+<context>
+ <name>QKeychain::DeletePasswordJobPrivate</name>
+ <message>
+ <location filename="../keychain_win.cpp" line="104"/>
+ <source>Password entry not found</source>
+ <translation>Mot de passe introuvable</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="108"/>
+ <source>Could not decrypt data</source>
+ <translation>Impossible de déchiffrer les données</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="585"/>
+ <location filename="../keychain_unix.cpp" line="593"/>
+ <source>Unknown error</source>
+ <translation>Erreur inconnue</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="614"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation>Impossible d&apos;ouvrir le portefeuille : %1; %2</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::JobPrivate</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="295"/>
+ <source>Unknown error</source>
+ <translation>Erreur inconnue</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="542"/>
+ <source>Access to keychain denied</source>
+ <translation>Accès au trousseau refusé</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::PlainTextStore</name>
+ <message>
+ <location filename="../plaintextstore.cpp" line="65"/>
+ <source>Could not store data in settings: access error</source>
+ <translation>Impossible de stocker les données dans les paramètres : Erreur d&apos;accès</translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="67"/>
+ <source>Could not store data in settings: format error</source>
+ <translation>Impossible de stocker les données dans les paramètres : Erreur de format</translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="85"/>
+ <source>Could not delete data from settings: access error</source>
+ <translation>Impossible de supprimer les données depuis les paramètres : Erreur d&apos;accès</translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="87"/>
+ <source>Could not delete data from settings: format error</source>
+ <translation>Impossible de supprimer les données depuis les paramètres : Erreur de format</translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="104"/>
+ <source>Entry not found</source>
+ <translation>Entrée introuvable</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::ReadPasswordJobPrivate</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="214"/>
+ <location filename="../keychain_unix.cpp" line="224"/>
+ <source>Unknown error</source>
+ <translation>Erreur inconnue</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="205"/>
+ <source>D-Bus is not running</source>
+ <translation>D-Bus n&apos;est pas en cours d&apos;exécution</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="316"/>
+ <source>No keychain service available</source>
+ <translation>Aucun service de trousseau disponible</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="318"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation>Impossible d&apos;ouvrir le trousseau : %1; %2</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="363"/>
+ <source>Access to keychain denied</source>
+ <translation>Accès au trousseau refusé</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="384"/>
+ <source>Could not determine data type: %1; %2</source>
+ <translation>Impossible de déterminer le type de données : %1: %2</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="402"/>
+ <source>Unsupported entry type &apos;Map&apos;</source>
+ <translation>Type d&apos;entrée non supporté &apos;Map&apos;</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="405"/>
+ <source>Unknown kwallet entry type &apos;%1&apos;</source>
+ <translation>Type de trousseau inconnu &apos;%1&apos;</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="393"/>
+ <source>Entry not found</source>
+ <translation>Entrée introuvable</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="32"/>
+ <source>Password entry not found</source>
+ <translation>Entrée de mot de passe introuvable</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="36"/>
+ <location filename="../keychain_win.cpp" line="139"/>
+ <source>Could not decrypt data</source>
+ <translation>Impossible de déchiffrer les données</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::WritePasswordJobPrivate</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="455"/>
+ <location filename="../keychain_unix.cpp" line="482"/>
+ <source>Unknown error</source>
+ <translation>Erreur inconnue</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="445"/>
+ <source>D-Bus is not running</source>
+ <translation>D-Bus n&apos;est pas en cours d&apos;exécution</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="501"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation>Impossible d&apos;ouvrir le trousseau : %1; %2</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="78"/>
+ <source>Credential size exceeds maximum size of %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="87"/>
+ <source>Credential key exceeds maximum size of %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="92"/>
+ <source>Writing credentials failed: Win32 error code %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="162"/>
+ <source>Encryption failed</source>
+ <translation>Le chiffrement a échoué</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="255"/>
+ <source>Access to keychain denied</source>
+ <translation>Accès au trousseau refusé</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="257"/>
+ <source>No keyring daemon</source>
+ <translation>Aucun démon de trousseau</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="259"/>
+ <source>Already unlocked</source>
+ <translation>Déjà déverrouillé</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="261"/>
+ <source>No such keyring</source>
+ <translation>Aucun trousseau</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="263"/>
+ <source>Bad arguments</source>
+ <translation>Mauvais arguments</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="265"/>
+ <source>I/O error</source>
+ <translation>Erreur d&apos;E/S</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="267"/>
+ <source>Cancelled</source>
+ <translation>Annulé</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="269"/>
+ <source>Keyring already exists</source>
+ <translation>Trousseau déjà existant</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="271"/>
+ <source>No match</source>
+ <translation>Aucune correspondance</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="276"/>
+ <source>Unknown error</source>
+ <translation>Erreur inconnue</translation>
+ </message>
+ <message>
+ <location filename="../libsecret.cpp" line="119"/>
+ <source>Entry not found</source>
+ <translation>Entrée introuvable</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/libs/3rdparty/qtkeychain/translations/qtkeychain_nl.ts b/src/libs/3rdparty/qtkeychain/translations/qtkeychain_nl.ts
new file mode 100644
index 0000000000..7033a98457
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/translations/qtkeychain_nl.ts
@@ -0,0 +1,320 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="nl_NL">
+<context>
+ <name>KeyChainClass</name>
+ <message>
+ <location filename="TestAppExample/keychainclass.cpp" line="22"/>
+ <source>Read key failed: %1</source>
+ <translation>De sleutel kan niet worden ingelezen: %1</translation>
+ </message>
+ <message>
+ <location filename="TestAppExample/keychainclass.cpp" line="37"/>
+ <source>Write key failed: %1</source>
+ <translation>De sleutel kan niet worden weggeschreven: %1</translation>
+ </message>
+ <message>
+ <location filename="TestAppExample/keychainclass.cpp" line="54"/>
+ <source>Delete key failed: %1</source>
+ <translation>De sleutel kan niet worden verwijderd: %1</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::DeletePasswordJobPrivate</name>
+ <message>
+ <location filename="keychain_android.cpp" line="173"/>
+ <source>Could not open keystore</source>
+ <translation>De sleutelbos kan niet worden geopend</translation>
+ </message>
+ <message>
+ <location filename="keychain_android.cpp" line="179"/>
+ <source>Could not remove private key from keystore</source>
+ <translation>De privésleutel kan niet worden verwijderd uit de sleutelbos</translation>
+ </message>
+ <message>
+ <location filename="keychain_haiku.cpp" line="177"/>
+ <source>Password not found</source>
+ <translation>Het wachtwoord is niet gevonden</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="552"/>
+ <location filename="keychain_unix.cpp" line="560"/>
+ <source>Unknown error</source>
+ <translation>Onbekende foutmelding</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="578"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation>De sleutelbos kan niet worden geopend: %1; %2</translation>
+ </message>
+ <message>
+ <location filename="keychain_win.cpp" line="104"/>
+ <source>Password entry not found</source>
+ <translation>Het wachtwoord is niet gevonden</translation>
+ </message>
+ <message>
+ <location filename="keychain_win.cpp" line="108"/>
+ <source>Could not decrypt data</source>
+ <translation>De gegevens kunnen niet worden ongrendeld</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::JobPrivate</name>
+ <message>
+ <location filename="keychain_unix.cpp" line="265"/>
+ <source>Unknown error</source>
+ <translation>Onbekende foutmelding</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="509"/>
+ <source>Access to keychain denied</source>
+ <translation>U heeft geen toegang tot de sleutelbos</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::PlainTextStore</name>
+ <message>
+ <location filename="plaintextstore.cpp" line="65"/>
+ <source>Could not store data in settings: access error</source>
+ <translation>De gegevens kunnen niet worden opgeslagen in de instellingen: toegangsfout</translation>
+ </message>
+ <message>
+ <location filename="plaintextstore.cpp" line="67"/>
+ <source>Could not store data in settings: format error</source>
+ <translation>De gegevens kunnen niet worden opgeslagen in de instellingen: opmaakfout</translation>
+ </message>
+ <message>
+ <location filename="plaintextstore.cpp" line="85"/>
+ <source>Could not delete data from settings: access error</source>
+ <translation>De gegevens kunnen niet worden verwijderd uit de instellingen: toegangsfout</translation>
+ </message>
+ <message>
+ <location filename="plaintextstore.cpp" line="87"/>
+ <source>Could not delete data from settings: format error</source>
+ <translation>De gegevens kunnen niet worden verwijderd uit de instellingen: opmaakfout</translation>
+ </message>
+ <message>
+ <location filename="plaintextstore.cpp" line="104"/>
+ <source>Entry not found</source>
+ <translation>Het item is niet gevonden</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::ReadPasswordJobPrivate</name>
+ <message>
+ <location filename="keychain_android.cpp" line="52"/>
+ <location filename="keychain_unix.cpp" line="363"/>
+ <source>Entry not found</source>
+ <translation>Het item is niet gevonden</translation>
+ </message>
+ <message>
+ <location filename="keychain_android.cpp" line="60"/>
+ <source>Could not open keystore</source>
+ <translation>De sleutelbos kan niet worden geopend</translation>
+ </message>
+ <message>
+ <location filename="keychain_android.cpp" line="68"/>
+ <source>Could not retrieve private key from keystore</source>
+ <translation>De privésleutel kan niet worden verwijderd uit de sleutelbos</translation>
+ </message>
+ <message>
+ <location filename="keychain_android.cpp" line="75"/>
+ <source>Could not create decryption cipher</source>
+ <translation>De ontgrendelcode kan niet worden aangemaakt</translation>
+ </message>
+ <message>
+ <location filename="keychain_haiku.cpp" line="96"/>
+ <source>Password not found</source>
+ <translation>Het wachtwoord is niet gevonden</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="178"/>
+ <source>D-Bus is not running</source>
+ <translation>D-Bus is niet actief</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="187"/>
+ <location filename="keychain_unix.cpp" line="197"/>
+ <source>Unknown error</source>
+ <translation>Onbekende foutmelding</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="286"/>
+ <source>No keychain service available</source>
+ <translation>De sleutelbosdienst is niet beschikbaar</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="288"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation>De sleutelbos kan niet worden geopend: %1; %2</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="333"/>
+ <source>Access to keychain denied</source>
+ <translation>U heeft geen toegang tot de sleutelbos</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="354"/>
+ <source>Could not determine data type: %1; %2</source>
+ <translation>De gegevensdrager kan niet worden bepaald: %1; %2</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="372"/>
+ <source>Unsupported entry type &apos;Map&apos;</source>
+ <translation>Niet-ondersteund itemtype ‘Map’</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="375"/>
+ <source>Unknown kwallet entry type &apos;%1&apos;</source>
+ <translation>Onbekend KWallet-item van type ‘%1’</translation>
+ </message>
+ <message>
+ <location filename="keychain_win.cpp" line="32"/>
+ <source>Password entry not found</source>
+ <translation>Het wachtwoord is niet gevonden</translation>
+ </message>
+ <message>
+ <location filename="keychain_win.cpp" line="36"/>
+ <location filename="keychain_win.cpp" line="139"/>
+ <source>Could not decrypt data</source>
+ <translation>De gegevens kunnen niet worden ongrendeld</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::WritePasswordJobPrivate</name>
+ <message>
+ <location filename="keychain_android.cpp" line="95"/>
+ <source>Could not open keystore</source>
+ <translation>De sleutelbos kan niet worden geopend</translation>
+ </message>
+ <message>
+ <location filename="keychain_android.cpp" line="124"/>
+ <source>Could not create private key generator</source>
+ <translation>De privésleutelgenerator kan niet worden gestart</translation>
+ </message>
+ <message>
+ <location filename="keychain_android.cpp" line="131"/>
+ <source>Could not generate new private key</source>
+ <translation>Er kan geen nieuwe privésleutel worden gegenereerd</translation>
+ </message>
+ <message>
+ <location filename="keychain_android.cpp" line="139"/>
+ <source>Could not retrieve private key from keystore</source>
+ <translation>De privésleutel kan niet worden opgehaald uit de sleutelbos</translation>
+ </message>
+ <message>
+ <location filename="keychain_android.cpp" line="147"/>
+ <source>Could not create encryption cipher</source>
+ <translation>De vergrendelcode kan niet worden aangemaakt</translation>
+ </message>
+ <message>
+ <location filename="keychain_android.cpp" line="155"/>
+ <source>Could not encrypt data</source>
+ <translation>De gegevens kunnen niet worden ontgrendeld</translation>
+ </message>
+ <message>
+ <location filename="keychain_haiku.cpp" line="144"/>
+ <source>Password not found</source>
+ <translation>Het wachtwoord is niet gevonden</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="415"/>
+ <source>D-Bus is not running</source>
+ <translation>D-Bus is niet actief</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="425"/>
+ <location filename="keychain_unix.cpp" line="452"/>
+ <source>Unknown error</source>
+ <translation>Onbekende foutmelding</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="468"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation>De sleutelbos kan niet worden geopend: %1; %2</translation>
+ </message>
+ <message>
+ <location filename="keychain_win.cpp" line="78"/>
+ <source>Credential size exceeds maximum size of %1</source>
+ <translation>De omvang overschrijdt de maximumomvang van %1</translation>
+ </message>
+ <message>
+ <location filename="keychain_win.cpp" line="87"/>
+ <source>Credential key exceeds maximum size of %1</source>
+ <translation>De sleutel overschrijdt de maximumomvang van %1</translation>
+ </message>
+ <message>
+ <location filename="keychain_win.cpp" line="92"/>
+ <source>Writing credentials failed: Win32 error code %1</source>
+ <translation>De gegevens kunnen niet worden weggeschreven: Win32-foutcode %1</translation>
+ </message>
+ <message>
+ <location filename="keychain_win.cpp" line="162"/>
+ <source>Encryption failed</source>
+ <translation>Het ontgrendelen is mislukt</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="keychain_haiku.cpp" line="72"/>
+ <source>error 0x%1: %2</source>
+ <translation>foutmelding 0x%1: %2</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="225"/>
+ <source>Access to keychain denied</source>
+ <translation>U heeft geen toegang tot de sleutelbos</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="227"/>
+ <source>No keyring daemon</source>
+ <translation>De sleutelbosdienst is niet actief</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="229"/>
+ <source>Already unlocked</source>
+ <translation>De sleutelbos is reeds ontgrendeld</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="231"/>
+ <source>No such keyring</source>
+ <translation>De sleutelbos bestaat niet</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="233"/>
+ <source>Bad arguments</source>
+ <translation>Onjuiste opties</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="235"/>
+ <source>I/O error</source>
+ <translation>I/O-fout</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="237"/>
+ <source>Cancelled</source>
+ <translation>Geannuleerd</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="239"/>
+ <source>Keyring already exists</source>
+ <translation>De sleutelbos bestaat reeds</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="241"/>
+ <source>No match</source>
+ <translation>Er zijn geen overeenkomsten</translation>
+ </message>
+ <message>
+ <location filename="keychain_unix.cpp" line="246"/>
+ <source>Unknown error</source>
+ <translation>Onbekende foutmelding</translation>
+ </message>
+ <message>
+ <location filename="libsecret.cpp" line="119"/>
+ <source>Entry not found</source>
+ <translation>Het item is niet gevonden</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/libs/3rdparty/qtkeychain/translations/qtkeychain_ro.ts b/src/libs/3rdparty/qtkeychain/translations/qtkeychain_ro.ts
new file mode 100644
index 0000000000..fb4e590676
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/translations/qtkeychain_ro.ts
@@ -0,0 +1,235 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="ro_RO">
+<context>
+ <name>QKeychain::DeletePasswordJobPrivate</name>
+ <message>
+ <location filename="../keychain_win.cpp" line="104"/>
+ <source>Password entry not found</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="108"/>
+ <source>Could not decrypt data</source>
+ <translation type="unfinished">Nu se poate decripta data</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="585"/>
+ <location filename="../keychain_unix.cpp" line="593"/>
+ <source>Unknown error</source>
+ <translation type="unfinished">Eroare necunoscută</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="614"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation type="unfinished">Nu se poate deschide portofelul: %1; %2</translation>
+ </message>
+ <message>
+ <source>Password not found</source>
+ <translation type="obsolete">Parola nu a fost găsită</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::JobPrivate</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="295"/>
+ <source>Unknown error</source>
+ <translation type="unfinished">Eroare necunoscută</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="542"/>
+ <source>Access to keychain denied</source>
+ <translation type="unfinished">Acces interzis la serviciul de chei</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::PlainTextStore</name>
+ <message>
+ <location filename="../plaintextstore.cpp" line="65"/>
+ <source>Could not store data in settings: access error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="67"/>
+ <source>Could not store data in settings: format error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="85"/>
+ <source>Could not delete data from settings: access error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="87"/>
+ <source>Could not delete data from settings: format error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="104"/>
+ <source>Entry not found</source>
+ <translation type="unfinished">Înregistrarea nu a fost găsită</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::ReadPasswordJobPrivate</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="214"/>
+ <location filename="../keychain_unix.cpp" line="224"/>
+ <source>Unknown error</source>
+ <translation>Eroare necunoscută</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="205"/>
+ <source>D-Bus is not running</source>
+ <translation>D-Bus nu rulează</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="316"/>
+ <source>No keychain service available</source>
+ <translatorcomment>Nu există niciun serviciu de chei disponibil</translatorcomment>
+ <translation>Kein Schlüsselbund-Dienst verfügbar</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="318"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation>Nu se poate deschide portofelul: %1; %2</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="363"/>
+ <source>Access to keychain denied</source>
+ <translation>Acces interzis la serviciul de chei</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="384"/>
+ <source>Could not determine data type: %1; %2</source>
+ <translation>Nu se poate stabili tipul de date: %1: %2</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="402"/>
+ <source>Unsupported entry type &apos;Map&apos;</source>
+ <translation>Tip de înregistrare nesuportat &apos;Map&apos;</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="405"/>
+ <source>Unknown kwallet entry type &apos;%1&apos;</source>
+ <translation>Tip de înregistrare kwallet necunoscut &apos;%1&apos;</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="393"/>
+ <source>Entry not found</source>
+ <translation>Înregistrarea nu a fost găsită</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="32"/>
+ <source>Password entry not found</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="36"/>
+ <location filename="../keychain_win.cpp" line="139"/>
+ <source>Could not decrypt data</source>
+ <translation>Nu se poate decripta data</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::WritePasswordJobPrivate</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="455"/>
+ <location filename="../keychain_unix.cpp" line="482"/>
+ <source>Unknown error</source>
+ <translation>Eroare necunoscută</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="445"/>
+ <source>D-Bus is not running</source>
+ <translation>D-Bus nu rulează</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="501"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation>Nu se poate deschide portofelul: %1; %2</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="78"/>
+ <source>Credential size exceeds maximum size of %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="87"/>
+ <source>Credential key exceeds maximum size of %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="92"/>
+ <source>Writing credentials failed: Win32 error code %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="162"/>
+ <source>Encryption failed</source>
+ <translation>Criptarea a eșuat</translation>
+ </message>
+ <message>
+ <source>Password not found</source>
+ <translation type="obsolete">Parola nu a fost găsită</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="255"/>
+ <source>Access to keychain denied</source>
+ <translation>Acces interzis la serviciul de chei</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="257"/>
+ <source>No keyring daemon</source>
+ <translation>Niciun demon pentru inelul de chei</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="259"/>
+ <source>Already unlocked</source>
+ <translation>Deja deblocat</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="261"/>
+ <source>No such keyring</source>
+ <translation>Nu există astfel de inel de chei</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="263"/>
+ <source>Bad arguments</source>
+ <translation>Argumente greșite</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="265"/>
+ <source>I/O error</source>
+ <translation>Eroare de I/E</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="267"/>
+ <source>Cancelled</source>
+ <translation>Anulat</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="269"/>
+ <source>Keyring already exists</source>
+ <translation>Inelul de chei deja există</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="271"/>
+ <source>No match</source>
+ <translation>Nicio potrivire</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="276"/>
+ <source>Unknown error</source>
+ <translation>Eroare necunoscută</translation>
+ </message>
+ <message>
+ <location filename="../libsecret.cpp" line="119"/>
+ <source>Entry not found</source>
+ <translation type="unfinished">Înregistrarea nu a fost găsită</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/libs/3rdparty/qtkeychain/translations/qtkeychain_ru.ts b/src/libs/3rdparty/qtkeychain/translations/qtkeychain_ru.ts
new file mode 100644
index 0000000000..c4cec0bb52
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/translations/qtkeychain_ru.ts
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="ru_RU">
+<context>
+ <name>QKeychain::DeletePasswordJobPrivate</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="585"/>
+ <location filename="../keychain_unix.cpp" line="593"/>
+ <source>Unknown error</source>
+ <translation>Неизвестная ошибка</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="614"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation>Не удалось открыть бумажник: %1; %2</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="104"/>
+ <source>Password entry not found</source>
+ <translation>Пароль не найден</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="108"/>
+ <source>Could not decrypt data</source>
+ <translation>Не удалось расшифровать данные</translation>
+ </message>
+ <message>
+ <source>Password not found</source>
+ <translation type="obsolete">Пароль не найден</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::JobPrivate</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="295"/>
+ <source>Unknown error</source>
+ <translation>Неизвестная ошибка</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="542"/>
+ <source>Access to keychain denied</source>
+ <translation>Доступ к связке ключей запрещён</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::PlainTextStore</name>
+ <message>
+ <location filename="../plaintextstore.cpp" line="65"/>
+ <source>Could not store data in settings: access error</source>
+ <translation>Не удалось сохранить данные в настройках: ошибка доступа</translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="67"/>
+ <source>Could not store data in settings: format error</source>
+ <translation>Не удалось сохранить данные в настройках: ошибка формата</translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="85"/>
+ <source>Could not delete data from settings: access error</source>
+ <translation>Не удалось удалить данные из настроек: ошибка доступа</translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="87"/>
+ <source>Could not delete data from settings: format error</source>
+ <translation>Не удалось удалить данные из настроек: ошибка формата</translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="104"/>
+ <source>Entry not found</source>
+ <translation>Запись не найдена</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::ReadPasswordJobPrivate</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="205"/>
+ <source>D-Bus is not running</source>
+ <translation>D-Bus не запущен</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="214"/>
+ <location filename="../keychain_unix.cpp" line="224"/>
+ <source>Unknown error</source>
+ <translation>Неизвестная ошибка</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="316"/>
+ <source>No keychain service available</source>
+ <translation>Служба связки ключей недоступна</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="318"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation>Не удалось открыть кошелёк: %1; %2</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="363"/>
+ <source>Access to keychain denied</source>
+ <translation>Доступ к связке ключей запрещён</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="384"/>
+ <source>Could not determine data type: %1; %2</source>
+ <translation>Не удалось определить тип данных: %1; %2</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="393"/>
+ <source>Entry not found</source>
+ <translation>Запись не найдена</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="402"/>
+ <source>Unsupported entry type &apos;Map&apos;</source>
+ <translation>Неподдерживаемый тип записи &apos;Map&apos;</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="405"/>
+ <source>Unknown kwallet entry type &apos;%1&apos;</source>
+ <translation>Неизвестный тип записи kwallet &apos;%1&apos;</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="32"/>
+ <source>Password entry not found</source>
+ <translation>Пароль не найден</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="36"/>
+ <location filename="../keychain_win.cpp" line="139"/>
+ <source>Could not decrypt data</source>
+ <translation>Не удалось расшифровать данные</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::WritePasswordJobPrivate</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="445"/>
+ <source>D-Bus is not running</source>
+ <translation>D-Bus не запущен</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="455"/>
+ <location filename="../keychain_unix.cpp" line="482"/>
+ <source>Unknown error</source>
+ <translation>Неизвестная ошибка</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="501"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation>Не удалось открыть кошелёк: %1; %2</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="78"/>
+ <source>Credential size exceeds maximum size of %1</source>
+ <translation>Учётные данные превышают максимальный размер %1</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="87"/>
+ <source>Credential key exceeds maximum size of %1</source>
+ <translation>Ключ учётных данных превышает максимальный размер %1</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="92"/>
+ <source>Writing credentials failed: Win32 error code %1</source>
+ <translation>Не удалось сохранить учётные данные: код ошибки win32 %1</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="162"/>
+ <source>Encryption failed</source>
+ <translation>Шифрование не удалось</translation>
+ </message>
+ <message>
+ <source>Password not found</source>
+ <translation type="obsolete">Пароль не найден</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="255"/>
+ <source>Access to keychain denied</source>
+ <translation>Доступ к связке ключей запрещён</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="257"/>
+ <source>No keyring daemon</source>
+ <translation>Нет демона связки ключей</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="259"/>
+ <source>Already unlocked</source>
+ <translation>Уже разблокировано</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="261"/>
+ <source>No such keyring</source>
+ <translation>Связка ключей не найдена</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="263"/>
+ <source>Bad arguments</source>
+ <translation>Неверные аргументы</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="265"/>
+ <source>I/O error</source>
+ <translation>Ошибка ввода/вывода</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="267"/>
+ <source>Cancelled</source>
+ <translation>Отменено</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="269"/>
+ <source>Keyring already exists</source>
+ <translation>Связка ключей уже существует</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="271"/>
+ <source>No match</source>
+ <translation>Нет совпадений</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="276"/>
+ <source>Unknown error</source>
+ <translation>Неизвестная ошибка</translation>
+ </message>
+ <message>
+ <location filename="../libsecret.cpp" line="119"/>
+ <source>Entry not found</source>
+ <translation>Запись не найдена</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/libs/3rdparty/qtkeychain/translations/qtkeychain_zh.ts b/src/libs/3rdparty/qtkeychain/translations/qtkeychain_zh.ts
new file mode 100644
index 0000000000..5d4d64a499
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/translations/qtkeychain_zh.ts
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="zh_TW">
+<context>
+ <name>QKeychain::DeletePasswordJobPrivate</name>
+ <message>
+ <location filename="../keychain_win.cpp" line="104"/>
+ <source>Password entry not found</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="108"/>
+ <source>Could not decrypt data</source>
+ <translation type="unfinished">無法解密資料</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="585"/>
+ <location filename="../keychain_unix.cpp" line="593"/>
+ <source>Unknown error</source>
+ <translation type="unfinished">未知的錯誤</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="614"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation type="unfinished">無法開啟錢包:%1; %2</translation>
+ </message>
+ <message>
+ <source>Password not found</source>
+ <translation type="obsolete">找不到密碼</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::JobPrivate</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="295"/>
+ <source>Unknown error</source>
+ <translation type="unfinished">未知的錯誤</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="542"/>
+ <source>Access to keychain denied</source>
+ <translation type="unfinished">鑰匙圈存取被拒絕</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::PlainTextStore</name>
+ <message>
+ <location filename="../plaintextstore.cpp" line="65"/>
+ <source>Could not store data in settings: access error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="67"/>
+ <source>Could not store data in settings: format error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="85"/>
+ <source>Could not delete data from settings: access error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="87"/>
+ <source>Could not delete data from settings: format error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../plaintextstore.cpp" line="104"/>
+ <source>Entry not found</source>
+ <translation type="unfinished">找不到項目</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::ReadPasswordJobPrivate</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="214"/>
+ <location filename="../keychain_unix.cpp" line="224"/>
+ <source>Unknown error</source>
+ <translation>未知的錯誤</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="205"/>
+ <source>D-Bus is not running</source>
+ <translation>D-Bus 不在執行中</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="316"/>
+ <source>No keychain service available</source>
+ <translation>沒有可用的鑰匙圈服務</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="318"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation>無法開啟錢包:%1; %2</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="363"/>
+ <source>Access to keychain denied</source>
+ <translation>鑰匙圈存取被拒絕</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="384"/>
+ <source>Could not determine data type: %1; %2</source>
+ <translation>無法判斷資料型別:%1; %2</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="402"/>
+ <source>Unsupported entry type &apos;Map&apos;</source>
+ <translation>不支援的項目類型 &apos;Map&apos;</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="405"/>
+ <source>Unknown kwallet entry type &apos;%1&apos;</source>
+ <translation>未知的 kwallet 項目類型 &apos;%1&apos;</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="393"/>
+ <source>Entry not found</source>
+ <translation>找不到項目</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="32"/>
+ <source>Password entry not found</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="36"/>
+ <location filename="../keychain_win.cpp" line="139"/>
+ <source>Could not decrypt data</source>
+ <translation>無法解密資料</translation>
+ </message>
+</context>
+<context>
+ <name>QKeychain::WritePasswordJobPrivate</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="455"/>
+ <location filename="../keychain_unix.cpp" line="482"/>
+ <source>Unknown error</source>
+ <translation>未知的錯誤</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="445"/>
+ <source>D-Bus is not running</source>
+ <translation>D-Bus 不在執行中</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="501"/>
+ <source>Could not open wallet: %1; %2</source>
+ <translation>無法開啟錢包:%1; %2</translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="78"/>
+ <source>Credential size exceeds maximum size of %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="87"/>
+ <source>Credential key exceeds maximum size of %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="92"/>
+ <source>Writing credentials failed: Win32 error code %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../keychain_win.cpp" line="162"/>
+ <source>Encryption failed</source>
+ <translation>加密失敗</translation>
+ </message>
+ <message>
+ <source>Password not found</source>
+ <translation type="obsolete">找不到密碼</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../keychain_unix.cpp" line="255"/>
+ <source>Access to keychain denied</source>
+ <translation>鑰匙圈存取被拒絕</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="257"/>
+ <source>No keyring daemon</source>
+ <translation>沒有可用的鑰匙圈背景程式</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="259"/>
+ <source>Already unlocked</source>
+ <translation>已解鎖</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="261"/>
+ <source>No such keyring</source>
+ <translation>鑰匙圈不存在</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="263"/>
+ <source>Bad arguments</source>
+ <translation>引數錯誤</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="265"/>
+ <source>I/O error</source>
+ <translation>I/O 錯誤</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="267"/>
+ <source>Cancelled</source>
+ <translation>已取消</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="269"/>
+ <source>Keyring already exists</source>
+ <translation>鑰匙圈已存在</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="271"/>
+ <source>No match</source>
+ <translation>無相符項目</translation>
+ </message>
+ <message>
+ <location filename="../keychain_unix.cpp" line="276"/>
+ <source>Unknown error</source>
+ <translation>未知的錯誤</translation>
+ </message>
+ <message>
+ <location filename="../libsecret.cpp" line="119"/>
+ <source>Entry not found</source>
+ <translation type="unfinished">找不到項目</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/libs/3rdparty/qtkeychain/translations/translations.qrc.in b/src/libs/3rdparty/qtkeychain/translations/translations.qrc.in
new file mode 100644
index 0000000000..f49df66150
--- /dev/null
+++ b/src/libs/3rdparty/qtkeychain/translations/translations.qrc.in
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/translations">
+ @QM_FILE_LIST@
+ </qresource>
+</RCC>