Comparar commits

..

22 Commits

Autor SHA1 Mensagem Data
Jenkins for ownCloud b66125baa7 [tx-robot] updated from transifex 2013-07-30 01:26:48 -04:00
Jenkins for ownCloud 1bc7468287 [tx-robot] updated from transifex 2013-07-28 01:27:25 -04:00
Jenkins for ownCloud bb5ea68807 [tx-robot] updated from transifex 2013-07-24 01:26:42 -04:00
Jenkins for ownCloud 9641ed1202 [tx-robot] updated from transifex 2013-07-22 01:26:25 -04:00
Jenkins for ownCloud c736439440 [tx-robot] updated from transifex 2013-07-21 01:26:20 -04:00
Jenkins for ownCloud 50674cf153 [tx-robot] updated from transifex 2013-07-18 01:26:22 -04:00
Jenkins for ownCloud 7270644e84 [tx-robot] updated from transifex 2013-07-17 02:15:53 -04:00
Jenkins for ownCloud 43b4ddd722 [tx-robot] updated from transifex 2013-07-16 01:27:18 -04:00
Jenkins for ownCloud bdd91712e7 [tx-robot] updated from transifex 2013-07-15 17:11:07 -04:00
Jenkins for ownCloud 72efce1416 [tx-robot] updated from transifex 2013-07-14 01:45:10 +02:00
Jenkins for ownCloud 3ff8db10e8 [tx-robot] updated from transifex 2013-07-13 01:26:34 +02:00
Klaas Freitag 24bdf60bd7 Documented the docexpire option.
(cherry picked from commit 5da6103fb5)
2013-07-12 18:17:18 +02:00
Daniel Molkentin 79924d5eec Detect missing system tray
Fixes #497
(cherry picked from commit a63863b65c)
2013-07-12 18:16:48 +02:00
Daniel Molkentin 4cebcce735 Folder wizard: Warn if a chosen dir is read-only
Fixes #755
2013-07-12 13:36:25 +02:00
Jenkins for ownCloud 48441ccb96 [tx-robot] updated from transifex 2013-07-11 01:28:57 +02:00
Jenkins for ownCloud 183fe2735d [tx-robot] updated from transifex 2013-07-09 01:29:53 +02:00
Jenkins for ownCloud 957dea03a6 [tx-robot] updated from transifex 2013-07-06 01:28:00 +02:00
Jenkins for ownCloud 859f79087f [tx-robot] updated from transifex 2013-07-05 01:26:53 +02:00
Jenkins for ownCloud 9be49c0c9a [tx-robot] updated from transifex 2013-07-04 09:37:46 +02:00
Jenkins for ownCloud 3fdc8aeecb [tx-robot] updated from transifex 2013-07-02 15:39:13 +02:00
Jenkins for ownCloud 68085915c4 [tx-robot] updated from transifex 2013-06-29 01:58:03 +02:00
Jenkins for ownCloud ca4ad7b71c [tx-robot] updated from transifex 2013-06-28 01:27:27 +02:00
282 arquivos alterados com 76562 adições e 64573 exclusões
-5
Ver Arquivo
@@ -1,4 +1,3 @@
.gitmodules
*build*/
*flymake*
CMakeLists.txt.user*
@@ -6,7 +5,3 @@ CMakeLists.txt.user*
*~
*.autosave
doc/_build/*
*~
*.kate-swp
*.kdev4
win/
-3
Ver Arquivo
@@ -1,3 +0,0 @@
[submodule "doc/ocdoc"]
path = doc/ocdoc
url = https://github.com/owncloud/documentation
+36 -27
Ver Arquivo
@@ -4,8 +4,6 @@ project(mirall)
set(PACKAGE "mirall")
set( CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules )
include(Warnings)
set(OEM_THEME_DIR "" CACHE STRING "Define directory containing a custom theme")
if ( EXISTS ${OEM_THEME_DIR}/OEM.cmake )
include ( ${OEM_THEME_DIR}/OEM.cmake )
@@ -13,27 +11,11 @@ else ()
include ( ${CMAKE_SOURCE_DIR}/OWNCLOUD.cmake )
endif()
if (NOT DEFINED APPLICATION_SHORTNAME)
set ( APPLICATION_SHORTNAME ${APPLICATION_NAME} )
endif()
include(${CMAKE_SOURCE_DIR}/VERSION.cmake)
configure_file( ${CMAKE_SOURCE_DIR}/src/mirall/version.h.in "${CMAKE_CURRENT_BINARY_DIR}/src/mirall/version.h" )
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR} "${CMAKE_CURRENT_BINARY_DIR}/src/mirall/")
#####
## handle DBUS for Fdo notifications
if( UNIX AND NOT APPLE )
add_definitions( -DUSE_FDO_NOTIFICATIONS)
set(WITH_DBUS ON)
endif()
####
include(GNUInstallDirs)
include(DefineInstallationPaths)
include(QtVersionAbstraction)
setup_qt()
include(GetGitRevisionDescription)
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
@@ -50,8 +32,10 @@ if (${GIT_SHA1} STREQUAL "GITDIR-NOTFOUND")
endif()
endif()
set(SYSCONFDIR ${SYSCONF_INSTALL_DIR})
set(DATADIR ${DATA_INSTALL_DIR})
## stupid, we should upstream this
if("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr" AND NOT CMAKE_INSTALL_SYSCONFDIR)
set(CMAKE_INSTALL_SYSCONFDIR "/etc")
endif()
#####
## handle BUILD_OWNCLOUD_OSX_BUNDLE
@@ -70,14 +54,19 @@ else()
endif()
#####
#####
## handle DBUS for Fdo notifications
if( UNIX AND NOT APPLE )
add_definitions( -DUSE_FDO_NOTIFICATIONS)
endif()
####
#### find libs
#find_package(Qt4 4.7.0 COMPONENTS QtCore QtGui QtXml QtNetwork QtTest QtWebkit REQUIRED )
#if( UNIX AND NOT APPLE ) # Fdo notifications
# find_package(Qt4 4.7.0 COMPONENTS QtDBus REQUIRED )
#endif()
find_package(Neon REQUIRED)
find_package(Qt4 4.6.0 COMPONENTS QtCore QtGui QtXml QtNetwork QtTest REQUIRED )
if( UNIX AND NOT APPLE ) # Fdo notifications
find_package(Qt4 4.6.0 COMPONENTS QtDBus REQUIRED )
endif()
find_package(Csync REQUIRED)
find_package(QtKeychain REQUIRED)
if(UNIX)
find_package(INotify REQUIRED)
else()
@@ -85,12 +74,32 @@ find_package(INotify)
endif()
find_package(Sphinx)
find_package(PdfLatex)
find_package(QtKeychain)
set(WITH_QTKEYCHAIN ${QTKEYCHAIN_FOUND})
set(USE_INOTIFY ${INOTIFY_FOUND})
configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
set(CPACK_SOURCE_IGNORE_FILES
# hidden files
"/\\\\..+$"
# temporary files
"\\\\.swp$"
# backup files
"~$"
# others
"\\\\.#"
"/#"
"/build/"
"/_build/"
# used before
"\\\\.o$"
"\\\\.lo$"
"\\\\.la$"
"Makefile\\\\.in$"
)
include(OwnCloudCPack.cmake)
add_definitions(-DUNICODE)
@@ -112,5 +121,5 @@ endif(UNIT_TESTING)
if(BUILD_OWNCLOUD_OSX_BUNDLE)
configure_file(sync-exclude.lst ${OWNCLOUD_OSX_BUNDLE}/Contents/Resources/sync-exclude.lst COPYONLY)
else()
install( FILES sync-exclude.lst DESTINATION ${SYSCONFDIR}/${APPLICATION_SHORTNAME} )
install( FILES sync-exclude.lst DESTINATION ${CMAKE_INSTALL_SYSCONFDIR} )
endif()
+2
Ver Arquivo
@@ -21,9 +21,11 @@ set( CSYNC_BINARY_DIR @CSYNC_BINARY_DIR@ )
set( MINGW_ROOT @CMAKE_FIND_ROOT_PATH@ )
if(CSYNC_BINARY_DIR)
set( CSYNC_LIBRARY_DIR "${CSYNC_BINARY_DIR}/src" )
set( CSYNC_PLUGIN_DIR "${CSYNC_BINARY_DIR}/modules" )
set( CSYNC_CONFIG_DIR "${CSYNC_BINARY_DIR}/config" )
else()
set( CSYNC_LIBRARY_DIR "${MINGW_ROOT}/bin" )
set( CSYNC_PLUGIN_DIR "${MINGW_ROOT}/plugins-0" ) #FIXME: whatever it is
set( CSYNC_CONFIG_DIR "${MINGW_ROOT}/etc/ocsync" )
endif()
set( BUILD_OWNCLOUD_OSX_BUNDLE @BUILD_OWNCLOUD_OSX_BUNDLE@)
-53
Ver Arquivo
@@ -1,58 +1,5 @@
ChangeLog
=========
version 1.4.1 (release 2013-09-24 ), csync 0.90.1 required
* Translation and documentation fixes.
* Fixed error display in settings/status dialog, displays multi
line error messages now correctly.
* Wait up to 30 secs before complaining about missing systray
Fixes bug #949
* Fixed utf8 issues with basic auth authentication, fixes bug #941
* Fixed remote folder selector, avoid recursive syncing, fixes bug #962
* Handle and display network problems at startup correctly.
* Enable and disable the folder watcher during syncs correctly.
* Fix setting of thread priority.
* Fixed file size display.
* Fixed various folder wizard issues, bug #992
* Made "Sync started" message optional, fixes bug #934
* Fixed shutdown, avoid crashed config on win32, fixes bug #945
* Pop up config wizard if no server url is configured, fixes bug #1018
* Settings: calculate sidebar width dynamically, fixes bug #1020
* Fixed a crash if sync folders were removed, fixes bug #713
* Do proper resync after network disconnect, fixes bug #1007
* Various minor code fixes
version 1.4.0 (release 2013-09-04 ), csync 0.90.0 required
* New Scheduler: Only sync when there are actual changes in the server
* Add a Settings Dialog, move Proxy Settings there
* Transform folder Status Dialog into Account Settings, provide feedback via context menu
* Add Bandwidth Control
* Add a visual storage/quota indicator (context menu and account settings)
* Add progress indication (context menu and account settings)
* Introduce a sync history, persisting results across syncs
* Move ability to switch to mono icons from a switch to a Settings option
* Add "Launch on System Startup" GUI option
* Add "Show Desktop Nofications"GUI option (enabled by default)
top optionally disable sync notifications
* Add Help item, pointing to online reference
* Implement graphical selection of remote folders in FolderWizard
* Allow custom ignore patterns
* Add an editor for ingore patterns
* ALlow to flag certain ignore patterns as discardable
* Ensure to ship with all valid translations
* Progress Dialog now preserves the last syncned items across sync runs
* Split Setup Wizard into multiple pages again
* Implement "--logfile -" to log to stdout
* Add preliminary support for Shibboleth authentication
* Linux: Provide more icon sizes
* Linux: Do not trigger notifier on ignored files
* Windows: Reduce priority of CSync thread
* Documentation: Prem. updates to reflect UI changes
* Significant code refactorings
* Require Qt 4.7
* Known issue: Under certain conditions, a file will only get uploaded after up to five minutes
version 1.3.0 (release 2013-06-25 ), csync 0.80.0 required
* Default proxy port to 8080
+5 -5
Ver Arquivo
@@ -1,9 +1,9 @@
set( APPLICATION_SHORTNAME "owncloud" )
set( APPLICATION_NAME "ownCloud" )
#set( APPLICATION_SHORTNAME ${APPLICATION_NAME} )
set( APPLICATION_EXECUTABLE "owncloud" )
set( APPLICATION_DOMAIN "owncloud.com" )
set( APPLICATION_VENDOR "ownCloud, Inc" )
set( THEME_CLASS "ownCloudTheme" )
set( APPLICATION_EXECUTABLE "owncloud" )
set( APPLICATION_DOMAIN "owncloud.com" )
set( APPLICATION_VENDOR "ownCloud, Inc" )
set( THEME_CLASS "ownCloudTheme" )
set( APPLICATION_REV_DOMAIN "com.owncloud.desktopclient" )
set( WIN_SETUP_BITMAP_PATH "${CMAKE_SOURCE_DIR}/admin/win/nsi" )
# set( THEME_INCLUDE "${OEM_THEME_DIR}/mytheme.h" )
+2 -2
Ver Arquivo
@@ -1,6 +1,6 @@
set( VERSION_MAJOR 1 )
set( VERSION_MINOR 5 )
set( VERSION_MINOR 3 )
set( VERSION_PATCH 0 )
set( VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}${VERSION_SUFFIX}beta1")
set( VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}${VERSION_SUFFIX})
set( SOVERSION 0 )
+2 -1
Ver Arquivo
@@ -10,7 +10,8 @@ mount="/Volumes/$(basename $src_dmg|cut -d"-" -f1)"
test -e $tmp_dmg && rm -rf $tmp_dmg
hdiutil convert $src_dmg -format UDRW -o $tmp_dmg
hdiutil attach $tmp_dmg
open $tmp_dmg
sleep 12s
pushd $mount
codesign -s "$identity" $mount/*.app
popd
@@ -5,6 +5,7 @@ This sample uses the registry plugin, so you need to download that if you don't
!define APPNAME "UAC_RealWorldFullyLoadedDualMode"
!define ELEVATIONTITLE "${APPNAME}: Elevate" ;displayed during elevation on our custom page
!define SMSUBDIR $StartMenuFolder ;"${APPNAME}"
!define UNINSTALLER_NAME "Uninstall ${APPNAME}.exe"
!define UNINSTALLER_REGSECTION "${APPNAME}"
!define RegPath.MSUninstall "Software\Microsoft\Windows\CurrentVersion\Uninstall"
@@ -199,7 +200,10 @@ UAC::Exec "" "Notepad.exe" "$Windir\Win.INI" "$InstDir"
FunctionEnd
Function CreateSMShortcuts
CreateShortcut "$SMPrograms\${APPNAME}.lnk" "$Windir\Notepad.exe"
StrCpy ${SMSUBDIR} $9 ;stupid sync
CreateDirectory "$SMPrograms\${SMSUBDIR}"
CreateShortcut "$SMPrograms\${SMSUBDIR}\${APPNAME}.lnk" "$Windir\Notepad.exe"
CreateShortcut "$SMPrograms\${SMSUBDIR}\Uninstall ${APPNAME}.lnk" "$InstDir\${UNINSTALLER_NAME}"
FunctionEnd
Function CreateDeskShortcuts
CreateShortcut "$Desktop\${APPNAME}.lnk" "$Windir\Notepad.exe"
@@ -218,6 +222,7 @@ ${registry::Unload}
SectionEnd
Section "Startmenu Shortcuts"
StrCpy $9 ${SMSUBDIR} ;this is stupid as hell, we need correct ${SMSUBDIR} in the outer process, this is the only way (plugins cannot enum "custom" var's AFAIK)
${UAC.CallFunctionAsUser} CreateSMShortcuts
SectionEnd
Section "Desktop Shortcut"
@@ -226,7 +231,9 @@ SectionEnd
Section Uninstall
Delete "$InstDir\${UNINSTALLER_NAME}"
Delete "$SMPrograms\${APPNAME}.lnk"
Delete "$SMPrograms\${SMSUBDIR}\${APPNAME}.lnk"
Delete "$SMPrograms\${SMSUBDIR}\Uninstall ${APPNAME}.lnk"
RMDir "$SMPrograms\${SMSUBDIR}"
Delete "$Desktop\${APPNAME}.lnk"
RMDir "$InstDir"
-108
Ver Arquivo
@@ -1,108 +0,0 @@
if (UNIX)
# Suffix for Linux
SET(LIB_SUFFIX
CACHE STRING "Define suffix of directory name (32/64)"
)
SET(EXEC_INSTALL_PREFIX
"${CMAKE_INSTALL_PREFIX}"
CACHE PATH "Base directory for executables and libraries"
)
SET(SHARE_INSTALL_PREFIX
"${CMAKE_INSTALL_PREFIX}/share"
CACHE PATH "Base directory for files which go to share/"
)
SET(DATA_INSTALL_PREFIX
"${SHARE_INSTALL_PREFIX}/${APPLICATION_SHORT_NAME}"
CACHE PATH "The parent directory where applications can install their data")
# The following are directories where stuff will be installed to
SET(BIN_INSTALL_DIR
"${EXEC_INSTALL_PREFIX}/bin"
CACHE PATH "The ${APPLICATION_SHORT_NAME} binary install dir (default prefix/bin)"
)
SET(SBIN_INSTALL_DIR
"${EXEC_INSTALL_PREFIX}/sbin"
CACHE PATH "The ${APPLICATION_SHORT_NAME} sbin install dir (default prefix/sbin)"
)
SET(LIB_INSTALL_DIR
"${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}"
CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/lib)"
)
SET(LIBEXEC_INSTALL_DIR
"${EXEC_INSTALL_PREFIX}/libexec"
CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/libexec)"
)
SET(PLUGIN_INSTALL_DIR
"${LIB_INSTALL_DIR}/${APPLICATION_SHORT_NAME}"
CACHE PATH "The subdirectory relative to the install prefix where plugins will be installed (default is prefix/lib/${APPLICATION_SHORT_NAME})"
)
SET(INCLUDE_INSTALL_DIR
"${CMAKE_INSTALL_PREFIX}/include"
CACHE PATH "The subdirectory to the header prefix (default prefix/include)"
)
SET(DATA_INSTALL_DIR
"${DATA_INSTALL_PREFIX}"
CACHE PATH "The parent directory where applications can install their data (default prefix/share/${APPLICATION_SHORT_NAME})"
)
SET(HTML_INSTALL_DIR
"${DATA_INSTALL_PREFIX}/doc/HTML"
CACHE PATH "The HTML install dir for documentation (default data/doc/html)"
)
SET(ICON_INSTALL_DIR
"${DATA_INSTALL_PREFIX}/icons"
CACHE PATH "The icon install dir (default data/icons/)"
)
SET(SOUND_INSTALL_DIR
"${DATA_INSTALL_PREFIX}/sounds"
CACHE PATH "The install dir for sound files (default data/sounds)"
)
SET(LOCALE_INSTALL_DIR
"${SHARE_INSTALL_PREFIX}/locale"
CACHE PATH "The install dir for translations (default prefix/share/locale)"
)
SET(XDG_APPS_DIR
"${SHARE_INSTALL_PREFIX}/applications/"
CACHE PATH "The XDG apps dir"
)
SET(XDG_DIRECTORY_DIR
"${SHARE_INSTALL_PREFIX}/desktop-directories"
CACHE PATH "The XDG directory"
)
IF(NOT "${EXEC_INSTALL_PREFIX}" STREQUAL "/usr")
SET(SYSCONFDIR_INSTALL_PREFIX "${EXEC_INSTALL_PREFIX}")
endif()
SET(SYSCONF_INSTALL_DIR
"${SYSCONFDIR_INSTALL_PREFIX}/etc"
CACHE PATH "The ${APPLICATION_SHORT_NAME} sysconfig install dir (default prefix/etc)"
)
SET(MAN_INSTALL_DIR
"${SHARE_INSTALL_PREFIX}/man"
CACHE PATH "The ${APPLICATION_SHORT_NAME} man install dir (default prefix/man)"
)
SET(INFO_INSTALL_DIR
"${SHARE_INSTALL_PREFIX}/info"
CACHE PATH "The ${APPLICATION_SHORT_NAME} info install dir (default prefix/info)"
)
endif (UNIX)
if (WIN32)
# Same same
set(SHARE_INSTALL_PREFIX "share" CACHE PATH "-")
set(BIN_INSTALL_DIR "." CACHE PATH "-")
set(SBIN_INSTALL_DIR "." CACHE PATH "-")
set(LIB_INSTALL_DIR "lib" CACHE PATH "-")
set(INCLUDE_INSTALL_DIR "include" CACHE PATH "-")
set(PLUGIN_INSTALL_DIR "plugins" CACHE PATH "-")
set(HTML_INSTALL_DIR "doc/HTML" CACHE PATH "-")
set(ICON_INSTALL_DIR "." CACHE PATH "-")
set(SOUND_INSTALL_DIR "." CACHE PATH "-")
set(LOCALE_INSTALL_DIR "lang" CACHE PATH "-")
set(SYSCONF_INSTALL_DIR "config" CACHE PATH "-")
set(MAN_INSTALL_DIR "man" CACHE PATH "-")
endif (WIN32)
-73
Ver Arquivo
@@ -1,73 +0,0 @@
# - Try to find Neon
# Once done this will define
#
# NEON_FOUND - system has Neon
# NEON_INCLUDE_DIRS - the Neon include directory
# NEON_LIBRARIES - Link these to use Neon
# NEON_DEFINITIONS - Compiler switches required for using Neon
#
# Copyright (c) 2011 Andreas Schneider <asn@cryptomilk.org>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(_NEON neon)
endif (PKG_CONFIG_FOUND)
include(GNUInstallDirs)
find_path(NEON_INCLUDE_DIRS
NAMES
neon/ne_basic.h
HINTS
${_NEON_INCLUDEDIR}
${CMAKE_INSTALL_INCLUDEDIR}
)
find_library(NEON_LIBRARIES
NAMES
neon
HINTS
${_NEON_LIBDIR}
${CMAKE_INSTALL_LIBDIR}
${CMAKE_INSTALL_PREFIX}/lib
${CMAKE_INSTALL_PREFIX}/lib64
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Neon DEFAULT_MSG NEON_LIBRARIES NEON_INCLUDE_DIRS)
# show the NEON_INCLUDE_DIRS and NEON_LIBRARIES variables only in the advanced view
mark_as_advanced(NEON_INCLUDE_DIRS NEON_LIBRARIES)
# Check if neon was compiled with LFS support, if so, the NE_LFS variable has to
# be defined in the owncloud module.
# If neon was not compiled with LFS its also ok since the underlying system
# than probably supports large files anyway.
IF( CMAKE_FIND_ROOT_PATH )
FIND_PROGRAM( NEON_CONFIG_EXECUTABLE NAMES neon-config HINTS ${CMAKE_FIND_ROOT_PATH}/bin )
ELSE( CMAKE_FIND_ROOT_PATH )
FIND_PROGRAM( NEON_CONFIG_EXECUTABLE NAMES neon-config )
ENDIF( CMAKE_FIND_ROOT_PATH )
IF ( NEON_CONFIG_EXECUTABLE )
MESSAGE(STATUS "neon-config executable: ${NEON_CONFIG_EXECUTABLE}")
# neon-config --support lfs
EXECUTE_PROCESS( COMMAND ${NEON_CONFIG_EXECUTABLE} "--support" "lfs"
RESULT_VARIABLE LFS
OUTPUT_STRIP_TRAILING_WHITESPACE )
IF (LFS EQUAL 0)
MESSAGE(STATUS "libneon has been compiled with LFS support")
SET(NEON_WITH_LFS 1 PARENT_SCOPE)
ELSE (LFS EQUAL 0)
MESSAGE(STATUS "libneon has not been compiled with LFS support, rely on OS")
ENDIF (LFS EQUAL 0)
ELSE ( NEON_CONFIG_EXECUTABLE )
MESSAGE(STATUS, "neon-config could not be found.")
ENDIF ( NEON_CONFIG_EXECUTABLE )
-157
Ver Arquivo
@@ -1,157 +0,0 @@
# This file defines the Feature Logging macros.
#
# MACRO_LOG_FEATURE(VAR FEATURE DESCRIPTION URL [REQUIRED [MIN_VERSION [COMMENTS]]])
# Logs the information so that it can be displayed at the end
# of the configure run
# VAR : TRUE or FALSE, indicating whether the feature is supported
# FEATURE: name of the feature, e.g. "libjpeg"
# DESCRIPTION: description what this feature provides
# URL: home page
# REQUIRED: TRUE or FALSE, indicating whether the featue is required
# MIN_VERSION: minimum version number. empty string if unneeded
# COMMENTS: More info you may want to provide. empty string if unnecessary
#
# MACRO_DISPLAY_FEATURE_LOG()
# Call this to display the collected results.
# Exits CMake with a FATAL error message if a required feature is missing
#
# Example:
#
# INCLUDE(MacroLogFeature)
#
# FIND_PACKAGE(JPEG)
# MACRO_LOG_FEATURE(JPEG_FOUND "libjpeg" "Support JPEG images" "http://www.ijg.org" TRUE "3.2a" "")
# ...
# MACRO_DISPLAY_FEATURE_LOG()
# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
# Copyright (c) 2006, Allen Winter, <winter@kde.org>
# Copyright (c) 2009, Sebastian Trueg, <trueg@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
IF (NOT _macroLogFeatureAlreadyIncluded)
SET(_file ${CMAKE_BINARY_DIR}/MissingRequirements.txt)
IF (EXISTS ${_file})
FILE(REMOVE ${_file})
ENDIF (EXISTS ${_file})
SET(_file ${CMAKE_BINARY_DIR}/EnabledFeatures.txt)
IF (EXISTS ${_file})
FILE(REMOVE ${_file})
ENDIF (EXISTS ${_file})
SET(_file ${CMAKE_BINARY_DIR}/DisabledFeatures.txt)
IF (EXISTS ${_file})
FILE(REMOVE ${_file})
ENDIF (EXISTS ${_file})
SET(_macroLogFeatureAlreadyIncluded TRUE)
INCLUDE(FeatureSummary)
ENDIF (NOT _macroLogFeatureAlreadyIncluded)
MACRO(MACRO_LOG_FEATURE _var _package _description _url ) # _required _minvers _comments)
STRING(TOUPPER "${ARGV4}" _required)
SET(_minvers "${ARGV5}")
SET(_comments "${ARGV6}")
IF (${_var})
SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/EnabledFeatures.txt)
ELSE (${_var})
IF ("${_required}" STREQUAL "TRUE")
SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/MissingRequirements.txt)
ELSE ("${_required}" STREQUAL "TRUE")
SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/DisabledFeatures.txt)
ENDIF ("${_required}" STREQUAL "TRUE")
ENDIF (${_var})
SET(_logtext " * ${_package}")
IF (NOT ${_var})
IF (${_minvers} MATCHES ".*")
SET(_logtext "${_logtext} (${_minvers} or higher)")
ENDIF (${_minvers} MATCHES ".*")
SET(_logtext "${_logtext} <${_url}>\n ")
ELSE (NOT ${_var})
SET(_logtext "${_logtext} - ")
ENDIF (NOT ${_var})
SET(_logtext "${_logtext}${_description}")
IF (NOT ${_var})
IF (${_comments} MATCHES ".*")
SET(_logtext "${_logtext}\n ${_comments}")
ENDIF (${_comments} MATCHES ".*")
# SET(_logtext "${_logtext}\n") #double-space missing features?
ENDIF (NOT ${_var})
FILE(APPEND "${_LOGFILENAME}" "${_logtext}\n")
IF(COMMAND SET_PACKAGE_INFO) # in FeatureSummary.cmake since CMake 2.8.3
SET_PACKAGE_INFO("${_package}" "\"${_description}\"" "${_url}" "\"${_comments}\"")
ENDIF(COMMAND SET_PACKAGE_INFO)
ENDMACRO(MACRO_LOG_FEATURE)
MACRO(MACRO_DISPLAY_FEATURE_LOG)
IF(COMMAND FEATURE_SUMMARY) # in FeatureSummary.cmake since CMake 2.8.3
FEATURE_SUMMARY(FILENAME ${CMAKE_CURRENT_BINARY_DIR}/FindPackageLog.txt
WHAT ALL)
ENDIF(COMMAND FEATURE_SUMMARY)
SET(_missingFile ${CMAKE_BINARY_DIR}/MissingRequirements.txt)
SET(_enabledFile ${CMAKE_BINARY_DIR}/EnabledFeatures.txt)
SET(_disabledFile ${CMAKE_BINARY_DIR}/DisabledFeatures.txt)
IF (EXISTS ${_missingFile} OR EXISTS ${_enabledFile} OR EXISTS ${_disabledFile})
SET(_printSummary TRUE)
ENDIF (EXISTS ${_missingFile} OR EXISTS ${_enabledFile} OR EXISTS ${_disabledFile})
IF(_printSummary)
SET(_missingDeps 0)
IF (EXISTS ${_enabledFile})
FILE(READ ${_enabledFile} _enabled)
FILE(REMOVE ${_enabledFile})
SET(_summary "${_summary}\n-----------------------------------------------------------------------------\n-- The following external packages were located on your system.\n-- This installation will have the extra features provided by these packages.\n-----------------------------------------------------------------------------\n${_enabled}")
ENDIF (EXISTS ${_enabledFile})
IF (EXISTS ${_disabledFile})
SET(_missingDeps 1)
FILE(READ ${_disabledFile} _disabled)
FILE(REMOVE ${_disabledFile})
SET(_summary "${_summary}\n-----------------------------------------------------------------------------\n-- The following OPTIONAL packages could NOT be located on your system.\n-- Consider installing them to enable more features from this software.\n-----------------------------------------------------------------------------\n${_disabled}")
ENDIF (EXISTS ${_disabledFile})
IF (EXISTS ${_missingFile})
SET(_missingDeps 1)
FILE(READ ${_missingFile} _requirements)
SET(_summary "${_summary}\n-----------------------------------------------------------------------------\n-- The following REQUIRED packages could NOT be located on your system.\n-- You must install these packages before continuing.\n-----------------------------------------------------------------------------\n${_requirements}")
FILE(REMOVE ${_missingFile})
SET(_haveMissingReq 1)
ENDIF (EXISTS ${_missingFile})
IF (NOT ${_missingDeps})
SET(_summary "${_summary}\n-----------------------------------------------------------------------------\n-- Congratulations! All external packages have been found.")
ENDIF (NOT ${_missingDeps})
MESSAGE(${_summary})
MESSAGE("-----------------------------------------------------------------------------\n")
IF(_haveMissingReq)
MESSAGE(FATAL_ERROR "Exiting: Missing Requirements")
ENDIF(_haveMissingReq)
ENDIF(_printSummary)
ENDMACRO(MACRO_DISPLAY_FEATURE_LOG)
-47
Ver Arquivo
@@ -1,47 +0,0 @@
# - MACRO_OPTIONAL_FIND_PACKAGE() combines FIND_PACKAGE() with an OPTION()
# MACRO_OPTIONAL_FIND_PACKAGE( <name> [QUIT] )
# This macro is a combination of OPTION() and FIND_PACKAGE(), it
# works like FIND_PACKAGE(), but additionally it automatically creates
# an option name WITH_<name>, which can be disabled via the cmake GUI.
# or via -DWITH_<name>=OFF
# The standard <name>_FOUND variables can be used in the same way
# as when using the normal FIND_PACKAGE()
# Copyright (c) 2006-2010 Alexander Neundorf, <neundorf@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
# This is just a helper macro to set a bunch of variables empty.
# We don't know whether the package uses UPPERCASENAME or CamelCaseName, so we try both:
macro(_MOFP_SET_EMPTY_IF_DEFINED _name _var)
if(DEFINED ${_name}_${_var})
set(${_name}_${_var} "")
endif(DEFINED ${_name}_${_var})
string(TOUPPER ${_name} _nameUpper)
if(DEFINED ${_nameUpper}_${_var})
set(${_nameUpper}_${_var} "")
endif(DEFINED ${_nameUpper}_${_var})
endmacro(_MOFP_SET_EMPTY_IF_DEFINED _package _var)
macro (MACRO_OPTIONAL_FIND_PACKAGE _name )
option(WITH_${_name} "Search for ${_name} package" ON)
if (WITH_${_name})
find_package(${_name} ${ARGN})
else (WITH_${_name})
string(TOUPPER ${_name} _nameUpper)
set(${_name}_FOUND FALSE)
set(${_nameUpper}_FOUND FALSE)
_mofp_set_empty_if_defined(${_name} INCLUDE_DIRS)
_mofp_set_empty_if_defined(${_name} INCLUDE_DIR)
_mofp_set_empty_if_defined(${_name} INCLUDES)
_mofp_set_empty_if_defined(${_name} LIBRARY)
_mofp_set_empty_if_defined(${_name} LIBRARIES)
_mofp_set_empty_if_defined(${_name} LIBS)
_mofp_set_empty_if_defined(${_name} FLAGS)
_mofp_set_empty_if_defined(${_name} DEFINITIONS)
endif (WITH_${_name})
endmacro (MACRO_OPTIONAL_FIND_PACKAGE)
+110 -22
Ver Arquivo
@@ -1,6 +1,6 @@
;ownCloud installer script.
!define APPLICATION_SHORTNAME "@APPLICATION_EXECUTABLE@"
!define APPLICATION_SHORTNAME "@APPLICATION_SHORTNAME@"
!define APPLICATION_NAME "@APPLICATION_NAME@"
!define APPLICATION_VENDOR "@APPLICATION_VENDOR@"
!define APPLICATION_EXECUTABLE "@APPLICATION_EXECUTABLE@.exe"
@@ -18,6 +18,7 @@
!define OPTION_SECTION_SC_START_MENU
!define OPTION_SECTION_SC_DESKTOP
!define OPTION_SECTION_SC_QUICK_LAUNCH
!define OPTION_SECTION_SC_AUTOSTART
!define OPTION_FINISHPAGE
!define OPTION_FINISHPAGE_LAUNCHER
; !define OPTION_FINISHPAGE_RELEASE_NOTES
@@ -39,6 +40,7 @@
!define IMAGEFORMATS_DLL_PATH "${MING_LIB}/qt4/plugins/imageformats"
!define CSYNC_LIBRARY_DIR "@CSYNC_LIBRARY_DIR@"
!define CSYNC_PLUGIN_DIR "@CSYNC_PLUGIN_DIR@"
!define CSYNC_CONFIG_DIR "@CSYNC_CONFIG_DIR@"
!define NSI_PATH "${source_path}/admin/win/nsi"
@@ -281,24 +283,90 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
!ifndef INSTALL_PATH
;Main executable.
File "${BUILD_PATH}\bin\${APPLICATION_EXECUTABLE}"
File "${BUILD_PATH}\src\lib${APPLICATION_SHORTNAME}sync.dll"
File "${BUILD_PATH}\src\libowncloudsync.dll"
File "${BUILD_PATH}\src\mirall_*.qm"
; Make sure only to copy qt, not qt_help, etc
File "${MING_SHARE}\qt4\translations\qt_??.qm"
File "${MING_SHARE}\qt4\translations\qt_??_??.qm"
File "${MING_SHARE}\qt4\translations\qtkeychain_*.qm"
File "${BUILD_PATH}\src\mirall_ca.qm"
File "${BUILD_PATH}\src\mirall_cs_CZ.qm"
File "${BUILD_PATH}\src\mirall_da.qm"
File "${BUILD_PATH}\src\mirall_de.qm"
File "${BUILD_PATH}\src\mirall_el.qm"
File "${BUILD_PATH}\src\mirall_en.qm"
File "${BUILD_PATH}\src\mirall_eo.qm"
File "${BUILD_PATH}\src\mirall_es.qm"
File "${BUILD_PATH}\src\mirall_es_AR.qm"
File "${BUILD_PATH}\src\mirall_et_EE.qm"
File "${BUILD_PATH}\src\mirall_eu.qm"
File "${BUILD_PATH}\src\mirall_fa.qm"
File "${BUILD_PATH}\src\mirall_fi_FI.qm"
File "${BUILD_PATH}\src\mirall_fr.qm"
File "${BUILD_PATH}\src\mirall_gl.qm"
File "${BUILD_PATH}\src\mirall_he.qm"
File "${BUILD_PATH}\src\mirall_hr.qm"
File "${BUILD_PATH}\src\mirall_hu_HU.qm"
File "${BUILD_PATH}\src\mirall_it.qm"
File "${BUILD_PATH}\src\mirall_ja_JP.qm"
File "${BUILD_PATH}\src\mirall_ko.qm"
File "${BUILD_PATH}\src\mirall_lb.qm"
File "${BUILD_PATH}\src\mirall_lt_LT.qm"
File "${BUILD_PATH}\src\mirall_lv.qm"
File "${BUILD_PATH}\src\mirall_mk.qm"
File "${BUILD_PATH}\src\mirall_ms_MY.qm"
File "${BUILD_PATH}\src\mirall_nb_NO.qm"
File "${BUILD_PATH}\src\mirall_nl.qm"
File "${BUILD_PATH}\src\mirall_oc.qm"
File "${BUILD_PATH}\src\mirall_pl.qm"
File "${BUILD_PATH}\src\mirall_pt_BR.qm"
File "${BUILD_PATH}\src\mirall_pt_PT.qm"
File "${BUILD_PATH}\src\mirall_ro.qm"
File "${BUILD_PATH}\src\mirall_ru.qm"
File "${BUILD_PATH}\src\mirall_ru_RU.qm"
File "${BUILD_PATH}\src\mirall_si_LK.qm"
File "${BUILD_PATH}\src\mirall_sk_SK.qm"
File "${BUILD_PATH}\src\mirall_sl.qm"
File "${BUILD_PATH}\src\mirall_sr@latin.qm"
File "${BUILD_PATH}\src\mirall_sv.qm"
File "${BUILD_PATH}\src\mirall_ta_LK.qm"
File "${BUILD_PATH}\src\mirall_th_TH.qm"
File "${BUILD_PATH}\src\mirall_tr.qm"
File "${BUILD_PATH}\src\mirall_uk.qm"
File "${BUILD_PATH}\src\mirall_vi.qm"
File "${BUILD_PATH}\src\mirall_zh_CN.qm"
File "${BUILD_PATH}\src\mirall_zh_TW.qm"
#File "${MING_SHARE}\qt4\translations\qt_ar.qm"
File "${MING_SHARE}\qt4\translations\qt_cs.qm"
File "${MING_SHARE}\qt4\translations\qt_da.qm"
File "${MING_SHARE}\qt4\translations\qt_de.qm"
File "${MING_SHARE}\qt4\translations\qt_es.qm"
File "${MING_SHARE}\qt4\translations\qt_fa.qm"
File "${MING_SHARE}\qt4\translations\qt_fr.qm"
File "${MING_SHARE}\qt4\translations\qt_gl.qm"
File "${MING_SHARE}\qt4\translations\qt_he.qm"
File "${MING_SHARE}\qt4\translations\qt_hu.qm"
File "${MING_SHARE}\qt4\translations\qt_ja.qm"
File "${MING_SHARE}\qt4\translations\qt_ko.qm"
File "${MING_SHARE}\qt4\translations\qt_lt.qm"
File "${MING_SHARE}\qt4\translations\qt_pl.qm"
File "${MING_SHARE}\qt4\translations\qt_pt.qm"
File "${MING_SHARE}\qt4\translations\qt_ru.qm"
File "${MING_SHARE}\qt4\translations\qt_sk.qm"
File "${MING_SHARE}\qt4\translations\qt_sl.qm"
File "${MING_SHARE}\qt4\translations\qt_sv.qm"
File "${MING_SHARE}\qt4\translations\qt_uk.qm"
File "${MING_SHARE}\qt4\translations\qt_zh_CN.qm"
File "${MING_SHARE}\qt4\translations\qt_zh_TW.qm"
File "${MING_SHARE}\qt4\translations\qt_zh_TW.qm"
File "${MING_SHARE}\qt4\translations\qtkeychain_de.qm"
SetOutPath "$INSTDIR\accessible"
File "${ACCESSIBLE_DLL_PATH}\qtaccessiblewidgets4.dll"
SetOutPath "$INSTDIR\imageformats"
File "${IMAGEFORMATS_DLL_PATH}\qgif4.dll"
File "${IMAGEFORMATS_DLL_PATH}\qjpeg4.dll"
File "${IMAGEFORMATS_DLL_PATH}\qico4.dll"
SetOutPath "$INSTDIR\sqldrivers"
File "${SQLITE_DLL_PATH}\qsqlite4.dll"
SetOutPath "$INSTDIR\modules"
; FIXME: fix installation dir of module, currently needs manual copying to
; /usr/i686-w64-mingw32/sys-root/mingw/bin/csync_modules/
File "${CSYNC_PLUGIN_DIR}/ocsync_owncloud.dll"
SetOutPath "$INSTDIR"
!endif
@@ -312,14 +380,12 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
File "${QT_DLL_PATH}\QtCore4.dll"
File "${QT_DLL_PATH}\QtGui4.dll"
File "${QT_DLL_PATH}\QtNetwork4.dll"
File "${QT_DLL_PATH}\QtSql4.dll"
File "${QT_DLL_PATH}\QtXml4.dll"
File "${QT_DLL_PATH}\QtWebKit4.dll"
;QtKeyChain stuff
File "${MING_BIN}\libqtkeychain.dll"
File "${CSYNC_LIBRARY_DIR}\libocsync.dll"
File "${CSYNC_LIBRARY_DIR}/libocsync.dll"
File "${MING_BIN}\libsqlite3-0.dll"
File "${MING_BIN}\libiniparser.dll"
File "${MING_BIN}\libdl.dll"
@@ -338,7 +404,7 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
; Other
;File "${MING_BIN}\libpng15-15.dll"
File "${MING_BIN}\libjpeg-8.dll"
;File "${MING_BIN}\libjpeg-8.dll"
File "${MING_BIN}\zlib1.dll"
File "${MING_BIN}\libcrypto-10.dll"
File "${MING_BIN}\libssl-10.dll"
@@ -351,13 +417,18 @@ SectionEnd
SectionGroup "Shortcuts"
!ifdef OPTION_SECTION_SC_START_MENU
${MementoSection} "Start Menu Program Shortcut" SEC_START_MENU
${MementoSection} "Start Menu Program Group" SEC_START_MENU
SectionIn 1 2 3
SetDetailsPrint textonly
DetailPrint "Adding shortcut for ${APPLICATION_NAME} to the Start Menu."
DetailPrint "Adding shortcuts for the ${APPLICATION_NAME} program group to the Start Menu."
SetDetailsPrint listonly
SetShellVarContext all
CreateShortCut "$SMPROGRAMS\${APPLICATION_NAME}.lnk" "$INSTDIR\${APPLICATION_EXECUTABLE}"
RMDir /r "$SMPROGRAMS\${APPLICATION_NAME}"
CreateDirectory "$SMPROGRAMS\${APPLICATION_NAME}"
;CreateShortCut "$SMPROGRAMS\${APPLICATION_NAME}\LICENSE.lnk" "$INSTDIR\LICENSE.txt"
CreateShortCut "$SMPROGRAMS\${APPLICATION_NAME}\${APPLICATION_NAME}.lnk" "$INSTDIR\${APPLICATION_EXECUTABLE}"
;CreateShortCut "$SMPROGRAMS\${APPLICATION_NAME}\Release notes.lnk" "$INSTDIR\NOTES.txt"
CreateShortCut "$SMPROGRAMS\${APPLICATION_NAME}\Uninstall.lnk" "$INSTDIR\uninstall.exe"
SetShellVarContext current
${MementoSectionEnd}
!endif
@@ -384,15 +455,27 @@ SectionGroup "Shortcuts"
SectionGroupEnd
!ifdef OPTION_SECTION_SC_AUTOSTART
${MementoSection} "Autostart" SEC_AUTOSTART
SectionIn 1 2
SetDetailsPrint textonly
DetailPrint "Creating Windows Start Entry"
SetDetailsPrint listonly
WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Run" \
"${APPLICATION_NAME}" "$INSTDIR\${APPLICATION_EXECUTABLE}"
${MementoSectionEnd}
!endif
${MementoSectionDone}
; Installer section descriptions
;--------------------------------
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_APPLICATION} "${APPLICATION_NAME} essentials."
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_START_MENU} "${APPLICATION_NAME} shortcut."
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_START_MENU} "${APPLICATION_NAME} program group."
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_DESKTOP} "Desktop shortcut for ${APPLICATION_NAME}."
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_QUICK_LAUNCH} "Quick Launch shortcut for ${APPLICATION_NAME}."
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_AUTOSTART} "Register ${APPLICATION_NAME} to run on Windows startup."
!insertmacro MUI_FUNCTION_DESCRIPTION_END
Section -post
@@ -495,10 +578,15 @@ Section Uninstall
DeleteRegKey HKCR "${APPLICATION_NAME}"
;Windows Start entry
!ifdef OPTION_SECTION_SC_AUTOSTART
DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "${APPLICATION_NAME}"
!endif
;Start menu shortcuts.
!ifdef OPTION_SECTION_SC_START_MENU
SetShellVarContext all
Delete "$SMPROGRAMS\${APPLICATION_NAME}.lnk"
RMDir /r "$SMPROGRAMS\${APPLICATION_NAME}"
SetShellVarContext current
!endif
-131
Ver Arquivo
@@ -1,131 +0,0 @@
include (MacroOptionalFindPackage)
include (MacroLogFeature)
option(BUILD_WITH_QT4 "Build with Qt4 no matter if Qt5 was found" ON)
if( NOT BUILD_WITH_QT4 )
find_package(Qt5Core QUIET)
if( Qt5Core_DIR )
find_package(Qt5Widgets QUIET)
find_package(Qt5Quick QUIET)
find_package(Qt5PrintSupport QUIET)
find_package(Qt5WebKit QUIET)
find_package(Qt5Location QUIET)
find_package(Qt5Network QUIET)
find_package(Qt5Sensors QUIET)
find_package(Qt5Xml QUIET)
# find_package(Qt5WebKitWidgets QUIET)
message(STATUS "Using Qt 5!")
# We need this to find the paths to qdbusxml2cpp and co
if (WITH_DBUS)
find_package(Qt5DBus REQUIRED)
include_directories(${Qt5DBus_INCLUDES})
add_definitions(${Qt5DBus_DEFINITIONS})
endif (WITH_DBUS)
include_directories(${Qt5Widgets_INCLUDES})
add_definitions(${Qt5Widgets_DEFINITIONS})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
# set(CMAKE_CXX_FLAGS "${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
macro(qt_wrap_ui)
qt5_wrap_ui(${ARGN})
endmacro()
macro(qt_add_resources)
qt5_add_resources(${ARGN})
endmacro()
# find_package(Qt5LinguistTools REQUIRED)
macro(qt_add_translation)
# qt5_add_translation(${ARGN})
endmacro()
macro(qt_add_dbus_interface)
qt5_add_dbus_interface(${ARGN})
endmacro()
macro(qt_add_dbus_adaptor)
qt5_add_dbus_adaptor(${ARGN})
endmacro()
macro(qt_wrap_cpp)
qt5_wrap_cpp(${ARGN})
endmacro()
macro(install_qt_executable)
install_qt5_executable(${ARGN})
endmacro()
macro(setup_qt)
endmacro()
set(QT_RCC_EXECUTABLE "${Qt5Core_RCC_EXECUTABLE}")
#Enable deprecated symbols
add_definitions("-DQT_DISABLE_DEPRECATED_BEFORE=0")
endif()
endif()
if( NOT Qt5Core_DIR )
message(STATUS "Could not find Qt5, searching for Qt4 instead...")
set(NEEDED_QT4_COMPONENTS "QtCore" "QtXml" "QtNetwork" "QtGui" "QtWebkit")
if( BUILD_TESTS )
list(APPEND NEEDED_QT4_COMPONENTS "QtTest")
endif()
macro_optional_find_package(Qt4 4.7.0 COMPONENTS ${NEEDED_QT4_COMPONENTS} )
macro_log_feature(QT4_FOUND "Qt" "A cross-platform application and UI framework" "http://qt.nokia.com" TRUE "" "If you see this, although libqt4-devel is installed, check whether the \n qtwebkit-devel package and whatever contains QtUiTools is installed too")
macro(qt5_use_modules)
endmacro()
macro(qt_wrap_ui)
qt4_wrap_ui(${ARGN})
endmacro()
macro(qt_add_resources)
qt4_add_resources(${ARGN})
endmacro()
macro(qt_add_translation)
qt4_add_translation(${ARGN})
endmacro()
macro(qt_add_dbus_interface)
qt4_add_dbus_interface(${ARGN})
endmacro()
macro(qt_add_dbus_adaptor)
qt4_add_dbus_adaptor(${ARGN})
endmacro()
macro(qt_wrap_cpp)
qt4_wrap_cpp(${ARGN})
endmacro()
macro(install_qt_executable)
install_qt4_executable(${ARGN})
endmacro()
macro(setup_qt)
set(QT_USE_QTGUI TRUE)
set(QT_USE_QTSQL TRUE)
set(QT_USE_QTNETWORK TRUE)
set(QT_USE_QTXML TRUE)
set(QT_USE_QTWEBKIT TRUE)
set(QT_USE_QTDBUS TRUE)
include( ${QT_USE_FILE} )
endmacro()
endif()
if( Qt5Core_DIR )
set( HAVE_QT5 TRUE )
else( Qt5Core_DIR )
set( HAVE_QT5 FALSE )
endif( Qt5Core_DIR )
-20
Ver Arquivo
@@ -1,20 +0,0 @@
if(CMAKE_COMPILER_IS_GNUCXX)
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
if(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wpedantic -Wno-long-long")
else(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
set(CMAKE_CXX_FLAGS "-Wall -Wextra -pedantic -Wno-long-long")
endif(GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
endif(CMAKE_COMPILER_IS_GNUCXX)
if(CMAKE_CXX_COMPILER MATCHES "clang")
set(CMAKE_CXX_FLAGS "-Wall -Wextra -pedantic -Wno-long-long")
endif(CMAKE_CXX_COMPILER MATCHES "clang")
# TODO: handle msvc compilers warnings?
if(DEFINED MIRALL_FATAL_WARNINGS)
if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER MATCHES "clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
endif (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER MATCHES "clang")
# TODO: handle msvc compilers warnings?
endif(DEFINED MIRALL_FATAL_WARNINGS)
+1 -7
Ver Arquivo
@@ -2,17 +2,11 @@
#define CONFIG_H
#cmakedefine USE_INOTIFY 1
#cmakedefine WITH_CSYNC 1
#cmakedefine WITH_QTKEYCHAIN 1
#cmakedefine GIT_SHA1 "@GIT_SHA1@"
#cmakedefine APPLICATION_DOMAIN @APPLICATION_DOMAIN@
#cmakedefine THEME_CLASS @THEME_CLASS@
#cmakedefine THEME_INCLUDE @THEME_INCLUDE@
#cmakedefine APPLICATION_NAME "@APPLICATION_NAME@"
#cmakedefine APPLICATION_SHORTNAME "@APPLICATION_SHORTNAME@"
#cmakedefine APPLICATION_EXECUTABLE "@APPLICATION_EXECUTABLE@"
#cmakedefine SYSCONFDIR "@SYSCONFDIR@"
#cmakedefine DATADIR "@DATADIR@"
#endif
+7 -24
Ver Arquivo
@@ -22,21 +22,16 @@ if(SPHINX_FOUND)
add_custom_target(doc DEPENDS doc-html doc-man COMMENT "Building documentation...")
endif(WITH_DOC)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/ocdoc/_shared_assets")
add_dependencies(doc doc-html-org)
add_dependencies(doc doc-html-com)
endif()
if(PDFLATEX_FOUND)
# if this still fails on Debian/Ubuntu, run
# apt-get install texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended
add_custom_target(doc-latex ${SPHINX_EXECUTABLE}
-q -c . -b latex
-d ${SPHINX_CACHE_DIR}/latex
-d ${SPHINX_CACHE_DIR}
-D latex_logo=${LATEX_LOGO}
${CMAKE_CURRENT_SOURCE_DIR}
${SPHINX_PDF_DIR} )
add_custom_target(doc-pdf $(MAKE) -C ${SPHINX_PDF_DIR} all-pdf
add_custom_target(doc-pdf make -C ${SPHINX_PDF_DIR} all-pdf
DEPENDS doc-latex )
add_dependencies(doc doc-pdf)
if (WITH_DOC)
@@ -46,7 +41,7 @@ if(SPHINX_FOUND)
if (EXISTS ${QT_QCOLLECTIONGENERATOR_EXECUTABLE})
add_custom_target( doc-qch-sphinx ${SPHINX_EXECUTABLE}
-q -c . -b qthelp
-d ${SPHINX_CACHE_DIR}/qthelp
-d ${SPHINX_CACHE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${SPHINX_QCH_DIR} )
add_custom_target( doc-qch ${QT_QCOLLECTIONGENERATOR_EXECUTABLE}
@@ -59,24 +54,12 @@ if(SPHINX_FOUND)
endif()
add_custom_target( doc-html ${SPHINX_EXECUTABLE}
-q -c . -b html
-d ${SPHINX_CACHE_DIR}/html
-d ${SPHINX_CACHE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${SPHINX_HTML_DIR}/unthemed )
add_custom_target( doc-html-org ${SPHINX_EXECUTABLE}
-q -c . -b html
-d ${SPHINX_CACHE_DIR}/html
-D html_theme=owncloud_org
${CMAKE_CURRENT_SOURCE_DIR}
${SPHINX_HTML_DIR}/org )
add_custom_target( doc-html-com ${SPHINX_EXECUTABLE}
-q -c . -b html
-d ${SPHINX_CACHE_DIR}/html
-D html_theme=owncloud_com
${CMAKE_CURRENT_SOURCE_DIR}
${SPHINX_HTML_DIR}/com )
${SPHINX_HTML_DIR} )
add_custom_target( doc-man ${SPHINX_EXECUTABLE}
-q -c . -b man
-d ${SPHINX_CACHE_DIR}/man
-d ${SPHINX_CACHE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${SPHINX_MAN_DIR} )
@@ -88,7 +71,7 @@ if(SPHINX_FOUND)
add_custom_target( doc-chm-sphinx ${SPHINX_EXECUTABLE}
-q -c . -b htmlhelp
-D html_theme=basic
-d ${SPHINX_CACHE_DIR}/htmlhelp
-d ${SPHINX_CACHE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${SPHINX_HTMLHELP_DIR} )
add_custom_target( doc-chm pushd ${SPHINX_HTMLHELP_DIR}; ${MSHTML_COMPILER} *.hhp; popd
+153
Ver Arquivo
@@ -0,0 +1,153 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/OwncloudDocumentation.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/OwncloudDocumentation.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/OwncloudDocumentation"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/OwncloudDocumentation"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
-37
Ver Arquivo
@@ -1,37 +0,0 @@
Setting up an Account
=====================
If no account has been configured, ownCloud Client will automatically assist
you in connecting to your ownCloud Server after the application has been
started.
As a first step, specify the URL to your Server, just
like you would when you open your ownCloud instance inside a browser.
.. image:: images/wizard_url.png
:scale: 50 %
.. note:: Make sure to use ``https://`` if the server supports it. Otherwise,
your password and all data will be transferred to the server unencrypted.
This makes it easy for third parties to intercept your communication, and
getting hold of your password!
Next, you are prompted for your username and password. Again, use the same
credentials that you would use to log on via the web interface.
.. image:: images/wizard_user.png
:scale: 50 %
Finally, choose the folder that ownCloud Client is supposed to sync the
contents of your ownCloud account with. By default, this is a folder
called `ownCloud`, which will reside in your home directory.
.. image:: images/wizard_targetfolder.png
:scale: 50 %
After pressing `Connect`, ownCloud Client will commence with the syncing
process. The next screen will give you the opportunity to review your
settings:
.. image:: images/wizard_overview.png
:scale: 50 %
-14
Ver Arquivo
@@ -1,14 +0,0 @@
Advanced Usage
==============
.. index:: Advanced Usage
Options
-------
.. index:: command line switches, command line, options, parameters
.. include:: options.rst
Config File
-----------
.. index:: config file
.. include:: conffile.rst
+27 -80
Ver Arquivo
@@ -1,6 +1,5 @@
Appendix B: Architecture
========================
Architecture
============
.. index:: architecture
The ownCloud project provides desktop sync clients to synchronize the
@@ -12,10 +11,11 @@ csync was written to synchronize with ownClouds built-in WebDAV server.
The ownCloud sync client is based on a tool called mirall initially written by
Duncan Mac Vicar. Later Klaas Freitag joined the project and enhanced it to work
with ownCloud server.
with ownCloud server. Both mirall and ownCloud Client (oCC) build from the same
source, currently hosted in the ownCloud source repo on gitorious.
ownCloud Client is written in C++ using the `Qt Framework`_. As a result, the
ownCloud Client runs on the three important platforms Linux, Windows and MacOS.
oCC is written in C++ using the `Qt Framework`_. As a result oCC runs on the
three important platforms Linux, Windows and MacOS.
.. _csync: http://www.csync.org
.. _`Qt Framework`: http://www.qt-project.org
@@ -23,8 +23,8 @@ ownCloud Client runs on the three important platforms Linux, Windows and MacOS.
The Sync Process
----------------
First it is important to recall what syncing is: It tries to keep the files
on two repositories the same. That means if a file is added to one repository
First it is important to recall what syncing is. Syncing tries to keep the files
on both repositories the same. That means if a file is added to one repository
it is going to be copied to the other repository. If a file is changed on one
repository, the change is propagated to the other repository. Also, if a file
is deleted on one side, it is deleted on the other. As a matter of fact, in
@@ -34,13 +34,8 @@ server is always master.
This is the major difference to other systems like a file backup where just
changes and new files are propagated but files never get deleted.
The ownCloud Client checks both repositories for changes frequently after a
certain time span. That is refered to as a sync run. In between the local
repository is monitored by a file system monitor system that starts a sync run
immediately if something was edited, added or removed.
Sync by Time versus ETag
------------------------
Sync Direction and Strategies
-----------------------------
.. index:: time stamps, file times, etag, unique id
Until the release of ownCloud 4.5 and ownCloud Client 1.1, ownCloud employed
@@ -49,7 +44,7 @@ synced to the other repository: the files modification time.
The *modification timestamp* is part of the files metadata. It is available on
every relevant filesystem and is the natural indicator for a file change.
Modification timestamps do not require special action to create and have
modification timestamps do not require special action to create and have
a general meaning. One design goal of csync is to not require a special server
component, thats why it was chosen as the backend component.
@@ -62,24 +57,29 @@ machines.
Since this strategy is rather fragile without NTP, ownCloud 4.5 introduced a
unique number, which changes whenever the file changes. Although it is a unique
value, it is not a hash of the file, but a randomly chosen number, which it will
transmit in the Etag_ field. Since the file number is guaranteed to change if
the file changes, it can now be used to determine if one of the files has
changed.
transmit in the Etag_ field. The client will store this number in a
per-directory database, located in the application directory (version 1.1) or
as a hidden file right in the directory to be synced (later versions).
Since the file number is guaranteed to change if the file changes, it can now be
used to determine if one of the files has changed.
.. note:: ownCloud Client 1.1 and newer require file ID capabilities on the
ownCloud server, hence using them with a server earlier than 4.5.0 is
not supported.
Before the 1.3.0 release of the client the sync process might create faux
conflict files if time deviates. The original and the conflict files only
differed in the timestamp, but not in content. This behaviour was changed
towards a binary check if the files are different.
.. todo:: describe what happens if both sides change
If the per-directory database gets removed, oCC's CSync backend will fall back
to a time-stamp based sync process to rebuild the database. Thus it should be
made sure that both server and client synchronized to NTP time before
restarting the client after a database removal. If time deviates, the sync
process might create faux conflict files, which only differ in their time.
Those need to be cleaned up manually later on and will not be synced back
to the server. However, no files will get deleted in this process.
Just like files, directories also hold a unique id, which changes whenever
one of the contained files or directories gets modified. Since this is a
recursive process, it significantly reduces the effort required for a sync
cycle, because the client will only walk directories with a modified unique id.
.. note:: oCC 1.1 and newer require file ID capabilities on the ownCloud server,
hence using them with a server earlier than 4.5.0 is not supported.
This table outlines the different sync methods attempted depending
on server/client combination:
@@ -106,56 +106,3 @@ are involved and one of them is not in sync with NTP time.
.. _`NTP time synchronisation`: http://en.wikipedia.org/wiki/Network_Time_Protocol
.. _Etag: http://en.wikipedia.org/wiki/HTTP_ETag
Comparison and Conflict Cases
-----------------------------
In a sync run the client first has to detect if one of the two repositories have
changed files. On the local repository, the client traverses the file
tree and compares the modification time of each file with the value it was
before. The previous value is stored in the client's database. If it is not, it
means that the file has been added to the local repository. Note that on
the local side, the modificaton time a good attribute to detect changes because
it does not depend on time shifts and such.
For the remote (ie. ownCloud) repository, the client compares the ETag of each
file with it's previous value. Again the previous value is queried from the
database. If the ETag is still the same, the file has not changed.
In case a file has changed on both, the local and the remote repository since
the last sync run, it can not easily be decided which version of the file is
the one that should be used. However, changes to any side must not be lost.
That is called a **conflict case**. The client solves it by creating a conflict
file of the older of the two files and save the newer one under the original
file name. Conflict files are always created on the client and never on the
server. The conflict file has the same name as the original file appended with
the timestamp of the conflict detection.
.. _ignored-files-label:
Ignored Files
-------------
ownCloud Client will refuse to sync the following files:
* Files matched by one of the pattern in :ref:`ignoredFilesEditor-label`
* Files containing characters that do not work on certain file systems.
Currently, these characters are: `\, :, ?, *, ", >, <, |`
* Files starting in ``.csync_journal.db`` (reserved for journalling)
The Sync Journal
----------------
The client stores the ETag number in a per-directory database,
called the journal. It is a hidden file right in the directory
to be synced.
If the journal database gets removed, ownCloud Client's CSync backend will
rebuild the database by comparing the files and their modification times. Thus
it should be made sure that both server and client synchronized with NTP time
before restarting the client after a database removal.
Pressing ``F5`` in the Account Settings Dialog that allows to "reset" the
journal. That can be used to recreate the journal database. Use this only
if advised to do so by the developer or support staff.
+24 -34
Ver Arquivo
@@ -1,17 +1,10 @@
.. _building-label:
Appendix A: Building the Client
===============================
Building the Client
===================
This section explains how to build the ownCloud Client from source
for all major platforms. You should read this section if you want
to development on the desktop client.
Note that the building instruction are subject to change as development
proceeds. It is important to check the version which is to built.
This instructions were updated to work with ownCloud Client 1.5.
Linux
-----
@@ -41,11 +34,10 @@ its own repository which contains non-standard recipes. Add it with::
Next, install the missing dependencies::
brew install $(brew deps ocsync)
brew install $(brew deps ocsync)
brew install $(brew deps mirall)
To build mirall and csync, follow the `generic build instructions`_.
To build mirall and cmake, follow the `generic build instructions`_.
.. note::
You should not call ``make install`` at any time, since the product of the
@@ -57,12 +49,13 @@ Windows (cross-compile)
Due to the amount of dependencies that csync entails, building the client
for Windows is **currently only supported on openSUSE**, by using the MinGW
cross compiler. You can set up openSUSE 12.1, 12.2 or 13.1 in a virtual machine
cross compiler. You can set up openSUSE 12.1 or 12.2 in a virtual machine
if you do not have it installed already.
In order to cross-compile, the following repositories need to be added
via YaST or ``zypper ar`` (adjust when using openSUSE 12.2 or 13.1)::
via YaST or ``zypper ar`` (adjust when using openSUSE 12.2)::
zypper ar http://download.opensuse.org/repositories/isv:/ownCloud:/devel:/mingw:/win32/openSUSE_12.1/isv:ownCloud:devel:mingw:win32.repo
zypper ar http://download.opensuse.org/repositories/windows:/mingw:/win32/openSUSE_12.1/windows:mingw:win32.repo
zypper ar http://download.opensuse.org/repositories/windows:/mingw/openSUSE_12.1/windows:mingw.repo
@@ -70,16 +63,14 @@ Next, install the cross-compiler packages and the cross-compiled dependencies::
zypper install cmake make mingw32-cross-binutils mingw32-cross-cpp mingw32-cross-gcc \
mingw32-cross-gcc-c++ mingw32-cross-pkg-config mingw32-filesystem \
mingw32-headers mingw32-runtime site-config mingw32-libqt4-sql
mingw32-libqt4-sql-sqlite mingw32-libsqlite-devel \
mingw32-dlfcn-devel mingw32-libssh2-devel kdewin-png2ico \
mingw32-libqt4 mingw32-libqt4-devel mingw32-libgcrypt \
mingw32-libgnutls mingw32-libneon-openssl mingw32-libneon-devel \
mingw32-libbeecrypt mingw32-libopenssl mingw32-openssl \
mingw32-libpng-devel mingw32-libsqlite mingw32-qtkeychain \
mingw32-qtkeychain-devel mingw32-dlfcn mingw32-libintl-devel \
mingw32-libneon-devel mingw32-libopenssl-devel mingw32-libproxy-devel \
mingw32-libxml2-devel mingw32-zlib-devel
mingw32-headers mingw32-runtime site-config mingw32-iniparser-devel \
mingw32-libsqlite-devel mingw32-dlfcn-devel mingw32-libssh2-devel \
kdewin-png2ico mingw32-libqt4 mingw32-libqt4-devel mingw32-libgcrypt \
mingw32-libgnutls mingw32-libneon mingw32-libneon-devel mingw32-libbeecrypt \
mingw32-libopenssl mingw32-openssl mingw32-libpng-devel mingw32-libsqlite \
mingw32-qtkeychain mingw32-qtkeychain-devel mingw32-iniparser mingw32-dlfcn \
mingw32-libintl-devel mingw32-libneon-devel mingw32-libopenssl-devel \
mingw32-libproxy-devel mingw32-libxml2-devel mingw32-zlib-devel
For the installer, the NSIS installer package is also required::
@@ -91,10 +82,10 @@ For the installer, the NSIS installer package is also required::
mingw32-cross-nsis-plugin-processes mingw32-cross-nsis-plugin-uac
You will also need to manually download and install the following files with
``rpm -ivh <package>`` (They will also work with openSUSE 12.2 and newer)::
``rpm -ivh <package>`` (They will also work with OpenSUSE 12.2)::
rpm -ihv http://download.tomahawk-player.org/packman/mingw:32/openSUSE_12.1/x86_64/mingw32-cross-nsis-plugin-processes-0-1.1.x86_64.rpm
rpm -ihv http://download.tomahawk-player.org/packman/mingw:32/openSUSE_12.1/x86_64/mingw32-cross-nsis-plugin-uac-0-3.1.x86_64.rpm
rpm -ihv http://pmbs.links2linux.org/download/mingw:/32/openSUSE_12.1/x86_64/mingw32-cross-nsis-plugin-processes-0-1.1.x86_64.rpm
rpm -ihv http://pmbs.links2linux.org/download/mingw:/32/openSUSE_12.1/x86_64/mingw32-cross-nsis-plugin-uac-0-3.1.x86_64.rpm
Now, follow the `generic build instructions`_, but pay attention to
the following differences:
@@ -124,7 +115,7 @@ CMake and Mirall can be downloaded at ownCloud's `Client Download Page`_.
If you want to build the leading edge version of the client, you should
use the latest versions of Mirall and CSync via Git_, like so::
git clone git://git.csync.org/users/owncloud/csync.git ocsync
git clone git://git.csync.org/users/freitag/csync.git ocsync
git clone git://github.com/owncloud/mirall.git
Next, create build directories::
@@ -133,11 +124,11 @@ Next, create build directories::
mkdir mirall-build
This guide assumes that all directories are residing next to each other.
Next, make sure to check out the branch called 'ocsync' in the newly checked out
Next, make sure to check out the 'dav' branch in the newly checked out
`ocsync` directory::
cd ocsync
git checkout ocsync
git checkout dav
The first package to build is CSync::
@@ -146,10 +137,9 @@ The first package to build is CSync::
make
You probably have to satisfy some dependencies. Make sure to install all the
needed development packages. You will need ``sqlite3`` as well as ``neon`` for
the ownCloud module. Take special care about ``neon``. If that is missing, the
cmake run will succeed but silently not build the ownCloud module.
needed development packages. You will need ``iniparser``, ``sqlite3`` as well as
``neon`` for the ownCloud module. Take special care about ``neon``. If that is
missing, the cmake run will succeed but silently not build the ownCloud module.
``libssh`` and ``libsmbclient`` are optional and not required for the client
to work. If you want to install the client, run ``make install`` as a final step.
+4 -4
Ver Arquivo
@@ -28,7 +28,7 @@ import sys, os
extensions = ['sphinx.ext.todo']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['@CMAKE_CURRENT_SOURCE_DIR@/ocdoc/_shared_assets/templates']
#templates_path = ['templates']
# The suffix of source filenames.
source_suffix = '.rst'
@@ -64,7 +64,7 @@ release = '@VERSION@'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build','scripts/*']
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
@@ -95,7 +95,7 @@ pygments_style = 'sphinx'
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = ['@CMAKE_CURRENT_SOURCE_DIR@/ocdoc/_shared_assets/themes']
#html_theme_path = ['themes']
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
@@ -120,7 +120,7 @@ html_short_title = "Client Manual"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['@CMAKE_CURRENT_SOURCE_DIR@/ocdoc/_shared_assets/static']
#html_static_path = ['static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
+1 -2
Ver Arquivo
@@ -4,8 +4,8 @@ Glossary
.. glossary::
:sorted:
ownCloud Sync Client
ownCloud Client
oCC
Name of the official ownCloud syncing client for desktop, which runs on
Windows, Mac OS X and Linux. It is based Mirall, and uses the CSync
sync engine for synchronization with the ownCloud server.
@@ -23,7 +23,6 @@ Glossary
exist in the client directory.
unique id
ETag
ID assigned to every file starting with ownCloud server 4.5 and submitted
via the HTTP ``Etag``. Used to check if files on client and server have
changed.
Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 45 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 1.3 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 48 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 18 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 72 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 50 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 59 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 168 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 40 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 39 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 39 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 37 KiB

+2 -5
Ver Arquivo
@@ -6,11 +6,8 @@ Contents
.. toctree::
:maxdepth: 2
introduction
accountsetup
visualtour
advancedusage
install
usage
building
architecture
troubleshooting
+36
Ver Arquivo
@@ -0,0 +1,36 @@
Installation
============
General
-------
The latest version of ownCloud client can be obtained at
http://owncloud.org/sync-clients/.
Windows
-------
ownCloud client for Windows is provided as a NSIS-based setup file for
machine-wide install.
Mac OS X
--------
Installing the ownCloud client on your Mac follows the normal app installation
pattern:
1. Download the installation file Click ownCloud-x.y.z.dmg, a window with the
2. ownCloud icon opens In that window, drag the ownCloud application into the
3. Applications folder on the right hand side From Applications, choose
ownCloud
Linux
------
The ownCloud client is provided as in a convenient repository for a wide range
of popular Linux distributions. If you want to build the sources instead.
Supported distributions are CentOS/RHEL, Fedora, SLES, openSUSE, Ubuntu and
Debian.
To support other distributions, a source build is required.
-37
Ver Arquivo
@@ -1,37 +0,0 @@
Introduction
============
This is the documentation for the ownCloud Sync Client, also referred to as
the ownCloud Client.
The ownCloud Sync Client is a desktop program you install on your computer.
Specify one ore more directories on the local machine to sync your ownCloud
server, and always have your latest files wherever you are. Make a change to the
files on one computer, it will flow across the others using these desktop sync
clients.
ownCloud Client is available for Windows, Mac OS X and various Linux
distributions. See below for details on how to obtain the Client.
Obtaining the Client
--------------------
The latest version of the ownCloud Client can be obtained at
http://owncloud.org/sync-clients/.
ownCloud client for **Windows** is provided as a NSIS-based setup file for
machine-wide install. Installing the ownCloud client on **Mac OS** follows
the normal app bundle installation pattern:
1. Download the installation file: Click ``ownCloud-x.y.z.dmg``, a window with
the ownCloud icon opens.
2. In that window, drag the ownCloud application into the ``Applications``
folder.
3. On the right hand side From ``Applications``, choose ``ownCloud``.
The ownCloud Client is also provided as in a convenient repository for a wide
range of popular **Linux distributions**. If you want to build the sources
instead.
Supported distributions are Fedora, openSUSE, Ubuntu and Debian.
To support other distributions, a is required, see :ref:`building-label`
Submodule doc/ocdoc deleted from 2c3e584b23
+8 -11
Ver Arquivo
@@ -1,20 +1,17 @@
ownCloud Client supports the following command line switches:
``--logwindow``
open a window to show log output.
open a window to show log output at startup.
``--logfile`` `<filename>`
write log output to file <filename>.
``--logfile`` `<file>`
write log output to a single file
``--logdir`` `<name>`
write each sync log output in a new file in directory <name>
``--logdir`` `<dir>`
write log output to dir, one for each sync run.
``--logexpire`` `<hours>`
removes logs older than <hours> hours. (to be used with --logdir)
``--logflush``
``--flushlog``
flush the log file after every write.
``--confdir`` `<dirname>`
Use the given configuration directory.
``--monoicons``
Use black/white pictograms for systray.
+6 -19
Ver Arquivo
@@ -1,5 +1,5 @@
Appendix C: Troubleshooting
===========================
Troubleshooting
===============
If the client fails to start syncing it basically can have two
basic reasons: Either the server setup has a problem or the client
@@ -55,12 +55,6 @@ ownCloud is not shared with other syncing apps.
not be attempted. In the worst case, doing so can result in data
loss.
If some files do not get take a look at the sync protocol. Some files are
automatically automatically being ignored because they are system files,
others get ignored because their file name contains characters that cannot
be represented on certain file systems. See :ref:`_ignored-files-label` for
details.
If you are operating your own server and use the local storage backend (the
default), make sure that ownCloud has exclusive access to the directory.
@@ -71,15 +65,13 @@ If you are using a different backend, you can try to exclude a bug in the
backend by reverting to the local backend.
Logfiles
--------
========
Doing effective debugging requires to provide as much as relevant logs as
possible. The log output can help you with tracking down problem, and if you
report a bug, you're advised to include the output.
Client Logfile
~~~~~~~~~~~~~~
:Client Logfile:
Start the client with ``--logwindow``. That opens a window providing a view
on the current log. It provides a Save button to let you save the log to a
file.
@@ -105,14 +97,11 @@ given expiry period.
For example, for a long running test where you intend to keep the log data of the
last two days, this would be the command line:
```
owncloud --logdir /tmp/owncloud_logs --logexpire 48
```
ownCloud server Logfile
~~~~~~~~~~~~~~~~~~~~~~~
:ownCloud server Logfile:
The ownCloud server maintains an ownCloud specific logfile as well. It can and
must be enabled through the ownCloud Administration page. There you can adjust
the loglevel. It is advisable to set it to a verbose level like ``Debug`` or
@@ -121,9 +110,7 @@ the loglevel. It is advisable to set it to a verbose level like ``Debug`` or
The logfile can be viewed either in the web interface or can be found in the
filesystem in the ownCloud server data dir.
Webserver Logfiles
~~~~~~~~~~~~~~~~~~
:Webserver Logfiles:
Also, please take a look at your webservers error log file to check if there
are problems. For Apache on Linux, the error logs usually can be found at
``/var/log/apache2``. A file called ``error_log`` shows errors like PHP code
+55
Ver Arquivo
@@ -0,0 +1,55 @@
Usage
=====
.. index:: usage, client sync usage
To start ownCloud Client, click on the desktop icon or start it from the
application menu. In the system tray, an ownCloud icon appears.
.. index:: start application
Overview
--------
ownCloud is represented by an icon in the Desktop's system tray, also known
as notification area.
The clients menu is accessed with a right click (Windows, Linux) or left click
(Mac OS).
The status of the current sync can be observed in the Status dialog, available
trough the ``Open status...`` option. On Windows, a left click on the tray icon
also opens the status dialog.
.. note:: Until the intial setup has finished, the Connection Wizard will be
shown instead when left-clicking on Windows.
The dialog provides an overview on the configured sync folders and allows to add
and remove more sync folder connections as well as pausing a sync connection.
Changing your password
----------------------
Use the ``Configure`` option. It will open the Connection Wizard, which next to
reconfiguring your connection to use a different user or server also will allow
to change the password for the local account, or to switch from HTTP to HTTPS.
Setting up a proxy
------------------
By default, the configured system proxy will be picked up. This may not be
working reliable on some Linux distributions, as only the ``http_proxy``
variable gets parsed. You can configure a proxy different from your
system default by choosing ``Configure proxy...`` from the menu.
By default, ownCloud expects a HTTP proxy. If you want to specify a SOCKS5
proxy instead, tick the "Use as SOCKSv5 proxy" option.
Options
-------
.. index:: command line switches, command line, options, parameters
.. include:: options.rst
Config File
-----------
.. index:: config file
.. include:: conffile.rst
-189
Ver Arquivo
@@ -1,189 +0,0 @@
Visual Tour
===========
.. index:: visual tour, usage
ownCloud Client stays in the background, and is visible as an
icon in your system tray (Windows, KDE), status bar (Mac OS X)
or notification area (Ubuntu), like so:
.. image:: images/icon.png
If a setup is still required, it will open the setup. Otherwise, the
main menu is opened, which provides several options and displays
progress information:
.. image:: images/menu.png
Here is an explanation of the individual items in the menu:
* ``Open ownCloud in browser``: Opens the ownCloud web interface
* ``Open folder 'ownCloud'``: Opens the local folder. If you have
defined multiple sync targets, you should see multiple entries
here.
* **Disk space indicator**: Shows how much space is used up on the server.
* Operation indicator: Shows the status of the current sync process, or
``Up to date`` if server and client are in sync.
* **Recent Changes**: shows the last six files modified by sync operations,
and provides access to the Sync status, which lists all changes
since the last restart of ownCloud Client.
* ``Settings...``: provides access to the settings menu.
* ``Help``: Opens a browser to display this help.
* ``Quit ownCloud``: Quits ownCloud, ending a currently running sync run.
The settings dialog is split up in three categories: ``Account Settings``,
``General Settings`` and ``Network Settings``:
Account Settings
~~~~~~~~~~~~~~~~
.. index:: account settings, user, password, Server URL
The ``Account Settings`` tab provides an executive summary about the synced
folders in your account and allows to modify them. It also provides a more
detailed report about the storage usage. Finally, it allows to change
the files that ownCloud Client should ignore (for details, see the
``Ignored Files Editor`` section below), and to modify various aspects
of the current account settings, such as user name, password and server URL.
.. image:: images/settings_account.png
:scale: 50 %
General Settings
~~~~~~~~~~~~~~~~
.. index:: general settings, auto start, startup, desktop notifications
The tab provides several useful options:
.. image:: images/settings_general.png
:scale: 50 %
* **Launch on System Startup**: This option is automatically activated
once a user has conimaged his account. Unchecking the box will cause
ownCloud client to not launch on startup for a particular user.
* **Show Desktop Nofications**: Do not show bubble notifications whenever
a set of sync operations has been performed.
* **Use Monochrome Icons**: Use less obstrusive icons. Especially useful
on Mac OS.
The acout menu provides information about authors as well as detailed
information about the build conditions. Those are particularly valuable
when filing a bug report.
Network Settings
~~~~~~~~~~~~~~~~
.. index:: proxy settings, SOCKS, bandwith, throttling, limiting
This tab consollidates ``Proxy Settings`` and ``Bandwith Limiting``:
.. image:: images/settings_network.png
:scale: 50 %
Proxy Settings
^^^^^^^^^^^^^^
* ``No Proxy``: Check this if ownCloud Client should circumvent the default
proxy conimaged on the system.
* ``Use system proxy``: Default, will follow the systems proxy settings.
On Linux, this will only pick up the value of the variable ``http_proxy``.
* ``Specify proxy manually as``: Allows to specify custom proxy settings.
If you require to go through a HTTP(S) proxy server such as Squid or Microsoft
Forefront TMG, pick ``HTTP(S)``. ``SOCKSv5`` on the other hand is particulary
useful in special company LAN setups, or in combination with the OpenSSH
dynamic application level forwarding feature (see ``ssh -D``).
* ``Host``: Enter the host name or IP address of your proxy server, followed
by the port number. HTTP proxies usually listen on Ports 8080 (default) or
3128. SOCKS server usually listen on port 1080.
* ``Proxy Server requires authentication``: Should be checked if the proxy
server does not allow anonymous usage. If you check this option, you must
provide username and password in the fields below, or ownless Cloud will no
longer be able to connect successfully.
Bandwidth Limiting
^^^^^^^^^^^^^^^^^^
The ``Download Bandwidth`` (i.e. the bandwidth available for data flowing
from the ownCloud Server to the client) can be either ``Unlimited``
(the default), or limited to a custom value, specified in bytes
The ``Upload Bandwith`` (i.e. the bandwith available for data flowing
from the ownCloud Client to the server) additionally has the option
to ``Limit automatically``: When this option is checked, the ownCloud
Client will surrender available upstream bandwith to other applications.
Use this option if you expirience problems with real time communication,
such as Skype or other VoIP software, in conjunction with ownCloud Client.
This is commonly the case with asymmetric internet connection, such as
certain DSL lines with very limited upstream capacity.
ownCloud Client will pick up changes immediately, but ongoing operations
will finish using the old settings.
The Sync Status Display
~~~~~~~~~~~~~~~~~~~~~~~
.. index:: sync status
The ``Sync Status`` window, which can be invoked from either from the main
menu (``Recent Changes`` -> ``Details...``) or the ``Account Settings``
(``Info`` button), will provide you with an in-depth summary of the recent
sync activity. It will also show files that have not been synched (ignored
files). Those are ignored either because they are listed in the ignored
files list (see ``Ignored Files Editor`` section below), or because they
cannot be synced in a cross-platform manner because they contain special
characters that cannot be stored on certain file systems.
.. image:: images/sync_protocol.png
:scale: 50 %
.. _ignoredFilesEditor-label:
The Ignored Files Editor
~~~~~~~~~~~~~~~~~~~~~~~~
.. index:: ignored files, exclude files, pattern
The ignored files editor allows adding patterns for files or directories
that should be excluded from the sync process. Next to normal characters,
wildcards can be used to match an arbitrary number of characters, designated
by an asterisk (``*``) or a single character, designated by a question mark
(``?``).
Global defaults cannot be directly modified within the editor. Hovering
with the mouse will reveal the location of the global exclude definition
file.
In addition to this list, ownCloud Client always excludes files with
characters that cannot be synched down to other file systems,
see :ref:`ignored-files-label`.
.. note:: Modifying the global exclude definition file might render the
client unusable or cause undesired behavior.
.. note:: Custom entries are currently not validated for syntactical
correctness by the editor, but might fail to load correctly.
.. image:: images/ignored_files_editor.png
:scale: 50%
Pattern Matching
^^^^^^^^^^^^^^^^
To match file names against the exclude patterns, the unix standard C
library function fnmatch is used. It checks the filename against the pattern
using standard shell wildcard pattern matching. Check `The opengroup website
<http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_13_01>`
for the gory details.
The path that is checked is the relative path unter the sync root directory.
Examples:
^^^^^^^^^
+-----------+------------------------------+
| Pattern | Matches |
+===========+==============================+
| ``~$*`` | ``~$foo``, ``~$example.doc`` |
+-----------+------------------------------+
| ``fl?p`` | ``flip``, ``flap`` |
+-----------+------------------------------+
+1 -2
Ver Arquivo
@@ -4,5 +4,4 @@ Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
GenericName=Folder Sync
Icon=@APPLICATION_EXECUTABLE@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
Icon=@APPLICATION_SHORTNAME@
-3
Ver Arquivo
@@ -10,9 +10,6 @@
<file>resources/task-ongoing.png</file>
<file>resources/view-refresh.png</file>
<file>resources/warning-16.png</file>
<file>resources/settings.png</file>
<file>resources/activity.png</file>
<file>resources/network.png</file>
<file>resources/owncloud_logo_blue.png</file>
</qresource>
</RCC>
Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 1.4 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 1.1 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 2.7 KiB

-245
Ver Arquivo
@@ -1,245 +0,0 @@
/*
* c_jhash.c Jenkins Hash
*
* Copyright (c) 1997 Bob Jenkins <bob_jenkins@burtleburtle.net>
*
* lookup8.c, by Bob Jenkins, January 4 1997, Public Domain.
* hash(), hash2(), hash3, and _c_mix() are externally useful functions.
* Routines to test the hash are included if SELF_TEST is defined.
* You can use this free for any purpose. It has no warranty.
*
* See http://burtleburtle.net/bob/hash/evahash.html
*/
/**
* @file c_jhash.h
*
* @brief Interface of the cynapses jhash implementation
*
* @defgroup cynJHashInternals cynapses libc jhash function
* @ingroup cynLibraryAPI
*
* @{
*/
#ifndef _C_JHASH_H
#define _C_JHASH_H
#include <stdint.h>
#define c_hashsize(n) ((uint8_t) 1 << (n))
#define c_hashmask(n) (xhashsize(n) - 1)
/**
* _c_mix -- Mix 3 32-bit values reversibly.
*
* For every delta with one or two bit set, and the deltas of all three
* high bits or all three low bits, whether the original value of a,b,c
* is almost all zero or is uniformly distributed,
* If _c_mix() is run forward or backward, at least 32 bits in a,b,c
* have at least 1/4 probability of changing.
* If _c_mix() is run forward, every bit of c will change between 1/3 and
* 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
* _c_mix() was built out of 36 single-cycle latency instructions in a
* structure that could supported 2x parallelism, like so:
* a -= b;
* a -= c; x = (c>>13);
* b -= c; a ^= x;
* b -= a; x = (a<<8);
* c -= a; b ^= x;
* c -= b; x = (b>>13);
* ...
*
* Unfortunately, superscalar Pentiums and Sparcs can't take advantage
* of that parallelism. They've also turned some of those single-cycle
* latency instructions into multi-cycle latency instructions. Still,
* this is the fastest good hash I could find. There were about 2^^68
* to choose from. I only looked at a billion or so.
*/
#define _c_mix(a,b,c) \
{ \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<<8); \
c -= a; c -= b; c ^= (b>>13); \
a -= b; a -= c; a ^= (c>>12); \
b -= c; b -= a; b ^= (a<<16); \
c -= a; c -= b; c ^= (b>>5); \
a -= b; a -= c; a ^= (c>>3); \
b -= c; b -= a; b ^= (a<<10); \
c -= a; c -= b; c ^= (b>>15); \
}
/**
* _c_mix64 -- Mix 3 64-bit values reversibly.
*
* _c_mix64() takes 48 machine instructions, but only 24 cycles on a superscalar
* machine (like Intel's new MMX architecture). It requires 4 64-bit
* registers for 4::2 parallelism.
* All 1-bit deltas, all 2-bit deltas, all deltas composed of top bits of
* (a,b,c), and all deltas of bottom bits were tested. All deltas were
* tested both on random keys and on keys that were nearly all zero.
* These deltas all cause every bit of c to change between 1/3 and 2/3
* of the time (well, only 113/400 to 287/400 of the time for some
* 2-bit delta). These deltas all cause at least 80 bits to change
* among (a,b,c) when the _c_mix is run either forward or backward (yes it
* is reversible).
* This implies that a hash using _c_mix64 has no funnels. There may be
* characteristics with 3-bit deltas or bigger, I didn't test for
* those.
*/
#define _c_mix64(a,b,c) \
{ \
a -= b; a -= c; a ^= (c>>43); \
b -= c; b -= a; b ^= (a<<9); \
c -= a; c -= b; c ^= (b>>8); \
a -= b; a -= c; a ^= (c>>38); \
b -= c; b -= a; b ^= (a<<23); \
c -= a; c -= b; c ^= (b>>5); \
a -= b; a -= c; a ^= (c>>35); \
b -= c; b -= a; b ^= (a<<49); \
c -= a; c -= b; c ^= (b>>11); \
a -= b; a -= c; a ^= (c>>12); \
b -= c; b -= a; b ^= (a<<18); \
c -= a; c -= b; c ^= (b>>22); \
}
/**
* @brief hash a variable-length key into a 32-bit value
*
* The best hash table sizes are powers of 2. There is no need to do
* mod a prime (mod is sooo slow!). If you need less than 32 bits,
* use a bitmask. For example, if you need only 10 bits, do
* h = (h & hashmask(10));
* In which case, the hash table should have hashsize(10) elements.
*
* Use for hash table lookup, or anything where one collision in 2^32 is
* acceptable. Do NOT use for cryptographic purposes.
*
* @param k The key (the unaligned variable-length array of bytes).
*
* @param length The length of the key, counting by bytes.
*
* @param initval Initial value, can be any 4-byte value.
*
* @return Returns a 32-bit value. Every bit of the key affects every bit
* of the return value. Every 1-bit and 2-bit delta achieves
* avalanche. About 36+6len instructions.
*/
static inline uint32_t c_jhash(const uint8_t *k, uint32_t length, uint32_t initval) {
uint32_t a,b,c,len;
/* Set up the internal state */
len = length;
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
c = initval; /* the previous hash value */
while (len >= 12) {
a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24));
b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24));
c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24));
_c_mix(a,b,c);
k += 12; len -= 12;
}
/* handle the last 11 bytes */
c += length;
/* all the case statements fall through */
switch(len) {
case 11: c+=((uint32_t)k[10]<<24);
case 10: c+=((uint32_t)k[9]<<16);
case 9 : c+=((uint32_t)k[8]<<8);
/* the first byte of c is reserved for the length */
case 8 : b+=((uint32_t)k[7]<<24);
case 7 : b+=((uint32_t)k[6]<<16);
case 6 : b+=((uint32_t)k[5]<<8);
case 5 : b+=k[4];
case 4 : a+=((uint32_t)k[3]<<24);
case 3 : a+=((uint32_t)k[2]<<16);
case 2 : a+=((uint32_t)k[1]<<8);
case 1 : a+=k[0];
/* case 0: nothing left to add */
}
_c_mix(a,b,c);
return c;
}
/**
* @brief hash a variable-length key into a 64-bit value
*
* The best hash table sizes are powers of 2. There is no need to do
* mod a prime (mod is sooo slow!). If you need less than 64 bits,
* use a bitmask. For example, if you need only 10 bits, do
* h = (h & hashmask(10));
* In which case, the hash table should have hashsize(10) elements.
*
* Use for hash table lookup, or anything where one collision in 2^^64
* is acceptable. Do NOT use for cryptographic purposes.
*
* @param k The key (the unaligned variable-length array of bytes).
* @param length The length of the key, counting by bytes.
* @param intval Initial value, can be any 8-byte value.
*
* @return A 64-bit value. Every bit of the key affects every bit of
* the return value. No funnels. Every 1-bit and 2-bit delta
* achieves avalanche. About 41+5len instructions.
*/
static inline uint64_t c_jhash64(const uint8_t *k, uint64_t length, uint64_t intval) {
uint64_t a,b,c,len;
/* Set up the internal state */
len = length;
a = b = intval; /* the previous hash value */
c = 0x9e3779b97f4a7c13LL; /* the golden ratio; an arbitrary value */
/* handle most of the key */
while (len >= 24)
{
a += (k[0] +((uint64_t)k[ 1]<< 8)+((uint64_t)k[ 2]<<16)+((uint64_t)k[ 3]<<24)
+((uint64_t)k[4 ]<<32)+((uint64_t)k[ 5]<<40)+((uint64_t)k[ 6]<<48)+((uint64_t)k[ 7]<<56));
b += (k[8] +((uint64_t)k[ 9]<< 8)+((uint64_t)k[10]<<16)+((uint64_t)k[11]<<24)
+((uint64_t)k[12]<<32)+((uint64_t)k[13]<<40)+((uint64_t)k[14]<<48)+((uint64_t)k[15]<<56));
c += (k[16] +((uint64_t)k[17]<< 8)+((uint64_t)k[18]<<16)+((uint64_t)k[19]<<24)
+((uint64_t)k[20]<<32)+((uint64_t)k[21]<<40)+((uint64_t)k[22]<<48)+((uint64_t)k[23]<<56));
_c_mix64(a,b,c);
k += 24; len -= 24;
}
/* handle the last 23 bytes */
c += length;
switch(len) {
case 23: c+=((uint64_t)k[22]<<56);
case 22: c+=((uint64_t)k[21]<<48);
case 21: c+=((uint64_t)k[20]<<40);
case 20: c+=((uint64_t)k[19]<<32);
case 19: c+=((uint64_t)k[18]<<24);
case 18: c+=((uint64_t)k[17]<<16);
case 17: c+=((uint64_t)k[16]<<8);
/* the first byte of c is reserved for the length */
case 16: b+=((uint64_t)k[15]<<56);
case 15: b+=((uint64_t)k[14]<<48);
case 14: b+=((uint64_t)k[13]<<40);
case 13: b+=((uint64_t)k[12]<<32);
case 12: b+=((uint64_t)k[11]<<24);
case 11: b+=((uint64_t)k[10]<<16);
case 10: b+=((uint64_t)k[ 9]<<8);
case 9: b+=((uint64_t)k[ 8]);
case 8: a+=((uint64_t)k[ 7]<<56);
case 7: a+=((uint64_t)k[ 6]<<48);
case 6: a+=((uint64_t)k[ 5]<<40);
case 5: a+=((uint64_t)k[ 4]<<32);
case 4: a+=((uint64_t)k[ 3]<<24);
case 3: a+=((uint64_t)k[ 2]<<16);
case 2: a+=((uint64_t)k[ 1]<<8);
case 1: a+=((uint64_t)k[ 0]);
/* case 0: nothing left to add */
}
_c_mix64(a,b,c);
return c;
}
/**
* }@
*/
#endif /* _C_JHASH_H */
-3
Ver Arquivo
@@ -1,3 +0,0 @@
Eeli Reilin <eeli@emicode.fi>
Luis Gustavo S. Barreto <gustavosbarreto@gmail.com>
Stephen Kockentiedt <Stephen@Kockentiedt.name>
-26
Ver Arquivo
@@ -1,26 +0,0 @@
Copyright 2011 Eeli Reilin. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL EELI REILIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation
are those of the authors and should not be interpreted as representing
official policies, either expressed or implied, of Eeli Reilin.
-96
Ver Arquivo
@@ -1,96 +0,0 @@
########################################################################
1. INTRODUCTION
The Json class is a simple class for parsing JSON data into a QVariant
hierarchies. Now, we can also reverse the process and serialize
QVariant hierarchies into valid JSON data.
########################################################################
2. HOW TO USE
The parser is really easy to use. Let's say we have the following
QString of JSON data:
------------------------------------------------------------------------
{
"encoding" : "UTF-8",
"plug-ins" : [
"python",
"c++",
"ruby"
],
"indent" : {
"length" : 3,
"use_space" : true
}
}
------------------------------------------------------------------------
We would first call the parse-method:
------------------------------------------------------------------------
//Say that we're using the QtJson namespace
using namespace QtJson;
bool ok;
//json is a QString containing the JSON data
QVariantMap result = Json::parse(json, ok).toMap();
if(!ok) {
qFatal("An error occurred during parsing");
exit(1);
}
------------------------------------------------------------------------
Assuming the parsing process completed without errors, we would then
go through the hierarchy:
------------------------------------------------------------------------
qDebug() << "encoding:" << result["encoding"].toString();
qDebug() << "plugins:";
foreach(QVariant plugin, result["plug-ins"].toList()) {
qDebug() << "\t-" << plugin.toString();
}
QVariantMap nestedMap = result["indent"].toMap();
qDebug() << "length:" << nestedMap["length"].toInt();
qDebug() << "use_space:" << nestedMap["use_space"].toBool();
------------------------------------------------------------------------
The previous code would print out the following:
------------------------------------------------------------------------
encoding: "UTF-8"
plugins:
- "python"
- "c++"
- "ruby"
length: 3
use_space: true
------------------------------------------------------------------------
To write JSON data from Qt object is as simple as parsing:
------------------------------------------------------------------------
QVariantMap map;
map["name"] = "Name";
map["age"] = 22;
QByteArray data = Json::serialize(map);
------------------------------------------------------------------------
The byte array 'data' contains valid JSON data:
------------------------------------------------------------------------
{
name: "Luis Gustavo",
age: 22,
}
------------------------------------------------------------------------
########################################################################
4. CONTRIBUTING
The code is available to download at GitHub. Contribute if you dare!
-653
Ver Arquivo
@@ -1,653 +0,0 @@
/* Copyright 2011 Eeli Reilin. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL EELI REILIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* official policies, either expressed or implied, of Eeli Reilin.
*/
/**
* \file json.cpp
*/
#include "json.h"
namespace QtJson
{
static QString sanitizeString(QString str);
static QByteArray join(const QList<QByteArray> &list, const QByteArray &sep);
static QVariant parseValue(const QString &json, int &index, bool &success);
static QVariant parseObject(const QString &json, int &index, bool &success);
static QVariant parseArray(const QString &json, int &index, bool &success);
static QVariant parseString(const QString &json, int &index, bool &success);
static QVariant parseNumber(const QString &json, int &index);
static int lastIndexOfNumber(const QString &json, int index);
static void eatWhitespace(const QString &json, int &index);
static int lookAhead(const QString &json, int index);
static int nextToken(const QString &json, int &index);
/***** public *****/
/**
* parse
*/
QVariant parse(const QString &json)
{
bool success = true;
return parse(json, success);
}
/**
* parse
*/
QVariant parse(const QString &json, bool &success)
{
success = true;
//Return an empty QVariant if the JSON data is either null or empty
if(!json.isNull() || !json.isEmpty())
{
QString data = json;
//We'll start from index 0
int index = 0;
//Parse the first value
QVariant value = parseValue(data, index, success);
//Return the parsed value
return value;
}
else
{
//Return the empty QVariant
return QVariant();
}
}
QByteArray serialize(const QVariant &data)
{
bool success = true;
return serialize(data, success);
}
QByteArray serialize(const QVariant &data, bool &success)
{
QByteArray str;
success = true;
if(!data.isValid()) // invalid or null?
{
str = "null";
}
else if((data.type() == QVariant::List) || (data.type() == QVariant::StringList)) // variant is a list?
{
QList<QByteArray> values;
const QVariantList list = data.toList();
Q_FOREACH(const QVariant& v, list)
{
QByteArray serializedValue = serialize(v);
if(serializedValue.isNull())
{
success = false;
break;
}
values << serializedValue;
}
str = "[ " + join( values, ", " ) + " ]";
}
else if(data.type() == QVariant::Hash) // variant is a hash?
{
const QVariantHash vhash = data.toHash();
QHashIterator<QString, QVariant> it( vhash );
str = "{ ";
QList<QByteArray> pairs;
while(it.hasNext())
{
it.next();
QByteArray serializedValue = serialize(it.value());
if(serializedValue.isNull())
{
success = false;
break;
}
pairs << sanitizeString(it.key()).toUtf8() + " : " + serializedValue;
}
str += join(pairs, ", ");
str += " }";
}
else if(data.type() == QVariant::Map) // variant is a map?
{
const QVariantMap vmap = data.toMap();
QMapIterator<QString, QVariant> it( vmap );
str = "{ ";
QList<QByteArray> pairs;
while(it.hasNext())
{
it.next();
QByteArray serializedValue = serialize(it.value());
if(serializedValue.isNull())
{
success = false;
break;
}
pairs << sanitizeString(it.key()).toUtf8() + " : " + serializedValue;
}
str += join(pairs, ", ");
str += " }";
}
else if((data.type() == QVariant::String) || (data.type() == QVariant::ByteArray)) // a string or a byte array?
{
str = sanitizeString(data.toString()).toUtf8();
}
else if(data.type() == QVariant::Double) // double?
{
str = QByteArray::number(data.toDouble(), 'g', 20);
if(!str.contains(".") && ! str.contains("e"))
{
str += ".0";
}
}
else if (data.type() == QVariant::Bool) // boolean value?
{
str = data.toBool() ? "true" : "false";
}
else if (data.type() == QVariant::ULongLong) // large unsigned number?
{
str = QByteArray::number(data.value<qulonglong>());
}
else if ( data.canConvert<qlonglong>() ) // any signed number?
{
str = QByteArray::number(data.value<qlonglong>());
}
else if (data.canConvert<long>())
{
str = QString::number(data.value<long>()).toUtf8();
}
else if (data.canConvert<QString>()) // can value be converted to string?
{
// this will catch QDate, QDateTime, QUrl, ...
str = sanitizeString(data.toString()).toUtf8();
}
else
{
success = false;
}
if (success)
{
return str;
}
else
{
return QByteArray();
}
}
/***** private *****/
/**
* \enum JsonToken
*/
enum JsonToken
{
JsonTokenNone = 0,
JsonTokenCurlyOpen = 1,
JsonTokenCurlyClose = 2,
JsonTokenSquaredOpen = 3,
JsonTokenSquaredClose = 4,
JsonTokenColon = 5,
JsonTokenComma = 6,
JsonTokenString = 7,
JsonTokenNumber = 8,
JsonTokenTrue = 9,
JsonTokenFalse = 10,
JsonTokenNull = 11
};
static QString sanitizeString(QString str)
{
str.replace(QLatin1String("\\"), QLatin1String("\\\\"));
str.replace(QLatin1String("\""), QLatin1String("\\\""));
str.replace(QLatin1String("\b"), QLatin1String("\\b"));
str.replace(QLatin1String("\f"), QLatin1String("\\f"));
str.replace(QLatin1String("\n"), QLatin1String("\\n"));
str.replace(QLatin1String("\r"), QLatin1String("\\r"));
str.replace(QLatin1String("\t"), QLatin1String("\\t"));
return QString(QLatin1String("\"%1\"")).arg(str);
}
static QByteArray join(const QList<QByteArray> &list, const QByteArray &sep)
{
QByteArray res;
Q_FOREACH(const QByteArray &i, list)
{
if(!res.isEmpty())
{
res += sep;
}
res += i;
}
return res;
}
/**
* parseValue
*/
static QVariant parseValue(const QString &json, int &index, bool &success)
{
//Determine what kind of data we should parse by
//checking out the upcoming token
switch(lookAhead(json, index))
{
case JsonTokenString:
return parseString(json, index, success);
case JsonTokenNumber:
return parseNumber(json, index);
case JsonTokenCurlyOpen:
return parseObject(json, index, success);
case JsonTokenSquaredOpen:
return parseArray(json, index, success);
case JsonTokenTrue:
nextToken(json, index);
return QVariant(true);
case JsonTokenFalse:
nextToken(json, index);
return QVariant(false);
case JsonTokenNull:
nextToken(json, index);
return QVariant();
case JsonTokenNone:
break;
}
//If there were no tokens, flag the failure and return an empty QVariant
success = false;
return QVariant();
}
/**
* parseObject
*/
static QVariant parseObject(const QString &json, int &index, bool &success)
{
QVariantMap map;
int token;
//Get rid of the whitespace and increment index
nextToken(json, index);
//Loop through all of the key/value pairs of the object
bool done = false;
while(!done)
{
//Get the upcoming token
token = lookAhead(json, index);
if(token == JsonTokenNone)
{
success = false;
return QVariantMap();
}
else if(token == JsonTokenComma)
{
nextToken(json, index);
}
else if(token == JsonTokenCurlyClose)
{
nextToken(json, index);
return map;
}
else
{
//Parse the key/value pair's name
QString name = parseString(json, index, success).toString();
if(!success)
{
return QVariantMap();
}
//Get the next token
token = nextToken(json, index);
//If the next token is not a colon, flag the failure
//return an empty QVariant
if(token != JsonTokenColon)
{
success = false;
return QVariant(QVariantMap());
}
//Parse the key/value pair's value
QVariant value = parseValue(json, index, success);
if(!success)
{
return QVariantMap();
}
//Assign the value to the key in the map
map[name] = value;
}
}
//Return the map successfully
return QVariant(map);
}
/**
* parseArray
*/
static QVariant parseArray(const QString &json, int &index, bool &success)
{
QVariantList list;
nextToken(json, index);
bool done = false;
while(!done)
{
int token = lookAhead(json, index);
if(token == JsonTokenNone)
{
success = false;
return QVariantList();
}
else if(token == JsonTokenComma)
{
nextToken(json, index);
}
else if(token == JsonTokenSquaredClose)
{
nextToken(json, index);
break;
}
else
{
QVariant value = parseValue(json, index, success);
if(!success)
{
return QVariantList();
}
list.push_back(value);
}
}
return QVariant(list);
}
/**
* parseString
*/
static QVariant parseString(const QString &json, int &index, bool &success)
{
QString s;
QChar c;
eatWhitespace(json, index);
c = json[index++];
bool complete = false;
while(!complete)
{
if(index == json.size())
{
break;
}
c = json[index++];
if(c == '\"')
{
complete = true;
break;
}
else if(c == '\\')
{
if(index == json.size())
{
break;
}
c = json[index++];
if(c == '\"')
{
s.append('\"');
}
else if(c == '\\')
{
s.append('\\');
}
else if(c == '/')
{
s.append('/');
}
else if(c == 'b')
{
s.append('\b');
}
else if(c == 'f')
{
s.append('\f');
}
else if(c == 'n')
{
s.append('\n');
}
else if(c == 'r')
{
s.append('\r');
}
else if(c == 't')
{
s.append('\t');
}
else if(c == 'u')
{
int remainingLength = json.size() - index;
if(remainingLength >= 4)
{
QString unicodeStr = json.mid(index, 4);
int symbol = unicodeStr.toInt(0, 16);
s.append(QChar(symbol));
index += 4;
}
else
{
break;
}
}
}
else
{
s.append(c);
}
}
if(!complete)
{
success = false;
return QVariant();
}
return QVariant(s);
}
/**
* parseNumber
*/
static QVariant parseNumber(const QString &json, int &index)
{
eatWhitespace(json, index);
int lastIndex = lastIndexOfNumber(json, index);
int charLength = (lastIndex - index) + 1;
QString numberStr;
numberStr = json.mid(index, charLength);
index = lastIndex + 1;
if (numberStr.contains('.')) {
return QVariant(numberStr.toDouble(NULL));
} else if (numberStr.startsWith('-')) {
return QVariant(numberStr.toLongLong(NULL));
} else {
return QVariant(numberStr.toULongLong(NULL));
}
}
/**
* lastIndexOfNumber
*/
static int lastIndexOfNumber(const QString &json, int index)
{
int lastIndex;
for(lastIndex = index; lastIndex < json.size(); lastIndex++)
{
if(QString("0123456789+-.eE").indexOf(json[lastIndex]) == -1)
{
break;
}
}
return lastIndex -1;
}
/**
* eatWhitespace
*/
static void eatWhitespace(const QString &json, int &index)
{
for(; index < json.size(); index++)
{
if(QString(" \t\n\r").indexOf(json[index]) == -1)
{
break;
}
}
}
/**
* lookAhead
*/
static int lookAhead(const QString &json, int index)
{
int saveIndex = index;
return nextToken(json, saveIndex);
}
/**
* nextToken
*/
static int nextToken(const QString &json, int &index)
{
eatWhitespace(json, index);
if(index == json.size())
{
return JsonTokenNone;
}
QChar c = json[index];
index++;
switch(c.toLatin1())
{
case '{': return JsonTokenCurlyOpen;
case '}': return JsonTokenCurlyClose;
case '[': return JsonTokenSquaredOpen;
case ']': return JsonTokenSquaredClose;
case ',': return JsonTokenComma;
case '"': return JsonTokenString;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '-': return JsonTokenNumber;
case ':': return JsonTokenColon;
}
index--;
int remainingLength = json.size() - index;
//True
if(remainingLength >= 4)
{
if (json[index] == 't' && json[index + 1] == 'r' &&
json[index + 2] == 'u' && json[index + 3] == 'e')
{
index += 4;
return JsonTokenTrue;
}
}
//False
if (remainingLength >= 5)
{
if (json[index] == 'f' && json[index + 1] == 'a' &&
json[index + 2] == 'l' && json[index + 3] == 's' &&
json[index + 4] == 'e')
{
index += 5;
return JsonTokenFalse;
}
}
//Null
if (remainingLength >= 4)
{
if (json[index] == 'n' && json[index + 1] == 'u' &&
json[index + 2] == 'l' && json[index + 3] == 'l')
{
index += 4;
return JsonTokenNull;
}
}
return JsonTokenNone;
}
} //end namespace
-85
Ver Arquivo
@@ -1,85 +0,0 @@
/* Copyright 2011 Eeli Reilin. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL EELI REILIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* official policies, either expressed or implied, of Eeli Reilin.
*/
/**
* \file json.h
*/
#ifndef JSON_H
#define JSON_H
#include <QVariant>
#include <QString>
/**
* \namespace QtJson
* \brief A JSON data parser
*
* Json parses a JSON data into a QVariant hierarchy.
*/
namespace QtJson
{
/**
* Parse a JSON string
*
* \param json The JSON data
*/
QVariant parse(const QString &json);
/**
* Parse a JSON string
*
* \param json The JSON data
* \param success The success of the parsing
*/
QVariant parse(const QString &json, bool &success);
/**
* This method generates a textual JSON representation
*
* \param data The JSON data generated by the parser.
*
* \return QByteArray Textual JSON representation
*/
QByteArray serialize(const QVariant &data);
/**
* This method generates a textual JSON representation
*
* \param data The JSON data generated by the parser.
* \param success The success of the serialization
*
* \return QByteArray Textual JSON representation
*/
QByteArray serialize(const QVariant &data, bool &success);
} //end namespace
#endif //JSON_H
@@ -61,13 +61,11 @@ QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char *
}
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type)
: QApplication(argc, argv, type)
{
sysInit();
}
#endif
#if defined(Q_WS_X11)
-6
Ver Arquivo
@@ -28,9 +28,6 @@
**
**************************************************************************/
#ifndef _SHAREDTOOLS_SINGLEAPPLICATION
#define _SHAREDTOOLS_SINGLEAPPLICATION
#include <QApplication>
namespace SharedTools {
@@ -44,9 +41,7 @@ class QtSingleApplication : public QApplication
public:
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
QtSingleApplication(const QString &id, int &argc, char **argv);
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
QtSingleApplication(int &argc, char **argv, Type type);
#endif
#if defined(Q_WS_X11)
explicit QtSingleApplication(Display *dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0);
@@ -88,4 +83,3 @@ private:
};
} // namespace SharedTools
#endif // _SHAREDTOOLS_SINGLEAPPLICATION
+64 -180
Ver Arquivo
@@ -1,17 +1,26 @@
#add_subdirectory(integration)
include(${QT_USE_FILE})
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
qt_add_resources(MIRALL_RC_SRC ../mirall.qrc)
QT4_ADD_RESOURCES ( MIRALL_RC_SRC ../mirall.qrc)
if ( IS_DIRECTORY ${OEM_THEME_DIR} )
qt_add_resources(MIRALL_RC_SRC ${OEM_THEME_DIR}/theme.qrc)
QT4_ADD_RESOURCES ( MIRALL_RC_SRC ${OEM_THEME_DIR}/theme.qrc)
set(theme_dir ${OEM_THEME_DIR}/theme)
else()
qt_add_resources(MIRALL_RC_SRC ../theme.qrc)
QT4_ADD_RESOURCES ( MIRALL_RC_SRC ../theme.qrc)
set(theme_dir ${CMAKE_CURRENT_SOURCE_DIR}/../theme)
endif()
set(synclib_NAME ${APPLICATION_EXECUTABLE}sync)
set(mirall_UI
mirall/folderwizardsourcepage.ui
mirall/folderwizardtargetpage.ui
mirall/statusdialog.ui
mirall/owncloudsetuppage_ng.ui
mirall/owncloudwizardresultpage.ui
mirall/sslerrordialog.ui
mirall/proxydialog.ui
mirall/fileitemdialog.ui
)
set(3rdparty_SRC
3rdparty/qtsingleapplication/qtsingleapplication.cpp
@@ -29,10 +38,9 @@ set(3rdparty_HEADER
3rdparty/fancylineedit/fancylineedit.h
3rdparty/QProgressIndicator/QProgressIndicator.h
)
qt4_wrap_cpp(3rdparty_MOC ${3rdparty_HEADER})
qt_wrap_cpp(3rdparty_MOC ${3rdparty_HEADER})
if(NOT WIN32)
if(NOT WIN32)
list(APPEND 3rdparty_SRC 3rdparty/qtlockedfile/qtlockedfile_unix.cpp)
else()
list(APPEND 3rdparty_SRC 3rdparty/qtlockedfile/qtlockedfile_win.cpp )
@@ -43,74 +51,38 @@ set(3rdparty_INC
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/qtsingleapplication
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/QProgressIndicator
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/fancylineedit
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/csync
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/qjson
)
qt4_wrap_ui(mirall_UI_SRCS ${mirall_UI})
set(libsync_SRCS
mirall/folderman.cpp
mirall/folder.cpp
mirall/folderwatcher.cpp
mirall/syncresult.cpp
mirall/networklocation.cpp
mirall/mirallconfigfile.cpp
mirall/credentialstore.cpp
mirall/owncloudfolder.cpp
mirall/csyncthread.cpp
mirall/owncloudpropagator.cpp
mirall/syncjournalfilerecord.cpp
mirall/syncjournaldb.cpp
mirall/fileutils.cpp
mirall/theme.cpp
mirall/owncloudtheme.cpp
mirall/owncloudinfo.cpp
mirall/logger.cpp
mirall/utility.cpp
mirall/connectionvalidator.cpp
mirall/progressdispatcher.cpp
mirall/mirallaccessmanager.cpp
mirall/networkjobs.cpp
mirall/account.cpp
mirall/quotainfo.cpp
creds/dummycredentials.cpp
creds/httpcredentials.cpp
creds/credentialsfactory.cpp
creds/http/httpconfigfile.cpp
creds/shibbolethcredentials.cpp
creds/shibboleth/shibbolethaccessmanager.cpp
creds/shibboleth/shibbolethcookiejar.cpp
creds/shibboleth/shibbolethwebview.cpp
creds/shibboleth/shibbolethrefresher.cpp
creds/shibboleth/shibbolethconfigfile.cpp
creds/credentialscommon.cpp
3rdparty/qjson/json.cpp
)
set(libsync_HEADERS
set(libsync_HEADERS
mirall/folderman.h
mirall/folder.h
mirall/folderwatcher.h
mirall/owncloudfolder.h
mirall/csyncthread.h
mirall/owncloudpropagator.h
mirall/syncjournaldb.h
mirall/theme.h
mirall/owncloudtheme.h
mirall/owncloudinfo.h
mirall/credentialstore.h
mirall/logger.h
mirall/connectionvalidator.h
mirall/progressdispatcher.h
mirall/mirallaccessmanager.h
mirall/networkjobs.h
mirall/account.h
mirall/quotainfo.h
creds/abstractcredentials.h
creds/dummycredentials.h
creds/httpcredentials.h
creds/credentialsfactory.h
creds/http/httpconfigfile.h
creds/shibbolethcredentials.h
creds/shibboleth/shibbolethaccessmanager.h
creds/shibboleth/shibbolethcookiejar.h
creds/shibboleth/shibbolethwebview.h
creds/shibboleth/shibbolethrefresher.h
creds/shibboleth/shibbolethconfigfile.h
creds/credentialscommon.h
3rdparty/qjson/json.h
)
IF( INOTIFY_FOUND )
@@ -119,7 +91,7 @@ IF( INOTIFY_FOUND )
set(libsync_HEADERS ${libsync_HEADERS} mirall/inotify.h)
set(libsync_HEADERS ${libsync_HEADERS} mirall/folderwatcher_inotify.h)
ENDIF()
IF( WIN32 )
IF( WIN32 )
set(libsync_SRCS ${libsync_SRCS} mirall/folderwatcher_win.cpp)
set(libsync_HEADERS ${libsync_HEADERS} mirall/folderwatcher_win.h)
ENDIF()
@@ -128,111 +100,59 @@ IF( APPLE )
ENDIF()
qt_wrap_cpp(syncMoc ${libsync_HEADERS})
IF( DEFINED CSYNC_BUILD_PATH )
SET(HTTPBF_LIBRARY ${CSYNC_BUILD_PATH}/src/httpbf/libhttpbf.a)
ELSE()
FIND_LIBRARY(HTTPBF_LIBRARY NAMES httpbf HINTS $ENV{CSYNC_DIR})
ENDIF()
qt4_wrap_cpp(syncMoc ${libsync_HEADERS})
list(APPEND libsync_LINK_TARGETS
${QT_LIBRARIES}
${CSYNC_LIBRARY}
${HTTPBF_LIBRARY}
dl
)
IF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
list(APPEND libsync_LINK_TARGETS
inotify
)
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
if(QTKEYCHAIN_FOUND)
list(APPEND libsync_LINK_TARGETS ${QTKEYCHAIN_LIBRARY})
include_directories(${QTKEYCHAIN_INCLUDE_DIR})
endif()
if(NEON_FOUND)
list(APPEND libsync_LINK_TARGETS ${NEON_LIBRARIES})
include_directories(${NEON_INCLUDE_DIRS})
endif()
add_library(${synclib_NAME} SHARED ${libsync_SRCS} ${syncMoc})
qt5_use_modules(${synclib_NAME} Widgets Network Xml WebKitWidgets Sql)
set_target_properties( ${synclib_NAME} PROPERTIES
add_library(owncloudsync SHARED ${libsync_SRCS} ${syncMoc})
set_target_properties( owncloudsync PROPERTIES
VERSION ${VERSION}
SOVERSION ${SOVERSION}
)
target_link_libraries(${synclib_NAME} ${libsync_LINK_TARGETS} )
target_link_libraries(owncloudsync ${libsync_LINK_TARGETS} )
if ( APPLE )
target_link_libraries(${synclib_NAME} /System/Library/Frameworks/CoreServices.framework)
target_link_libraries(owncloudsync /System/Library/Frameworks/CoreServices.framework)
endif()
if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
install(TARGETS ${synclib_NAME}
install(TARGETS owncloudsync
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
if(NOT WIN32)
configure_file(${CMAKE_SOURCE_DIR}/mirall.desktop.in
${CMAKE_CURRENT_BINARY_DIR}/${APPLICATION_EXECUTABLE}.desktop)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${APPLICATION_EXECUTABLE}.desktop DESTINATION share/applications )
${CMAKE_CURRENT_BINARY_DIR}/${APPLICATION_SHORTNAME}.desktop)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${APPLICATION_SHORTNAME}.desktop DESTINATION share/applications )
endif()
else()
install(TARGETS ${synclib_NAME} DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/MacOS)
install(TARGETS owncloudsync DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/MacOS)
endif()
set(mirall_UI
mirall/folderwizardsourcepage.ui
mirall/folderwizardtargetpage.ui
mirall/sslerrordialog.ui
mirall/settingsdialog.ui
mirall/generalsettings.ui
mirall/networksettings.ui
mirall/accountsettings.ui
mirall/ignorelisteditor.ui
mirall/protocolwidget.ui
wizard/owncloudsetupnocredspage.ui
wizard/owncloudhttpcredspage.ui
wizard/owncloudwizardresultpage.ui
wizard/owncloudadvancedsetuppage.ui
)
qt_wrap_ui(mirall_UI_SRCS ${mirall_UI})
set(mirall_SRCS
mirall/application.cpp
mirall/systray.cpp
mirall/folderwizard.cpp
mirall/folderstatusmodel.cpp
mirall/protocolwidget.cpp
wizard/owncloudwizard.cpp
wizard/owncloudsetuppage.cpp
wizard/owncloudhttpcredspage.cpp
wizard/owncloudwizardresultpage.cpp
wizard/owncloudwizardcommon.cpp
wizard/owncloudshibbolethcredspage.cpp
wizard/owncloudadvancedsetuppage.cpp
mirall/statusdialog.cpp
mirall/owncloudwizard.cpp
mirall/owncloudsetupwizard.cpp
mirall/updatedetector.cpp
mirall/occinfo.cpp
mirall/sslerrordialog.cpp
mirall/logbrowser.cpp
mirall/settingsdialog.cpp
mirall/generalsettings.cpp
mirall/networksettings.cpp
mirall/accountsettings.cpp
mirall/ignorelisteditor.cpp
mirall/owncloudgui.cpp
mirall/socketapi.cpp
mirall/proxydialog.cpp
mirall/fileitemdialog.cpp
)
set(mirall_HEADERS
@@ -240,25 +160,13 @@ set(mirall_HEADERS
mirall/systray.h
mirall/folderwizard.h
mirall/owncloudsetupwizard.h
wizard/owncloudwizard.h
wizard/owncloudsetuppage.h
wizard/owncloudhttpcredspage.h
wizard/owncloudwizardresultpage.h
wizard/owncloudwizardcommon.h
wizard/owncloudshibbolethcredspage.h
wizard/owncloudadvancedsetuppage.h
mirall/folderstatusmodel.h
mirall/owncloudwizard.h
mirall/statusdialog.h
mirall/updatedetector.h
mirall/sslerrordialog.h
mirall/logbrowser.h
mirall/settingsdialog.h
mirall/generalsettings.h
mirall/networksettings.h
mirall/accountsettings.h
mirall/ignorelisteditor.h
mirall/protocolwidget.h
mirall/owncloudgui.h
mirall/socketapi.h
mirall/proxydialog.h
mirall/fileitemdialog.h
)
if( UNIX AND NOT APPLE)
@@ -268,12 +176,12 @@ if( UNIX AND NOT APPLE)
endif()
# csync is required.
include_directories(${CSYNC_INCLUDE_DIR}/csync ${CSYNC_INCLUDE_DIR} ${CSYNC_INCLUDE_DIR}/httpbf/src ${CSYNC_BUILD_PATH}/src)
include_directories(${CSYNC_INCLUDE_DIR}/csync ${CSYNC_INCLUDE_DIR} ${CSYNC_BUILD_PATH}/src)
include_directories(${3rdparty_INC})
qt_wrap_cpp(mirallMoc ${mirall_HEADERS})
qt4_wrap_cpp(mirallMoc ${mirall_HEADERS})
qt_add_translation(mirall_I18N ${TRANSLATIONS})
qt4_add_translation(mirall_I18N ${TRANSLATIONS})
set( final_src
${mirall_HEADERS}
@@ -291,41 +199,26 @@ set( final_src
include( AddAppIconMacro )
set(ownCloud_old ${ownCloud})
# set an icon_app_name. For historical reasons we can not use the
# application_shortname for ownCloud but must rather set it manually.
if ( EXISTS ${OEM_THEME_DIR}/OEM.cmake )
set(ICON_APP_NAME ${APPLICATION_SHORTNAME})
else()
set(ICON_APP_NAME "owncloud")
endif()
kde4_add_app_icon( ownCloud "${theme_dir}/colored/${ICON_APP_NAME}-icon*.png")
kde4_add_app_icon( ownCloud "${theme_dir}/colored/${APPLICATION_SHORTNAME}-icon*.png")
list(APPEND final_src ${ownCloud})
set(ownCloud ${ownCloud_old})
if (WITH_DBUS)
set(ADDITIONAL_APP_MODULES DBus)
endif(WITH_DBUS)
if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
if(NOT WIN32)
file( GLOB _icons "${theme_dir}/colored/${ICON_APP_NAME}-icon-*.png" )
foreach( _file ${_icons} )
string( REPLACE "${theme_dir}/colored/${ICON_APP_NAME}-icon-" "" _res ${_file} )
string( REPLACE ".png" "" _res ${_res} )
install( FILES ${_file} RENAME ${ICON_APP_NAME}.png DESTINATION ${DATADIR}/icons/hicolor/${_res}x${_res}/apps )
endforeach( _file )
install(FILES
${theme_dir}/colored/${APPLICATION_SHORTNAME}-icon-48.png
DESTINATION share/icons/hicolor/48x48/apps/ RENAME ${APPLICATION_SHORTNAME}.png)
endif(NOT WIN32)
install(FILES ${mirall_I18N} DESTINATION share/${APPLICATION_EXECUTABLE}/i18n)
install(FILES ${mirall_I18N} DESTINATION share/mirall/i18n)
# we may not add MACOSX_BUNDLE here, if not building one
# add_executable( ${APPLICATION_EXECUTABLE} main.cpp ${final_src})
add_executable( ${APPLICATION_EXECUTABLE} WIN32 main.cpp ${final_src})
qt5_use_modules(${APPLICATION_EXECUTABLE} Widgets Network Xml WebKitWidgets Sql ${ADDITIONAL_APP_MODULES})
else()
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
include(DeployQt4)
@@ -335,7 +228,13 @@ else()
# we must add MACOSX_BUNDLE only if building a bundle
add_executable( ${APPLICATION_EXECUTABLE} WIN32 MACOSX_BUNDLE main.cpp ${final_src})
qt5_use_modules(${APPLICATION_EXECUTABLE} Widgets Network Xml WebKitWidgets Sql ${ADDITIONAL_APP_MODULES})
#FIXME: hardcoded path
if ( EXISTS ${CSYNC_BINARY_DIR}/modules/ocsync_owncloud.so )
install(FILES ${CSYNC_BINARY_DIR}/modules/ocsync_owncloud.so DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/Plugins)
else()
install(FILES /usr/local/lib/ocsync-0/ocsync_owncloud.so DESTINATION ${OWNCLOUD_OSX_BUNDLE}/Contents/Plugins)
endif()
set (QM_DIR ${OWNCLOUD_OSX_BUNDLE}/Contents/Resources/Translations)
install(FILES ${mirall_I18N} DESTINATION ${QM_DIR})
@@ -343,6 +242,7 @@ else()
install(FILES ${qt_I18N} DESTINATION ${QM_DIR})
file(GLOB qtkeychain_I18N ${QT_TRANSLATIONS_DIR}/qtkeychain*.qm)
install(FILES ${qtkeychain_I18N} DESTINATION ${QM_DIR})
list(APPEND dirs "/usr/local/lib")
endif()
@@ -350,7 +250,7 @@ set_target_properties( ${APPLICATION_EXECUTABLE} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIRECTORY}
)
target_link_libraries( ${APPLICATION_EXECUTABLE} ${QT_LIBRARIES} )
target_link_libraries( ${APPLICATION_EXECUTABLE} ${synclib_NAME} )
target_link_libraries( ${APPLICATION_EXECUTABLE} owncloudsync )
target_link_libraries( ${APPLICATION_EXECUTABLE} ${CSYNC_LIBRARY} )
install(TARGETS ${APPLICATION_EXECUTABLE}
@@ -364,9 +264,7 @@ install(TARGETS ${APPLICATION_EXECUTABLE}
# currently it needs to be done because the code right above needs to be executed no matter
# if building a bundle or not and the install_qt4_executable needs to be called afterwards
if(BUILD_OWNCLOUD_OSX_BUNDLE)
install_qt4_executable(${OWNCLOUD_OSX_BUNDLE})
install_qt4_plugin(qsqlite ${OWNCLOUD_OSX_BUNDLE} 0 "")
install_qt4_plugin(qtaccessiblewidgets ${OWNCLOUD_OSX_BUNDLE} 0 "")
install_qt4_executable(${OWNCLOUD_OSX_BUNDLE} "" "${OWNCLOUD_OSX_BUNDLE}/Contents/Plugins/ocsync_owncloud.so" ${dirs})
endif()
find_program(KRAZY2_EXECUTABLE krazy2)
@@ -379,17 +277,3 @@ if(KRAZY2_EXECUTABLE)
)
endif()
set(owncloudcmd_NAME ${APPLICATION_EXECUTABLE}cmd)
set(OWNCLOUDCMD_SRC owncloudcmd/owncloudcmd.cpp)
add_executable(${owncloudcmd_NAME} ${OWNCLOUDCMD_SRC})
qt5_use_modules(${owncloudcmd_NAME} Network Sql)
set_target_properties(${owncloudcmd_NAME} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIRECTORY} )
target_link_libraries(${owncloudcmd_NAME} ${synclib_NAME})
target_link_libraries(${owncloudcmd_NAME} ${CSYNC_LIBRARY})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mirall)
install(TARGETS ${owncloudcmd_NAME}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
-54
Ver Arquivo
@@ -1,54 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_CREDS_ABSTRACT_CREDENTIALS_H
#define MIRALL_CREDS_ABSTRACT_CREDENTIALS_H
#include <QObject>
#include <csync.h>
class QNetworkAccessManager;
class QNetworkReply;
namespace Mirall
{
class Account;
class AbstractCredentials : public QObject
{
Q_OBJECT
public:
// No need for virtual destructor - QObject already has one.
virtual void syncContextPreInit(CSYNC* ctx) = 0;
virtual void syncContextPreStart(CSYNC* ctx) = 0;
virtual bool changed(AbstractCredentials* credentials) const = 0;
virtual QString authType() const = 0;
virtual QString user() const = 0;
virtual QNetworkAccessManager* getQNAM() const = 0;
virtual bool ready() const = 0;
virtual void fetch(Account *account) = 0;
virtual bool stillValid(QNetworkReply *reply) = 0;
virtual bool fetchFromUser(Account *account) = 0;
virtual void persist(Account *account) = 0;
/** Invalidates auth token, or password for basic auth */
virtual void invalidateToken(Account *account) = 0;
Q_SIGNALS:
void fetched();
};
} // ns Mirall
#endif
-78
Ver Arquivo
@@ -1,78 +0,0 @@
/*
* Copyright (C) by Klaas Freitag <freitag@kde.org>
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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. See the GNU General Public License
* for more details.
*/
#include <QList>
#include <QRegExp>
#include <QString>
#include <QSslCertificate>
#include <QDebug>
#include "creds/credentialscommon.h"
#include "mirall/utility.h"
#include "mirall/account.h"
namespace Mirall
{
int handleNeonSSLProblems(const char* prompt,
char* buf,
size_t /*len*/,
int /*echo*/,
int /*verify*/,
void* /*userdata*/)
{
int re = 0;
const QString qPrompt = QString::fromLatin1( prompt ).trimmed();
if( qPrompt.startsWith( QLatin1String("There are problems with the SSL certificate:"))) {
// SSL is requested. If the program came here, the SSL check was done by mirall
// It needs to be checked if the chain is still equal to the one which
// was verified by the user.
const QRegExp regexp("fingerprint: ([\\w\\d:]+)");
bool certOk = false;
int pos = 0;
// This is the set of certificates which QNAM accepted, so we should accept
// them as well
QList<QSslCertificate> certs = AccountManager::instance()->account()->certificateChain();
while (!certOk && (pos = regexp.indexIn(qPrompt, 1+pos)) != -1) {
QString neon_fingerprint = regexp.cap(1);
foreach( const QSslCertificate& c, certs ) {
QString verified_shasum = Utility::formatFingerprint(c.digest(QCryptographicHash::Sha1).toHex());
qDebug() << "SSL Fingerprint from neon: " << neon_fingerprint << " compared to verified: " << verified_shasum;
if( verified_shasum == neon_fingerprint ) {
certOk = true;
break;
}
}
}
// certOk = false; DEBUG setting, keep disabled!
if( !certOk ) { // Problem!
qstrcpy( buf, "no" );
re = -1;
} else {
qstrcpy( buf, "yes" ); // Certificate is fine!
}
} else {
qDebug() << "Unknown prompt: <" << prompt << ">";
re = -1;
}
return re;
}
} // ns Mirall
-31
Ver Arquivo
@@ -1,31 +0,0 @@
/*
* Copyright (C) by Klaas Freitag <freitag@kde.org>
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_CREDS_COMMON_H
#define MIRALL_CREDS_COMMON_H
namespace Mirall
{
int handleNeonSSLProblems(const char* prompt,
char* buf,
size_t len,
int echo,
int verify,
void* userdata);
} // ns Mirall
#endif
-43
Ver Arquivo
@@ -1,43 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#include <QString>
#include "creds/httpcredentials.h"
#include "creds/dummycredentials.h"
#include "creds/shibbolethcredentials.h"
namespace Mirall
{
namespace CredentialsFactory
{
AbstractCredentials* create(const QString& type)
{
// empty string might happen for old version of configuration
if (type == "http" || type == "") {
return new HttpCredentials;
} else if (type == "dummy") {
return new DummyCredentials;
} else if (type == "shibboleth") {
return new ShibbolethCredentials;
} else {
qWarning("Unknown credentials type: %s", qPrintable(type));
return new DummyCredentials;
}
}
} // ns CredentialsFactory
} // ns Mirall
-32
Ver Arquivo
@@ -1,32 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_CREDS_CREDENTIALS_FACTORY_H
#define MIRALL_CREDS_CREDENTIALS_FACTORY_H
class AbstractCredentials;
class QString;
namespace Mirall
{
namespace CredentialsFactory
{
AbstractCredentials* create(const QString& type);
} // ns CredentialsFactory
} // ns Mirall
#endif
-73
Ver Arquivo
@@ -1,73 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#include "creds/dummycredentials.h"
#include "mirall/mirallaccessmanager.h"
namespace Mirall
{
void DummyCredentials::syncContextPreInit(CSYNC*)
{}
void DummyCredentials::syncContextPreStart(CSYNC*)
{}
bool DummyCredentials::changed(AbstractCredentials* credentials) const
{
DummyCredentials* dummy(dynamic_cast< DummyCredentials* >(credentials));
return dummy == 0;
}
QString DummyCredentials::authType() const
{
return QString::fromLatin1("dummy");
}
QString DummyCredentials::user() const
{
return QString();
}
QNetworkAccessManager* DummyCredentials::getQNAM() const
{
return new MirallAccessManager;
}
bool DummyCredentials::ready() const
{
return true;
}
bool DummyCredentials::stillValid(QNetworkReply *reply)
{
Q_UNUSED(reply)
return true;
}
bool DummyCredentials::fetchFromUser(Account *account)
{
Q_UNUSED(account)
return false;
}
void DummyCredentials::fetch(Account*)
{
Q_EMIT(fetched());
}
void DummyCredentials::persist(Account*)
{}
} // ns Mirall
-43
Ver Arquivo
@@ -1,43 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_CREDS_DUMMY_CREDENTIALS_H
#define MIRALL_CREDS_DUMMY_CREDENTIALS_H
#include "creds/abstractcredentials.h"
namespace Mirall
{
class DummyCredentials : public AbstractCredentials
{
Q_OBJECT
public:
void syncContextPreInit(CSYNC* ctx);
void syncContextPreStart(CSYNC* ctx);
bool changed(AbstractCredentials* credentials) const;
QString authType() const;
QString user() const;
QNetworkAccessManager* getQNAM() const;
bool ready() const;
bool stillValid(QNetworkReply *reply);
bool fetchFromUser(Account *account);
void fetch(Account*);
void persist(Account*);
void invalidateToken(Account *) {}
};
} // ns Mirall
#endif
-81
Ver Arquivo
@@ -1,81 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#include "creds/http/httpconfigfile.h"
namespace Mirall
{
namespace
{
const char userC[] = "user";
const char passwdC[] = "passwd";
const char oldPasswdC[] = "password";
} // ns
QString HttpConfigFile::user() const
{
return retrieveData(QString(), QLatin1String(userC)).toString();
}
void HttpConfigFile::setUser(const QString& user)
{
storeData(QString(), QLatin1String(userC), QVariant(user));
}
QString HttpConfigFile::password() const
{
const QVariant passwd(retrieveData(QString(), QLatin1String(passwdC)));
if (passwd.isValid()) {
return QString::fromUtf8(QByteArray::fromBase64(passwd.toByteArray()));
}
return QString();
}
void HttpConfigFile::setPassword(const QString& password)
{
QByteArray pwdba = password.toUtf8();
storeData( QString(), QLatin1String(passwdC), QVariant(pwdba.toBase64()) );
removeOldPassword();
}
bool HttpConfigFile::passwordExists() const
{
return dataExists(QString(), QLatin1String(passwdC));
}
void HttpConfigFile::removePassword()
{
removeOldPassword();
removeData(QString(), QLatin1String(passwdC));
}
void HttpConfigFile::fixupOldPassword()
{
const QString old(QString::fromLatin1(oldPasswdC));
if (dataExists(QString(), old)) {
setPassword(retrieveData(QString(), old).toString());
}
}
void HttpConfigFile::removeOldPassword()
{
removeData(QString(), QLatin1String(oldPasswdC));
}
} // ns Mirall
-40
Ver Arquivo
@@ -1,40 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_CREDS_HTTP_CONFIG_FILE_H
#define MIRALL_CREDS_HTTP_CONFIG_FILE_H
#include "mirall/mirallconfigfile.h"
namespace Mirall
{
class HttpConfigFile : public MirallConfigFile
{
public:
QString user() const;
void setUser(const QString& user);
QString password() const;
void setPassword(const QString& password);
bool passwordExists() const;
void removePassword();
void fixupOldPassword();
private:
void removeOldPassword();
};
} // ns Mirall
#endif
-314
Ver Arquivo
@@ -1,314 +0,0 @@
/*
* Copyright (C) by Klaas Freitag <freitag@kde.org>
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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. See the GNU General Public License
* for more details.
*/
#include <QMutex>
#include <QDebug>
#include <QNetworkReply>
#include <QSettings>
#include <QInputDialog>
#include <qtkeychain/keychain.h>
#include "mirall/account.h"
#include "mirall/mirallaccessmanager.h"
#include "mirall/utility.h"
#include "mirall/theme.h"
#include "creds/credentialscommon.h"
#include "creds/httpcredentials.h"
using namespace QKeychain;
Q_DECLARE_METATYPE(Mirall::Account*)
namespace Mirall
{
namespace
{
int getauth(const char *prompt,
char *buf,
size_t len,
int echo,
int verify,
void *userdata)
{
int re = 0;
QMutex mutex;
// ### safe?
HttpCredentials* http_credentials = qobject_cast<HttpCredentials*>(AccountManager::instance()->account()->credentials());
if (!http_credentials) {
qDebug() << "Not a HTTP creds instance!";
return -1;
}
QString qPrompt = QString::fromLatin1( prompt ).trimmed();
QString user = http_credentials->user();
QString pwd = http_credentials->password();
if( qPrompt == QLatin1String("Enter your username:") ) {
// qDebug() << "OOO Username requested!";
QMutexLocker locker( &mutex );
qstrncpy( buf, user.toUtf8().constData(), len );
} else if( qPrompt == QLatin1String("Enter your password:") ) {
QMutexLocker locker( &mutex );
// qDebug() << "OOO Password requested!";
qstrncpy( buf, pwd.toUtf8().constData(), len );
} else {
re = handleNeonSSLProblems(prompt, buf, len, echo, verify, userdata);
}
return re;
}
const char userC[] = "user";
} // ns
class HttpCredentialsAccessManager : public MirallAccessManager {
public:
HttpCredentialsAccessManager(const HttpCredentials *cred, QObject* parent = 0)
: MirallAccessManager(parent), _cred(cred) {}
protected:
QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData) {
QByteArray credHash = QByteArray(_cred->user().toUtf8()+":"+_cred->password().toUtf8()).toBase64();
QNetworkRequest req(request);
req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash);
//qDebug() << "Request for " << req.url() << "with authorization" << QByteArray::fromBase64(credHash);
return MirallAccessManager::createRequest(op, req, outgoingData);
}
private:
const HttpCredentials *_cred;
};
HttpCredentials::HttpCredentials()
: _user(),
_password(),
_ready(false)
{}
HttpCredentials::HttpCredentials(const QString& user, const QString& password)
: _user(user),
_password(password),
_ready(true)
{
}
void HttpCredentials::syncContextPreInit (CSYNC* ctx)
{
csync_set_auth_callback (ctx, getauth);
}
void HttpCredentials::syncContextPreStart (CSYNC* ctx)
{
// TODO: This should not be a part of this method, but we don't have
// any way to get "session_key" module property from csync. Had we
// have it, then we could remove this code and keep it in
// csyncthread code (or folder code, git remembers).
QList<QNetworkCookie> cookies(AccountManager::instance()->account()->lastAuthCookies());
QString cookiesAsString;
// Stuff cookies inside csync, then we can avoid the intermediate HTTP 401 reply
// when https://github.com/owncloud/core/pull/4042 is merged.
foreach(QNetworkCookie c, cookies) {
cookiesAsString += c.name();
cookiesAsString += '=';
cookiesAsString += c.value();
cookiesAsString += "; ";
}
csync_set_module_property(ctx, "session_key", cookiesAsString.toLatin1().data());
}
bool HttpCredentials::changed(AbstractCredentials* credentials) const
{
HttpCredentials* other(dynamic_cast< HttpCredentials* >(credentials));
if (!other || other->user() != this->user()) {
return true;
}
return false;
}
QString HttpCredentials::authType() const
{
return QString::fromLatin1("http");
}
QString HttpCredentials::user() const
{
return _user;
}
QString HttpCredentials::password() const
{
return _password;
}
QNetworkAccessManager* HttpCredentials::getQNAM() const
{
MirallAccessManager* qnam = new HttpCredentialsAccessManager(this);
connect( qnam, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)),
this, SLOT(slotAuthentication(QNetworkReply*,QAuthenticator*)));
return qnam;
}
bool HttpCredentials::ready() const
{
return _ready;
}
void HttpCredentials::fetch(Account *account)
{
_user = account->credentialSetting(QLatin1String(userC)).toString();
if (_ready) {
Q_EMIT fetched();
} else {
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
job->setSettings(account->settingsWithGroup(Theme::instance()->appName()));
job->setInsecureFallback(true);
job->setKey(keychainKey(account->url().toString(), _user));
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
job->setProperty("account", QVariant::fromValue(account));
job->start();
}
}
bool HttpCredentials::stillValid(QNetworkReply *reply)
{
return ((reply->error() != QNetworkReply::AuthenticationRequiredError)
// returned if user or password is incorrect
&& (reply->error() != QNetworkReply::OperationCanceledError));
}
bool HttpCredentials::fetchFromUser(Account *account)
{
bool ok = false;
QString password = queryPassword(&ok);
if (ok) {
_password = password;
_ready = true;
persist(account);
}
return ok;
}
void HttpCredentials::slotReadJobDone(QKeychain::Job *job)
{
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(job);
delete readJob->settings();
_password = readJob->textData();
QKeychain::Error error = job->error();
switch (error) {
case NoError:
_ready = true;
Q_EMIT fetched();
break;
default:
if (!_user.isEmpty()) {
bool ok;
QString pwd = queryPassword(&ok);
if (ok) {
_password = pwd;
_ready = true;
persist(qvariant_cast<Account*>(readJob->property("account")));
Q_EMIT fetched();
break;
}
}
qDebug() << "Error while reading password" << job->errorString();
}
}
QString HttpCredentials::queryPassword(bool *ok)
{
qDebug() << AccountManager::instance()->account()->state();
if (ok) {
QString str = QInputDialog::getText(0, tr("Enter Password"),
tr("Please enter %1 password for user '%2':")
.arg(Theme::instance()->appNameGUI(), _user),
QLineEdit::Password, QString(), ok);
qDebug() << AccountManager::instance()->account()->state();
return str;
} else {
return QString();
}
}
void HttpCredentials::invalidateToken(Account *account)
{
_password = QString();
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
job->setKey(keychainKey(account->url().toString(), _user));
job->start();
_ready = false;
}
void HttpCredentials::persist(Account *account)
{
account->setCredentialSetting(QLatin1String(userC), _user);
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
job->setSettings(account->settingsWithGroup(Theme::instance()->appName()));
job->setInsecureFallback(true);
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteJobDone(QKeychain::Job*)));
job->setKey(keychainKey(account->url().toString(), _user));
job->setTextData(_password);
job->start();
}
void HttpCredentials::slotWriteJobDone(QKeychain::Job *job)
{
delete job->settings();
switch (job->error()) {
case NoError:
break;
default:
qDebug() << "Error while writing password" << job->errorString();
}
}
void HttpCredentials::slotAuthentication(QNetworkReply* reply, QAuthenticator* authenticator)
{
Q_UNUSED(authenticator)
// we cannot use QAuthenticator, because it sends username and passwords with latin1
// instead of utf8 encoding. Instead, we send it manually. Thus, if we reach this signal,
// those credentials were invalid and we terminate.
qDebug() << "Stop request: Authentication failed for " << reply->url().toString();
reply->close();
}
QString HttpCredentials::keychainKey(const QString &url, const QString &user)
{
QString u(url);
if( u.isEmpty() ) {
qDebug() << "Empty url in keyChain, error!";
return QString::null;
}
if( user.isEmpty() ) {
qDebug() << "Error: User is emty!";
return QString::null;
}
if( !u.endsWith(QChar('/')) ) {
u.append(QChar('/'));
}
QString key = user+QLatin1Char(':')+u;
return key;
}
} // ns Mirall
-70
Ver Arquivo
@@ -1,70 +0,0 @@
/*
* Copyright (C) by Klaas Freitag <freitag@kde.org>
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_CREDS_HTTP_CREDENTIALS_H
#define MIRALL_CREDS_HTTP_CREDENTIALS_H
#include <QMap>
#include "creds/abstractcredentials.h"
class QNetworkReply;
class QAuthenticator;
namespace QKeychain {
class Job;
}
namespace Mirall
{
class HttpCredentials : public AbstractCredentials
{
Q_OBJECT
public:
HttpCredentials();
HttpCredentials(const QString& user, const QString& password);
void syncContextPreInit(CSYNC* ctx);
void syncContextPreStart(CSYNC* ctx);
bool changed(AbstractCredentials* credentials) const;
QString authType() const;
QNetworkAccessManager* getQNAM() const;
bool ready() const;
void fetch(Account *account);
bool stillValid(QNetworkReply *reply);
bool fetchFromUser(Account *account);
void persist(Account *account);
QString user() const;
QString password() const;
QString queryPassword(bool *ok);
void invalidateToken(Account *account);
private Q_SLOTS:
void slotAuthentication(QNetworkReply*, QAuthenticator*);
void slotReadJobDone(QKeychain::Job*);
void slotWriteJobDone(QKeychain::Job*);
private:
static QString keychainKey(const QString &url, const QString &user);
QString _user;
QString _password;
bool _ready;
};
} // ns Mirall
#endif
@@ -1,56 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#include <QDebug>
#include <QNetworkRequest>
#include <QNetworkCookieJar>
#include "creds/shibboleth/shibbolethaccessmanager.h"
namespace Mirall
{
ShibbolethAccessManager::ShibbolethAccessManager(const QNetworkCookie& cookie, QObject* parent)
: MirallAccessManager (parent),
_cookie(cookie)
{}
QNetworkReply* ShibbolethAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
{
if (!_cookie.name().isEmpty()) {
QNetworkCookieJar* jar(cookieJar());
QUrl url(request.url());
QList<QNetworkCookie> cookies;
Q_FOREACH(const QNetworkCookie& cookie, jar->cookiesForUrl(url)) {
if (!cookie.name().startsWith("_shibsession_")) {
cookies << cookie;
}
}
cookies << _cookie;
jar->setCookiesFromUrl(cookies, url);
}
qDebug() << "Creating a request to " << request.url().toString() << " with shibboleth cookie:" << _cookie.name();
return MirallAccessManager::createRequest (op, request, outgoingData);
}
void ShibbolethAccessManager::setCookie(const QNetworkCookie& cookie)
{
qDebug() << "Got new shibboleth cookie:" << cookie.name();
_cookie = cookie;
}
} // ns Mirall
@@ -1,43 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_WIZARD_SHIBBOLETH_ACCESS_MANAGER_H
#define MIRALL_WIZARD_SHIBBOLETH_ACCESS_MANAGER_H
#include <QNetworkCookie>
#include "mirall/mirallaccessmanager.h"
namespace Mirall
{
class ShibbolethAccessManager : public MirallAccessManager
{
Q_OBJECT
public:
ShibbolethAccessManager(const QNetworkCookie& cookie, QObject* parent = 0);
public Q_SLOTS:
void setCookie(const QNetworkCookie& cookie);
protected:
QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData = 0);
private:
QNetworkCookie _cookie;
};
} // ns Mirall
#endif
-104
Ver Arquivo
@@ -1,104 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#include <QDebug>
#include <QTextStream>
#include "creds/shibboleth/shibbolethconfigfile.h"
#include "creds/shibboleth/shibbolethcookiejar.h"
namespace Mirall
{
namespace
{
const char otherCookiesC[] = "otherCookies";
} // ns
void ShibbolethConfigFile::storeCookies(const QMap<QUrl, QList<QNetworkCookie> >& cookiesForUrl)
{
if (cookiesForUrl.isEmpty()) {
removeData(QString(), QString::fromLatin1(otherCookiesC));
} else {
QByteArray data;
QTextStream stream(&data);
Q_FOREACH (const QUrl& url, cookiesForUrl.keys()) {
const QList<QNetworkCookie>& cookies(cookiesForUrl[url]);
if (cookies.isEmpty()) {
continue;
}
stream << "URL: " << url.toString().toUtf8() << "\n";
qDebug() << "URL: " << url.toString().toUtf8();
Q_FOREACH (const QNetworkCookie& cookie, cookies) {
stream << cookie.toRawForm(QNetworkCookie::NameAndValueOnly) << "\n";
qDebug() << cookie.toRawForm(QNetworkCookie::NameAndValueOnly);
}
}
stream.flush();
const QByteArray encodedCookies(data.toBase64());
qDebug() << "Raw cookies:\n" << data;
qDebug() << "Encoded cookies: " << encodedCookies;
storeData(QString(), QString::fromLatin1(otherCookiesC), QVariant(encodedCookies));
}
}
ShibbolethCookieJar* ShibbolethConfigFile::createCookieJar() const
{
ShibbolethCookieJar* jar = new ShibbolethCookieJar();
const QVariant variant(retrieveData(QString(), QString::fromLatin1(otherCookiesC)));
if (variant.isValid()) {
QByteArray data(QByteArray::fromBase64(variant.toByteArray()));
QTextStream stream (&data);
const QString urlHeader(QString::fromLatin1("URL: "));
QUrl currentUrl;
QList<QNetworkCookie> currentCookies;
qDebug() << "Got valid cookies variant: " << data;
while (!stream.atEnd()) {
const QString line(stream.readLine());
qDebug() << line;
if (line.startsWith(urlHeader)) {
if (!currentUrl.isEmpty() && !currentCookies.isEmpty()) {
jar->setCookiesFromUrl(currentCookies, currentUrl);
currentCookies.clear();
currentUrl.clear();
}
currentUrl = QUrl(line.mid(5));
} else if (!currentUrl.isEmpty()) {
const int equalPos(line.indexOf('='));
currentCookies << QNetworkCookie(line.left(equalPos).toUtf8(), line.mid(equalPos + 1).toUtf8());
}
}
if (!currentUrl.isEmpty() && !currentCookies.isEmpty()) {
jar->setCookiesFromUrl(currentCookies, currentUrl);
}
}
return jar;
}
} // ns Mirall
-38
Ver Arquivo
@@ -1,38 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_CREDS_SHIBBOLETH_CONFIG_FILE_H
#define MIRALL_CREDS_SHIBBOLETH_CONFIG_FILE_H
#include <QList>
#include <QMap>
#include <QNetworkCookie>
#include <QUrl>
#include "mirall/mirallconfigfile.h"
namespace Mirall
{
class ShibbolethCookieJar;
class ShibbolethConfigFile : public MirallConfigFile
{
public:
void storeCookies(const QMap<QUrl, QList<QNetworkCookie> >& cookies);
ShibbolethCookieJar* createCookieJar() const;
};
} // ns Mirall
#endif
-34
Ver Arquivo
@@ -1,34 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#include "creds/shibboleth/shibbolethcookiejar.h"
namespace Mirall
{
ShibbolethCookieJar::ShibbolethCookieJar (QObject* parent)
: QNetworkCookieJar (parent)
{}
bool ShibbolethCookieJar::setCookiesFromUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url)
{
if (QNetworkCookieJar::setCookiesFromUrl (cookieList, url)) {
Q_EMIT newCookiesForUrl (cookieList, url);
return true;
}
return false;
}
} // ns Mirall
-41
Ver Arquivo
@@ -1,41 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_WIZARD_SHIBBOLETH_COOKIE_JAR_H
#define MIRALL_WIZARD_SHIBBOLETH_COOKIE_JAR_H
#include <QNetworkCookieJar>
#include <QList>
class QUrl;
class QNetworkCookie;
namespace Mirall
{
class ShibbolethCookieJar : public QNetworkCookieJar
{
Q_OBJECT
public:
ShibbolethCookieJar (QObject* parent = 0);
virtual bool setCookiesFromUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url);
Q_SIGNALS:
void newCookiesForUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url);
};
} // ns Mirall
#endif
-55
Ver Arquivo
@@ -1,55 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#include <QEventLoop>
#include "mirall/account.h"
#include "creds/shibboleth/shibbolethrefresher.h"
#include "creds/shibbolethcredentials.h"
namespace Mirall
{
ShibbolethRefresher::ShibbolethRefresher(Account *account, ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent)
: QObject(parent),
_account(account),
_creds(creds),
_csync_ctx(csync_ctx)
{}
void ShibbolethRefresher::refresh()
{
QEventLoop loop;
connect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
this, SLOT(onInvalidatedAndFetched(QByteArray)));
connect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
&loop, SLOT(quit()));
QMetaObject::invokeMethod(_creds, "invalidateAndFetch",Qt::QueuedConnection,
Q_ARG(Account*, _account));
loop.exec();
disconnect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
&loop, SLOT(quit()));
}
void ShibbolethRefresher::onInvalidatedAndFetched(const QByteArray& cookies)
{
// "cookies" is const and its data() return const void*. We want just void*.
QByteArray myCookies(cookies);
disconnect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
this, SLOT(onInvalidatedAndFetched(QByteArray)));
csync_set_module_property(_csync_ctx, "session_key", myCookies.data());
}
} // ns Mirall
-49
Ver Arquivo
@@ -1,49 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_CREDS_SHIBBOLETH_REFRESHER_H
#define MIRALL_CREDS_SHIBBOLETH_REFRESHER_H
#include <QObject>
#include <csync.h>
class QByteArray;
namespace Mirall
{
class Account;
class ShibbolethCredentials;
class ShibbolethRefresher : public QObject
{
Q_OBJECT
public:
ShibbolethRefresher(Account *account, ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent = 0);
void refresh();
private Q_SLOTS:
void onInvalidatedAndFetched(const QByteArray& cookieData);
private:
Account* _account;
ShibbolethCredentials* _creds;
CSYNC* _csync_ctx;
};
} // ns Mirall
#endif
-124
Ver Arquivo
@@ -1,124 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#include <QApplication>
#include <QDebug>
#include <QNetworkCookie>
#include <QWebFrame>
#include <QWebPage>
#include <QMessageBox>
#include "creds/shibboleth/shibbolethcookiejar.h"
#include "creds/shibboleth/shibbolethwebview.h"
#include "mirall/account.h"
#include "mirall/mirallaccessmanager.h"
#include "mirall/theme.h"
namespace Mirall
{
void ShibbolethWebView::setup(Account *account, ShibbolethCookieJar* jar)
{
MirallAccessManager* nm = new MirallAccessManager(this);
// we need our own QNAM, but the we offload the SSL error handling to
// the account object, which already can do this
connect(nm, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
account, SLOT(slotHandleErrors(QNetworkReply*,QList<QSslError>)));
QWebPage* page = new QWebPage(this);
jar->setParent(this);
connect(jar, SIGNAL (newCookiesForUrl (QList<QNetworkCookie>, QUrl)),
this, SLOT (onNewCookiesForUrl (QList<QNetworkCookie>, QUrl)));
connect(page, SIGNAL(loadStarted()),
this, SLOT(slotLoadStarted()));
connect(page, SIGNAL(loadFinished(bool)),
this, SLOT(slotLoadFinished(bool)));
nm->setCookieJar(jar);
page->setNetworkAccessManager(nm);
page->mainFrame()->load(account->url());
this->setPage(page);
setWindowTitle(tr("%1 - Authenticate").arg(Theme::instance()->appNameGUI()));
}
ShibbolethWebView::ShibbolethWebView(Account* account, QWidget* parent)
: QWebView(parent)
{
setup(account, new ShibbolethCookieJar(this));
}
ShibbolethWebView::~ShibbolethWebView()
{
slotLoadFinished();
}
ShibbolethWebView::ShibbolethWebView(Account* account, ShibbolethCookieJar* jar, QWidget* parent)
: QWebView(parent)
{
setup(account, jar);
}
void ShibbolethWebView::onNewCookiesForUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url)
{
QList<QNetworkCookie> otherCookies;
QNetworkCookie shibCookie;
Q_FOREACH (const QNetworkCookie& cookie, cookieList) {
if (cookie.name().startsWith ("_shibsession_")) {
if (shibCookie.name().isEmpty()) {
shibCookie = cookie;
} else {
qWarning() << "Too many Shibboleth session cookies at once!";
}
} else {
otherCookies << cookie;
}
}
if (!otherCookies.isEmpty()) {
Q_EMIT otherCookiesReceived(otherCookies, url);
}
if (!shibCookie.name().isEmpty()) {
Q_EMIT shibbolethCookieReceived(shibCookie);
}
}
void ShibbolethWebView::hideEvent(QHideEvent* event)
{
Q_EMIT viewHidden();
QWebView::hideEvent(event);
}
void ShibbolethWebView::slotLoadStarted()
{
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
}
void ShibbolethWebView::slotLoadFinished(bool success)
{
QApplication::restoreOverrideCursor();
if (!title().isNull()) {
setWindowTitle(tr("%1 - %2").arg(Theme::instance()->appNameGUI(), title()));
}
if (!success) {
QMessageBox::critical(this, tr("Error loading IdP login page"),
tr("Could not load Shibboleth login page to log you in.\n"
"Please ensure that your network connection is working."));
}
}
} // ns Mirall
-57
Ver Arquivo
@@ -1,57 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_WIZARD_SHIBBOLETH_WEB_VIEW_H
#define MIRALL_WIZARD_SHIBBOLETH_WEB_VIEW_H
#include <QList>
#include <QWebView>
class QNetworkCookie;
class QUrl;
namespace Mirall
{
class ShibbolethCookieJar;
class Account;
class ShibbolethWebView : public QWebView
{
Q_OBJECT
public:
ShibbolethWebView(Account *account, QWidget* parent = 0);
ShibbolethWebView(Account *account, ShibbolethCookieJar* jar, QWidget* parent = 0);
~ShibbolethWebView();
protected:
void hideEvent(QHideEvent* event);
Q_SIGNALS:
void shibbolethCookieReceived(const QNetworkCookie& cookie);
void viewHidden();
void otherCookiesReceived(const QList<QNetworkCookie>& cookieList, const QUrl& url);
private Q_SLOTS:
void onNewCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
void slotLoadStarted();
void slotLoadFinished(bool success = true);
private:
void setup(Account *account, ShibbolethCookieJar* jar);
};
} // ns Mirall
#endif
-269
Ver Arquivo
@@ -1,269 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#include <QDebug>
#include <QMutex>
#include "creds/shibbolethcredentials.h"
#include "creds/shibboleth/shibbolethaccessmanager.h"
#include "creds/shibboleth/shibbolethwebview.h"
#include "creds/shibboleth/shibbolethrefresher.h"
#include "creds/shibboleth/shibbolethconfigfile.h"
#include "creds/credentialscommon.h"
#include "mirall/account.h"
namespace Mirall
{
namespace
{
int shibboleth_redirect_callback(CSYNC* csync_ctx,
const char* uri)
{
if (!csync_ctx || !uri) {
return 1;
}
const QString qurl(QString::fromLatin1(uri));
QRegExp shibbolethyWords ("SAML|wayf");
shibbolethyWords.setCaseSensitivity (Qt::CaseInsensitive);
if (!qurl.contains(shibbolethyWords)) {
return 1;
}
QMutex mutex;
QMutexLocker locker(&mutex);
Account *account = AccountManager::instance()->account();
ShibbolethCredentials* creds = qobject_cast<ShibbolethCredentials*>(account->credentials());
if (!creds) {
qDebug() << "Not a Shibboleth creds instance!";
return 1;
}
ShibbolethRefresher refresher(account, creds, csync_ctx);
// blocks
refresher.refresh();
return creds->ready() ? 0 : 1;
}
} // ns
ShibbolethCredentials::ShibbolethCredentials()
: AbstractCredentials(),
_url(),
_shibCookie(),
_ready(false),
_browser(0),
_otherCookies()
{}
ShibbolethCredentials::ShibbolethCredentials(const QNetworkCookie& cookie, const QMap<QUrl, QList<QNetworkCookie> >& otherCookies)
: _shibCookie(cookie),
_ready(true),
_browser(0),
_otherCookies(otherCookies)
{}
void ShibbolethCredentials::syncContextPreInit(CSYNC* ctx)
{
csync_set_auth_callback (ctx, handleNeonSSLProblems);
}
QByteArray ShibbolethCredentials::prepareCookieData() const
{
QString cookiesAsString;
// TODO: This should not be a part of this method, but we don't
// have any way to get "session_key" module property from
// csync. Had we have it, then we could just append shibboleth
// cookies to the "session_key" value and set it in csync module.
QList<QNetworkCookie> cookies(AccountManager::instance()->account()->lastAuthCookies());
QMap<QString, QString> uniqueCookies;
cookies << _shibCookie;
// Stuff cookies inside csync, then we can avoid the intermediate HTTP 401 reply
// when https://github.com/owncloud/core/pull/4042 is merged.
foreach(QNetworkCookie c, cookies) {
const QString cookieName(c.name());
if (cookieName.startsWith("_shibsession_")) {
continue;
}
uniqueCookies.insert(cookieName, c.value());
}
if (!_shibCookie.name().isEmpty()) {
uniqueCookies.insert(_shibCookie.name(), _shibCookie.value());
}
foreach(const QString& cookieName, uniqueCookies.keys()) {
cookiesAsString += cookieName;
cookiesAsString += '=';
cookiesAsString += uniqueCookies[cookieName];
cookiesAsString += "; ";
}
return cookiesAsString.toLatin1();
}
void ShibbolethCredentials::syncContextPreStart (CSYNC* ctx)
{
typedef int (*csync_owncloud_redirect_callback_t)(CSYNC* ctx, const char* uri);
csync_owncloud_redirect_callback_t cb = shibboleth_redirect_callback;
csync_set_module_property(ctx, "session_key", prepareCookieData().data());
csync_set_module_property(ctx, "redirect_callback", &cb);
}
bool ShibbolethCredentials::changed(AbstractCredentials* credentials) const
{
ShibbolethCredentials* other(dynamic_cast< ShibbolethCredentials* >(credentials));
if (!other || other->cookie() != this->cookie()) {
return true;
}
return false;
}
QString ShibbolethCredentials::authType() const
{
return QString::fromLatin1("shibboleth");
}
QString ShibbolethCredentials::user() const
{
// ### TODO: If we had a way to extract the currently authenticated user
// somehow, we could return its id token (email) here (stored in REMOTE_USER)
// The server doesn't return it by default
return QString();
}
QNetworkCookie ShibbolethCredentials::cookie() const
{
return _shibCookie;
}
QNetworkAccessManager* ShibbolethCredentials::getQNAM() const
{
ShibbolethAccessManager* qnam(new ShibbolethAccessManager(_shibCookie));
connect(this, SIGNAL(newCookie(QNetworkCookie)),
qnam, SLOT(setCookie(QNetworkCookie)));
return qnam;
}
bool ShibbolethCredentials::ready() const
{
return _ready;
}
void ShibbolethCredentials::fetch(Account *account)
{
if (_ready) {
Q_EMIT fetched();
} else {
ShibbolethConfigFile cfg;
if (account) {
_url = account->url();
}
_browser = new ShibbolethWebView(account, cfg.createCookieJar());
connect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie)),
this, SLOT(onShibbolethCookieReceived(QNetworkCookie)));
connect(_browser, SIGNAL(viewHidden()),
this, SLOT(slotBrowserHidden()));
_browser->show ();
}
}
bool ShibbolethCredentials::stillValid(QNetworkReply *reply)
{
Q_UNUSED(reply)
return true;
}
bool ShibbolethCredentials::fetchFromUser(Account *account)
{
Q_UNUSED(account)
return false;
}
void ShibbolethCredentials::persist(Account* /*account*/)
{
ShibbolethConfigFile cfg;
cfg.storeCookies(_otherCookies);
}
void ShibbolethCredentials::invalidateToken(Account *account)
{
Q_UNUSED(account)
_shibCookie.setValue("");
// ### access to ctx missing, but might not be required at all
//csync_set_module_property(ctx, "session_key", "");
}
void ShibbolethCredentials::disposeBrowser()
{
disconnect(_browser, SIGNAL(viewHidden()),
this, SLOT(slotBrowserHidden()));
disconnect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie)),
this, SLOT(onShibbolethCookieReceived(QNetworkCookie)));
_browser->hide();
_browser->deleteLater();
_browser = 0;
}
void ShibbolethCredentials::onShibbolethCookieReceived(const QNetworkCookie& cookie)
{
disposeBrowser();
_ready = true;
_shibCookie = cookie;
Q_EMIT newCookie(_shibCookie);
Q_EMIT fetched();
}
void ShibbolethCredentials::slotBrowserHidden()
{
disposeBrowser();
_ready = false;
_shibCookie = QNetworkCookie();
Q_EMIT fetched();
}
void ShibbolethCredentials::invalidateAndFetch(Account* account)
{
_ready = false;
connect (this, SIGNAL(fetched()),
this, SLOT(onFetched()));
// small hack to support the ShibbolethRefresher hack
// we already rand fetch() with a valid account object,
// and hence know the url on refresh
fetch(account);
}
void ShibbolethCredentials::onFetched()
{
disconnect (this, SIGNAL(fetched()),
this, SLOT(onFetched()));
Q_EMIT invalidatedAndFetched(prepareCookieData());
}
} // ns Mirall
-77
Ver Arquivo
@@ -1,77 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_CREDS_SHIBBOLETH_CREDENTIALS_H
#define MIRALL_CREDS_SHIBBOLETH_CREDENTIALS_H
#include <QList>
#include <QMap>
#include <QNetworkCookie>
#include <QUrl>
#include "creds/abstractcredentials.h"
namespace Mirall
{
class ShibbolethWebView;
class ShibbolethCredentials : public AbstractCredentials
{
Q_OBJECT
public:
ShibbolethCredentials();
ShibbolethCredentials(const QNetworkCookie& cookie, const QMap<QUrl, QList<QNetworkCookie> >& otherCookies);
void syncContextPreInit(CSYNC* ctx);
void syncContextPreStart(CSYNC* ctx);
bool changed(AbstractCredentials* credentials) const;
QString authType() const;
QString user() const;
QNetworkAccessManager* getQNAM() const;
bool ready() const;
void fetch(Account *account);
bool stillValid(QNetworkReply *reply);
virtual bool fetchFromUser(Account *account);
void persist(Account *account);
void invalidateToken(Account *account);
QNetworkCookie cookie() const;
public Q_SLOTS:
void invalidateAndFetch(Account *account);
private Q_SLOTS:
void onShibbolethCookieReceived(const QNetworkCookie& cookie);
void slotBrowserHidden();
void onFetched();
Q_SIGNALS:
void newCookie(const QNetworkCookie& cookie);
void invalidatedAndFetched(const QByteArray& cookieData);
private:
QUrl _url;
QByteArray prepareCookieData() const;
void disposeBrowser();
QNetworkCookie _shibCookie;
bool _ready;
ShibbolethWebView* _browser;
QMap<QUrl, QList<QNetworkCookie> > _otherCookies;
};
} // ns Mirall
#endif
+14 -33
Ver Arquivo
@@ -11,24 +11,11 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <signal.h>
#include "mirall/application.h"
#include "mirall/theme.h"
#include "mirall/utility.h"
#include <QMessageBox>
#include <QTimer>
void warnSystray()
{
QMessageBox::critical(0, qApp->translate("main.cpp", "System Tray not available"),
qApp->translate("main.cpp", "%1 requires on a working system tray. "
"If you are running XFCE, please follow "
"<a href=\"http://docs.xfce.org/xfce/xfce4-panel/systray\">these instructions</a>. "
"Otherwise, please install a system tray application such as 'trayer' and try again.")
.arg(Mirall::Theme::instance()->appNameGUI()));
}
int main(int argc, char **argv)
{
@@ -36,14 +23,7 @@ int main(int argc, char **argv)
Mirall::Application app(argc, argv);
app.initialize();
#ifndef Q_OS_WIN32
signal(SIGPIPE, SIG_IGN);
#endif
if( app.giveHelp() ) {
app.showHelp();
return 0;
}
// if the application is already running, notify it.
if( app.isRunning() ) {
QStringList args = app.arguments();
@@ -54,19 +34,20 @@ int main(int argc, char **argv)
}
return 0;
} else {
int attempts = 0;
forever {
if (!QSystemTrayIcon::isSystemTrayAvailable() && qgetenv("DESKTOP_SESSION") != "ubuntu") {
Mirall::Utility::sleep(1);
attempts++;
if (attempts < 30) continue;
} else {
break;
}
warnSystray();
break;
if (!QSystemTrayIcon::isSystemTrayAvailable()) {
QMessageBox::critical(0, qApp->translate("main.cpp", "System Tray not available"),
qApp->translate("main.cpp", "%1 requires on a working system tray. "
"If you are running XFCE, please follow "
"<a href=\"http://docs.xfce.org/xfce/xfce4-panel/systray\">these instructions</a>. "
"Otherwise, please install a system tray application such as 'trayer' and try again.")
.arg(Mirall::Theme::instance()->appNameGUI()));
}
}
return app.exec();
// if help requested, show on command line and exit.
if( ! app.giveHelp() ) {
return app.exec();
} else {
app.showHelp();
}
}
-326
Ver Arquivo
@@ -1,326 +0,0 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#include "mirall/account.h"
#include "mirall/theme.h"
#include "mirall/mirallconfigfile.h"
#include "creds/abstractcredentials.h"
#include "creds/credentialsfactory.h"
#include <QSettings>
#include <QMutex>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QSslSocket>
#include <QNetworkCookieJar>
#include <QDebug>
namespace Mirall {
static const char urlC[] = "url";
static const char authTypeC[] = "authType";
static const char userC[] = "user";
static const char httpUserC[] = "http_user";
AccountManager *AccountManager::_instance = 0;
AccountManager *AccountManager::instance()
{
static QMutex mutex;
if (!_instance)
{
QMutexLocker lock(&mutex);
if (!_instance) {
_instance = new AccountManager;
}
}
return _instance;
}
void AccountManager::setAccount(Account *account)
{
emit accountAboutToChange(account, _account);
std::swap(_account, account);
emit accountChanged(_account, account);
}
Account::Account(AbstractSslErrorHandler *sslErrorHandler, QObject *parent)
: QObject(parent)
, _sslErrorHandler(sslErrorHandler)
, _am(0)
, _credentials(0)
, _treatSslErrorsAsFailure(false)
, _state(Account::Disconnected)
{
}
Account::~Account()
{
}
void Account::save()
{
QScopedPointer<QSettings> settings(settingsWithGroup(Theme::instance()->appName()));
settings->setValue(QLatin1String(urlC), _url.toString());
if (_credentials) {
_credentials->persist(this);
Q_FOREACH(QString key, _settingsMap.keys()) {
settings->setValue(key, _settingsMap.value(key));
}
settings->setValue(QLatin1String(authTypeC), _credentials->authType());
// HACK: Save http_user also as user
if (_settingsMap.contains(httpUserC))
settings->setValue(userC, _settingsMap.value(httpUserC));
}
settings->sync();
// ### TODO port away from MirallConfigFile
MirallConfigFile cfg;
qDebug() << "Saving " << approvedCerts().count() << " unknown certs.";
QByteArray certs;
Q_FOREACH( const QSslCertificate& cert, approvedCerts() ) {
certs += cert.toPem() + '\n';
}
if (!certs.isEmpty()) {
cfg.setCaCerts( certs );
}
}
Account* Account::restore()
{
QScopedPointer<QSettings> settings(settingsWithGroup(Theme::instance()->appName()));
if (!settings->childKeys().isEmpty()) {
Account *acc = new Account;
MirallConfigFile cfg;
acc->setApprovedCerts(QSslCertificate::fromData(cfg.caCerts()));
acc->setUrl(settings->value(QLatin1String(urlC)).toUrl());
acc->setCredentials(CredentialsFactory::create(settings->value(QLatin1String(authTypeC)).toString()));
// We want to only restore settings for that auth type and the user value
acc->_settingsMap.insert(QLatin1String(userC), settings->value(userC));
QString authTypePrefix = settings->value(authTypeC).toString() + "_";
Q_FOREACH(QString key, settings->childKeys()) {
if (!key.startsWith(authTypePrefix))
continue;
acc->_settingsMap.insert(key, settings->value(key));
}
return acc;
}
return 0;
}
static bool isEqualExceptProtocol(const QUrl &url1, const QUrl &url2)
{
return (url1.host() != url2.host() ||
url1.port() != url2.port() ||
url1.path() != url2.path());
}
bool Account::changed(Account *other, bool ignoreUrlProtocol) const
{
if (!other) {
return false;
}
bool changes = false;
if (ignoreUrlProtocol) {
changes = isEqualExceptProtocol(_url, other->_url);
} else {
changes = (_url == other->_url);
}
if (!changes) {
changes = _credentials->changed(other->_credentials);
}
return changes;
}
AbstractCredentials *Account::credentials() const
{
return _credentials;
}
void Account::setCredentials(AbstractCredentials *cred)
{
_credentials = cred;
// set active credential manager
if (_am) {
_am->deleteLater();
}
_am = _credentials->getQNAM();
connect(_am, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
SLOT(slotHandleErrors(QNetworkReply*,QList<QSslError>)));
}
QUrl Account::davUrl() const
{
return concatUrlPath(url(), davPath());
}
QList<QNetworkCookie> Account::lastAuthCookies() const
{
return _am->cookieJar()->cookiesForUrl(_url);
}
QNetworkReply *Account::headRequest(const QString &relPath)
{
return headRequest(concatUrlPath(url(), relPath));
}
QNetworkReply *Account::headRequest(const QUrl &url)
{
QNetworkRequest request(url);
return _am->head(request);
}
QNetworkReply *Account::getRequest(const QString &relPath)
{
return getRequest(concatUrlPath(url(), relPath));
}
QNetworkReply *Account::getRequest(const QUrl &url)
{
QNetworkRequest request(url);
return _am->get(request);
}
QNetworkReply *Account::davRequest(const QByteArray &verb, const QString &relPath, QNetworkRequest req, QIODevice *data)
{
return davRequest(verb, concatUrlPath(davUrl(), relPath), req, data);
}
QNetworkReply *Account::davRequest(const QByteArray &verb, const QUrl &url, QNetworkRequest req, QIODevice *data)
{
req.setUrl(url);
return _am->sendCustomRequest(req, verb, data);
}
void Account::setCertificateChain(const QList<QSslCertificate> &certs)
{
_certificateChain = certs;
}
void Account::setApprovedCerts(const QList<QSslCertificate> certs)
{
_approvedCerts = certs;
}
void Account::addApprovedCerts(const QList<QSslCertificate> certs)
{
_approvedCerts += certs;
}
void Account::setSslErrorHandler(AbstractSslErrorHandler *handler)
{
_sslErrorHandler.reset(handler);
}
void Account::setUrl(const QUrl &url)
{
_url = url;
}
QUrl Account::concatUrlPath(const QUrl &url, const QString &concatPath)
{
QUrl tmpUrl = url;
QString path = tmpUrl.path();
// avoid '//'
if (path.endsWith('/') && concatPath.startsWith('/')) {
path.chop(1);
} // avoid missing '/'
else if (!path.endsWith('/') && !concatPath.startsWith('/')) {
path += QLatin1Char('/');
}
path += concatPath;
tmpUrl.setPath(path);
return tmpUrl;
}
QString Account::_configFileName;
QSettings *Account::settingsWithGroup(const QString& group)
{
if (_configFileName.isEmpty()) {
// cache file name
MirallConfigFile cfg;
_configFileName = cfg.configFile();
}
QSettings *settings = new QSettings(_configFileName, QSettings::IniFormat);
settings->beginGroup(group);
return settings;
}
QVariant Account::credentialSetting(const QString &key) const
{
if (_credentials) {
QString prefix = _credentials->authType();
QString value = _settingsMap.value(prefix+"_"+key).toString();
if (value.isEmpty()) {
value = _settingsMap.value(key).toString();
}
return value;
}
return QVariant();
}
void Account::setCredentialSetting(const QString &key, const QVariant &value)
{
if (_credentials) {
QString prefix = _credentials->authType();
_settingsMap.insert(prefix+"_"+key, value);
}
}
int Account::state() const
{
return _state;
}
void Account::setState(int state)
{
if (_state != state) {
_state = state;
emit stateChanged(state);
}
}
void Account::slotHandleErrors(QNetworkReply *reply , QList<QSslError> errors)
{
qDebug() << "SSL-Warnings happened for url " << reply->url().toString();
if( _treatSslErrorsAsFailure ) {
// User decided once not to trust. Honor this decision.
qDebug() << "Certs not trusted by user decision, returning.";
return;
}
QList<QSslCertificate> approvedCerts;
if (_sslErrorHandler.isNull() ) {
qDebug() << Q_FUNC_INFO << "called without valid SSL error handler for account" << url();
} else {
if (_sslErrorHandler->handleErrors(errors, &approvedCerts, this)) {
QSslSocket::addDefaultCaCertificates(approvedCerts);
addApprovedCerts(approvedCerts);
// all ssl certs are known and accepted. We can ignore the problems right away.
qDebug() << "Certs are already known and trusted, Warnings are not valid.";
reply->ignoreSslErrors();
} else {
_treatSslErrorsAsFailure = true;
return;
}
}
}
} // namespace Mirall
-164
Ver Arquivo
@@ -1,164 +0,0 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#ifndef SERVERCONNECTION_H
#define SERVERCONNECTION_H
#include <QByteArray>
#include <QUrl>
#include <QNetworkCookie>
#include <QNetworkRequest>
#include <QSslCertificate>
#include <QSslError>
class QSettings;
class QNetworkReply;
class QUrl;
class QNetworkAccessManager;
namespace Mirall {
class AbstractCredentials;
class Account;
class AccountManager : public QObject {
Q_OBJECT
public:
static AccountManager *instance();
~AccountManager() {}
void setAccount(Account *account);
Account *account() { return _account; }
Q_SIGNALS:
void accountChanged(Account *newAccount, Account *oldAccount);
void accountAboutToChange(Account *newAccount, Account *oldAccount);
private:
AccountManager() : _account(0) {}
Account *_account;
static AccountManager *_instance;
};
/* Reimplement this to handle SSL errors */
class AbstractSslErrorHandler {
public:
virtual ~AbstractSslErrorHandler() {}
virtual bool handleErrors(QList<QSslError>, QList<QSslCertificate>*, Account*) = 0;
};
/**
* @brief This class represents an account on an ownCloud Server
*/
class Account : public QObject {
Q_OBJECT
public:
enum State { Disconnected = 0, /// no network connection
Connected, /// account is online
SignedOut /// Disconnected + credential token has been discarded
};
static QString davPath() { return "remote.php/webdav/"; }
Account(AbstractSslErrorHandler *sslErrorHandler = 0, QObject *parent = 0);
~Account();
/**
* Saves the account to a given settings file
*/
void save();
/**
* Creates an account object from from a given settings file.
*/
static Account* restore();
/**
* @brief Creates a minimal account object
*
* This will set up a ssl error handler
*
* @return A new Account object
*/
static Account* create(const QUrl &url);
/**
* @brief Checks the Account instance is different from \param other
*
* @returns true, if credentials or url have changed, false otherwise
*/
bool changed(Account *other, bool ignoreUrlProtocol) const;
/** Holds the accounts credentials */
AbstractCredentials* credentials() const;
void setCredentials(AbstractCredentials *cred);
/** Server url of the account */
void setUrl(const QUrl &url);
QUrl url() const { return _url; }
/** Returns webdav entry URL, based on url() */
QUrl davUrl() const;
QList<QNetworkCookie> lastAuthCookies() const;
QNetworkReply* headRequest(const QString &relPath);
QNetworkReply* headRequest(const QUrl &url);
QNetworkReply* getRequest(const QString &relPath);
QNetworkReply* getRequest(const QUrl &url);
QNetworkReply* davRequest(const QByteArray &verb, const QString &relPath, QNetworkRequest req, QIODevice *data = 0);
QNetworkReply* davRequest(const QByteArray &verb, const QUrl &url, QNetworkRequest req, QIODevice *data = 0);
/** The certificates of the account */
QList<QSslCertificate> certificateChain() const { return _certificateChain; }
void setCertificateChain(const QList<QSslCertificate> &certs);
/** The certificates of the account */
QList<QSslCertificate> approvedCerts() const { return _approvedCerts; }
void setApprovedCerts(const QList<QSslCertificate> certs);
void addApprovedCerts(const QList<QSslCertificate> certs);
// pluggable handler
void setSslErrorHandler(AbstractSslErrorHandler *handler);
// static helper function
static QUrl concatUrlPath(const QUrl &url, const QString &concatPath);
static QSettings* settingsWithGroup(const QString &group);
// to be called by credentials only
QVariant credentialSetting(const QString& key) const;
void setCredentialSetting(const QString& key, const QVariant &value);
int state() const;
void setState(int state);
signals:
void stateChanged(int state);
protected Q_SLOTS:
void slotHandleErrors(QNetworkReply*,QList<QSslError>);
private:
QMap<QString, QVariant> _settingsMap;
QUrl _url;
QList<QSslCertificate> _approvedCerts;
QList<QSslCertificate> _certificateChain;
QScopedPointer<AbstractSslErrorHandler> _sslErrorHandler;
QNetworkAccessManager *_am;
AbstractCredentials* _credentials;
bool _treatSslErrorsAsFailure;
int _state;
static QString _configFileName;
};
}
#endif //SERVERCONNECTION_H
-810
Ver Arquivo
@@ -1,810 +0,0 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#include "accountsettings.h"
#include "ui_accountsettings.h"
#include "mirall/theme.h"
#include "mirall/folderman.h"
#include "mirall/folderwizard.h"
#include "mirall/folderstatusmodel.h"
#include "mirall/utility.h"
#include "mirall/application.h"
#include "mirall/owncloudsetupwizard.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/ignorelisteditor.h"
#include "mirall/account.h"
#include "creds/abstractcredentials.h"
#include <math.h>
#include <QDebug>
#include <QDesktopServices>
#include <QListWidgetItem>
#include <QMessageBox>
#include <QAction>
#include <QKeySequence>
#include <QIcon>
#include <QVariant>
#include "mirall/account.h"
namespace Mirall {
static const char progressBarStyleC[] =
"QProgressBar {"
"border: 1px solid grey;"
"border-radius: 5px;"
"text-align: center;"
"}"
"QProgressBar::chunk {"
"background-color: %1; width: 1px;"
"}";
AccountSettings::AccountSettings(QWidget *parent) :
QWidget(parent),
ui(new Ui::AccountSettings),
_wasDisabledBefore(false),
_account(AccountManager::instance()->account())
{
ui->setupUi(this);
_model = new FolderStatusModel;
_model->setParent(this);
FolderStatusDelegate *delegate = new FolderStatusDelegate;
delegate->setParent(this);
ui->_folderList->setItemDelegate( delegate );
ui->_folderList->setModel( _model );
ui->_folderList->setMinimumWidth( 300 );
ui->_folderList->setEditTriggers( QAbstractItemView::NoEditTriggers );
ui->_buttonRemove->setEnabled(false);
ui->_buttonEnable->setEnabled(false);
ui->_buttonAdd->setEnabled(true);
QAction *resetFolderAction = new QAction(this);
resetFolderAction->setShortcut(QKeySequence(Qt::Key_F5));
connect(resetFolderAction, SIGNAL(triggered()), SLOT(slotResetCurrentFolder()));
addAction(resetFolderAction);
QAction *syncNowAction = new QAction(this);
syncNowAction->setShortcut(QKeySequence(Qt::Key_F6));
connect(syncNowAction, SIGNAL(triggered()), SLOT(slotSyncCurrentFolderNow()));
addAction(syncNowAction);
connect(ui->_buttonRemove, SIGNAL(clicked()), this, SLOT(slotRemoveCurrentFolder()));
connect(ui->_buttonEnable, SIGNAL(clicked()), this, SLOT(slotEnableCurrentFolder()));
connect(ui->_buttonAdd, SIGNAL(clicked()), this, SLOT(slotAddFolder()));
connect(ui->modifyAccountButton, SIGNAL(clicked()), SLOT(slotOpenAccountWizard()));
connect(ui->ignoredFilesButton, SIGNAL(clicked()), SLOT(slotIgnoreFilesEditor()));;
connect(ui->_folderList, SIGNAL(clicked(QModelIndex)), SLOT(slotFolderActivated(QModelIndex)));
connect(ui->_folderList, SIGNAL(doubleClicked(QModelIndex)),SLOT(slotDoubleClicked(QModelIndex)));
QColor color = palette().highlight().color();
ui->quotaProgressBar->setStyleSheet(QString::fromLatin1(progressBarStyleC).arg(color.name()));
ui->connectLabel->setWordWrap(true);
ui->connectLabel->setOpenExternalLinks(true);
ui->quotaLabel->setWordWrap(true);
ui->connectLabel->setText(tr("No account configured."));
ui->_buttonAdd->setEnabled(false);
if (_account) {
connect(_account, SIGNAL(stateChanged(int)), SLOT(slotAccountStateChanged(int)));
slotAccountStateChanged(_account->state());
}
setFolderList(FolderMan::instance()->map());
}
void AccountSettings::slotFolderActivated( const QModelIndex& indx )
{
bool state = indx.isValid();
bool haveFolders = ui->_folderList->model()->rowCount() > 0;
ui->_buttonRemove->setEnabled(state);
if( Theme::instance()->singleSyncFolder() ) {
// only one folder synced folder allowed.
ui->_buttonAdd->setVisible(!haveFolders);
} else {
ui->_buttonAdd->setVisible(true);
ui->_buttonAdd->setEnabled( state );
}
ui->_buttonEnable->setEnabled( state );
if ( state ) {
bool folderEnabled = _model->data( indx, FolderStatusDelegate::FolderSyncEnabled).toBool();
qDebug() << "folder is sync enabled: " << folderEnabled;
if ( folderEnabled ) {
ui->_buttonEnable->setText( tr( "Pause" ) );
} else {
ui->_buttonEnable->setText( tr( "Resume" ) );
}
}
}
void AccountSettings::slotAddFolder()
{
FolderMan *folderMan = FolderMan::instance();
folderMan->setSyncEnabled(false); // do not start more syncs.
FolderWizard *folderWizard = new FolderWizard(this);
Folder::Map folderMap = folderMan->map();
folderWizard->setFolderMap( folderMap );
connect(folderWizard, SIGNAL(accepted()), SLOT(slotFolderWizardAccepted()));
connect(folderWizard, SIGNAL(rejected()), SLOT(slotFolderWizardRejected()));
folderWizard->open();
}
void AccountSettings::slotFolderWizardAccepted()
{
FolderWizard *folderWizard = qobject_cast<FolderWizard*>(sender());
FolderMan *folderMan = FolderMan::instance();
qDebug() << "* Folder wizard completed";
QString alias = folderWizard->field(QLatin1String("alias")).toString();
QString sourceFolder = folderWizard->field(QLatin1String("sourceFolder")).toString();
QString targetPath = folderWizard->property("targetPath").toString();
if (!FolderMan::ensureJournalGone( sourceFolder ))
return;
folderMan->addFolderDefinition(alias, sourceFolder, targetPath );
Folder *f = folderMan->setupFolderFromConfigFile( alias );
slotAddFolder( f );
folderMan->setSyncEnabled(true);
if( f ) {
folderMan->slotScheduleAllFolders();
emit folderChanged();
}
slotButtonsSetEnabled();
}
void AccountSettings::slotFolderWizardRejected()
{
qDebug() << "* Folder wizard cancelled";
FolderMan *folderMan = FolderMan::instance();
folderMan->setSyncEnabled(true);
folderMan->slotScheduleAllFolders();
}
void AccountSettings::slotOpenAccountWizard()
{
this->topLevelWidget()->close();
OwncloudSetupWizard::runWizard(qApp, SLOT(slotownCloudWizardDone(int)), 0);
}
void AccountSettings::slotAddFolder( Folder *folder )
{
if( ! folder || folder->alias().isEmpty() ) return;
QStandardItem *item = new QStandardItem();
folderToModelItem( item, folder );
_model->appendRow( item );
// in order to update the enabled state of the "Sync now" button
connect(folder, SIGNAL(syncStateChange()), this, SLOT(slotButtonsSetEnabled()), Qt::UniqueConnection);
}
void AccountSettings::slotButtonsSetEnabled()
{
QModelIndex selected = ui->_folderList->currentIndex();
bool isSelected = selected.isValid();
if (isSelected) {
slotFolderActivated(selected);
}
}
void AccountSettings::setGeneralErrors( const QStringList& errors )
{
_generalErrors = errors;
}
void AccountSettings::folderToModelItem( QStandardItem *item, Folder *f )
{
if( ! item || !f ) return;
item->setData( f->nativePath(), FolderStatusDelegate::FolderPathRole );
item->setData( f->remotePath(), FolderStatusDelegate::FolderSecondPathRole );
item->setData( f->alias(), FolderStatusDelegate::FolderAliasRole );
item->setData( f->syncEnabled(), FolderStatusDelegate::FolderSyncEnabled );
SyncResult res = f->syncResult();
SyncResult::Status status = res.status();
QStringList errorList = res.errorStrings();
Theme *theme = Theme::instance();
item->setData( theme->statusHeaderText( status ), Qt::ToolTipRole );
if( f->syncEnabled() ) {
if( status == SyncResult::SyncPrepare ) {
if( _wasDisabledBefore ) {
// if the folder was disabled before, set the sync icon
item->setData( theme->syncStateIcon( SyncResult::SyncRunning), FolderStatusDelegate::FolderStatusIconRole );
} // we keep the previous icon for the SyncPrepare state.
} else {
// kepp the previous icon for the prepare phase.
if( status == SyncResult::Problem) {
item->setData( theme->syncStateIcon( SyncResult::Success), FolderStatusDelegate::FolderStatusIconRole );
} else {
item->setData( theme->syncStateIcon( status ), FolderStatusDelegate::FolderStatusIconRole );
}
}
} else {
item->setData( theme->folderDisabledIcon( ), FolderStatusDelegate::FolderStatusIconRole ); // size 48 before
_wasDisabledBefore = false;
}
item->setData( theme->statusHeaderText( status ), FolderStatusDelegate::FolderStatus );
if( errorList.isEmpty() ) {
if( (status == SyncResult::Error ||
status == SyncResult::SetupError ||
status == SyncResult::SyncAbortRequested ||
status == SyncResult::Unavailable)) {
errorList << theme->statusHeaderText(status);
}
}
item->setData( errorList, FolderStatusDelegate::FolderErrorMsg);
bool ongoing = false;
item->setData( QVariant(res.warnCount()), FolderStatusDelegate::WarningCount );
if( status == SyncResult::SyncRunning ) {
ongoing = true;
}
item->setData( ongoing, FolderStatusDelegate::SyncRunning);
}
void AccountSettings::slotRemoveCurrentFolder()
{
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
if( selected.isValid() ) {
int row = selected.row();
QString alias = _model->data( selected, FolderStatusDelegate::FolderAliasRole ).toString();
qDebug() << "Remove Folder alias " << alias;
if( !alias.isEmpty() ) {
// remove from file system through folder man
// _model->removeRow( selected.row() );
int ret = QMessageBox::question( this, tr("Confirm Folder Remove"),
tr("<p>Do you really want to stop syncing the folder <i>%1</i>?</p>"
"<p><b>Note:</b> This will not remove the files from your client.</p>").arg(alias),
QMessageBox::Yes|QMessageBox::No );
if( ret == QMessageBox::No ) {
return;
}
/* Remove the selected item from the timer hash. */
QStandardItem *item = NULL;
if( selected.isValid() )
item = _model->itemFromIndex(selected);
if( selected.isValid() && item && _hideProgressTimers.contains(item) ) {
QTimer *t = _hideProgressTimers[item];
t->stop();
_hideProgressTimers.remove(item);
delete(t);
}
FolderMan *folderMan = FolderMan::instance();
folderMan->slotRemoveFolder( alias );
_model->removeRow(row);
emit folderChanged();
}
}
}
void AccountSettings::slotResetCurrentFolder()
{
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
if( selected.isValid() ) {
QString alias = _model->data( selected, FolderStatusDelegate::FolderAliasRole ).toString();
int ret = QMessageBox::question( 0, tr("Confirm Folder Reset"),
tr("<p>Do you really want to reset folder <i>%1</i> and rebuild your client database?</p>"
"<p><b>Note:</b> This function is designed for maintenance purposes only. "
"No files will be removed, but this can cause significant data traffic and "
"take several minutes or hours to complete, depending on the size of the folder. "
"Only use this option if advised by your administrator.</p>").arg(alias),
QMessageBox::Yes|QMessageBox::No );
if( ret == QMessageBox::Yes ) {
FolderMan *folderMan = FolderMan::instance();
Folder *f = folderMan->folder(alias);
f->slotTerminateSync(true);
f->wipe();
folderMan->slotScheduleAllFolders();
}
}
}
void AccountSettings::slotDoubleClicked( const QModelIndex& indx )
{
if( ! indx.isValid() ) return;
QString alias = _model->data( indx, FolderStatusDelegate::FolderAliasRole ).toString();
emit openFolderAlias( alias );
}
void AccountSettings::showConnectionLabel( const QString& message, const QString& tooltip )
{
const QString errStyle = QLatin1String("color:#ffffff; background-color:#bb4d4d;padding:5px;"
"border-width: 1px; border-style: solid; border-color: #aaaaaa;"
"border-radius:5px;");
if( _generalErrors.isEmpty() ) {
ui->connectLabel->setText( message );
ui->connectLabel->setToolTip(tooltip);
} else {
const QString msg = _generalErrors.join(QLatin1String("\n"));
ui->connectLabel->setText( msg );
ui->connectLabel->setToolTip(QString());
ui->connectLabel->setStyleSheet(errStyle);
}
}
void AccountSettings::setFolderList( const Folder::Map &folders )
{
_model->clear();
foreach(QTimer *t, _hideProgressTimers) {
t->stop();
delete t;
}
_hideProgressTimers.clear();
foreach( Folder *f, folders ) {
slotAddFolder( f );
}
QModelIndex idx = _model->index(0, 0);
if (idx.isValid()) {
ui->_folderList->setCurrentIndex(idx);
}
slotButtonsSetEnabled();
}
// move from Application
void AccountSettings::slotFolderOpenAction( const QString& alias )
{
Folder *f = FolderMan::instance()->folder(alias);
qDebug() << "opening local url " << f->path();
if( f ) {
QUrl url(f->path(), QUrl::TolerantMode);
url.setScheme( QLatin1String("file") );
#ifdef Q_OS_WIN32
// work around a bug in QDesktopServices on Win32, see i-net
QString filePath = f->path();
if (filePath.startsWith(QLatin1String("\\\\")) || filePath.startsWith(QLatin1String("//")))
url.setUrl(QDir::toNativeSeparators(filePath));
else
url = QUrl::fromLocalFile(filePath);
#endif
QDesktopServices::openUrl(url);
}
}
void AccountSettings::slotEnableCurrentFolder()
{
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
if( selected.isValid() ) {
QString alias = _model->data( selected, FolderStatusDelegate::FolderAliasRole ).toString();
bool folderEnabled = _model->data( selected, FolderStatusDelegate::FolderSyncEnabled).toBool();
qDebug() << "Toggle enabled/disabled Folder alias " << alias << " - current state: " << folderEnabled;
if( !alias.isEmpty() ) {
FolderMan *folderMan = FolderMan::instance();
qDebug() << "Application: enable folder with alias " << alias;
bool terminate = false;
// this sets the folder status to disabled but does not interrupt it.
Folder *f = folderMan->folder( alias );
if( f && folderEnabled ) {
// check if a sync is still running and if so, ask if we should terminate.
if( f->isBusy() ) { // its still running
int reply = QMessageBox::question( 0, tr("Sync Running"),
tr("The syncing operation is running.<br/>Do you want to terminate it?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes );
if ( reply == QMessageBox::Yes )
terminate = true;
else
return; // do nothing
}
}
// message box can return at any time while the thread keeps running,
// so better check again after the user has responded.
if ( f->isBusy() && terminate ) {
f->slotTerminateSync(false);
}
folderMan->slotEnableFolder( alias, !folderEnabled );
// keep state for the icon setting.
if( !folderEnabled ) _wasDisabledBefore = true;
slotUpdateFolderState (f);
// set the button text accordingly.
slotFolderActivated( selected );
}
}
}
void AccountSettings::slotSyncCurrentFolderNow()
{
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
if( !selected.isValid() )
return;
QString alias = _model->data( selected, FolderStatusDelegate::FolderAliasRole ).toString();
FolderMan *folderMan = FolderMan::instance();
Folder *f = folderMan->folder( alias );
if (!f)
return;
f->evaluateSync(QStringList());
}
void AccountSettings::slotUpdateFolderState( Folder *folder )
{
QStandardItem *item = 0;
int row = 0;
if( ! folder ) return;
item = _model->item( row );
while( item ) {
if( item->data( FolderStatusDelegate::FolderAliasRole ) == folder->alias() ) {
// its the item to update!
break;
}
item = _model->item( ++row );
}
if( item ) {
folderToModelItem( item, folder );
} else {
// the dialog is not visible.
}
}
//void AccountSettings::slotOCInfo( const QString& url, const QString& versionStr, const QString& version, const QString& )
//{
//#ifdef Q_OS_WIN32
// // work around a bug in QDesktopServices on Win32, see i-net
// QString filePath = url;
// if (filePath.startsWith("\\\\") || filePath.startsWith("//"))
// _OCUrl.setUrl(QDir::toNativeSeparators(filePath));
// else
// _OCUrl = QUrl::fromLocalFile(filePath);
//#else
// _OCUrl = QUrl::fromLocalFile(url);
//#endif
// qDebug() << "#-------# oC found on " << url;
// /* enable the open button */
// ui->connectLabel->setOpenExternalLinks(true);
// QUrl safeUrl(url);
// safeUrl.setPassword(QString()); // Remove the password from the URL to avoid showing it in the UI
// showConnectionLabel( tr("Connected to <a href=\"%1\">%2</a>.").arg(url, safeUrl.toString()),
// tr("Version: %1 (%2)").arg(versionStr).arg(version) );
// ui->_buttonAdd->setEnabled(true);
// disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(const QString&, const QString&, const QString&, const QString&)),
// this, SLOT(slotOCInfo( const QString&, const QString&, const QString&, const QString& )));
// disconnect(ownCloudInfo::instance(), SIGNAL(noOwncloudFound(QNetworkReply*)),
// this, SLOT(slotOCInfoFail(QNetworkReply*)));
//}
//void AccountSettings::slotOCInfoFail( QNetworkReply *reply)
//{
// QString errStr = tr("unknown problem.");
// if( reply ) errStr = reply->errorString();
// showConnectionLabel( tr("<p>Failed to connect to %1: <tt>%2</tt></p>").arg(Theme::instance()->appNameGUI()).arg(errStr) );
// ui->_buttonAdd->setEnabled( false);
//}
void AccountSettings::slotOpenOC()
{
if( _OCUrl.isValid() )
QDesktopServices::openUrl( _OCUrl );
}
QStandardItem* AccountSettings::itemForFolder(const QString& folder)
{
QStandardItem *item = NULL;
if( folder.isEmpty() ) {
return item;
}
int row = 0;
item = _model->item( row );
while( item ) {
if( item->data( FolderStatusDelegate::FolderAliasRole ) == folder ) {
// its the item to update!
break;
}
item = _model->item( ++row );
}
return item;
}
QString AccountSettings::shortenFilename( const QString& folder, const QString& file ) const
{
// strip off the server prefix from the file name
QString shortFile(file);
if( shortFile.isEmpty() ) {
return QString::null;
}
if(shortFile.startsWith(QLatin1String("ownclouds://")) ||
shortFile.startsWith(QLatin1String("owncloud://")) ) {
// rip off the whole ownCloud URL.
Folder *f = FolderMan::instance()->folder(folder);
if( f ) {
QString remotePathUrl = f->remoteUrl().toString();
shortFile.remove(Utility::toCSyncScheme(remotePathUrl));
}
}
return shortFile;
}
void AccountSettings::slotProgressProblem(const QString& folder, const Progress::SyncProblem& problem)
{
Q_UNUSED(problem);
QStandardItem *item = itemForFolder( folder );
if( !item ) return;
int warnCount = qvariant_cast<int>( item->data(FolderStatusDelegate::WarningCount) );
warnCount++;
item->setData( QVariant(warnCount), FolderStatusDelegate::WarningCount );
}
void AccountSettings::slotSetProgress(const QString& folder, const Progress::Info &progress )
{
// qDebug() << "================================> Progress for folder " << folder << " progress " << Progress::asResultString(progress.kind);
QStandardItem *item = itemForFolder( folder );
qint64 prog1 = progress.current_file_bytes;
qint64 prog2 = progress.file_size;
if( item == NULL ) {
return;
}
// Hotfix for a crash that I experienced in a very rare case/setup
if (progress.kind == Mirall::Progress::Invalid) {
qDebug() << "================================> INVALID Progress for folder " << folder;
return;
}
if( (progress.kind == Progress::StartSync)
&& progress.overall_file_count == 0 ) {
// do not show progress if nothing is transmitted.
return;
}
QString itemFileName = shortenFilename(folder, progress.current_file);
QString syncFileProgressString;
// stay with the previous kind-string for Context.
if( progress.kind != Progress::Context ) {
_kindContext = Progress::asActionString(progress.kind);
} else {
if( _kindContext.isEmpty() ) {
// empty kind context means that the dialog was opened after the action
// was started.
Progress::Kind kind = ProgressDispatcher::instance()->currentFolderContext(progress.folder);
if( kind != Progress::Invalid ) {
_kindContext = Progress::asActionString(kind);
}
}
}
QString kindString = _kindContext;
switch( progress.kind ) {
case Progress::StartSync:
item->setData( QVariant(0), FolderStatusDelegate::WarningCount );
break;
case Progress::StartDownload:
case Progress::StartUpload:
case Progress::StartDelete:
case Progress::StartRename:
syncFileProgressString = tr("Start");
if( _hideProgressTimers.contains(item) ) {
// The timer is still running.
QTimer *t = _hideProgressTimers.take(item);
t->stop();
t->deleteLater();
}
break;
case Progress::Context:
syncFileProgressString = tr("Currently");
break;
case Progress::EndDownload:
case Progress::EndUpload:
case Progress::EndDelete:
case Progress::EndRename:
break;
case Progress::EndSync:
syncFileProgressString = tr("Completely");
// start a timer to stop the progress display
QTimer *timer;
if( _hideProgressTimers.contains(item) ) {
timer = _hideProgressTimers[item];
// there is already one timer running.
} else {
timer = new QTimer;
connect(timer, SIGNAL(timeout()), this, SLOT(slotHideProgress()));
timer->setSingleShot(true);
_hideProgressTimers.insert(item, timer);
}
timer->start(5000);
break;
case Progress::Invalid:
case Progress::Download:
case Progress::Upload:
case Progress::Inactive:
case Progress::SoftError:
case Progress::NormalError:
case Progress::FatalError:
break;
}
QString fileProgressString;
QString s1 = Utility::octetsToString( prog1 );
QString s2 = Utility::octetsToString( prog2 );
// switch on extra space.
item->setData( QVariant(true), FolderStatusDelegate::AddProgressSpace );
if( progress.kind != Progress::EndSync ) {
// Example text: "Currently uploading foobar.png (1MB of 2MB)"
fileProgressString = tr("%1 %2 %3 (%4 of %5)").arg(syncFileProgressString).arg(kindString).
arg(itemFileName).arg(s1).arg(s2);
} else {
fileProgressString = tr("Completely finished.");
}
item->setData( fileProgressString,FolderStatusDelegate::SyncProgressItemString);
// overall progress
s1 = Utility::octetsToString( progress.overall_current_bytes );
s2 = Utility::octetsToString( progress.overall_transmission_size );
QString overallSyncString = tr("%1 of %2, file %3 of %4").arg(s1).arg(s2)
.arg(progress.current_file_no).arg(progress.overall_file_count);
item->setData( overallSyncString, FolderStatusDelegate::SyncProgressOverallString );
int overallPercent = 0;
if( progress.overall_transmission_size > 0 ) {
overallPercent = qRound(double(progress.overall_current_bytes)/double(progress.overall_transmission_size) * 100.0);
}
item->setData( overallPercent, FolderStatusDelegate::SyncProgressOverallPercent);
}
void AccountSettings::slotHideProgress()
{
QTimer *send_timer = qobject_cast<QTimer*>(this->sender());
QHash<QStandardItem*, QTimer*>::const_iterator i = _hideProgressTimers.constBegin();
while (i != _hideProgressTimers.constEnd()) {
if( i.value() == send_timer ) {
QStandardItem *item = i.key();
/* Check if this item is still existing */
bool ok = false;
for( int r = 0; !ok && r < _model->rowCount(); r++) {
if( item == _model->item(r,0) ) {
ok = true;
}
}
if( ok ) {
item->setData( QVariant(false), FolderStatusDelegate::AddProgressSpace );
item->setData( QVariant(QString::null), FolderStatusDelegate::SyncProgressOverallString );
item->setData( QVariant(QString::null), FolderStatusDelegate::SyncProgressItemString );
item->setData( 0, FolderStatusDelegate::SyncProgressOverallPercent );
}
_hideProgressTimers.remove(item);
break;
}
++i;
}
send_timer->deleteLater();
}
void AccountSettings::slotUpdateQuota(qint64 total, qint64 used)
{
if( total > 0 ) {
ui->quotaProgressBar->setVisible(true);
ui->quotaInfoLabel->setVisible(true);
ui->quotaProgressBar->setEnabled(true);
// workaround the label only accepting ints (which may be only 32 bit wide)
ui->quotaProgressBar->setMaximum(100);
int qVal = qRound(used/(double)total * 100);
if( qVal > 100 ) qVal = 100;
ui->quotaProgressBar->setValue(qVal);
QString usedStr = Utility::octetsToString(used);
QString totalStr = Utility::octetsToString(total);
double percent = used/(double)total*100;
QString percentStr = Utility::compactFormatDouble(percent, 1);
ui->quotaLabel->setText(tr("%1 of %2 (%3%) in use.").arg(usedStr, totalStr, percentStr));
} else {
ui->quotaProgressBar->setVisible(false);
ui->quotaInfoLabel->setVisible(false);
ui->quotaLabel->setText(tr("Currently there is no storage usage information available."));
}
}
void AccountSettings::slotIgnoreFilesEditor()
{
if (_ignoreEditor.isNull()) {
_ignoreEditor = new IgnoreListEditor(this);
_ignoreEditor->setAttribute( Qt::WA_DeleteOnClose, true );
_ignoreEditor->open();
} else {
Utility::raiseDialog(_ignoreEditor);
}
}
void AccountSettings::slotAccountStateChanged(int state)
{
if (_account) {
QUrl safeUrl(_account->url());
safeUrl.setPassword(QString()); // Remove the password from the URL to avoid showing it in the UI
ui->_buttonAdd->setEnabled(state == Account::Connected);
if (state == Account::Connected) {
QString user;
if (AbstractCredentials *cred = _account->credentials()) {
user = cred->user();
}
if (user.isEmpty()) {
showConnectionLabel( tr("Connected to <a href=\"%1\">%2</a>.").arg(_account->url().toString(), safeUrl.toString())
/*, tr("Version: %1 (%2)").arg(versionStr).arg(version) */ );
} else {
showConnectionLabel( tr("Connected to <a href=\"%1\">%2</a> as <i>%3</i>.").arg(_account->url().toString(), safeUrl.toString(), user)
/*, tr("Version: %1 (%2)").arg(versionStr).arg(version) */ );
}
} else {
showConnectionLabel( tr("No connection to %1 at <a href=\"%1\">%2</a>.")
.arg(Theme::instance()->appNameGUI(),
_account->url().toString(),
safeUrl.toString()) );
}
} else {
// ownCloud is not yet configured.
showConnectionLabel( tr("No %1 connection configured.").arg(Theme::instance()->appNameGUI()) );
ui->_buttonAdd->setEnabled( false);
}
}
AccountSettings::~AccountSettings()
{
delete ui;
}
} // namespace Mirall
-106
Ver Arquivo
@@ -1,106 +0,0 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#ifndef ACCOUNTSETTINGS_H
#define ACCOUNTSETTINGS_H
#include <QWidget>
#include <QUrl>
#include <QPointer>
#include <QHash>
#include <QTimer>
#include <QStandardItem>
#include "mirall/folder.h"
#include "mirall/progressdispatcher.h"
class QStandardItemModel;
class QModelIndex;
class QStandardItem;
class QNetworkReply;
class QListWidgetItem;
namespace Mirall {
namespace Ui {
class AccountSettings;
}
class FolderMan;
class IgnoreListEditor;
class Account;
class AccountSettings : public QWidget
{
Q_OBJECT
public:
explicit AccountSettings(QWidget *parent = 0);
~AccountSettings();
void setFolderList( const Folder::Map& );
signals:
void folderChanged();
void openProtocol();
void openFolderAlias( const QString& );
void infoFolderAlias( const QString& );
public slots:
void slotFolderActivated( const QModelIndex& );
void slotOpenOC();
void slotUpdateFolderState( Folder* );
void slotDoubleClicked( const QModelIndex& );
void slotFolderOpenAction( const QString& );
void slotSetProgress(const QString&, const Progress::Info& progress);
void slotProgressProblem(const QString& folder, const Progress::SyncProblem& problem);
void slotButtonsSetEnabled();
void slotUpdateQuota( qint64,qint64 );
void slotIgnoreFilesEditor();
void slotAccountStateChanged(int state);
void setGeneralErrors( const QStringList& errors );
protected slots:
void slotAddFolder();
void slotAddFolder( Folder* );
void slotEnableCurrentFolder();
void slotSyncCurrentFolderNow();
void slotRemoveCurrentFolder();
void slotResetCurrentFolder();
void slotFolderWizardAccepted();
void slotFolderWizardRejected();
void slotOpenAccountWizard();
void slotHideProgress();
private:
QString shortenFilename( const QString& folder, const QString& file ) const;
void folderToModelItem( QStandardItem *, Folder * );
QStandardItem* itemForFolder(const QString& );
void showConnectionLabel( const QString& message, const QString& tooltip = QString() );
Ui::AccountSettings *ui;
QPointer<IgnoreListEditor> _ignoreEditor;
QStandardItemModel *_model;
QUrl _OCUrl;
QHash<QStandardItem*, QTimer*> _hideProgressTimers;
QString _kindContext;
QStringList _generalErrors;
bool _wasDisabledBefore;
Account *_account;
};
} // namespace Mirall
#endif // ACCOUNTSETTINGS_H
-146
Ver Arquivo
@@ -1,146 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Mirall::AccountSettings</class>
<widget class="QWidget" name="Mirall::AccountSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>607</width>
<height>382</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="1">
<widget class="QGroupBox" name="maintenanceGroupBox">
<property name="title">
<string>Account Maintenance</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QPushButton" name="ignoredFilesButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Edit Ignored Files</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="modifyAccountButton">
<property name="text">
<string>Modify Account</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="syncStatusGroupBox">
<property name="title">
<string>Account to Synchronize</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="connectLabel">
<property name="text">
<string>Connected with &lt;server&gt; as &lt;user&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QListView" name="_folderList"/>
</item>
<item row="1" column="1">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPushButton" name="_buttonAdd">
<property name="text">
<string>Add Folder...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="_buttonEnable">
<property name="text">
<string>Pause</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="_buttonRemove">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="storageGroupBox">
<property name="title">
<string>Storage Usage</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QProgressBar" name="quotaProgressBar">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximum">
<number>0</number>
</property>
<property name="value">
<number>-1</number>
</property>
<property name="textVisible">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="quotaLabel">
<property name="text">
<string>Retrieving usage information...</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="quotaInfoLabel">
<property name="text">
<string>&lt;b&gt;Note:&lt;/b&gt; Some folders, including network mounted or shared folders, might have different limits.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+84 -42
Ver Arquivo
@@ -16,25 +16,35 @@
#define APPLICATION_H
#include <QApplication>
#include <QNetworkReply>
#include <QSslError>
#include <QPointer>
#include <QQueue>
#include "qtsingleapplication.h"
#include "mirall/syncresult.h"
#include "mirall/folder.h"
#include "mirall/logbrowser.h"
#include "mirall/owncloudgui.h"
#include "mirall/connectionvalidator.h"
#include "mirall/progressdispatcher.h"
#include "mirall/folderman.h"
#include "mirall/fileitemdialog.h"
#include "mirall/systray.h"
class QMessageBox;
class QAction;
class QMenu;
class QSystemTrayIcon;
class QNetworkConfigurationManager;
class QSignalMapper;
class QNetworkReply;
namespace Mirall {
class Theme;
class Folder;
class FolderWatcher;
class FolderWizard;
class StatusDialog;
class OwncloudSetupWizard;
class ownCloudInfo;
class SslErrorDialog;
class SocketApi;
class ProxyDialog;
class Application : public SharedTools::QtSingleApplication
{
@@ -46,63 +56,95 @@ public:
bool giveHelp();
void showHelp();
public slots:
// TODO: this should not be public
void slotownCloudWizardDone(int);
signals:
protected slots:
void slotAddFolder();
void slotOpenStatus();
void slotRemoveFolder( const QString& );
void slotResetFolder( const QString& );
void slotEnableFolder( const QString&, const bool );
void slotInfoFolder( const QString& );
void slotConfigure();
void slotConfigureProxy();
void slotParseOptions( const QString& );
void slotShowTrayMessage(const QString&, const QString&);
void slotSyncStateChange( const QString& );
void slotownCloudWizardDone(int);
protected:
void parseOptions(const QStringList& );
void setupTranslations();
void setupLogging();
void setupActions();
void setupSystemTray();
void setupContextMenu();
void setupLogBrowser();
void enterNextLogFile();
bool checkConfigExists(bool openSettings);
//folders have to be disabled while making config changes
void computeOverallSyncStatus();
// reimplemented
#if defined(Q_WS_WIN)
bool winEventFilter( MSG * message, long * result );
#endif
signals:
void folderRemoved();
void folderStateChanged(Folder*);
protected slots:
void slotParseOptions( const QString& );
void slotCheckConnection();
void slotConnectionValidatorResult(ConnectionValidator::Status);
void slotTrayClicked( QSystemTrayIcon::ActivationReason );
void slotFolderOpenAction(const QString & );
void slotOpenOwnCloud();
void slotStartFolderSetup(int result = QDialog::Accepted); // defaulting to Accepted
void slotOwnCloudFound( const QString&, const QString&, const QString&, const QString& );
void slotNoOwnCloudFound( QNetworkReply* );
void slotCheckAuthentication();
void slotAuthCheck( const QString& ,QNetworkReply* );
void slotOpenLogBrowser();
void slotAbout();
void slotSSLFailed( QNetworkReply *reply, QList<QSslError> errors );
void slotFetchCredentials();
void slotCredentialsFetched( bool );
void slotStartUpdateDetector();
void slotSetupProxy();
void slotUseMonoIconsChanged( bool );
void slotCredentialsFetched();
void slotLogin();
void slotLogout();
void slotCleanup();
void slotAccountChanged(Account *newAccount, Account *oldAccount);
private:
void setHelp();
void runValidator();
void raiseDialog( QWidget* );
QPointer<ownCloudGui> _gui;
QPointer<SocketApi> _socketApi;
// configuration file -> folder
Systray *_tray;
QAction *_actionQuit;
QAction *_actionAddFolder;
QAction *_actionOpenStatus;
QAction *_actionConfigure;
QAction *_actionOpenoC;
QAction *_actionConfigureProxy;
QAction *_actionAbout;
ConnectionValidator *_conValidator;
#if QT_VERSION >= 0x040700
QNetworkConfigurationManager *_networkMgr;
#endif
QPointer<FolderWizard> _folderWizard;
QScopedPointer<OwncloudSetupWizard> _owncloudSetupWizard;
SslErrorDialog *_sslErrorDialog;
// tray's menu
QMenu *_contextMenu;
StatusDialog *_statusDialog;
FileItemDialog *_fileItemDialog;
FolderMan *_folderMan;
Theme *_theme;
bool _helpOnly;
bool _startupNetworkError;
// options from command line:
bool _showLogWindow;
QSignalMapper *_folderOpenActionMapper;
LogBrowser *_logBrowser;
QPointer<ProxyDialog> _proxyDialog;
QString _logFile;
QString _logDir;
int _logExpire;
bool _logFlush;
bool _userTriggeredConnect;
QPointer<QMessageBox> _connectionMsgBox;
friend class ownCloudGui; // for _startupNetworkError
QString _logDirectory;
int _logExpire;
bool _showLogWindow;
bool _logFlush;
bool _helpOnly;
};
} // namespace Mirall
+125 -103
Ver Arquivo
@@ -12,21 +12,25 @@
*/
#include <QtCore>
#include <QNetworkReply>
#include "mirall/connectionvalidator.h"
#include "mirall/owncloudinfo.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/theme.h"
#include "mirall/account.h"
#include "mirall/networkjobs.h"
#include "mirall/credentialstore.h"
namespace Mirall {
ConnectionValidator::ConnectionValidator(Account *account, QObject *parent)
: QObject(parent),
_account(account),
_networkError(QNetworkReply::NoError)
ConnectionValidator::ConnectionValidator(QObject *parent) :
QObject(parent)
{
}
ConnectionValidator::ConnectionValidator(const QString& connection, QObject *parent)
:_connection(connection)
{
ownCloudInfo::instance()->setCustomConfigHandle(_connection);
}
QStringList ConnectionValidator::errors() const
@@ -34,138 +38,156 @@ QStringList ConnectionValidator::errors() const
return _errors;
}
bool ConnectionValidator::networkError() const
QString ConnectionValidator::statusString( Status )
{
return _networkError;
}
QString ConnectionValidator::statusString( Status stat ) const
{
QString re;
switch( stat ) {
case Undefined:
re = QLatin1String("Undefined");
break;
case Connected:
re = QLatin1String("Connected");
break;
case NotConfigured:
re = QLatin1String("NotConfigured");
break;
case ServerVersionMismatch:
re = QLatin1String("Server Version Mismatch");
break;
case CredentialsTooManyAttempts:
re = QLatin1String("Credentials Too Many Attempts");
break;
case CredentialError:
re = QLatin1String("CredentialError");
break;
case CredentialsUserCanceled:
re = QLatin1String("Credential User Canceled");
break;
case CredentialsWrong:
re = QLatin1String("Credentials Wrong");
break;
case StatusNotFound:
re = QLatin1String("Status not found");
break;
default:
re = QLatin1String("status undeclared.");
}
return re;
return QLatin1String("Get your street creds!");
}
void ConnectionValidator::checkConnection()
{
if( _account ) {
CheckServerJob *checkJob = new CheckServerJob(_account, false, this);
checkJob->setIgnoreCredentialFailure(true);
connect(checkJob, SIGNAL(instanceFound(QUrl,QVariantMap)), SLOT(slotStatusFound(QUrl,QVariantMap)));
connect(checkJob, SIGNAL(networkError(QNetworkReply*)), SLOT(slotNoStatusFound(QNetworkReply*)));
checkJob->start();
if( ownCloudInfo::instance()->isConfigured() ) {
connect( ownCloudInfo::instance(),SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
SLOT(slotStatusFound(QString,QString,QString,QString)));
connect( ownCloudInfo::instance(),SIGNAL(noOwncloudFound(QNetworkReply*)),
SLOT(slotNoStatusFound(QNetworkReply*)));
// checks for status.php
ownCloudInfo::instance()->checkInstallation();
} else {
_errors << tr("No ownCloud account configured");
emit connectionResult( NotConfigured );
}
}
void ConnectionValidator::slotStatusFound(const QUrl&url, const QVariantMap &info)
void ConnectionValidator::slotStatusFound( const QString& url, const QString& versionStr, const QString& version, const QString& edition)
{
// status.php was found.
qDebug() << "** Application: ownCloud found: "
<< url << " with version "
<< CheckServerJob::versionString(info)
<< "(" << CheckServerJob::version(info) << ")";
qDebug() << "** Application: ownCloud found: " << url << " with version " << versionStr << "(" << version << ")";
// now check the authentication
MirallConfigFile cfgFile(_connection);
if( CheckServerJob::version(info).startsWith("4.0") ) {
_errors.append( tr("The configured server for this client is too old") );
_errors.append( tr("Please update to the latest server and restart the client.") );
cfgFile.setOwnCloudVersion( version );
// disconnect from ownCloudInfo
disconnect( ownCloudInfo::instance(),SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
this, SLOT(slotStatusFound(QString,QString,QString,QString)));
disconnect( ownCloudInfo::instance(),SIGNAL(noOwncloudFound(QNetworkReply*)),
this, SLOT(slotNoStatusFound(QNetworkReply*)));
if( version.startsWith("4.0") ) {
_errors.append( tr("<p>The configured server for this client is too old.</p>"
"<p>Please update to the latest server and restart the client.</p>"));
emit connectionResult( ServerVersionMismatch );
return;
}
QTimer::singleShot( 0, this, SLOT( slotCheckAuthentication() ));
QTimer::singleShot( 0, this, SLOT( slotFetchCredentials() ));
}
// status.php could not be loaded.
void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply)
{
_account->setState(Account::Disconnected);
// disconnect from ownCloudInfo
disconnect( ownCloudInfo::instance(),SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
this, SLOT(slotStatusFound(QString,QString,QString,QString)));
disconnect( ownCloudInfo::instance(),SIGNAL(noOwncloudFound(QNetworkReply*)),
this, SLOT(slotNoStatusFound(QNetworkReply*)));
// ### TODO
_errors.append(tr("Unable to connect to %1").arg(_account->url().toString()));
_errors.append( reply->errorString() );
_networkError = (reply->error() != QNetworkReply::NoError);
emit connectionResult( StatusNotFound );
}
void ConnectionValidator::slotCheckAuthentication()
void ConnectionValidator::slotFetchCredentials()
{
// simply GET the webdav root, will fail if credentials are wrong.
// continue in slotAuthCheck here :-)
PropfindJob *job = new PropfindJob(_account, "/", this);
job->setIgnoreCredentialFailure(true);
job->setProperties(QList<QByteArray>() << "getlastmodified");
connect(job, SIGNAL(result(QVariantMap)), SLOT(slotAuthSuccess()));
connect(job, SIGNAL(networkError(QNetworkReply*)), SLOT(slotAuthFailed(QNetworkReply*)));
job->start();
qDebug() << "# checking for authentication settings.";
}
void ConnectionValidator::slotAuthFailed(QNetworkReply *reply)
{
Status stat = StatusNotFound;
if( reply->error() == QNetworkReply::AuthenticationRequiredError ||
reply->error() == QNetworkReply::OperationCanceledError ) { // returned if the user/pwd is wrong.
qDebug() << reply->error() << reply->errorString();
qDebug() << "******** Password is wrong!";
_errors << tr("The provided credentials are not correct");
stat = CredentialsWrong;
switch (_account->state()) {
case Account::SignedOut:
_account->setState(Account::SignedOut);
break;
default:
_account->setState(Account::Disconnected);
if( _connection.isEmpty() ) {
if( CredentialStore::instance()->canTryAgain() ) {
connect( CredentialStore::instance(), SIGNAL(fetchCredentialsFinished(bool)),
this, SLOT(slotCredentialsFetched(bool)) );
CredentialStore::instance()->fetchCredentials();
}
} else if( reply->error() != QNetworkReply::NoError ) {
_errors << reply->errorString();
if( CredentialStore::instance()->state() == CredentialStore::TooManyAttempts ) {
_errors << tr("Too many attempts to get a valid password.");
emit connectionResult( CredentialsTooManyAttempts );
}
} else {
// Pull credentials from Mirall config.
slotCredentialsFetched( true );
}
}
void ConnectionValidator::slotCredentialsFetched( bool ok )
{
qDebug() << "Credentials successfully fetched: " << ok;
disconnect( CredentialStore::instance(), SIGNAL(fetchCredentialsFinished(bool)) );
if( ! ok ) {
Status stat;
_errors << tr("Error: Could not retrieve the password!");
if( CredentialStore::instance()->state() == CredentialStore::UserCanceled ) {
_errors << tr("Password dialog was canceled!");
stat = CredentialsUserCanceled;
} else {
_errors << CredentialStore::instance()->errorMessage();
stat = CredentialError;
}
qDebug() << "Could not fetch credentials" << _errors;
emit connectionResult( stat );
} else {
QString user, pwd;
if( _connection.isEmpty() ) {
user = CredentialStore::instance()->user();
pwd = CredentialStore::instance()->password();
} else {
// in case of reconfiguration, the _connection is set.
MirallConfigFile cfg(_connection);
user = cfg.ownCloudUser();
pwd = cfg.ownCloudPasswd();
}
ownCloudInfo::instance()->setCredentials( user, pwd );
// Credential fetched ok.
QTimer::singleShot( 0, this, SLOT( slotCheckAuthentication() ));
}
}
void ConnectionValidator::slotCheckAuthentication()
{
connect( ownCloudInfo::instance(), SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
this, SLOT(slotAuthCheck(QString,QNetworkReply*)));
qDebug() << "# checking for authentication settings.";
ownCloudInfo::instance()->getRequest(QLatin1String("/"), true ); // this call needs to be authenticated.
// simply GET the webdav root, will fail if credentials are wrong.
// continue in slotAuthCheck here :-)
}
void ConnectionValidator::slotAuthCheck( const QString& ,QNetworkReply *reply )
{
bool ok = true;
Status stat = Connected;
if( reply->error() == QNetworkReply::AuthenticationRequiredError ||
reply->error() == QNetworkReply::OperationCanceledError ) { // returned if the user is wrong.
qDebug() << "******** Password is wrong!";
_errors << "The provided credentials are wrong.";
stat = CredentialsWrong;
ok = false;
}
// disconnect from ownCloud Info signals
disconnect( ownCloudInfo::instance(),SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
this,SLOT(slotAuthCheck(QString,QNetworkReply*)));
emit connectionResult( stat );
}
void ConnectionValidator::slotAuthSuccess()
{
_account->setState(Account::Connected);
emit connectionResult(Connected);
}
} // namespace Mirall
}
+13 -15
Ver Arquivo
@@ -16,18 +16,17 @@
#include <QObject>
#include <QStringList>
#include <QVariantMap>
#include <QNetworkReply>
class QNetworkReply;
namespace Mirall {
class Account;
class ConnectionValidator : public QObject
{
Q_OBJECT
public:
explicit ConnectionValidator(Account *account, QObject *parent = 0);
explicit ConnectionValidator(QObject *parent = 0);
explicit ConnectionValidator(const QString& connection, QObject *parent = 0);
enum Status {
Undefined,
@@ -43,31 +42,30 @@ public:
};
QStringList errors() const;
bool networkError() const;
void checkConnection();
QString statusString( Status ) const;
QString statusString( Status );
signals:
void connectionResult( ConnectionValidator::Status );
// void connectionAvailable();
// void connectionFailed();
void connectionAvailable();
void connectionFailed();
public slots:
protected slots:
void slotStatusFound(const QUrl&url, const QVariantMap &info);
void slotNoStatusFound(QNetworkReply *reply);
void slotStatusFound( const QString&, const QString&, const QString&, const QString& );
void slotNoStatusFound(QNetworkReply *);
void slotFetchCredentials();
void slotCredentialsFetched( bool );
void slotCheckAuthentication();
void slotAuthFailed(QNetworkReply *reply);
void slotAuthSuccess();
void slotAuthCheck( const QString& ,QNetworkReply * );
private:
QStringList _errors;
Account *_account;
bool _networkError;
QString _connection;
};
}
+397
Ver Arquivo
@@ -0,0 +1,397 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#include <QtGui>
#include <QInputDialog>
#include "config.h"
#include "mirall/credentialstore.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/theme.h"
#ifdef WITH_QTKEYCHAIN
#include <qtkeychain/keychain.h>
using namespace QKeychain;
#endif
#define MAX_LOGIN_ATTEMPTS 3
namespace Mirall {
CredentialStore *CredentialStore::_instance=0;
CredentialStore::CredState CredentialStore::_state = NotFetched;
QString CredentialStore::_passwd = QString::null;
QString CredentialStore::_user = QString::null;
QString CredentialStore::_url = QString::null;
QString CredentialStore::_errorMsg = QString::null;
int CredentialStore::_tries = 0;
#ifdef WITH_QTKEYCHAIN
CredentialStore::CredentialType CredentialStore::_type = KeyChain;
#else
CredentialStore::CredentialType CredentialStore::_type = Settings;
#endif
CredentialStore::CredentialStore(QObject *parent) :
QObject(parent)
{
}
CredentialStore *CredentialStore::instance()
{
if( !CredentialStore::_instance ) CredentialStore::_instance = new CredentialStore;
return CredentialStore::_instance;
}
QString CredentialStore::password() const
{
return _passwd;
}
QString CredentialStore::user() const
{
return _user;
}
CredentialStore::CredState CredentialStore::state()
{
return _state;
}
bool CredentialStore::canTryAgain()
{
if( _tries > MAX_LOGIN_ATTEMPTS ) {
qDebug() << "canTryAgain: Max attempts reached.";
return false;
}
/* Since QtKeyChain is required now, it makes sense to only query once. */
if( _state == NotFetched || _state == AsyncWriting ) {
return true;
} else {
return false;
}
}
void CredentialStore::fetchCredentials()
{
MirallConfigFile cfgFile;
if( ++_tries > MAX_LOGIN_ATTEMPTS ) {
qDebug() << "Too many attempts to enter password!";
_state = TooManyAttempts;
emit( fetchCredentialsFinished(false) );
return;
}
bool ok = false;
QString pwd;
_user = cfgFile.ownCloudUser();
_url = cfgFile.ownCloudUrl();
if( !cfgFile.passwordStorageAllowed() ) {
_type = CredentialStore::User;
}
QString key = keyChainKey(_url);
if( key.isNull() ) {
qDebug() << "Can not fetch credentials, url is zero!";
_state = Error;
emit( fetchCredentialsFinished(false) );
return;
}
switch( _type ) {
case CredentialStore::User: {
/* Ask the user for the password */
/* Fixme: Move user interaction out here. */
_state = AsyncFetching;
_inputDialog = new QInputDialog;
_inputDialog->setWindowTitle(QApplication::translate("MirallConfigFile","Password Required") );
_inputDialog->setLabelText( QApplication::translate("MirallConfigFile","Please enter your %1 password:")
.arg(Theme::instance()->appNameGUI()));
_inputDialog->setInputMode( QInputDialog::TextInput );
_inputDialog->setTextEchoMode( QLineEdit::Password );
connect(_inputDialog, SIGNAL(finished(int)), SLOT(slotUserDialogDone(int)));
_inputDialog->open();
break;
}
case CredentialStore::Settings: {
/* Read from config file. */
_state = Fetching;
pwd = cfgFile.ownCloudPasswd();
ok = true;
break;
}
case CredentialStore::KeyChain: {
// If the credentials are here already, return.
if( _state == Ok || _state == AsyncWriting ) {
emit(fetchCredentialsFinished(true));
return;
}
// otherwise fetch asynchronious.
#ifdef WITH_QTKEYCHAIN
_state = AsyncFetching;
if( !_user.isEmpty() ) {
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
job->setKey( key );
connect( job, SIGNAL(finished(QKeychain::Job*)), this,
SLOT(slotKeyChainReadFinished(QKeychain::Job*)));
job->start();
}
#else
qDebug() << "QtKeyChain: Not yet implemented!";
_state = Error;
#endif
break;
}
default: {
break;
}
}
if( _state == Fetching ) { // ...but not AsyncFetching
if( ok ) {
_passwd = pwd;
_state = Ok;
}
if( !ok && _state == Fetching ) {
_state = Error;
}
emit( fetchCredentialsFinished(ok) );
} else {
// in case of AsyncFetching nothing happens here. The finished-Slot
// will emit the finish signal.
}
}
void CredentialStore::slotUserDialogDone( int result )
{
if( result == QDialog::Accepted ) {
_passwd = _inputDialog->textValue();
_state = Ok;
} else {
_state = UserCanceled;
_passwd = QString::null;
}
_inputDialog->deleteLater();
emit(fetchCredentialsFinished(_state == Ok));
}
void CredentialStore::reset()
{
_state = NotFetched;
_user = QString::null;
_passwd = QString::null;
_tries = 0;
}
QString CredentialStore::keyChainKey( const QString& url ) const
{
QString u(url);
if( u.isEmpty() ) {
qDebug() << "Empty url in keyChain, error!";
return QString::null;
}
if( _user.isEmpty() ) {
qDebug() << "Error: User is emty!";
return QString::null;
}
if( !u.endsWith(QChar('/')) ) {
u.append(QChar('/'));
}
QString key = _user+QLatin1Char(':')+u;
return key;
}
void CredentialStore::slotKeyChainReadFinished(QKeychain::Job* job)
{
#ifdef WITH_QTKEYCHAIN
ReadPasswordJob *pwdJob = static_cast<ReadPasswordJob*>(job);
if( pwdJob ) {
switch( pwdJob->error() ) {
case QKeychain::NoError:
_passwd = pwdJob->textData();
#ifdef Q_OS_LINUX
// Currently there is a bug in the keychain on linux that if no
// entry is there, an empty password comes back, but no error.
if( _passwd.isEmpty() ) {
_state = EntryNotFound;
_errorMsg = tr("No password entry found in keychain. Please reconfigure.");
} else
#endif
_state = Ok;
break;
case QKeychain::EntryNotFound:
_state = EntryNotFound;
break;
case QKeychain::CouldNotDeleteEntry:
_state = Error;
break;
case QKeychain::AccessDeniedByUser:
_state = AccessDeniedByUser;
break;
case QKeychain::AccessDenied:
_state = AccessDenied;
break;
case QKeychain::NoBackendAvailable:
_state = NoKeychainBackend;
break;
case QKeychain::NotImplemented:
_state = NoKeychainBackend;
break;
case QKeychain::OtherError:
default:
_state = Error;
}
/* In case there is no backend, tranparentely switch to Settings file. */
if( _state == NoKeychainBackend ) {
qDebug() << "No Storage Backend, falling back to Settings mode.";
_type = CredentialStore::Settings;
fetchCredentials();
return;
}
if( _state == EntryNotFound ) {
// try to migrate.
}
if( _state != Ok ) {
qDebug() << "Error with keychain: " << pwdJob->errorString();
if(_errorMsg.isEmpty()) _errorMsg = pwdJob->errorString();
} else {
_errorMsg = QString::null;
}
} else {
_state = Error;
qDebug() << "Error: KeyChain Read Password Job failed!";
}
emit(fetchCredentialsFinished(_state == Ok));
#else
(void) job;
#endif
}
QString CredentialStore::errorMessage()
{
return _errorMsg;
}
void CredentialStore::setCredentials( const QString& url, const QString& user,
const QString& pwd, bool allowToStore )
{
_passwd = pwd;
_user = user;
if( allowToStore ) {
#ifdef WITH_QTKEYCHAIN
_type = KeyChain;
#else
_type = Settings;
#endif
} else {
_type = User;
}
_url = url;
_state = Ok;
}
void CredentialStore::saveCredentials( )
{
MirallConfigFile cfgFile;
QString key = keyChainKey(_url);
if( key.isNull() ) {
qDebug() << "Error: Can not save credentials, URL is zero!";
return;
}
#ifdef WITH_QTKEYCHAIN
WritePasswordJob *job = NULL;
#endif
switch( _type ) {
case CredentialStore::User:
deleteKeyChainCredential( key );
break;
case CredentialStore::KeyChain:
#ifdef WITH_QTKEYCHAIN
// Set password in KeyChain
job = new WritePasswordJob(Theme::instance()->appName());
job->setKey( key );
job->setTextData(_passwd);
connect( job, SIGNAL(finished(QKeychain::Job*)), this,
SLOT(slotKeyChainWriteFinished(QKeychain::Job*)));
_state = AsyncWriting;
job->start();
#endif
break;
case CredentialStore::Settings:
cfgFile.writePassword( _passwd );
reset();
break;
default:
// unsupported.
break;
}
}
void CredentialStore::slotKeyChainWriteFinished( QKeychain::Job *job )
{
#ifdef WITH_QTKEYCHAIN
WritePasswordJob *pwdJob = static_cast<WritePasswordJob*>(job);
if( pwdJob ) {
QKeychain::Error err = pwdJob->error();
if( err != QKeychain::NoError ) {
qDebug() << "Error with keychain: " << pwdJob->errorString();
if( err == NoBackendAvailable || err == NotImplemented ||
pwdJob->errorString().contains(QLatin1String("Could not open wallet"))) {
_state = NoKeychainBackend;
_type = Settings;
saveCredentials();
} else {
_state = Error;
}
} else {
qDebug() << "Successfully stored password for user " << _user;
// Try to remove password formerly stored in the config file.
MirallConfigFile cfgFile;
cfgFile.clearPasswordFromConfig();
_state = NotFetched;
_tries = 0;
}
} else {
qDebug() << "Error: KeyChain Write Password Job failed!";
_state = Error;
}
#else
(void) job;
#endif
}
// Called if a user chooses to not store the password locally.
void CredentialStore::deleteKeyChainCredential( const QString& key )
{
#ifdef WITH_QTKEYCHAIN
// Start the remove job, do not care so much about the result.
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
job->setKey( key );
job->start();
#endif
}
}
+147
Ver Arquivo
@@ -0,0 +1,147 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#ifndef CREDENTIALSTORE_H
#define CREDENTIALSTORE_H
#include <QObject>
#include <QInputDialog>
namespace QKeychain {
class Job;
}
namespace Mirall {
/*
* This object holds the credential information of the ownCloud connection. It
* is implemented as a singleton.
* At startup of the client, at first the fetchCredentials() method must be called
* which tries to get credentials from one of the supported backends. To determine
* which backend should be used, MirallConfigFile::credentialType() is called as
* the backend is configured in the config file.
*
* The fetchCredentials() call changes the internal state of the credential store
* to one of
* Ok: There are credentials. Note that it's unknown if they are correct!!
* UserCanceled: The fetching involved user interaction and the user canceled
* the operation. No valid credentials are there.
* TooManyAttempts: The user tried to often to enter a password.
* Fetching: The fetching is not yet finished.
* Error: A general error happened.
* After fetching has finished, signal fetchCredentialsFinished(bool) is emitted.
* The result can be retrieved with state() and password() and user() methods.
*/
class CredentialStore : public QObject
{
Q_OBJECT
public:
enum CredState { NotFetched = 0,
Ok,
UserCanceled,
Fetching,
AsyncFetching,
EntryNotFound,
AccessDeniedByUser,
AccessDenied,
NoKeychainBackend,
Error,
AsyncWriting,
TooManyAttempts };
enum CredentialType {
User = 0,
Settings,
KeyChain
};
QString password( ) const;
QString user( ) const;
/**
* @brief state
* @return the state of the Credentialstore.
*/
CredState state();
/**
* @brief fetchCredentials - start to retrieve user credentials.
*
* This method must be called first to retrieve the credentials.
* At the end, this method emits the fetchKeyChainFinished() signal.
*/
void fetchCredentials();
/**
* @brief instance - singleton pointer.
* @return the singleton pointer to access the object.
*/
static CredentialStore *instance();
/**
* @brief setCredentials - sets the user credentials.
*
* This function is called from the setup wizard to set the credentials
* int this store. Note that it does not store the password.
* The function also sets the state to ok.
* @param url - the connection url
* @param user - the user name
* @param password - the password.
*/
void setCredentials( const QString&, const QString&, const QString&, bool );
void saveCredentials( );
QString errorMessage();
/**
* @brief canTryAgain - check if another try to get credentials makes sense.
*/
bool canTryAgain();
void reset();
signals:
/**
* @brief fetchCredentialsFinished
*
* emitted as soon as the fetching of the credentials has finished.
* If the parameter is true, there is a password and user. This does
* however, not say if the credentials are valid log in data.
* If false, the user pressed cancel.
*/
void fetchCredentialsFinished(bool);
protected slots:
void slotKeyChainReadFinished( QKeychain::Job* );
void slotKeyChainWriteFinished( QKeychain::Job* );
void slotUserDialogDone(int);
private:
explicit CredentialStore(QObject *parent = 0);
void deleteKeyChainCredential( const QString& );
QString keyChainKey( const QString& ) const;
static CredentialStore *_instance;
static CredState _state;
static QString _passwd;
static QString _user;
static QString _url;
static QString _errorMsg;
static int _tries;
static CredentialType _type;
QInputDialog *_inputDialog;
};
}
#endif // CREDENTIALSTORE_H
+126 -412
Ver Arquivo
@@ -14,14 +14,10 @@
*/
#include "mirall/csyncthread.h"
#include "mirall/account.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/theme.h"
#include "mirall/logger.h"
#include "owncloudpropagator.h"
#include "syncjournaldb.h"
#include "syncjournalfilerecord.h"
#include "creds/abstractcredentials.h"
#include "mirall/owncloudinfo.h"
#ifdef Q_OS_WIN
#include <windows.h>
@@ -45,28 +41,16 @@
namespace Mirall {
void csyncLogCatcher(int /*verbosity*/,
const char */*function*/,
const char *buffer,
void */*userdata*/)
{
Logger::instance()->csyncLog( QString::fromUtf8(buffer) );
}
/* static variables to hold the credentials */
QMutex CSyncThread::_mutex;
QMutex CSyncThread::_syncMutex;
CSyncThread::CSyncThread(CSYNC *csync, const QString &localPath, const QString &remotePath, SyncJournalDb *journal)
CSyncThread::CSyncThread(CSYNC *csync)
{
_mutex.lock();
_localPath = localPath;
_remotePath = remotePath;
_csync_ctx = csync;
_journal = journal;
_mutex.unlock();
qRegisterMetaType<SyncFileItem>("SyncFileItem");
qRegisterMetaType<SyncFileItem::Status>("SyncFileItem::Status");
}
CSyncThread::~CSyncThread()
@@ -76,163 +60,110 @@ CSyncThread::~CSyncThread()
//Convert an error code from csync to a user readable string.
// Keep that function thread safe as it can be called from the sync thread or the main thread
QString CSyncThread::csyncErrorToString(CSYNC_STATUS err)
QString CSyncThread::csyncErrorToString( CSYNC_ERROR_CODE err, const char *errString )
{
QString errStr;
switch( err ) {
case CSYNC_STATUS_OK:
case CSYNC_ERR_NONE:
errStr = tr("Success.");
break;
case CSYNC_STATUS_NO_LOCK:
case CSYNC_ERR_LOG:
errStr = tr("CSync Logging setup failed.");
break;
case CSYNC_ERR_LOCK:
errStr = tr("CSync failed to create a lock file.");
break;
case CSYNC_STATUS_STATEDB_LOAD_ERROR:
case CSYNC_ERR_STATEDB_LOAD:
errStr = tr("CSync failed to load the state db.");
break;
case CSYNC_STATUS_STATEDB_WRITE_ERROR:
errStr = tr("CSync failed to write the state db.");
break;
case CSYNC_STATUS_NO_MODULE:
case CSYNC_ERR_MODULE:
errStr = tr("<p>The %1 plugin for csync could not be loaded.<br/>Please verify the installation!</p>").arg(Theme::instance()->appNameGUI());
break;
case CSYNC_STATUS_TIMESKEW:
case CSYNC_ERR_TIMESKEW:
errStr = tr("The system time on this client is different than the system time on the server. "
"Please use a time synchronization service (NTP) on the server and client machines "
"so that the times remain the same.");
break;
case CSYNC_STATUS_FILESYSTEM_UNKNOWN:
case CSYNC_ERR_FILESYSTEM:
errStr = tr("CSync could not detect the filesystem type.");
break;
case CSYNC_STATUS_TREE_ERROR:
case CSYNC_ERR_TREE:
errStr = tr("CSync got an error while processing internal trees.");
break;
case CSYNC_STATUS_MEMORY_ERROR:
case CSYNC_ERR_MEM:
errStr = tr("CSync failed to reserve memory.");
break;
case CSYNC_STATUS_PARAM_ERROR:
case CSYNC_ERR_PARAM:
errStr = tr("CSync fatal parameter error.");
break;
case CSYNC_STATUS_UPDATE_ERROR:
case CSYNC_ERR_UPDATE:
errStr = tr("CSync processing step update failed.");
break;
case CSYNC_STATUS_RECONCILE_ERROR:
case CSYNC_ERR_RECONCILE:
errStr = tr("CSync processing step reconcile failed.");
break;
case CSYNC_STATUS_PROPAGATE_ERROR:
case CSYNC_ERR_PROPAGATE:
errStr = tr("CSync processing step propagate failed.");
break;
case CSYNC_STATUS_REMOTE_ACCESS_ERROR:
case CSYNC_ERR_ACCESS_FAILED:
errStr = tr("<p>The target directory does not exist.</p><p>Please check the sync setup.</p>");
break;
case CSYNC_STATUS_REMOTE_CREATE_ERROR:
case CSYNC_STATUS_REMOTE_STAT_ERROR:
case CSYNC_ERR_REMOTE_CREATE:
case CSYNC_ERR_REMOTE_STAT:
errStr = tr("A remote file can not be written. Please check the remote access.");
break;
case CSYNC_STATUS_LOCAL_CREATE_ERROR:
case CSYNC_STATUS_LOCAL_STAT_ERROR:
case CSYNC_ERR_LOCAL_CREATE:
case CSYNC_ERR_LOCAL_STAT:
errStr = tr("The local filesystem can not be written. Please check permissions.");
break;
case CSYNC_STATUS_PROXY_ERROR:
case CSYNC_ERR_PROXY:
errStr = tr("CSync failed to connect through a proxy.");
break;
case CSYNC_STATUS_PROXY_AUTH_ERROR:
errStr = tr("CSync could not authenticate at the proxy.");
break;
case CSYNC_STATUS_LOOKUP_ERROR:
case CSYNC_ERR_LOOKUP:
errStr = tr("CSync failed to lookup proxy or server.");
break;
case CSYNC_STATUS_SERVER_AUTH_ERROR:
case CSYNC_ERR_AUTH_SERVER:
errStr = tr("CSync failed to authenticate at the %1 server.").arg(Theme::instance()->appNameGUI());
break;
case CSYNC_STATUS_CONNECT_ERROR:
case CSYNC_ERR_AUTH_PROXY:
errStr = tr("CSync failed to authenticate at the proxy.");
break;
case CSYNC_ERR_CONNECT:
errStr = tr("CSync failed to connect to the network.");
break;
case CSYNC_STATUS_TIMEOUT:
case CSYNC_ERR_TIMEOUT:
errStr = tr("A network connection timeout happend.");
break;
case CSYNC_STATUS_HTTP_ERROR:
case CSYNC_ERR_HTTP:
errStr = tr("A HTTP transmission error happened.");
break;
case CSYNC_STATUS_PERMISSION_DENIED:
case CSYNC_ERR_PERM:
errStr = tr("CSync failed due to not handled permission deniend.");
break;
case CSYNC_STATUS_NOT_FOUND:
errStr = tr("CSync failed to access "); // filename gets added.
case CSYNC_ERR_NOT_FOUND:
errStr = tr("CSync failed to find a specific file.");
break;
case CSYNC_STATUS_FILE_EXISTS:
case CSYNC_ERR_EXISTS:
errStr = tr("CSync tried to create a directory that already exists.");
break;
case CSYNC_STATUS_OUT_OF_SPACE:
case CSYNC_ERR_NOSPC:
errStr = tr("CSync: No space on %1 server available.").arg(Theme::instance()->appNameGUI());
break;
case CSYNC_STATUS_QUOTA_EXCEEDED:
errStr = tr("CSync: No space on %1 server available.").arg(Theme::instance()->appNameGUI());
break;
case CSYNC_STATUS_UNSUCCESSFUL:
case CSYNC_ERR_UNSPEC:
errStr = tr("CSync unspecified error.");
break;
case CSYNC_STATUS_ABORTED:
errStr = tr("Aborted by the user");
break;
default:
errStr = tr("An internal error number %1 happend.").arg( (int) err );
}
if( errString ) {
errStr += tr("<br/>Backend Message: ")+QString::fromUtf8(errString);
}
return errStr;
}
bool CSyncThread::checkBlacklisting( SyncFileItem *item )
{
bool re = false;
if( !_journal ) {
qWarning() << "Journal is undefined!";
return false;
}
SyncJournalBlacklistRecord entry = _journal->blacklistEntry(item->_file);
item->_blacklistedInDb = false;
// if there is a valid entry in the blacklist table and the retry count is
// already null or smaller than 0, the file is blacklisted.
if( entry.isValid() ) {
if( entry._retryCount <= 0 ) {
re = true;
item->_blacklistedInDb = true;
}
// if the retryCount is 0, but the etag has changed, it is tried again
// note that if the retryCount is -1 we never try again.
if( entry._retryCount == 0 ) {
if( item->_etag.isEmpty() || entry._lastTryEtag.isEmpty() ) {
// compare the mtimes.
if(entry._lastTryModtime != item->_modtime) {
re = false;
qDebug() << item->_file << " is blacklisted, but has changed mtime!";
}
} else {
if( entry._lastTryEtag != item->_etag) {
re = false;
qDebug() << item->_file << " is blacklisted, but has changed etag!";
}
}
}
if( re ) {
qDebug() << "Item is on blacklist: " << entry._file << "retries:" << entry._retryCount;
item->_blacklistedInDb = true;
item->_instruction = CSYNC_INSTRUCTION_IGNORE;
item->_errorString = tr("The item is not synced because it is on the blacklist.");
slotProgress( Progress::SoftError, *item );
}
}
return re;
}
int CSyncThread::treewalkLocal( TREE_WALK_FILE* file, void *data )
{
return static_cast<CSyncThread*>(data)->treewalkFile( file, false );
@@ -243,37 +174,23 @@ int CSyncThread::treewalkRemote( TREE_WALK_FILE* file, void *data )
return static_cast<CSyncThread*>(data)->treewalkFile( file, true );
}
int CSyncThread::walkFinalize(TREE_WALK_FILE* file, void *data )
{
return static_cast<CSyncThread*>(data)->treewalkError( file);
}
int CSyncThread::treewalkFile( TREE_WALK_FILE *file, bool remote )
{
if( ! file ) return -1;
SyncFileItem item;
item._file = QString::fromUtf8( file->path );
item._originalFile = item._file;
item._instruction = file->instruction;
item._dir = SyncFileItem::None;
item._fileId = QString::fromUtf8(file->file_id);
// record the seen files to be able to clean the journal later
_seenFiles[item._file] = QString();
if(file->error_string) {
item._errorString = QString::fromUtf8(file->error_string);
}
item._isDirectory = file->type == CSYNC_FTW_TYPE_DIR;
item._modtime = file->modtime;
item._etag = file->etag;
item._size = file->size;
item._should_update_etag = file->should_update_etag;
SyncFileItem::Direction dir;
int re = 0;
// check for blacklisting of this item.
// if the item is on blacklist, the instruction was set to IGNORE
checkBlacklisting( &item );
if (file->instruction != CSYNC_INSTRUCTION_IGNORE
&& file->instruction != CSYNC_INSTRUCTION_REMOVE) {
_hasFiles = true;
@@ -281,47 +198,27 @@ int CSyncThread::treewalkFile( TREE_WALK_FILE *file, bool remote )
switch(file->instruction) {
case CSYNC_INSTRUCTION_NONE:
case CSYNC_INSTRUCTION_IGNORE:
break;
case CSYNC_INSTRUCTION_NEW:
case CSYNC_INSTRUCTION_SYNC:
case CSYNC_INSTRUCTION_CONFLICT:
case CSYNC_INSTRUCTION_RENAME:
case CSYNC_INSTRUCTION_REMOVE:
_progressInfo.overall_file_count++;
_progressInfo.overall_transmission_size += file->size;
//fall trough
default:
_needsUpdate = true;
if (!_needsUpdate)
_needsUpdate = true;
}
switch(file->instruction) {
case CSYNC_INSTRUCTION_UPDATED:
// We need to update the database.
_journal->setFileRecord(SyncJournalFileRecord(item, _localPath + item._file));
item._instruction = CSYNC_INSTRUCTION_NONE;
// fall trough
case CSYNC_INSTRUCTION_NONE:
if (item._isDirectory && remote) {
// Because we want still to update etags of directories
dir = SyncFileItem::None;
} else {
// No need to do anything.
return re;
}
// No need to do anything.
return re;
break;
case CSYNC_INSTRUCTION_RENAME:
dir = !remote ? SyncFileItem::Down : SyncFileItem::Up;
item._renameTarget = QString::fromUtf8( file->rename_path );
if (item._isDirectory)
_renamedFolders.insert(item._file, item._renameTarget);
break;
case CSYNC_INSTRUCTION_REMOVE:
dir = !remote ? SyncFileItem::Down : SyncFileItem::Up;
break;
break;
case CSYNC_INSTRUCTION_CONFLICT:
case CSYNC_INSTRUCTION_IGNORE:
case CSYNC_INSTRUCTION_ERROR:
//
slotProgress(Progress::SoftError, item, 0, 0);
dir = SyncFileItem::None;
break;
case CSYNC_INSTRUCTION_EVAL:
@@ -329,60 +226,71 @@ int CSyncThread::treewalkFile( TREE_WALK_FILE *file, bool remote )
case CSYNC_INSTRUCTION_SYNC:
case CSYNC_INSTRUCTION_STAT_ERROR:
case CSYNC_INSTRUCTION_DELETED:
case CSYNC_INSTRUCTION_UPDATED:
default:
dir = remote ? SyncFileItem::Down : SyncFileItem::Up;
break;
}
switch( file->type ) {
case CSYNC_FTW_TYPE_DIR:
item._type = SyncFileItem::Directory;
break;
case CSYNC_FTW_TYPE_FILE:
item._type = SyncFileItem::File;
break;
case CSYNC_FTW_TYPE_SLINK:
item._type = SyncFileItem::SoftLink;
break;
default:
item._type = SyncFileItem::UnknownType;
}
item._dir = dir;
_mutex.lock();
_syncedItems.append(item);
_mutex.unlock();
return re;
}
void CSyncThread::handleSyncError(CSYNC *ctx, const char *state) {
CSYNC_STATUS err = csync_get_status( ctx );
const char *errMsg = csync_get_status_string( ctx );
QString errStr = csyncErrorToString(err);
if( errMsg ) {
if( !errStr.endsWith(" ")) {
errStr.append(" ");
}
errStr += QString::fromUtf8(errMsg);
int CSyncThread::treewalkError(TREE_WALK_FILE* file)
{
SyncFileItem item;
item._file= QString::fromUtf8(file->path);
int indx = _syncedItems.indexOf(item);
if ( indx == -1 )
return 0;
if( file &&
(file->instruction == CSYNC_INSTRUCTION_STAT_ERROR ||
file->instruction == CSYNC_INSTRUCTION_ERROR) ) {
_mutex.lock();
_syncedItems[indx]._instruction = file->instruction;
_mutex.unlock();
}
// if there is csyncs url modifier in the error message, replace it.
if( errStr.contains("ownclouds://") ) errStr.replace("ownclouds://", "https://");
if( errStr.contains("owncloud://") ) errStr.replace("owncloud://", "http://");
return 0;
}
struct CSyncRunScopeHelper {
CSyncRunScopeHelper(CSYNC *ctx, CSyncThread *parent)
: _ctx(ctx), _parent(parent)
{
_t.start();
}
~CSyncRunScopeHelper() {
csync_commit(_ctx);
qDebug() << "CSync run took " << _t.elapsed() << " Milliseconds";
emit(_parent->finished());
_parent->_syncMutex.unlock();
}
CSYNC *_ctx;
QTime _t;
CSyncThread *_parent;
};
void CSyncThread::handleSyncError(CSYNC *ctx, const char *state) {
CSYNC_ERROR_CODE err = csync_get_error( ctx );
const char *errMsg = csync_get_error_string( ctx );
QString errStr = csyncErrorToString(err, errMsg);
qDebug() << " #### ERROR during "<< state << ": " << errStr;
if( CSYNC_STATUS_IS_EQUAL( err, CSYNC_STATUS_ABORTED) ) {
qDebug() << "Update phase was aborted by user!";
} else if( CSYNC_STATUS_IS_EQUAL( err, CSYNC_STATUS_SERVICE_UNAVAILABLE ) ||
CSYNC_STATUS_IS_EQUAL( err, CSYNC_STATUS_CONNECT_ERROR )) {
switch (err) {
case CSYNC_ERR_SERVICE_UNAVAILABLE:
case CSYNC_ERR_CONNECT:
emit csyncUnavailable();
} else {
break;
default:
emit csyncError(errStr);
}
csync_commit(_csync_ctx);
emit finished();
_syncMutex.unlock();
thread()->quit();
}
void CSyncThread::startSync()
@@ -397,105 +305,36 @@ void CSyncThread::startSync()
}
qDebug() << Q_FUNC_INFO << "Sync started";
qDebug() << "starting to sync " << qApp->thread() << QThread::currentThread();
_syncedItems.clear();
_mutex.lock();
_syncedItems.clear();
_needsUpdate = false;
if (!_abortRequested.fetchAndAddRelease(0)) {
csync_resume(_csync_ctx);
}
_mutex.unlock();
// maybe move this somewhere else where it can influence a running sync?
MirallConfigFile cfg;
if (!_journal->exists()) {
qDebug() << "=====sync looks new (no DB exists), activating recursive PROPFIND if csync supports it";
bool no_recursive_propfind = false;
csync_set_module_property(_csync_ctx, "no_recursive_propfind", &no_recursive_propfind);
} else {
// retrieve the file count from the db and close it afterwards because
// csync_update also opens the database.
int fileRecordCount = 0;
fileRecordCount = _journal->getFileRecordCount();
_journal->close();
if( fileRecordCount == -1 ) {
qDebug() << "No way to create a sync journal!";
emit csyncError(tr("Unable to initialize a sync journal."));
csync_commit(_csync_ctx);
emit finished();
_syncMutex.unlock();
thread()->quit();
return;
// database creation error!
} else if ( fileRecordCount < 50 ) {
qDebug() << "=====sync DB has only" << fileRecordCount << "items, enable recursive PROPFIND if csync supports it";
bool no_recursive_propfind = false;
csync_set_module_property(_csync_ctx, "no_recursive_propfind", &no_recursive_propfind);
} else {
qDebug() << "=====sync with existing DB";
}
}
// cleans up behind us and emits finished() to ease error handling
CSyncRunScopeHelper helper(_csync_ctx, this);
csync_set_module_property(_csync_ctx, "csync_context", _csync_ctx);
csync_set_userdata(_csync_ctx, this);
// TODO: This should be a part of this method, but we don't have
// any way to get "session_key" module property from csync. Had we
// have it, then we could keep this code and remove it from
// AbstractCredentials implementations.
if (Account *account = AccountManager::instance()->account()) {
account->credentials()->syncContextPreStart(_csync_ctx);
} else {
qDebug() << Q_FUNC_INFO << "No default Account object, huh?";
}
// if (_lastAuthCookies.length() > 0) {
// // Stuff cookies inside csync, then we can avoid the intermediate HTTP 401 reply
// // when https://github.com/owncloud/core/pull/4042 is merged.
// QString cookiesAsString;
// foreach(QNetworkCookie c, _lastAuthCookies) {
// cookiesAsString += c.name();
// cookiesAsString += '=';
// cookiesAsString += c.value();
// cookiesAsString += "; ";
// }
// csync_set_module_property(_csync_ctx, "session_key", cookiesAsString.to
// }
// csync_set_auth_callback( _csync_ctx, getauth );
csync_set_log_callback( csyncLogCatcher );
csync_set_log_level( 11 );
csync_set_progress_callback( _csync_ctx, progress );
_syncTime.start();
QElapsedTimer updateTime;
updateTime.start();
qDebug() << "#### Update start #################################################### >>";
if( csync_update(_csync_ctx) < 0 ) {
handleSyncError(_csync_ctx, "csync_update");
return;
}
qDebug() << "<<#### Update end #################################################### " << updateTime.elapsed();
qDebug() << "<<#### Update end ###########################################################";
if( csync_reconcile(_csync_ctx) < 0 ) {
handleSyncError(_csync_ctx, "csync_reconcile");
handleSyncError(_csync_ctx, "cysnc_reconcile");
return;
}
slotProgress(Progress::StartSync, SyncFileItem(), 0, 0);
_progressInfo = Progress::Info();
_hasFiles = false;
bool walkOk = true;
_seenFiles.clear();
if( csync_walk_local_tree(_csync_ctx, &treewalkLocal, 0) < 0 ) {
qDebug() << "Error in local treewalk.";
walkOk = false;
@@ -504,15 +343,9 @@ void CSyncThread::startSync()
qDebug() << "Error in remote treewalk.";
}
// Adjust the paths for the renames.
for (SyncFileItemVector::iterator it = _syncedItems.begin();
it != _syncedItems.end(); ++it) {
it->_file = adjustRenamedPath(it->_file);
}
if (!_hasFiles && !_syncedItems.isEmpty()) {
qDebug() << Q_FUNC_INFO << "All the files are going to be removed, asking the user";
bool cancel = false;
bool cancel = true;
emit aboutToRemoveAllFiles(_syncedItems.first()._dir, &cancel);
if (cancel) {
qDebug() << Q_FUNC_INFO << "Abort sync";
@@ -523,152 +356,33 @@ void CSyncThread::startSync()
if (_needsUpdate)
emit(started());
ne_session_s *session = 0;
// that call to set property actually is a get which will return the session
// FIXME add a csync_get_module_property to csync
csync_set_module_property(_csync_ctx, "get_dav_session", &session);
Q_ASSERT(session);
_propagator.reset(new OwncloudPropagator (session, _localPath, _remotePath,
_journal, &_abortRequested));
connect(_propagator.data(), SIGNAL(completed(SyncFileItem)),
this, SLOT(transferCompleted(SyncFileItem)), Qt::QueuedConnection);
connect(_propagator.data(), SIGNAL(progress(Progress::Kind,SyncFileItem,quint64,quint64)),
this, SLOT(slotProgress(Progress::Kind,SyncFileItem,quint64,quint64)));
connect(_propagator.data(), SIGNAL(finished()), this, SLOT(slotFinished()));
int downloadLimit = 0;
if (cfg.useDownloadLimit()) {
downloadLimit = cfg.downloadLimit() * 1000;
}
_propagator->_downloadLimit = downloadLimit;
int uploadLimit = -75; // 75%
int useUpLimit = cfg.useUploadLimit();
if ( useUpLimit >= 1) {
uploadLimit = cfg.uploadLimit() * 1000;
} else if (useUpLimit == 0) {
uploadLimit = 0;
}
_propagator->_uploadLimit = uploadLimit;
_propagator->start(_syncedItems);
}
void CSyncThread::transferCompleted(const SyncFileItem &item)
{
qDebug() << Q_FUNC_INFO << item._file << item._status << item._errorString;
/* Update the _syncedItems vector */
int idx = _syncedItems.indexOf(item);
if (idx >= 0) {
_syncedItems[idx]._instruction = item._instruction;
_syncedItems[idx]._errorString = item._errorString;
_syncedItems[idx]._status = item._status;
} else {
qWarning() << Q_FUNC_INFO << "Could not find index in synced items!";
}
if (item._status == SyncFileItem::FatalError) {
emit csyncError(item._errorString);
}
}
void CSyncThread::slotFinished()
{
// emit the treewalk results.
if( ! _journal->postSyncCleanup( _seenFiles ) ) {
qDebug() << "Cleaning of synced ";
}
_journal->commit("All Finished.", false);
emit treeWalkResult(_syncedItems);
csync_commit(_csync_ctx);
qDebug() << "CSync run took " << _syncTime.elapsed() << " Milliseconds";
slotProgress(Progress::EndSync,SyncFileItem(), 0 , 0);
emit finished();
_propagator.reset(0);
_syncMutex.unlock();
thread()->quit();
}
void CSyncThread::progressProblem(Progress::Kind kind, const SyncFileItem& item)
{
Progress::SyncProblem problem;
problem.kind = kind;
problem.current_file = item._file;
problem.error_message = item._errorString;
problem.error_code = item._httpErrorCode;
problem.timestamp = QDateTime::currentDateTime();
// connected to something in folder.
emit transmissionProblem( problem );
}
void CSyncThread::slotProgress(Progress::Kind kind, const SyncFileItem& item, quint64 curr, quint64 total)
{
if( Progress::isErrorKind(kind) ) {
progressProblem(kind, item);
if( csync_propagate(_csync_ctx) < 0 ) {
handleSyncError(_csync_ctx, "cysnc_reconcile");
return;
}
if( kind == Progress::StartSync ) {
QMutexLocker lock(&_mutex);
_currentFileNo = 0;
_lastOverallBytes = 0;
}
if( kind == Progress::StartDelete ||
kind == Progress::StartDownload ||
kind == Progress::StartRename ||
kind == Progress::StartUpload ) {
QMutexLocker lock(&_mutex);
_currentFileNo += 1;
}
if( kind == Progress::EndUpload ||
kind == Progress::EndDownload ||
kind == Progress::EndRename ||
kind == Progress::EndDelete ) {
QMutexLocker lock(&_mutex);
_lastOverallBytes += total;
curr = 0;
}
Progress::Info pInfo(_progressInfo);
pInfo.kind = kind;
pInfo.current_file = item._file;
pInfo.file_size = total;
pInfo.current_file_bytes = curr;
pInfo.current_file_no = _currentFileNo;
pInfo.timestamp = QDateTime::currentDateTime();
pInfo.overall_current_bytes = _lastOverallBytes + curr;
// Connect to something in folder!
emit transmissionProgress( pInfo );
}
/* Given a path on the remote, give the path as it is when the rename is done */
QString CSyncThread::adjustRenamedPath(const QString& original)
{
int slashPos = original.size();
while ((slashPos = original.lastIndexOf('/' , slashPos - 1)) > 0) {
QHash< QString, QString >::const_iterator it = _renamedFolders.constFind(original.left(slashPos));
if (it != _renamedFolders.constEnd()) {
return *it + original.mid(slashPos);
if( walkOk ) {
if( csync_walk_local_tree(_csync_ctx, &walkFinalize, 0) < 0 ||
csync_walk_remote_tree( _csync_ctx, &walkFinalize, 0 ) < 0 ) {
qDebug() << "Error in finalize treewalk.";
} else {
// emit the treewalk results.
emit treeWalkResult(_syncedItems);
}
}
return original;
qDebug() << Q_FUNC_INFO << "Sync finished";
}
void CSyncThread::abort()
void CSyncThread::progress(const char *remote_url, enum csync_notify_type_e kind,
long long o1, long long o2, void *userdata)
{
QMutexLocker locker(&_mutex);
csync_request_abort(_csync_ctx);
_abortRequested = true;
(void) o1; (void) o2;
if (kind == CSYNC_NOTIFY_FINISHED_DOWNLOAD) {
QString path = QUrl::fromEncoded(remote_url).toString();
CSyncThread *thread = static_cast<CSyncThread*>(userdata);
thread->fileReceived(path);
}
}
} // ns Mirall
}
+14 -52
Ver Arquivo
@@ -21,55 +21,35 @@
#include <QMutex>
#include <QThread>
#include <QString>
#include <qelapsedtimer.h>
#include <qstack.h>
#include <QNetworkProxy>
#include <QNetworkCookie>
#include <csync.h>
#include "mirall/syncfileitem.h"
#include "mirall/progressdispatcher.h"
class QProcess;
namespace Mirall {
class SyncJournalFileRecord;
class SyncJournalDb;
class OwncloudPropagator;
void csyncLogCatcher(int /*verbosity*/,
const char */*function*/,
const char *buffer,
void */*userdata*/);
class CSyncThread : public QObject
{
Q_OBJECT
public:
CSyncThread(CSYNC *, const QString &localPath, const QString &remotePath, SyncJournalDb *journal);
CSyncThread(CSYNC *);
~CSyncThread();
static QString csyncErrorToString( CSYNC_STATUS);
static QString csyncErrorToString( CSYNC_ERROR_CODE, const char * );
Q_INVOKABLE void startSync();
/* Abort the sync. Called from the main thread */
void abort();
signals:
void fileReceived( const QString& );
void fileRemoved( const QString& );
void csyncError( const QString& );
void csyncWarning( const QString& );
void csyncUnavailable();
void treeWalkResult(const SyncFileItemVector&);
void transmissionProgress( const Progress::Info& progress );
void transmissionProblem( const Progress::SyncProblem& problem );
void csyncStateDbFile( const QString& );
void wipeDb();
@@ -78,19 +58,21 @@ signals:
void aboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel);
private slots:
void transferCompleted(const SyncFileItem& item);
void slotFinished();
void slotProgress(Progress::Kind kind, const SyncFileItem &item, quint64 curr = 0, quint64 total = 0);
private:
void handleSyncError(CSYNC *ctx, const char *state);
void progressProblem(Progress::Kind kind, const SyncFileItem& item);
static void progress(const char *remote_url,
enum csync_notify_type_e kind,
long long o1, long long o2,
void *userdata);
static int treewalkLocal( TREE_WALK_FILE*, void *);
static int treewalkRemote( TREE_WALK_FILE*, void *);
int treewalkFile( TREE_WALK_FILE*, bool );
bool checkBlacklisting( SyncFileItem *item );
int treewalkError( TREE_WALK_FILE* );
static int walkFinalize(TREE_WALK_FILE*, void* );
static QMutex _mutex;
static QMutex _syncMutex;
@@ -98,30 +80,10 @@ private:
CSYNC *_csync_ctx;
bool _needsUpdate;
QString _localPath;
QString _remotePath;
SyncJournalDb *_journal;
QScopedPointer <OwncloudPropagator> _propagator;
QElapsedTimer _syncTime;
QString _lastDeleted; // if the last item was a path and it has been deleted
QHash <QString, QString> _seenFiles;
// maps the origin and the target of the folders that have been renamed
QHash<QString, QString> _renamedFolders;
QString adjustRenamedPath(const QString &original);
bool _hasFiles; // true if there is at least one file that is not ignored or removed
Progress::Info _progressInfo;
int _downloadLimit;
int _uploadLimit;
qint64 _currentFileNo;
qint64 _overallFileCount;
quint64 _lastOverallBytes;
QAtomicInt _abortRequested;
friend struct CSyncRunScopeHelper;
friend class CSyncRunScopeHelper;
};
}
+304
Ver Arquivo
@@ -0,0 +1,304 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#include <QtGui>
#include "mirall/fileitemdialog.h"
#include "mirall/theme.h"
#include "mirall/syncresult.h"
#include "mirall/logger.h"
#define TYPE_SUCCESS 1
#define TYPE_CONFLICT 2
#define TYPE_NEW 3
#define TYPE_DELETED 4
#define TYPE_ERROR 5
#define TYPE_RENAME 6
#define TYPE_IGNORE 7
#define FILE_TYPE 100
namespace Mirall {
FileItemDialog::FileItemDialog(Theme *theme, QWidget *parent) :
QDialog(parent),
_theme(theme)
{
setupUi(this);
connect(_dialogButtonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()),
this, SLOT(accept()));
QStringList header;
header << tr("Files");
QString firstColString = tr("File Count");
header << firstColString;
_treeWidget->setHeaderLabels( header );
_treeWidget->setColumnWidth(0, 480);
_timer.setInterval(1000);
connect(&_timer, SIGNAL(timeout()), this, SLOT(slotSetFolderMessage()));
connect(this, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(guiLog(QString,QString)));
QPushButton *copyBtn = _dialogButtonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
connect(copyBtn, SIGNAL(clicked()), SLOT(copyToClipboard()));
setWindowTitle(tr("Sync Protocol"));
}
void FileItemDialog::setSyncResult( const SyncResult& result )
{
QString folderMessage;
SyncResult::Status syncStatus = result.status();
switch( syncStatus ) {
case SyncResult::Undefined:
folderMessage = tr( "Undefined Folder State" );
break;
case SyncResult::NotYetStarted:
folderMessage = tr( "The folder waits to start syncing." );
break;
case SyncResult::SyncPrepare:
folderMessage = tr( "Determining which files to sync." );
break;
case SyncResult::Unavailable:
folderMessage = tr( "Server is currently not available." );
break;
case SyncResult::SyncRunning:
folderMessage = tr("Sync is running.");
break;
case SyncResult::Success:
folderMessage = tr("Last Sync was successful.");
break;
case SyncResult::Error:
folderMessage = tr( "Syncing Error." );
break;
case SyncResult::SetupError:
folderMessage = tr( "Setup Error." );
break;
default:
folderMessage = tr( "Undefined Error State." );
}
_folderMessage = folderMessage;
_lastSyncTime = result.syncTime();
if( result.errorStrings().count() ) {
_errorLabel->setVisible(true);
_errorLabel->setTextFormat(Qt::RichText);
QString errStr;
foreach( QString err, result.errorStrings() ) {
errStr.append(QString("<p>%1</p>").arg(err));
}
_errorLabel->setText(errStr);
} else {
_errorLabel->setText(QString::null);
_errorLabel->setVisible(false);
}
slotSetFolderMessage();
if( syncStatus == SyncResult::SyncRunning ) {
_timer.stop();
} else {
_timer.start();
}
setSyncFileItems( result.syncFileItemVector() );
}
void FileItemDialog::slotSetFolderMessage()
{
QDateTime now = QDateTime::currentDateTime();
int secs = _lastSyncTime.secsTo(now);
if (secs < 60)
_timelabel->setText(tr("%1 (last finished %n sec. ago)", "", secs).arg(_folderMessage));
else
_timelabel->setText(tr("%1 (last finished %n min. ago)", "", secs/60).arg(_folderMessage));
}
void FileItemDialog::copyToClipboard()
{
QString text;
QTextStream ts(&text);
int topLevelItems = _treeWidget->topLevelItemCount();
for (int i = 0; i < topLevelItems; i++) {
QTreeWidgetItem *item = _treeWidget->topLevelItem(i);
ts << left << qSetFieldWidth(50)
<< item->data(0, Qt::DisplayRole).toString()
<< right << qSetFieldWidth(6)
<< item->data(1, Qt::DisplayRole).toString()
<< endl;
int childItems = item->childCount();
for (int j = 0; j < childItems; j++) {
QTreeWidgetItem *child =item->child(j);
ts << left << qSetFieldWidth(0) << QLatin1String(" ")
<< child->data(0,Qt::DisplayRole).toString()
<< QString::fromLatin1(" (%1)").arg(
child->data(1, Qt::DisplayRole).toString()
)
<< endl;
}
}
QApplication::clipboard()->setText(text);
emit guiLog(tr("Copied to clipboard"), tr("The sync protocol has been copied to the clipboard."));
}
void FileItemDialog::accept()
{
_timer.stop();
QDialog::accept();
}
void FileItemDialog::setSyncFileItems( const SyncFileItemVector& list )
{
_treeWidget->clear();
QStringList strings;
QFont headerFont;
headerFont.setWeight(QFont::Bold);
strings.clear();
strings.append(tr("Synced Files"));
_syncedFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_SUCCESS );
_syncedFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
_treeWidget->addTopLevelItem(_syncedFileItem);
strings.clear();
strings.append(tr("New Files"));
_newFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_NEW );
_newFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
_treeWidget->addTopLevelItem(_newFileItem);
strings.clear();
strings.append(tr("Deleted Files"));
_deletedFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_DELETED );
_deletedFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
_treeWidget->addTopLevelItem(_deletedFileItem);
strings.clear();
strings.append(tr("Renamed Files"));
_renamedFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_RENAME);
_renamedFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
_treeWidget->addTopLevelItem(_renamedFileItem);
strings.clear();
strings.append(tr("Ignored Files"));
_ignoredFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_IGNORE);
_ignoredFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
_treeWidget->addTopLevelItem(_renamedFileItem);
strings.clear();
strings.append(tr("Errors"));
_errorFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_ERROR );
_errorFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
_treeWidget->addTopLevelItem(_errorFileItem);
strings.clear();
strings.append(tr("Conflicts"));
_conflictFileItem = new QTreeWidgetItem( _treeWidget, strings, TYPE_CONFLICT);
_conflictFileItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);
_treeWidget->addTopLevelItem(_conflictFileItem);
QList<QTreeWidgetItem*> syncedItems;
QList<QTreeWidgetItem*> renamedItems;
QList<QTreeWidgetItem*> newItems;
QList<QTreeWidgetItem*> deletedItems;
QList<QTreeWidgetItem*> ignoredItems;
QList<QTreeWidgetItem*> conflictItems;
QList<QTreeWidgetItem*> errorItems;
quint64 overall_files = 0;
foreach( SyncFileItem item, list ) {
overall_files++;
QString dir;
QStringList str( item._file );
if( item._dir == SyncFileItem::Up ) dir = tr("Uploaded");
if( item._dir == SyncFileItem::Down ) dir = tr("Downloaded");
str << dir;
switch( item._instruction ) {
case CSYNC_INSTRUCTION_NONE:
// do nothing.
break;
case CSYNC_INSTRUCTION_EVAL:
// should not happen
break;
case CSYNC_INSTRUCTION_REMOVE:
case CSYNC_INSTRUCTION_DELETED:
deletedItems.append( new QTreeWidgetItem(_deletedFileItem, str, FILE_TYPE) );
break;
case CSYNC_INSTRUCTION_RENAME:
renamedItems.append( new QTreeWidgetItem(_renamedFileItem, str, FILE_TYPE) );
break;
case CSYNC_INSTRUCTION_NEW:
newItems.append( new QTreeWidgetItem(_newFileItem, str, FILE_TYPE) );
break;
case CSYNC_INSTRUCTION_CONFLICT:
conflictItems.append( new QTreeWidgetItem(_conflictFileItem, str, FILE_TYPE) );
break;
case CSYNC_INSTRUCTION_IGNORE:
ignoredItems.append( new QTreeWidgetItem(_ignoredFileItem, str, FILE_TYPE) );
break;
case CSYNC_INSTRUCTION_SYNC:
case CSYNC_INSTRUCTION_UPDATED:
syncedItems.append( new QTreeWidgetItem(_syncedFileItem, str, FILE_TYPE) );
break;
case CSYNC_INSTRUCTION_STAT_ERROR:
case CSYNC_INSTRUCTION_ERROR:
errorItems.append( new QTreeWidgetItem(_errorFileItem, str, FILE_TYPE) );
break;
default:
break;
}
}
formatHeaderItem( _syncedFileItem, syncedItems );
formatHeaderItem( _newFileItem, newItems );
formatHeaderItem( _deletedFileItem, deletedItems );
formatHeaderItem( _renamedFileItem, renamedItems );
formatHeaderItem( _errorFileItem, errorItems );
formatHeaderItem( _conflictFileItem, conflictItems );
formatHeaderItem( _ignoredFileItem, ignoredItems );
}
void FileItemDialog::formatHeaderItem( QTreeWidgetItem *header, const QList<QTreeWidgetItem*>& list )
{
if( !header ) return;
header->addChildren( list );
int count = list.count();
#if LEAVE_THAT_TO_DESIGNERS
QColor col("#adc5d3");
header->setBackgroundColor(0, col);
header->setBackgroundColor(1, col);
#endif
header->setText(1, QString::number( count ));
if( count ) {
QFont font;
font.setWeight( QFont::Bold );
header->setFont(0, font);
header->setFont(1, font);
header->setExpanded(true);
} else {
header->setExpanded(false);
}
}
}
+68
Ver Arquivo
@@ -0,0 +1,68 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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. See the GNU General Public License
* for more details.
*/
#ifndef FILEITEMDIALOG_H
#define FILEITEMDIALOG_H
#include <QDialog>
#include <QDateTime>
#include <QTimer>
#include "mirall/syncfileitem.h"
#include "ui_fileitemdialog.h"
namespace Mirall {
class Theme;
class SyncResult;
class FileItemDialog : public QDialog, public Ui::_fileItemDialog
{
Q_OBJECT
public:
explicit FileItemDialog(Theme*, QWidget *parent = 0);
void setSyncResult( const SyncResult& );
signals:
public slots:
void accept();
protected slots:
void slotSetFolderMessage();
void copyToClipboard();
signals:
void guiLog(const QString&, const QString&);
private:
void setSyncFileItems( const SyncFileItemVector& list );
void formatHeaderItem( QTreeWidgetItem *, const QList<QTreeWidgetItem*>& );
QTreeWidgetItem *_newFileItem;
QTreeWidgetItem *_syncedFileItem;
QTreeWidgetItem *_deletedFileItem;
QTreeWidgetItem *_renamedFileItem;
QTreeWidgetItem *_errorFileItem;
QTreeWidgetItem *_conflictFileItem;
QTreeWidgetItem *_ignoredFileItem;
Theme *_theme;
QString _folderMessage;
QDateTime _lastSyncTime;
QTimer _timer;
};
}
#endif // FILEITEMDIALOG_H
+87
Ver Arquivo
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>_fileItemDialog</class>
<widget class="QWidget" name="_fileItemDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>612</width>
<height>543</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>Detailed Sync Protocol</string>
</property>
</widget>
</item>
<item>
<widget class="QTreeWidget" name="_treeWidget">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="rootIsDecorated">
<bool>true</bool>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="columnCount">
<number>2</number>
</property>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
<column>
<property name="text">
<string notr="true">2</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="QLabel" name="_timelabel">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="_errorLabel">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="_dialogButtonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+1 -1
Ver Arquivo
@@ -25,7 +25,7 @@ class FileUtils
public:
enum SubFolderListOption {
SubFolderNoOptions = 0x0,
SubFolderRecursive = 0x1
SubFolderRecursive = 0x1,
};
Q_DECLARE_FLAGS(SubFolderListOptions, SubFolderListOption)

Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais