⬆️ Update qtkeychain

This commit is contained in:
Edgar 2021-05-30 13:37:40 +02:00
parent a1b4487b1e
commit 078164838e
63 changed files with 6375 additions and 3445 deletions

8
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,8 @@
# Set update schedule for GitHub Actions
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every weekday
interval: "weekly"

77
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,77 @@
---
name: Build
on: [push, pull_request]
jobs:
build-msvc:
name: Build Windows
runs-on: windows-latest
env:
BUILD_TOOLS_PATH: C:\apps\build-tools\
steps:
- run: echo $env:BUILD_TOOLS_PATH | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- uses: actions/checkout@v2.3.4
with:
submodules: true
- name: Install JOM
shell: cmake -P {0}
run: |
file(MAKE_DIRECTORY $ENV{BUILD_TOOLS_PATH})
file(DOWNLOAD http://prdownloads.sourceforge.net/rigs-of-rods/build-tools.zip "$ENV{TMP}/build-tools.zip" SHOW_PROGRESS)
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf "$ENV{TMP}/build-tools.zip" WORKING_DIRECTORY "$ENV{BUILD_TOOLS_PATH}")
- name: Enable Developer Command Prompt
uses: ilammy/msvc-dev-cmd@v1.8.0
- name: Cache Qt
id: cache-qt
uses: actions/cache@v1
with:
path: ../Qt
key: ${{ runner.os }}-QtCache
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
cached: ${{ steps.cache-qt.outputs.cache-hit }}
modules: qtwebengine
- name: Build
run: |
mkdir build
cd build
cmake -G"NMake Makefiles JOM" ..
jom
shell: cmd
build-gcc:
name: Build Linux
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.3.4
with:
submodules: true
- name: Cache Qt
id: cache-qt
uses: actions/cache@v1
with:
path: ../Qt
key: ${{ runner.os }}-QtCache
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
cached: ${{ steps.cache-qt.outputs.cache-hit }}
modules: qtwebengine
- name: Build
run: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j8
shell: bash

2
.gitignore vendored
View File

@ -43,3 +43,5 @@ target_wrapper.*
CMakeLists.txt.user*
*.qm
/build*
.idea/

View File

@ -1,10 +0,0 @@
dist: bionic
language: cpp
install:
- sudo apt-get update
- sudo apt-get install qt5-default qtwebengine5-dev qttools5-dev-tools -y
script:
- qmake fuel.pro
- make

154
CMakeLists.txt Normal file
View File

@ -0,0 +1,154 @@
cmake_minimum_required(VERSION 3.10)
cmake_policy(SET CMP0087 NEW)
include(FeatureSummary)
# Setup paths
SET(RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/")
SET(LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/")
SET(ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/")
SET(EXECUTABLE_OUTPUT_PATH ${RUNTIME_OUTPUT_DIRECTORY})
SET(LIBRARY_OUTPUT_PATH ${RUNTIME_OUTPUT_DIRECTORY})
# Fix executable paths for windows
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${RUNTIME_OUTPUT_DIRECTORY})
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${RUNTIME_OUTPUT_DIRECTORY})
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${RUNTIME_OUTPUT_DIRECTORY})
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${RUNTIME_OUTPUT_DIRECTORY})
project(Fuel)
option(UPDATE_TRANSLATIONS "Update translations" OFF)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOUIC_SEARCH_PATHS "${CMAKE_SOURCE_DIR}/ui")
find_package(Qt5 COMPONENTS Core Gui WebEngineWidgets REQUIRED)
set(FORMS
ui/MainWindow.ui
ui/CommitDialog.ui
ui/FileActionDialog.ui
ui/SettingsDialog.ui
ui/FslSettingsDialog.ui
ui/CloneDialog.ui
ui/BrowserWidget.ui
ui/RevisionDialog.ui
ui/RemoteDialog.ui
ui/AboutDialog.ui)
set(SOURCES
src/main.cpp
src/MainWindow.cpp
src/CommitDialog.cpp
src/FileActionDialog.cpp
src/SettingsDialog.cpp
src/FslSettingsDialog.cpp
src/CloneDialog.cpp
src/RevisionDialog.cpp
src/Utils.cpp
src/FileTableView.cpp
src/LoggedProcess.cpp
src/BrowserWidget.cpp
src/CustomWebView.cpp
src/Fossil.cpp
src/Workspace.cpp
src/SearchBox.cpp
src/AppSettings.cpp
src/RemoteDialog.cpp
src/AboutDialog.cpp)
set(HEADERS
src/MainWindow.h
src/CommitDialog.h
src/FileActionDialog.h
src/SettingsDialog.h
src/FslSettingsDialog.h
src/CloneDialog.h
src/RevisionDialog.h
src/Utils.h
src/FileTableView.h
src/LoggedProcess.h
src/BrowserWidget.h
src/CustomWebView.h
src/Fossil.h
src/Workspace.h
src/SearchBox.h
src/AppSettings.h
src/RemoteDialog.h
src/AboutDialog.h
src/WorkspaceCommon.h)
set(RESOURCES
rsrc/resources.qrc)
set(TRANSLATIONS
intl/en_US.ts
intl/el_GR.ts
intl/de_DE.ts
intl/es_ES.ts
intl/fr_FR.ts
intl/ru_RU.ts
intl/pt_PT.ts
intl/it_IT.ts
intl/nl_NL.ts
intl/ko_KR.ts)
set_source_files_properties(${TRANSLATIONS} PROPERTIES OUTPUT_LOCATION "${RUNTIME_OUTPUT_DIRECTORY}translations")
find_package(Qt5LinguistTools)
if (Qt5LinguistTools_FOUND)
if (UPDATE_TRANSLATIONS)
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR}/ui ${CMAKE_SOURCE_DIR}/src ${TRANSLATIONS})
else ()
qt5_add_translation(QM_FILES ${TRANSLATIONS})
endif ()
install(FILES ${QM_FILES} DESTINATION ./translations)
else ()
message("Qt5LinguistTools not found")
endif ()
if (WIN32)
# clang-cl doesn't support resource files
if (NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
list(APPEND SOURCES "${CMAKE_SOURCE_DIR}/rsrc/fuel.rc")
endif ()
elseif (APPLE)
list(APPEND SOURCES "${CMAKE_SOURCE_DIR}/rsrc/icons/fuel.icns")
endif ()
add_subdirectory("${CMAKE_SOURCE_DIR}/ext/qtkeychain" EXCLUDE_FROM_ALL)
add_executable(${PROJECT_NAME}
${FORMS}
${HEADERS}
${SOURCES}
${QM_FILES}
${RESOURCES})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/ui/
${CMAKE_SOURCE_DIR}/src/)
target_link_libraries(${PROJECT_NAME} Qt5::Widgets Qt5::WebEngineCore Qt5::WebEngineWidgets qt5keychain)
if (WIN32)
set_target_properties(${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE TRUE)
get_target_property(Qt5_Core_Location Qt5::Core LOCATION)
get_filename_component(QT_BIN_DIR ${Qt5_Core_Location} DIRECTORY)
add_custom_target(copy_dll
COMMAND ${QT_BIN_DIR}/windeployqt.exe $<TARGET_FILE:${PROJECT_NAME}> --release --no-compiler-runtime --no-translations --no-opengl-sw
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
install(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION .
)
install(CODE "execute_process(COMMAND ${QT_BIN_DIR}/windeployqt.exe $<TARGET_FILE:${PROJECT_NAME}> --release --no-compiler-runtime --no-translations --no-opengl-sw --dir \${CMAKE_INSTALL_PREFIX})")
endif ()
feature_summary(WHAT ALL)

View File

@ -1,35 +0,0 @@
version: "{build}"
image: Visual Studio 2017
pull_requests:
do_not_increment_build_number: true
shallow_clone: true
install:
- cmd: >-
set QTDIR=C:\Qt\5.13\msvc2017_64
set PATH=%PATH%;%QTDIR%\bin
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
build_script:
- cmd: >-
dir
mkdir build
cd build
qmake ../fuel.pro
set cl=/MP
nmake /S /NOLOGO
windeployqt release/fuel.exe --release --no-compiler-runtime --no-opengl-sw --dir fuel-scm/
cp release/fuel.exe fuel-scm/
artifacts:
- path: build/fuel-scm
name: fuel-scm

9
ext/qtkeychain.pri Normal file
View File

@ -0,0 +1,9 @@
freebsd {
INCLUDEPATH += /usr/local/include/qt5keychain
LIBS += -lqt5keychain
} else {
unix:!android:!macx:!ios {
DEFINES += KEYCHAIN_DBUS
}
include(qtkeychain/qt5keychain.pri)
}

50
ext/qtkeychain/.gitignore vendored Normal file
View File

@ -0,0 +1,50 @@
#CMake files
CMakeCache.txt
CMakeFiles
CMakeScripts
cmake_install.cmake
#Keychain temporary files
Qt5KeychainBuildTreeSettings.cmake
Qt5KeychainConfig.cmake
Qt5KeychainConfigVersion.cmake
QtKeychainBuildTreeSettings.cmake
QtKeychainConfig.cmake
QtKeychainConfigVersion.cmake
kwallet_interface.cpp
kwallet_interface.h
kwallet_interface.moc
moc_keychain.*
moc_keychain_p.*
moc_gnomekeyring_p.*
qkeychain_export.h
qt_Qt5Keychain.pri
#Qt files
*_parameters
*.qm
#General build files
Debug
Release
Makefile
#Linux build files
libqt5keychain.*
testclient
#Windows build files
install_manifest.txt
*.manifest
*.lib
*.exe
#Mac build files
qtkeychain.xcodeproj
qtkeychain.build
#Temporary files
*.sw?
*~

View File

@ -1,195 +1,307 @@
cmake_minimum_required(VERSION 2.8)
project(qtkeychain)
cmake_minimum_required(VERSION 3.3)
###
set(QTKEYCHAIN_VERSION 0.12.90)
set(QTKEYCHAIN_SOVERSION 1)
set(QTKEYCHAIN_VERSION 0.5.90)
set(QTKEYCHAIN_SOVERSION 0)
project(qtkeychain VERSION ${QTKEYCHAIN_VERSION} LANGUAGES CXX)
# Enable C++11
SET(CMAKE_CXX_STANDARD 11)
include(FindPkgConfig)
###
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${PROJECT_SOURCE_DIR}/cmake/Modules")
include(GNUInstallDirs)
include(GenerateExportHeader)
include(CMakePackageConfigHelpers)
include(ECMSetupVersion)
include(ECMGeneratePriFile)
option(BUILD_WITH_QT4 "Build qtkeychain with Qt4 no matter if Qt5 was found" OFF)
option(BUILD_WITH_QT6 "Build qtkeychain with Qt 6" OFF)
option(BUILD_TEST_APPLICATION "Build test application" ON)
option(BUILD_TRANSLATIONS "Build translations" ON)
option(QTKEYCHAIN_STATIC "Build static library" OFF)
if (CMAKE_SYSTEM_NAME STREQUAL Android)
set(ANDROID 1)
endif ()
if( NOT BUILD_WITH_QT4 )
# try Qt5 first, and prefer that if found
find_package(Qt5Core QUIET)
endif()
if (CMAKE_SYSTEM_NAME STREQUAL Haiku)
set(HAIKU 1)
endif ()
if (Qt5Core_FOUND)
set(QTKEYCHAIN_VERSION_INFIX 5)
if(UNIX AND NOT APPLE)
find_package(Qt5DBus REQUIRED)
include_directories(${Qt5DBus_INCLUDE_DIRS})
set(QTDBUS_LIBRARIES ${Qt5DBus_LIBRARIES})
macro(qt_add_dbus_interface)
qt5_add_dbus_interface(${ARGN})
if (WIN32)
option(USE_CREDENTIAL_STORE "Build with windows CredentialStore support" ON)
if (USE_CREDENTIAL_STORE)
add_definitions(-DUSE_CREDENTIAL_STORE=1)
endif ()
endif ()
if (NOT BUILD_WITH_QT6)
find_package(Qt5 COMPONENTS Core REQUIRED)
endif ()
if (Qt5Core_FOUND AND NOT BUILD_WITH_QT6)
set(QTKEYCHAIN_VERSION_INFIX 5)
if (ANDROID)
if (Qt5Core_VERSION VERSION_LESS 5.7)
find_package(Qt5 COMPONENTS Core REQUIRED Private)
include_directories(${Qt5Core_PRIVATE_INCLUDE_DIRS})
endif ()
find_package(Qt5 COMPONENTS AndroidExtras REQUIRED)
include_directories(${Qt5AndroidExtras_INCLUDE_DIRS})
set(QTANDROIDEXTRAS_LIBRARIES ${Qt5AndroidExtras_LIBRARIES})
endif ()
if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT HAIKU)
find_package(Qt5 COMPONENTS DBus REQUIRED)
include_directories(${Qt5DBus_INCLUDE_DIRS})
set(QTDBUS_LIBRARIES ${Qt5DBus_LIBRARIES})
macro(qt_add_dbus_interface)
qt5_add_dbus_interface(${ARGN})
endmacro()
endif ()
if (BUILD_TRANSLATIONS)
find_package(Qt5 COMPONENTS LinguistTools REQUIRED)
macro(qt_add_translation)
qt5_add_translation(${ARGN})
endmacro(qt_add_translation)
macro(qt_create_translation)
qt5_create_translation(${ARGN})
endmacro(qt_create_translation)
endif ()
macro(qt_wrap_cpp)
qt5_wrap_cpp(${ARGN})
endmacro()
endif()
find_package(Qt5LinguistTools REQUIRED)
macro(qt_add_translation)
qt5_add_translation(${ARGN})
endmacro(qt_add_translation)
macro(qt_create_translation)
qt5_create_translation(${ARGN})
endmacro(qt_create_translation)
macro(qt_wrap_cpp)
qt5_wrap_cpp(${ARGN})
endmacro()
set(QTCORE_LIBRARIES ${Qt5Core_LIBRARIES})
include_directories(${Qt5Core_INCLUDE_DIRS})
set(QTCORE_LIBRARIES ${Qt5Core_LIBRARIES})
include_directories(${Qt5Core_INCLUDE_DIRS})
else ()
find_package(Qt6 COMPONENTS Core REQUIRED)
set(QTKEYCHAIN_VERSION_INFIX 6)
if (Qt5_POSITION_INDEPENDENT_CODE)
if (CMAKE_VERSION VERSION_LESS 2.8.9) # TODO remove once we increase the cmake requirement
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
else()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
endif()
else()
set(QTKEYCHAIN_VERSION_INFIX "")
if(UNIX AND NOT APPLE)
find_package(Qt4 COMPONENTS QtCore QtDBus REQUIRED)
set(QTDBUS_LIBRARIES ${QT_QTDBUS_LIBRARY})
macro(qt_add_dbus_interface)
qt4_add_dbus_interface(${ARGN})
if (ANDROID)
find_package(Qt6 COMPONENTS AndroidExtras REQUIRED)
include_directories(${Qt6AndroidExtras_INCLUDE_DIRS})
set(QTANDROIDEXTRAS_LIBRARIES ${Qt6AndroidExtras_LIBRARIES})
endif ()
if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT HAIKU)
find_package(Qt6 COMPONENTS DBus REQUIRED)
include_directories(${Qt6DBus_INCLUDE_DIRS})
set(QTDBUS_LIBRARIES ${Qt6DBus_LIBRARIES})
macro(qt_add_dbus_interface)
qt6_add_dbus_interface(${ARGN})
endmacro()
endif ()
if (BUILD_TRANSLATIONS)
find_package(Qt6 COMPONENTS LinguistTools REQUIRED)
macro(qt_add_translation)
qt6_add_translation(${ARGN})
endmacro(qt_add_translation)
macro(qt_create_translation)
qt6_create_translation(${ARGN})
endmacro(qt_create_translation)
endif ()
macro(qt_wrap_cpp)
qt6_wrap_cpp(${ARGN})
endmacro()
else()
find_package(Qt4 COMPONENTS QtCore REQUIRED)
endif()
include_directories(${QT_INCLUDES})
set(QTCORE_LIBRARIES ${QT_QTCORE_LIBRARY})
macro(qt_add_translation)
qt4_add_translation(${ARGN})
endmacro(qt_add_translation)
macro(qt_create_translation)
qt4_create_translation(${ARGN})
endmacro(qt_create_translation)
macro(qt_wrap_cpp)
qt4_wrap_cpp(${ARGN})
endmacro()
endif()
set(QTCORE_LIBRARIES ${Qt6Core_LIBRARIES})
endif ()
include_directories(${CMAKE_CURRENT_BINARY_DIR})
list(APPEND qtkeychain_LIBRARIES ${QTCORE_LIBRARIES})
set(qtkeychain_SOURCES
keychain.cpp
)
keychain.cpp
qkeychain_export.h
keychain.h
)
ADD_DEFINITIONS( -Wall )
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)
endif ()
if(WIN32)
if (WIN32)
list(APPEND qtkeychain_SOURCES keychain_win.cpp)
list(APPEND qtkeychain_LIBRARIES crypt32)
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 (MINGW)
add_definitions(-O2)
endif ()
endif ()
if(APPLE)
list(APPEND qtkeychain_SOURCES keychain_mac.cpp)
if (APPLE)
list(APPEND qtkeychain_SOURCES keychain_apple.mm)
list(APPEND qtkeychain_LIBRARIES "-framework Foundation" "-framework Security")
endif ()
find_library(COREFOUNDATION_LIBRARY CoreFoundation)
list(APPEND qtkeychain_LIBRARIES ${COREFOUNDATION_LIBRARY})
if (HAIKU)
list(APPEND qtkeychain_SOURCES keychain_haiku.cpp)
find_library(SECURITY_LIBRARY Security)
list(APPEND qtkeychain_LIBRARIES ${SECURITY_LIBRARY})
endif()
find_library(BE_LIBRARY be REQUIRED)
list(APPEND qtkeychain_LIBRARIES ${BE_LIBRARY})
endif ()
if(UNIX AND NOT APPLE)
list(APPEND qtkeychain_SOURCES keychain_unix.cpp gnomekeyring.cpp)
if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT HAIKU)
option(LIBSECRET_SUPPORT "Build with libsecret support" ON)
if (LIBSECRET_SUPPORT)
pkg_check_modules(LIBSECRET libsecret-1)
if (LIBSECRET_FOUND)
add_definitions(-DHAVE_LIBSECRET=1)
endif ()
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)
qt_add_dbus_interface(qtkeychain_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/org.kde.KWallet.xml kwallet_interface KWalletInterface)
list(APPEND qtkeychain_LIBRARIES ${QTDBUS_LIBRARIES})
endif()
endif ()
QT_WRAP_CPP(qtkeychain_MOC_OUTFILES keychain.h keychain_p.h)
if (ANDROID)
list(APPEND qtkeychain_SOURCES keychain_android.cpp androidkeystore.cpp plaintextstore.cpp)
list(APPEND qtkeychain_LIBRARIES ${QTANDROIDEXTRAS_LIBRARIES})
endif ()
QT_WRAP_CPP(qtkeychain_MOC_OUTFILES keychain.h keychain_p.h gnomekeyring_p.h)
set(qtkeychain_TR_FILES
translations/qtkeychain_de.ts
translations/qtkeychain_ro.ts
)
translations/qtkeychain_de.ts
translations/qtkeychain_fr.ts
translations/qtkeychain_ro.ts
translations/qtkeychain_ru.ts
translations/qtkeychain_zh.ts
)
file(GLOB qtkeychain_TR_SOURCES *.cpp *.h *.ui)
qt_create_translation(qtkeychain_MESSAGES ${qtkeychain_TR_SOURCES} ${qtkeychain_TR_FILES})
qt_add_translation(qtkeychain_QM_FILES ${qtkeychain_TR_FILES})
add_custom_target(messages DEPENDS ${qtkeychain_MESSAGES})
add_custom_target(translations DEPENDS ${qtkeychain_QM_FILES})
if (BUILD_TRANSLATIONS)
qt_create_translation(qtkeychain_MESSAGES ${qtkeychain_TR_SOURCES} ${qtkeychain_TR_FILES})
qt_add_translation(qtkeychain_QM_FILES ${qtkeychain_TR_FILES})
add_custom_target(messages DEPENDS ${qtkeychain_MESSAGES})
add_custom_target(translations DEPENDS ${qtkeychain_QM_FILES})
if(NOT QT_TRANSLATIONS_DIR)
# If this directory is missing, we are in a Qt5 environment.
# Extract the qmake executable location
get_target_property(QT5_QMAKE_EXECUTABLE Qt5::qmake IMPORTED_LOCATION)
# Ask Qt5 where to put the translations
execute_process( COMMAND ${QT5_QMAKE_EXECUTABLE} -query QT_INSTALL_TRANSLATIONS
OUTPUT_VARIABLE qt_translations_dir OUTPUT_STRIP_TRAILING_WHITESPACE )
# make sure we have / and not \ as qmake gives on windows
FILE(TO_CMAKE_PATH "${qt_translations_dir}" qt_translations_dir)
SET(QT_TRANSLATIONS_DIR ${qt_translations_dir} CACHE PATH "The
location of the Qt translations" FORCE)
endif()
if (QTKEYCHAIN_VERSION_INFIX EQUAL 5 AND QT_TRANSLATIONS_DIR AND NOT QTKEYCHAIN_TRANSLATIONS_DIR)
# Back compatibility with pre-0.11 versions
message(WARNING "QT_TRANSLATIONS_DIR is deprecated, use QTKEYCHAIN_TRANSLATIONS_DIR instead")
set(QTKEYCHAIN_TRANSLATIONS_DIR ${QT_TRANSLATIONS_DIR}
CACHE PATH "The location of the QtKeychain translations" FORCE)
else ()
set(QTKEYCHAIN_TRANSLATIONS_DIR
${CMAKE_INSTALL_DATADIR}/qt${QTKEYCHAIN_VERSION_INFIX}keychain/translations
CACHE PATH "The location of the QtKeychain translations")
endif ()
install(FILES ${qtkeychain_QM_FILES}
DESTINATION ${QT_TRANSLATIONS_DIR})
install(FILES ${qtkeychain_QM_FILES}
DESTINATION ${QTKEYCHAIN_TRANSLATIONS_DIR})
endif (BUILD_TRANSLATIONS)
set(QTKEYCHAIN_TARGET_NAME qt${QTKEYCHAIN_VERSION_INFIX}keychain)
if(NOT QTKEYCHAIN_STATIC)
if (NOT QTKEYCHAIN_STATIC)
add_library(${QTKEYCHAIN_TARGET_NAME} SHARED ${qtkeychain_SOURCES} ${qtkeychain_MOC_OUTFILES} ${qtkeychain_QM_FILES})
set_target_properties(${QTKEYCHAIN_TARGET_NAME} PROPERTIES COMPILE_DEFINITIONS QKEYCHAIN_BUILD_QKEYCHAIN_LIB)
target_link_libraries(${QTKEYCHAIN_TARGET_NAME} ${qtkeychain_LIBRARIES})
else()
else ()
add_library(${QTKEYCHAIN_TARGET_NAME} STATIC ${qtkeychain_SOURCES} ${qtkeychain_MOC_OUTFILES} ${qtkeychain_QM_FILES})
set_target_properties(${QTKEYCHAIN_TARGET_NAME} PROPERTIES COMPILE_DEFINITIONS QKEYCHAIN_STATICLIB)
endif()
endif ()
if (WIN32)
set_target_properties(${QTKEYCHAIN_TARGET_NAME} PROPERTIES DEBUG_POSTFIX "d")
endif ()
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
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR}>"
$<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}
MACOSX_RPATH 1
INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}"
)
VERSION ${QTKEYCHAIN_VERSION}
SOVERSION ${QTKEYCHAIN_SOVERSION}
MACOSX_RPATH 1
INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}"
INSTALL_RPATH_USE_LINK_PATH TRUE
)
install(FILES keychain.h qkeychain_export.h
install(FILES keychain.h ${CMAKE_CURRENT_BINARY_DIR}/qkeychain_export.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/qt${QTKEYCHAIN_VERSION_INFIX}keychain/
)
)
install(TARGETS ${QTKEYCHAIN_TARGET_NAME}
EXPORT Qt${QTKEYCHAIN_VERSION_INFIX}KeychainLibraryDepends
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
EXPORT Qt${QTKEYCHAIN_VERSION_INFIX}KeychainLibraryDepends
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
add_executable( testclient testclient.cpp )
target_link_libraries( testclient ${QTKEYCHAIN_TARGET_NAME})
if (BUILD_TEST_APPLICATION)
add_executable(testclient testclient.cpp)
target_link_libraries(testclient ${QTKEYCHAIN_TARGET_NAME})
endif ()
###
### CMake config file
###
export(TARGETS ${QTKEYCHAIN_TARGET_NAME} FILE "${PROJECT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainLibraryDepends.cmake")
export(PACKAGE Qt${QTKEYCHAIN_VERSION_INFIX}Keychain)
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/QtKeychainConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfig.cmake"
INSTALL_DESTINATION Qt${QTKEYCHAIN_VERSION_INFIX}Keychain)
ecm_setup_version("${QTKEYCHAIN_VERSION}" VARIABLE_PREFIX SNORE
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfigVersion.cmake"
SOVERSION ${QTKEYCHAIN_VERSION})
if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT HAIKU)
set(PRI_EXTRA_DEPS "dbus")
endif ()
ecm_generate_pri_file(BASE_NAME Qt${QTKEYCHAIN_VERSION_INFIX}Keychain
LIB_NAME ${QTKEYCHAIN_TARGET_NAME}
DEPS "core ${PRI_EXTRA_DEPS}"
INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}
FILENAME_VAR pri_filename)
install(FILES ${pri_filename} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
configure_file(QtKeychainBuildTreeSettings.cmake.in
"${PROJECT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainBuildTreeSettings.cmake" @ONLY)
configure_file(QtKeychainConfig.cmake.in
"${PROJECT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfig.cmake" @ONLY)
configure_file(QtKeychainConfigVersion.cmake.in
"${PROJECT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfigVersion.cmake" @ONLY)
install(EXPORT Qt${QTKEYCHAIN_VERSION_INFIX}KeychainLibraryDepends
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Qt${QTKEYCHAIN_VERSION_INFIX}Keychain"
)
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Qt${QTKEYCHAIN_VERSION_INFIX}Keychain"
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfigVersion.cmake
${CMAKE_CURRENT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfigVersion.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Qt${QTKEYCHAIN_VERSION_INFIX}Keychain
)
)

View File

@ -7,6 +7,9 @@ are met:
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

View File

@ -1,6 +1,65 @@
ChangeLog
=========
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)

View File

@ -1,4 +0,0 @@
set(QTKEYCHAIN_INCLUDE_DIRS
"@PROJECT_SOURCE_DIR@"
"@PROJECT_BINARY_DIR@"
)

View File

@ -3,19 +3,17 @@
# QTKEYCHAIN_INCLUDE_DIRS - include directories for QtKeychain
# QTKEYCHAIN_LIBRARIES - libraries to link against
# Compute paths
get_filename_component(QTKEYCHAIN_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
if(EXISTS "${QTKEYCHAIN_CMAKE_DIR}/CMakeCache.txt")
# In build tree
include("${QTKEYCHAIN_CMAKE_DIR}/Qt@QTKEYCHAIN_VERSION_INFIX@KeychainBuildTreeSettings.cmake")
else()
set(QTKEYCHAIN_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/Qt@QTKEYCHAIN_VERSION_INFIX@KeychainLibraryDepends.cmake")
include(CMakeFindDependencyMacro)
find_dependency(Qt@QTKEYCHAIN_VERSION_INFIX@Core)
if(UNIX AND NOT APPLE)
find_dependency(Qt@QTKEYCHAIN_VERSION_INFIX@DBus)
endif()
# Our library dependencies (contains definitions for IMPORTED targets)
include("${QTKEYCHAIN_CMAKE_DIR}/Qt@QTKEYCHAIN_VERSION_INFIX@KeychainLibraryDepends.cmake")
# These are IMPORTED targets created by FooBarLibraryDepends.cmake
set(QTKEYCHAIN_LIBRARIES "@QTKEYCHAIN_TARGET_NAME@")
set(QTKEYCHAIN_FOUND TRUE)
get_target_property(QTKEYCHAIN_INCLUDE_DIRS "@QTKEYCHAIN_TARGET_NAME@" INTERFACE_INCLUDE_DIRECTORIES)

View File

@ -1,11 +0,0 @@
set(PACKAGE_VERSION "@QTKEYCHAIN_VERSION@")
# Check whether the requested PACKAGE_FIND_VERSION is compatible
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()

View File

@ -1,15 +0,0 @@
QtKeychain
==========
QtKeychain is a Qt API to store passwords and other secret data securely. How the data is stored depends on the platform:
* **Mac OS X:** Passwords are stored in the OS X Keychain.
* **Linux/Unix:** If running, GNOME Keyring is used, otherwise
qtkeychain tries to use KWallet (via D-Bus), if available.
* **Windows:** Windows does not provide a service for secure storage. QtKeychain uses the Windows API function [CryptProtectData](http://msdn.microsoft.com/en-us/library/windows/desktop/aa380261%28v=vs.85%29.aspx "CryptProtectData function") to encrypt the password with the user's logon credentials. The encrypted data is then persisted via QSettings.
In unsupported environments QtKeychain will report an error. It will not store any data unencrypted unless explicitly requested (setInsecureFallback( true )).
**License:** QtKeychain is available under the [Modified BSD License](http://www.gnu.org/licenses/license-list.html#ModifiedBSD). See the file COPYING for details.

35
ext/qtkeychain/ReadMe.md Normal file
View File

@ -0,0 +1,35 @@
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.
Changes made in this fork (Chatterino/qtkeychain)
-------
Updated the .pri file to point to the right mac/apple-specific file
Added `#undef singals` in libsecret.cpp to fix compilation.

View File

@ -1,15 +0,0 @@
QtKeychain
==========
QtKeychain is a Qt API to store passwords and other secret data securely. How the data is stored depends on the platform:
* **Mac OS X:** Passwords are stored in the OS X Keychain.
* **Linux/Unix:** If running, GNOME Keyring is used, otherwise
qtkeychain tries to use KWallet (via D-Bus), if available.
* **Windows:** Windows does not provide a service for secure storage. QtKeychain uses the Windows API function [CryptProtectData](http://msdn.microsoft.com/en-us/library/windows/desktop/aa380261%28v=vs.85%29.aspx "CryptProtectData function") to encrypt the password with the user's logon credentials. The encrypted data is then persisted via QSettings.
In unsupported environments QtKeychain will report an error. It will not store any data unencrypted unless explicitly requested (setInsecureFallback( true )).
**License:** QtKeychain is available under the [Modified BSD License](http://www.gnu.org/licenses/license-list.html#ModifiedBSD). See the file COPYING for details.

View File

@ -0,0 +1,302 @@
#include "androidkeystore_p.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 7, 0)
#include "private/qjni_p.h"
#endif
#include <QAndroidJniEnvironment>
using namespace QKeychain;
using namespace android::content;
using namespace android::security;
using namespace java::io;
using namespace java::lang;
using namespace java::math;
using namespace java::util;
using namespace java::security;
using namespace java::security::spec;
using namespace javax::crypto;
using namespace javax::security::auth::x500;
using namespace javax::security::cert;
const BigInteger BigInteger::ONE = BigInteger::getStaticObjectField("java/math/BigInteger", "ONE", "Ljava/math/BigInteger;");
const int Calendar::YEAR = Calendar::getStaticField<jint>("java/util/Calendar", "YEAR");
const int Cipher::DECRYPT_MODE = Cipher::getStaticField<jint>("javax/crypto/Cipher", "DECRYPT_MODE");
const int Cipher::ENCRYPT_MODE = Cipher::getStaticField<jint>("javax/crypto/Cipher", "ENCRYPT_MODE");
namespace {
#if QT_VERSION < QT_VERSION_CHECK(5, 7, 0)
struct JNIObject
{
JNIObject(QSharedPointer<QJNIObjectPrivate> d): d(d) {}
static JNIObject fromLocalRef(jobject o)
{
return JNIObject(QSharedPointer<QJNIObjectPrivate>::create(QJNIObjectPrivate::fromLocalRef(o)));
}
jobject object() const { return d->object(); }
QSharedPointer<QJNIObjectPrivate> d;
};
#else
using JNIObject = QAndroidJniObject;
#endif
QByteArray fromArray(const jbyteArray array)
{
QAndroidJniEnvironment env;
jbyte *const bytes = env->GetByteArrayElements(array, Q_NULLPTR);
const QByteArray result(reinterpret_cast<const char *>(bytes), env->GetArrayLength(array));
env->ReleaseByteArrayElements(array, bytes, JNI_ABORT);
return result;
}
JNIObject toArray(const QByteArray &bytes)
{
QAndroidJniEnvironment env;
const int length = bytes.length();
JNIObject array = JNIObject::fromLocalRef(env->NewByteArray(length));
env->SetByteArrayRegion(static_cast<jbyteArray>(array.object()),
0, length, reinterpret_cast<const jbyte *>(bytes.constData()));
return array;
}
}
bool Object::handleExceptions()
{
QAndroidJniEnvironment env;
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
return false;
}
return true;
}
KeyPairGenerator KeyPairGenerator::getInstance(const QString &algorithm, const QString &provider)
{
return handleExceptions(callStaticObjectMethod("java/security/KeyPairGenerator", "getInstance",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/security/KeyPairGenerator;",
fromString(algorithm).object(), fromString(provider).object()));
}
KeyPair KeyPairGenerator::generateKeyPair() const
{
return handleExceptions(callObjectMethod("generateKeyPair", "()Ljava/security/KeyPair;"));
}
bool KeyPairGenerator::initialize(const AlgorithmParameterSpec &spec) const
{
callMethod<void>("initialize", "(Ljava/security/spec/AlgorithmParameterSpec;)V", spec.object());
return handleExceptions();
}
bool KeyStore::containsAlias(const QString &alias) const
{
return handleExceptions(callMethod<jboolean>("containsAlias", "(Ljava/lang/String;)Z",
fromString(alias).object()));
}
bool KeyStore::deleteEntry(const QString &alias) const
{
callMethod<void>("deleteEntry", "(Ljava/lang/String;)Z", fromString(alias).object());
return handleExceptions();
}
KeyStore KeyStore::getInstance(const QString &type)
{
return handleExceptions(callStaticObjectMethod("java/security/KeyStore", "getInstance",
"(Ljava/lang/String;)Ljava/security/KeyStore;",
fromString(type).object()));
}
KeyStore::Entry KeyStore::getEntry(const QString &alias, const KeyStore::ProtectionParameter &param) const
{
return handleExceptions(callObjectMethod("getEntry",
"(Ljava/lang/String;Ljava/security/KeyStore$ProtectionParameter;)Ljava/security/KeyStore$Entry;",
fromString(alias).object(), param.object()));
}
bool KeyStore::load(const KeyStore::LoadStoreParameter &param) const
{
callMethod<void>("load", "(Ljava/security/KeyStore$LoadStoreParameter;)V", param.object());
return handleExceptions();
}
Calendar Calendar::getInstance()
{
return handleExceptions(callStaticObjectMethod("java/util/Calendar", "getInstance",
"()Ljava/util/Calendar;"));
}
bool Calendar::add(int field, int amount) const
{
callMethod<void>("add", "(II)V", field, amount);
return handleExceptions();
}
Date Calendar::getTime() const
{
return handleExceptions(callObjectMethod("getTime", "()Ljava/util/Date;"));
}
KeyPairGeneratorSpec::Builder::Builder(const Context &context)
: Object(QAndroidJniObject("android/security/KeyPairGeneratorSpec$Builder",
"(Landroid/content/Context;)V",
context.object()))
{
handleExceptions();
}
KeyPairGeneratorSpec::Builder KeyPairGeneratorSpec::Builder::setAlias(const QString &alias) const
{
return handleExceptions(callObjectMethod("setAlias",
"(Ljava/lang/String;)Landroid/security/KeyPairGeneratorSpec$Builder;",
fromString(alias).object()));
}
KeyPairGeneratorSpec::Builder KeyPairGeneratorSpec::Builder::setSubject(const X500Principal &subject) const
{
return handleExceptions(callObjectMethod("setSubject",
"(Ljavax/security/auth/x500/X500Principal;)Landroid/security/KeyPairGeneratorSpec$Builder;",
subject.object()));
}
KeyPairGeneratorSpec::Builder KeyPairGeneratorSpec::Builder::setSerialNumber(const BigInteger &serial) const
{
return handleExceptions(callObjectMethod("setSerialNumber",
"(Ljava/math/BigInteger;)Landroid/security/KeyPairGeneratorSpec$Builder;",
serial.object()));
}
KeyPairGeneratorSpec::Builder KeyPairGeneratorSpec::Builder::setStartDate(const Date &date) const
{
return handleExceptions(callObjectMethod("setStartDate",
"(Ljava/util/Date;)Landroid/security/KeyPairGeneratorSpec$Builder;",
date.object()));
}
KeyPairGeneratorSpec::Builder KeyPairGeneratorSpec::Builder::setEndDate(const Date &date) const
{
return handleExceptions(callObjectMethod("setEndDate",
"(Ljava/util/Date;)Landroid/security/KeyPairGeneratorSpec$Builder;",
date.object()));
}
KeyPairGeneratorSpec KeyPairGeneratorSpec::Builder::build() const
{
return handleExceptions(callObjectMethod("build", "()Landroid/security/KeyPairGeneratorSpec;"));
}
X500Principal::X500Principal(const QString &name)
: Object(QAndroidJniObject("javax/security/auth/x500/X500Principal",
"(Ljava/lang/String;)V",
fromString(name).object()))
{
handleExceptions();
}
Certificate KeyStore::PrivateKeyEntry::getCertificate() const
{
return handleExceptions(callObjectMethod("getCertificate", "()Ljava/security/cert/Certificate;"));
}
PrivateKey KeyStore::PrivateKeyEntry::getPrivateKey() const
{
return handleExceptions(callObjectMethod("getPrivateKey", "()Ljava/security/PrivateKey;"));
}
PublicKey Certificate::getPublicKey() const
{
return handleExceptions(callObjectMethod("getPublicKey", "()Ljava/security/PublicKey;"));
}
ByteArrayInputStream::ByteArrayInputStream(const QByteArray &bytes)
: InputStream(QAndroidJniObject("java/io/ByteArrayInputStream", "([B)V", toArray(bytes).object()))
{
}
ByteArrayOutputStream::ByteArrayOutputStream()
: OutputStream(QAndroidJniObject("java/io/ByteArrayOutputStream"))
{
handleExceptions();
}
QByteArray ByteArrayOutputStream::toByteArray() const
{
const QAndroidJniObject wrapper = callObjectMethod<jbyteArray>("toByteArray");
if (!handleExceptions())
return QByteArray();
return fromArray(static_cast<jbyteArray>(wrapper.object()));
}
int InputStream::read() const
{
return handleExceptions(callMethod<int>("read"), -1);
}
bool OutputStream::write(const QByteArray &bytes) const
{
callMethod<void>("write", "([B)V", toArray(bytes).object());
return handleExceptions();
}
bool OutputStream::close() const
{
callMethod<void>("close");
return handleExceptions();
}
bool OutputStream::flush() const
{
callMethod<void>("flush");
return handleExceptions();
}
Cipher Cipher::getInstance(const QString &transformation)
{
return handleExceptions(callStaticObjectMethod("javax/crypto/Cipher", "getInstance",
"(Ljava/lang/String;)Ljavax/crypto/Cipher;",
fromString(transformation).object()));
}
bool Cipher::init(int opMode, const Key &key) const
{
callMethod<void>("init", "(ILjava/security/Key;)V", opMode, key.object());
return handleExceptions();
}
CipherOutputStream::CipherOutputStream(const OutputStream &stream, const Cipher &cipher)
: FilterOutputStream(QAndroidJniObject("javax/crypto/CipherOutputStream",
"(Ljava/io/OutputStream;Ljavax/crypto/Cipher;)V",
stream.object(), cipher.object()))
{
handleExceptions();
}
CipherInputStream::CipherInputStream(const InputStream &stream, const Cipher &cipher)
: FilterInputStream(QAndroidJniObject("javax/crypto/CipherInputStream",
"(Ljava/io/InputStream;Ljavax/crypto/Cipher;)V",
stream.object(), cipher.object()))
{
handleExceptions();
}

View File

@ -0,0 +1,371 @@
/******************************************************************************
* 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_ANDROIDKEYSTORE_P_H
#define QTKEYCHAIN_ANDROIDKEYSTORE_P_H
#include <QAndroidJniObject>
namespace QKeychain {
namespace javax {
namespace security {
namespace auth { namespace x500 { class X500Principal; } }
namespace cert { class Certificate; }
}
}
namespace java {
namespace lang {
class Object : protected QAndroidJniObject
{
public:
inline Object(jobject object) : QAndroidJniObject(object) {}
inline Object(const QAndroidJniObject &object) : QAndroidJniObject(object) {}
inline operator bool() const { return isValid(); }
using QAndroidJniObject::object;
using QAndroidJniObject::toString;
protected:
static bool handleExceptions();
template<typename T>
static T handleExceptions(const T &result, const T &resultOnError = T());
};
template<typename T>
inline T Object::handleExceptions(const T &result, const T &resultOnError)
{
if (!handleExceptions())
return resultOnError;
return result;
}
} // namespace lang
namespace io {
class InputStream : public java::lang::Object
{
public:
using Object::Object;
int read() const;
};
class ByteArrayInputStream : public InputStream
{
public:
using InputStream::InputStream;
explicit ByteArrayInputStream(const QByteArray &bytes);
};
class FilterInputStream : public InputStream
{
public:
using InputStream::InputStream;
};
class OutputStream : public java::lang::Object
{
public:
using Object::Object;
bool write(const QByteArray &bytes) const;
bool flush() const;
bool close() const;
};
class ByteArrayOutputStream : public OutputStream
{
public:
using OutputStream::OutputStream;
ByteArrayOutputStream();
QByteArray toByteArray() const;
};
class FilterOutputStream : public OutputStream
{
public:
using OutputStream::OutputStream;
};
} // namespace io
namespace math {
class BigInteger : public java::lang::Object
{
public:
using Object::Object;
static const BigInteger ZERO;
static const BigInteger ONE;
static const BigInteger TEN;
};
} // namespace math
namespace util {
class Date : public java::lang::Object
{
public:
using Object::Object;
};
class Calendar : public java::lang::Object
{
public:
using Object::Object;
static const int YEAR;
static const int MONTH;
static const int DAY;
static const int HOUR;
static const int MINUTE;
static const int SECOND;
static const int MILLISECOND;
static Calendar getInstance();
bool add(int field, int amount) const;
Date getTime() const;
};
} // namespace util
namespace security {
namespace spec {
class AlgorithmParameterSpec : public java::lang::Object
{
public:
using Object::Object;
};
} // namespace spec
class Key : public java::lang::Object
{
public:
using Object::Object;
};
class PrivateKey : public Key
{
public:
using Key::Key;
PrivateKey(const Key &init): Key(init) {}
};
class PublicKey : public Key
{
public:
using Key::Key;
PublicKey(const Key &init): Key(init) {}
};
class KeyPair : public java::lang::Object
{
public:
using Object::Object;
};
class KeyPairGenerator : public java::lang::Object
{
public:
using Object::Object;
static KeyPairGenerator getInstance(const QString &algorithm, const QString &provider);
KeyPair generateKeyPair() const;
bool initialize(const spec::AlgorithmParameterSpec &spec) const;
};
class KeyStore : public java::lang::Object
{
public:
class Entry : public java::lang::Object
{
public:
using Object::Object;
};
class PrivateKeyEntry : public Entry
{
public:
using Entry::Entry;
inline PrivateKeyEntry(const Entry &init): Entry(init) {}
javax::security::cert::Certificate getCertificate() const;
java::security::PrivateKey getPrivateKey() const;
};
class LoadStoreParameter : public java::lang::Object
{
public:
using Object::Object;
};
class ProtectionParameter : public java::lang::Object
{
public:
using Object::Object;
};
using Object::Object;
bool containsAlias(const QString &alias) const;
bool deleteEntry(const QString &alias) const;
static KeyStore getInstance(const QString &type);
Entry getEntry(const QString &alias, const ProtectionParameter &param = Q_NULLPTR) const;
bool load(const LoadStoreParameter &param = Q_NULLPTR) const;
};
namespace interfaces {
class RSAPrivateKey : public PrivateKey
{
public:
using PrivateKey::PrivateKey;
RSAPrivateKey(const PrivateKey &init): PrivateKey(init) {}
};
class RSAPublicKey : public PublicKey
{
public:
using PublicKey::PublicKey;
RSAPublicKey(const PublicKey &init): PublicKey(init) {}
};
} // namespace interfaces
} // namespace security
} // namespace java
namespace android {
namespace content {
class Context : public java::lang::Object
{
public:
using Object::Object;
};
} // namespace content
namespace security {
class KeyPairGeneratorSpec : public java::security::spec::AlgorithmParameterSpec
{
public:
class Builder : public java::lang::Object
{
public:
using Object::Object;
explicit Builder(const android::content::Context &context);
Builder setAlias(const QString &alias) const;
Builder setSubject(const javax::security::auth::x500::X500Principal &subject) const;
Builder setSerialNumber(const java::math::BigInteger &serial) const;
Builder setStartDate(const java::util::Date &date) const;
Builder setEndDate(const java::util::Date &date) const;
KeyPairGeneratorSpec build() const;
};
using AlgorithmParameterSpec::AlgorithmParameterSpec;
};
} // namespace security
} // namespace android
namespace javax {
namespace crypto {
class Cipher : public java::lang::Object
{
public:
static const int DECRYPT_MODE;
static const int ENCRYPT_MODE;
using Object::Object;
static Cipher getInstance(const QString &transformation);
bool init(int opMode, const java::security::Key &key) const;
};
class CipherInputStream : public java::io::FilterInputStream
{
public:
using FilterInputStream::FilterInputStream;
explicit CipherInputStream(const InputStream &stream, const Cipher &cipher);
};
class CipherOutputStream : public java::io::FilterOutputStream
{
public:
using FilterOutputStream::FilterOutputStream;
explicit CipherOutputStream(const OutputStream &stream, const Cipher &cipher);
};
}
namespace security {
namespace auth {
namespace x500 {
class X500Principal;
class X500Principal : public java::lang::Object
{
public:
using Object::Object;
explicit X500Principal(const QString &name);
};
} // namespace x500
} // namespace auth
namespace cert {
class Certificate : public java::lang::Object
{
public:
using Object::Object;
java::security::PublicKey getPublicKey() const;
};
} // namespace cert
} // namespace security
} // namespace javax
} // namespace QKeychain
#endif // QTKEYCHAIN_ANDROIDKEYSTORE_P_H

View File

@ -0,0 +1,31 @@
version: '{build}'
build_script:
- ps: |
$ErrorActionPreference="Stop"
Import-Module $env:APPVEYOR_BUILD_FOLDER\appveyorHelp.psm1
Init @("ninja")
mkdir -Force $env:APPVEYOR_BUILD_FOLDER\work\build\$env:APPVEYOR_PROJECT_NAME
cd $env:APPVEYOR_BUILD_FOLDER\work\build\$env:APPVEYOR_PROJECT_NAME
LogExec cmake -G"Ninja" $env:APPVEYOR_BUILD_FOLDER -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$CMAKE_INSTALL_ROOT"
CmakeImageInstall
test: off
cache:
- work\install -> appveyor.yml
- C:\ProgramData\chocolatey\bin -> appveyor.yml
- C:\ProgramData\chocolatey\lib -> appveyor.yml
environment:
QT_VER: 5.7
matrix:
- COMPILER: msvc2015
- COMPILER: msvc2015_64
- COMPILER: mingw53_32

View File

@ -0,0 +1,362 @@
Write-Host "Appveyor Helper scrips https://github.com/TheOneRing/appVeyorHelp"
$ErrorActionPreference="Stop"
$script:INSTALL_DIR="$env:APPVEYOR_BUILD_FOLDER\work\install"
$CMAKE_INSTALL_ROOT="`"$INSTALL_DIR`"" -replace "\\", "/"
$env:PATH="$env:PATH;$script:INSTALL_DIR"
if(!$env:CI -eq "true")
{
function Push-AppveyorArtifact()
{
Write-Host "Push-AppveyorArtifact $ARGS"
}
function Start-FileDownload([string] $url, [string] $out)
{
if(!$out)
{
$out = $url.SubString($url.LastIndexOf("/"))
}
wget $url -Outfile $out
}
}
function LogExec()
{
$OldErrorActionPreference=$ErrorActionPreference
$ErrorActionPreference="Continue"
$LastExitCode = 0
Write-Host $Args[0], $Args[1..(($Args.Count)-1)]
& $Args[0] $Args[1..(($Args.Count)-1)]
if(!$LastExitCode -eq 0)
{
exit $LastExitCode
}
$ErrorActionPreference=$OldErrorActionPreference
}
#Set environment variables for Visual Studio Command Prompt
#http://stackoverflow.com/questions/2124753/how-i-can-use-powershell-with-the-visual-studio-command-prompt
function BAT-CALL([string] $path, [string] $arg)
{
Write-Host "Calling `"$path`" `"$arg`""
cmd /c "$path" "$arg" `&`& set `|`| exit 1|
foreach {
if ($_ -match "=") {
$v = $_.split("=")
#Write-Host "ENV:\$($v[0])=$($v[1])"
set-item -force -path "ENV:\$($v[0])" -value "$($v[1])"
}
}
if($LastExitCode -eq 1) {
Write-Error "$path not found."
}
}
function Get-QtDir()
{
$ver = 5.5
if($env:QT_VER)
{
$ver = $env:QT_VER
}
return "C:\Qt\$ver\$env:COMPILER\"
}
function SETUP-QT()
{
[string] $compiler=$env:COMPILER
$qtDir = Get-QtDir
$script:QT_BINARY_DIRS = @($qtDir)
BAT-CALL "$qtDir\bin\qtenv2.bat"
if ($compiler.StartsWith("mingw49"))
{
#remove sh.exe from path
$env:PATH=$env:PATH -replace "C:\\Program Files \(x86\)\\Git\\bin", ""
$script:MAKE="mingw32-make"
$script:CMAKE_GENERATOR="MinGW Makefiles"
$script:STRIP=@("strip", "-s")
$script:QT_BINARY_DIRS += (Resolve-Path "$qtDir\..\..\Tools\mingw492_32\opt\")
}
elseif ($compiler.StartsWith("msvc"))
{
$arch = "x86"
if($compiler.EndsWith("64"))
{
$arch = "amd64"
}
$compilerDirs = @{
"msvc2010" = "VS100COMNTOOLS";
"msvc2012" = "VS110COMNTOOLS";
"msvc2013" = "VS120COMNTOOLS";
"msvc2015" = "VS140COMNTOOLS"
}
$compilerVar = $compilerDirs[$compiler.Split("_")[0]]
$compilerDir = (get-item -path "env:\$($compilerVar)").Value
BAT-CALL "$compilerDir\..\..\VC\vcvarsall.bat" $arch
$script:MAKE="nmake"
$script:CMAKE_GENERATOR="NMake Makefiles"
if($arch -eq "x86")
{
$script:QT_BINARY_DIRS += ("C:\OpenSSL-Win32")
}
else
{
$script:QT_BINARY_DIRS += ("C:\OpenSSL-Win64")
}
}
}
function Install-ChocolatelyModule([string] $module, [string[]] $myargs)
{
Write-Host "Install chocolately package $module"
LogExec cinst $module @myargs -y
}
function Install-CmakeGitModule([string] $url, [hashtable] $arguments)
{
$module = $url.SubString($url.LastIndexOf("/")+1)
$module = $module.Substring(0,$module.Length - 4)
if(!$arguments.Contains("branch"))
{
$arguments["branch"] = "master"
}
if(!$arguments.Contains("buildType"))
{
$arguments["buildType"] = "Release"
}
mkdir -Force $env:APPVEYOR_BUILD_FOLDER\work\build\$module
pushd $env:APPVEYOR_BUILD_FOLDER\work\git
LogExec git clone -q --depth 1 --branch ([string]$arguments["branch"]) $url $module
popd
pushd $env:APPVEYOR_BUILD_FOLDER\work\build\$module
LogExec cmake -G $script:CMAKE_GENERATOR ("-DCMAKE_BUILD_TYPE=`"{0}`"" -f [string]$arguments["buildType"]) $env:APPVEYOR_BUILD_FOLDER\work\git\$module -DCMAKE_INSTALL_PREFIX="$CMAKE_INSTALL_ROOT" $arguments["options"]
LogExec $script:MAKE install
popd
}
function Init([string[]] $chocoDeps, [System.Collections.Specialized.OrderedDictionary] $cmakeModules)
{
$script:MAKE=""
$script:CMAKE_GENERATOR=""
$script:STRIP=$null
mkdir -Force $env:APPVEYOR_BUILD_FOLDER\work\image | Out-Null
mkdir -Force $env:APPVEYOR_BUILD_FOLDER\work\build | Out-Null
SETUP-QT
if($chocoDeps -contains "ninja") {
$script:CMAKE_GENERATOR="Ninja"
$script:MAKE="ninja"
}
if ( !(Test-Path "$env:APPVEYOR_BUILD_FOLDER\work\install" ) )
{
mkdir -Force $env:APPVEYOR_BUILD_FOLDER\work\install | Out-Null
mkdir -Force $env:APPVEYOR_BUILD_FOLDER\work\git | Out-Null
foreach($module in $chocoDeps) {
if($module -eq "nsis")
{
Install-ChocolatelyModule "nsis.portable" @("-pre")
continue
}
Install-ChocolatelyModule $module
}
foreach($key in $cmakeModules.Keys) {
Install-CmakeGitModule $key $cmakeModules[$key]
}
[string] $compiler=$env:COMPILER
if($compiler.StartsWith("msvc"))
{
Write-Host "Downloading vcredist.exe"
if ($compiler.StartsWith("msvc2015"))
{
if($compiler.EndsWith("64"))
{
Start-FileDownload https://download.microsoft.com/download/9/3/F/93FCF1E7-E6A4-478B-96E7-D4B285925B00/vc_redist.x64.exe $env:APPVEYOR_BUILD_FOLDER\work\install\vcredist.exe
}
else
{
Start-FileDownload https://download.microsoft.com/download/9/3/F/93FCF1E7-E6A4-478B-96E7-D4B285925B00/vc_redist.x86.exe $env:APPVEYOR_BUILD_FOLDER\work\install\vcredist.exe
}
}
else
{
if($compiler.EndsWith("64"))
{
Start-FileDownload http://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3/vcredist_x64.exe $env:APPVEYOR_BUILD_FOLDER\work\install\vcredist.exe
}
else
{
Start-FileDownload http://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3/vcredist_x86.exe $env:APPVEYOR_BUILD_FOLDER\work\install\vcredist.exe
}
}
}
}
}
function relativePath([string] $root, [string] $path)
{
pushd $root
$out = Resolve-Path -Relative $path
popd
return $out
}
function StripFile([string] $name)
{
if($script:STRIP) {
if( $name.EndsWith(".dll") -or $name.EndsWith(".exe"))
{
Write-Host "strip file $name"
LogExec @script:STRIP $name
}
}
}
function Get-DeployImageName()
{
$version = Get-Version
if($env:APPVEYOR_REPO_TAG -eq "true") {
return "$env:APPVEYOR_PROJECT_NAME`_$version`_Qt$env:QT_VER`_$env:COMPILER"
}else{
return "$env:APPVEYOR_PROJECT_NAME`_$env:APPVEYOR_REPO_BRANCH`_$version`_Qt$env:QT_VER`_$env:COMPILER"
}
}
function Get-Version()
{
if($env:APPVEYOR_REPO_TAG -eq "true") {
return $env:APPVEYOR_REPO_TAG_NAME
}else{
$commit = ([string]$env:APPVEYOR_REPO_COMMIT).SubString(0,6)
return $commit
}
}
function CmakeImageInstall()
{
$imageName = Get-DeployImageName
$destDir = "$env:APPVEYOR_BUILD_FOLDER\work\cmakeDeployImage\$imageName"
$env:DESTDIR = $destDir
LogExec $script:MAKE install
$env:DESTDIR = $null
if(!$LastExitCode -eq 0)
{
Write-Error "Build Failed"
}
$env:DESTDIR=$null
$prefix=$script:INSTALL_DIR
if( $prefix.substring(1,1) -eq ":")
{
$prefix=$prefix.substring(3)
}
Write-Host "move $destDir\$prefix to $destDir"
mv -Force "$destDir\$prefix\*" "$destDir"
$rootLeftOver = $prefix.substring(0, $prefix.indexOf("\"))
rm -Recurse "$destDir\$rootLeftOver"
}
function CreateDeployImage([string[]] $whiteList, [string[]] $blackList)
{
$imageName = Get-DeployImageName
$deployPath = "$env:APPVEYOR_BUILD_FOLDER\work\deployImage\$imageName"
function copyWithWhitelist([string] $root)
{
$files = ls $root -Recurse
foreach($fileName in $files.FullName)
{
$relPath = (relativePath $root $fileName).SubString(2)
if($whiteList | Where {$relPath -match $_})
{
if($blackList | Where {$relPath -match $_})
{
continue
}
if(!(Test-Path $deployPath\$relPath))
{
Write-Host "copy $fileName to $deployPath\$relPath"
mkdir -Force (Split-Path -Parent $deployPath\$relPath) | Out-Null
cp -Force $fileName $deployPath\$relPath
StripFile $deployPath\$relPath
}
}
}
}
Write-Host "CreateDeployImage $imageName"
mkdir $deployPath | Out-Null
copyWithWhitelist "$env:APPVEYOR_BUILD_FOLDER\work\cmakeDeployImage\$imageName"
copyWithWhitelist "$env:APPVEYOR_BUILD_FOLDER\work\install\"
foreach($folder in $script:QT_BINARY_DIRS)
{
copyWithWhitelist $folder
}
Write-Host "Deploy path $deployPath"
return $deployPath
}
function 7ZipDeployImage()
{
$imageName = Get-DeployImageName
LogExec 7za a "$env:APPVEYOR_BUILD_FOLDER\work\deployImage\$imageName.7z" "$env:APPVEYOR_BUILD_FOLDER\work\deployImage\$imageName"
Push-AppveyorArtifact "$env:APPVEYOR_BUILD_FOLDER\work\deployImage\$imageName.7z"
}
function NsisDeployImage([string] $scriptName)
{
$imageName = Get-DeployImageName
$installerName = "$env:APPVEYOR_BUILD_FOLDER\work\deployImage\$imageName.exe"
$version = Get-Version
if(([string]$env:COMPILER).StartsWith("msvc"))
{
$redist = "$env:APPVEYOR_BUILD_FOLDER\work\install\vcredist.exe"
}else{
$redist = "none"
}
if($env:COMPILER.EndsWith("64"))
{
$defaultinstdir = "`$PROGRAMFILES64"
}else{
$defaultinstdir = "`$PROGRAMFILES"
}
LogExec makensis.exe /DgitDir=$env:APPVEYOR_BUILD_FOLDER /Dsetupname=$installerName /Dcaption=$imageName /Dversion=$version /Dcompiler=$env:COMPILER /Dvcredist=$redist /Ddefaultinstdir=$defaultinstdir /Dsrcdir=$env:APPVEYOR_BUILD_FOLDER\work\deployImage\$imageName $scriptName
Push-AppveyorArtifact $installerName
}
# based on http://thesurlyadmin.com/2013/01/07/remove-empty-directories-recursively/
function DeleteEmptyFodlers([string] $root)
{
$Folders = @()
foreach($Folder in (Get-ChildItem -Path $root -Recurse -Directory))
{
$Folders += New-Object PSObject -Property @{
Object = $Folder
Depth = ($Folder.FullName.Split("\")).Count
}
}
$Folders = $Folders | Sort Depth -Descending
foreach($Folder in $Folders)
{
If ($Folder.Object.GetFileSystemInfos().Count -eq 0)
{
Write-Host "Delete empty dir:" $Folder.Object.FullName
Remove-Item -Path $Folder.Object.FullName -Force
}
}
}
Write-Host "CMAKE_INSTALL_ROOT: $CMAKE_INSTALL_ROOT"
Write-Host "Image-Name: ", (Get-DeployImageName)
Export-ModuleMember -Function @("Init","CmakeImageInstall", "CreateDeployImage", "LogExec", "7ZipDeployImage", "NsisDeployImage", "DeleteEmptyFodlers") -Variable @("CMAKE_INSTALL_ROOT")

View File

@ -0,0 +1,199 @@
#.rst:
# ECMGeneratePriFile
# ------------------
#
# Generate a ``.pri`` file for the benefit of qmake-based projects.
#
# As well as the function below, this module creates the cache variable
# ``ECM_MKSPECS_INSTALL_DIR`` and sets the default value to ``mkspecs/modules``.
# This assumes Qt and the current project are both installed to the same
# non-system prefix. Packagers who use ``-DCMAKE_INSTALL_PREFIX=/usr`` will
# certainly want to set ``ECM_MKSPECS_INSTALL_DIR`` to something like
# ``share/qt5/mkspecs/modules``.
#
# The main thing is that this should be the ``modules`` subdirectory of either
# the default qmake ``mkspecs`` directory or of a directory that will be in the
# ``$QMAKEPATH`` environment variable when qmake is run.
#
# ::
#
# ecm_generate_pri_file(BASE_NAME <baseName>
# LIB_NAME <libName>
# [DEPS "<dep> [<dep> [...]]"]
# [FILENAME_VAR <filename_variable>]
# [INCLUDE_INSTALL_DIR <dir>]
# [LIB_INSTALL_DIR <dir>])
#
# If your CMake project produces a Qt-based library, you may expect there to be
# applications that wish to use it that use a qmake-based build system, rather
# than a CMake-based one. Creating a ``.pri`` file will make use of your
# library convenient for them, in much the same way that CMake config files make
# things convenient for CMake-based applications.
#
# ecm_generate_pri_file() generates just such a file. It requires the
# ``PROJECT_VERSION_STRING`` variable to be set. This is typically set by
# :module:`ECMSetupVersion`, although the project() command in CMake 3.0.0 and
# later can also set this.
#
# BASE_NAME specifies the name qmake project (.pro) files should use to refer to
# the library (eg: KArchive). LIB_NAME is the name of the actual library to
# link to (ie: the first argument to add_library()). DEPS is a space-separated
# list of the base names of other libraries (for Qt libraries, use the same
# names you use with the ``QT`` variable in a qmake project file, such as "core"
# for QtCore). FILENAME_VAR specifies the name of a variable to store the path
# to the generated file in.
#
# INCLUDE_INSTALL_DIR is the path (relative to ``CMAKE_INSTALL_PREFIX``) that
# include files will be installed to. It defaults to
# ``${INCLUDE_INSTALL_DIR}/<baseName>`` if the ``INCLUDE_INSTALL_DIR`` variable
# is set. If that variable is not set, the ``CMAKE_INSTALL_INCLUDEDIR`` variable
# is used instead, and if neither are set ``include`` is used. LIB_INSTALL_DIR
# operates similarly for the installation location for libraries; it defaults to
# ``${LIB_INSTALL_DIR}``, ``${CMAKE_INSTALL_LIBDIR}`` or ``lib``, in that order.
#
# Example usage:
#
# .. code-block:: cmake
#
# ecm_generate_pri_file(
# BASE_NAME KArchive
# LIB_NAME KF5KArchive
# DEPS "core"
# FILENAME_VAR pri_filename
# )
# install(FILES ${pri_filename} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
#
# A qmake-based project that wished to use this would then do::
#
# QT += KArchive
#
# in their ``.pro`` file.
#
# Since pre-1.0.0.
#=============================================================================
# SPDX-FileCopyrightText: 2014 David Faure <faure@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause
# Replicate the logic from KDEInstallDirs.cmake as we can't depend on it
# Ask qmake if we're using the same prefix as Qt
set(_askqmake OFF)
if(NOT DEFINED KDE_INSTALL_USE_QT_SYS_PATHS)
include(ECMQueryQmake)
query_qmake(qt_install_prefix_dir QT_INSTALL_PREFIX TRY)
if(qt_install_prefix_dir STREQUAL "${CMAKE_INSTALL_PREFIX}")
set(_askqmake ON)
endif()
endif()
if(KDE_INSTALL_USE_QT_SYS_PATHS OR _askqmake)
include(ECMQueryQmake)
query_qmake(qt_host_data_dir QT_HOST_DATA)
set(ECM_MKSPECS_INSTALL_DIR ${qt_host_data_dir}/mkspecs/modules CACHE PATH "The directory where mkspecs will be installed to.")
else()
set(ECM_MKSPECS_INSTALL_DIR mkspecs/modules CACHE PATH "The directory where mkspecs will be installed to.")
endif()
function(ECM_GENERATE_PRI_FILE)
set(options )
set(oneValueArgs BASE_NAME LIB_NAME DEPS FILENAME_VAR INCLUDE_INSTALL_DIR LIB_INSTALL_DIR)
set(multiValueArgs )
cmake_parse_arguments(EGPF "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(EGPF_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unknown keywords given to ECM_GENERATE_PRI_FILE(): \"${EGPF_UNPARSED_ARGUMENTS}\"")
endif()
if(NOT EGPF_BASE_NAME)
message(FATAL_ERROR "Required argument BASE_NAME missing in ECM_GENERATE_PRI_FILE() call")
endif()
if(NOT EGPF_LIB_NAME)
message(FATAL_ERROR "Required argument LIB_NAME missing in ECM_GENERATE_PRI_FILE() call")
endif()
if(NOT PROJECT_VERSION_STRING)
message(FATAL_ERROR "Required variable PROJECT_VERSION_STRING not set before ECM_GENERATE_PRI_FILE() call. Did you call ecm_setup_version?")
endif()
if(NOT EGPF_INCLUDE_INSTALL_DIR)
if(INCLUDE_INSTALL_DIR)
set(EGPF_INCLUDE_INSTALL_DIR "${INCLUDE_INSTALL_DIR}/${EGPF_BASE_NAME}")
elseif(CMAKE_INSTALL_INCLUDEDIR)
set(EGPF_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}/${EGPF_BASE_NAME}")
else()
set(EGPF_INCLUDE_INSTALL_DIR "include/${EGPF_BASE_NAME}")
endif()
endif()
if(NOT EGPF_LIB_INSTALL_DIR)
if(LIB_INSTALL_DIR)
set(EGPF_LIB_INSTALL_DIR "${LIB_INSTALL_DIR}")
elseif(CMAKE_INSTALL_LIBDIR)
set(EGPF_LIB_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}")
else()
set(EGPF_LIB_INSTALL_DIR "lib")
endif()
endif()
string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" PROJECT_VERSION_MAJOR "${PROJECT_VERSION_STRING}")
string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" PROJECT_VERSION_MINOR "${PROJECT_VERSION_STRING}")
string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" PROJECT_VERSION_PATCH "${PROJECT_VERSION_STRING}")
# Prepare the right number of "../.." to go from ECM_MKSPECS_INSTALL_DIR to the install prefix
# This allows to make the generated pri files relocatable (no absolute paths)
if (IS_ABSOLUTE ${ECM_MKSPECS_INSTALL_DIR})
set(BASEPATH ${CMAKE_INSTALL_PREFIX})
else()
string(REGEX REPLACE "[^/]+" ".." PRI_ROOT_RELATIVE_TO_MKSPECS ${ECM_MKSPECS_INSTALL_DIR})
set(BASEPATH "$$PWD/${PRI_ROOT_RELATIVE_TO_MKSPECS}")
endif()
set(PRI_TARGET_BASENAME ${EGPF_BASE_NAME})
set(PRI_TARGET_LIBNAME ${EGPF_LIB_NAME})
set(PRI_TARGET_QTDEPS ${EGPF_DEPS})
if(IS_ABSOLUTE "${EGPF_INCLUDE_INSTALL_DIR}")
set(PRI_TARGET_INCLUDES "${EGPF_INCLUDE_INSTALL_DIR}")
else()
set(PRI_TARGET_INCLUDES "${BASEPATH}/${EGPF_INCLUDE_INSTALL_DIR}")
endif()
if(IS_ABSOLUTE "${EGPF_LIB_INSTALL_DIR}")
set(PRI_TARGET_LIBS "${EGPF_LIB_INSTALL_DIR}")
else()
set(PRI_TARGET_LIBS "${BASEPATH}/${EGPF_LIB_INSTALL_DIR}")
endif()
set(PRI_TARGET_DEFINES "")
set(PRI_FILENAME ${CMAKE_CURRENT_BINARY_DIR}/qt_${PRI_TARGET_BASENAME}.pri)
if (EGPF_FILENAME_VAR)
set(${EGPF_FILENAME_VAR} ${PRI_FILENAME} PARENT_SCOPE)
endif()
set(PRI_TARGET_MODULE_CONFIG "")
# backward compat: it was not obvious LIB_NAME needs to be a target name,
# and some projects where the target name was not the actual library output name
# passed the output name for LIB_NAME, so .name & .module prperties are correctly set.
# TODO: improve API dox, allow control over module name if target name != output name
if(TARGET ${EGPF_LIB_NAME})
get_target_property(target_type ${EGPF_LIB_NAME} TYPE)
if (target_type STREQUAL "STATIC_LIBRARY")
set(PRI_TARGET_MODULE_CONFIG "staticlib")
endif()
endif()
file(GENERATE
OUTPUT ${PRI_FILENAME}
CONTENT
"QT.${PRI_TARGET_BASENAME}.VERSION = ${PROJECT_VERSION_STRING}
QT.${PRI_TARGET_BASENAME}.MAJOR_VERSION = ${PROJECT_VERSION_MAJOR}
QT.${PRI_TARGET_BASENAME}.MINOR_VERSION = ${PROJECT_VERSION_MINOR}
QT.${PRI_TARGET_BASENAME}.PATCH_VERSION = ${PROJECT_VERSION_PATCH}
QT.${PRI_TARGET_BASENAME}.name = ${PRI_TARGET_LIBNAME}
QT.${PRI_TARGET_BASENAME}.module = ${PRI_TARGET_LIBNAME}
QT.${PRI_TARGET_BASENAME}.defines = ${PRI_TARGET_DEFINES}
QT.${PRI_TARGET_BASENAME}.includes = ${PRI_TARGET_INCLUDES}
QT.${PRI_TARGET_BASENAME}.private_includes =
QT.${PRI_TARGET_BASENAME}.libs = ${PRI_TARGET_LIBS}
QT.${PRI_TARGET_BASENAME}.depends = ${PRI_TARGET_QTDEPS}
QT.${PRI_TARGET_BASENAME}.module_config = ${PRI_TARGET_MODULE_CONFIG}
"
)
endfunction()

View File

@ -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()

View File

@ -0,0 +1,46 @@
find_package(Qt5Core QUIET)
if (Qt5Core_FOUND)
set(_qmake_executable_default "qmake-qt5")
endif ()
if (TARGET Qt5::qmake)
get_target_property(_qmake_executable_default Qt5::qmake LOCATION)
endif()
set(QMAKE_EXECUTABLE ${_qmake_executable_default}
CACHE FILEPATH "Location of the Qt5 qmake executable")
# Helper method
# This is not public API (yet)!
# Usage: query_qmake(<result_variable> <qt_variable> [TRY])
# Passing TRY will result in the method not failing fatal if no qmake executable
# has been found, but instead simply returning an empty string
function(query_qmake result_variable qt_variable)
set(options TRY)
set(oneValueArgs )
set(multiValueArgs )
cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT QMAKE_EXECUTABLE)
if(ARGS_TRY)
set(${result_variable} "" PARENT_SCOPE)
message(STATUS "No qmake Qt5 binary found. Can't check ${qt_variable}")
return()
else()
message(FATAL_ERROR "No qmake Qt5 binary found. Can't check ${qt_variable} as required")
endif()
endif()
execute_process(
COMMAND ${QMAKE_EXECUTABLE} -query "${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: ${QMAKE_EXECUTABLE} -query \"${qt_variable}\"")
message(FATAL_ERROR "QMake call failed: ${return_code}")
endif()
endfunction()

View File

@ -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()

View File

@ -14,25 +14,39 @@ bool GnomeKeyring::isAvailable()
keyring.is_available();
}
GnomeKeyring::gpointer GnomeKeyring::store_network_password( const gchar* keyring, const gchar* display_name,
const gchar* user, const gchar* server, const gchar* password,
OperationDoneCallback callback, gpointer data, GDestroyNotify destroy_data )
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, static_cast<char*>(0) );
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,
OperationGetStringCallback callback, gpointer data, GDestroyNotify destroy_data )
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, static_cast<char*>(0) );
"user", user, "server", server, "type", type,
static_cast<char*>(0) );
}
GnomeKeyring::gpointer GnomeKeyring::delete_network_password( const gchar* user,
@ -49,12 +63,13 @@ GnomeKeyring::gpointer GnomeKeyring::delete_network_password( const gchar* user,
}
GnomeKeyring::GnomeKeyring()
: QLibrary("gnome-keyring", 0)
: 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 ) }}
};

View File

@ -4,6 +4,8 @@
#include <QLibrary>
class GnomeKeyring : private QLibrary {
Q_OBJECT
public:
enum Result {
RESULT_OK,
@ -43,7 +45,8 @@ public:
} attributes[32];
} PasswordSchema;
typedef void ( *OperationGetStringCallback )( Result result, const char* string, gpointer data );
typedef void ( *OperationGetStringCallback )( Result result, bool binary,
const char* string, gpointer data );
typedef void ( *OperationDoneCallback )( Result result, gpointer data );
typedef void ( *GDestroyNotify )( gpointer data );
@ -52,11 +55,14 @@ public:
static bool isAvailable();
static gpointer store_network_password( const gchar* keyring, const gchar* display_name,
const gchar* user, const gchar* server, const gchar* password,
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,
OperationGetStringCallback callback, gpointer data, GDestroyNotify destroy_data );
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 );

View File

@ -11,9 +11,9 @@
using namespace QKeychain;
Job::Job( const QString& service, QObject *parent )
Job::Job( JobPrivate *q, QObject *parent )
: QObject( parent )
, d ( new JobPrivate( service ) ) {
, d ( q ) {
}
Job::~Job() {
@ -52,6 +52,10 @@ void Job::setInsecureFallback( bool insecureFallback ) {
d->insecureFallback = insecureFallback;
}
void Job::doStart() {
JobExecutor::instance()->enqueue( this );
}
void Job::emitFinished() {
emit finished( this );
if ( d->autoDelete )
@ -64,6 +68,10 @@ void Job::emitFinishedWithError( Error error, const QString& errorString ) {
emitFinished();
}
void Job::scheduledStart() {
d->scheduledStart();
}
Error Job::error() const {
return d->error;
}
@ -81,12 +89,11 @@ void Job::setErrorString( const QString& errorString ) {
}
ReadPasswordJob::ReadPasswordJob( const QString& service, QObject* parent )
: Job( service, parent )
, d( new ReadPasswordJobPrivate( this ) )
{}
: Job( new ReadPasswordJobPrivate( service, this ), parent ) {
}
ReadPasswordJob::~ReadPasswordJob() {
delete d;
}
QString ReadPasswordJob::textData() const {
@ -97,126 +104,80 @@ QByteArray ReadPasswordJob::binaryData() const {
return d->data;
}
QString ReadPasswordJob::key() const {
QString Job::key() const {
return d->key;
}
void ReadPasswordJob::setKey( const QString& key ) {
d->key = key;
}
void ReadPasswordJob::doStart() {
JobExecutor::instance()->enqueue( this );
void Job::setKey( const QString& key_ ) {
d->key = key_;
}
WritePasswordJob::WritePasswordJob( const QString& service, QObject* parent )
: Job( service, parent )
, d( new WritePasswordJobPrivate( this ) ) {
: Job( new WritePasswordJobPrivate( service, this ), parent ) {
}
WritePasswordJob::~WritePasswordJob() {
delete d;
}
QString WritePasswordJob::key() const {
return d->key;
}
void WritePasswordJob::setKey( const QString& key ) {
d->key = key;
}
void WritePasswordJob::setBinaryData( const QByteArray& data ) {
d->binaryData = data;
d->mode = WritePasswordJobPrivate::Binary;
d->data = data;
d->mode = JobPrivate::Binary;
}
void WritePasswordJob::setTextData( const QString& data ) {
d->textData = data;
d->mode = WritePasswordJobPrivate::Text;
}
void WritePasswordJob::doStart() {
JobExecutor::instance()->enqueue( this );
d->data = data.toUtf8();
d->mode = JobPrivate::Text;
}
DeletePasswordJob::DeletePasswordJob( const QString& service, QObject* parent )
: Job( service, parent )
, d( new DeletePasswordJobPrivate( this ) ) {
: Job( new DeletePasswordJobPrivate( service, this ), parent ) {
}
DeletePasswordJob::~DeletePasswordJob() {
delete d;
}
void DeletePasswordJob::doStart() {
//Internally, to delete a password we just execute a write job with no data set (null byte array).
//In all current implementations, this deletes the entry so this is sufficient
WritePasswordJob* job = new WritePasswordJob( service(), this );
connect( job, SIGNAL(finished(QKeychain::Job*)), d, SLOT(jobFinished(QKeychain::Job*)) );
job->setInsecureFallback(true);
job->setSettings(settings());
job->setKey( d->key );
job->doStart();
}
DeletePasswordJobPrivate::DeletePasswordJobPrivate(const QString &service_, DeletePasswordJob *qq) :
JobPrivate(service_, qq) {
QString DeletePasswordJob::key() const {
return d->key;
}
void DeletePasswordJob::setKey( const QString& key ) {
d->key = key;
}
void DeletePasswordJobPrivate::jobFinished( Job* job ) {
q->setError( job->error() );
q->setErrorString( job->errorString() );
q->emitFinished();
}
JobExecutor::JobExecutor()
: QObject( 0 )
, m_runningJob( 0 )
{
, m_jobRunning( false ) {
}
void JobExecutor::enqueue( Job* job ) {
m_queue.append( job );
m_queue.enqueue( job );
startNextIfNoneRunning();
}
void JobExecutor::startNextIfNoneRunning() {
if ( m_queue.isEmpty() || m_runningJob )
if ( m_queue.isEmpty() || m_jobRunning )
return;
QPointer<Job> next;
while ( !next && !m_queue.isEmpty() ) {
next = m_queue.first();
m_queue.pop_front();
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_runningJob = next;
if ( ReadPasswordJob* rpj = qobject_cast<ReadPasswordJob*>( m_runningJob ) )
rpj->d->scheduledStart();
else if ( WritePasswordJob* wpj = qobject_cast<WritePasswordJob*>( m_runningJob) )
wpj->d->scheduledStart();
m_jobRunning = true;
next->scheduledStart();
}
}
void JobExecutor::jobDestroyed( QObject* object ) {
Job* job = static_cast<Job*>(object);
Q_UNUSED( object ) // for release mode
Q_ASSERT( object == m_runningJob );
m_runningJob->disconnect( this );
m_runningJob = 0;
job->disconnect( this );
m_jobRunning = false;
startNextIfNoneRunning();
}
void JobExecutor::jobFinished( Job* job ) {
Q_UNUSED( job ) // for release mode
Q_ASSERT( job == m_runningJob );
m_runningJob->disconnect( this );
m_runningJob = 0;
job->disconnect( this );
m_jobRunning = false;
startNextIfNoneRunning();
}
@ -227,3 +188,48 @@ JobExecutor* JobExecutor::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) {
}

View File

@ -9,7 +9,11 @@
#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>
@ -37,107 +41,229 @@ enum Error {
class JobExecutor;
class JobPrivate;
/**
* @brief Abstract base class for all QKeychain jobs.
*/
class QKEYCHAIN_EXPORT Job : public QObject {
Q_OBJECT
public:
explicit Job( const QString& service, QObject* parent=0 );
~Job();
~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 );
Q_SIGNALS:
void finished( QKeychain::Job* );
/**
* @return The string used as key by this job.
* @see setKey()
*/
QString key() const;
protected:
Q_INVOKABLE virtual void doStart() = 0;
/**
* 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 setError( Error error );
void setErrorString( const QString& errorString );
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:
explicit ReadPasswordJob( const QString& service, QObject* parent=0 );
~ReadPasswordJob();
QString key() const;
void setKey( const QString& key );
/**
* 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;
QString textData() const;
protected:
void doStart();
/**
* @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;
friend class QKeychain::JobExecutor;
ReadPasswordJobPrivate* const d;
};
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:
explicit WritePasswordJob( const QString& service, QObject* parent=0 );
~WritePasswordJob();
QString key() const;
void setKey( const QString& key );
/**
* 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 );
protected:
void doStart();
private:
friend class QKeychain::JobExecutor;
friend class QKeychain::WritePasswordJobPrivate;
friend class DeletePasswordJob;
WritePasswordJobPrivate* const d;
};
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:
explicit DeletePasswordJob( const QString& service, QObject* parent=0 );
~DeletePasswordJob();
QString key() const;
void setKey( const QString& key );
protected:
void doStart();
/**
* 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;
DeletePasswordJobPrivate* const d;
};
} // namespace QtKeychain

View File

@ -0,0 +1,182 @@
/******************************************************************************
* 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"
#include "androidkeystore_p.h"
#include "plaintextstore_p.h"
#include <QtAndroid>
using namespace QKeychain;
using android::content::Context;
using android::security::KeyPairGeneratorSpec;
using java::io::ByteArrayInputStream;
using java::io::ByteArrayOutputStream;
using java::security::interfaces::RSAPrivateKey;
using java::security::interfaces::RSAPublicKey;
using java::security::KeyPair;
using java::security::KeyPairGenerator;
using java::security::KeyStore;
using java::util::Calendar;
using javax::crypto::Cipher;
using javax::crypto::CipherInputStream;
using javax::crypto::CipherOutputStream;
using javax::security::auth::x500::X500Principal;
namespace {
inline QString makeAlias(const QString &service, const QString &key)
{
return service + QLatin1Char('/') + key;
}
}
void ReadPasswordJobPrivate::scheduledStart()
{
PlainTextStore plainTextStore(q->service(), q->settings());
if (!plainTextStore.contains(q->key())) {
q->emitFinishedWithError(Error::EntryNotFound, tr("Entry not found"));
return;
}
const QByteArray &encryptedData = plainTextStore.readData(q->key());
const KeyStore keyStore = KeyStore::getInstance(QStringLiteral("AndroidKeyStore"));
if (!keyStore || !keyStore.load()) {
q->emitFinishedWithError(Error::AccessDenied, tr("Could not open keystore"));
return;
}
const auto &alias = makeAlias(q->service(), q->key());
const KeyStore::PrivateKeyEntry entry = keyStore.getEntry(alias);
if (!entry) {
q->emitFinishedWithError(Error::AccessDenied, tr("Could not retrieve private key from keystore"));
return;
}
const Cipher cipher = Cipher::getInstance(QStringLiteral("RSA/ECB/PKCS1Padding"));
if (!cipher || !cipher.init(Cipher::DECRYPT_MODE, entry.getPrivateKey())) {
q->emitFinishedWithError(Error::OtherError, tr("Could not create decryption cipher"));
return;
}
QByteArray plainData;
const CipherInputStream inputStream(ByteArrayInputStream(encryptedData), cipher);
for (int nextByte; (nextByte = inputStream.read()) != -1; )
plainData.append(nextByte);
mode = plainTextStore.readMode(q->key());
data = plainData;
q->emitFinished();
}
void WritePasswordJobPrivate::scheduledStart()
{
const KeyStore keyStore = KeyStore::getInstance(QStringLiteral("AndroidKeyStore"));
if (!keyStore || !keyStore.load()) {
q->emitFinishedWithError(Error::AccessDenied, tr("Could not open keystore"));
return;
}
const auto &alias = makeAlias(q->service(), q->key());
if (!keyStore.containsAlias(alias)) {
const Calendar start = Calendar::getInstance();
const Calendar end = Calendar::getInstance();
end.add(Calendar::YEAR, 99);
const KeyPairGeneratorSpec spec =
KeyPairGeneratorSpec::Builder(Context(QtAndroid::androidActivity())).
setAlias(alias).
setSubject(X500Principal(QStringLiteral("CN=QtKeychain, O=Android Authority"))).
setSerialNumber(java::math::BigInteger::ONE).
setStartDate(start.getTime()).
setEndDate(end.getTime()).
build();
const KeyPairGenerator generator = KeyPairGenerator::getInstance(QStringLiteral("RSA"),
QStringLiteral("AndroidKeyStore"));
if (!generator) {
q->emitFinishedWithError(Error::OtherError, tr("Could not create private key generator"));
return;
}
generator.initialize(spec);
if (!generator.generateKeyPair()) {
q->emitFinishedWithError(Error::OtherError, tr("Could not generate new private key"));
return;
}
}
const KeyStore::PrivateKeyEntry entry = keyStore.getEntry(alias);
if (!entry) {
q->emitFinishedWithError(Error::AccessDenied, tr("Could not retrieve private key from keystore"));
return;
}
const RSAPublicKey publicKey = entry.getCertificate().getPublicKey();
const Cipher cipher = Cipher::getInstance(QStringLiteral("RSA/ECB/PKCS1Padding"));
if (!cipher || !cipher.init(Cipher::ENCRYPT_MODE, publicKey)) {
q->emitFinishedWithError(Error::OtherError, tr("Could not create encryption cipher"));
return;
}
ByteArrayOutputStream outputStream;
CipherOutputStream cipherOutputStream(outputStream, cipher);
if (!cipherOutputStream.write(data) || !cipherOutputStream.close()) {
q->emitFinishedWithError(Error::OtherError, tr("Could not encrypt data"));
return;
}
PlainTextStore plainTextStore(q->service(), q->settings());
plainTextStore.write(q->key(), outputStream.toByteArray(), mode);
if (plainTextStore.error() != NoError)
q->emitFinishedWithError(plainTextStore.error(), plainTextStore.errorString());
else
q->emitFinished();
}
void DeletePasswordJobPrivate::scheduledStart()
{
const KeyStore keyStore = KeyStore::getInstance(QStringLiteral("AndroidKeyStore"));
if (!keyStore || !keyStore.load()) {
q->emitFinishedWithError(Error::AccessDenied, tr("Could not open keystore"));
return;
}
const auto &alias = makeAlias(q->service(), q->key());
if (!keyStore.deleteEntry(alias)) {
q->emitFinishedWithError(Error::OtherError, tr("Could not remove private key from keystore"));
return;
}
PlainTextStore plainTextStore(q->service(), q->settings());
plainTextStore.remove(q->key());
if (plainTextStore.error() != NoError)
q->emitFinishedWithError(plainTextStore.error(), plainTextStore.errorString());
else
q->emitFinished();
}

View File

@ -0,0 +1,146 @@
/******************************************************************************
* 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"));
}
};
void ReadPasswordJobPrivate::scheduledStart()
{
NSDictionary *const query = @{
(__bridge id) kSecClass: (__bridge id) kSecClassGenericPassword,
(__bridge id) kSecAttrService: (__bridge NSString *) service.toCFString(),
(__bridge id) kSecAttrAccount: (__bridge NSString *) key.toCFString(),
(__bridge id) kSecReturnData: @YES,
};
CFTypeRef dataRef = nil;
const OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &dataRef);
data.clear();
mode = Binary;
if (status == errSecSuccess) {
if (dataRef)
data = QByteArray::fromCFData((CFDataRef) dataRef);
q->emitFinished();
} else {
const ErrorDescription error = ErrorDescription::fromStatus(status);
q->emitFinishedWithError(error.code, Job::tr("Could not retrieve private key from keystore: %1").arg(error.message));
}
if (dataRef)
[dataRef release];
}
void WritePasswordJobPrivate::scheduledStart()
{
NSDictionary *const query = @{
(__bridge id) kSecClass: (__bridge id) kSecClassGenericPassword,
(__bridge id) kSecAttrService: (__bridge NSString *) service.toCFString(),
(__bridge id) kSecAttrAccount: (__bridge NSString *) key.toCFString(),
};
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, nil);
if (status == errSecSuccess) {
NSDictionary *const update = @{
(__bridge id) kSecValueData: (__bridge NSData *) data.toCFData(),
};
status = SecItemUpdate((__bridge CFDictionaryRef) query, (__bridge CFDictionaryRef) update);
} else {
NSDictionary *const insert = @{
(__bridge id) kSecClass: (__bridge id) kSecClassGenericPassword,
(__bridge id) kSecAttrService: (__bridge NSString *) service.toCFString(),
(__bridge id) kSecAttrAccount: (__bridge NSString *) key.toCFString(),
(__bridge id) kSecValueData: (__bridge NSData *) data.toCFData(),
};
status = SecItemAdd((__bridge CFDictionaryRef) insert, nil);
}
if (status == errSecSuccess) {
q->emitFinished();
} else {
const ErrorDescription error = ErrorDescription::fromStatus(status);
q->emitFinishedWithError(error.code, tr("Could not store data in settings: %1").arg(error.message));
}
}
void DeletePasswordJobPrivate::scheduledStart()
{
const NSDictionary *const query = @{
(__bridge id) kSecClass: (__bridge id) kSecClassGenericPassword,
(__bridge id) kSecAttrService: (__bridge NSString *) service.toCFString(),
(__bridge id) kSecAttrAccount: (__bridge NSString *) key.toCFString(),
};
const OSStatus status = SecItemDelete((__bridge CFDictionaryRef) query);
if (status == errSecSuccess) {
q->emitFinished();
} else {
const ErrorDescription error = ErrorDescription::fromStatus(status);
q->emitFinishedWithError(error.code, Job::tr("Could not remove private key from keystore: %1").arg(error.message));
}
}

View File

@ -0,0 +1,187 @@
/******************************************************************************
* Copyright (C) 2018 François Revol <revol@free.fr> *
* *
* 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 <KeyStore.h>
#include <Application.h>
#include <AppFileInfo.h>
#include <File.h>
#include <QDebug>
#include <QCoreApplication>
#include <QString>
using namespace QKeychain;
class AutoApp {
public:
AutoApp();
~AutoApp();
BApplication *app;
};
AutoApp::AutoApp()
: app(NULL)
{
if (be_app != NULL)
return;
// no BApplication object, probably using QCoreApplication
// but we need one around
QString appSignature;
char signature[B_MIME_TYPE_LENGTH];
signature[0] = '\0';
QString appPath = QCoreApplication::applicationFilePath();
BFile appFile(appPath.toUtf8(), B_READ_ONLY);
if (appFile.InitCheck() == B_OK) {
BAppFileInfo info(&appFile);
if (info.InitCheck() == B_OK) {
if (info.GetSignature(signature) != B_OK)
signature[0] = '\0';
}
}
if (signature[0] != '\0')
appSignature = QLatin1String(signature);
else
appSignature = QLatin1String("application/x-vnd.qtkeychain-") +
QCoreApplication::applicationName().remove("_x86");
app = new BApplication(appSignature.toUtf8().constData());
}
AutoApp::~AutoApp()
{
delete app;
}
static QString strForStatus( status_t os ) {
const char * const buf = strerror(os) ;
return QObject::tr( "error 0x%1: %2" )
.arg( os, 8, 16 ).arg( QString::fromUtf8( buf, strlen( buf ) ) );
}
void ReadPasswordJobPrivate::scheduledStart()
{
AutoApp aa;
QString errorString;
Error error = NoError;
BKeyStore keyStore;
BPasswordKey password;
status_t result = keyStore.GetKey(B_KEY_TYPE_PASSWORD,
q->service().toUtf8().constData(),
q->key().toUtf8().constData(),
false, password);
data = QByteArray(reinterpret_cast<const char*>(password.Data()), password.DataLength());
switch ( result ) {
case B_OK:
q->emitFinished();
return;
case B_ENTRY_NOT_FOUND:
errorString = tr("Password not found");
error = EntryNotFound;
break;
default:
errorString = strForStatus( result );
error = OtherError;
break;
}
q->emitFinishedWithError( error, errorString );
}
void WritePasswordJobPrivate::scheduledStart()
{
AutoApp aa;
QString errorString;
Error error = NoError;
BKeyStore keyStore;
BPasswordKey password(data.constData(),
B_KEY_PURPOSE_GENERIC,
q->service().toUtf8().constData(),
q->key().toUtf8().constData());
status_t result = B_OK;
// re-add as binary if it's not text
if (mode == Binary)
result = password.SetData(reinterpret_cast<const uint8*>(data.constData()), data.size());
if (result == B_OK)
result = keyStore.AddKey(password);
if (result == B_NAME_IN_USE) {
BPasswordKey old_password;
result = keyStore.GetKey(B_KEY_TYPE_PASSWORD,
q->service().toUtf8().constData(),
q->key().toUtf8().constData(),
false, old_password);
if (result == B_OK)
result = keyStore.RemoveKey(old_password);
if (result == B_OK)
result = keyStore.AddKey(password);
}
switch ( result ) {
case B_OK:
q->emitFinished();
return;
case B_ENTRY_NOT_FOUND:
errorString = tr("Password not found");
error = EntryNotFound;
break;
default:
errorString = strForStatus( result );
error = OtherError;
break;
}
q->emitFinishedWithError( error, errorString );
}
void DeletePasswordJobPrivate::scheduledStart()
{
AutoApp aa;
QString errorString;
Error error = NoError;
BKeyStore keyStore;
BPasswordKey password;
status_t result = keyStore.GetKey(B_KEY_TYPE_PASSWORD,
q->service().toUtf8().constData(),
q->key().toUtf8().constData(),
false, password);
if (result == B_OK)
result = keyStore.RemoveKey(password);
switch ( result ) {
case B_OK:
q->emitFinished();
return;
case B_ENTRY_NOT_FOUND:
errorString = tr("Password not found");
error = EntryNotFound;
break;
default:
errorString = strForStatus( result );
error = CouldNotDeleteEntry;
break;
}
q->emitFinishedWithError( error, errorString );
}

View File

@ -1,161 +0,0 @@
/******************************************************************************
* 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 <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
#include <QDebug>
using namespace QKeychain;
template <typename T>
struct Releaser {
explicit Releaser( const T& v ) : value( v ) {}
~Releaser() {
CFRelease( value );
}
const T value;
};
static QString strForStatus( OSStatus os ) {
const Releaser<CFStringRef> str( SecCopyErrorMessageString( os, 0 ) );
const char * const buf = CFStringGetCStringPtr( str.value, kCFStringEncodingUTF8 );
if ( !buf )
return QObject::tr( "%1 (OSStatus %2)" )
.arg( "OSX Keychain Error" ).arg( os );
return QObject::tr( "%1 (OSStatus %2)" )
.arg( QString::fromUtf8( buf, strlen( buf ) ) ).arg( os );
}
static OSStatus readPw( QByteArray* pw,
const QString& service,
const QString& account,
SecKeychainItemRef* ref ) {
Q_ASSERT( pw );
pw->clear();
const QByteArray serviceData = service.toUtf8();
const QByteArray accountData = account.toUtf8();
void* data = 0;
UInt32 len = 0;
const OSStatus ret = SecKeychainFindGenericPassword( NULL, // default keychain
serviceData.size(),
serviceData.constData(),
accountData.size(),
accountData.constData(),
&len,
&data,
ref );
if ( ret == noErr ) {
*pw = QByteArray( reinterpret_cast<const char*>( data ), len );
const OSStatus ret2 = SecKeychainItemFreeContent ( 0, data );
if ( ret2 != noErr )
qWarning() << "Could not free item content: " << strForStatus( ret2 );
}
return ret;
}
void ReadPasswordJobPrivate::scheduledStart()
{
QString errorString;
Error error = NoError;
const OSStatus ret = readPw( &data, q->service(), q->key(), 0 );
switch ( ret ) {
case noErr:
break;
case errSecItemNotFound:
errorString = tr("Password not found");
error = EntryNotFound;
break;
default:
errorString = strForStatus( ret );
error = OtherError;
break;
}
q->emitFinishedWithError( error, errorString );
}
static QKeychain::Error deleteEntryImpl( const QString& service, const QString& account, QString* err ) {
SecKeychainItemRef ref;
QByteArray pw;
const OSStatus ret1 = readPw( &pw, service, account, &ref );
if ( ret1 == errSecItemNotFound )
return NoError; // No item stored, we're done
if ( ret1 != noErr ) {
*err = strForStatus( ret1 );
//TODO map error code, set errstr
return OtherError;
}
const Releaser<SecKeychainItemRef> releaser( ref );
const OSStatus ret2 = SecKeychainItemDelete( ref );
if ( ret2 == noErr )
return NoError;
//TODO map error code
*err = strForStatus( ret2 );
return CouldNotDeleteEntry;
}
static QKeychain::Error writeEntryImpl( const QString& service,
const QString& account,
const QByteArray& data,
QString* err ) {
Q_ASSERT( err );
err->clear();
const QByteArray serviceData = service.toUtf8();
const QByteArray accountData = account.toUtf8();
const OSStatus ret = SecKeychainAddGenericPassword( NULL, //default keychain
serviceData.size(),
serviceData.constData(),
accountData.size(),
accountData.constData(),
data.size(),
data.constData(),
NULL //item reference
);
if ( ret != noErr ) {
switch ( ret ) {
case errSecDuplicateItem:
{
Error derr = deleteEntryImpl( service, account, err );
if ( derr != NoError )
return CouldNotDeleteEntry;
else
return writeEntryImpl( service, account, data, err );
}
default:
*err = strForStatus( ret );
return OtherError;
}
}
return NoError;
}
void WritePasswordJobPrivate::scheduledStart()
{
QString errorString;
Error error = NoError;
if ( mode == Delete ) {
const Error derr = deleteEntryImpl( q->service(), key, &errorString );
if ( derr != NoError )
error = CouldNotDeleteEntry;
q->emitFinishedWithError( error, errorString );
return;
}
const QByteArray data = mode == Text ? textData.toUtf8() : binaryData;
error = writeEntryImpl( q->service(), key, data, &errorString );
q->emitFinishedWithError( error, errorString );
}

View File

@ -13,9 +13,9 @@
#include <QObject>
#include <QPointer>
#include <QSettings>
#include <QVector>
#include <QQueue>
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
#if defined(KEYCHAIN_DBUS)
#include <QDBusPendingCallWatcher>
@ -35,105 +35,109 @@ class JobExecutor;
class JobPrivate : public QObject {
Q_OBJECT
public:
JobPrivate( const QString& service_ )
: error( NoError )
, service( service_ )
, autoDelete( true )
, insecureFallback( false ) {}
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 QObject {
class ReadPasswordJobPrivate : public JobPrivate {
Q_OBJECT
public:
explicit ReadPasswordJobPrivate( ReadPasswordJob* qq ) : q( qq ), walletHandle( 0 ), dataType( Text ) {}
void scheduledStart();
explicit ReadPasswordJobPrivate( const QString &service_, ReadPasswordJob* qq );
void scheduledStart() override;
ReadPasswordJob* const q;
QByteArray data;
QString key;
int walletHandle;
enum DataType {
Binary,
Text
};
DataType dataType;
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
org::kde::KWallet* iface;
static void gnomeKeyring_cb( int result, const char* string, ReadPasswordJobPrivate* data );
friend class QKeychain::JobExecutor;
void fallbackOnError(const QDBusError& err);
#if defined(KEYCHAIN_DBUS)
void fallbackOnError(const QDBusError& err) override;
private Q_SLOTS:
void kwalletWalletFound( QDBusPendingCallWatcher* watcher );
void kwalletOpenFinished( QDBusPendingCallWatcher* watcher );
void kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) override;
void kwalletEntryTypeFinished( QDBusPendingCallWatcher* watcher );
void kwalletReadFinished( 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 kwalletWalletFound( QDBusPendingCallWatcher* ) {}
void kwalletOpenFinished( QDBusPendingCallWatcher* ) {}
void kwalletEntryTypeFinished( QDBusPendingCallWatcher* ) {}
void kwalletReadFinished( QDBusPendingCallWatcher* ) {}
void kwalletFinished( QDBusPendingCallWatcher* ) {}
#endif
friend class ReadPasswordJob;
};
class WritePasswordJobPrivate : public QObject {
class WritePasswordJobPrivate : public JobPrivate {
Q_OBJECT
public:
explicit WritePasswordJobPrivate( WritePasswordJob* qq ) : q( qq ), mode( Delete ) {}
void scheduledStart();
explicit WritePasswordJobPrivate( const QString &service_, WritePasswordJob* qq );
void scheduledStart() override;
enum Mode {
Delete,
Text,
Binary
};
static QString modeToString(Mode m);
static Mode stringToMode(const QString& s);
WritePasswordJob* const q;
Mode mode;
QString key;
QByteArray binaryData;
QString textData;
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
org::kde::KWallet* iface;
static void gnomeKeyring_cb( int result, WritePasswordJobPrivate* self );
friend class QKeychain::JobExecutor;
void fallbackOnError(const QDBusError& err);
private Q_SLOTS:
void kwalletWalletFound( QDBusPendingCallWatcher* watcher );
void kwalletOpenFinished( QDBusPendingCallWatcher* watcher );
void kwalletWriteFinished( QDBusPendingCallWatcher* watcher );
#else
private Q_SLOTS:
void kwalletWalletFound( QDBusPendingCallWatcher* ) {}
void kwalletOpenFinished( QDBusPendingCallWatcher* ) {}
void kwalletWriteFinished( QDBusPendingCallWatcher* ) {}
#if defined(KEYCHAIN_DBUS)
void fallbackOnError(const QDBusError& err) override;
#endif
friend class WritePasswordJob;
};
class DeletePasswordJobPrivate : public QObject {
class DeletePasswordJobPrivate : public JobPrivate {
Q_OBJECT
public:
explicit DeletePasswordJobPrivate( DeletePasswordJob* qq ) : q( qq ) {}
explicit DeletePasswordJobPrivate( const QString &service_, DeletePasswordJob* qq );
void scheduledStart() override;
#if defined(KEYCHAIN_DBUS)
void fallbackOnError(const QDBusError& err) override;
#endif
protected:
void doStart();
DeletePasswordJob* const q;
QString key;
private Q_SLOTS:
void jobFinished( QKeychain::Job* );
friend class DeletePasswordJob;
};
class JobExecutor : public QObject {
@ -154,8 +158,8 @@ private Q_SLOTS:
private:
static JobExecutor* s_instance;
Job* m_runningJob;
QVector<QPointer<Job> > m_queue;
QQueue<QPointer<Job> > m_queue;
bool m_jobRunning;
};
}

View File

@ -8,24 +8,15 @@
*****************************************************************************/
#include "keychain_p.h"
#include "gnomekeyring_p.h"
#include <QSettings>
#include "libsecret_p.h"
#include "plaintextstore_p.h"
#include <QScopedPointer>
using namespace QKeychain;
static QString typeKey( const QString& key )
{
return QString::fromLatin1( "%1/type" ).arg( key );
}
static QString dataKey( const QString& key )
{
return QString::fromLatin1( "%1/data" ).arg( key );
}
enum KeyringBackend {
Backend_LibSecretKeyring,
Backend_GnomeKeyring,
Backend_Kwallet4,
Backend_Kwallet5
@ -44,7 +35,7 @@ enum DesktopEnvironment {
// licensed under BSD, see base/nix/xdg_util.cc
static DesktopEnvironment getKdeVersion() {
QString value = qgetenv("KDE_SESSION_VERSION");
QByteArray value = qgetenv("KDE_SESSION_VERSION");
if ( value == "5" ) {
return DesktopEnv_Plasma5;
} else if (value == "4" ) {
@ -63,6 +54,8 @@ static DesktopEnvironment detectDesktopEnvironment() {
return DesktopEnv_Unity;
} else if ( xdgCurrentDesktop == "KDE" ) {
return getKdeVersion();
} else if ( xdgCurrentDesktop == "XFCE" ) {
return DesktopEnv_Xfce;
}
QByteArray desktopSession = qgetenv("DESKTOP_SESSION");
@ -85,26 +78,82 @@ static DesktopEnvironment detectDesktopEnvironment() {
return DesktopEnv_Other;
}
static bool isKwallet5Available()
{
if (!QDBusConnection::sessionBus().isConnected())
return false;
org::kde::KWallet iface(
QLatin1String("org.kde.kwalletd5"),
QLatin1String("/modules/kwalletd5"),
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;
break;
case DesktopEnv_Plasma5:
if (isKwallet5Available()) {
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;
break;
// fall through
case DesktopEnv_Gnome:
case DesktopEnv_Unity:
case DesktopEnv_Xfce:
case DesktopEnv_Other:
default:
if ( GnomeKeyring::isAvailable() ) {
return Backend_GnomeKeyring;
} else {
return Backend_Kwallet4;
if (LibSecretKeyring::isAvailable()) {
return Backend_LibSecretKeyring;
}
if (GnomeKeyring::isAvailable()) {
return Backend_GnomeKeyring;
}
if (isKwallet5Available()) {
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;
}
}
@ -125,7 +174,7 @@ static void kwalletReadPasswordScheduledStartImpl(const char * service, const ch
}
else
{
// D-Bus is not reachable so none can tell us something about KWalletd
// 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 );
}
@ -133,9 +182,17 @@ static void kwalletReadPasswordScheduledStartImpl(const char * service, const ch
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:
if ( !GnomeKeyring::find_network_password( key.toUtf8().constData(), q->service().toUtf8().constData(),
reinterpret_cast<GnomeKeyring::OperationGetStringCallback>( &ReadPasswordJobPrivate::gnomeKeyring_cb ),
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;
@ -149,13 +206,14 @@ void ReadPasswordJobPrivate::scheduledStart() {
}
}
void ReadPasswordJobPrivate::kwalletWalletFound(QDBusPendingCallWatcher *watcher)
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*)) );
connect( pendingWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
this, SLOT(kwalletOpenFinished(QDBusPendingCallWatcher*)) );
}
static QPair<Error, QString> mapGnomeKeyringError( int result )
@ -188,14 +246,23 @@ static QPair<Error, QString> mapGnomeKeyringError( int result )
return qMakePair( OtherError, QObject::tr("Unknown error") );
}
void ReadPasswordJobPrivate::gnomeKeyring_cb( int result, const char* string, ReadPasswordJobPrivate* self )
void JobPrivate::gnomeKeyring_readCb( int result, const char* string, JobPrivate* self )
{
if ( result == GnomeKeyring::RESULT_OK ) {
if ( self->dataType == ReadPasswordJobPrivate::Text )
self->data = string;
if (self->mode == JobPrivate::Text)
self->data = QByteArray(string);
else
self->data = QByteArray::fromBase64( string );
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 );
@ -204,19 +271,16 @@ void ReadPasswordJobPrivate::gnomeKeyring_cb( int result, const char* string, Re
void ReadPasswordJobPrivate::fallbackOnError(const QDBusError& err )
{
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.data();
PlainTextStore plainTextStore( q->service(), q->settings() );
if ( q->insecureFallback() && actual->contains( dataKey( key ) ) ) {
if ( q->insecureFallback() && plainTextStore.contains( key ) ) {
mode = plainTextStore.readMode( key );
data = plainTextStore.readData( key );
const WritePasswordJobPrivate::Mode mode = WritePasswordJobPrivate::stringToMode( actual->value( typeKey( key ) ).toString() );
if (mode == WritePasswordJobPrivate::Binary)
dataType = Binary;
if ( plainTextStore.error() != NoError )
q->emitFinishedWithError( plainTextStore.error(), plainTextStore.errorString() );
else
dataType = Text;
data = actual->value( dataKey( key ) ).toByteArray();
q->emitFinished();
q->emitFinished();
} else {
if ( err.type() == QDBusError::ServiceUnknown ) //KWalletd not running
q->emitFinishedWithError( NoBackendAvailable, tr("No keychain service available") );
@ -229,21 +293,20 @@ void ReadPasswordJobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watch
watcher->deleteLater();
const QDBusPendingReply<int> reply = *watcher;
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.data();
if ( reply.isError() ) {
fallbackOnError( reply.error() );
return;
}
if ( actual->contains( dataKey( key ) ) ) {
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 = actual->value( dataKey( key ) ).toByteArray();
const WritePasswordJobPrivate::Mode mode = WritePasswordJobPrivate::stringToMode( actual->value( typeKey( key ) ).toString() );
actual->remove( key );
data = plainTextStore.readData( key );
const WritePasswordJobPrivate::Mode mode = plainTextStore.readMode( key );
plainTextStore.remove( key );
q->emitFinished();
@ -300,10 +363,10 @@ void ReadPasswordJobPrivate::kwalletEntryTypeFinished( QDBusPendingCallWatcher*
q->emitFinishedWithError( EntryNotFound, tr("Entry not found") );
return;
case Password:
dataType = Text;
mode = Text;
break;
case Stream:
dataType = Binary;
mode = Binary;
break;
case Map:
q->emitFinishedWithError( EntryNotFound, tr("Unsupported entry type 'Map'") );
@ -313,32 +376,32 @@ void ReadPasswordJobPrivate::kwalletEntryTypeFinished( QDBusPendingCallWatcher*
return;
}
const QDBusPendingCall nextReply = dataType == Text
? QDBusPendingCall( iface->readPassword( walletHandle, q->service(), key, q->service() ) )
: QDBusPendingCall( iface->readEntry( walletHandle, q->service(), key, q->service() ) );
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(kwalletReadFinished(QDBusPendingCallWatcher*)) );
connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletFinished(QDBusPendingCallWatcher*)) );
}
void ReadPasswordJobPrivate::kwalletReadFinished( QDBusPendingCallWatcher* watcher ) {
watcher->deleteLater();
if ( watcher->isError() ) {
const QDBusError err = watcher->error();
q->emitFinishedWithError( OtherError, tr("Could not read password: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
return;
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();
}
}
}
if ( dataType == Binary ) {
QDBusPendingReply<QByteArray> reply = *watcher;
data = reply.value();
} else {
QDBusPendingReply<QString> reply = *watcher;
data = reply.value().toUtf8();
}
q->emitFinished();
JobPrivate::kwalletFinished(watcher);
}
static void kwalletWritePasswordScheduledStart( const char * service, const char * path, WritePasswordJobPrivate * priv ) {
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 );
@ -356,21 +419,38 @@ static void kwalletWritePasswordScheduledStart( const char * service, const char
void WritePasswordJobPrivate::scheduledStart() {
switch ( getKeyringBackend() ) {
case Backend_GnomeKeyring:
if ( mode == WritePasswordJobPrivate::Delete ) {
if ( !GnomeKeyring::delete_network_password( key.toUtf8().constData(), q->service().toUtf8().constData(),
reinterpret_cast<GnomeKeyring::OperationDoneCallback>( &WritePasswordJobPrivate::gnomeKeyring_cb ),
this, 0 ) )
q->emitFinishedWithError( OtherError, tr("Unknown error") );
} else {
QByteArray password = mode == WritePasswordJobPrivate::Text ? textData.toUtf8() : binaryData.toBase64();
QByteArray service = q->service().toUtf8();
if ( !GnomeKeyring::store_network_password( GnomeKeyring::GNOME_KEYRING_DEFAULT, service.constData(),
key.toUtf8().constData(), service.constData(), password.constData(),
reinterpret_cast<GnomeKeyring::OperationDoneCallback>( &WritePasswordJobPrivate::gnomeKeyring_cb ),
this, 0 ) )
q->emitFinishedWithError( OtherError, tr("Unknown error") );
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:
@ -382,64 +462,23 @@ void WritePasswordJobPrivate::scheduledStart() {
}
}
QString WritePasswordJobPrivate::modeToString(Mode m)
{
switch (m) {
case Delete:
return QLatin1String("Delete");
case Text:
return QLatin1String("Text");
case Binary:
return QLatin1String("Binary");
}
Q_ASSERT_X(false, Q_FUNC_INFO, "Unhandled Mode value");
return QString();
}
WritePasswordJobPrivate::Mode WritePasswordJobPrivate::stringToMode(const QString& s)
{
if (s == QLatin1String("Delete") || s == QLatin1String("0"))
return Delete;
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;
}
void WritePasswordJobPrivate::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;
}
if ( mode == Delete ) {
actual->remove( key );
actual->sync();
PlainTextStore plainTextStore( q->service(), q->settings() );
plainTextStore.write( key, data, mode );
if ( plainTextStore.error() != NoError )
q->emitFinishedWithError( plainTextStore.error(), plainTextStore.errorString() );
else
q->emitFinished();
return;
}
actual->setValue( QString::fromLatin1( "%1/type" ).arg( key ), mode );
if ( mode == Text )
actual->setValue( QString::fromLatin1( "%1/data" ).arg( key ), textData.toUtf8() );
else if ( mode == Binary )
actual->setValue( QString::fromLatin1( "%1/data" ).arg( key ), binaryData );
actual->sync();
q->emitFinished();
}
void WritePasswordJobPrivate::gnomeKeyring_cb( int result, WritePasswordJobPrivate* self )
void JobPrivate::gnomeKeyring_writeCb(int result, JobPrivate* self )
{
if ( result == GnomeKeyring::RESULT_OK ) {
self->q->emitFinished();
@ -449,32 +488,19 @@ void WritePasswordJobPrivate::gnomeKeyring_cb( int result, WritePasswordJobPriva
}
}
void WritePasswordJobPrivate::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*)) );
}
void WritePasswordJobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
void JobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
watcher->deleteLater();
QDBusPendingReply<int> reply = *watcher;
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.data();
if ( reply.isError() ) {
fallbackOnError( reply.error() );
return;
}
if ( actual->contains( key ) )
{
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
actual->remove( key );
actual->sync();
plainTextStore.remove( key );
}
const int handle = reply.value();
@ -486,25 +512,75 @@ void WritePasswordJobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watc
QDBusPendingReply<int> nextReply;
if ( !textData.isEmpty() )
nextReply = iface->writePassword( handle, q->service(), key, textData, q->service() );
else if ( !binaryData.isEmpty() )
nextReply = iface->writeEntry( handle, q->service(), key, binaryData, q->service() );
if ( mode == Text )
nextReply = iface->writePassword( handle, q->service(), key, QString::fromUtf8(data), q->service() );
else if ( 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(kwalletWriteFinished(QDBusPendingCallWatcher*)) );
connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletFinished(QDBusPendingCallWatcher*)) );
}
void WritePasswordJobPrivate::kwalletWriteFinished( QDBusPendingCallWatcher* watcher ) {
watcher->deleteLater();
QDBusPendingReply<int> reply = *watcher;
if ( reply.isError() ) {
const QDBusError err = reply.error();
q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
return;
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("org.kde.kwalletd", "/modules/kwalletd", this);
break;
case Backend_Kwallet5:
kwalletWritePasswordScheduledStart("org.kde.kwalletd5", "/modules/kwalletd5", 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();
}

View File

@ -7,8 +7,7 @@
* details, check the accompanying file 'COPYING'. *
*****************************************************************************/
#include "keychain_p.h"
#include <QSettings>
#include "plaintextstore_p.h"
#include <windows.h>
#include <wincrypt.h>
@ -17,14 +16,110 @@
using namespace QKeychain;
void ReadPasswordJobPrivate::scheduledStart() {
//Use settings member if there, create local settings object if not
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.get();
#if defined(USE_CREDENTIAL_STORE)
#include <wincred.h>
QByteArray encrypted = actual->value( key ).toByteArray();
if ( encrypted.isNull() ) {
q->emitFinishedWithError( EntryNotFound, tr("Entry not found") );
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;
}
@ -53,24 +148,6 @@ void ReadPasswordJobPrivate::scheduledStart() {
}
void WritePasswordJobPrivate::scheduledStart() {
if ( mode == Delete ) {
//Use settings member if there, create local settings object if not
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.get();
actual->remove( key );
actual->sync();
if ( actual->status() != QSettings::NoError ) {
const QString err = actual->status() == QSettings::AccessError
? tr("Could not delete encrypted data from settings: access error")
: tr("Could not delete encrypted data from settings: format error");
q->emitFinishedWithError( OtherError, err );
} else {
q->emitFinished();
}
return;
}
QByteArray data = mode == Binary ? binaryData : textData.toUtf8();
DATA_BLOB blob_in, blob_out;
blob_in.pbData = reinterpret_cast<BYTE*>( data.data() );
blob_in.cbData = data.size();
@ -89,19 +166,23 @@ void WritePasswordJobPrivate::scheduledStart() {
const QByteArray encrypted( reinterpret_cast<char*>( blob_out.pbData ), blob_out.cbData );
LocalFree( blob_out.pbData );
//Use settings member if there, create local settings object if not
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.get();
actual->setValue( key, encrypted );
actual->sync();
if ( actual->status() != QSettings::NoError ) {
const QString errorString = actual->status() == QSettings::AccessError
? tr("Could not store encrypted data in settings: access error")
: tr("Could not store encrypted data in settings: format error");
q->emitFinishedWithError( OtherError, errorString );
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

View File

@ -0,0 +1,350 @@
#undef signals
#if defined(HAVE_LIBSECRET)
#include <libsecret/secret.h>
#endif
#include "libsecret_p.h"
#include <QLibrary>
#include <QDebug>
#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 = NULL;
static secret_password_lookup_finish_t secret_password_lookup_finish_fn = NULL;
static secret_password_store_t secret_password_store_fn = NULL;
static secret_password_store_finish_t secret_password_store_finish_fn = NULL;
static secret_password_clear_t secret_password_clear_fn = NULL;
static secret_password_clear_finish_t secret_password_clear_finish_fn = NULL;
static secret_password_free_t secret_password_free_fn = NULL;
static secret_error_get_quark_t secret_error_get_quark_fn = NULL;
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 = NULL;
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 != NULL) {
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(), NULL,
on_password_lookup, arg,
"user", arg->user.toUtf8().constData(),
"server", arg->server.toUtf8().constData(),
"type", "base64",
NULL);
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 = NULL;
QKeychain::JobPrivate *self = (QKeychain::JobPrivate*)inst;
Q_UNUSED(source);
secret_password_store_finish_fn (result, &error);
if (self) {
if (error != NULL) {
self->q->emitFinishedWithError( gerrorToCode(error),
QString::fromUtf8(error->message) );
} else {
self->q->emitFinished();
}
}
if (error != NULL) {
g_error_free (error);
}
}
static void
on_password_cleared (GObject *source,
GAsyncResult *result,
gpointer inst)
{
GError *error = NULL;
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 != NULL) {
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 == NULL)
return false;
if (secret_password_lookup_finish_fn == NULL)
return false;
if (secret_password_store_fn == NULL)
return false;
if (secret_password_store_finish_fn == NULL)
return false;
if (secret_password_clear_fn == NULL)
return false;
if (secret_password_clear_finish_fn == NULL)
return false;
if (secret_password_free_fn == NULL)
return false;
if (secret_error_get_quark_fn == NULL)
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;
qDebug() << Q_FUNC_INFO;
secret_password_lookup_fn (qtkeychainSchema(), NULL, on_password_lookup, arg,
"user", user.toUtf8().constData(),
"server", server.toUtf8().constData(),
"type", "plaintext",
NULL);
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;
}
qDebug() << Q_FUNC_INFO;
secret_password_store_fn (qtkeychainSchema(), SECRET_COLLECTION_DEFAULT,
display_name.toUtf8().constData(),
pwd.constData(), NULL, on_password_stored, self,
"user", user.toUtf8().constData(),
"server", server.toUtf8().constData(),
"type", type.toUtf8().constData(),
NULL);
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;
}
qDebug() << Q_FUNC_INFO;
secret_password_clear_fn (qtkeychainSchema(), NULL, on_password_cleared, self,
"user", key.toUtf8().constData(),
"server", service.toUtf8().constData(),
NULL);
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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -1,17 +0,0 @@
#ifndef QKEYCHAIN_EXPORT_H
#define QKEYCHAIN_EXPORT_H
#include <qglobal.h>
# ifdef QKEYCHAIN_STATICLIB
# undef QKEYCHAIN_SHAREDLIB
# define QKEYCHAIN_EXPORT
# else
# ifdef QKEYCHAIN_BUILD_QKEYCHAIN_LIB
# define QKEYCHAIN_EXPORT Q_DECL_EXPORT
# else
# define QKEYCHAIN_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif

View File

@ -0,0 +1,100 @@
# Minimal qmake support.
# This file is provided as is without any warranty.
# It can break at anytime or be removed without notice.
lessThan(QT_MAJOR_VERSION, 5) {
error("qtkeychain requires Qt 5 or later")
}
QTKEYCHAIN_PWD = $$PWD
CONFIG += depend_includepath
DEFINES += QTKEYCHAIN_NO_EXPORT
INCLUDEPATH += \
$$PWD/.. \
$$QTKEYCHAIN_PWD
HEADERS += \
$$QTKEYCHAIN_PWD/keychain_p.h \
$$QTKEYCHAIN_PWD/keychain.h
SOURCES += \
$$QTKEYCHAIN_PWD/keychain.cpp
unix:!android:!macx:!ios {
# Remove the following LIBSECRET_SUPPORT line
# to build without libsecret support.
DEFINES += LIBSECRET_SUPPORT
contains(DEFINES, LIBSECRET_SUPPORT) {
packagesExist(libsecret-1) {
!build_pass:message("Libsecret support: on")
CONFIG += link_pkgconfig
PKGCONFIG += libsecret-1
DEFINES += HAVE_LIBSECRET
} else {
!build_pass:warning("Libsecret not found.")
!build_pass:message("Libsecret support: off")
}
} else {
!build_pass:message("Libsecret support: off")
}
# Generate D-Bus interface:
DEFINES += KEYCHAIN_DBUS
QT += dbus
kwallet_interface.files = $$PWD/org.kde.KWallet.xml
DBUS_INTERFACES += kwallet_interface
HEADERS += \
$$QTKEYCHAIN_PWD/gnomekeyring_p.h \
$$QTKEYCHAIN_PWD/plaintextstore_p.h \
$$QTKEYCHAIN_PWD/libsecret_p.h
SOURCES += \
$$QTKEYCHAIN_PWD/keychain_unix.cpp \
$$QTKEYCHAIN_PWD/plaintextstore.cpp \
$$QTKEYCHAIN_PWD/gnomekeyring.cpp \
$$QTKEYCHAIN_PWD/libsecret.cpp
}
android {
QT += androidextras
HEADERS += \
$$QTKEYCHAIN_PWD/androidkeystore_p.h \
$$QTKEYCHAIN_PWD/plaintextstore_p.h
SOURCES += \
$$QTKEYCHAIN_PWD/androidkeystore.cpp \
$$QTKEYCHAIN_PWD/keychain_android.cpp \
$$QTKEYCHAIN_PWD/plaintextstore.cpp
}
win32 {
# Remove the following USE_CREDENTIAL_STORE line
# to use the CryptProtectData Windows API function
# instead of the Windows Credential Store.
DEFINES += USE_CREDENTIAL_STORE
contains(DEFINES, USE_CREDENTIAL_STORE) {
!build_pass:message("Windows Credential Store support: on")
LIBS += -ladvapi32
} else {
!build_pass:message("Windows Credential Store support: off")
LIBS += -lcrypt32
HEADERS += $$QTKEYCHAIN_PWD/plaintextstore_p.h
SOURCES += $$QTKEYCHAIN_PWD/plaintextstore.cpp
}
HEADERS += $$QTKEYCHAIN_PWD/libsecret_p.h
SOURCES += \
$$QTKEYCHAIN_PWD/keychain_win.cpp \
$$QTKEYCHAIN_PWD/libsecret.cpp
}
macx:!ios {
LIBS += -framework Security -framework Foundation
SOURCES += $$QTKEYCHAIN_PWD/keychain_apple.mm
}
ios {
LIBS += -framework Security -framework Foundation
OBJECTIVE_SOURCES += $$QTKEYCHAIN_PWD/keychain_ios.mm
}

View File

@ -52,6 +52,29 @@ int main( int argc, char** argv ) {
return 1;
}
std::cout << "Password stored successfully" << std::endl;
} else if ( *it == QLatin1String("bstore") ) {
if ( ++it == args.constEnd() )
return printUsage();
const QString acc = *it;
if ( ++it == args.constEnd() )
return printUsage();
const QString pass = *it;
if ( ++it != args.constEnd() )
return printUsage();
WritePasswordJob job( QLatin1String("qtkeychain-testclient") );
job.setAutoDelete( false );
job.setKey( acc );
job.setBinaryData( pass.toUtf8() );
QEventLoop loop;
job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()) );
job.start();
loop.exec();
if ( job.error() ) {
std::cerr << "Storing binary password failed: "
<< qPrintable(job.errorString()) << std::endl;
return 1;
}
std::cout << "Password stored successfully" << std::endl;
} else if ( *it == QLatin1String("restore") ) {
if ( ++it == args.constEnd() )
return printUsage();

View File

@ -1,176 +1,325 @@
<?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="548"/>
<location filename="../keychain_unix.cpp" line="556"/>
<source>Unknown error</source>
<translation type="unfinished">Unbekannter Fehler</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="574"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished">Konnte Brieftasche nicht öffnen: %1; %2</translation>
</message>
<message>
<location filename="../keychain_haiku.cpp" line="177"/>
<source>Password not found</source>
<translation type="unfinished">Passwort nicht gefunden</translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="165"/>
<source>Could not open keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="171"/>
<source>Could not remove private key from keystore</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::JobPrivate</name>
<message>
<location filename="../keychain_unix.cpp" line="265"/>
<source>Unknown error</source>
<translation type="unfinished">Unbekannter Fehler</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="509"/>
<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="140"/>
<location filename="../keychain_unix.cpp" line="187"/>
<location filename="../keychain_unix.cpp" line="197"/>
<source>Unknown error</source>
<translation>Unbekannter Fehler</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="129"/>
<location filename="../keychain_unix.cpp" line="178"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="222"/>
<location filename="../keychain_unix.cpp" line="286"/>
<source>No keychain service available</source>
<translation>Kein Schlüsselbund-Dienst verfügbar</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="224"/>
<location filename="../keychain_unix.cpp" line="288"/>
<source>Could not open wallet: %1; %2</source>
<translation>Konnte Brieftasche nicht öffnen: %1; %2</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="270"/>
<location filename="../keychain_unix.cpp" line="333"/>
<source>Access to keychain denied</source>
<translation>Zugriff auf Schlüsselbund verweigert</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="291"/>
<location filename="../keychain_unix.cpp" line="354"/>
<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="309"/>
<location filename="../keychain_unix.cpp" line="372"/>
<source>Unsupported entry type &apos;Map&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="312"/>
<location filename="../keychain_unix.cpp" line="375"/>
<source>Unknown kwallet entry type &apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="327"/>
<source>Could not read password: %1; %2</source>
<translation>Passwort konnte nicht ausgelesen werden: %1; %2</translation>
<translation type="vanished">Passwort konnte nicht ausgelesen werden: %1; %2</translation>
</message>
<message>
<location filename="../keychain_mac.cpp" line="76"/>
<location filename="../keychain_haiku.cpp" line="96"/>
<source>Password not found</source>
<translation>Passwort nicht gefunden</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="300"/>
<location filename="../keychain_win.cpp" line="27"/>
<location filename="../keychain_unix.cpp" line="363"/>
<location filename="../keychain_android.cpp" line="50"/>
<source>Entry not found</source>
<translation>Eintrag nicht gefunden</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="44"/>
<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>
<message>
<location filename="../keychain_android.cpp" line="58"/>
<source>Could not open keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="66"/>
<source>Could not retrieve private key from keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="73"/>
<source>Could not create decryption cipher</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../keychain_unix.cpp" line="364"/>
<location filename="../keychain_unix.cpp" line="372"/>
<location filename="../keychain_unix.cpp" line="425"/>
<location filename="../keychain_unix.cpp" line="452"/>
<source>Unknown error</source>
<translation>Unbekannter Fehler</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="352"/>
<location filename="../keychain_unix.cpp" line="415"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="420"/>
<location filename="../keychain_unix.cpp" line="505"/>
<location filename="../keychain_unix.cpp" line="468"/>
<source>Could not open wallet: %1; %2</source>
<translation>Konnte Brieftasche nicht öffnen: %1; %2</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="483"/>
<source>Access to keychain denied</source>
<translation>Zugriff auf Schlüsselbund verweigert</translation>
<translation type="vanished">Zugriff auf Schlüsselbund verweigert</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="64"/>
<source>Could not delete encrypted data from settings: access error</source>
<translation>Kann verschlüsselte Daten nicht aus den Einstellungen entfernen: Zugriffsfehler</translation>
<translation type="vanished">Kann verschlüsselte Daten nicht aus den Einstellungen entfernen: Zugriffsfehler</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="65"/>
<source>Could not delete encrypted data from settings: format error</source>
<translation>Kann verschlüsselte Daten nicht aus den Einstellungen entfernen: Formatfehler</translation>
<translation type="vanished">Kann verschlüsselte Daten nicht aus den Einstellungen entfernen: Formatfehler</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="85"/>
<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>
<location filename="../keychain_win.cpp" line="100"/>
<source>Could not store encrypted data in settings: access error</source>
<translation>Kann verschlüsselte Daten nicht in den Einstellungen speichern: Zugriffsfehler</translation>
<translation type="vanished">Kann verschlüsselte Daten nicht in den Einstellungen speichern: Zugriffsfehler</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="101"/>
<source>Could not store encrypted data in settings: format error</source>
<translation>Kann verschlüsselte Daten nicht in den Einstellungen speichern: Formatfehler</translation>
<translation type="vanished">Kann verschlüsselte Daten nicht in den Einstellungen speichern: Formatfehler</translation>
</message>
<message>
<location filename="../keychain_haiku.cpp" line="144"/>
<source>Password not found</source>
<translation type="unfinished">Passwort nicht gefunden</translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="93"/>
<source>Could not open keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="116"/>
<source>Could not create private key generator</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="123"/>
<source>Could not generate new private key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="131"/>
<source>Could not retrieve private key from keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="139"/>
<source>Could not create encryption cipher</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="147"/>
<source>Could not encrypt data</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../keychain_unix.cpp" line="167"/>
<location filename="../keychain_unix.cpp" line="225"/>
<source>Access to keychain denied</source>
<translation>Zugriff auf Schlüsselbund verweigert</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="169"/>
<location filename="../keychain_unix.cpp" line="227"/>
<source>No keyring daemon</source>
<translation>Kein Schlüsselbund-Dienst </translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="171"/>
<location filename="../keychain_unix.cpp" line="229"/>
<source>Already unlocked</source>
<translation>Bereits entsperrt</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="173"/>
<location filename="../keychain_unix.cpp" line="231"/>
<source>No such keyring</source>
<translation>Kein solcher Schlüsselbund</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="175"/>
<location filename="../keychain_unix.cpp" line="233"/>
<source>Bad arguments</source>
<translation>Ungültige Argumente</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="177"/>
<location filename="../keychain_unix.cpp" line="235"/>
<source>I/O error</source>
<translation>Ein-/Ausgabe-Fehler</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="179"/>
<location filename="../keychain_unix.cpp" line="237"/>
<source>Cancelled</source>
<translation>Abgebrochen</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="181"/>
<location filename="../keychain_unix.cpp" line="239"/>
<source>Keyring already exists</source>
<translation>Schlüsselbund existiert bereits</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="183"/>
<location filename="../keychain_unix.cpp" line="241"/>
<source>No match</source>
<translation>Kein Treffer</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="188"/>
<location filename="../keychain_unix.cpp" line="246"/>
<source>Unknown error</source>
<translation>Unbekannter Fehler</translation>
</message>
<message>
<location filename="../keychain_mac.cpp" line="31"/>
<location filename="../keychain_mac.cpp" line="33"/>
<source>%1 (OSStatus %2)</source>
<location filename="../libsecret.cpp" line="122"/>
<source>Entry not found</source>
<translation type="unfinished">Eintrag nicht gefunden</translation>
</message>
<message>
<location filename="../keychain_haiku.cpp" line="72"/>
<source>error 0x%1: %2</source>
<translation type="unfinished"></translation>
</message>
</context>

View File

@ -0,0 +1,334 @@
<?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="548"/>
<location filename="../keychain_unix.cpp" line="556"/>
<source>Unknown error</source>
<translation>Erreur inconnue</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="574"/>
<source>Could not open wallet: %1; %2</source>
<translation>Impossible d&apos;ouvrir le portefeuille : %1; %2</translation>
</message>
<message>
<location filename="../keychain_haiku.cpp" line="177"/>
<source>Password not found</source>
<translation>Mot de passe introuvable</translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="165"/>
<source>Could not open keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="171"/>
<source>Could not remove private key from keystore</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::JobPrivate</name>
<message>
<location filename="../keychain_unix.cpp" line="265"/>
<source>Unknown error</source>
<translation>Erreur inconnue</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="509"/>
<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="187"/>
<location filename="../keychain_unix.cpp" line="197"/>
<source>Unknown error</source>
<translation>Erreur inconnue</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="178"/>
<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="286"/>
<source>No keychain service available</source>
<translation>Aucun service de trousseau disponible</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="288"/>
<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="333"/>
<source>Access to keychain denied</source>
<translation>Accès au trousseau refusé</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="354"/>
<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="372"/>
<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="375"/>
<source>Unknown kwallet entry type &apos;%1&apos;</source>
<translation>Type de trousseau inconnu &apos;%1&apos;</translation>
</message>
<message>
<source>Could not read password: %1; %2</source>
<translation type="vanished">Impossible de lire le mot de passe : %1; %2</translation>
</message>
<message>
<location filename="../keychain_haiku.cpp" line="96"/>
<source>Password not found</source>
<translation>Mot de passe introuvable</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="363"/>
<location filename="../keychain_android.cpp" line="50"/>
<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>
<message>
<location filename="../keychain_android.cpp" line="58"/>
<source>Could not open keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="66"/>
<source>Could not retrieve private key from keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="73"/>
<source>Could not create decryption cipher</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../keychain_unix.cpp" line="425"/>
<location filename="../keychain_unix.cpp" line="452"/>
<source>Unknown error</source>
<translation>Erreur inconnue</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="415"/>
<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="468"/>
<source>Could not open wallet: %1; %2</source>
<translation>Impossible d&apos;ouvrir le trousseau : %1; %2</translation>
</message>
<message>
<source>Access to keychain denied</source>
<translation type="vanished">Accès au trousseau refusé</translation>
</message>
<message>
<source>Could not delete encrypted data from settings: access error</source>
<translation type="vanished">Impossible de supprimer des données chiffrées dans les paramètres : Erreur d&apos;accès</translation>
</message>
<message>
<source>Could not delete encrypted data from settings: format error</source>
<translation type="vanished">Impossible de supprimer des données chiffrées dans les paramètres : Erreur de format</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>
<message>
<source>Could not store encrypted data in settings: access error</source>
<translation type="vanished">Impossible de stocker des données chiffrées dans les paramètres : Erreur d&apos;accès</translation>
</message>
<message>
<source>Could not store encrypted data in settings: format error</source>
<translation type="vanished">Impossible de stocker des données chiffrées dans les paramètres : Erreur de format</translation>
</message>
<message>
<location filename="../keychain_haiku.cpp" line="144"/>
<source>Password not found</source>
<translation>Mot de passe introuvable</translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="93"/>
<source>Could not open keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="116"/>
<source>Could not create private key generator</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="123"/>
<source>Could not generate new private key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="131"/>
<source>Could not retrieve private key from keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="139"/>
<source>Could not create encryption cipher</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="147"/>
<source>Could not encrypt data</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../keychain_unix.cpp" line="225"/>
<source>Access to keychain denied</source>
<translation>Accès au trousseau refusé</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="227"/>
<source>No keyring daemon</source>
<translation>Aucun démon de trousseau</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="229"/>
<source>Already unlocked</source>
<translation>Déjà déverrouillé</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="231"/>
<source>No such keyring</source>
<translation>Aucun trousseau</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="233"/>
<source>Bad arguments</source>
<translation>Mauvais arguments</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="235"/>
<source>I/O error</source>
<translation>Erreur d&apos;E/S</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="237"/>
<source>Cancelled</source>
<translation>Annulé</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="239"/>
<source>Keyring already exists</source>
<translation>Trousseau déjà existant</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="241"/>
<source>No match</source>
<translation>Aucune correspondance</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="246"/>
<source>Unknown error</source>
<translation>Erreur inconnue</translation>
</message>
<message>
<source>OS X Keychain error (OSStatus %1)</source>
<translation type="vanished">OS X Keychain error (OSStatus %1)</translation>
</message>
<message>
<source>%1 (OSStatus %2)</source>
<translation type="vanished">%1 (OSStatus %2)</translation>
</message>
<message>
<location filename="../libsecret.cpp" line="122"/>
<source>Entry not found</source>
<translation>Entrée introuvable</translation>
</message>
<message>
<location filename="../keychain_haiku.cpp" line="72"/>
<source>error 0x%1: %2</source>
<translation>Erreur 0x%1 : %2</translation>
</message>
</context>
</TS>

View File

@ -1,178 +1,331 @@
<?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="548"/>
<location filename="../keychain_unix.cpp" line="556"/>
<source>Unknown error</source>
<translation type="unfinished">Eroare necunoscută</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="574"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished">Nu se poate deschide portofelul: %1; %2</translation>
</message>
<message>
<location filename="../keychain_haiku.cpp" line="177"/>
<source>Password not found</source>
<translation type="unfinished">Parola nu a fost găsită</translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="165"/>
<source>Could not open keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="171"/>
<source>Could not remove private key from keystore</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::JobPrivate</name>
<message>
<location filename="../keychain_unix.cpp" line="265"/>
<source>Unknown error</source>
<translation type="unfinished">Eroare necunoscută</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="509"/>
<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="140"/>
<location filename="../keychain_unix.cpp" line="187"/>
<location filename="../keychain_unix.cpp" line="197"/>
<source>Unknown error</source>
<translation>Eroare necunoscută</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="129"/>
<location filename="../keychain_unix.cpp" line="178"/>
<source>D-Bus is not running</source>
<translation>D-Bus nu rulează</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="222"/>
<location filename="../keychain_unix.cpp" line="286"/>
<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="224"/>
<location filename="../keychain_unix.cpp" line="288"/>
<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="270"/>
<location filename="../keychain_unix.cpp" line="333"/>
<source>Access to keychain denied</source>
<translation>Acces interzis la serviciul de chei</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="291"/>
<location filename="../keychain_unix.cpp" line="354"/>
<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="309"/>
<location filename="../keychain_unix.cpp" line="372"/>
<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="312"/>
<location filename="../keychain_unix.cpp" line="375"/>
<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="327"/>
<source>Could not read password: %1; %2</source>
<translation>Nu se poate citi parola: %1; %2</translation>
<translation type="vanished">Nu se poate citi parola: %1; %2</translation>
</message>
<message>
<location filename="../keychain_mac.cpp" line="76"/>
<location filename="../keychain_haiku.cpp" line="96"/>
<source>Password not found</source>
<translation>Parola nu a fost găsită</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="300"/>
<location filename="../keychain_win.cpp" line="27"/>
<location filename="../keychain_unix.cpp" line="363"/>
<location filename="../keychain_android.cpp" line="50"/>
<source>Entry not found</source>
<translation>Înregistrarea nu a fost găsită</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="44"/>
<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>
<message>
<location filename="../keychain_android.cpp" line="58"/>
<source>Could not open keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="66"/>
<source>Could not retrieve private key from keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="73"/>
<source>Could not create decryption cipher</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../keychain_unix.cpp" line="364"/>
<location filename="../keychain_unix.cpp" line="372"/>
<location filename="../keychain_unix.cpp" line="425"/>
<location filename="../keychain_unix.cpp" line="452"/>
<source>Unknown error</source>
<translation>Eroare necunoscută</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="352"/>
<location filename="../keychain_unix.cpp" line="415"/>
<source>D-Bus is not running</source>
<translation>D-Bus nu rulează</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="420"/>
<location filename="../keychain_unix.cpp" line="505"/>
<location filename="../keychain_unix.cpp" line="468"/>
<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="483"/>
<source>Access to keychain denied</source>
<translation>Acces interzis la serviciul de chei</translation>
<translation type="vanished">Acces interzis la serviciul de chei</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="64"/>
<source>Could not delete encrypted data from settings: access error</source>
<translation>Nu se pot șterge datele criptate din setări: eroare de acces</translation>
<translation type="vanished">Nu se pot șterge datele criptate din setări: eroare de acces</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="65"/>
<source>Could not delete encrypted data from settings: format error</source>
<translation>Nu se pot șterge datele criptate din setări: eroare de format</translation>
<translation type="vanished">Nu se pot șterge datele criptate din setări: eroare de format</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="85"/>
<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>
<location filename="../keychain_win.cpp" line="100"/>
<source>Could not store encrypted data in settings: access error</source>
<translation>Nu se pot stoca datele criptate în setări: eroare de acces</translation>
<translation type="vanished">Nu se pot stoca datele criptate în setări: eroare de acces</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="101"/>
<source>Could not store encrypted data in settings: format error</source>
<translation>Nu se pot stoca datele criptate în setări: eroare de format</translation>
<translation type="vanished">Nu se pot stoca datele criptate în setări: eroare de format</translation>
</message>
<message>
<location filename="../keychain_haiku.cpp" line="144"/>
<source>Password not found</source>
<translation type="unfinished">Parola nu a fost găsită</translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="93"/>
<source>Could not open keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="116"/>
<source>Could not create private key generator</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="123"/>
<source>Could not generate new private key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="131"/>
<source>Could not retrieve private key from keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="139"/>
<source>Could not create encryption cipher</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="147"/>
<source>Could not encrypt data</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../keychain_unix.cpp" line="167"/>
<location filename="../keychain_unix.cpp" line="225"/>
<source>Access to keychain denied</source>
<translation>Acces interzis la serviciul de chei</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="169"/>
<location filename="../keychain_unix.cpp" line="227"/>
<source>No keyring daemon</source>
<translation>Niciun demon pentru inelul de chei</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="171"/>
<location filename="../keychain_unix.cpp" line="229"/>
<source>Already unlocked</source>
<translation>Deja deblocat</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="173"/>
<location filename="../keychain_unix.cpp" line="231"/>
<source>No such keyring</source>
<translation>Nu există astfel de inel de chei</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="175"/>
<location filename="../keychain_unix.cpp" line="233"/>
<source>Bad arguments</source>
<translation>Argumente greșite</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="177"/>
<location filename="../keychain_unix.cpp" line="235"/>
<source>I/O error</source>
<translation>Eroare de I/E</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="179"/>
<location filename="../keychain_unix.cpp" line="237"/>
<source>Cancelled</source>
<translation>Anulat</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="181"/>
<location filename="../keychain_unix.cpp" line="239"/>
<source>Keyring already exists</source>
<translation>Inelul de chei deja există</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="183"/>
<location filename="../keychain_unix.cpp" line="241"/>
<source>No match</source>
<translation>Nicio potrivire</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="188"/>
<location filename="../keychain_unix.cpp" line="246"/>
<source>Unknown error</source>
<translation>Eroare necunoscută</translation>
</message>
<message>
<location filename="../keychain_mac.cpp" line="31"/>
<location filename="../keychain_mac.cpp" line="33"/>
<source>%1 (OSStatus %2)</source>
<translation>%1 (OSStatus %2)</translation>
<translation type="vanished">%1 (OSStatus %2)</translation>
</message>
<message>
<location filename="../libsecret.cpp" line="122"/>
<source>Entry not found</source>
<translation type="unfinished">Înregistrarea nu a fost găsită</translation>
</message>
<message>
<location filename="../keychain_haiku.cpp" line="72"/>
<source>error 0x%1: %2</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -0,0 +1,310 @@
<?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="548"/>
<location filename="../keychain_unix.cpp" line="556"/>
<source>Unknown error</source>
<translation>Неизвестная ошибка</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="574"/>
<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>
<location filename="../keychain_haiku.cpp" line="177"/>
<source>Password not found</source>
<translation type="unfinished">Пароль не найден</translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="165"/>
<source>Could not open keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="171"/>
<source>Could not remove private key from keystore</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::JobPrivate</name>
<message>
<location filename="../keychain_unix.cpp" line="265"/>
<source>Unknown error</source>
<translation>Неизвестная ошибка</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="509"/>
<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_haiku.cpp" line="96"/>
<source>Password not found</source>
<translation>Пароль не найден</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="178"/>
<source>D-Bus is not running</source>
<translation>D-Bus не запущен</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="187"/>
<location filename="../keychain_unix.cpp" line="197"/>
<source>Unknown error</source>
<translation>Неизвестная ошибка</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="286"/>
<source>No keychain service available</source>
<translation>Служба связки ключей недоступна</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="288"/>
<source>Could not open wallet: %1; %2</source>
<translation>Не удалось открыть кошелёк: %1; %2</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="333"/>
<source>Access to keychain denied</source>
<translation>Доступ к связке ключей запрещён</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="354"/>
<source>Could not determine data type: %1; %2</source>
<translation>Не удалось определить тип данных: %1; %2</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="363"/>
<location filename="../keychain_android.cpp" line="50"/>
<source>Entry not found</source>
<translation>Запись не найдена</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="372"/>
<source>Unsupported entry type &apos;Map&apos;</source>
<translation>Неподдерживаемый тип записи &apos;Map&apos;</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="375"/>
<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>
<message>
<location filename="../keychain_android.cpp" line="58"/>
<source>Could not open keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="66"/>
<source>Could not retrieve private key from keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="73"/>
<source>Could not create decryption cipher</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../keychain_unix.cpp" line="415"/>
<source>D-Bus is not running</source>
<translation>D-Bus не запущен</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="425"/>
<location filename="../keychain_unix.cpp" line="452"/>
<source>Unknown error</source>
<translation>Неизвестная ошибка</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="468"/>
<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>
<location filename="../keychain_haiku.cpp" line="144"/>
<source>Password not found</source>
<translation type="unfinished">Пароль не найден</translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="93"/>
<source>Could not open keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="116"/>
<source>Could not create private key generator</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="123"/>
<source>Could not generate new private key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="131"/>
<source>Could not retrieve private key from keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="139"/>
<source>Could not create encryption cipher</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="147"/>
<source>Could not encrypt data</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<source>OS X Keychain error (OSStatus %1)</source>
<translation type="vanished">Ошибка связки ключей OS X (OSStatus %1)</translation>
</message>
<message>
<source>%1 (OSStatus %2)</source>
<translation type="vanished">%1 (OSStatus %2)</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="225"/>
<source>Access to keychain denied</source>
<translation>Доступ к связке ключей запрещён</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="227"/>
<source>No keyring daemon</source>
<translation>Нет демона связки ключей</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="229"/>
<source>Already unlocked</source>
<translation>Уже разблокировано</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="231"/>
<source>No such keyring</source>
<translation>Связка ключей не найдена</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="233"/>
<source>Bad arguments</source>
<translation>Неверные аргументы</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="235"/>
<source>I/O error</source>
<translation>Ошибка ввода/вывода</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="237"/>
<source>Cancelled</source>
<translation>Отменено</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="239"/>
<source>Keyring already exists</source>
<translation>Связка ключей уже существует</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="241"/>
<source>No match</source>
<translation>Нет совпадений</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="246"/>
<source>Unknown error</source>
<translation>Неизвестная ошибка</translation>
</message>
<message>
<location filename="../libsecret.cpp" line="122"/>
<source>Entry not found</source>
<translation>Запись не найдена</translation>
</message>
<message>
<location filename="../keychain_haiku.cpp" line="72"/>
<source>error 0x%1: %2</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -0,0 +1,330 @@
<?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="548"/>
<location filename="../keychain_unix.cpp" line="556"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="574"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished">%1; %2</translation>
</message>
<message>
<location filename="../keychain_haiku.cpp" line="177"/>
<source>Password not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="165"/>
<source>Could not open keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="171"/>
<source>Could not remove private key from keystore</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::JobPrivate</name>
<message>
<location filename="../keychain_unix.cpp" line="265"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="509"/>
<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="187"/>
<location filename="../keychain_unix.cpp" line="197"/>
<source>Unknown error</source>
<translation></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="178"/>
<source>D-Bus is not running</source>
<translation>D-Bus </translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="286"/>
<source>No keychain service available</source>
<translation></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="288"/>
<source>Could not open wallet: %1; %2</source>
<translation>%1; %2</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="333"/>
<source>Access to keychain denied</source>
<translation></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="354"/>
<source>Could not determine data type: %1; %2</source>
<translation>%1; %2</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="372"/>
<source>Unsupported entry type &apos;Map&apos;</source>
<translation> &apos;Map&apos;</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="375"/>
<source>Unknown kwallet entry type &apos;%1&apos;</source>
<translation> kwallet &apos;%1&apos;</translation>
</message>
<message>
<source>Could not read password: %1; %2</source>
<translation type="vanished">%1; %2</translation>
</message>
<message>
<location filename="../keychain_haiku.cpp" line="96"/>
<source>Password not found</source>
<translation></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="363"/>
<location filename="../keychain_android.cpp" line="50"/>
<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>
<message>
<location filename="../keychain_android.cpp" line="58"/>
<source>Could not open keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="66"/>
<source>Could not retrieve private key from keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="73"/>
<source>Could not create decryption cipher</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../keychain_unix.cpp" line="425"/>
<location filename="../keychain_unix.cpp" line="452"/>
<source>Unknown error</source>
<translation></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="415"/>
<source>D-Bus is not running</source>
<translation>D-Bus </translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="468"/>
<source>Could not open wallet: %1; %2</source>
<translation>%1; %2</translation>
</message>
<message>
<source>Access to keychain denied</source>
<translation type="vanished"></translation>
</message>
<message>
<source>Could not delete encrypted data from settings: access error</source>
<translation type="vanished"></translation>
</message>
<message>
<source>Could not delete encrypted data from settings: format error</source>
<translation type="vanished"></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>Could not store encrypted data in settings: access error</source>
<translation type="vanished"></translation>
</message>
<message>
<source>Could not store encrypted data in settings: format error</source>
<translation type="vanished"></translation>
</message>
<message>
<location filename="../keychain_haiku.cpp" line="144"/>
<source>Password not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="93"/>
<source>Could not open keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="116"/>
<source>Could not create private key generator</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="123"/>
<source>Could not generate new private key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="131"/>
<source>Could not retrieve private key from keystore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="139"/>
<source>Could not create encryption cipher</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_android.cpp" line="147"/>
<source>Could not encrypt data</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../keychain_unix.cpp" line="225"/>
<source>Access to keychain denied</source>
<translation></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="227"/>
<source>No keyring daemon</source>
<translation></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="229"/>
<source>Already unlocked</source>
<translation></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="231"/>
<source>No such keyring</source>
<translation></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="233"/>
<source>Bad arguments</source>
<translation></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="235"/>
<source>I/O error</source>
<translation>I/O </translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="237"/>
<source>Cancelled</source>
<translation></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="239"/>
<source>Keyring already exists</source>
<translation></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="241"/>
<source>No match</source>
<translation></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="246"/>
<source>Unknown error</source>
<translation></translation>
</message>
<message>
<source>%1 (OSStatus %2)</source>
<translation type="vanished">%1 (OSStatus %2)</translation>
</message>
<message>
<location filename="../libsecret.cpp" line="122"/>
<source>Entry not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_haiku.cpp" line="72"/>
<source>error 0x%1: %2</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -23,9 +23,6 @@ TEMPLATE = app
win32 {
RC_FILE = rsrc/fuel.rc
LIBS += -luser32 -lshell32 -luuid
# Prevent batch file being called multiple times
!build_pass:system(intl\convert.bat)
}
macx {
@ -53,7 +50,6 @@ unix:!macx {
icon.files += rsrc/icons/fuel.png
INSTALLS += target desktop icon
system(intl/convert.sh)
}
@ -114,36 +110,7 @@ RESOURCES += \
rsrc/resources.qrc
# QtKeychain
SOURCES += ext/qtkeychain/keychain.cpp
HEADERS += ext/qtkeychain/keychain.h \
ext/qtkeychain/keychain_p.h \
ext/qtkeychain/qkeychain_export.h
DEFINES += QKEYCHAIN_STATICLIB
unix:!macx {
QT += dbus
SOURCES += ext/qtkeychain/keychain_unix.cpp \
ext/qtkeychain/gnomekeyring.cpp
HEADERS += ext/qtkeychain/gnomekeyring_p.h
DBUS_INTERFACES += ext/qtkeychain/org.kde.KWallet.xml
}
macx {
SOURCES += ext/qtkeychain/keychain_mac.cpp
LIBS += -framework CoreFoundation -framework Security
}
win32 {
SOURCES += ext/qtkeychain/keychain_win.cpp
LIBS += -lCrypt32
}
include(ext/qtkeychain.pri)
CODECFORTR = UTF-8

View File

@ -1,20 +0,0 @@
@echo off
setlocal EnableDelayedExpansion
set SCRIPTDIR=%~dp0%
set PRJDIR=%SCRIPTDIR%..
set QTPATH=C:\Qt\5.5\mingw492_32
if NOT "%QTDIR%"=="" set QTPATH=%QTDIR%
echo Using QT at %QTPATH%
echo Converting localizations
del /q %PRJDIR%\rsrc\intl\*
if not exist %PRJDIR%\rsrc\intl\ mkdir %PRJDIR%\rsrc\intl\
REM Convert all except the en_US which is the original text in the code
for %%i in (de_DE el_GR es_ES fr_FR ru_RU pt_PT it_IT nl_NL ko_KR) do (
%QTPATH%\bin\lrelease %PRJDIR%\intl\%%i.ts -qm %PRJDIR%\rsrc\intl\%%i.qm
)
endlocal

View File

@ -1,36 +0,0 @@
#!/bin/sh
SCRIPTDIR="$( cd "$( dirname "$0" )" && pwd )"
PRJDIR=$SCRIPTDIR/..
INTLDIR=$SCRIPTDIR
# Detect lrelease tool
if which lrelease-qt5 2>/dev/null; then
LRELEASE="lrelease-qt5"
elif which lrelease4 2>/dev/null; then
LRELEASE="lrelease4"
elif which lrelease 2>/dev/null; then
LRELEASE="lrelease"
else
echo "lrelease not found"
exit 1
fi
echo "Using ${LRELEASE}"
echo "Converting localizations"
rm -rf $PRJDIR/rsrc/intl
mkdir $PRJDIR/rsrc/intl
for i in $INTLDIR/*.ts
do
BASE=`basename $i .ts`
# Convert all except the en_US which is
# the original text in the code
if [ "$BASE" != "en_US" ]; then
echo "$TARGET"
$LRELEASE $i -qm $PRJDIR/rsrc/intl/$BASE.qm
fi
done

View File

@ -108,6 +108,11 @@ Released under the GNU GPL</source>
<source>Local Repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Pfad der lokalen Repositorydatei</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="136"/>
<source>The URL of the HTTP proxy. Leave blank if not required</source>
@ -118,11 +123,6 @@ Released under the GNU GPL</source>
<source>HTTP Proxy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Pfad der lokalen Repositorydatei</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="59"/>
<location filename="../ui/CloneDialog.ui" line="127"/>
@ -342,6 +342,11 @@ Released under the GNU GPL</source>
<source>Main Toolbar</source>
<translation>Hauptwerkzeugleiste</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="346"/>
<location filename="../ui/MainWindow.ui" line="349"/>
@ -353,11 +358,6 @@ Released under the GNU GPL</source>
<source>F5</source>
<translation>F5</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="361"/>
<source>&amp;Commit</source>
@ -470,6 +470,11 @@ Released under the GNU GPL</source>
<source>C&amp;lone...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="486"/>
<source>Clone a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="495"/>
<source>&amp;Push</source>
@ -490,6 +495,74 @@ Released under the GNU GPL</source>
<source>Pull changes from the default remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="841"/>
<location filename="../ui/MainWindow.ui" line="844"/>
<source>View files as a list</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="931"/>
<source>Create &amp;Tag</source>
@ -617,11 +690,6 @@ Released under the GNU GPL</source>
<source>Abort the current operation</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="486"/>
<source>Clone a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="501"/>
<source>Push changes to the remote repository</source>
@ -642,28 +710,6 @@ Released under the GNU GPL</source>
<source>Ctrl+L</source>
<translation>Strg+L</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="561"/>
<location filename="../src/MainWindow.cpp" line="1714"/>
@ -728,47 +774,6 @@ Released under the GNU GPL</source>
<source>Open File</source>
<translation type="unfinished">Öffne Datei</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="841"/>
<location filename="../ui/MainWindow.ui" line="844"/>
<source>View files as a list</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="636"/>
<source>Revert</source>
@ -939,11 +944,6 @@ Released under the GNU GPL</source>
<source>Rename the selected folder</source>
<translation>Ausgewählten Ordner umbenennen</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="889"/>
<source>Stash changes</source>
@ -1603,178 +1603,8 @@ Die folgenden Dateien werden in das Repository verschoben.</translation>
<translation>Die folgenden Stashes werden entfernt</translation>
</message>
</context>
<context>
<name>QKeychain::ReadPasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="76"/>
<source>Password not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="129"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="140"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="222"/>
<source>No keychain service available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="224"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="270"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="291"/>
<source>Could not determine data type: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="300"/>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="27"/>
<source>Entry not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="309"/>
<source>Unsupported entry type &apos;Map&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="312"/>
<source>Unknown kwallet entry type &apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="327"/>
<source>Could not read password: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="44"/>
<source>Could not decrypt data</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="352"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="364"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="372"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="420"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="505"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="483"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="64"/>
<source>Could not delete encrypted data from settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="65"/>
<source>Could not delete encrypted data from settings: format error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="85"/>
<source>Encryption failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="100"/>
<source>Could not store encrypted data in settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="101"/>
<source>Could not store encrypted data in settings: format error</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="31"/>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="33"/>
<source>%1 (OSStatus %2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="167"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="169"/>
<source>No keyring daemon</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="171"/>
<source>Already unlocked</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="173"/>
<source>No such keyring</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="175"/>
<source>Bad arguments</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="177"/>
<source>I/O error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="179"/>
<source>Cancelled</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="181"/>
<source>Keyring already exists</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="183"/>
<source>No match</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="188"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/AppSettings.cpp" line="44"/>
<source>Custom Action %0</source>

View File

@ -108,6 +108,11 @@ Released under the GNU GPL</source>
<source>Local Repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Διαδρομή για το αρχείο τοπικού αποθετηρίου</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="136"/>
<source>The URL of the HTTP proxy. Leave blank if not required</source>
@ -118,11 +123,6 @@ Released under the GNU GPL</source>
<source>HTTP Proxy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Διαδρομή για το αρχείο τοπικού αποθετηρίου</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="59"/>
<location filename="../ui/CloneDialog.ui" line="127"/>
@ -342,6 +342,11 @@ Released under the GNU GPL</source>
<source>Main Toolbar</source>
<translation>Κύρια μπάρα εργαλείων</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="346"/>
<location filename="../ui/MainWindow.ui" line="349"/>
@ -353,11 +358,6 @@ Released under the GNU GPL</source>
<source>F5</source>
<translation>F5</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="361"/>
<source>&amp;Commit</source>
@ -490,6 +490,68 @@ Released under the GNU GPL</source>
<source>Pull changes from the default remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="931"/>
<source>Create &amp;Tag</source>
@ -642,28 +704,6 @@ Released under the GNU GPL</source>
<source>Ctrl+L</source>
<translation>Ctrl+L</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="561"/>
<location filename="../src/MainWindow.cpp" line="1714"/>
@ -728,41 +768,6 @@ Released under the GNU GPL</source>
<source>Open File</source>
<translation>Άνοιγμα Αρχείου</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="841"/>
<location filename="../ui/MainWindow.ui" line="844"/>
@ -939,11 +944,6 @@ Released under the GNU GPL</source>
<source>Rename the selected folder</source>
<translation>Μετονομασία του επιλεγμένου φακέλου</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="889"/>
<source>Stash changes</source>
@ -1602,178 +1602,8 @@ The following files will be moved in the repository.</source>
<translation>Οι παρακάτω στοίβες θα διαγραφούν.</translation>
</message>
</context>
<context>
<name>QKeychain::ReadPasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="76"/>
<source>Password not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="129"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="140"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="222"/>
<source>No keychain service available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="224"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="270"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="291"/>
<source>Could not determine data type: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="300"/>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="27"/>
<source>Entry not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="309"/>
<source>Unsupported entry type &apos;Map&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="312"/>
<source>Unknown kwallet entry type &apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="327"/>
<source>Could not read password: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="44"/>
<source>Could not decrypt data</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="352"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="364"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="372"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="420"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="505"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="483"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="64"/>
<source>Could not delete encrypted data from settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="65"/>
<source>Could not delete encrypted data from settings: format error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="85"/>
<source>Encryption failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="100"/>
<source>Could not store encrypted data in settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="101"/>
<source>Could not store encrypted data in settings: format error</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="31"/>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="33"/>
<source>%1 (OSStatus %2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="167"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="169"/>
<source>No keyring daemon</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="171"/>
<source>Already unlocked</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="173"/>
<source>No such keyring</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="175"/>
<source>Bad arguments</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="177"/>
<source>I/O error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="179"/>
<source>Cancelled</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="181"/>
<source>Keyring already exists</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="183"/>
<source>No match</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="188"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/AppSettings.cpp" line="44"/>
<source>Custom Action %0</source>

View File

@ -108,6 +108,11 @@ Released under the GNU GPL</source>
<source>Local Repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Path to the local repository file</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="136"/>
<source>The URL of the HTTP proxy. Leave blank if not required</source>
@ -118,11 +123,6 @@ Released under the GNU GPL</source>
<source>HTTP Proxy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Path to the local repository file</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="59"/>
<location filename="../ui/CloneDialog.ui" line="127"/>
@ -342,6 +342,11 @@ Released under the GNU GPL</source>
<source>Main Toolbar</source>
<translation>Main Toolbar</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="346"/>
<location filename="../ui/MainWindow.ui" line="349"/>
@ -353,11 +358,6 @@ Released under the GNU GPL</source>
<source>F5</source>
<translation>F5</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="361"/>
<source>&amp;Commit</source>
@ -490,6 +490,68 @@ Released under the GNU GPL</source>
<source>Pull changes from the default remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="931"/>
<source>Create &amp;Tag</source>
@ -642,28 +704,6 @@ Released under the GNU GPL</source>
<source>Ctrl+L</source>
<translation>Ctrl+L</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="561"/>
<location filename="../src/MainWindow.cpp" line="1714"/>
@ -728,41 +768,6 @@ Released under the GNU GPL</source>
<source>Open File</source>
<translation>Open File</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="841"/>
<location filename="../ui/MainWindow.ui" line="844"/>
@ -939,11 +944,6 @@ Released under the GNU GPL</source>
<source>Rename the selected folder</source>
<translation>Rename the selected folder</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="889"/>
<source>Stash changes</source>
@ -1602,178 +1602,8 @@ The following files will be moved in the repository.</translation>
<translation>The following stashes will be deleted.</translation>
</message>
</context>
<context>
<name>QKeychain::ReadPasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="76"/>
<source>Password not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="129"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="140"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="222"/>
<source>No keychain service available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="224"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="270"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="291"/>
<source>Could not determine data type: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="300"/>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="27"/>
<source>Entry not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="309"/>
<source>Unsupported entry type &apos;Map&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="312"/>
<source>Unknown kwallet entry type &apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="327"/>
<source>Could not read password: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="44"/>
<source>Could not decrypt data</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="352"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="364"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="372"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="420"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="505"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="483"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="64"/>
<source>Could not delete encrypted data from settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="65"/>
<source>Could not delete encrypted data from settings: format error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="85"/>
<source>Encryption failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="100"/>
<source>Could not store encrypted data in settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="101"/>
<source>Could not store encrypted data in settings: format error</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="31"/>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="33"/>
<source>%1 (OSStatus %2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="167"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="169"/>
<source>No keyring daemon</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="171"/>
<source>Already unlocked</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="173"/>
<source>No such keyring</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="175"/>
<source>Bad arguments</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="177"/>
<source>I/O error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="179"/>
<source>Cancelled</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="181"/>
<source>Keyring already exists</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="183"/>
<source>No match</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="188"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/AppSettings.cpp" line="44"/>
<source>Custom Action %0</source>

View File

@ -108,6 +108,11 @@ Released under the GNU GPL</source>
<source>Local Repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Ruta al archivo del depósito local</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="136"/>
<source>The URL of the HTTP proxy. Leave blank if not required</source>
@ -118,11 +123,6 @@ Released under the GNU GPL</source>
<source>HTTP Proxy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Ruta al archivo del depósito local</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="59"/>
<location filename="../ui/CloneDialog.ui" line="127"/>
@ -342,6 +342,11 @@ Released under the GNU GPL</source>
<source>Main Toolbar</source>
<translation>Barra principal de herramientas</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="346"/>
<location filename="../ui/MainWindow.ui" line="349"/>
@ -353,11 +358,6 @@ Released under the GNU GPL</source>
<source>F5</source>
<translation>F5</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="361"/>
<source>&amp;Commit</source>
@ -470,6 +470,11 @@ Released under the GNU GPL</source>
<source>C&amp;lone...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="486"/>
<source>Clone a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="495"/>
<source>&amp;Push</source>
@ -490,6 +495,74 @@ Released under the GNU GPL</source>
<source>Pull changes from the default remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="841"/>
<location filename="../ui/MainWindow.ui" line="844"/>
<source>View files as a list</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="931"/>
<source>Create &amp;Tag</source>
@ -617,11 +690,6 @@ Released under the GNU GPL</source>
<source>Abort the current operation</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="486"/>
<source>Clone a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="501"/>
<source>Push changes to the remote repository</source>
@ -642,28 +710,6 @@ Released under the GNU GPL</source>
<source>Ctrl+L</source>
<translation>Ctrl+L</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="561"/>
<location filename="../src/MainWindow.cpp" line="1714"/>
@ -728,47 +774,6 @@ Released under the GNU GPL</source>
<source>Open File</source>
<translation type="unfinished">Abrir Archivo</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="841"/>
<location filename="../ui/MainWindow.ui" line="844"/>
<source>View files as a list</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="636"/>
<source>Revert</source>
@ -939,11 +944,6 @@ Released under the GNU GPL</source>
<source>Rename the selected folder</source>
<translation>Renombrar la carpeta seleccionada</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="889"/>
<source>Stash changes</source>
@ -1602,178 +1602,8 @@ Los siguientes archivos serán movidos al depósito.</translation>
<translation>Serán borrados los siguientes cambios apartados</translation>
</message>
</context>
<context>
<name>QKeychain::ReadPasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="76"/>
<source>Password not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="129"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="140"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="222"/>
<source>No keychain service available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="224"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="270"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="291"/>
<source>Could not determine data type: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="300"/>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="27"/>
<source>Entry not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="309"/>
<source>Unsupported entry type &apos;Map&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="312"/>
<source>Unknown kwallet entry type &apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="327"/>
<source>Could not read password: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="44"/>
<source>Could not decrypt data</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="352"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="364"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="372"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="420"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="505"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="483"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="64"/>
<source>Could not delete encrypted data from settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="65"/>
<source>Could not delete encrypted data from settings: format error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="85"/>
<source>Encryption failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="100"/>
<source>Could not store encrypted data in settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="101"/>
<source>Could not store encrypted data in settings: format error</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="31"/>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="33"/>
<source>%1 (OSStatus %2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="167"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="169"/>
<source>No keyring daemon</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="171"/>
<source>Already unlocked</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="173"/>
<source>No such keyring</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="175"/>
<source>Bad arguments</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="177"/>
<source>I/O error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="179"/>
<source>Cancelled</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="181"/>
<source>Keyring already exists</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="183"/>
<source>No match</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="188"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/AppSettings.cpp" line="44"/>
<source>Custom Action %0</source>

View File

@ -108,6 +108,11 @@ Released under the GNU GPL</source>
<source>Local Repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Chemin vers le fichier du dépôt local</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="136"/>
<source>The URL of the HTTP proxy. Leave blank if not required</source>
@ -118,11 +123,6 @@ Released under the GNU GPL</source>
<source>HTTP Proxy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Chemin vers le fichier du dépôt local</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="59"/>
<location filename="../ui/CloneDialog.ui" line="127"/>
@ -342,6 +342,11 @@ Released under the GNU GPL</source>
<source>Main Toolbar</source>
<translation>Barre d&apos;outils principale</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="346"/>
<location filename="../ui/MainWindow.ui" line="349"/>
@ -353,11 +358,6 @@ Released under the GNU GPL</source>
<source>F5</source>
<translation>F5</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="361"/>
<source>&amp;Commit</source>
@ -490,6 +490,68 @@ Released under the GNU GPL</source>
<source>Pull changes from the default remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="931"/>
<source>Create &amp;Tag</source>
@ -642,28 +704,6 @@ Released under the GNU GPL</source>
<source>Ctrl+L</source>
<translation>Ctrl+L</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="561"/>
<location filename="../src/MainWindow.cpp" line="1714"/>
@ -728,41 +768,6 @@ Released under the GNU GPL</source>
<source>Open File</source>
<translation>Ouvrir le fichier</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="841"/>
<location filename="../ui/MainWindow.ui" line="844"/>
@ -939,11 +944,6 @@ Released under the GNU GPL</source>
<source>Rename the selected folder</source>
<translation>Renommer le dossier sélectionné</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="889"/>
<source>Stash changes</source>
@ -1602,178 +1602,8 @@ Les fichiers suivants seront déplacés dans le dépôt.</translation>
<translation>Les réserves suivantes seront supprimées.</translation>
</message>
</context>
<context>
<name>QKeychain::ReadPasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="76"/>
<source>Password not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="129"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="140"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="222"/>
<source>No keychain service available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="224"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="270"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="291"/>
<source>Could not determine data type: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="300"/>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="27"/>
<source>Entry not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="309"/>
<source>Unsupported entry type &apos;Map&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="312"/>
<source>Unknown kwallet entry type &apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="327"/>
<source>Could not read password: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="44"/>
<source>Could not decrypt data</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="352"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="364"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="372"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="420"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="505"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="483"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="64"/>
<source>Could not delete encrypted data from settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="65"/>
<source>Could not delete encrypted data from settings: format error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="85"/>
<source>Encryption failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="100"/>
<source>Could not store encrypted data in settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="101"/>
<source>Could not store encrypted data in settings: format error</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="31"/>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="33"/>
<source>%1 (OSStatus %2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="167"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="169"/>
<source>No keyring daemon</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="171"/>
<source>Already unlocked</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="173"/>
<source>No such keyring</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="175"/>
<source>Bad arguments</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="177"/>
<source>I/O error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="179"/>
<source>Cancelled</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="181"/>
<source>Keyring already exists</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="183"/>
<source>No match</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="188"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/AppSettings.cpp" line="44"/>
<source>Custom Action %0</source>

View File

@ -108,6 +108,11 @@ Released under the GNU GPL</source>
<source>Local Repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Percorso al file dell&apos;archivio locale</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="136"/>
<source>The URL of the HTTP proxy. Leave blank if not required</source>
@ -118,11 +123,6 @@ Released under the GNU GPL</source>
<source>HTTP Proxy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Percorso al file dell&apos;archivio locale</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="59"/>
<location filename="../ui/CloneDialog.ui" line="127"/>
@ -342,6 +342,11 @@ Released under the GNU GPL</source>
<source>Main Toolbar</source>
<translation>Barra degli strumenti principale</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="346"/>
<location filename="../ui/MainWindow.ui" line="349"/>
@ -353,11 +358,6 @@ Released under the GNU GPL</source>
<source>F5</source>
<translation>F5</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="361"/>
<source>&amp;Commit</source>
@ -490,6 +490,68 @@ Released under the GNU GPL</source>
<source>Pull changes from the default remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="931"/>
<source>Create &amp;Tag</source>
@ -642,28 +704,6 @@ Released under the GNU GPL</source>
<source>Ctrl+L</source>
<translation> Ctrl+L</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="561"/>
<location filename="../src/MainWindow.cpp" line="1714"/>
@ -728,41 +768,6 @@ Released under the GNU GPL</source>
<source>Open File</source>
<translation>Apri file</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="841"/>
<location filename="../ui/MainWindow.ui" line="844"/>
@ -939,11 +944,6 @@ Released under the GNU GPL</source>
<source>Rename the selected folder</source>
<translation>Rinomina la cartella selezionata</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="889"/>
<source>Stash changes</source>
@ -1602,178 +1602,8 @@ Saranno spostati nell&apos;archivio i file seguenti:</translation>
<translation>Le seguenti modiche riposte verranno rimosse</translation>
</message>
</context>
<context>
<name>QKeychain::ReadPasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="76"/>
<source>Password not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="129"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="140"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="222"/>
<source>No keychain service available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="224"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="270"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="291"/>
<source>Could not determine data type: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="300"/>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="27"/>
<source>Entry not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="309"/>
<source>Unsupported entry type &apos;Map&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="312"/>
<source>Unknown kwallet entry type &apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="327"/>
<source>Could not read password: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="44"/>
<source>Could not decrypt data</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="352"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="364"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="372"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="420"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="505"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="483"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="64"/>
<source>Could not delete encrypted data from settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="65"/>
<source>Could not delete encrypted data from settings: format error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="85"/>
<source>Encryption failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="100"/>
<source>Could not store encrypted data in settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="101"/>
<source>Could not store encrypted data in settings: format error</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="31"/>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="33"/>
<source>%1 (OSStatus %2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="167"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="169"/>
<source>No keyring daemon</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="171"/>
<source>Already unlocked</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="173"/>
<source>No such keyring</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="175"/>
<source>Bad arguments</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="177"/>
<source>I/O error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="179"/>
<source>Cancelled</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="181"/>
<source>Keyring already exists</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="183"/>
<source>No match</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="188"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/AppSettings.cpp" line="44"/>
<source>Custom Action %0</source>

View File

@ -108,6 +108,11 @@ Released under the GNU GPL</source>
<source>Local Repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation> .</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="136"/>
<source>The URL of the HTTP proxy. Leave blank if not required</source>
@ -118,11 +123,6 @@ Released under the GNU GPL</source>
<source>HTTP Proxy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation> .</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="59"/>
<location filename="../ui/CloneDialog.ui" line="127"/>
@ -342,6 +342,11 @@ Released under the GNU GPL</source>
<source>Main Toolbar</source>
<translation> </translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="346"/>
<location filename="../ui/MainWindow.ui" line="349"/>
@ -353,11 +358,6 @@ Released under the GNU GPL</source>
<source>F5</source>
<translation>F5</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="361"/>
<source>&amp;Commit</source>
@ -490,6 +490,68 @@ Released under the GNU GPL</source>
<source>Pull changes from the default remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="931"/>
<source>Create &amp;Tag</source>
@ -642,28 +704,6 @@ Released under the GNU GPL</source>
<source>Ctrl+L</source>
<translation>Ctrl+L</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="561"/>
<location filename="../src/MainWindow.cpp" line="1714"/>
@ -728,41 +768,6 @@ Released under the GNU GPL</source>
<source>Open File</source>
<translation> </translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="841"/>
<location filename="../ui/MainWindow.ui" line="844"/>
@ -939,11 +944,6 @@ Released under the GNU GPL</source>
<source>Rename the selected folder</source>
<translation> .</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="889"/>
<source>Stash changes</source>
@ -1602,178 +1602,8 @@ The following files will be moved in the repository.</source>
<translation> .</translation>
</message>
</context>
<context>
<name>QKeychain::ReadPasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="76"/>
<source>Password not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="129"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="140"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="222"/>
<source>No keychain service available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="224"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="270"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="291"/>
<source>Could not determine data type: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="300"/>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="27"/>
<source>Entry not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="309"/>
<source>Unsupported entry type &apos;Map&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="312"/>
<source>Unknown kwallet entry type &apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="327"/>
<source>Could not read password: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="44"/>
<source>Could not decrypt data</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="352"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="364"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="372"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="420"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="505"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="483"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="64"/>
<source>Could not delete encrypted data from settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="65"/>
<source>Could not delete encrypted data from settings: format error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="85"/>
<source>Encryption failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="100"/>
<source>Could not store encrypted data in settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="101"/>
<source>Could not store encrypted data in settings: format error</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="31"/>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="33"/>
<source>%1 (OSStatus %2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="167"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="169"/>
<source>No keyring daemon</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="171"/>
<source>Already unlocked</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="173"/>
<source>No such keyring</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="175"/>
<source>Bad arguments</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="177"/>
<source>I/O error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="179"/>
<source>Cancelled</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="181"/>
<source>Keyring already exists</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="183"/>
<source>No match</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="188"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/AppSettings.cpp" line="44"/>
<source>Custom Action %0</source>

View File

@ -108,6 +108,11 @@ Released under the GNU GPL</source>
<source>Local Repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Pad naar het lokale archief</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="136"/>
<source>The URL of the HTTP proxy. Leave blank if not required</source>
@ -118,11 +123,6 @@ Released under the GNU GPL</source>
<source>HTTP Proxy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Pad naar het lokale archief</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="59"/>
<location filename="../ui/CloneDialog.ui" line="127"/>
@ -342,6 +342,11 @@ Released under the GNU GPL</source>
<source>Main Toolbar</source>
<translation>Hoofd taakbalk</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="346"/>
<location filename="../ui/MainWindow.ui" line="349"/>
@ -353,11 +358,6 @@ Released under the GNU GPL</source>
<source>F5</source>
<translation>F5</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="361"/>
<source>&amp;Commit</source>
@ -490,6 +490,68 @@ Released under the GNU GPL</source>
<source>Pull changes from the default remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="931"/>
<source>Create &amp;Tag</source>
@ -642,28 +704,6 @@ Released under the GNU GPL</source>
<source>Ctrl+L</source>
<translation>Ctrl+L</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="561"/>
<location filename="../src/MainWindow.cpp" line="1714"/>
@ -728,41 +768,6 @@ Released under the GNU GPL</source>
<source>Open File</source>
<translation>Open Bestand</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="841"/>
<location filename="../ui/MainWindow.ui" line="844"/>
@ -939,11 +944,6 @@ Released under the GNU GPL</source>
<source>Rename the selected folder</source>
<translation>Geselecteerde map hernoemen</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="889"/>
<source>Stash changes</source>
@ -1602,178 +1602,8 @@ De volgende bestanden worden verplaatst naar het archief.</translation>
<translation>De volgende verborgen veranderingen zullen worden verwijderd.</translation>
</message>
</context>
<context>
<name>QKeychain::ReadPasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="76"/>
<source>Password not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="129"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="140"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="222"/>
<source>No keychain service available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="224"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="270"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="291"/>
<source>Could not determine data type: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="300"/>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="27"/>
<source>Entry not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="309"/>
<source>Unsupported entry type &apos;Map&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="312"/>
<source>Unknown kwallet entry type &apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="327"/>
<source>Could not read password: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="44"/>
<source>Could not decrypt data</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="352"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="364"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="372"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="420"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="505"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="483"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="64"/>
<source>Could not delete encrypted data from settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="65"/>
<source>Could not delete encrypted data from settings: format error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="85"/>
<source>Encryption failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="100"/>
<source>Could not store encrypted data in settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="101"/>
<source>Could not store encrypted data in settings: format error</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="31"/>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="33"/>
<source>%1 (OSStatus %2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="167"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="169"/>
<source>No keyring daemon</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="171"/>
<source>Already unlocked</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="173"/>
<source>No such keyring</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="175"/>
<source>Bad arguments</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="177"/>
<source>I/O error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="179"/>
<source>Cancelled</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="181"/>
<source>Keyring already exists</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="183"/>
<source>No match</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="188"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/AppSettings.cpp" line="44"/>
<source>Custom Action %0</source>

View File

@ -108,6 +108,11 @@ Released under the GNU GPL</source>
<source>Local Repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Caminho para o ficheiro do repositório local</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="136"/>
<source>The URL of the HTTP proxy. Leave blank if not required</source>
@ -118,11 +123,6 @@ Released under the GNU GPL</source>
<source>HTTP Proxy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Caminho para o ficheiro do repositório local</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="59"/>
<location filename="../ui/CloneDialog.ui" line="127"/>
@ -342,6 +342,11 @@ Released under the GNU GPL</source>
<source>Main Toolbar</source>
<translation>Barra de ferramentas</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="346"/>
<location filename="../ui/MainWindow.ui" line="349"/>
@ -353,11 +358,6 @@ Released under the GNU GPL</source>
<source>F5</source>
<translation>F5</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="361"/>
<source>&amp;Commit</source>
@ -490,6 +490,68 @@ Released under the GNU GPL</source>
<source>Pull changes from the default remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="931"/>
<source>Create &amp;Tag</source>
@ -642,28 +704,6 @@ Released under the GNU GPL</source>
<source>Ctrl+L</source>
<translation>Ctrl+L</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="561"/>
<location filename="../src/MainWindow.cpp" line="1714"/>
@ -728,41 +768,6 @@ Released under the GNU GPL</source>
<source>Open File</source>
<translation>Abrir ficheiro</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="841"/>
<location filename="../ui/MainWindow.ui" line="844"/>
@ -939,11 +944,6 @@ Released under the GNU GPL</source>
<source>Rename the selected folder</source>
<translation>Renomear a pasta seleccionada</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="889"/>
<source>Stash changes</source>
@ -1602,178 +1602,8 @@ Os ficheiros seguintes irão ser movidos no repositório.</translation>
<translation>Os seguintes armazéns irão ser eliminados.</translation>
</message>
</context>
<context>
<name>QKeychain::ReadPasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="76"/>
<source>Password not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="129"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="140"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="222"/>
<source>No keychain service available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="224"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="270"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="291"/>
<source>Could not determine data type: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="300"/>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="27"/>
<source>Entry not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="309"/>
<source>Unsupported entry type &apos;Map&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="312"/>
<source>Unknown kwallet entry type &apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="327"/>
<source>Could not read password: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="44"/>
<source>Could not decrypt data</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="352"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="364"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="372"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="420"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="505"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="483"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="64"/>
<source>Could not delete encrypted data from settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="65"/>
<source>Could not delete encrypted data from settings: format error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="85"/>
<source>Encryption failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="100"/>
<source>Could not store encrypted data in settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="101"/>
<source>Could not store encrypted data in settings: format error</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="31"/>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="33"/>
<source>%1 (OSStatus %2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="167"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="169"/>
<source>No keyring daemon</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="171"/>
<source>Already unlocked</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="173"/>
<source>No such keyring</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="175"/>
<source>Bad arguments</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="177"/>
<source>I/O error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="179"/>
<source>Cancelled</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="181"/>
<source>Keyring already exists</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="183"/>
<source>No match</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="188"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/AppSettings.cpp" line="44"/>
<source>Custom Action %0</source>

View File

@ -108,6 +108,11 @@ Released under the GNU GPL</source>
<source>Local Repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Путь к локальному хранилищу</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="136"/>
<source>The URL of the HTTP proxy. Leave blank if not required</source>
@ -118,11 +123,6 @@ Released under the GNU GPL</source>
<source>HTTP Proxy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="108"/>
<source>Path to the local repository file</source>
<translation>Путь к локальному хранилищу</translation>
</message>
<message>
<location filename="../ui/CloneDialog.ui" line="59"/>
<location filename="../ui/CloneDialog.ui" line="127"/>
@ -342,6 +342,11 @@ Released under the GNU GPL</source>
<source>Main Toolbar</source>
<translation>Панель</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="346"/>
<location filename="../ui/MainWindow.ui" line="349"/>
@ -353,11 +358,6 @@ Released under the GNU GPL</source>
<source>F5</source>
<translation>F5</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="343"/>
<source>&amp;Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="361"/>
<source>&amp;Commit</source>
@ -490,6 +490,68 @@ Released under the GNU GPL</source>
<source>Pull changes from the default remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="931"/>
<source>Create &amp;Tag</source>
@ -642,28 +704,6 @@ Released under the GNU GPL</source>
<source>Ctrl+L</source>
<translation>Ctrl+L</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="531"/>
<source>&amp;Push to Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="534"/>
<location filename="../ui/MainWindow.ui" line="537"/>
<source>Push changes to a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="546"/>
<source>Pu&amp;ll from Remote</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="549"/>
<location filename="../ui/MainWindow.ui" line="552"/>
<source>Pull changes from a remote repository</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="561"/>
<location filename="../src/MainWindow.cpp" line="1714"/>
@ -728,41 +768,6 @@ Released under the GNU GPL</source>
<source>Open File</source>
<translation>Открыть Файл</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="717"/>
<source>U&amp;ndo</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="750"/>
<source>&amp;Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="753"/>
<source>Update the workspace to a revision</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="788"/>
<source>&amp;Modified Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="802"/>
<source>&amp;Unchanged Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="816"/>
<source>Un&amp;known Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="827"/>
<source>&amp;Ignored Files</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="841"/>
<location filename="../ui/MainWindow.ui" line="844"/>
@ -939,11 +944,6 @@ Released under the GNU GPL</source>
<source>Rename the selected folder</source>
<translation>Переименовать выбранную директорию</translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="886"/>
<source>&amp;Stash Changes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/MainWindow.ui" line="889"/>
<source>Stash changes</source>
@ -1602,178 +1602,8 @@ The following files will be moved in the repository.</source>
<translation>Следующие изменения в Буфере будут удалены</translation>
</message>
</context>
<context>
<name>QKeychain::ReadPasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="76"/>
<source>Password not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="129"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="140"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="222"/>
<source>No keychain service available</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="224"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="270"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="291"/>
<source>Could not determine data type: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="300"/>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="27"/>
<source>Entry not found</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="309"/>
<source>Unsupported entry type &apos;Map&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="312"/>
<source>Unknown kwallet entry type &apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="327"/>
<source>Could not read password: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="44"/>
<source>Could not decrypt data</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="352"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="364"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="372"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="420"/>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="505"/>
<source>Could not open wallet: %1; %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="483"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="64"/>
<source>Could not delete encrypted data from settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="65"/>
<source>Could not delete encrypted data from settings: format error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="85"/>
<source>Encryption failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="100"/>
<source>Could not store encrypted data in settings: access error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_win.cpp" line="101"/>
<source>Could not store encrypted data in settings: format error</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="31"/>
<location filename="../ext/qtkeychain/keychain_mac.cpp" line="33"/>
<source>%1 (OSStatus %2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="167"/>
<source>Access to keychain denied</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="169"/>
<source>No keyring daemon</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="171"/>
<source>Already unlocked</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="173"/>
<source>No such keyring</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="175"/>
<source>Bad arguments</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="177"/>
<source>I/O error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="179"/>
<source>Cancelled</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="181"/>
<source>Keyring already exists</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="183"/>
<source>No match</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ext/qtkeychain/keychain_unix.cpp" line="188"/>
<source>Unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/AppSettings.cpp" line="44"/>
<source>Custom Action %0</source>

View File

@ -1,5 +0,0 @@
#!/bin/sh
# Update existing translations
lupdate-qt5 ../fuel.pro

View File

@ -156,22 +156,24 @@
<file>icons/Zoom In-01.png</file>
<file>icons/Zoom Out-01.png</file>
</qresource>
<qresource prefix="/intl">
<file>intl/el_GR.qm</file>
<file>intl/de_DE.qm</file>
<file>intl/es_ES.qm</file>
<file>intl/fr_FR.qm</file>
<file>intl/ru_RU.qm</file>
<file>intl/pt_PT.qm</file>
<file>intl/it_IT.qm</file>
<file>intl/nl_NL.qm</file>
<file>intl/ko_KR.qm</file>
</qresource>
<qresource prefix="/docs">
<file>docs/Translators.txt</file>
<file>docs/Licenses.txt</file>
</qresource>
<qresource prefix="/version">
<file alias="manifest">../manifest.uuid</file>
</qresource>
<!-->
<qresource prefix="/intl">
<file>intl/el_GR.qm</file>
<file>intl/de_DE.qm</file>
<file>intl/es_ES.qm</file>
<file>intl/fr_FR.qm</file>
<file>intl/ru_RU.qm</file>
<file>intl/pt_PT.qm</file>
<file>intl/it_IT.qm</file>
<file>intl/nl_NL.qm</file>
<file>intl/ko_KR.qm</file>
</qresource>
<-->
<qresource prefix="/docs">
<file>docs/Translators.txt</file>
<file>docs/Licenses.txt</file>
</qresource>
<qresource prefix="/version">
<file alias="manifest">../manifest.uuid</file>
</qresource>
</RCC>