Comparar commits
1 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 43e071aea9 |
+3
-2
@@ -7,8 +7,6 @@ endif()
|
|||||||
|
|
||||||
project(client)
|
project(client)
|
||||||
|
|
||||||
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
|
||||||
|
|
||||||
set(OEM_THEME_DIR "" CACHE STRING "Define directory containing a custom theme")
|
set(OEM_THEME_DIR "" CACHE STRING "Define directory containing a custom theme")
|
||||||
if ( EXISTS ${OEM_THEME_DIR}/OEM.cmake )
|
if ( EXISTS ${OEM_THEME_DIR}/OEM.cmake )
|
||||||
include ( ${OEM_THEME_DIR}/OEM.cmake )
|
include ( ${OEM_THEME_DIR}/OEM.cmake )
|
||||||
@@ -60,6 +58,9 @@ if( UNIX AND NOT APPLE )
|
|||||||
endif()
|
endif()
|
||||||
####
|
####
|
||||||
|
|
||||||
|
# Enable Q_ASSERT etc. in all builds
|
||||||
|
add_definitions( -DQT_FORCE_ASSERTS )
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
include(DefineInstallationPaths)
|
include(DefineInstallationPaths)
|
||||||
include(GenerateExportHeader)
|
include(GenerateExportHeader)
|
||||||
|
|||||||
+4
-5
@@ -1,11 +1,10 @@
|
|||||||
ChangeLog
|
ChangeLog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
version 2.3.0 (2017-02-xx)
|
version 2.3.0 (2017-0x-xx)
|
||||||
* Decreased memory usage during sync
|
* WiP!
|
||||||
* Overlay icons: Lower CPU usage
|
* WiP Switch Windows and OS X build to 5.6.2
|
||||||
* Allow to not sync the server's external storages by default
|
* WiP Performance improvements for exclude detection
|
||||||
* Switch Windows and OS X build to 5.6.2
|
|
||||||
* Switch to new ownCloud server WebDAV endpoint
|
* Switch to new ownCloud server WebDAV endpoint
|
||||||
* Chunking NG: New file upload chunking algorithmn for ownCloud server 9.2
|
* Chunking NG: New file upload chunking algorithmn for ownCloud server 9.2
|
||||||
* Allow to sync a folder to multiple different servers (Filename change from .csync_journal.db to _sync_$HASH.db)
|
* Allow to sync a folder to multiple different servers (Filename change from .csync_journal.db to _sync_$HASH.db)
|
||||||
|
|||||||
externo
+1
-1
@@ -39,7 +39,7 @@ node('CLIENT') {
|
|||||||
|
|
||||||
|
|
||||||
stage 'Win32'
|
stage 'Win32'
|
||||||
def win32 = docker.image('guruz/docker-owncloud-client-win32:latest')
|
def win32 = docker.image('deepdiver/docker-owncloud-client-win32:latest')
|
||||||
win32.pull() // make sure we have the latest available from Docker Hub
|
win32.pull() // make sure we have the latest available from Docker Hub
|
||||||
win32.inside {
|
win32.inside {
|
||||||
sh '''
|
sh '''
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Показати примітки
|
|||||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Знайдено процес(и) ${APPLICATION_EXECUTABLE}, які необхідно зупинити.$\nХочете щоб програма установки зробила це самостійно?"
|
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Знайдено процес(и) ${APPLICATION_EXECUTABLE}, які необхідно зупинити.$\nХочете щоб програма установки зробила це самостійно?"
|
||||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Завершення процесів ${APPLICATION_EXECUTABLE}."
|
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Завершення процесів ${APPLICATION_EXECUTABLE}."
|
||||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Не знайдено процеси, які необхідно зупинити!"
|
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Не знайдено процеси, які необхідно зупинити!"
|
||||||
StrCpy $PageReinstall_NEW_Field_1 "У вашої системі встановлена застаріла версія додатку ${APPLICATION_NAME}. Рекомендуємо видалити її перед початком встановлення поточної версії. Оберіть подальшу дію та натисніть $\"Далі$\"."
|
StrCpy $PageReinstall_NEW_Field_1 "Знайдено застарілу версію програми ${APPLICATION_NAME}. Рекомендуємо її спочатку видалити. Оберіть подальшу дію та натисніть $\"Далі$\"."
|
||||||
StrCpy $PageReinstall_NEW_Field_2 "Видалити перед установкою"
|
StrCpy $PageReinstall_NEW_Field_2 "Видалити перед установкою"
|
||||||
StrCpy $PageReinstall_NEW_Field_3 "Не видаляти"
|
StrCpy $PageReinstall_NEW_Field_3 "Не видаляти"
|
||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Установлено"
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Установлено"
|
||||||
|
|||||||
+1
-1
Submodule binary updated: 741b49156b...0d89ac7766
@@ -418,8 +418,10 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
|||||||
File "${QT_DLL_PATH}\Qt5Core.dll"
|
File "${QT_DLL_PATH}\Qt5Core.dll"
|
||||||
File "${QT_DLL_PATH}\Qt5Gui.dll"
|
File "${QT_DLL_PATH}\Qt5Gui.dll"
|
||||||
File "${QT_DLL_PATH}\Qt5Network.dll"
|
File "${QT_DLL_PATH}\Qt5Network.dll"
|
||||||
|
File "${QT_DLL_PATH}\Qt5OpenGL.dll"
|
||||||
File "${QT_DLL_PATH}\Qt5PrintSupport.dll"
|
File "${QT_DLL_PATH}\Qt5PrintSupport.dll"
|
||||||
File "${QT_DLL_PATH}\Qt5Qml.dll"
|
File "${QT_DLL_PATH}\Qt5Qml.dll"
|
||||||
|
File "${QT_DLL_PATH}\Qt5Quick.dll"
|
||||||
File "${QT_DLL_PATH}\Qt5Sql.dll"
|
File "${QT_DLL_PATH}\Qt5Sql.dll"
|
||||||
File "${QT_DLL_PATH}\Qt5WebKit.dll"
|
File "${QT_DLL_PATH}\Qt5WebKit.dll"
|
||||||
File "${QT_DLL_PATH}\Qt5WebKitWidgets.dll"
|
File "${QT_DLL_PATH}\Qt5WebKitWidgets.dll"
|
||||||
@@ -433,9 +435,9 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
|||||||
|
|
||||||
;Qt deps
|
;Qt deps
|
||||||
File "${MING_BIN}\libpng16-16.dll"
|
File "${MING_BIN}\libpng16-16.dll"
|
||||||
File "${MING_BIN}\icudata56.dll"
|
File "${MING_BIN}\icudata53.dll"
|
||||||
File "${MING_BIN}\icui18n56.dll"
|
File "${MING_BIN}\icui18n53.dll"
|
||||||
File "${MING_BIN}\icuuc56.dll"
|
File "${MING_BIN}\icuuc53.dll"
|
||||||
File "${MING_BIN}\libEGL.dll"
|
File "${MING_BIN}\libEGL.dll"
|
||||||
File "${MING_BIN}\libGLESv2.dll"
|
File "${MING_BIN}\libGLESv2.dll"
|
||||||
File "${MING_BIN}\libjpeg-8.dll"
|
File "${MING_BIN}\libjpeg-8.dll"
|
||||||
@@ -444,14 +446,11 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
|||||||
File "${MING_BIN}\libcrypto-10.dll"
|
File "${MING_BIN}\libcrypto-10.dll"
|
||||||
File "${MING_BIN}\libssl-10.dll"
|
File "${MING_BIN}\libssl-10.dll"
|
||||||
File "${MING_BIN}\libstdc++-6.dll"
|
File "${MING_BIN}\libstdc++-6.dll"
|
||||||
File "${MING_BIN}\libwebp-5.dll"
|
File "${MING_BIN}\libwebp-4.dll"
|
||||||
File "${MING_BIN}\libxslt-1.dll"
|
File "${MING_BIN}\libxslt-1.dll"
|
||||||
File "${MING_BIN}\libxml2-2.dll"
|
File "${MING_BIN}\libxml2-2.dll"
|
||||||
File "${MING_BIN}\zlib1.dll"
|
File "${MING_BIN}\zlib1.dll"
|
||||||
File "${MING_BIN}\libharfbuzz-0.dll"
|
File "${MING_BIN}\libsqlite3-0.dll"
|
||||||
File "${MING_BIN}\libfreetype-6.dll"
|
|
||||||
File "${MING_BIN}\libglib-2.0-0.dll"
|
|
||||||
File "${MING_BIN}\libintl-8.dll"
|
|
||||||
|
|
||||||
;QtKeyChain stuff
|
;QtKeyChain stuff
|
||||||
File "${MING_BIN}\libqt5keychain.dll"
|
File "${MING_BIN}\libqt5keychain.dll"
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ include(ConfigureChecks.cmake)
|
|||||||
|
|
||||||
|
|
||||||
set(SOURCE_DIR ${CMAKE_SOURCE_DIR})
|
set(SOURCE_DIR ${CMAKE_SOURCE_DIR})
|
||||||
|
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||||
|
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ endif (MEM_NULL_TESTS)
|
|||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
||||||
if (UNIT_TESTING)
|
if (UNIT_TESTING)
|
||||||
set(WITH_TESTING ON)
|
set(WITH_UNIT_TESTING ON)
|
||||||
|
|
||||||
find_package(CMocka)
|
find_package(CMocka)
|
||||||
if (CMOCKA_FOUND)
|
if (CMOCKA_FOUND)
|
||||||
|
|||||||
@@ -26,4 +26,4 @@
|
|||||||
#cmakedefine HAVE___MINGW_ASPRINTF 1
|
#cmakedefine HAVE___MINGW_ASPRINTF 1
|
||||||
#cmakedefine HAVE_ASPRINTF 1
|
#cmakedefine HAVE_ASPRINTF 1
|
||||||
|
|
||||||
#cmakedefine WITH_TESTING 1
|
#cmakedefine WITH_UNIT_TESTING 1
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
#define CSYNC_LOG_CATEGORY_NAME "csync.exclude"
|
#define CSYNC_LOG_CATEGORY_NAME "csync.exclude"
|
||||||
#include "csync_log.h"
|
#include "csync_log.h"
|
||||||
|
|
||||||
#ifndef WITH_TESTING
|
#ifndef WITH_UNIT_TESTING
|
||||||
static
|
static
|
||||||
#endif
|
#endif
|
||||||
int _csync_exclude_add(c_strlist_t **inList, const char *string) {
|
int _csync_exclude_add(c_strlist_t **inList, const char *string) {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ enum csync_exclude_type_e {
|
|||||||
};
|
};
|
||||||
typedef enum csync_exclude_type_e CSYNC_EXCLUDE_TYPE;
|
typedef enum csync_exclude_type_e CSYNC_EXCLUDE_TYPE;
|
||||||
|
|
||||||
#ifdef WITH_TESTING
|
#ifdef WITH_UNIT_TESTING
|
||||||
int OCSYNC_EXPORT _csync_exclude_add(c_strlist_t **inList, const char *string);
|
int OCSYNC_EXPORT _csync_exclude_add(c_strlist_t **inList, const char *string);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ struct csync_s {
|
|||||||
|
|
||||||
/* hooks for checking the white list (uses the update_callback_userdata) */
|
/* hooks for checking the white list (uses the update_callback_userdata) */
|
||||||
int (*checkSelectiveSyncBlackListHook)(void*, const char*);
|
int (*checkSelectiveSyncBlackListHook)(void*, const char*);
|
||||||
int (*checkSelectiveSyncNewFolderHook)(void*, const char* /* path */, const char* /* remotePerm */);
|
int (*checkSelectiveSyncNewFolderHook)(void*, const char*);
|
||||||
|
|
||||||
|
|
||||||
csync_vio_opendir_hook remote_opendir_hook;
|
csync_vio_opendir_hook remote_opendir_hook;
|
||||||
@@ -207,7 +207,7 @@ __attribute__ ((packed))
|
|||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
OCSYNC_EXPORT void csync_file_stat_free(csync_file_stat_t *st);
|
void csync_file_stat_free(csync_file_stat_t *st);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* context for the treewalk function
|
* context for the treewalk function
|
||||||
|
|||||||
@@ -56,15 +56,17 @@ int csync_get_statedb_exists(CSYNC *ctx);
|
|||||||
*
|
*
|
||||||
* @return 0 on success, less than 0 if an error occurred with errno set.
|
* @return 0 on success, less than 0 if an error occurred with errno set.
|
||||||
*/
|
*/
|
||||||
OCSYNC_EXPORT int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb);
|
int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb);
|
||||||
|
|
||||||
OCSYNC_EXPORT int csync_statedb_close(CSYNC *ctx);
|
int csync_statedb_close(CSYNC *ctx);
|
||||||
|
|
||||||
OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx, uint64_t phash);
|
csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx, uint64_t phash);
|
||||||
|
|
||||||
OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx, uint64_t inode);
|
csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx, uint64_t inode);
|
||||||
|
|
||||||
OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx, const char *file_id);
|
csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx, const char *file_id);
|
||||||
|
|
||||||
|
char *csync_statedb_get_etag(CSYNC *ctx, uint64_t jHash);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Query all files metadata inside and below a path.
|
* @brief Query all files metadata inside and below a path.
|
||||||
|
|||||||
@@ -436,7 +436,7 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
|||||||
st->instruction = CSYNC_INSTRUCTION_NEW;
|
st->instruction = CSYNC_INSTRUCTION_NEW;
|
||||||
|
|
||||||
if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY && ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncNewFolderHook) {
|
if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY && ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncNewFolderHook) {
|
||||||
if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path, fs->remotePerm)) {
|
if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path)) {
|
||||||
csync_file_stat_free(st);
|
csync_file_stat_free(st);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-11
@@ -77,7 +77,7 @@ a synchronization process.
|
|||||||
|
|
||||||
Before the 1.3.0 release of the Desktop Client, the synchronization process
|
Before the 1.3.0 release of the Desktop Client, the synchronization process
|
||||||
might create false conflict files if time deviates. Original and changed files
|
might create false conflict files if time deviates. Original and changed files
|
||||||
conflict only in their timestamp, but not in their content. This behavior was
|
conflict only in their timestamp, but not in their content. This behaviour was
|
||||||
changed to employ a binary check if files differ.
|
changed to employ a binary check if files differ.
|
||||||
|
|
||||||
Like files, directories also hold a unique ID that changes whenever one of the
|
Like files, directories also hold a unique ID that changes whenever one of the
|
||||||
@@ -132,16 +132,11 @@ changed and no synchronization occurs.
|
|||||||
In the event a file has changed on both the local and the remote repository
|
In the event 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
|
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 will not be lost. Instead,
|
is the one that should be used. However, changes to any side will not be lost. Instead,
|
||||||
a *conflict case* is created. The client resolves this conflict by renaming the
|
a *conflict case* is created. The client resolves this conflict by creating a
|
||||||
local file, appending a conflict label and timestamp, and saving the remote file
|
conflict file of the older of the two files and saving the newer file under the
|
||||||
under the original file name.
|
original file name. Conflict files are always created on the client and never
|
||||||
|
on the server. The conflict file uses the same name as the original file, but
|
||||||
Example: Assume there is a conflict in message.txt because its contents have
|
is appended with the timestamp of the conflict detection.
|
||||||
changed both locally and remotely since the last sync run. The local file with
|
|
||||||
the local changes will be renamed to message_conflict-20160101-153110.txt and
|
|
||||||
the remote file will be downloaded and saved as message.txt.
|
|
||||||
|
|
||||||
Conflict files are always created on the client and never on the server.
|
|
||||||
|
|
||||||
|
|
||||||
.. _ignored-files-label:
|
.. _ignored-files-label:
|
||||||
|
|||||||
+19
-2
@@ -49,6 +49,7 @@ the Linux operating system do not perform any updates on their own. The client
|
|||||||
will inform you (``Settings -> General -> Updates``) when an update is
|
will inform you (``Settings -> General -> Updates``) when an update is
|
||||||
available.
|
available.
|
||||||
|
|
||||||
|
|
||||||
Preventing Automatic Updates
|
Preventing Automatic Updates
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
@@ -109,8 +110,24 @@ To prevent automatic updates and disallow manual overrides:
|
|||||||
Preventing Automatic Updates in Mac OS X Environments
|
Preventing Automatic Updates in Mac OS X Environments
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
You can disable the automatic update mechanism, in the Mac OS X operating system,
|
You can disable the automatic update mechanism in Mac OS X operating systems
|
||||||
by copying the file
|
using the system-wide ``.plist`` file. To access this file:
|
||||||
|
|
||||||
|
1. Go to this directory::
|
||||||
|
|
||||||
|
/Library/Preferences/
|
||||||
|
|
||||||
|
2. Locate and open the following file::
|
||||||
|
|
||||||
|
com.owncloud.desktopclient.plist
|
||||||
|
|
||||||
|
3. Add a new root level item of type ``bool``.
|
||||||
|
|
||||||
|
4. Name the item ``skipUpdateCheck``.
|
||||||
|
|
||||||
|
5. Set the item to ``true``.
|
||||||
|
|
||||||
|
Alternatively, you can copy the file
|
||||||
``owncloud.app/Contents/Resources/deny_autoupdate_com.owncloud.desktopclient.plist``
|
``owncloud.app/Contents/Resources/deny_autoupdate_com.owncloud.desktopclient.plist``
|
||||||
to ``/Library/Preferences/com.owncloud.desktopclient.plist``.
|
to ``/Library/Preferences/com.owncloud.desktopclient.plist``.
|
||||||
|
|
||||||
|
|||||||
+8
-12
@@ -54,7 +54,7 @@ distribution. Make sure the repositories for source packages are enabled.
|
|||||||
Mac OS X
|
Mac OS X
|
||||||
--------
|
--------
|
||||||
|
|
||||||
In addition to needing XCode (along with the command line tools), developing in
|
In additon to needing XCode (along with the command line tools), developing in
|
||||||
the Mac OS X environment requires extra dependencies. You can install these
|
the Mac OS X environment requires extra dependencies. You can install these
|
||||||
dependencies through MacPorts_ or Homebrew_. These dependencies are required
|
dependencies through MacPorts_ or Homebrew_. These dependencies are required
|
||||||
only on the build machine, because non-standard libs are deployed in the app
|
only on the build machine, because non-standard libs are deployed in the app
|
||||||
@@ -77,29 +77,25 @@ To set up your build environment for development using HomeBrew_:
|
|||||||
|
|
||||||
brew tap owncloud/owncloud
|
brew tap owncloud/owncloud
|
||||||
|
|
||||||
5. Install a Qt5 version with qtwebkit support::
|
5. Install any missing dependencies::
|
||||||
|
|
||||||
brew install qt5 --with-qtwebkit
|
|
||||||
|
|
||||||
6. Install any missing dependencies::
|
|
||||||
|
|
||||||
brew install $(brew deps owncloud-client)
|
brew install $(brew deps owncloud-client)
|
||||||
|
|
||||||
7. Add Qt from brew to the path::
|
3. Add Qt from brew to the path::
|
||||||
|
|
||||||
export PATH=/usr/local/Cellar/qt5/5.x.y/bin:$PATH
|
export PATH=/usr/local/Cellar/qt5/5.x.y/bin:$PATH
|
||||||
|
|
||||||
Where ``x.y`` is the current version of Qt 5 that brew has installed
|
Where ``x.z`` is the current version of Qt 5 that brew has installed
|
||||||
on your machine.
|
on your machine.
|
||||||
8. Install qtkeychain from here: git clone https://github.com/frankosterfeld/qtkeychain.git
|
4. Install qtkeychain from here: git clone https://github.com/frankosterfeld/qtkeychain.git
|
||||||
make sure you make the same install prefix as later while building the client e.g. -
|
make sure you make the same install prefix as later while building the client e.g. -
|
||||||
``DCMAKE_INSTALL_PREFIX=/Path/to/client-install``
|
``DCMAKE_INSTALL_PREFIX=/Path/to/client-install``
|
||||||
|
|
||||||
9. For compilation of the client, follow the :ref:`generic-build-instructions`.
|
5. For compilation of the client, follow the :ref:`generic-build-instructions`.
|
||||||
|
|
||||||
10. Install the Packages_ package creation tool.
|
6. Install the Packages_ package creation tool.
|
||||||
|
|
||||||
11. In the build directory, run ``admin/osx/create_mac.sh <build_dir>
|
7. In the build directory, run ``admin/osx/create_mac.sh <build_dir>
|
||||||
<install_dir>``. If you have a developer signing certificate, you can specify
|
<install_dir>``. If you have a developer signing certificate, you can specify
|
||||||
its Common Name as a third parameter (use quotes) to have the package
|
its Common Name as a third parameter (use quotes) to have the package
|
||||||
signed automatically.
|
signed automatically.
|
||||||
|
|||||||
+3
-8
@@ -16,20 +16,15 @@ format. You can overwrite changes using the ownCloud configuration dialog.
|
|||||||
.. note:: Use caution when making changes to the ownCloud Client configuration
|
.. note:: Use caution when making changes to the ownCloud Client configuration
|
||||||
file. Incorrect settings can produce unintended results.
|
file. Incorrect settings can produce unintended results.
|
||||||
|
|
||||||
You can change the following configuration settings in the ``[ownCloud]`` section:
|
You can change the following configuration settings (must be under the ``[ownCloud]`` section)
|
||||||
|
|
||||||
- ``remotePollInterval`` (default: ``30000``) -- Specifies the poll time for the remote repository in milliseconds.
|
- ``remotePollInterval`` (default: ``30000``) -- Specifies the poll time for the remote repository in milliseconds.
|
||||||
|
|
||||||
- ``forceSyncInterval`` (default: ``7200000``) -- The duration of no activity after which a synchronization run shall be triggered automatically.
|
- ``maxLogLines`` (default: ``20000``) -- Specifies the maximum number of log lines displayed in the log window.
|
||||||
|
|
||||||
- ``notificationRefreshInterval`` (default: ``300000``) -- Specifies the default interval of checking for new server notifications in milliseconds.
|
|
||||||
|
|
||||||
You can change the following configuration settings in the ``[General]`` section:
|
|
||||||
|
|
||||||
- ``chunkSize`` (default: ``5242880``) -- Specifies the chunk size of uploaded files in bytes.
|
- ``chunkSize`` (default: ``5242880``) -- Specifies the chunk size of uploaded files in bytes.
|
||||||
|
|
||||||
- ``promptDeleteAllFiles`` (default: ``true``) -- If a UI prompt should ask for confirmation if it was detected that all files and folders were deleted.
|
- ``promptDeleteAllFiles`` (default: ``true``) -- If a UI prompt should ask for confirmation if it was detected that all files and folders were deleted.
|
||||||
|
|
||||||
- ``maxLogLines`` (default: ``20000``) -- Specifies the maximum number of log lines displayed in the log window.
|
- ``notificationRefreshInterval`` (default``300,000``) -- Specifies the default interval of checking for new server notifications in milliseconds.
|
||||||
|
|
||||||
- ``timeout`` (default: ``300``) -- The timeout for network connections in seconds.
|
|
||||||
|
|||||||
+6
-9
@@ -1,20 +1,17 @@
|
|||||||
FAQ
|
FAQ
|
||||||
===
|
===
|
||||||
|
|
||||||
|
**Issue:**
|
||||||
|
|
||||||
Some files are continuously uploaded to the server, even when they are not modified.
|
Some files are continuously uploaded to the server, even when they are not modified.
|
||||||
------------------------------------------------------------------------------------
|
|
||||||
|
**Resolution:**
|
||||||
|
|
||||||
It is possible that another program is changing the modification date of the file.
|
It is possible that another program is changing the modification date of the file.
|
||||||
|
|
||||||
If the file is uses the ``.eml`` extension, Windows automatically and
|
If the file is uses the ``.eml`` extension, Windows automatically and
|
||||||
continually changes all files, unless you remove
|
continually changes all files, unless you remove
|
||||||
``\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\PropertyHandlers``
|
``\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\PropertyHandlers``
|
||||||
from the windows registry.
|
from the windows registry.
|
||||||
|
|
||||||
See http://petersteier.wordpress.com/2011/10/22/windows-indexer-changes-modification-dates-of-eml-files/ for more information.
|
See http://petersteier.wordpress.com/2011/10/22/windows-indexer-changes-modification-dates-of-eml-files/ for more information.
|
||||||
|
|
||||||
Syncing breaks when attempting to sync deeper than 50 sub-directories, but the sync client does not report an error (RC=0)
|
|
||||||
--------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
The sync client has been intentionally limited to sync no deeper than
|
|
||||||
fifty sub-directories, to help prevent memory problems.
|
|
||||||
Unfortunately, it, *currently*, does not report an error when this occurs.
|
|
||||||
However, a UI notification is planned for a future release of ownCloud.
|
|
||||||
|
|||||||
@@ -51,21 +51,6 @@ Identifying Basic Functionality Problems
|
|||||||
``propget`` command to obtain various properties pertaining to the current
|
``propget`` command to obtain various properties pertaining to the current
|
||||||
directory and also verify WebDAV server connection.
|
directory and also verify WebDAV server connection.
|
||||||
|
|
||||||
"CSync unknown error"
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
If you see this error message stop your client, delete the
|
|
||||||
``.csync_journal.db`` file, and then restart your client.
|
|
||||||
There is a ``.csync_journal.db`` file inside the folder of every account
|
|
||||||
configured on your client.
|
|
||||||
|
|
||||||
.. NOTE::
|
|
||||||
Please note that this will also erase some of your settings about which
|
|
||||||
files to download.
|
|
||||||
|
|
||||||
See https://github.com/owncloud/client/issues/5226 for more discussion of this
|
|
||||||
issue.
|
|
||||||
|
|
||||||
|
|
||||||
Isolating other issues
|
Isolating other issues
|
||||||
----------------------
|
----------------------
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ Network
|
|||||||
|
|
||||||
.. index:: proxy settings, SOCKS, bandwith, throttling, limiting
|
.. index:: proxy settings, SOCKS, bandwith, throttling, limiting
|
||||||
|
|
||||||
This tab consolidates ``Proxy Settings`` and ``Bandwith Limiting``:
|
This tab consollidates ``Proxy Settings`` and ``Bandwith Limiting``:
|
||||||
|
|
||||||
.. image:: images/settings_network.png
|
.. image:: images/settings_network.png
|
||||||
:scale: 50 %
|
:scale: 50 %
|
||||||
@@ -152,7 +152,7 @@ Proxy Settings
|
|||||||
On Linux, this will only pick up the value of the variable ``http_proxy``.
|
On Linux, this will only pick up the value of the variable ``http_proxy``.
|
||||||
* ``Specify proxy manually as``: Allows to specify custom proxy settings.
|
* ``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
|
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 particularly
|
Forefront TMG, pick ``HTTP(S)``. ``SOCKSv5`` on the other hand is particulary
|
||||||
useful in special company LAN setups, or in combination with the OpenSSH
|
useful in special company LAN setups, or in combination with the OpenSSH
|
||||||
dynamic application level forwarding feature (see ``ssh -D``).
|
dynamic application level forwarding feature (see ``ssh -D``).
|
||||||
* ``Host``: Enter the host name or IP address of your proxy server, followed
|
* ``Host``: Enter the host name or IP address of your proxy server, followed
|
||||||
|
|||||||
@@ -37,10 +37,6 @@ Operating system:
|
|||||||
|
|
||||||
OS language:
|
OS language:
|
||||||
|
|
||||||
Qt version used by client package (Linux only, see also Settings dialog):
|
|
||||||
|
|
||||||
Client package (From ownCloud or distro) (Linux only):
|
|
||||||
|
|
||||||
Installation path of client:
|
Installation path of client:
|
||||||
|
|
||||||
### Logs
|
### Logs
|
||||||
|
|||||||
+8
-107
@@ -625,96 +625,6 @@ X-GNOME-Autostart-Delay=3
|
|||||||
# Translations
|
# Translations
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
Comment[oc]=@APPLICATION_NAME@ sincronizacion del client
|
Comment[oc]=@APPLICATION_NAME@ sincronizacion del client
|
||||||
GenericName[oc]=Dorsièr de Sincronizacion
|
GenericName[oc]=Dorsièr de Sincronizacion
|
||||||
@@ -740,9 +650,7 @@ Comment[ja_JP]=@APPLICATION_NAME@ デスクトップ同期クライアント
|
|||||||
GenericName[ja_JP]=フォルダー同期
|
GenericName[ja_JP]=フォルダー同期
|
||||||
Name[ja_JP]=@APPLICATION_NAME@ デスクトップ同期クライアント
|
Name[ja_JP]=@APPLICATION_NAME@ デスクトップ同期クライアント
|
||||||
Icon[ja_JP]=@APPLICATION_EXECUTABLE@
|
Icon[ja_JP]=@APPLICATION_EXECUTABLE@
|
||||||
Comment[el]=@ΟΝΟΜΑ_ΕΦΑΡΜΟΓΗΣ@ συγχρονισμός επιφάνειας εργασίας πελάτη
|
|
||||||
GenericName[el]=Συγχρονισμός φακέλου
|
GenericName[el]=Συγχρονισμός φακέλου
|
||||||
Name[el]=@ΟΝΟΜΑ_ΕΦΑΡΜΟΓΗΣ@ συγχρονισμός επιφάνειας εργασίας πελάτη
|
|
||||||
Icon[el]=@APPLICATION_EXECUTABLE@
|
Icon[el]=@APPLICATION_EXECUTABLE@
|
||||||
Comment[en_GB]=@APPLICATION_NAME@ desktop synchronisation client
|
Comment[en_GB]=@APPLICATION_NAME@ desktop synchronisation client
|
||||||
GenericName[en_GB]=Folder Sync
|
GenericName[en_GB]=Folder Sync
|
||||||
@@ -756,13 +664,10 @@ Comment[de_DE]=@APPLICATION_NAME@ Desktop-Synchronisationsclient
|
|||||||
GenericName[de_DE]=Ordner-Synchronisation
|
GenericName[de_DE]=Ordner-Synchronisation
|
||||||
Name[de_DE]=@APPLICATION_NAME@ Desktop-Synchronisationsclient
|
Name[de_DE]=@APPLICATION_NAME@ Desktop-Synchronisationsclient
|
||||||
Icon[de_DE]=@APPLICATION_EXECUTABLE@
|
Icon[de_DE]=@APPLICATION_EXECUTABLE@
|
||||||
Comment[bg_BG]=@APPLICATION_NAME@ клиент за десктоп синхронизация
|
Comment[pl]=@APPLICATION_NAME@ klient synchronizacji dla komputerów stacjonarnych
|
||||||
GenericName[bg_BG]=Синхронизиране на папката
|
GenericName[pl]=Folder Synchronizacji
|
||||||
Name[bg_BG]=@APPLICATION_NAME@ клиент десктоп синхронизация
|
Name[pl]=@APPLICATION_NAME@ klient synchronizacji dla komputerów stacjonarnych
|
||||||
Icon[bg_BG]=@APPLICATION_EXECUTABLE@
|
Icon[pl]=@APPLICATION_EXECUTABLE@
|
||||||
GenericName[fa]=همسان سازی پوشهها
|
|
||||||
Name[fa]=@APPLICATION_EXECUTABLE@ نسخهی همسان سازی مشتری
|
|
||||||
Icon[fa]=@APPLICATION_EXECUTABLE@
|
|
||||||
Comment[fr]=@APPLICATION_NAME@ synchronisation du client
|
Comment[fr]=@APPLICATION_NAME@ synchronisation du client
|
||||||
GenericName[fr]=Dossier de Synchronisation
|
GenericName[fr]=Dossier de Synchronisation
|
||||||
Name[fr]=@APPLICATION_NAME@ synchronisation du client
|
Name[fr]=@APPLICATION_NAME@ synchronisation du client
|
||||||
@@ -771,10 +676,6 @@ Comment[he]=@APPLICATION_NAME@ לקוח סנכון שולחן עבודה
|
|||||||
GenericName[he]=סנכון תיקייה
|
GenericName[he]=סנכון תיקייה
|
||||||
Name[he]=@APPLICATION_NAME@ לקוח סנכרון שולחן עבודה
|
Name[he]=@APPLICATION_NAME@ לקוח סנכרון שולחן עבודה
|
||||||
Icon[he]=@APPLICATION_EXECUTABLE@
|
Icon[he]=@APPLICATION_EXECUTABLE@
|
||||||
Comment[ia]=@APPLICATION_NAME@ cliente de synchronisation pro scriptorio
|
|
||||||
GenericName[ia]=Synchronisar Dossier
|
|
||||||
Name[ia]=@APPLICATION_NAME@ cliente de synchronisation pro scriptorio
|
|
||||||
Icon[ia]=@APPLICATION_EXECUTABLE@
|
|
||||||
Comment[id]=Klien sinkronisasi desktop @APPLICATION_NAME@
|
Comment[id]=Klien sinkronisasi desktop @APPLICATION_NAME@
|
||||||
GenericName[id]=Folder Sync
|
GenericName[id]=Folder Sync
|
||||||
Name[id]=Klien sync desktop @APPLICATION_NAME@
|
Name[id]=Klien sync desktop @APPLICATION_NAME@
|
||||||
@@ -802,10 +703,10 @@ Comment[et_EE]=@APPLICATION_NAME@ sünkroonimise klient töölauale
|
|||||||
GenericName[et_EE]=Kaustade sünkroonimine
|
GenericName[et_EE]=Kaustade sünkroonimine
|
||||||
Name[et_EE]=@APPLICATION_NAME@ sünkroonimise klient töölauale
|
Name[et_EE]=@APPLICATION_NAME@ sünkroonimise klient töölauale
|
||||||
Icon[et_EE]=@APPLICATION_EXECUTABLE@
|
Icon[et_EE]=@APPLICATION_EXECUTABLE@
|
||||||
Comment[pl]=@APPLICATION_NAME@ klient synchronizacji dla komputerów stacjonarnych
|
Comment[bg_BG]=@APPLICATION_NAME@ клиент за десктоп синхронизация
|
||||||
GenericName[pl]=Folder Synchronizacji
|
GenericName[bg_BG]=Синхронизиране на папката
|
||||||
Name[pl]=@APPLICATION_NAME@ klient synchronizacji dla komputerów stacjonarnych
|
Name[bg_BG]=@APPLICATION_NAME@ клиент десктоп синхронизация
|
||||||
Icon[pl]=@APPLICATION_EXECUTABLE@
|
Icon[bg_BG]=@APPLICATION_EXECUTABLE@
|
||||||
Comment[pt_BR]=@APPLICATION_NAME@ cliente de sincronização do computador
|
Comment[pt_BR]=@APPLICATION_NAME@ cliente de sincronização do computador
|
||||||
GenericName[pt_BR]=Sincronização de Pasta
|
GenericName[pt_BR]=Sincronização de Pasta
|
||||||
Name[pt_BR]=@APPLICATION_NAME@ cliente de sincronização de desktop
|
Name[pt_BR]=@APPLICATION_NAME@ cliente de sincronização de desktop
|
||||||
|
|||||||
@@ -16,13 +16,12 @@ set(OC_OEM_SHARE_ICNS "${CMAKE_BINARY_DIR}/src/gui/ownCloud.icns")
|
|||||||
# those user-defined settings to build the plist.
|
# those user-defined settings to build the plist.
|
||||||
add_custom_target( mac_overlayplugin ALL
|
add_custom_target( mac_overlayplugin ALL
|
||||||
xcodebuild -project ${CMAKE_SOURCE_DIR}/shell_integration/MacOSX/OwnCloudFinderSync/OwnCloudFinderSync.xcodeproj
|
xcodebuild -project ${CMAKE_SOURCE_DIR}/shell_integration/MacOSX/OwnCloudFinderSync/OwnCloudFinderSync.xcodeproj
|
||||||
-target FinderSyncExt -configuration Release "SYMROOT=${CMAKE_CURRENT_BINARY_DIR}"
|
-target FinderSyncExt -configuration Release SYMROOT=${CMAKE_CURRENT_BINARY_DIR}
|
||||||
"OC_OEM_SHARE_ICNS=${OC_OEM_SHARE_ICNS}"
|
OC_OEM_SHARE_ICNS=${OC_OEM_SHARE_ICNS}
|
||||||
"OC_APPLICATION_NAME=${APPLICATION_NAME}"
|
OC_APPLICATION_NAME="${APPLICATION_NAME}"
|
||||||
"OC_APPLICATION_REV_DOMAIN=${APPLICATION_REV_DOMAIN}"
|
OC_APPLICATION_REV_DOMAIN=${APPLICATION_REV_DOMAIN}
|
||||||
"OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX=${SOCKETAPI_TEAM_IDENTIFIER_PREFIX}"
|
OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX=${SOCKETAPI_TEAM_IDENTIFIER_PREFIX}
|
||||||
COMMENT building Mac Overlay icons
|
COMMENT building Mac Overlay icons)
|
||||||
VERBATIM)
|
|
||||||
add_dependencies(mac_overlayplugin ${APPLICATION_EXECUTABLE}) # for the ownCloud.icns to be generated
|
add_dependencies(mac_overlayplugin ${APPLICATION_EXECUTABLE}) # for the ownCloud.icns to be generated
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -155,13 +155,9 @@
|
|||||||
{
|
{
|
||||||
_shareMenuTitle = nil;
|
_shareMenuTitle = nil;
|
||||||
|
|
||||||
[_registeredDirectories removeAllObjects];
|
|
||||||
// For some reason the FIFinderSync cache doesn't seem to be cleared for the root item when
|
|
||||||
// we reset the directoryURLs (seen on macOS 10.12 at least).
|
|
||||||
// First setting it to the FS root and then setting it to nil seems to work around the issue.
|
|
||||||
[FIFinderSyncController defaultController].directoryURLs = [NSSet setWithObject:[NSURL fileURLWithPath:@"/"]];
|
|
||||||
// This will tell Finder that this extension isn't attached to any directory
|
// This will tell Finder that this extension isn't attached to any directory
|
||||||
// until we can reconnect to the sync client.
|
// until we can reconnect to the sync client.
|
||||||
|
[_registeredDirectories removeAllObjects];
|
||||||
[FIFinderSyncController defaultController].directoryURLs = nil;
|
[FIFinderSyncController defaultController].directoryURLs = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -152,9 +152,8 @@ IFACEMETHODIMP OCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT
|
|||||||
|
|
||||||
OCClientInterface::ContextMenuInfo info = OCClientInterface::FetchInfo();
|
OCClientInterface::ContextMenuInfo info = OCClientInterface::FetchInfo();
|
||||||
bool skip = true;
|
bool skip = true;
|
||||||
size_t selectedFileLength = wcslen(m_szSelectedFile);
|
|
||||||
for (const std::wstring path : info.watchedDirectories) {
|
for (const std::wstring path : info.watchedDirectories) {
|
||||||
if (StringUtil::isDescendantOf(m_szSelectedFile, selectedFileLength, path)) {
|
if (StringUtil::begins_with(std::wstring(m_szSelectedFile), path)) {
|
||||||
skip = false;
|
skip = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU Lesser General Public License as published by the Free
|
||||||
|
* Software Foundation; either version 2.1 of the License, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||||
|
* details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "OCContextMenu.h"
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
#define IDM_SHARE 0
|
||||||
|
|
||||||
|
OCContextMenu::OCContextMenu()
|
||||||
|
: m_pwszVerb(0)
|
||||||
|
, m_referenceCount(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
OCContextMenu::~OCContextMenu()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
IFACEMETHODIMP_(ULONG) OCContextMenu::AddRef()
|
||||||
|
{
|
||||||
|
return InterlockedIncrement(&m_referenceCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
IFACEMETHODIMP_(ULONG) OCContextMenu::Release()
|
||||||
|
{
|
||||||
|
ULONG cRef = InterlockedDecrement(&m_referenceCount);
|
||||||
|
if (0 == cRef)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
IFACEMETHODIMP OCContextMenu::QueryInterface(REFIID riid, void **ppv)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
if (IsEqualIID(IID_IUnknown, riid) || IsEqualIID(IID_IContextMenu, riid))
|
||||||
|
{
|
||||||
|
*ppv = static_cast<IContextMenu *>(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hr = E_NOINTERFACE;
|
||||||
|
*ppv = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ppv)
|
||||||
|
{
|
||||||
|
AddRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
IFACEMETHODIMP OCContextMenu::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
|
||||||
|
{
|
||||||
|
HRESULT hr = E_INVALIDARG;
|
||||||
|
|
||||||
|
if (idCmd == IDM_SHARE)
|
||||||
|
{
|
||||||
|
switch (uFlags)
|
||||||
|
{
|
||||||
|
case GCS_HELPTEXTW:
|
||||||
|
hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName), cchMax, L"Shares file or directory with ownCloud");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GCS_VERBW:
|
||||||
|
// GCS_VERBW is an optional feature that enables a caller
|
||||||
|
// to discover the canonical name for the verb that is passed in
|
||||||
|
// through idCommand.
|
||||||
|
hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName), cchMax, L"ownCloudShare");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
|
||||||
|
{
|
||||||
|
if (pici->cbSize == sizeof(CMINVOKECOMMANDINFOEX) &&
|
||||||
|
(pici->fMask & CMIC_MASK_UNICODE))
|
||||||
|
{
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
||||||
|
if (HIWORD(((CMINVOKECOMMANDINFOEX *)pici)->lpVerbW))
|
||||||
|
{
|
||||||
|
if (StrCmpIW(((CMINVOKECOMMANDINFOEX *)pici)->lpVerbW, m_pwszVerb))
|
||||||
|
{
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LOWORD(pici->lpVerb) != IDM_SHARE) {
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageBox(pici->hwnd,
|
||||||
|
L"ownCloud was here",
|
||||||
|
L"ownCloud was here",
|
||||||
|
MB_OK | MB_ICONINFORMATION);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
IFACEMETHODIMP OCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
if (!(CMF_DEFAULTONLY & uFlags))
|
||||||
|
{
|
||||||
|
InsertMenu(hMenu, indexMenu, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SHARE, L"&Share with ownCloud");
|
||||||
|
}
|
||||||
|
hr = StringCbCopyW(m_pwszVerb, sizeof(m_pwszVerb), L"ownCloudShare");
|
||||||
|
|
||||||
|
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_SHARE + 1));
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU Lesser General Public License as published by the Free
|
||||||
|
* Software Foundation; either version 2.1 of the License, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||||
|
* details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OCCONTEXTMENU_H
|
||||||
|
#define OCCONTEXTMENU_H
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ShObjIdl.h"
|
||||||
|
#include "memory"
|
||||||
|
|
||||||
|
class OCContextMenu :public IContextMenu
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OCContextMenu();
|
||||||
|
~OCContextMenu();
|
||||||
|
|
||||||
|
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||||||
|
IFACEMETHODIMP_(ULONG) AddRef();
|
||||||
|
IFACEMETHODIMP_(ULONG) Release();
|
||||||
|
|
||||||
|
|
||||||
|
IFACEMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax);
|
||||||
|
IFACEMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici);
|
||||||
|
IFACEMETHODIMP QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
|
||||||
|
private:
|
||||||
|
TCHAR* m_pwszVerb;
|
||||||
|
long m_referenceCount;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //OCCONTEXTMENU_H
|
||||||
@@ -129,16 +129,14 @@ IFACEMETHODIMP OCOverlay::GetPriority(int *pPriority)
|
|||||||
IFACEMETHODIMP OCOverlay::IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib)
|
IFACEMETHODIMP OCOverlay::IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib)
|
||||||
{
|
{
|
||||||
RemotePathChecker* checker = getGlobalChecker();
|
RemotePathChecker* checker = getGlobalChecker();
|
||||||
std::shared_ptr<const std::vector<std::wstring>> watchedDirectories = checker->WatchedDirectories();
|
auto watchedDirectories = checker->WatchedDirectories();
|
||||||
|
|
||||||
if (watchedDirectories->empty()) {
|
|
||||||
return MAKE_HRESULT(S_FALSE, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
wstring wpath(pwszPath);
|
||||||
|
wpath.append(L"\\");
|
||||||
|
vector<wstring>::iterator it;
|
||||||
bool watched = false;
|
bool watched = false;
|
||||||
size_t pathLength = wcslen(pwszPath);
|
for (it = watchedDirectories.begin(); it != watchedDirectories.end(); ++it) {
|
||||||
for (auto it = watchedDirectories->begin(); it != watchedDirectories->end(); ++it) {
|
if (StringUtil::begins_with(wpath, *it)) {
|
||||||
if (StringUtil::isDescendantOf(pwszPath, pathLength, *it)) {
|
|
||||||
watched = true;
|
watched = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,3 +166,20 @@ IFACEMETHODIMP OCOverlay::GetOverlayInfo(PWSTR pwszIconFile, int cchMax, int *pI
|
|||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool OCOverlay::_IsOverlaysEnabled()
|
||||||
|
{
|
||||||
|
//int enable;
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
//if(RegistryUtil::ReadRegistry(REGISTRY_ROOT_KEY, REGISTRY_ENABLE_OVERLAY, &enable))
|
||||||
|
//{
|
||||||
|
// if(enable) {
|
||||||
|
// success = true;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ protected:
|
|||||||
~OCOverlay();
|
~OCOverlay();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool _IsOverlaysEnabled();
|
||||||
long _referenceCount;
|
long _referenceCount;
|
||||||
int _state;
|
int _state;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -75,39 +75,30 @@ void RemotePathChecker::workerThreadLoop()
|
|||||||
if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) {
|
if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) {
|
||||||
wstring responsePath = response.substr(14); // length of REGISTER_PATH:
|
wstring responsePath = response.substr(14); // length of REGISTER_PATH:
|
||||||
|
|
||||||
auto sharedPtrCopy = atomic_load(&_watchedDirectories);
|
{ std::unique_lock<std::mutex> lock(_mutex);
|
||||||
auto vectorCopy = make_shared<vector<wstring>>(*sharedPtrCopy);
|
_watchedDirectories.push_back(responsePath);
|
||||||
vectorCopy->push_back(responsePath);
|
}
|
||||||
atomic_store(&_watchedDirectories, shared_ptr<const vector<wstring>>(vectorCopy));
|
|
||||||
|
|
||||||
// We don't keep track of all files and can't know which file is currently visible
|
|
||||||
// to the user, but at least reload the root dir so that any shortcut to the root
|
|
||||||
// is updated without the user needing to refresh.
|
|
||||||
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
|
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
|
||||||
} else if (StringUtil::begins_with(response, wstring(L"UNREGISTER_PATH:"))) {
|
} else if (StringUtil::begins_with(response, wstring(L"UNREGISTER_PATH:"))) {
|
||||||
wstring responsePath = response.substr(16); // length of UNREGISTER_PATH:
|
wstring responsePath = response.substr(16); // length of UNREGISTER_PATH:
|
||||||
|
|
||||||
auto sharedPtrCopy = atomic_load(&_watchedDirectories);
|
|
||||||
auto vectorCopy = make_shared<vector<wstring>>(*sharedPtrCopy);
|
|
||||||
vectorCopy->erase(
|
|
||||||
std::remove(vectorCopy->begin(), vectorCopy->end(), responsePath),
|
|
||||||
vectorCopy->end());
|
|
||||||
atomic_store(&_watchedDirectories, shared_ptr<const vector<wstring>>(vectorCopy));
|
|
||||||
|
|
||||||
vector<wstring> removedPaths;
|
|
||||||
{ std::unique_lock<std::mutex> lock(_mutex);
|
{ std::unique_lock<std::mutex> lock(_mutex);
|
||||||
|
_watchedDirectories.erase(
|
||||||
|
std::remove(_watchedDirectories.begin(), _watchedDirectories.end(), responsePath),
|
||||||
|
_watchedDirectories.end());
|
||||||
|
|
||||||
// Remove any item from the cache
|
// Remove any item from the cache
|
||||||
for (auto it = _cache.begin(); it != _cache.end() ; ) {
|
for (auto it = _cache.begin(); it != _cache.end() ; ) {
|
||||||
if (StringUtil::isDescendantOf(it->first, responsePath)) {
|
if (StringUtil::begins_with(it->first, responsePath)) {
|
||||||
removedPaths.emplace_back(move(it->first));
|
|
||||||
it = _cache.erase(it);
|
it = _cache.erase(it);
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Assume that we won't need this at this point, UNREGISTER_PATH is rare
|
||||||
|
_oldCache.clear();
|
||||||
}
|
}
|
||||||
for (auto& path : removedPaths)
|
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
|
||||||
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, path.data(), NULL);
|
|
||||||
} else if (StringUtil::begins_with(response, wstring(L"STATUS:")) ||
|
} else if (StringUtil::begins_with(response, wstring(L"STATUS:")) ||
|
||||||
StringUtil::begins_with(response, wstring(L"BROADCAST:"))) {
|
StringUtil::begins_with(response, wstring(L"BROADCAST:"))) {
|
||||||
|
|
||||||
@@ -125,42 +116,43 @@ void RemotePathChecker::workerThreadLoop()
|
|||||||
auto state = _StrToFileState(responseStatus);
|
auto state = _StrToFileState(responseStatus);
|
||||||
bool wasAsked = asked.erase(responsePath) > 0;
|
bool wasAsked = asked.erase(responsePath) > 0;
|
||||||
|
|
||||||
bool updateView = false;
|
bool changed = false;
|
||||||
{ std::unique_lock<std::mutex> lock(_mutex);
|
{ std::unique_lock<std::mutex> lock(_mutex);
|
||||||
auto it = _cache.find(responsePath);
|
bool wasCached = _cache.find(responsePath) != _cache.end();
|
||||||
if (it == _cache.end()) {
|
if (wasAsked || wasCached) {
|
||||||
// The client only approximates requested files, if the bloom
|
auto &it = _cache[responsePath];
|
||||||
// filter becomes saturated after navigating multiple directories we'll start getting
|
changed = (it != state);
|
||||||
// status pushes that we never requested and fill our cache. Ignore those.
|
it = state;
|
||||||
if (!wasAsked) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
it = _cache.insert(make_pair(responsePath, StateNone)).first;
|
|
||||||
}
|
}
|
||||||
|
if (changed) {
|
||||||
updateView = it->second != state;
|
|
||||||
it->second = state;
|
|
||||||
}
|
|
||||||
if (updateView) {
|
|
||||||
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
|
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else if (StringUtil::begins_with(response, wstring(L"UPDATE_VIEW"))) {
|
||||||
|
|
||||||
if (socket.Event() == INVALID_HANDLE_VALUE) {
|
|
||||||
atomic_store(&_watchedDirectories, make_shared<const vector<wstring>>());
|
|
||||||
std::unique_lock<std::mutex> lock(_mutex);
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
_connected = connected = false;
|
// Keep the old states to continue having something to display while the new state is
|
||||||
|
// requested from the client, triggered by clearing _cache.
|
||||||
|
_oldCache.insert(_cache.cbegin(), _cache.cend());
|
||||||
|
|
||||||
// Swap to make a copy of the cache under the mutex and clear the one stored.
|
// Swap to make a copy of the cache under the mutex and clear the one stored.
|
||||||
std::unordered_map<std::wstring, FileState> cache;
|
std::unordered_map<std::wstring, FileState> cache;
|
||||||
swap(cache, _cache);
|
swap(cache, _cache);
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
// Let explorer know about each invalidated cache entry that needs to get its icon removed.
|
// Let explorer know about the invalidated cache entries, it will re-request the ones it needs.
|
||||||
for (auto it = cache.begin(); it != cache.end(); ++it) {
|
for (auto it = cache.begin(); it != cache.end(); ++it) {
|
||||||
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, it->first.data(), NULL);
|
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, it->first.data(), NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket.Event() == INVALID_HANDLE_VALUE) {
|
||||||
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
|
_cache.clear();
|
||||||
|
_oldCache.clear();
|
||||||
|
_watchedDirectories.clear();
|
||||||
|
_connected = connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (_stop) return;
|
if (_stop) return;
|
||||||
|
|
||||||
@@ -172,8 +164,7 @@ void RemotePathChecker::workerThreadLoop()
|
|||||||
|
|
||||||
|
|
||||||
RemotePathChecker::RemotePathChecker()
|
RemotePathChecker::RemotePathChecker()
|
||||||
: _watchedDirectories(make_shared<const vector<wstring>>())
|
: _connected(false)
|
||||||
, _connected(false)
|
|
||||||
, _newQueries(CreateEvent(NULL, true, true, NULL))
|
, _newQueries(CreateEvent(NULL, true, true, NULL))
|
||||||
, _thread([this]{ this->workerThreadLoop(); })
|
, _thread([this]{ this->workerThreadLoop(); })
|
||||||
{
|
{
|
||||||
@@ -188,9 +179,10 @@ RemotePathChecker::~RemotePathChecker()
|
|||||||
CloseHandle(_newQueries);
|
CloseHandle(_newQueries);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const std::vector<std::wstring>> RemotePathChecker::WatchedDirectories() const
|
vector<wstring> RemotePathChecker::WatchedDirectories()
|
||||||
{
|
{
|
||||||
return atomic_load(&_watchedDirectories);
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
|
return _watchedDirectories;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state)
|
bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state)
|
||||||
@@ -206,16 +198,21 @@ bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state)
|
|||||||
|
|
||||||
auto it = _cache.find(path);
|
auto it = _cache.find(path);
|
||||||
if (it != _cache.end()) {
|
if (it != _cache.end()) {
|
||||||
// The path is in our cache, and we'll get updates pushed if the status changes.
|
|
||||||
*state = it->second;
|
*state = it->second;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Re-request the status while we display what we have in _oldCache
|
||||||
_pending.push(filePath);
|
_pending.push(filePath);
|
||||||
|
|
||||||
|
it = _oldCache.find(path);
|
||||||
|
bool foundInOldCache = it != _oldCache.end();
|
||||||
|
if (foundInOldCache)
|
||||||
|
*state = it->second;
|
||||||
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
SetEvent(_newQueries);
|
SetEvent(_newQueries);
|
||||||
return false;
|
return foundInOldCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
RemotePathChecker::FileState RemotePathChecker::_StrToFileState(const std::wstring &str)
|
RemotePathChecker::FileState RemotePathChecker::_StrToFileState(const std::wstring &str)
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
@@ -38,7 +37,7 @@ public:
|
|||||||
};
|
};
|
||||||
RemotePathChecker();
|
RemotePathChecker();
|
||||||
~RemotePathChecker();
|
~RemotePathChecker();
|
||||||
std::shared_ptr<const std::vector<std::wstring>> WatchedDirectories() const;
|
std::vector<std::wstring> WatchedDirectories();
|
||||||
bool IsMonitoredPath(const wchar_t* filePath, int* state);
|
bool IsMonitoredPath(const wchar_t* filePath, int* state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -53,9 +52,8 @@ private:
|
|||||||
std::queue<std::wstring> _pending;
|
std::queue<std::wstring> _pending;
|
||||||
|
|
||||||
std::unordered_map<std::wstring, FileState> _cache;
|
std::unordered_map<std::wstring, FileState> _cache;
|
||||||
// The vector is const since it will be accessed from multiple threads through OCOverlay::IsMemberOf.
|
std::unordered_map<std::wstring, FileState> _oldCache;
|
||||||
// Each modification needs to be made onto a copy and then atomically replaced in the shared_ptr.
|
std::vector<std::wstring> _watchedDirectories;
|
||||||
std::shared_ptr<const std::vector<std::wstring>> _watchedDirectories;
|
|
||||||
bool _connected;
|
bool _connected;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,21 +29,6 @@ public:
|
|||||||
return input.size() >= match.size()
|
return input.size() >= match.size()
|
||||||
&& std::equal(match.begin(), match.end(), input.begin());
|
&& std::equal(match.begin(), match.end(), input.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isDescendantOf(const std::wstring& child, const std::wstring& parent) {
|
|
||||||
return isDescendantOf(child.c_str(), child.size(), parent.c_str(), parent.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isDescendantOf(PCWSTR child, size_t childLength, const std::wstring& parent) {
|
|
||||||
return isDescendantOf(child, childLength, parent.c_str(), parent.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isDescendantOf(PCWSTR child, size_t childLength, PCWSTR parent, size_t parentLength) {
|
|
||||||
if (!parentLength)
|
|
||||||
return false;
|
|
||||||
return (childLength == parentLength || childLength > parentLength && (child[parentLength] == L'\\' || child[parentLength - 1] == L'\\'))
|
|
||||||
&& wcsncmp(child, parent, parentLength) == 0;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // STRINGUTIL_H
|
#endif // STRINGUTIL_H
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
// This is the number that will end up in the version window of the DLLs.
|
// This is the number that will end up in the version window of the DLLs.
|
||||||
// Increment this version before committing a new build if you are today's shell_integration build master.
|
// Increment this version before committing a new build if you are today's shell_integration build master.
|
||||||
#define OCEXT_BUILD_NUM 44
|
#define OCEXT_BUILD_NUM 43
|
||||||
|
|
||||||
#define STRINGIZE2(s) #s
|
#define STRINGIZE2(s) #s
|
||||||
#define STRINGIZE(s) STRINGIZE2(s)
|
#define STRINGIZE(s) STRINGIZE2(s)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# TODO: OSX and LIB_ONLY seem to require this to go to binary dir only
|
# TODO: OSX and LIB_ONLY seem to require this to go to binary dir only
|
||||||
if(NOT TOKEN_AUTH_ONLY)
|
if(NOT TOKEN_AUTH_ONLY)
|
||||||
endif()
|
endif()
|
||||||
|
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||||
|
|
||||||
set(synclib_NAME ${APPLICATION_EXECUTABLE}sync)
|
set(synclib_NAME ${APPLICATION_EXECUTABLE}sync)
|
||||||
|
|
||||||
|
|||||||
@@ -46,17 +46,11 @@ AccountManager *AccountManager::instance()
|
|||||||
bool AccountManager::restore()
|
bool AccountManager::restore()
|
||||||
{
|
{
|
||||||
auto settings = Utility::settingsWithGroup(QLatin1String(accountsC));
|
auto settings = Utility::settingsWithGroup(QLatin1String(accountsC));
|
||||||
if (settings->status() != QSettings::NoError) {
|
|
||||||
qDebug() << "Could not read settings from" << settings->fileName()
|
|
||||||
<< settings->status();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are no accounts, check the old format.
|
// If there are no accounts, check the old format.
|
||||||
if (settings->childGroups().isEmpty()
|
if (settings->childGroups().isEmpty()
|
||||||
&& !settings->contains(QLatin1String(versionC))) {
|
&& !settings->contains(QLatin1String(versionC))) {
|
||||||
restoreFromLegacySettings();
|
return restoreFromLegacySettings();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (const auto& accountId, settings->childGroups()) {
|
foreach (const auto& accountId, settings->childGroups()) {
|
||||||
@@ -75,9 +69,6 @@ bool AccountManager::restore()
|
|||||||
|
|
||||||
bool AccountManager::restoreFromLegacySettings()
|
bool AccountManager::restoreFromLegacySettings()
|
||||||
{
|
{
|
||||||
qDebug() << "Migrate: restoreFromLegacySettings, checking settings group"
|
|
||||||
<< Theme::instance()->appName();
|
|
||||||
|
|
||||||
// try to open the correctly themed settings
|
// try to open the correctly themed settings
|
||||||
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
|
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
|
||||||
|
|
||||||
@@ -95,7 +86,7 @@ bool AccountManager::restoreFromLegacySettings()
|
|||||||
|
|
||||||
QFileInfo fi( oCCfgFile );
|
QFileInfo fi( oCCfgFile );
|
||||||
if( fi.isReadable() ) {
|
if( fi.isReadable() ) {
|
||||||
std::unique_ptr<QSettings> oCSettings(new QSettings(oCCfgFile, QSettings::IniFormat));
|
QSettings *oCSettings = new QSettings(oCCfgFile, QSettings::IniFormat);
|
||||||
oCSettings->beginGroup(QLatin1String("ownCloud"));
|
oCSettings->beginGroup(QLatin1String("ownCloud"));
|
||||||
|
|
||||||
// Check the theme url to see if it is the same url that the oC config was for
|
// Check the theme url to see if it is the same url that the oC config was for
|
||||||
@@ -110,7 +101,9 @@ bool AccountManager::restoreFromLegacySettings()
|
|||||||
qDebug() << "Migrate oC config if " << oCUrl << " == " << overrideUrl << ":"
|
qDebug() << "Migrate oC config if " << oCUrl << " == " << overrideUrl << ":"
|
||||||
<< (oCUrl == overrideUrl ? "Yes" : "No");
|
<< (oCUrl == overrideUrl ? "Yes" : "No");
|
||||||
if( oCUrl == overrideUrl ) {
|
if( oCUrl == overrideUrl ) {
|
||||||
settings = std::move(oCSettings);
|
settings.reset( oCSettings );
|
||||||
|
} else {
|
||||||
|
delete oCSettings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,8 +196,8 @@ void AccountManager::saveAccountHelper(Account* acc, QSettings& settings, bool s
|
|||||||
if (acc->_am) {
|
if (acc->_am) {
|
||||||
CookieJar* jar = qobject_cast<CookieJar*>(acc->_am->cookieJar());
|
CookieJar* jar = qobject_cast<CookieJar*>(acc->_am->cookieJar());
|
||||||
if (jar) {
|
if (jar) {
|
||||||
qDebug() << "Saving cookies." << acc->cookieJarPath();
|
qDebug() << "Saving cookies.";
|
||||||
jar->save(acc->cookieJarPath());
|
jar->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,9 +235,6 @@ AccountPtr AccountManager::loadAccountHelper(QSettings& settings)
|
|||||||
} else {
|
} else {
|
||||||
acc->setUrl(urlConfig.toUrl());
|
acc->setUrl(urlConfig.toUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "Account for" << acc->url() << "using auth type" << authType;
|
|
||||||
|
|
||||||
acc->_serverVersion = settings.value(QLatin1String(serverVersionC)).toString();
|
acc->_serverVersion = settings.value(QLatin1String(serverVersionC)).toString();
|
||||||
|
|
||||||
// We want to only restore settings for that auth type and the user value
|
// We want to only restore settings for that auth type and the user value
|
||||||
@@ -296,8 +286,6 @@ void AccountManager::deleteAccount(AccountState* account)
|
|||||||
auto copy = *it; // keep a reference to the shared pointer so it does not delete it just yet
|
auto copy = *it; // keep a reference to the shared pointer so it does not delete it just yet
|
||||||
_accounts.erase(it);
|
_accounts.erase(it);
|
||||||
|
|
||||||
QFile::remove(account->account()->cookieJarPath());
|
|
||||||
|
|
||||||
auto settings = Utility::settingsWithGroup(QLatin1String(accountsC));
|
auto settings = Utility::settingsWithGroup(QLatin1String(accountsC));
|
||||||
settings->remove(account->account()->id());
|
settings->remove(account->account()->id());
|
||||||
|
|
||||||
|
|||||||
@@ -36,9 +36,7 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates account objects from a given settings file.
|
* Creates account objects from a given settings file.
|
||||||
*
|
* return true if the account was restored
|
||||||
* Returns false if there was an error reading the settings,
|
|
||||||
* but note that settings not existing is not an error.
|
|
||||||
*/
|
*/
|
||||||
bool restore();
|
bool restore();
|
||||||
|
|
||||||
|
|||||||
@@ -675,13 +675,8 @@ void AccountSettings::refreshSelectiveSyncStatus()
|
|||||||
ui->selectiveSyncButtons->setVisible(true);
|
ui->selectiveSyncButtons->setVisible(true);
|
||||||
ui->bigFolderUi->setVisible(false);
|
ui->bigFolderUi->setVisible(false);
|
||||||
} else {
|
} else {
|
||||||
ConfigFile cfg;
|
QString wholeMsg = tr("There are new folders that were not synchronized because they are too big: ") + msg;
|
||||||
QString info =
|
ui->selectiveSyncNotification->setText(wholeMsg);
|
||||||
!cfg.confirmExternalStorage() ? tr("There are folders that were not synchronized because they are too big: ") :
|
|
||||||
!cfg.newBigFolderSizeLimit().first ? tr("There are folders that were not synchronized because they are external storages: ") :
|
|
||||||
tr("There are folders that were not synchronized because they are too big or external storages: ");
|
|
||||||
|
|
||||||
ui->selectiveSyncNotification->setText(info + msg);
|
|
||||||
ui->selectiveSyncButtons->setVisible(false);
|
ui->selectiveSyncButtons->setVisible(false);
|
||||||
ui->bigFolderUi->setVisible(true);
|
ui->bigFolderUi->setVisible(true);
|
||||||
shouldBeVisible = true;
|
shouldBeVisible = true;
|
||||||
|
|||||||
@@ -156,23 +156,7 @@ Application::Application(int &argc, char **argv) :
|
|||||||
|
|
||||||
connect(this, SIGNAL(messageReceived(QString, QObject*)), SLOT(slotParseMessage(QString, QObject*)));
|
connect(this, SIGNAL(messageReceived(QString, QObject*)), SLOT(slotParseMessage(QString, QObject*)));
|
||||||
|
|
||||||
if (!AccountManager::instance()->restore()) {
|
AccountManager::instance()->restore();
|
||||||
// If there is an error reading the account settings, try again
|
|
||||||
// after a couple of seconds, if that fails, give up.
|
|
||||||
// (non-existence is not an error)
|
|
||||||
Utility::sleep(5);
|
|
||||||
if (!AccountManager::instance()->restore()) {
|
|
||||||
qDebug() << "Could not read the account settings, quitting";
|
|
||||||
QMessageBox::critical(
|
|
||||||
0,
|
|
||||||
tr("Error accessing the configuration file"),
|
|
||||||
tr("There was an error while accessing the configuration "
|
|
||||||
"file at %1.").arg(ConfigFile().configFile()),
|
|
||||||
tr("Quit ownCloud"));
|
|
||||||
QTimer::singleShot(0, qApp, SLOT(quit()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FolderMan::instance()->setSyncEnabled(true);
|
FolderMan::instance()->setSyncEnabled(true);
|
||||||
|
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ void ShibbolethCredentials::fetchFromKeychain()
|
|||||||
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
|
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
|
||||||
job->setSettings(Utility::settingsWithGroup(Theme::instance()->appName(), job).release());
|
job->setSettings(Utility::settingsWithGroup(Theme::instance()->appName(), job).release());
|
||||||
job->setInsecureFallback(false);
|
job->setInsecureFallback(false);
|
||||||
job->setKey(keychainKey(_account->url().toString(), user()));
|
job->setKey(keychainKey(_account->url().toString(), "shibAssertion"));
|
||||||
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
|
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
@@ -309,7 +309,7 @@ void ShibbolethCredentials::storeShibCookie(const QNetworkCookie &cookie)
|
|||||||
job->setSettings(Utility::settingsWithGroup(Theme::instance()->appName(), job).release());
|
job->setSettings(Utility::settingsWithGroup(Theme::instance()->appName(), job).release());
|
||||||
// we don't really care if it works...
|
// we don't really care if it works...
|
||||||
//connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteJobDone(QKeychain::Job*)));
|
//connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteJobDone(QKeychain::Job*)));
|
||||||
job->setKey(keychainKey(_account->url().toString(), user()));
|
job->setKey(keychainKey(_account->url().toString(), "shibAssertion"));
|
||||||
job->setTextData(QString::fromUtf8(cookie.toRawForm()));
|
job->setTextData(QString::fromUtf8(cookie.toRawForm()));
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
@@ -318,7 +318,7 @@ void ShibbolethCredentials::removeShibCookie()
|
|||||||
{
|
{
|
||||||
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
||||||
job->setSettings(Utility::settingsWithGroup(Theme::instance()->appName(), job).release());
|
job->setSettings(Utility::settingsWithGroup(Theme::instance()->appName(), job).release());
|
||||||
job->setKey(keychainKey(_account->url().toString(), user()));
|
job->setKey(keychainKey(_account->url().toString(), "shibAssertion"));
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+164
-65
@@ -46,13 +46,17 @@
|
|||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
|
const char oldJournalPath[] = ".csync_journal.db";
|
||||||
|
|
||||||
Folder::Folder(const FolderDefinition& definition,
|
Folder::Folder(const FolderDefinition& definition,
|
||||||
AccountState* accountState,
|
AccountState* accountState,
|
||||||
QObject* parent)
|
QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, _accountState(accountState)
|
, _accountState(accountState)
|
||||||
, _definition(definition)
|
, _definition(definition)
|
||||||
|
, _csyncError(false)
|
||||||
, _csyncUnavail(false)
|
, _csyncUnavail(false)
|
||||||
|
, _wipeDb(false)
|
||||||
, _proxyDirty(true)
|
, _proxyDirty(true)
|
||||||
, _lastSyncDuration(0)
|
, _lastSyncDuration(0)
|
||||||
, _consecutiveFailingSyncs(0)
|
, _consecutiveFailingSyncs(0)
|
||||||
@@ -85,6 +89,8 @@ Folder::Folder(const FolderDefinition& definition,
|
|||||||
|
|
||||||
connect(_accountState.data(), SIGNAL(isConnectedChanged()), this, SIGNAL(canSyncChanged()));
|
connect(_accountState.data(), SIGNAL(isConnectedChanged()), this, SIGNAL(canSyncChanged()));
|
||||||
connect(_engine.data(), SIGNAL(rootEtag(QString)), this, SLOT(etagRetreivedFromSyncEngine(QString)));
|
connect(_engine.data(), SIGNAL(rootEtag(QString)), this, SLOT(etagRetreivedFromSyncEngine(QString)));
|
||||||
|
connect(_engine.data(), SIGNAL(treeWalkResult(const SyncFileItemVector&)),
|
||||||
|
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection);
|
||||||
|
|
||||||
connect(_engine.data(), SIGNAL(started()), SLOT(slotSyncStarted()), Qt::QueuedConnection);
|
connect(_engine.data(), SIGNAL(started()), SLOT(slotSyncStarted()), Qt::QueuedConnection);
|
||||||
connect(_engine.data(), SIGNAL(finished(bool)), SLOT(slotSyncFinished(bool)), Qt::QueuedConnection);
|
connect(_engine.data(), SIGNAL(finished(bool)), SLOT(slotSyncFinished(bool)), Qt::QueuedConnection);
|
||||||
@@ -98,10 +104,9 @@ Folder::Folder(const FolderDefinition& definition,
|
|||||||
SLOT(slotAboutToRestoreBackup(bool*)));
|
SLOT(slotAboutToRestoreBackup(bool*)));
|
||||||
connect(_engine.data(), SIGNAL(folderDiscovered(bool,QString)), this, SLOT(slotFolderDiscovered(bool,QString)));
|
connect(_engine.data(), SIGNAL(folderDiscovered(bool,QString)), this, SLOT(slotFolderDiscovered(bool,QString)));
|
||||||
connect(_engine.data(), SIGNAL(transmissionProgress(ProgressInfo)), this, SLOT(slotTransmissionProgress(ProgressInfo)));
|
connect(_engine.data(), SIGNAL(transmissionProgress(ProgressInfo)), this, SLOT(slotTransmissionProgress(ProgressInfo)));
|
||||||
connect(_engine.data(), SIGNAL(itemCompleted(const SyncFileItemPtr &)),
|
connect(_engine.data(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)),
|
||||||
this, SLOT(slotItemCompleted(const SyncFileItemPtr &)));
|
this, SLOT(slotItemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||||
connect(_engine.data(), SIGNAL(newBigFolder(QString,bool)),
|
connect(_engine.data(), SIGNAL(newBigFolder(QString)), this, SLOT(slotNewBigFolderDiscovered(QString)));
|
||||||
this, SLOT(slotNewBigFolderDiscovered(QString,bool)));
|
|
||||||
connect(_engine.data(), SIGNAL(seenLockedFile(QString)), FolderMan::instance(), SLOT(slotSyncOnceFileUnlocks(QString)));
|
connect(_engine.data(), SIGNAL(seenLockedFile(QString)), FolderMan::instance(), SLOT(slotSyncOnceFileUnlocks(QString)));
|
||||||
connect(_engine.data(), SIGNAL(aboutToPropagate(SyncFileItemVector&)),
|
connect(_engine.data(), SIGNAL(aboutToPropagate(SyncFileItemVector&)),
|
||||||
SLOT(slotLogPropagationStart()));
|
SLOT(slotLogPropagationStart()));
|
||||||
@@ -135,13 +140,13 @@ void Folder::checkLocalPath()
|
|||||||
} else {
|
} else {
|
||||||
// Check directory again
|
// Check directory again
|
||||||
if( !FileSystem::fileExists(_definition.localPath, fi) ) {
|
if( !FileSystem::fileExists(_definition.localPath, fi) ) {
|
||||||
_syncResult.appendErrorString(tr("Local folder %1 does not exist.").arg(_definition.localPath));
|
_syncResult.setErrorString(tr("Local folder %1 does not exist.").arg(_definition.localPath));
|
||||||
_syncResult.setStatus( SyncResult::SetupError );
|
_syncResult.setStatus( SyncResult::SetupError );
|
||||||
} else if( !fi.isDir() ) {
|
} else if( !fi.isDir() ) {
|
||||||
_syncResult.appendErrorString(tr("%1 should be a folder but is not.").arg(_definition.localPath));
|
_syncResult.setErrorString(tr("%1 should be a folder but is not.").arg(_definition.localPath));
|
||||||
_syncResult.setStatus( SyncResult::SetupError );
|
_syncResult.setStatus( SyncResult::SetupError );
|
||||||
} else if( !fi.isReadable() ) {
|
} else if( !fi.isReadable() ) {
|
||||||
_syncResult.appendErrorString(tr("%1 is not readable.").arg(_definition.localPath));
|
_syncResult.setErrorString(tr("%1 is not readable.").arg(_definition.localPath));
|
||||||
_syncResult.setStatus( SyncResult::SetupError );
|
_syncResult.setStatus( SyncResult::SetupError );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -264,8 +269,8 @@ SyncResult Folder::syncResult() const
|
|||||||
|
|
||||||
void Folder::prepareToSync()
|
void Folder::prepareToSync()
|
||||||
{
|
{
|
||||||
_syncResult.reset();
|
|
||||||
_syncResult.setStatus( SyncResult::NotYetStarted );
|
_syncResult.setStatus( SyncResult::NotYetStarted );
|
||||||
|
_syncResult.clearErrors();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::slotRunEtagJob()
|
void Folder::slotRunEtagJob()
|
||||||
@@ -319,33 +324,120 @@ void Folder::etagRetreivedFromSyncEngine(const QString& etag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Folder::showSyncResultPopup()
|
void Folder::bubbleUpSyncResult()
|
||||||
{
|
{
|
||||||
if( _syncResult.firstItemNew() ) {
|
// count new, removed and updated items
|
||||||
createGuiLog( _syncResult.firstItemNew()->_file, LogStatusNew, _syncResult.numNewItems() );
|
int newItems = 0;
|
||||||
|
int removedItems = 0;
|
||||||
|
int updatedItems = 0;
|
||||||
|
int ignoredItems = 0;
|
||||||
|
int renamedItems = 0;
|
||||||
|
int conflictItems = 0;
|
||||||
|
int errorItems = 0;
|
||||||
|
|
||||||
|
SyncFileItemPtr firstItemNew;
|
||||||
|
SyncFileItemPtr firstItemDeleted;
|
||||||
|
SyncFileItemPtr firstItemUpdated;
|
||||||
|
SyncFileItemPtr firstItemRenamed;
|
||||||
|
SyncFileItemPtr firstConflictItem;
|
||||||
|
SyncFileItemPtr firstItemError;
|
||||||
|
|
||||||
|
QElapsedTimer timer;
|
||||||
|
timer.start();
|
||||||
|
|
||||||
|
foreach (const SyncFileItemPtr &item, _syncResult.syncFileItemVector() ) {
|
||||||
|
// Process the item to the gui
|
||||||
|
if( item->_status == SyncFileItem::FatalError || item->_status == SyncFileItem::NormalError ) {
|
||||||
|
//: this displays an error string (%2) for a file %1
|
||||||
|
slotSyncError( tr("%1: %2").arg(item->_file, item->_errorString) );
|
||||||
|
errorItems++;
|
||||||
|
if (!firstItemError) {
|
||||||
|
firstItemError = item;
|
||||||
}
|
}
|
||||||
if( _syncResult.firstItemDeleted() ) {
|
} else if( item->_status == SyncFileItem::FileIgnored ) {
|
||||||
createGuiLog( _syncResult.firstItemDeleted()->_file, LogStatusRemove, _syncResult.numRemovedItems() );
|
// ignored files don't show up in notifications
|
||||||
|
continue;
|
||||||
|
} else if( item->_status == SyncFileItem::Conflict ) {
|
||||||
|
conflictItems++;
|
||||||
|
if (!firstConflictItem) {
|
||||||
|
firstConflictItem = item;
|
||||||
}
|
}
|
||||||
if( _syncResult.firstItemUpdated() ) {
|
} else {
|
||||||
createGuiLog( _syncResult.firstItemUpdated()->_file, LogStatusUpdated, _syncResult.numUpdatedItems() );
|
// add new directories or remove gone away dirs to the watcher
|
||||||
|
if (item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_NEW ) {
|
||||||
|
FolderMan::instance()->addMonitorPath( alias(), path()+item->_file );
|
||||||
|
}
|
||||||
|
if (item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_REMOVE ) {
|
||||||
|
FolderMan::instance()->removeMonitorPath( alias(), path()+item->_file );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( _syncResult.firstItemRenamed() ) {
|
if (!item->hasErrorStatus() && item->_direction == SyncFileItem::Down) {
|
||||||
|
switch (item->_instruction) {
|
||||||
|
case CSYNC_INSTRUCTION_NEW:
|
||||||
|
case CSYNC_INSTRUCTION_TYPE_CHANGE:
|
||||||
|
newItems++;
|
||||||
|
if (!firstItemNew)
|
||||||
|
firstItemNew = item;
|
||||||
|
break;
|
||||||
|
case CSYNC_INSTRUCTION_REMOVE:
|
||||||
|
removedItems++;
|
||||||
|
if (!firstItemDeleted)
|
||||||
|
firstItemDeleted = item;
|
||||||
|
break;
|
||||||
|
case CSYNC_INSTRUCTION_SYNC:
|
||||||
|
updatedItems++;
|
||||||
|
if (!firstItemUpdated)
|
||||||
|
firstItemUpdated = item;
|
||||||
|
break;
|
||||||
|
case CSYNC_INSTRUCTION_ERROR:
|
||||||
|
qDebug() << "Got Instruction ERROR. " << _syncResult.errorString();
|
||||||
|
break;
|
||||||
|
case CSYNC_INSTRUCTION_RENAME:
|
||||||
|
if (!firstItemRenamed) {
|
||||||
|
firstItemRenamed = item;
|
||||||
|
}
|
||||||
|
renamedItems++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// nothing.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if( item->_direction == SyncFileItem::None ) { // ignored files counting.
|
||||||
|
if( item->_instruction == CSYNC_INSTRUCTION_IGNORE ) {
|
||||||
|
ignoredItems++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Processing result list and logging took " << timer.elapsed() << " Milliseconds.";
|
||||||
|
_syncResult.setWarnCount(ignoredItems);
|
||||||
|
|
||||||
|
if( firstItemNew ) {
|
||||||
|
createGuiLog( firstItemNew->_file, LogStatusNew, newItems );
|
||||||
|
}
|
||||||
|
if( firstItemDeleted ) {
|
||||||
|
createGuiLog( firstItemDeleted->_file, LogStatusRemove, removedItems );
|
||||||
|
}
|
||||||
|
if( firstItemUpdated ) {
|
||||||
|
createGuiLog( firstItemUpdated->_file, LogStatusUpdated, updatedItems );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( firstItemRenamed ) {
|
||||||
LogStatus status(LogStatusRename);
|
LogStatus status(LogStatusRename);
|
||||||
// if the path changes it's rather a move
|
// if the path changes it's rather a move
|
||||||
QDir renTarget = QFileInfo(_syncResult.firstItemRenamed()->_renameTarget).dir();
|
QDir renTarget = QFileInfo(firstItemRenamed->_renameTarget).dir();
|
||||||
QDir renSource = QFileInfo(_syncResult.firstItemRenamed()->_file).dir();
|
QDir renSource = QFileInfo(firstItemRenamed->_file).dir();
|
||||||
if(renTarget != renSource) {
|
if(renTarget != renSource) {
|
||||||
status = LogStatusMove;
|
status = LogStatusMove;
|
||||||
}
|
}
|
||||||
createGuiLog( _syncResult.firstItemRenamed()->_originalFile, status, _syncResult.numRenamedItems(), _syncResult.firstItemRenamed()->_renameTarget );
|
createGuiLog( firstItemRenamed->_originalFile, status, renamedItems, firstItemRenamed->_renameTarget );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( _syncResult.firstConflictItem() ) {
|
if( firstConflictItem ) {
|
||||||
createGuiLog( _syncResult.firstConflictItem()->_file, LogStatusConflict, _syncResult.numConflictItems() );
|
createGuiLog( firstConflictItem->_file, LogStatusConflict, conflictItems );
|
||||||
}
|
}
|
||||||
createGuiLog( _syncResult.firstItemError()->_file, LogStatusError, _syncResult.numErrorItems() );
|
createGuiLog( firstItemError->_file, LogStatusError, errorItems );
|
||||||
|
|
||||||
qDebug() << "OO folder slotSyncFinished: result: " << int(_syncResult.status());
|
qDebug() << "OO folder slotSyncFinished: result: " << int(_syncResult.status());
|
||||||
}
|
}
|
||||||
@@ -484,6 +576,12 @@ void Folder::slotWatchedPathChanged(const QString& path)
|
|||||||
scheduleThisFolderSoon();
|
scheduleThisFolderSoon();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Folder::slotThreadTreeWalkResult(const SyncFileItemVector& items)
|
||||||
|
{
|
||||||
|
_syncResult.setSyncFileItemVector(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Folder::saveToSettings() const
|
void Folder::saveToSettings() const
|
||||||
{
|
{
|
||||||
// Remove first to make sure we don't get duplicates
|
// Remove first to make sure we don't get duplicates
|
||||||
@@ -546,6 +644,9 @@ void Folder::slotTerminateSync()
|
|||||||
if( _engine->isSyncRunning() ) {
|
if( _engine->isSyncRunning() ) {
|
||||||
_engine->abort();
|
_engine->abort();
|
||||||
|
|
||||||
|
// Do not display an error message, user knows his own actions.
|
||||||
|
// _errors.append( tr("The CSync thread terminated.") );
|
||||||
|
// _csyncError = true;
|
||||||
setSyncState(SyncResult::SyncAbortRequested);
|
setSyncState(SyncResult::SyncAbortRequested);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -593,9 +694,10 @@ bool Folder::setIgnoredFiles()
|
|||||||
// a QSet of files to load.
|
// a QSet of files to load.
|
||||||
ConfigFile cfg;
|
ConfigFile cfg;
|
||||||
QString systemList = cfg.excludeFile(ConfigFile::SystemScope);
|
QString systemList = cfg.excludeFile(ConfigFile::SystemScope);
|
||||||
|
if( QFile::exists(systemList) ) {
|
||||||
qDebug() << "==== adding system ignore list to csync:" << systemList;
|
qDebug() << "==== adding system ignore list to csync:" << systemList;
|
||||||
_engine->excludedFiles().addExcludeFilePath(systemList);
|
_engine->excludedFiles().addExcludeFilePath(systemList);
|
||||||
|
}
|
||||||
QString userList = cfg.excludeFile(ConfigFile::UserScope);
|
QString userList = cfg.excludeFile(ConfigFile::UserScope);
|
||||||
if( QFile::exists(userList) ) {
|
if( QFile::exists(userList) ) {
|
||||||
qDebug() << "==== adding user defined ignore list to csync:" << userList;
|
qDebug() << "==== adding user defined ignore list to csync:" << userList;
|
||||||
@@ -626,17 +728,19 @@ void Folder::startSync(const QStringList &pathList)
|
|||||||
qCritical() << "* ERROR csync is still running and new sync requested.";
|
qCritical() << "* ERROR csync is still running and new sync requested.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
_errors.clear();
|
||||||
|
_csyncError = false;
|
||||||
_csyncUnavail = false;
|
_csyncUnavail = false;
|
||||||
|
|
||||||
_timeSinceLastSyncStart.restart();
|
_timeSinceLastSyncStart.restart();
|
||||||
|
_syncResult.clearErrors();
|
||||||
_syncResult.setStatus( SyncResult::SyncPrepare );
|
_syncResult.setStatus( SyncResult::SyncPrepare );
|
||||||
|
_syncResult.setSyncFileItemVector(SyncFileItemVector());
|
||||||
emit syncStateChange();
|
emit syncStateChange();
|
||||||
|
|
||||||
qDebug() << "*** Start syncing " << remoteUrl().toString() << " - client version"
|
qDebug() << "*** Start syncing " << remoteUrl().toString() << " - client version"
|
||||||
<< qPrintable(Theme::instance()->version());
|
<< qPrintable(Theme::instance()->version());
|
||||||
|
|
||||||
_fileLog->start(path());
|
|
||||||
|
|
||||||
if (!setIgnoredFiles())
|
if (!setIgnoredFiles())
|
||||||
{
|
{
|
||||||
slotSyncError(tr("Could not read system exclude file"));
|
slotSyncError(tr("Could not read system exclude file"));
|
||||||
@@ -646,15 +750,15 @@ void Folder::startSync(const QStringList &pathList)
|
|||||||
|
|
||||||
setDirtyNetworkLimits();
|
setDirtyNetworkLimits();
|
||||||
|
|
||||||
SyncOptions opt;
|
|
||||||
ConfigFile cfgFile;
|
ConfigFile cfgFile;
|
||||||
auto newFolderLimit = cfgFile.newBigFolderSizeLimit();
|
auto newFolderLimit = cfgFile.newBigFolderSizeLimit();
|
||||||
opt._newBigFolderSizeLimit = newFolderLimit.first ? newFolderLimit.second * 1000LL * 1000LL : -1; // convert from MB to B
|
quint64 limit = newFolderLimit.first ? newFolderLimit.second * 1000 * 1000 : -1; // convert from MB to B
|
||||||
opt._confirmExternalStorage = cfgFile.confirmExternalStorage();
|
_engine->setNewBigFolderSizeLimit(limit);
|
||||||
_engine->setSyncOptions(opt);
|
|
||||||
|
|
||||||
_engine->setIgnoreHiddenFiles(_definition.ignoreHiddenFiles);
|
_engine->setIgnoreHiddenFiles(_definition.ignoreHiddenFiles);
|
||||||
|
|
||||||
|
_fileLog->start(path());
|
||||||
|
|
||||||
QMetaObject::invokeMethod(_engine.data(), "startSync", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(_engine.data(), "startSync", Qt::QueuedConnection);
|
||||||
|
|
||||||
emit syncStarted();
|
emit syncStarted();
|
||||||
@@ -685,7 +789,8 @@ void Folder::setDirtyNetworkLimits()
|
|||||||
|
|
||||||
void Folder::slotSyncError(const QString& err)
|
void Folder::slotSyncError(const QString& err)
|
||||||
{
|
{
|
||||||
_syncResult.appendErrorString(err);
|
_errors.append( err );
|
||||||
|
_csyncError = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::slotSyncStarted()
|
void Folder::slotSyncStarted()
|
||||||
@@ -709,24 +814,27 @@ void Folder::slotSyncFinished(bool success)
|
|||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
bool syncError = !_syncResult.errorStrings().isEmpty();
|
|
||||||
if( syncError ) {
|
if( _csyncError ) {
|
||||||
qDebug() << "-> SyncEngine finished with ERROR";
|
qDebug() << "-> SyncEngine finished with ERROR, warn count is" << _syncResult.warnCount();
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "-> SyncEngine finished without problem.";
|
qDebug() << "-> SyncEngine finished without problem.";
|
||||||
}
|
}
|
||||||
_fileLog->finish();
|
_fileLog->finish();
|
||||||
showSyncResultPopup();
|
bubbleUpSyncResult();
|
||||||
|
|
||||||
auto anotherSyncNeeded = _engine->isAnotherSyncNeeded();
|
auto anotherSyncNeeded = _engine->isAnotherSyncNeeded();
|
||||||
|
|
||||||
if (syncError) {
|
if (_csyncError) {
|
||||||
_syncResult.setStatus(SyncResult::Error);
|
_syncResult.setStatus(SyncResult::Error);
|
||||||
|
qDebug() << " ** error Strings: " << _errors;
|
||||||
|
_syncResult.setErrorStrings( _errors );
|
||||||
qDebug() << " * owncloud csync thread finished with error";
|
qDebug() << " * owncloud csync thread finished with error";
|
||||||
} else if (_csyncUnavail) {
|
} else if (_csyncUnavail) {
|
||||||
_syncResult.setStatus(SyncResult::Error);
|
_syncResult.setStatus(SyncResult::Error);
|
||||||
qDebug() << " ** csync not available.";
|
qDebug() << " ** csync not available.";
|
||||||
} else if( _syncResult.foundFilesNotSynced() ) {
|
} else if( _syncResult.warnCount() > 0 ) {
|
||||||
|
// there have been warnings on the way.
|
||||||
_syncResult.setStatus(SyncResult::Problem);
|
_syncResult.setStatus(SyncResult::Problem);
|
||||||
} else if( _definition.paused ) {
|
} else if( _definition.paused ) {
|
||||||
// Maybe the sync was terminated because the user paused the folder
|
// Maybe the sync was terminated because the user paused the folder
|
||||||
@@ -803,28 +911,26 @@ void Folder::slotFolderDiscovered(bool, QString folderName)
|
|||||||
// and hand the result over to the progress dispatcher.
|
// and hand the result over to the progress dispatcher.
|
||||||
void Folder::slotTransmissionProgress(const ProgressInfo &pi)
|
void Folder::slotTransmissionProgress(const ProgressInfo &pi)
|
||||||
{
|
{
|
||||||
|
if( !pi.isUpdatingEstimates() ) {
|
||||||
|
// this is the beginning of a sync, set the warning level to 0
|
||||||
|
_syncResult.setWarnCount(0);
|
||||||
|
}
|
||||||
emit progressInfo(pi);
|
emit progressInfo(pi);
|
||||||
ProgressDispatcher::instance()->setProgressInfo(alias(), pi);
|
ProgressDispatcher::instance()->setProgressInfo(alias(), pi);
|
||||||
}
|
}
|
||||||
|
|
||||||
// a item is completed: count the errors and forward to the ProgressDispatcher
|
// a item is completed: count the errors and forward to the ProgressDispatcher
|
||||||
void Folder::slotItemCompleted(const SyncFileItemPtr &item)
|
void Folder::slotItemCompleted(const SyncFileItem &item, const PropagatorJob& job)
|
||||||
{
|
{
|
||||||
// add new directories or remove gone away dirs to the watcher
|
if (Progress::isWarningKind(item._status)) {
|
||||||
if (item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_NEW ) {
|
// Count all error conditions.
|
||||||
FolderMan::instance()->addMonitorPath( alias(), path()+item->_file );
|
_syncResult.setWarnCount(_syncResult.warnCount()+1);
|
||||||
}
|
}
|
||||||
if (item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_REMOVE ) {
|
_fileLog->logItem(item);
|
||||||
FolderMan::instance()->removeMonitorPath( alias(), path()+item->_file );
|
emit ProgressDispatcher::instance()->itemCompleted(alias(), item, job);
|
||||||
}
|
}
|
||||||
|
|
||||||
_syncResult.processCompletedItem(item);
|
void Folder::slotNewBigFolderDiscovered(const QString &newF)
|
||||||
|
|
||||||
_fileLog->logItem(*item);
|
|
||||||
emit ProgressDispatcher::instance()->itemCompleted(alias(), item);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Folder::slotNewBigFolderDiscovered(const QString &newF, bool isExternal)
|
|
||||||
{
|
{
|
||||||
auto newFolder = newF;
|
auto newFolder = newF;
|
||||||
if (!newFolder.endsWith(QLatin1Char('/'))) {
|
if (!newFolder.endsWith(QLatin1Char('/'))) {
|
||||||
@@ -849,11 +955,9 @@ void Folder::slotNewBigFolderDiscovered(const QString &newF, bool isExternal)
|
|||||||
journal->setSelectiveSyncList(SyncJournalDb::SelectiveSyncUndecidedList, undecidedList);
|
journal->setSelectiveSyncList(SyncJournalDb::SelectiveSyncUndecidedList, undecidedList);
|
||||||
emit newBigFolderDiscovered(newFolder);
|
emit newBigFolderDiscovered(newFolder);
|
||||||
}
|
}
|
||||||
QString message = !isExternal ?
|
QString message = tr("A new folder larger than %1 MB has been added: %2.\n"
|
||||||
(tr("A new folder larger than %1 MB has been added: %2.\n")
|
"Please go in the settings to select it if you wish to download it.")
|
||||||
.arg(ConfigFile().newBigFolderSizeLimit().second).arg(newF))
|
.arg(ConfigFile().newBigFolderSizeLimit().second).arg(newF);
|
||||||
: (tr("A folder from an external storage has been added.\n"));
|
|
||||||
message += tr("Please go in the settings to select it if you wish to download it.");
|
|
||||||
|
|
||||||
auto logger = Logger::instance();
|
auto logger = Logger::instance();
|
||||||
logger->postOptionalGuiLog(Theme::instance()->appNameGUI(), message);
|
logger->postOptionalGuiLog(Theme::instance()->appNameGUI(), message);
|
||||||
@@ -882,22 +986,17 @@ void Folder::setSaveBackwardsCompatible(bool save)
|
|||||||
_saveBackwardsCompatible = save;
|
_saveBackwardsCompatible = save;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction dir, bool *cancel)
|
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool *cancel)
|
||||||
{
|
{
|
||||||
ConfigFile cfgFile;
|
ConfigFile cfgFile;
|
||||||
if (!cfgFile.promptDeleteFiles())
|
if (!cfgFile.promptDeleteFiles())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QString msg = dir == SyncFileItem::Down ?
|
QString msg =
|
||||||
tr("All files in the sync folder '%1' folder were deleted on the server.\n"
|
tr("This sync would remove all the files in the sync folder '%1'.\n"
|
||||||
"These deletes will be synchronized to your local sync folder, making such files "
|
"This might be because the folder was silently reconfigured, or that all "
|
||||||
"unavailable unless you have a right to restore. \n"
|
"the files were manually removed.\n"
|
||||||
"If you decide to keep the files, they will be re-synced with the server if you have rights to do so.\n"
|
"Are you sure you want to perform this operation?");
|
||||||
"If you decide to delete the files, they will be unavailable to you, unless you are the owner.") :
|
|
||||||
tr("All the files in your local sync folder '%1' were deleted. These deletes will be "
|
|
||||||
"synchronized with your server, making such files unavailable unless restored.\n"
|
|
||||||
"Are you sure you want to sync those actions with the server?\n"
|
|
||||||
"If this was an accident and you decide to keep your files, they will be re-synced from the server.");
|
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Remove All Files?"),
|
QMessageBox msgBox(QMessageBox::Warning, tr("Remove All Files?"),
|
||||||
msg.arg(shortGuiLocalPath()));
|
msg.arg(shortGuiLocalPath()));
|
||||||
msgBox.addButton(tr("Remove all files"), QMessageBox::DestructiveRole);
|
msgBox.addButton(tr("Remove all files"), QMessageBox::DestructiveRole);
|
||||||
|
|||||||
+8
-3
@@ -280,15 +280,17 @@ private slots:
|
|||||||
|
|
||||||
void slotFolderDiscovered(bool local, QString folderName);
|
void slotFolderDiscovered(bool local, QString folderName);
|
||||||
void slotTransmissionProgress(const ProgressInfo& pi);
|
void slotTransmissionProgress(const ProgressInfo& pi);
|
||||||
void slotItemCompleted(const SyncFileItemPtr&);
|
void slotItemCompleted(const SyncFileItem&, const PropagatorJob&);
|
||||||
|
|
||||||
void slotRunEtagJob();
|
void slotRunEtagJob();
|
||||||
void etagRetreived(const QString &);
|
void etagRetreived(const QString &);
|
||||||
void etagRetreivedFromSyncEngine(const QString &);
|
void etagRetreivedFromSyncEngine(const QString &);
|
||||||
|
|
||||||
|
void slotThreadTreeWalkResult(const SyncFileItemVector& ); // after sync is done
|
||||||
|
|
||||||
void slotEmitFinishedDelayed();
|
void slotEmitFinishedDelayed();
|
||||||
|
|
||||||
void slotNewBigFolderDiscovered(const QString &, bool isExternal);
|
void slotNewBigFolderDiscovered(const QString &);
|
||||||
|
|
||||||
void slotLogPropagationStart();
|
void slotLogPropagationStart();
|
||||||
|
|
||||||
@@ -300,7 +302,7 @@ private slots:
|
|||||||
private:
|
private:
|
||||||
bool setIgnoredFiles();
|
bool setIgnoredFiles();
|
||||||
|
|
||||||
void showSyncResultPopup();
|
void bubbleUpSyncResult();
|
||||||
|
|
||||||
void checkLocalPath();
|
void checkLocalPath();
|
||||||
|
|
||||||
@@ -323,7 +325,10 @@ private:
|
|||||||
|
|
||||||
SyncResult _syncResult;
|
SyncResult _syncResult;
|
||||||
QScopedPointer<SyncEngine> _engine;
|
QScopedPointer<SyncEngine> _engine;
|
||||||
|
QStringList _errors;
|
||||||
|
bool _csyncError;
|
||||||
bool _csyncUnavail;
|
bool _csyncUnavail;
|
||||||
|
bool _wipeDb;
|
||||||
bool _proxyDirty;
|
bool _proxyDirty;
|
||||||
QPointer<RequestEtagJob> _requestEtagJob;
|
QPointer<RequestEtagJob> _requestEtagJob;
|
||||||
QString _lastEtag;
|
QString _lastEtag;
|
||||||
|
|||||||
+9
-10
@@ -23,7 +23,6 @@
|
|||||||
#include "accountmanager.h"
|
#include "accountmanager.h"
|
||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
#include "lockwatcher.h"
|
#include "lockwatcher.h"
|
||||||
#include "asserts.h"
|
|
||||||
#include <syncengine.h>
|
#include <syncengine.h>
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
@@ -49,7 +48,7 @@ FolderMan::FolderMan(QObject *parent) :
|
|||||||
_lockWatcher(new LockWatcher),
|
_lockWatcher(new LockWatcher),
|
||||||
_appRestartRequired(false)
|
_appRestartRequired(false)
|
||||||
{
|
{
|
||||||
ASSERT(!_instance);
|
Q_ASSERT(!_instance);
|
||||||
_instance = this;
|
_instance = this;
|
||||||
|
|
||||||
_socketApi.reset(new SocketApi);
|
_socketApi.reset(new SocketApi);
|
||||||
@@ -116,7 +115,7 @@ void FolderMan::unloadFolder( Folder *f )
|
|||||||
disconnect(f, SIGNAL(syncPausedChanged(Folder*,bool)),
|
disconnect(f, SIGNAL(syncPausedChanged(Folder*,bool)),
|
||||||
this, SLOT(slotFolderSyncPaused(Folder*,bool)));
|
this, SLOT(slotFolderSyncPaused(Folder*,bool)));
|
||||||
disconnect(&f->syncEngine().syncFileStatusTracker(), SIGNAL(fileStatusChanged(const QString &, SyncFileStatus)),
|
disconnect(&f->syncEngine().syncFileStatusTracker(), SIGNAL(fileStatusChanged(const QString &, SyncFileStatus)),
|
||||||
_socketApi.data(), SLOT(broadcastStatusPushMessage(const QString &, SyncFileStatus)));
|
_socketApi.data(), SLOT(slotFileStatusChanged(const QString &, SyncFileStatus)));
|
||||||
disconnect(f, SIGNAL(watchedFileChangedExternally(QString)),
|
disconnect(f, SIGNAL(watchedFileChangedExternally(QString)),
|
||||||
&f->syncEngine().syncFileStatusTracker(), SLOT(slotPathTouched(QString)));
|
&f->syncEngine().syncFileStatusTracker(), SLOT(slotPathTouched(QString)));
|
||||||
}
|
}
|
||||||
@@ -134,13 +133,12 @@ int FolderMan::unloadAndDeleteAllFolders()
|
|||||||
delete f;
|
delete f;
|
||||||
cnt++;
|
cnt++;
|
||||||
}
|
}
|
||||||
ASSERT(_folderMap.isEmpty());
|
|
||||||
|
|
||||||
_lastSyncFolder = 0;
|
_lastSyncFolder = 0;
|
||||||
_currentSyncFolder = 0;
|
_currentSyncFolder = 0;
|
||||||
_scheduledFolders.clear();
|
_scheduledFolders.clear();
|
||||||
emit scheduleQueueChanged();
|
emit scheduleQueueChanged();
|
||||||
|
|
||||||
|
Q_ASSERT(_folderMap.count() == 0);
|
||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,6 +260,7 @@ int FolderMan::setupFoldersMigration()
|
|||||||
{
|
{
|
||||||
ConfigFile cfg;
|
ConfigFile cfg;
|
||||||
QDir storageDir(cfg.configPath());
|
QDir storageDir(cfg.configPath());
|
||||||
|
storageDir.mkpath(QLatin1String("folders"));
|
||||||
_folderConfigPath = cfg.configPath() + QLatin1String("folders");
|
_folderConfigPath = cfg.configPath() + QLatin1String("folders");
|
||||||
|
|
||||||
qDebug() << "* Setup folders from " << _folderConfigPath << "(migration)";
|
qDebug() << "* Setup folders from " << _folderConfigPath << "(migration)";
|
||||||
@@ -464,7 +463,7 @@ void FolderMan::slotFolderSyncPaused( Folder *f, bool paused )
|
|||||||
void FolderMan::slotFolderCanSyncChanged()
|
void FolderMan::slotFolderCanSyncChanged()
|
||||||
{
|
{
|
||||||
Folder *f = qobject_cast<Folder*>(sender());
|
Folder *f = qobject_cast<Folder*>(sender());
|
||||||
ASSERT(f);
|
Q_ASSERT(f);
|
||||||
if (f->canSync()) {
|
if (f->canSync()) {
|
||||||
_socketApi->slotRegisterPath(f->alias());
|
_socketApi->slotRegisterPath(f->alias());
|
||||||
} else {
|
} else {
|
||||||
@@ -939,7 +938,7 @@ Folder* FolderMan::addFolderInternal(FolderDefinition folderDefinition,
|
|||||||
connect(folder, SIGNAL(syncPausedChanged(Folder*,bool)), SLOT(slotFolderSyncPaused(Folder*,bool)));
|
connect(folder, SIGNAL(syncPausedChanged(Folder*,bool)), SLOT(slotFolderSyncPaused(Folder*,bool)));
|
||||||
connect(folder, SIGNAL(canSyncChanged()), SLOT(slotFolderCanSyncChanged()));
|
connect(folder, SIGNAL(canSyncChanged()), SLOT(slotFolderCanSyncChanged()));
|
||||||
connect(&folder->syncEngine().syncFileStatusTracker(), SIGNAL(fileStatusChanged(const QString &, SyncFileStatus)),
|
connect(&folder->syncEngine().syncFileStatusTracker(), SIGNAL(fileStatusChanged(const QString &, SyncFileStatus)),
|
||||||
_socketApi.data(), SLOT(broadcastStatusPushMessage(const QString &, SyncFileStatus)));
|
_socketApi.data(), SLOT(slotFileStatusChanged(const QString &, SyncFileStatus)));
|
||||||
connect(folder, SIGNAL(watchedFileChangedExternally(QString)),
|
connect(folder, SIGNAL(watchedFileChangedExternally(QString)),
|
||||||
&folder->syncEngine().syncFileStatusTracker(), SLOT(slotPathTouched(QString)));
|
&folder->syncEngine().syncFileStatusTracker(), SLOT(slotPathTouched(QString)));
|
||||||
|
|
||||||
@@ -1122,7 +1121,7 @@ void FolderMan::setDirtyNetworkLimits()
|
|||||||
|
|
||||||
SyncResult FolderMan::accountStatus(const QList<Folder*> &folders)
|
SyncResult FolderMan::accountStatus(const QList<Folder*> &folders)
|
||||||
{
|
{
|
||||||
SyncResult overallResult;
|
SyncResult overallResult(SyncResult::Undefined);
|
||||||
|
|
||||||
int cnt = folders.count();
|
int cnt = folders.count();
|
||||||
|
|
||||||
@@ -1236,10 +1235,10 @@ SyncResult FolderMan::accountStatus(const QList<Folder*> &folders)
|
|||||||
return overallResult;
|
return overallResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString FolderMan::statusToString( SyncResult::Status syncStatus, bool paused ) const
|
QString FolderMan::statusToString( SyncResult syncStatus, bool paused ) const
|
||||||
{
|
{
|
||||||
QString folderMessage;
|
QString folderMessage;
|
||||||
switch( syncStatus ) {
|
switch( syncStatus.status() ) {
|
||||||
case SyncResult::Undefined:
|
case SyncResult::Undefined:
|
||||||
folderMessage = tr( "Undefined State." );
|
folderMessage = tr( "Undefined State." );
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ public:
|
|||||||
/** Creates a new and empty local directory. */
|
/** Creates a new and empty local directory. */
|
||||||
bool startFromScratch( const QString& );
|
bool startFromScratch( const QString& );
|
||||||
|
|
||||||
QString statusToString(SyncResult::Status, bool paused ) const;
|
QString statusToString(SyncResult, bool paused ) const;
|
||||||
|
|
||||||
static SyncResult accountStatus( const QList<Folder*> &folders );
|
static SyncResult accountStatus( const QList<Folder*> &folders );
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#include "folderman.h"
|
#include "folderman.h"
|
||||||
#include "accountstate.h"
|
#include "accountstate.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "asserts.h"
|
|
||||||
#include <theme.h>
|
#include <theme.h>
|
||||||
#include <account.h>
|
#include <account.h>
|
||||||
#include "folderstatusdelegate.h"
|
#include "folderstatusdelegate.h"
|
||||||
@@ -30,14 +29,6 @@ Q_DECLARE_METATYPE(QPersistentModelIndex)
|
|||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
static const char propertyParentIndexC[] = "oc_parentIndex";
|
static const char propertyParentIndexC[] = "oc_parentIndex";
|
||||||
static const char propertyPermissionMap[] = "oc_permissionMap";
|
|
||||||
|
|
||||||
static QString removeTrailingSlash(const QString &s) {
|
|
||||||
if (s.endsWith('/')) {
|
|
||||||
return s.left(s.size() - 1);
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
FolderStatusModel::FolderStatusModel(QObject *parent)
|
FolderStatusModel::FolderStatusModel(QObject *parent)
|
||||||
:QAbstractItemModel(parent), _accountState(0), _dirty(false)
|
:QAbstractItemModel(parent), _accountState(0), _dirty(false)
|
||||||
@@ -171,7 +162,7 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
|
|||||||
case Qt::CheckStateRole:
|
case Qt::CheckStateRole:
|
||||||
return x._checked;
|
return x._checked;
|
||||||
case Qt::DecorationRole:
|
case Qt::DecorationRole:
|
||||||
return QFileIconProvider().icon(x._isExternal ? QFileIconProvider::Network : QFileIconProvider::Folder);
|
return QFileIconProvider().icon(QFileIconProvider::Folder);
|
||||||
case Qt::ForegroundRole:
|
case Qt::ForegroundRole:
|
||||||
if (x._isUndecided) {
|
if (x._isUndecided) {
|
||||||
return QColor(Qt::red);
|
return QColor(Qt::red);
|
||||||
@@ -377,9 +368,6 @@ FolderStatusModel::SubFolderInfo* FolderStatusModel::infoForIndex(const QModelIn
|
|||||||
if (parentInfo->hasLabel()) {
|
if (parentInfo->hasLabel()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (index.row() >= parentInfo->_subs.size()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return &parentInfo->_subs[index.row()];
|
return &parentInfo->_subs[index.row()];
|
||||||
} else {
|
} else {
|
||||||
if (index.row() >= _folders.count()) {
|
if (index.row() >= _folders.count()) {
|
||||||
@@ -481,14 +469,14 @@ QModelIndex FolderStatusModel::parent(const QModelIndex& child) const
|
|||||||
}
|
}
|
||||||
auto pathIdx = static_cast<SubFolderInfo*>(child.internalPointer())->_pathIdx;
|
auto pathIdx = static_cast<SubFolderInfo*>(child.internalPointer())->_pathIdx;
|
||||||
int i = 1;
|
int i = 1;
|
||||||
ASSERT(pathIdx.at(0) < _folders.count());
|
Q_ASSERT(pathIdx.at(0) < _folders.count());
|
||||||
if (pathIdx.count() == 1) {
|
if (pathIdx.count() == 1) {
|
||||||
return createIndex(pathIdx.at(0), 0/*, nullptr*/);
|
return createIndex(pathIdx.at(0), 0/*, nullptr*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
const SubFolderInfo *info = &_folders[pathIdx.at(0)];
|
const SubFolderInfo *info = &_folders[pathIdx.at(0)];
|
||||||
while (i < pathIdx.count() - 1) {
|
while (i < pathIdx.count() - 1) {
|
||||||
ASSERT(pathIdx.at(i) < info->_subs.count());
|
Q_ASSERT(pathIdx.at(i) < info->_subs.count());
|
||||||
info = &info->_subs[pathIdx.at(i)];
|
info = &info->_subs[pathIdx.at(i)];
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
@@ -549,15 +537,12 @@ void FolderStatusModel::fetchMore(const QModelIndex& parent)
|
|||||||
path += info->_path;
|
path += info->_path;
|
||||||
}
|
}
|
||||||
LsColJob *job = new LsColJob(_accountState->account(), path, this);
|
LsColJob *job = new LsColJob(_accountState->account(), path, this);
|
||||||
job->setProperties(QList<QByteArray>() << "resourcetype" << "http://owncloud.org/ns:size" << "http://owncloud.org/ns:permissions");
|
job->setProperties(QList<QByteArray>() << "resourcetype" << "http://owncloud.org/ns:size");
|
||||||
job->setTimeout(60 * 1000);
|
job->setTimeout(60 * 1000);
|
||||||
connect(job, SIGNAL(directoryListingSubfolders(QStringList)),
|
connect(job, SIGNAL(directoryListingSubfolders(QStringList)),
|
||||||
SLOT(slotUpdateDirectories(QStringList)));
|
SLOT(slotUpdateDirectories(QStringList)));
|
||||||
connect(job, SIGNAL(finishedWithError(QNetworkReply*)),
|
connect(job, SIGNAL(finishedWithError(QNetworkReply*)),
|
||||||
this, SLOT(slotLscolFinishedWithError(QNetworkReply*)));
|
this, SLOT(slotLscolFinishedWithError(QNetworkReply*)));
|
||||||
connect(job, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
|
|
||||||
this, SLOT(slotGatherPermissions(const QString&, const QMap<QString,QString>&)));
|
|
||||||
|
|
||||||
job->start();
|
job->start();
|
||||||
|
|
||||||
QPersistentModelIndex persistentIndex(parent);
|
QPersistentModelIndex persistentIndex(parent);
|
||||||
@@ -568,24 +553,10 @@ void FolderStatusModel::fetchMore(const QModelIndex& parent)
|
|||||||
QTimer::singleShot(1000, this, SLOT(slotShowFetchProgress()));
|
QTimer::singleShot(1000, this, SLOT(slotShowFetchProgress()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderStatusModel::slotGatherPermissions(const QString &href, const QMap<QString,QString> &map)
|
|
||||||
{
|
|
||||||
auto it = map.find("permissions");
|
|
||||||
if (it == map.end())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto job = sender();
|
|
||||||
auto permissionMap = job->property(propertyPermissionMap).toMap();
|
|
||||||
job->setProperty(propertyPermissionMap, QVariant()); // avoid a detach of the map while it is modified
|
|
||||||
ASSERT(!href.endsWith(QLatin1Char('/')), "LsColXMLParser::parse should remove the trailing slash before calling us.");
|
|
||||||
permissionMap[href] = *it;
|
|
||||||
job->setProperty(propertyPermissionMap, permissionMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
||||||
{
|
{
|
||||||
auto job = qobject_cast<LsColJob *>(sender());
|
auto job = qobject_cast<LsColJob *>(sender());
|
||||||
ASSERT(job);
|
Q_ASSERT(job);
|
||||||
QModelIndex idx = qvariant_cast<QPersistentModelIndex>(job->property(propertyParentIndexC));
|
QModelIndex idx = qvariant_cast<QPersistentModelIndex>(job->property(propertyParentIndexC));
|
||||||
auto parentInfo = infoForIndex(idx);
|
auto parentInfo = infoForIndex(idx);
|
||||||
if (!parentInfo) {
|
if (!parentInfo) {
|
||||||
@@ -627,7 +598,6 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
|||||||
selectiveSyncUndecidedSet.insert(str);
|
selectiveSyncUndecidedSet.insert(str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto permissionMap = job->property(propertyPermissionMap).toMap();
|
|
||||||
|
|
||||||
QStringList sortedSubfolders = list;
|
QStringList sortedSubfolders = list;
|
||||||
// skip the parent item (first in the list)
|
// skip the parent item (first in the list)
|
||||||
@@ -648,8 +618,8 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
|||||||
newInfo._folder = parentInfo->_folder;
|
newInfo._folder = parentInfo->_folder;
|
||||||
newInfo._pathIdx = parentInfo->_pathIdx;
|
newInfo._pathIdx = parentInfo->_pathIdx;
|
||||||
newInfo._pathIdx << newSubs.size();
|
newInfo._pathIdx << newSubs.size();
|
||||||
newInfo._size = job->_sizes.value(path);
|
auto size = job ? job->_sizes.value(path) : 0;
|
||||||
newInfo._isExternal = permissionMap.value(removeTrailingSlash(path)).toString().contains("M");
|
newInfo._size = size;
|
||||||
newInfo._path = relativePath;
|
newInfo._path = relativePath;
|
||||||
newInfo._name = relativePath.split('/', QString::SkipEmptyParts).last();
|
newInfo._name = relativePath.split('/', QString::SkipEmptyParts).last();
|
||||||
|
|
||||||
@@ -716,7 +686,7 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
|||||||
void FolderStatusModel::slotLscolFinishedWithError(QNetworkReply* r)
|
void FolderStatusModel::slotLscolFinishedWithError(QNetworkReply* r)
|
||||||
{
|
{
|
||||||
auto job = qobject_cast<LsColJob *>(sender());
|
auto job = qobject_cast<LsColJob *>(sender());
|
||||||
ASSERT(job);
|
Q_ASSERT(job);
|
||||||
QModelIndex idx = qvariant_cast<QPersistentModelIndex>(job->property(propertyParentIndexC));
|
QModelIndex idx = qvariant_cast<QPersistentModelIndex>(job->property(propertyParentIndexC));
|
||||||
if (!idx.isValid()) {
|
if (!idx.isValid()) {
|
||||||
return;
|
return;
|
||||||
@@ -731,7 +701,7 @@ void FolderStatusModel::slotLscolFinishedWithError(QNetworkReply* r)
|
|||||||
if (r->error() == QNetworkReply::ContentNotFoundError) {
|
if (r->error() == QNetworkReply::ContentNotFoundError) {
|
||||||
parentInfo->_fetched = true;
|
parentInfo->_fetched = true;
|
||||||
} else {
|
} else {
|
||||||
ASSERT(!parentInfo->hasLabel());
|
Q_ASSERT(!parentInfo->hasLabel());
|
||||||
beginInsertRows(idx, 0, 0);
|
beginInsertRows(idx, 0, 0);
|
||||||
parentInfo->_hasError = true;
|
parentInfo->_hasError = true;
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
@@ -1011,7 +981,7 @@ void FolderStatusModel::slotFolderSyncStateChange(Folder *f)
|
|||||||
auto& pi = _folders[folderIndex]._progress;
|
auto& pi = _folders[folderIndex]._progress;
|
||||||
|
|
||||||
SyncResult::Status state = f->syncResult().status();
|
SyncResult::Status state = f->syncResult().status();
|
||||||
if (!f->canSync()) {
|
if (f->syncPaused()) {
|
||||||
// Reset progress info.
|
// Reset progress info.
|
||||||
pi = SubFolderInfo::Progress();
|
pi = SubFolderInfo::Progress();
|
||||||
} else if (state == SyncResult::NotYetStarted) {
|
} else if (state == SyncResult::NotYetStarted) {
|
||||||
@@ -1042,10 +1012,18 @@ void FolderStatusModel::slotFolderSyncStateChange(Folder *f)
|
|||||||
// update the icon etc. now
|
// update the icon etc. now
|
||||||
slotUpdateFolderState(f);
|
slotUpdateFolderState(f);
|
||||||
|
|
||||||
if (state == SyncResult::Success && f->syncResult().folderStructureWasChanged()) {
|
if (state == SyncResult::Success) {
|
||||||
|
foreach (const SyncFileItemPtr &i, f->syncResult().syncFileItemVector()) {
|
||||||
|
if (i->_isDirectory && (i->_instruction == CSYNC_INSTRUCTION_NEW
|
||||||
|
|| i->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE
|
||||||
|
|| i->_instruction == CSYNC_INSTRUCTION_REMOVE
|
||||||
|
|| i->_instruction == CSYNC_INSTRUCTION_RENAME)) {
|
||||||
// There is a new or a removed folder. reset all data
|
// There is a new or a removed folder. reset all data
|
||||||
auto & info = _folders[folderIndex];
|
auto & info = _folders[folderIndex];
|
||||||
info.resetSubs(this, index(folderIndex));
|
info.resetSubs(this, index(folderIndex));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1136,7 +1114,7 @@ void FolderStatusModel::slotSyncNoPendingBigFolders()
|
|||||||
void FolderStatusModel::slotNewBigFolder()
|
void FolderStatusModel::slotNewBigFolder()
|
||||||
{
|
{
|
||||||
auto f = qobject_cast<Folder *>(sender());
|
auto f = qobject_cast<Folder *>(sender());
|
||||||
ASSERT(f);
|
Q_ASSERT(f);
|
||||||
|
|
||||||
int folderIndex = -1;
|
int folderIndex = -1;
|
||||||
for (int i = 0; i < _folders.count(); ++i) {
|
for (int i = 0; i < _folders.count(); ++i) {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public:
|
|||||||
|
|
||||||
struct SubFolderInfo {
|
struct SubFolderInfo {
|
||||||
SubFolderInfo()
|
SubFolderInfo()
|
||||||
: _folder(0), _size(0), _isExternal(false), _fetched(false), _fetching(false),
|
: _folder(0), _size(0), _fetched(false), _fetching(false),
|
||||||
_hasError(false), _fetchingLabel(false), _isUndecided(false), _checked(Qt::Checked) {}
|
_hasError(false), _fetchingLabel(false), _isUndecided(false), _checked(Qt::Checked) {}
|
||||||
Folder *_folder;
|
Folder *_folder;
|
||||||
QString _name;
|
QString _name;
|
||||||
@@ -59,7 +59,6 @@ public:
|
|||||||
QVector<int> _pathIdx;
|
QVector<int> _pathIdx;
|
||||||
QVector<SubFolderInfo> _subs;
|
QVector<SubFolderInfo> _subs;
|
||||||
qint64 _size;
|
qint64 _size;
|
||||||
bool _isExternal;
|
|
||||||
|
|
||||||
bool _fetched; // If we did the LSCOL for this folder already
|
bool _fetched; // If we did the LSCOL for this folder already
|
||||||
bool _fetching; // Whether a LSCOL job is currently running
|
bool _fetching; // Whether a LSCOL job is currently running
|
||||||
@@ -114,7 +113,6 @@ public slots:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void slotUpdateDirectories(const QStringList &);
|
void slotUpdateDirectories(const QStringList &);
|
||||||
void slotGatherPermissions(const QString &name, const QMap<QString,QString> &properties);
|
|
||||||
void slotLscolFinishedWithError(QNetworkReply *r);
|
void slotLscolFinishedWithError(QNetworkReply *r);
|
||||||
void slotFolderSyncStateChange(Folder* f);
|
void slotFolderSyncStateChange(Folder* f);
|
||||||
void slotFolderScheduleQueueChanged();
|
void slotFolderScheduleQueueChanged();
|
||||||
|
|||||||
@@ -482,8 +482,9 @@ void FolderWizardRemotePath::showWarn( const QString& msg ) const
|
|||||||
FolderWizardSelectiveSync::FolderWizardSelectiveSync(const AccountPtr& account)
|
FolderWizardSelectiveSync::FolderWizardSelectiveSync(const AccountPtr& account)
|
||||||
{
|
{
|
||||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||||
_selectiveSync = new SelectiveSyncWidget(account, this);
|
_treeView = new SelectiveSyncTreeView(account, this);
|
||||||
layout->addWidget(_selectiveSync);
|
layout->addWidget(new QLabel(tr("Choose What to Sync: You can optionally deselect remote subfolders you do not wish to synchronize.")));
|
||||||
|
layout->addWidget(_treeView);
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderWizardSelectiveSync::~FolderWizardSelectiveSync()
|
FolderWizardSelectiveSync::~FolderWizardSelectiveSync()
|
||||||
@@ -500,17 +501,13 @@ void FolderWizardSelectiveSync::initializePage()
|
|||||||
QString alias = QFileInfo(targetPath).fileName();
|
QString alias = QFileInfo(targetPath).fileName();
|
||||||
if (alias.isEmpty())
|
if (alias.isEmpty())
|
||||||
alias = Theme::instance()->appName();
|
alias = Theme::instance()->appName();
|
||||||
QStringList initialBlacklist;
|
_treeView->setFolderInfo(targetPath, alias);
|
||||||
if (Theme::instance()->wizardSelectiveSyncDefaultNothing()) {
|
|
||||||
initialBlacklist = QStringList("/");
|
|
||||||
}
|
|
||||||
_selectiveSync->setFolderInfo(targetPath, alias, initialBlacklist);
|
|
||||||
QWizardPage::initializePage();
|
QWizardPage::initializePage();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FolderWizardSelectiveSync::validatePage()
|
bool FolderWizardSelectiveSync::validatePage()
|
||||||
{
|
{
|
||||||
wizard()->setProperty("selectiveSyncBlackList", QVariant(_selectiveSync->createBlackList()));
|
wizard()->setProperty("selectiveSyncBlackList", QVariant(_treeView->createBlackList()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,7 +517,7 @@ void FolderWizardSelectiveSync::cleanupPage()
|
|||||||
QString alias = QFileInfo(targetPath).fileName();
|
QString alias = QFileInfo(targetPath).fileName();
|
||||||
if (alias.isEmpty())
|
if (alias.isEmpty())
|
||||||
alias = Theme::instance()->appName();
|
alias = Theme::instance()->appName();
|
||||||
_selectiveSync->setFolderInfo(targetPath, alias);
|
_treeView->setFolderInfo(targetPath, alias);
|
||||||
QWizardPage::cleanupPage();
|
QWizardPage::cleanupPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
class SelectiveSyncWidget;
|
class SelectiveSyncTreeView;
|
||||||
|
|
||||||
class ownCloudInfo;
|
class ownCloudInfo;
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ public:
|
|||||||
virtual void cleanupPage() Q_DECL_OVERRIDE;
|
virtual void cleanupPage() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SelectiveSyncWidget *_selectiveSync;
|
SelectiveSyncTreeView *_treeView;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -32,14 +32,12 @@
|
|||||||
|
|
||||||
#include <QNetworkProxy>
|
#include <QNetworkProxy>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QScopedValueRollback>
|
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
GeneralSettings::GeneralSettings(QWidget *parent) :
|
GeneralSettings::GeneralSettings(QWidget *parent) :
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
_ui(new Ui::GeneralSettings),
|
_ui(new Ui::GeneralSettings)
|
||||||
_currentlyLoading(false)
|
|
||||||
{
|
{
|
||||||
_ui->setupUi(this);
|
_ui->setupUi(this);
|
||||||
|
|
||||||
@@ -68,7 +66,6 @@ GeneralSettings::GeneralSettings(QWidget *parent) :
|
|||||||
connect(_ui->crashreporterCheckBox, SIGNAL(toggled(bool)), SLOT(saveMiscSettings()));
|
connect(_ui->crashreporterCheckBox, SIGNAL(toggled(bool)), SLOT(saveMiscSettings()));
|
||||||
connect(_ui->newFolderLimitCheckBox, SIGNAL(toggled(bool)), SLOT(saveMiscSettings()));
|
connect(_ui->newFolderLimitCheckBox, SIGNAL(toggled(bool)), SLOT(saveMiscSettings()));
|
||||||
connect(_ui->newFolderLimitSpinBox, SIGNAL(valueChanged(int)), SLOT(saveMiscSettings()));
|
connect(_ui->newFolderLimitSpinBox, SIGNAL(valueChanged(int)), SLOT(saveMiscSettings()));
|
||||||
connect(_ui->newExternalStorage, SIGNAL(toggled(bool)), SLOT(saveMiscSettings()));
|
|
||||||
|
|
||||||
#ifndef WITH_CRASHREPORTER
|
#ifndef WITH_CRASHREPORTER
|
||||||
_ui->crashreporterCheckBox->setVisible(false);
|
_ui->crashreporterCheckBox->setVisible(false);
|
||||||
@@ -88,9 +85,6 @@ GeneralSettings::GeneralSettings(QWidget *parent) :
|
|||||||
_ui->monoIconsCheckBox->setVisible(QDir(themeDir).exists());
|
_ui->monoIconsCheckBox->setVisible(QDir(themeDir).exists());
|
||||||
|
|
||||||
connect(_ui->ignoredFilesButton, SIGNAL(clicked()), SLOT(slotIgnoreFilesEditor()));
|
connect(_ui->ignoredFilesButton, SIGNAL(clicked()), SLOT(slotIgnoreFilesEditor()));
|
||||||
|
|
||||||
// accountAdded means the wizard was finished and the wizard might change some options.
|
|
||||||
connect(AccountManager::instance(), SIGNAL(accountAdded(AccountState*)), this, SLOT(loadMiscSettings()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GeneralSettings::~GeneralSettings()
|
GeneralSettings::~GeneralSettings()
|
||||||
@@ -105,12 +99,6 @@ QSize GeneralSettings::sizeHint() const {
|
|||||||
|
|
||||||
void GeneralSettings::loadMiscSettings()
|
void GeneralSettings::loadMiscSettings()
|
||||||
{
|
{
|
||||||
#if QT_VERSION < QT_VERSION_CHECK( 5, 4, 0 )
|
|
||||||
QScopedValueRollback<bool> scope(_currentlyLoading);
|
|
||||||
_currentlyLoading = true;
|
|
||||||
#else
|
|
||||||
QScopedValueRollback<bool> scope(_currentlyLoading, true);
|
|
||||||
#endif
|
|
||||||
ConfigFile cfgFile;
|
ConfigFile cfgFile;
|
||||||
_ui->monoIconsCheckBox->setChecked(cfgFile.monoIcons());
|
_ui->monoIconsCheckBox->setChecked(cfgFile.monoIcons());
|
||||||
_ui->desktopNotificationsCheckBox->setChecked(cfgFile.optionalDesktopNotifications());
|
_ui->desktopNotificationsCheckBox->setChecked(cfgFile.optionalDesktopNotifications());
|
||||||
@@ -118,14 +106,11 @@ void GeneralSettings::loadMiscSettings()
|
|||||||
auto newFolderLimit = cfgFile.newBigFolderSizeLimit();
|
auto newFolderLimit = cfgFile.newBigFolderSizeLimit();
|
||||||
_ui->newFolderLimitCheckBox->setChecked(newFolderLimit.first);
|
_ui->newFolderLimitCheckBox->setChecked(newFolderLimit.first);
|
||||||
_ui->newFolderLimitSpinBox->setValue(newFolderLimit.second);
|
_ui->newFolderLimitSpinBox->setValue(newFolderLimit.second);
|
||||||
_ui->newExternalStorage->setChecked(cfgFile.confirmExternalStorage());
|
|
||||||
_ui->monoIconsCheckBox->setChecked(cfgFile.monoIcons());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeneralSettings::slotUpdateInfo()
|
void GeneralSettings::slotUpdateInfo()
|
||||||
{
|
{
|
||||||
// Note: the sparkle-updater is not an OCUpdater
|
OCUpdater *updater = dynamic_cast<OCUpdater*>(Updater::instance());
|
||||||
OCUpdater *updater = qobject_cast<OCUpdater*>(Updater::instance());
|
|
||||||
if (ConfigFile().skipUpdateCheck()) {
|
if (ConfigFile().skipUpdateCheck()) {
|
||||||
updater = 0; // don't show update info if updates are disabled
|
updater = 0; // don't show update info if updates are disabled
|
||||||
}
|
}
|
||||||
@@ -144,8 +129,6 @@ void GeneralSettings::slotUpdateInfo()
|
|||||||
|
|
||||||
void GeneralSettings::saveMiscSettings()
|
void GeneralSettings::saveMiscSettings()
|
||||||
{
|
{
|
||||||
if (_currentlyLoading)
|
|
||||||
return;
|
|
||||||
ConfigFile cfgFile;
|
ConfigFile cfgFile;
|
||||||
bool isChecked = _ui->monoIconsCheckBox->isChecked();
|
bool isChecked = _ui->monoIconsCheckBox->isChecked();
|
||||||
cfgFile.setMonoIcons(isChecked);
|
cfgFile.setMonoIcons(isChecked);
|
||||||
@@ -154,7 +137,6 @@ void GeneralSettings::saveMiscSettings()
|
|||||||
|
|
||||||
cfgFile.setNewBigFolderSizeLimit(_ui->newFolderLimitCheckBox->isChecked(),
|
cfgFile.setNewBigFolderSizeLimit(_ui->newFolderLimitCheckBox->isChecked(),
|
||||||
_ui->newFolderLimitSpinBox->value());
|
_ui->newFolderLimitSpinBox->value());
|
||||||
cfgFile.setConfirmExternalStorage(_ui->newExternalStorage->isChecked());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeneralSettings::slotToggleLaunchOnStartup(bool enable)
|
void GeneralSettings::slotToggleLaunchOnStartup(bool enable)
|
||||||
|
|||||||
@@ -45,14 +45,13 @@ private slots:
|
|||||||
void slotToggleOptionalDesktopNotifications(bool);
|
void slotToggleOptionalDesktopNotifications(bool);
|
||||||
void slotUpdateInfo();
|
void slotUpdateInfo();
|
||||||
void slotIgnoreFilesEditor();
|
void slotIgnoreFilesEditor();
|
||||||
void loadMiscSettings();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void loadMiscSettings();
|
||||||
|
|
||||||
Ui::GeneralSettings *_ui;
|
Ui::GeneralSettings *_ui;
|
||||||
QPointer<IgnoreListEditor> _ignoreEditor;
|
QPointer<IgnoreListEditor> _ignoreEditor;
|
||||||
QPointer<SyncLogDialog> _syncLogDialog;
|
QPointer<SyncLogDialog> _syncLogDialog;
|
||||||
bool _currentlyLoading;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>785</width>
|
<width>706</width>
|
||||||
<height>523</height>
|
<height>523</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -52,17 +52,15 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Advanced</string>
|
<string>Advanced</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item>
|
<item row="0" column="0">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="ignoredFilesButton">
|
<widget class="QPushButton" name="ignoredFilesButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Edit &Ignored Files</string>
|
<string>Edit &Ignored Files</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="0" column="1" colspan="2">
|
||||||
<spacer name="horizontalSpacer_4">
|
<spacer name="horizontalSpacer_4">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
@@ -75,14 +73,12 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
<item row="1" column="0" colspan="3">
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="newFolderLimitCheckBox">
|
<widget class="QCheckBox" name="newFolderLimitCheckBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Ask for confirmation before synchronizing folders larger than</string>
|
<string>Ask &confirmation before downloading folders larger than</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="checked">
|
<property name="checked">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
@@ -102,7 +98,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string extracomment="Trailing part of "Ask confirmation before syncing folder larger than" ">MB</string>
|
<string>MB</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -121,14 +117,7 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="2" column="0" colspan="2">
|
||||||
<widget class="QCheckBox" name="newExternalStorage">
|
|
||||||
<property name="text">
|
|
||||||
<string>Ask for confirmation before synchronizing external storages</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="crashreporterCheckBox">
|
<widget class="QCheckBox" name="crashreporterCheckBox">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||||
@@ -141,6 +130,23 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_5">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
+1
-2
@@ -107,8 +107,7 @@ int main(int argc, char **argv)
|
|||||||
// if handleStartup returns true, main()
|
// if handleStartup returns true, main()
|
||||||
// needs to terminate here, e.g. because
|
// needs to terminate here, e.g. because
|
||||||
// the updater is triggered
|
// the updater is triggered
|
||||||
Updater *updater = Updater::instance();
|
if (Updater::instance()->handleStartup()) {
|
||||||
if ( updater && updater->handleStartup()) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
#include "notificationwidget.h"
|
#include "notificationwidget.h"
|
||||||
#include "QProgressIndicator.h"
|
#include "QProgressIndicator.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "asserts.h"
|
|
||||||
|
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
|
||||||
@@ -34,8 +33,8 @@ void NotificationWidget::setActivity(const Activity& activity)
|
|||||||
{
|
{
|
||||||
_myActivity = activity;
|
_myActivity = activity;
|
||||||
|
|
||||||
|
Q_ASSERT( !activity._accName.isEmpty() );
|
||||||
_accountName = activity._accName;
|
_accountName = activity._accName;
|
||||||
ASSERT(!_accountName.isEmpty());
|
|
||||||
|
|
||||||
// _ui._headerLabel->setText( );
|
// _ui._headerLabel->setText( );
|
||||||
_ui._subjectLabel->setVisible( !activity._subject.isEmpty() );
|
_ui._subjectLabel->setVisible( !activity._subject.isEmpty() );
|
||||||
|
|||||||
@@ -533,12 +533,10 @@ void OwncloudSetupWizard::slotAssistantFinished( int result )
|
|||||||
if (f) {
|
if (f) {
|
||||||
f->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList,
|
f->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList,
|
||||||
_ocWizard->selectiveSyncBlacklist());
|
_ocWizard->selectiveSyncBlacklist());
|
||||||
if (!_ocWizard->isConfirmBigFolderChecked()) {
|
|
||||||
// The user already accepted the selective sync dialog. everything is in the white list
|
// The user already accepted the selective sync dialog. everything is in the white list
|
||||||
f->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncWhiteList,
|
f->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncWhiteList,
|
||||||
QStringList() << QLatin1String("/"));
|
QStringList() << QLatin1String("/"));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
|
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include "syncfileitem.h"
|
#include "syncfileitem.h"
|
||||||
#include "folder.h"
|
#include "folder.h"
|
||||||
#include "openfilemanager.h"
|
#include "openfilemanager.h"
|
||||||
|
#include "owncloudpropagator.h"
|
||||||
#include "activityitemdelegate.h"
|
#include "activityitemdelegate.h"
|
||||||
|
|
||||||
#include "ui_protocolwidget.h"
|
#include "ui_protocolwidget.h"
|
||||||
@@ -44,8 +45,8 @@ ProtocolWidget::ProtocolWidget(QWidget *parent) :
|
|||||||
|
|
||||||
connect(ProgressDispatcher::instance(), SIGNAL(progressInfo(QString,ProgressInfo)),
|
connect(ProgressDispatcher::instance(), SIGNAL(progressInfo(QString,ProgressInfo)),
|
||||||
this, SLOT(slotProgressInfo(QString,ProgressInfo)));
|
this, SLOT(slotProgressInfo(QString,ProgressInfo)));
|
||||||
connect(ProgressDispatcher::instance(), SIGNAL(itemCompleted(QString,SyncFileItemPtr)),
|
connect(ProgressDispatcher::instance(), SIGNAL(itemCompleted(QString,SyncFileItem,PropagatorJob)),
|
||||||
this, SLOT(slotItemCompleted(QString,SyncFileItemPtr)));
|
this, SLOT(slotItemCompleted(QString,SyncFileItem,PropagatorJob)));
|
||||||
|
|
||||||
connect(_ui->_treeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), SLOT(slotOpenFile(QTreeWidgetItem*,int)));
|
connect(_ui->_treeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), SLOT(slotOpenFile(QTreeWidgetItem*,int)));
|
||||||
|
|
||||||
@@ -221,11 +222,15 @@ void ProtocolWidget::slotProgressInfo( const QString& folder, const ProgressInfo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtocolWidget::slotItemCompleted(const QString &folder, const SyncFileItemPtr &item)
|
void ProtocolWidget::slotItemCompleted(const QString &folder, const SyncFileItem &item, const PropagatorJob &job)
|
||||||
{
|
{
|
||||||
QTreeWidgetItem *line = createCompletedTreewidgetItem(folder, *item);
|
if (qobject_cast<const PropagateDirectory*>(&job)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTreeWidgetItem *line = createCompletedTreewidgetItem(folder, item);
|
||||||
if(line) {
|
if(line) {
|
||||||
if( item->hasErrorStatus() ) {
|
if( item.hasErrorStatus() ) {
|
||||||
_issueItemView->insertTopLevelItem(0, line);
|
_issueItemView->insertTopLevelItem(0, line);
|
||||||
emit issueItemCountUpdated(_issueItemView->topLevelItemCount());
|
emit issueItemCountUpdated(_issueItemView->topLevelItemCount());
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void slotProgressInfo( const QString& folder, const ProgressInfo& progress );
|
void slotProgressInfo( const QString& folder, const ProgressInfo& progress );
|
||||||
void slotItemCompleted( const QString& folder, const SyncFileItemPtr& item);
|
void slotItemCompleted( const QString& folder, const SyncFileItem& item, const PropagatorJob& job);
|
||||||
void slotOpenFile( QTreeWidgetItem* item, int );
|
void slotOpenFile( QTreeWidgetItem* item, int );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
#include "networkjobs.h"
|
#include "networkjobs.h"
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
#include "folderman.h"
|
#include "folderman.h"
|
||||||
#include "configfile.h"
|
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QTreeWidget>
|
#include <QTreeWidget>
|
||||||
@@ -30,7 +29,6 @@
|
|||||||
#include <QScopedValueRollback>
|
#include <QScopedValueRollback>
|
||||||
#include <QTreeWidgetItem>
|
#include <QTreeWidgetItem>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QVBoxLayout>
|
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
@@ -56,48 +54,32 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
SelectiveSyncWidget::SelectiveSyncWidget(AccountPtr account, QWidget *parent)
|
SelectiveSyncTreeView::SelectiveSyncTreeView(AccountPtr account, QWidget* parent)
|
||||||
: QWidget(parent)
|
: QTreeWidget(parent), _inserting(false), _account(account)
|
||||||
, _account(account)
|
|
||||||
, _inserting(false)
|
|
||||||
, _folderTree(new QTreeWidget(this))
|
|
||||||
{
|
{
|
||||||
_loading = new QLabel(tr("Loading ..."), _folderTree);
|
_loading = new QLabel(tr("Loading ..."), this);
|
||||||
|
connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(slotItemExpanded(QTreeWidgetItem*)));
|
||||||
auto layout = new QVBoxLayout(this);
|
connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(slotItemChanged(QTreeWidgetItem*,int)));
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
setSortingEnabled(true);
|
||||||
|
sortByColumn(0, Qt::AscendingOrder);
|
||||||
auto header = new QLabel(this);
|
setColumnCount(2);
|
||||||
header->setText(tr("Deselect remote folders you do not wish to synchronize."));
|
|
||||||
header->setWordWrap(true);
|
|
||||||
layout->addWidget(header);
|
|
||||||
|
|
||||||
layout->addWidget(_folderTree);
|
|
||||||
|
|
||||||
connect(_folderTree, SIGNAL(itemExpanded(QTreeWidgetItem*)),
|
|
||||||
SLOT(slotItemExpanded(QTreeWidgetItem*)));
|
|
||||||
connect(_folderTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
|
|
||||||
SLOT(slotItemChanged(QTreeWidgetItem*,int)));
|
|
||||||
_folderTree->setSortingEnabled(true);
|
|
||||||
_folderTree->sortByColumn(0, Qt::AscendingOrder);
|
|
||||||
_folderTree->setColumnCount(2);
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||||
_folderTree->header()->setSectionResizeMode(0, QHeaderView::QHeaderView::ResizeToContents);
|
header()->setSectionResizeMode(0, QHeaderView::QHeaderView::ResizeToContents);
|
||||||
_folderTree->header()->setSectionResizeMode(1, QHeaderView::QHeaderView::ResizeToContents);
|
header()->setSectionResizeMode(1, QHeaderView::QHeaderView::ResizeToContents);
|
||||||
#else
|
#else
|
||||||
_folderTree->header()->resizeSection(0, sizeHint().width()/2);
|
header()->resizeSection(0, sizeHint().width()/2);
|
||||||
#endif
|
#endif
|
||||||
_folderTree->header()->setStretchLastSection(true);
|
header()->setStretchLastSection(true);
|
||||||
_folderTree->headerItem()->setText(0, tr("Name"));
|
headerItem()->setText(0, tr("Name"));
|
||||||
_folderTree->headerItem()->setText(1, tr("Size"));
|
headerItem()->setText(1, tr("Size"));
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize SelectiveSyncWidget::sizeHint() const
|
QSize SelectiveSyncTreeView::sizeHint() const
|
||||||
{
|
{
|
||||||
return QWidget::sizeHint().expandedTo(QSize(600, 600));
|
return QTreeView::sizeHint().expandedTo(QSize(400, 400));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectiveSyncWidget::refreshFolders()
|
void SelectiveSyncTreeView::refreshFolders()
|
||||||
{
|
{
|
||||||
LsColJob *job = new LsColJob(_account, _folderPath, this);
|
LsColJob *job = new LsColJob(_account, _folderPath, this);
|
||||||
job->setProperties(QList<QByteArray>() << "resourcetype" << "http://owncloud.org/ns:size");
|
job->setProperties(QList<QByteArray>() << "resourcetype" << "http://owncloud.org/ns:size");
|
||||||
@@ -106,12 +88,12 @@ void SelectiveSyncWidget::refreshFolders()
|
|||||||
connect(job, SIGNAL(finishedWithError(QNetworkReply*)),
|
connect(job, SIGNAL(finishedWithError(QNetworkReply*)),
|
||||||
this, SLOT(slotLscolFinishedWithError(QNetworkReply*)));
|
this, SLOT(slotLscolFinishedWithError(QNetworkReply*)));
|
||||||
job->start();
|
job->start();
|
||||||
_folderTree->clear();
|
clear();
|
||||||
_loading->show();
|
_loading->show();
|
||||||
_loading->move(10, _folderTree->header()->height() + 10);
|
_loading->move(10,header()->height() + 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectiveSyncWidget::setFolderInfo(const QString& folderPath, const QString& rootName, const QStringList& oldBlackList)
|
void SelectiveSyncTreeView::setFolderInfo(const QString& folderPath, const QString& rootName, const QStringList& oldBlackList)
|
||||||
{
|
{
|
||||||
_folderPath = folderPath;
|
_folderPath = folderPath;
|
||||||
if (_folderPath.startsWith(QLatin1Char('/'))) {
|
if (_folderPath.startsWith(QLatin1Char('/'))) {
|
||||||
@@ -134,7 +116,7 @@ static QTreeWidgetItem* findFirstChild(QTreeWidgetItem *parent, const QString& t
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectiveSyncWidget::recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path, qint64 size)
|
void SelectiveSyncTreeView::recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path, qint64 size)
|
||||||
{
|
{
|
||||||
QFileIconProvider prov;
|
QFileIconProvider prov;
|
||||||
QIcon folderIcon = prov.icon(QFileIconProvider::Folder);
|
QIcon folderIcon = prov.icon(QFileIconProvider::Folder);
|
||||||
@@ -177,13 +159,13 @@ void SelectiveSyncWidget::recursiveInsert(QTreeWidgetItem* parent, QStringList p
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectiveSyncWidget::slotUpdateDirectories(QStringList list)
|
void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
|
||||||
{
|
{
|
||||||
auto job = qobject_cast<LsColJob *>(sender());
|
auto job = qobject_cast<LsColJob *>(sender());
|
||||||
QScopedValueRollback<bool> isInserting(_inserting);
|
QScopedValueRollback<bool> isInserting(_inserting);
|
||||||
_inserting = true;
|
_inserting = true;
|
||||||
|
|
||||||
SelectiveSyncTreeViewItem *root = static_cast<SelectiveSyncTreeViewItem*>(_folderTree->topLevelItem(0));
|
SelectiveSyncTreeViewItem *root = static_cast<SelectiveSyncTreeViewItem*>(topLevelItem(0));
|
||||||
|
|
||||||
QUrl url = _account->davUrl();
|
QUrl url = _account->davUrl();
|
||||||
QString pathToRemove = url.path();
|
QString pathToRemove = url.path();
|
||||||
@@ -224,11 +206,15 @@ void SelectiveSyncWidget::slotUpdateDirectories(QStringList list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!root) {
|
if (!root) {
|
||||||
root = new SelectiveSyncTreeViewItem(_folderTree);
|
root = new SelectiveSyncTreeViewItem(this);
|
||||||
root->setText(0, _rootName);
|
root->setText(0, _rootName);
|
||||||
root->setIcon(0, Theme::instance()->applicationIcon());
|
root->setIcon(0, Theme::instance()->applicationIcon());
|
||||||
root->setData(0, Qt::UserRole, QString());
|
root->setData(0, Qt::UserRole, QString());
|
||||||
|
if (_oldBlackList.isEmpty()) {
|
||||||
root->setCheckState(0, Qt::Checked);
|
root->setCheckState(0, Qt::Checked);
|
||||||
|
} else {
|
||||||
|
root->setCheckState(0, Qt::PartiallyChecked);
|
||||||
|
}
|
||||||
qint64 size = job ? job->_sizes.value(pathToRemove, -1) : -1;
|
qint64 size = job ? job->_sizes.value(pathToRemove, -1) : -1;
|
||||||
if (size >= 0) {
|
if (size >= 0) {
|
||||||
root->setText(1, Utility::octetsToString(size));
|
root->setText(1, Utility::octetsToString(size));
|
||||||
@@ -250,19 +236,10 @@ void SelectiveSyncWidget::slotUpdateDirectories(QStringList list)
|
|||||||
recursiveInsert(root, paths, path, size);
|
recursiveInsert(root, paths, path, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Root is partially checked if any children are not checked
|
|
||||||
for (int i = 0; i < root->childCount(); ++i) {
|
|
||||||
const auto child = root->child(i);
|
|
||||||
if (child->checkState(0) != Qt::Checked) {
|
|
||||||
root->setCheckState(0, Qt::PartiallyChecked);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
root->setExpanded(true);
|
root->setExpanded(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectiveSyncWidget::slotLscolFinishedWithError(QNetworkReply *r)
|
void SelectiveSyncTreeView::slotLscolFinishedWithError(QNetworkReply *r)
|
||||||
{
|
{
|
||||||
if (r->error() == QNetworkReply::ContentNotFoundError) {
|
if (r->error() == QNetworkReply::ContentNotFoundError) {
|
||||||
_loading->setText(tr("No subfolders currently on the server."));
|
_loading->setText(tr("No subfolders currently on the server."));
|
||||||
@@ -272,7 +249,7 @@ void SelectiveSyncWidget::slotLscolFinishedWithError(QNetworkReply *r)
|
|||||||
_loading->resize(_loading->sizeHint()); // because it's not in a layout
|
_loading->resize(_loading->sizeHint()); // because it's not in a layout
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectiveSyncWidget::slotItemExpanded(QTreeWidgetItem *item)
|
void SelectiveSyncTreeView::slotItemExpanded(QTreeWidgetItem *item)
|
||||||
{
|
{
|
||||||
QString dir = item->data(0, Qt::UserRole).toString();
|
QString dir = item->data(0, Qt::UserRole).toString();
|
||||||
if (dir.isEmpty()) return;
|
if (dir.isEmpty()) return;
|
||||||
@@ -287,7 +264,7 @@ void SelectiveSyncWidget::slotItemExpanded(QTreeWidgetItem *item)
|
|||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectiveSyncWidget::slotItemChanged(QTreeWidgetItem *item, int col)
|
void SelectiveSyncTreeView::slotItemChanged(QTreeWidgetItem *item, int col)
|
||||||
{
|
{
|
||||||
if (col != 0 || _inserting)
|
if (col != 0 || _inserting)
|
||||||
return;
|
return;
|
||||||
@@ -345,10 +322,10 @@ void SelectiveSyncWidget::slotItemChanged(QTreeWidgetItem *item, int col)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList SelectiveSyncWidget::createBlackList(QTreeWidgetItem* root) const
|
QStringList SelectiveSyncTreeView::createBlackList(QTreeWidgetItem* root) const
|
||||||
{
|
{
|
||||||
if (!root) {
|
if (!root) {
|
||||||
root = _folderTree->topLevelItem(0);
|
root = topLevelItem(0);
|
||||||
}
|
}
|
||||||
if (!root) return QStringList();
|
if (!root) return QStringList();
|
||||||
|
|
||||||
@@ -377,15 +354,15 @@ QStringList SelectiveSyncWidget::createBlackList(QTreeWidgetItem* root) const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList SelectiveSyncWidget::oldBlackList() const
|
QStringList SelectiveSyncTreeView::oldBlackList() const
|
||||||
{
|
{
|
||||||
return _oldBlackList;
|
return _oldBlackList;
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 SelectiveSyncWidget::estimatedSize(QTreeWidgetItem* root)
|
qint64 SelectiveSyncTreeView::estimatedSize(QTreeWidgetItem* root)
|
||||||
{
|
{
|
||||||
if (!root) {
|
if (!root) {
|
||||||
root = _folderTree->topLevelItem(0);
|
root = topLevelItem(0);
|
||||||
}
|
}
|
||||||
if (!root) return -1;
|
if (!root) return -1;
|
||||||
|
|
||||||
@@ -419,10 +396,10 @@ SelectiveSyncDialog::SelectiveSyncDialog(AccountPtr account, Folder* folder, QWi
|
|||||||
_okButton(0) // defined in init()
|
_okButton(0) // defined in init()
|
||||||
{
|
{
|
||||||
bool ok;
|
bool ok;
|
||||||
init(account);
|
init(account, tr("Unchecked folders will be <b>removed</b> from your local file system and will not be synchronized to this computer anymore"));
|
||||||
QStringList selectiveSyncList = _folder->journalDb()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &ok);
|
QStringList selectiveSyncList = _folder->journalDb()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &ok);
|
||||||
if( ok ) {
|
if( ok ) {
|
||||||
_selectiveSync->setFolderInfo(_folder->remotePath(), _folder->alias(),selectiveSyncList);
|
_treeView->setFolderInfo(_folder->remotePath(), _folder->alias(),selectiveSyncList);
|
||||||
} else {
|
} else {
|
||||||
_okButton->setEnabled(false);
|
_okButton->setEnabled(false);
|
||||||
}
|
}
|
||||||
@@ -434,16 +411,22 @@ SelectiveSyncDialog::SelectiveSyncDialog(AccountPtr account, const QString &fold
|
|||||||
const QStringList& blacklist, QWidget* parent, Qt::WindowFlags f)
|
const QStringList& blacklist, QWidget* parent, Qt::WindowFlags f)
|
||||||
: QDialog(parent, f), _folder(0)
|
: QDialog(parent, f), _folder(0)
|
||||||
{
|
{
|
||||||
init(account);
|
init(account,
|
||||||
_selectiveSync->setFolderInfo(folder, folder, blacklist);
|
Theme::instance()->wizardSelectiveSyncDefaultNothing() ?
|
||||||
|
tr("Choose What to Sync: Select remote subfolders you wish to synchronize.") :
|
||||||
|
tr("Choose What to Sync: Deselect remote subfolders you do not wish to synchronize."));
|
||||||
|
_treeView->setFolderInfo(folder, folder, blacklist);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectiveSyncDialog::init(const AccountPtr &account)
|
void SelectiveSyncDialog::init(const AccountPtr &account, const QString &labelText)
|
||||||
{
|
{
|
||||||
setWindowTitle(tr("Choose What to Sync"));
|
setWindowTitle(tr("Choose What to Sync"));
|
||||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||||
_selectiveSync = new SelectiveSyncWidget(account, this);
|
_treeView = new SelectiveSyncTreeView(account, this);
|
||||||
layout->addWidget(_selectiveSync);
|
auto label = new QLabel(labelText);
|
||||||
|
label->setWordWrap(true);
|
||||||
|
layout->addWidget(label);
|
||||||
|
layout->addWidget(_treeView);
|
||||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal);
|
QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal);
|
||||||
_okButton = buttonBox->addButton(QDialogButtonBox::Ok);
|
_okButton = buttonBox->addButton(QDialogButtonBox::Ok);
|
||||||
connect(_okButton, SIGNAL(clicked()), this, SLOT(accept()));
|
connect(_okButton, SIGNAL(clicked()), this, SLOT(accept()));
|
||||||
@@ -461,7 +444,7 @@ void SelectiveSyncDialog::accept()
|
|||||||
if( ! ok ) {
|
if( ! ok ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QStringList blackList = _selectiveSync->createBlackList();
|
QStringList blackList = _treeView->createBlackList();
|
||||||
_folder->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, blackList);
|
_folder->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, blackList);
|
||||||
|
|
||||||
FolderMan *folderMan = FolderMan::instance();
|
FolderMan *folderMan = FolderMan::instance();
|
||||||
@@ -484,18 +467,19 @@ void SelectiveSyncDialog::accept()
|
|||||||
|
|
||||||
QStringList SelectiveSyncDialog::createBlackList() const
|
QStringList SelectiveSyncDialog::createBlackList() const
|
||||||
{
|
{
|
||||||
return _selectiveSync->createBlackList();
|
return _treeView->createBlackList();
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList SelectiveSyncDialog::oldBlackList() const
|
QStringList SelectiveSyncDialog::oldBlackList() const
|
||||||
{
|
{
|
||||||
return _selectiveSync->oldBlackList();
|
return _treeView->oldBlackList();
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 SelectiveSyncDialog::estimatedSize()
|
qint64 SelectiveSyncDialog::estimatedSize()
|
||||||
{
|
{
|
||||||
return _selectiveSync->estimatedSize();
|
return _treeView->estimatedSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,50 +26,40 @@ namespace OCC {
|
|||||||
class Folder;
|
class Folder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The SelectiveSyncWidget contains a folder tree with labels
|
* @brief The SelectiveSyncTreeView class
|
||||||
* @ingroup gui
|
* @ingroup gui
|
||||||
*/
|
*/
|
||||||
class SelectiveSyncWidget : public QWidget {
|
class SelectiveSyncTreeView : public QTreeWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit SelectiveSyncWidget(AccountPtr account, QWidget* parent = 0);
|
explicit SelectiveSyncTreeView(AccountPtr account, QWidget* parent = 0);
|
||||||
|
|
||||||
/// Returns a list of blacklisted paths, each including the trailing /
|
/// Returns a list of blacklisted paths, each including the trailing /
|
||||||
QStringList createBlackList(QTreeWidgetItem* root = 0) const;
|
QStringList createBlackList(QTreeWidgetItem* root = 0) const;
|
||||||
|
|
||||||
/** Returns the oldBlackList passed into setFolderInfo(), except that
|
|
||||||
* a "/" entry is expanded to all top-level folder names.
|
|
||||||
*/
|
|
||||||
QStringList oldBlackList() const;
|
QStringList oldBlackList() const;
|
||||||
|
|
||||||
// Estimates the total size of checked items (recursively)
|
// Estimates the total size of checked items (recursively)
|
||||||
qint64 estimatedSize(QTreeWidgetItem *root = 0);
|
qint64 estimatedSize(QTreeWidgetItem *root = 0);
|
||||||
|
void refreshFolders();
|
||||||
|
|
||||||
// oldBlackList is a list of excluded paths, each including a trailing /
|
// oldBlackList is a list of excluded paths, each including a trailing /
|
||||||
void setFolderInfo(const QString &folderPath, const QString &rootName,
|
void setFolderInfo(const QString &folderPath, const QString &rootName,
|
||||||
const QStringList &oldBlackList = QStringList());
|
const QStringList &oldBlackList = QStringList());
|
||||||
|
|
||||||
QSize sizeHint() const Q_DECL_OVERRIDE;
|
QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void slotUpdateDirectories(QStringList);
|
void slotUpdateDirectories(QStringList);
|
||||||
void slotItemExpanded(QTreeWidgetItem *);
|
void slotItemExpanded(QTreeWidgetItem *);
|
||||||
void slotItemChanged(QTreeWidgetItem*,int);
|
void slotItemChanged(QTreeWidgetItem*,int);
|
||||||
void slotLscolFinishedWithError(QNetworkReply*);
|
void slotLscolFinishedWithError(QNetworkReply*);
|
||||||
private:
|
private:
|
||||||
void refreshFolders();
|
|
||||||
void recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path, qint64 size);
|
void recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path, qint64 size);
|
||||||
|
|
||||||
AccountPtr _account;
|
|
||||||
|
|
||||||
QString _folderPath;
|
QString _folderPath;
|
||||||
QString _rootName;
|
QString _rootName;
|
||||||
QStringList _oldBlackList;
|
QStringList _oldBlackList;
|
||||||
|
|
||||||
bool _inserting; // set to true when we are inserting new items on the list
|
bool _inserting; // set to true when we are inserting new items on the list
|
||||||
|
AccountPtr _account;
|
||||||
QLabel *_loading;
|
QLabel *_loading;
|
||||||
|
|
||||||
QTreeWidget *_folderTree;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -95,9 +85,9 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void init(const AccountPtr &account);
|
void init(const AccountPtr &account, const QString &label);
|
||||||
|
|
||||||
SelectiveSyncWidget *_selectiveSync;
|
SelectiveSyncTreeView *_treeView;
|
||||||
|
|
||||||
Folder *_folder;
|
Folder *_folder;
|
||||||
QPushButton *_okButton;
|
QPushButton *_okButton;
|
||||||
|
|||||||
+102
-153
@@ -31,12 +31,9 @@
|
|||||||
#include "accountstate.h"
|
#include "accountstate.h"
|
||||||
#include "account.h"
|
#include "account.h"
|
||||||
#include "capabilities.h"
|
#include "capabilities.h"
|
||||||
#include "asserts.h"
|
|
||||||
|
|
||||||
#include <QBitArray>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QMetaMethod>
|
|
||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QScopedPointer>
|
#include <QScopedPointer>
|
||||||
@@ -59,8 +56,6 @@
|
|||||||
// The second number should be changed when there are new features.
|
// The second number should be changed when there are new features.
|
||||||
#define MIRALL_SOCKET_API_VERSION "1.0"
|
#define MIRALL_SOCKET_API_VERSION "1.0"
|
||||||
|
|
||||||
#define DEBUG qDebug() << "SocketApi: "
|
|
||||||
|
|
||||||
static inline QString removeTrailingSlash(QString path)
|
static inline QString removeTrailingSlash(QString path)
|
||||||
{
|
{
|
||||||
Q_ASSERT(path.endsWith(QLatin1Char('/')));
|
Q_ASSERT(path.endsWith(QLatin1Char('/')));
|
||||||
@@ -68,89 +63,9 @@ static inline QString removeTrailingSlash(QString path)
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString buildMessage(const QString& verb, const QString &path, const QString &status = QString::null )
|
|
||||||
{
|
|
||||||
QString msg(verb);
|
|
||||||
|
|
||||||
if( !status.isEmpty() ) {
|
|
||||||
msg.append(QLatin1Char(':'));
|
|
||||||
msg.append(status);
|
|
||||||
}
|
|
||||||
if( !path.isEmpty() ) {
|
|
||||||
msg.append(QLatin1Char(':'));
|
|
||||||
QFileInfo fi(path);
|
|
||||||
msg.append(QDir::toNativeSeparators(fi.absoluteFilePath()));
|
|
||||||
}
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
class BloomFilter {
|
#define DEBUG qDebug() << "SocketApi: "
|
||||||
// Initialize with m=1024 bits and k=2 (high and low 16 bits of a qHash).
|
|
||||||
// For a client navigating in less than 100 directories, this gives us a probability less than (1-e^(-2*100/1024))^2 = 0.03147872136 false positives.
|
|
||||||
const static int NumBits = 1024;
|
|
||||||
|
|
||||||
public:
|
|
||||||
BloomFilter() : hashBits(NumBits) { }
|
|
||||||
|
|
||||||
void storeHash(uint hash) {
|
|
||||||
hashBits.setBit((hash & 0xFFFF) % NumBits);
|
|
||||||
hashBits.setBit((hash >> 16) % NumBits);
|
|
||||||
}
|
|
||||||
bool isHashMaybeStored(uint hash) const {
|
|
||||||
return hashBits.testBit((hash & 0xFFFF) % NumBits)
|
|
||||||
&& hashBits.testBit((hash >> 16) % NumBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
QBitArray hashBits;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SocketListener {
|
|
||||||
public:
|
|
||||||
QIODevice* socket;
|
|
||||||
|
|
||||||
SocketListener(QIODevice* socket = 0) : socket(socket) { }
|
|
||||||
|
|
||||||
void sendMessage(const QString& message, bool doWait = false) const
|
|
||||||
{
|
|
||||||
DEBUG << "Sending message: " << message;
|
|
||||||
QString localMessage = message;
|
|
||||||
if( ! localMessage.endsWith(QLatin1Char('\n'))) {
|
|
||||||
localMessage.append(QLatin1Char('\n'));
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray bytesToSend = localMessage.toUtf8();
|
|
||||||
qint64 sent = socket->write(bytesToSend);
|
|
||||||
if( doWait ) {
|
|
||||||
socket->waitForBytesWritten(1000);
|
|
||||||
}
|
|
||||||
if( sent != bytesToSend.length() ) {
|
|
||||||
qDebug() << "WARN: Could not send all data on socket for " << localMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void sendMessageIfDirectoryMonitored(const QString& message, uint systemDirectoryHash) const
|
|
||||||
{
|
|
||||||
if (_monitoredDirectoriesBloomFilter.isHashMaybeStored(systemDirectoryHash))
|
|
||||||
sendMessage(message, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerMonitoredDirectory(uint systemDirectoryHash)
|
|
||||||
{
|
|
||||||
_monitoredDirectoriesBloomFilter.storeHash(systemDirectoryHash);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
BloomFilter _monitoredDirectoriesBloomFilter;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ListenerHasSocketPred {
|
|
||||||
QIODevice *socket;
|
|
||||||
ListenerHasSocketPred(QIODevice *socket) : socket(socket) { }
|
|
||||||
bool operator()(const SocketListener &listener) const { return listener.socket == socket; }
|
|
||||||
};
|
|
||||||
|
|
||||||
SocketApi::SocketApi(QObject* parent)
|
SocketApi::SocketApi(QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
@@ -214,7 +129,7 @@ SocketApi::~SocketApi()
|
|||||||
DEBUG << "dtor";
|
DEBUG << "dtor";
|
||||||
_localServer.close();
|
_localServer.close();
|
||||||
// All remaining sockets will be destroyed with _localServer, their parent
|
// All remaining sockets will be destroyed with _localServer, their parent
|
||||||
ASSERT(_listeners.isEmpty() || _listeners.first().socket->parent() == &_localServer);
|
Q_ASSERT(_listeners.isEmpty() || _listeners.first()->parent() == &_localServer);
|
||||||
_listeners.clear();
|
_listeners.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,16 +143,14 @@ void SocketApi::slotNewConnection()
|
|||||||
DEBUG << "New connection" << socket;
|
DEBUG << "New connection" << socket;
|
||||||
connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadSocket()));
|
connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadSocket()));
|
||||||
connect(socket, SIGNAL(disconnected()), this, SLOT(onLostConnection()));
|
connect(socket, SIGNAL(disconnected()), this, SLOT(onLostConnection()));
|
||||||
connect(socket, SIGNAL(destroyed(QObject*)), this, SLOT(slotSocketDestroyed(QObject*)));
|
Q_ASSERT(socket->readAll().isEmpty());
|
||||||
ASSERT(socket->readAll().isEmpty());
|
|
||||||
|
|
||||||
_listeners.append(SocketListener(socket));
|
_listeners.append(socket);
|
||||||
SocketListener &listener = _listeners.last();
|
|
||||||
|
|
||||||
foreach( Folder *f, FolderMan::instance()->map() ) {
|
foreach( Folder *f, FolderMan::instance()->map() ) {
|
||||||
if (f->canSync()) {
|
if (f->canSync()) {
|
||||||
QString message = buildRegisterPathMessage(removeTrailingSlash(f->path()));
|
QString message = buildRegisterPathMessage(removeTrailingSlash(f->path()));
|
||||||
listener.sendMessage(message);
|
sendMessage(socket, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,33 +158,32 @@ void SocketApi::slotNewConnection()
|
|||||||
void SocketApi::onLostConnection()
|
void SocketApi::onLostConnection()
|
||||||
{
|
{
|
||||||
DEBUG << "Lost connection " << sender();
|
DEBUG << "Lost connection " << sender();
|
||||||
sender()->deleteLater();
|
|
||||||
|
QIODevice* socket = qobject_cast<QIODevice*>(sender());
|
||||||
|
_listeners.removeAll(socket);
|
||||||
|
socket->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketApi::slotSocketDestroyed(QObject* obj)
|
|
||||||
{
|
|
||||||
QIODevice* socket = static_cast<QIODevice*>(obj);
|
|
||||||
_listeners.erase(std::remove_if(_listeners.begin(), _listeners.end(), ListenerHasSocketPred(socket)), _listeners.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SocketApi::slotReadSocket()
|
void SocketApi::slotReadSocket()
|
||||||
{
|
{
|
||||||
QIODevice* socket = qobject_cast<QIODevice*>(sender());
|
QIODevice* socket = qobject_cast<QIODevice*>(sender());
|
||||||
ASSERT(socket);
|
Q_ASSERT(socket);
|
||||||
SocketListener *listener = &*std::find_if(_listeners.begin(), _listeners.end(), ListenerHasSocketPred(socket));
|
|
||||||
|
|
||||||
while(socket->canReadLine()) {
|
while(socket->canReadLine()) {
|
||||||
// Make sure to normalize the input from the socket to
|
// Make sure to normalize the input from the socket to
|
||||||
// make sure that the path will match, especially on OS X.
|
// make sure that the path will match, especially on OS X.
|
||||||
QString line = QString::fromUtf8(socket->readLine()).normalized(QString::NormalizationForm_C);
|
QString line = QString::fromUtf8(socket->readLine()).normalized(QString::NormalizationForm_C);
|
||||||
line.chop(1); // remove the '\n'
|
line.chop(1); // remove the '\n'
|
||||||
QByteArray command = line.split(":").value(0).toAscii();
|
QString command = line.split(":").value(0);
|
||||||
QByteArray functionWithArguments = "command_" + command + "(QString,SocketListener*)";
|
QString function = QString(QLatin1String("command_")).append(command);
|
||||||
int indexOfMethod = staticMetaObject.indexOfMethod(functionWithArguments);
|
|
||||||
|
QString functionWithArguments = function + QLatin1String("(QString,QIODevice*)");
|
||||||
|
int indexOfMethod = this->metaObject()->indexOfMethod(functionWithArguments.toAscii());
|
||||||
|
|
||||||
QString argument = line.remove(0, command.length()+1);
|
QString argument = line.remove(0, command.length()+1);
|
||||||
if(indexOfMethod != -1) {
|
if(indexOfMethod != -1) {
|
||||||
staticMetaObject.method(indexOfMethod).invoke(this, Q_ARG(QString, argument), Q_ARG(SocketListener*, listener));
|
QMetaObject::invokeMethod(this, function.toAscii(), Q_ARG(QString, argument), Q_ARG(QIODevice*, socket));
|
||||||
} else {
|
} else {
|
||||||
DEBUG << "The command is not supported by this version of the client:" << command << "with argument:" << argument;
|
DEBUG << "The command is not supported by this version of the client:" << command << "with argument:" << argument;
|
||||||
}
|
}
|
||||||
@@ -287,8 +199,8 @@ void SocketApi::slotRegisterPath( const QString& alias )
|
|||||||
Folder *f = FolderMan::instance()->folder(alias);
|
Folder *f = FolderMan::instance()->folder(alias);
|
||||||
if (f) {
|
if (f) {
|
||||||
QString message = buildRegisterPathMessage(removeTrailingSlash(f->path()));
|
QString message = buildRegisterPathMessage(removeTrailingSlash(f->path()));
|
||||||
foreach (auto &listener, _listeners) {
|
foreach(QIODevice *socket, _listeners) {
|
||||||
listener.sendMessage(message);
|
sendMessage(socket, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,7 +214,7 @@ void SocketApi::slotUnregisterPath( const QString& alias )
|
|||||||
|
|
||||||
Folder *f = FolderMan::instance()->folder(alias);
|
Folder *f = FolderMan::instance()->folder(alias);
|
||||||
if (f)
|
if (f)
|
||||||
broadcastMessage(buildMessage(QLatin1String("UNREGISTER_PATH"), removeTrailingSlash(f->path()), QString::null), true);
|
broadcastMessage(QLatin1String("UNREGISTER_PATH"), removeTrailingSlash(f->path()), QString::null, true );
|
||||||
|
|
||||||
_registeredAliases.remove(alias);
|
_registeredAliases.remove(alias);
|
||||||
}
|
}
|
||||||
@@ -323,42 +235,74 @@ void SocketApi::slotUpdateFolderView(Folder *f)
|
|||||||
f->syncResult().status() == SyncResult::SetupError ) {
|
f->syncResult().status() == SyncResult::SetupError ) {
|
||||||
|
|
||||||
QString rootPath = removeTrailingSlash(f->path());
|
QString rootPath = removeTrailingSlash(f->path());
|
||||||
broadcastStatusPushMessage(rootPath, f->syncEngine().syncFileStatusTracker().fileStatus(""));
|
broadcastMessage(QLatin1String("STATUS"), rootPath,
|
||||||
|
f->syncEngine().syncFileStatusTracker().fileStatus("").toSocketAPIString());
|
||||||
|
|
||||||
broadcastMessage(buildMessage(QLatin1String("UPDATE_VIEW"), rootPath));
|
broadcastMessage(QLatin1String("UPDATE_VIEW"), rootPath);
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Not sending UPDATE_VIEW for" << f->alias() << "because status() is" << f->syncResult().status();
|
qDebug() << "Not sending UPDATE_VIEW for" << f->alias() << "because status() is" << f->syncResult().status();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketApi::broadcastMessage(const QString& msg, bool doWait)
|
void SocketApi::slotFileStatusChanged(const QString& systemFileName, SyncFileStatus fileStatus)
|
||||||
{
|
{
|
||||||
foreach (auto &listener, _listeners) {
|
broadcastMessage(QLatin1String("STATUS"), systemFileName, fileStatus.toSocketAPIString());
|
||||||
listener.sendMessage(msg, doWait);
|
}
|
||||||
|
|
||||||
|
void SocketApi::sendMessage(QIODevice *socket, const QString& message, bool doWait)
|
||||||
|
{
|
||||||
|
DEBUG << "Sending message: " << message;
|
||||||
|
QString localMessage = message;
|
||||||
|
if( ! localMessage.endsWith(QLatin1Char('\n'))) {
|
||||||
|
localMessage.append(QLatin1Char('\n'));
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray bytesToSend = localMessage.toUtf8();
|
||||||
|
qint64 sent = socket->write(bytesToSend);
|
||||||
|
if( doWait ) {
|
||||||
|
socket->waitForBytesWritten(1000);
|
||||||
|
}
|
||||||
|
if( sent != bytesToSend.length() ) {
|
||||||
|
qDebug() << "WARN: Could not send all data on socket for " << localMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketApi::broadcastMessage( const QString& verb, const QString& path, const QString& status, bool doWait )
|
||||||
|
{
|
||||||
|
QString msg(verb);
|
||||||
|
|
||||||
|
if( !status.isEmpty() ) {
|
||||||
|
msg.append(QLatin1Char(':'));
|
||||||
|
msg.append(status);
|
||||||
|
}
|
||||||
|
if( !path.isEmpty() ) {
|
||||||
|
msg.append(QLatin1Char(':'));
|
||||||
|
QFileInfo fi(path);
|
||||||
|
msg.append(QDir::toNativeSeparators(fi.absoluteFilePath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(QIODevice *socket, _listeners) {
|
||||||
|
sendMessage(socket, msg, doWait);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketApi::broadcastStatusPushMessage(const QString& systemPath, SyncFileStatus fileStatus)
|
void SocketApi::command_RETRIEVE_FOLDER_STATUS(const QString& argument, QIODevice* socket)
|
||||||
{
|
|
||||||
QString msg = buildMessage(QLatin1String("STATUS"), systemPath, fileStatus.toSocketAPIString());
|
|
||||||
Q_ASSERT(!systemPath.endsWith('/'));
|
|
||||||
uint directoryHash = qHash(systemPath.left(systemPath.lastIndexOf('/')));
|
|
||||||
foreach (auto &listener, _listeners) {
|
|
||||||
listener.sendMessageIfDirectoryMonitored(msg, directoryHash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SocketApi::command_RETRIEVE_FOLDER_STATUS(const QString& argument, SocketListener* listener)
|
|
||||||
{
|
{
|
||||||
// This command is the same as RETRIEVE_FILE_STATUS
|
// This command is the same as RETRIEVE_FILE_STATUS
|
||||||
|
|
||||||
//qDebug() << Q_FUNC_INFO << argument;
|
//qDebug() << Q_FUNC_INFO << argument;
|
||||||
command_RETRIEVE_FILE_STATUS(argument, listener);
|
command_RETRIEVE_FILE_STATUS(argument, socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, SocketListener* listener)
|
void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, QIODevice* socket)
|
||||||
{
|
{
|
||||||
|
if( !socket ) {
|
||||||
|
qDebug() << "No valid socket object.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << argument;
|
qDebug() << Q_FUNC_INFO << argument;
|
||||||
|
|
||||||
QString statusString;
|
QString statusString;
|
||||||
@@ -368,27 +312,27 @@ void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, SocketList
|
|||||||
// this can happen in offline mode e.g.: nothing to worry about
|
// this can happen in offline mode e.g.: nothing to worry about
|
||||||
statusString = QLatin1String("NOP");
|
statusString = QLatin1String("NOP");
|
||||||
} else {
|
} else {
|
||||||
QString systemPath = QDir::cleanPath(argument);
|
QString relativePath = QDir::cleanPath(argument).mid(syncFolder->cleanPath().length()+1);
|
||||||
if( systemPath.endsWith(QLatin1Char('/')) ) {
|
if( relativePath.endsWith(QLatin1Char('/')) ) {
|
||||||
systemPath.truncate(systemPath.length()-1);
|
relativePath.truncate(relativePath.length()-1);
|
||||||
qWarning() << "Removed trailing slash for directory: " << systemPath << "Status pushes won't have one.";
|
qWarning() << "Removed trailing slash for directory: " << relativePath << "Status pushes won't have one.";
|
||||||
}
|
}
|
||||||
// The user probably visited this directory in the file shell.
|
|
||||||
// Let the listener know that it should now send status pushes for sibblings of this file.
|
|
||||||
QString directory = systemPath.left(systemPath.lastIndexOf('/'));
|
|
||||||
listener->registerMonitoredDirectory(qHash(directory));
|
|
||||||
|
|
||||||
QString relativePath = systemPath.mid(syncFolder->cleanPath().length()+1);
|
|
||||||
SyncFileStatus fileStatus = syncFolder->syncEngine().syncFileStatusTracker().fileStatus(relativePath);
|
SyncFileStatus fileStatus = syncFolder->syncEngine().syncFileStatusTracker().fileStatus(relativePath);
|
||||||
|
|
||||||
statusString = fileStatus.toSocketAPIString();
|
statusString = fileStatus.toSocketAPIString();
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString message = QLatin1String("STATUS:") % statusString % QLatin1Char(':') % QDir::toNativeSeparators(argument);
|
const QString message = QLatin1String("STATUS:") % statusString % QLatin1Char(':') % QDir::toNativeSeparators(argument);
|
||||||
listener->sendMessage(message);
|
sendMessage(socket, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketApi::command_SHARE(const QString& localFile, SocketListener* listener)
|
void SocketApi::command_SHARE(const QString& localFile, QIODevice* socket)
|
||||||
{
|
{
|
||||||
|
if (!socket) {
|
||||||
|
qDebug() << Q_FUNC_INFO << "No valid socket object.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << localFile;
|
qDebug() << Q_FUNC_INFO << localFile;
|
||||||
|
|
||||||
auto theme = Theme::instance();
|
auto theme = Theme::instance();
|
||||||
@@ -397,16 +341,16 @@ void SocketApi::command_SHARE(const QString& localFile, SocketListener* listener
|
|||||||
if (!shareFolder) {
|
if (!shareFolder) {
|
||||||
const QString message = QLatin1String("SHARE:NOP:")+QDir::toNativeSeparators(localFile);
|
const QString message = QLatin1String("SHARE:NOP:")+QDir::toNativeSeparators(localFile);
|
||||||
// files that are not within a sync folder are not synced.
|
// files that are not within a sync folder are not synced.
|
||||||
listener->sendMessage(message);
|
sendMessage(socket, message);
|
||||||
} else if (!shareFolder->accountState()->isConnected()) {
|
} else if (!shareFolder->accountState()->isConnected()) {
|
||||||
const QString message = QLatin1String("SHARE:NOTCONNECTED:")+QDir::toNativeSeparators(localFile);
|
const QString message = QLatin1String("SHARE:NOTCONNECTED:")+QDir::toNativeSeparators(localFile);
|
||||||
// if the folder isn't connected, don't open the share dialog
|
// if the folder isn't connected, don't open the share dialog
|
||||||
listener->sendMessage(message);
|
sendMessage(socket, message);
|
||||||
} else if (!theme->linkSharing() && (
|
} else if (!theme->linkSharing() && (
|
||||||
!theme->userGroupSharing() ||
|
!theme->userGroupSharing() ||
|
||||||
shareFolder->accountState()->account()->serverVersionInt() < ((8 << 16) + (2 << 8)))) {
|
shareFolder->accountState()->account()->serverVersionInt() < ((8 << 16) + (2 << 8)))) {
|
||||||
const QString message = QLatin1String("SHARE:NOP:")+QDir::toNativeSeparators(localFile);
|
const QString message = QLatin1String("SHARE:NOP:")+QDir::toNativeSeparators(localFile);
|
||||||
listener->sendMessage(message);
|
sendMessage(socket, message);
|
||||||
} else {
|
} else {
|
||||||
const QString localFileClean = QDir::cleanPath(localFile);
|
const QString localFileClean = QDir::cleanPath(localFile);
|
||||||
const QString file = localFileClean.mid(shareFolder->cleanPath().length()+1);
|
const QString file = localFileClean.mid(shareFolder->cleanPath().length()+1);
|
||||||
@@ -415,7 +359,7 @@ void SocketApi::command_SHARE(const QString& localFile, SocketListener* listener
|
|||||||
// Verify the file is on the server (to our knowledge of course)
|
// Verify the file is on the server (to our knowledge of course)
|
||||||
if (fileStatus.tag() != SyncFileStatus::StatusUpToDate) {
|
if (fileStatus.tag() != SyncFileStatus::StatusUpToDate) {
|
||||||
const QString message = QLatin1String("SHARE:NOTSYNCED:")+QDir::toNativeSeparators(localFile);
|
const QString message = QLatin1String("SHARE:NOTSYNCED:")+QDir::toNativeSeparators(localFile);
|
||||||
listener->sendMessage(message);
|
sendMessage(socket, message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,7 +368,7 @@ void SocketApi::command_SHARE(const QString& localFile, SocketListener* listener
|
|||||||
// Can't share root folder
|
// Can't share root folder
|
||||||
if (remotePath == "/") {
|
if (remotePath == "/") {
|
||||||
const QString message = QLatin1String("SHARE:CANNOTSHAREROOT:")+QDir::toNativeSeparators(localFile);
|
const QString message = QLatin1String("SHARE:CANNOTSHAREROOT:")+QDir::toNativeSeparators(localFile);
|
||||||
listener->sendMessage(message);
|
sendMessage(socket, message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,26 +382,31 @@ void SocketApi::command_SHARE(const QString& localFile, SocketListener* listener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const QString message = QLatin1String("SHARE:OK:")+QDir::toNativeSeparators(localFile);
|
const QString message = QLatin1String("SHARE:OK:")+QDir::toNativeSeparators(localFile);
|
||||||
listener->sendMessage(message);
|
sendMessage(socket, message);
|
||||||
|
|
||||||
emit shareCommandReceived(remotePath, localFileClean, allowReshare);
|
emit shareCommandReceived(remotePath, localFileClean, allowReshare);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketApi::command_VERSION(const QString&, SocketListener* listener)
|
void SocketApi::command_VERSION(const QString&, QIODevice* socket)
|
||||||
{
|
{
|
||||||
listener->sendMessage(QLatin1String("VERSION:" MIRALL_VERSION_STRING ":" MIRALL_SOCKET_API_VERSION));
|
sendMessage(socket, QLatin1String("VERSION:" MIRALL_VERSION_STRING ":" MIRALL_SOCKET_API_VERSION));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketApi::command_SHARE_STATUS(const QString &localFile, SocketListener* listener)
|
void SocketApi::command_SHARE_STATUS(const QString &localFile, QIODevice *socket)
|
||||||
{
|
{
|
||||||
|
if (!socket) {
|
||||||
|
qDebug() << Q_FUNC_INFO << "No valid socket object.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << localFile;
|
qDebug() << Q_FUNC_INFO << localFile;
|
||||||
|
|
||||||
Folder *shareFolder = FolderMan::instance()->folderForPath(localFile);
|
Folder *shareFolder = FolderMan::instance()->folderForPath(localFile);
|
||||||
|
|
||||||
if (!shareFolder) {
|
if (!shareFolder) {
|
||||||
const QString message = QLatin1String("SHARE_STATUS:NOP:")+QDir::toNativeSeparators(localFile);
|
const QString message = QLatin1String("SHARE_STATUS:NOP:")+QDir::toNativeSeparators(localFile);
|
||||||
listener->sendMessage(message);
|
sendMessage(socket, message);
|
||||||
} else {
|
} else {
|
||||||
const QString file = QDir::cleanPath(localFile).mid(shareFolder->cleanPath().length()+1);
|
const QString file = QDir::cleanPath(localFile).mid(shareFolder->cleanPath().length()+1);
|
||||||
SyncFileStatus fileStatus = shareFolder->syncEngine().syncFileStatusTracker().fileStatus(file);
|
SyncFileStatus fileStatus = shareFolder->syncEngine().syncFileStatusTracker().fileStatus(file);
|
||||||
@@ -465,7 +414,7 @@ void SocketApi::command_SHARE_STATUS(const QString &localFile, SocketListener* l
|
|||||||
// Verify the file is on the server (to our knowledge of course)
|
// Verify the file is on the server (to our knowledge of course)
|
||||||
if (fileStatus.tag() != SyncFileStatus::StatusUpToDate) {
|
if (fileStatus.tag() != SyncFileStatus::StatusUpToDate) {
|
||||||
const QString message = QLatin1String("SHARE_STATUS:NOTSYNCED:")+QDir::toNativeSeparators(localFile);
|
const QString message = QLatin1String("SHARE_STATUS:NOTSYNCED:")+QDir::toNativeSeparators(localFile);
|
||||||
listener->sendMessage(message);
|
sendMessage(socket, message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,7 +422,7 @@ void SocketApi::command_SHARE_STATUS(const QString &localFile, SocketListener* l
|
|||||||
|
|
||||||
if (!capabilities.shareAPI()) {
|
if (!capabilities.shareAPI()) {
|
||||||
const QString message = QLatin1String("SHARE_STATUS:DISABLED:")+QDir::toNativeSeparators(localFile);
|
const QString message = QLatin1String("SHARE_STATUS:DISABLED:")+QDir::toNativeSeparators(localFile);
|
||||||
listener->sendMessage(message);
|
sendMessage(socket, message);
|
||||||
} else {
|
} else {
|
||||||
auto theme = Theme::instance();
|
auto theme = Theme::instance();
|
||||||
QString available;
|
QString available;
|
||||||
@@ -492,18 +441,18 @@ void SocketApi::command_SHARE_STATUS(const QString &localFile, SocketListener* l
|
|||||||
|
|
||||||
if (available.isEmpty()) {
|
if (available.isEmpty()) {
|
||||||
const QString message = QLatin1String("SHARE_STATUS:DISABLED") + ":" + QDir::toNativeSeparators(localFile);
|
const QString message = QLatin1String("SHARE_STATUS:DISABLED") + ":" + QDir::toNativeSeparators(localFile);
|
||||||
listener->sendMessage(message);
|
sendMessage(socket, message);
|
||||||
} else {
|
} else {
|
||||||
const QString message = QLatin1String("SHARE_STATUS:") + available + ":" + QDir::toNativeSeparators(localFile);
|
const QString message = QLatin1String("SHARE_STATUS:") + available + ":" + QDir::toNativeSeparators(localFile);
|
||||||
listener->sendMessage(message);
|
sendMessage(socket, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketApi::command_SHARE_MENU_TITLE(const QString &, SocketListener* listener)
|
void SocketApi::command_SHARE_MENU_TITLE(const QString &, QIODevice* socket)
|
||||||
{
|
{
|
||||||
listener->sendMessage(QLatin1String("SHARE_MENU_TITLE:") + tr("Share with %1", "parameter is ownCloud").arg(Theme::instance()->appNameGUI()));
|
sendMessage(socket, QLatin1String("SHARE_MENU_TITLE:") + tr("Share with %1", "parameter is ownCloud").arg(Theme::instance()->appNameGUI()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SocketApi::buildRegisterPathMessage(const QString& path)
|
QString SocketApi::buildRegisterPathMessage(const QString& path)
|
||||||
|
|||||||
+10
-11
@@ -35,7 +35,6 @@ namespace OCC {
|
|||||||
|
|
||||||
class SyncFileStatus;
|
class SyncFileStatus;
|
||||||
class Folder;
|
class Folder;
|
||||||
class SocketListener;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The SocketApi class
|
* @brief The SocketApi class
|
||||||
@@ -61,25 +60,25 @@ signals:
|
|||||||
private slots:
|
private slots:
|
||||||
void slotNewConnection();
|
void slotNewConnection();
|
||||||
void onLostConnection();
|
void onLostConnection();
|
||||||
void slotSocketDestroyed(QObject* obj);
|
|
||||||
void slotReadSocket();
|
void slotReadSocket();
|
||||||
void broadcastStatusPushMessage(const QString& systemPath, SyncFileStatus fileStatus);
|
void slotFileStatusChanged(const QString& systemFileName, SyncFileStatus fileStatus);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void broadcastMessage(const QString& msg, bool doWait = false);
|
void sendMessage(QIODevice* socket, const QString& message, bool doWait = false);
|
||||||
|
void broadcastMessage(const QString& verb, const QString &path, const QString &status = QString::null, bool doWait = false);
|
||||||
|
|
||||||
Q_INVOKABLE void command_RETRIEVE_FOLDER_STATUS(const QString& argument, SocketListener* listener);
|
Q_INVOKABLE void command_RETRIEVE_FOLDER_STATUS(const QString& argument, QIODevice* socket);
|
||||||
Q_INVOKABLE void command_RETRIEVE_FILE_STATUS(const QString& argument, SocketListener* listener);
|
Q_INVOKABLE void command_RETRIEVE_FILE_STATUS(const QString& argument, QIODevice* socket);
|
||||||
Q_INVOKABLE void command_SHARE(const QString& localFile, SocketListener* listener);
|
Q_INVOKABLE void command_SHARE(const QString& localFile, QIODevice* socket);
|
||||||
|
|
||||||
Q_INVOKABLE void command_VERSION(const QString& argument, SocketListener* listener);
|
Q_INVOKABLE void command_VERSION(const QString& argument, QIODevice* socket);
|
||||||
|
|
||||||
Q_INVOKABLE void command_SHARE_STATUS(const QString& localFile, SocketListener* listener);
|
Q_INVOKABLE void command_SHARE_STATUS(const QString& localFile, QIODevice *socket);
|
||||||
Q_INVOKABLE void command_SHARE_MENU_TITLE(const QString& argument, SocketListener* listener);
|
Q_INVOKABLE void command_SHARE_MENU_TITLE(const QString& argument, QIODevice* socket);
|
||||||
QString buildRegisterPathMessage(const QString& path);
|
QString buildRegisterPathMessage(const QString& path);
|
||||||
|
|
||||||
QSet<QString> _registeredAliases;
|
QSet<QString> _registeredAliases;
|
||||||
QList<SocketListener> _listeners;
|
QList<QIODevice*> _listeners;
|
||||||
SocketApiServer _localServer;
|
SocketApiServer _localServer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -145,18 +145,18 @@ void SyncRunFileLog::logItem( const SyncFileItem& item )
|
|||||||
|
|
||||||
const QChar L = QLatin1Char('|');
|
const QChar L = QLatin1Char('|');
|
||||||
_out << ts << L;
|
_out << ts << L;
|
||||||
_out << L;
|
_out << QString::number(item._requestDuration) << L;
|
||||||
if( item._instruction != CSYNC_INSTRUCTION_RENAME ) {
|
if( item.log._instruction != CSYNC_INSTRUCTION_RENAME ) {
|
||||||
_out << item._file << L;
|
_out << item._file << L;
|
||||||
} else {
|
} else {
|
||||||
_out << item._file << QLatin1String(" -> ") << item._renameTarget << L;
|
_out << item._file << QLatin1String(" -> ") << item._renameTarget << L;
|
||||||
}
|
}
|
||||||
_out << instructionToStr( item._instruction ) << L;
|
_out << instructionToStr( item.log._instruction ) << L;
|
||||||
_out << directionToStr( item._direction ) << L;
|
_out << directionToStr( item._direction ) << L;
|
||||||
_out << QString::number(item._modtime) << L;
|
_out << QString::number(item.log._modtime) << L;
|
||||||
_out << item._etag << L;
|
_out << item.log._etag << L;
|
||||||
_out << QString::number(item._size) << L;
|
_out << QString::number(item.log._size) << L;
|
||||||
_out << item._fileId << L;
|
_out << item.log._fileId << L;
|
||||||
_out << item._status << L;
|
_out << item._status << L;
|
||||||
_out << item._errorString << L;
|
_out << item._errorString << L;
|
||||||
_out << QString::number(item._httpErrorCode) << L;
|
_out << QString::number(item._httpErrorCode) << L;
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include "updater/ocupdater.h"
|
#include "updater/ocupdater.h"
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
#include <QtNetwork>
|
#include <QtNetwork>
|
||||||
#include <QtGui>
|
#include <QtGui>
|
||||||
@@ -44,8 +43,9 @@ UpdaterScheduler::UpdaterScheduler(QObject *parent) :
|
|||||||
connect( &_updateCheckTimer, SIGNAL(timeout()),
|
connect( &_updateCheckTimer, SIGNAL(timeout()),
|
||||||
this, SLOT(slotTimerFired()) );
|
this, SLOT(slotTimerFired()) );
|
||||||
|
|
||||||
// Note: the sparkle-updater is not an OCUpdater
|
// Note: the sparkle-updater is not an OCUpdater and thus the dynamic_cast
|
||||||
if (OCUpdater *updater = qobject_cast<OCUpdater*>(Updater::instance())) {
|
// returns NULL. Clever detail.
|
||||||
|
if (OCUpdater *updater = dynamic_cast<OCUpdater*>(Updater::instance())) {
|
||||||
connect(updater, SIGNAL(newUpdateAvailable(QString,QString)),
|
connect(updater, SIGNAL(newUpdateAvailable(QString,QString)),
|
||||||
this, SIGNAL(updaterAnnouncement(QString,QString)) );
|
this, SIGNAL(updaterAnnouncement(QString,QString)) );
|
||||||
connect(updater, SIGNAL(requestRestart()), SIGNAL(requestRestart()));
|
connect(updater, SIGNAL(requestRestart()), SIGNAL(requestRestart()));
|
||||||
@@ -76,17 +76,14 @@ void UpdaterScheduler::slotTimerFired()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Updater *updater = Updater::instance();
|
Updater::instance()->backgroundCheckForUpdate();
|
||||||
if (updater) {
|
|
||||||
updater->backgroundCheckForUpdate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------- */
|
/* ----------------------------------------------------------------- */
|
||||||
|
|
||||||
OCUpdater::OCUpdater(const QUrl &url) :
|
OCUpdater::OCUpdater(const QUrl &url, QObject *parent) :
|
||||||
Updater()
|
QObject(parent)
|
||||||
, _updateUrl(url)
|
, _updateUrl(url)
|
||||||
, _state(Unknown)
|
, _state(Unknown)
|
||||||
, _accessManager(new AccessManager(this))
|
, _accessManager(new AccessManager(this))
|
||||||
@@ -245,8 +242,8 @@ void OCUpdater::slotTimedOut()
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
NSISUpdater::NSISUpdater(const QUrl &url)
|
NSISUpdater::NSISUpdater(const QUrl &url, QObject *parent)
|
||||||
: OCUpdater(url)
|
: OCUpdater(url, parent)
|
||||||
, _showFallbackMessage(false)
|
, _showFallbackMessage(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -424,8 +421,8 @@ void NSISUpdater::slotSetSeenVersion()
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
PassiveUpdateNotifier::PassiveUpdateNotifier(const QUrl &url)
|
PassiveUpdateNotifier::PassiveUpdateNotifier(const QUrl &url, QObject *parent)
|
||||||
: OCUpdater(url)
|
: OCUpdater(url, parent)
|
||||||
{
|
{
|
||||||
// remember the version of the currently running binary. On Linux it might happen that the
|
// remember the version of the currently running binary. On Linux it might happen that the
|
||||||
// package management updates the package while the app is running. This is detected in the
|
// package management updates the package while the app is running. This is detected in the
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ private:
|
|||||||
* @brief Class that uses an ownCloud proprietary XML format to fetch update information
|
* @brief Class that uses an ownCloud proprietary XML format to fetch update information
|
||||||
* @ingroup gui
|
* @ingroup gui
|
||||||
*/
|
*/
|
||||||
class OCUpdater : public Updater
|
class OCUpdater : public QObject, public Updater
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@@ -94,7 +94,7 @@ public:
|
|||||||
Downloading, DownloadComplete,
|
Downloading, DownloadComplete,
|
||||||
DownloadFailed, DownloadTimedOut,
|
DownloadFailed, DownloadTimedOut,
|
||||||
UpdateOnlyAvailableThroughSystem };
|
UpdateOnlyAvailableThroughSystem };
|
||||||
explicit OCUpdater(const QUrl &url);
|
explicit OCUpdater(const QUrl &url, QObject *parent = 0);
|
||||||
|
|
||||||
bool performUpdate();
|
bool performUpdate();
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ class NSISUpdater : public OCUpdater {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
enum UpdateState { NoUpdate = 0, UpdateAvailable, UpdateFailed };
|
enum UpdateState { NoUpdate = 0, UpdateAvailable, UpdateFailed };
|
||||||
explicit NSISUpdater(const QUrl &url);
|
explicit NSISUpdater(const QUrl &url, QObject *parent = 0);
|
||||||
bool handleStartup() Q_DECL_OVERRIDE;
|
bool handleStartup() Q_DECL_OVERRIDE;
|
||||||
private slots:
|
private slots:
|
||||||
void slotSetSeenVersion();
|
void slotSetSeenVersion();
|
||||||
@@ -167,7 +167,7 @@ private:
|
|||||||
class PassiveUpdateNotifier : public OCUpdater {
|
class PassiveUpdateNotifier : public OCUpdater {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit PassiveUpdateNotifier(const QUrl &url);
|
explicit PassiveUpdateNotifier(const QUrl &url, QObject *parent = 0);
|
||||||
bool handleStartup() Q_DECL_OVERRIDE { return false; }
|
bool handleStartup() Q_DECL_OVERRIDE { return false; }
|
||||||
void backgroundCheckForUpdate() Q_DECL_OVERRIDE;
|
void backgroundCheckForUpdate() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
|||||||
@@ -87,10 +87,6 @@ Updater *Updater::create()
|
|||||||
if (updateBaseUrl.isEmpty()) {
|
if (updateBaseUrl.isEmpty()) {
|
||||||
updateBaseUrl = QUrl(QLatin1String(APPLICATION_UPDATE_URL));
|
updateBaseUrl = QUrl(QLatin1String(APPLICATION_UPDATE_URL));
|
||||||
}
|
}
|
||||||
if (!updateBaseUrl.isValid() || updateBaseUrl.host() == ".") {
|
|
||||||
qDebug() << "Not a valid updater URL, will not do update check";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
updateBaseUrl = addQueryParams(updateBaseUrl);
|
updateBaseUrl = addQueryParams(updateBaseUrl);
|
||||||
#if defined(Q_OS_MAC) && defined(HAVE_SPARKLE)
|
#if defined(Q_OS_MAC) && defined(HAVE_SPARKLE)
|
||||||
updateBaseUrl.addQueryItem( QLatin1String("sparkle"), QLatin1String("true"));
|
updateBaseUrl.addQueryItem( QLatin1String("sparkle"), QLatin1String("true"));
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ class QUrl;
|
|||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
class Updater : public QObject {
|
class Updater {
|
||||||
Q_OBJECT
|
|
||||||
public:
|
public:
|
||||||
struct Helper {
|
struct Helper {
|
||||||
static qint64 stringVersionToInt(const QString& version);
|
static qint64 stringVersionToInt(const QString& version);
|
||||||
@@ -38,7 +37,6 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
static QString clientVersion();
|
static QString clientVersion();
|
||||||
Updater() : QObject(0) {}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static QString getSystemInfo();
|
static QString getSystemInfo();
|
||||||
|
|||||||
@@ -68,15 +68,6 @@ OwncloudAdvancedSetupPage::OwncloudAdvancedSetupPage()
|
|||||||
_ui.lServerIcon->setPixmap(appIcon.pixmap(48));
|
_ui.lServerIcon->setPixmap(appIcon.pixmap(48));
|
||||||
_ui.lLocalIcon->setText(QString());
|
_ui.lLocalIcon->setText(QString());
|
||||||
_ui.lLocalIcon->setPixmap(QPixmap(Theme::hidpiFileName(":/client/resources/folder-sync.png")));
|
_ui.lLocalIcon->setPixmap(QPixmap(Theme::hidpiFileName(":/client/resources/folder-sync.png")));
|
||||||
|
|
||||||
if (theme->wizardHideExternalStorageConfirmationCheckbox()) {
|
|
||||||
_ui.confCheckBoxExternal->hide();
|
|
||||||
}
|
|
||||||
if (theme->wizardHideFolderSizeLimitCheckbox()) {
|
|
||||||
_ui.confCheckBoxSize->hide();
|
|
||||||
_ui.confSpinBox->hide();
|
|
||||||
_ui.confTraillingSizeLabel->hide();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OwncloudAdvancedSetupPage::setupCustomization()
|
void OwncloudAdvancedSetupPage::setupCustomization()
|
||||||
@@ -127,12 +118,6 @@ void OwncloudAdvancedSetupPage::initializePage()
|
|||||||
_selectiveSyncBlacklist = QStringList("/");
|
_selectiveSyncBlacklist = QStringList("/");
|
||||||
QTimer::singleShot(0, this, SLOT(slotSelectiveSyncClicked()));
|
QTimer::singleShot(0, this, SLOT(slotSelectiveSyncClicked()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigFile cfgFile;
|
|
||||||
auto newFolderLimit = cfgFile.newBigFolderSizeLimit();
|
|
||||||
_ui.confCheckBoxSize->setChecked(newFolderLimit.first);
|
|
||||||
_ui.confSpinBox->setValue(newFolderLimit.second);
|
|
||||||
_ui.confCheckBoxExternal->setChecked(cfgFile.confirmExternalStorage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called if the user changes the user- or url field. Adjust the texts and
|
// Called if the user changes the user- or url field. Adjust the texts and
|
||||||
@@ -215,11 +200,6 @@ QStringList OwncloudAdvancedSetupPage::selectiveSyncBlacklist() const
|
|||||||
return _selectiveSyncBlacklist;
|
return _selectiveSyncBlacklist;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OwncloudAdvancedSetupPage::isConfirmBigFolderChecked() const
|
|
||||||
{
|
|
||||||
return _ui.rSyncEverything->isChecked() && _ui.confCheckBoxSize->isChecked();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OwncloudAdvancedSetupPage::validatePage()
|
bool OwncloudAdvancedSetupPage::validatePage()
|
||||||
{
|
{
|
||||||
if(!_created) {
|
if(!_created) {
|
||||||
@@ -228,13 +208,6 @@ bool OwncloudAdvancedSetupPage::validatePage()
|
|||||||
startSpinner();
|
startSpinner();
|
||||||
emit completeChanged();
|
emit completeChanged();
|
||||||
|
|
||||||
if (_ui.rSyncEverything->isChecked()) {
|
|
||||||
ConfigFile cfgFile;
|
|
||||||
cfgFile.setNewBigFolderSizeLimit(_ui.confCheckBoxSize->isChecked(),
|
|
||||||
_ui.confSpinBox->value());
|
|
||||||
cfgFile.setConfirmExternalStorage(_ui.confCheckBoxExternal->isChecked());
|
|
||||||
}
|
|
||||||
|
|
||||||
emit createLocalAndRemoteFolders(localFolder(), _remoteFolder);
|
emit createLocalAndRemoteFolders(localFolder(), _remoteFolder);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ public:
|
|||||||
bool validatePage() Q_DECL_OVERRIDE;
|
bool validatePage() Q_DECL_OVERRIDE;
|
||||||
QString localFolder() const;
|
QString localFolder() const;
|
||||||
QStringList selectiveSyncBlacklist() const;
|
QStringList selectiveSyncBlacklist() const;
|
||||||
bool isConfirmBigFolderChecked() const;
|
|
||||||
void setRemoteFolder( const QString& remoteFolder);
|
void setRemoteFolder( const QString& remoteFolder);
|
||||||
void setMultipleFoldersExist( bool exist );
|
void setMultipleFoldersExist( bool exist );
|
||||||
void directoriesCreated();
|
void directoriesCreated();
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>912</width>
|
<width>917</width>
|
||||||
<height>633</height>
|
<height>493</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
@@ -226,14 +226,11 @@
|
|||||||
<item row="0" column="1" colspan="2">
|
<item row="0" column="1" colspan="2">
|
||||||
<widget class="QWidget" name="widget" native="true">
|
<widget class="QWidget" name="widget" native="true">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="rSyncEverything">
|
<widget class="QRadioButton" name="rSyncEverything">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@@ -266,64 +263,6 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
|
||||||
<property name="horizontalSpacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<spacer name="horizontalSpacer_4">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeType">
|
|
||||||
<enum>QSizePolicy::Minimum</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>10</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="confCheckBoxSize">
|
|
||||||
<property name="text">
|
|
||||||
<string>Ask for confirmation before synchroni&zing folders larger than</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QSpinBox" name="confSpinBox">
|
|
||||||
<property name="maximum">
|
|
||||||
<number>999999</number>
|
|
||||||
</property>
|
|
||||||
<property name="value">
|
|
||||||
<number>99</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="confTraillingSizeLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string extracomment="Trailing part of "Ask confirmation before syncing folder larger than" ">MB</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QCheckBox" name="confCheckBoxExternal">
|
|
||||||
<property name="text">
|
|
||||||
<string>Ask for confirmation before synchronizing e&xternal storages</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
@@ -406,70 +345,5 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections/>
|
||||||
<connection>
|
|
||||||
<sender>rSyncEverything</sender>
|
|
||||||
<signal>toggled(bool)</signal>
|
|
||||||
<receiver>confCheckBoxSize</receiver>
|
|
||||||
<slot>setEnabled(bool)</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>217</x>
|
|
||||||
<y>78</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>298</x>
|
|
||||||
<y>126</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>rSyncEverything</sender>
|
|
||||||
<signal>toggled(bool)</signal>
|
|
||||||
<receiver>confSpinBox</receiver>
|
|
||||||
<slot>setEnabled(bool)</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>311</x>
|
|
||||||
<y>83</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>952</x>
|
|
||||||
<y>134</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>rSyncEverything</sender>
|
|
||||||
<signal>toggled(bool)</signal>
|
|
||||||
<receiver>confTraillingSizeLabel</receiver>
|
|
||||||
<slot>setEnabled(bool)</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>277</x>
|
|
||||||
<y>76</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>1076</x>
|
|
||||||
<y>136</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>rSyncEverything</sender>
|
|
||||||
<signal>toggled(bool)</signal>
|
|
||||||
<receiver>confCheckBoxExternal</receiver>
|
|
||||||
<slot>setEnabled(bool)</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>181</x>
|
|
||||||
<y>78</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>382</x>
|
|
||||||
<y>174</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
</connections>
|
|
||||||
</ui>
|
</ui>
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>506</width>
|
<width>602</width>
|
||||||
<height>515</height>
|
<height>193</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="label_2">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Ser&ver Address</string>
|
<string>Server &Address</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy">
|
<property name="buddy">
|
||||||
<cstring>leUrl</cstring>
|
<cstring>leUrl</cstring>
|
||||||
@@ -166,13 +166,10 @@
|
|||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeType">
|
|
||||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
<width>20</width>
|
<width>20</width>
|
||||||
<height>200</height>
|
<height>40</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ void OwncloudShibbolethCredsPage::setupBrowser()
|
|||||||
// i.e. if someone presses "back"
|
// i.e. if someone presses "back"
|
||||||
QNetworkAccessManager *qnam = account->networkAccessManager();
|
QNetworkAccessManager *qnam = account->networkAccessManager();
|
||||||
CookieJar *jar = new CookieJar;
|
CookieJar *jar = new CookieJar;
|
||||||
jar->restore(account->cookieJarPath());
|
|
||||||
// Implicitly deletes the old cookie jar, and reparents the jar
|
// Implicitly deletes the old cookie jar, and reparents the jar
|
||||||
qnam->setCookieJar(jar);
|
qnam->setCookieJar(jar);
|
||||||
|
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ OwncloudWizard::OwncloudWizard(QWidget *parent)
|
|||||||
setTitleFormat(Qt::RichText);
|
setTitleFormat(Qt::RichText);
|
||||||
setSubTitleFormat(Qt::RichText);
|
setSubTitleFormat(Qt::RichText);
|
||||||
setButtonText(QWizard::CustomButton1, tr("Skip folders configuration"));
|
setButtonText(QWizard::CustomButton1, tr("Skip folders configuration"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OwncloudWizard::setAccount(AccountPtr account)
|
void OwncloudWizard::setAccount(AccountPtr account)
|
||||||
@@ -108,10 +109,6 @@ QStringList OwncloudWizard::selectiveSyncBlacklist() const
|
|||||||
return _advancedSetupPage->selectiveSyncBlacklist();
|
return _advancedSetupPage->selectiveSyncBlacklist();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OwncloudWizard::isConfirmBigFolderChecked() const
|
|
||||||
{
|
|
||||||
return _advancedSetupPage->isConfirmBigFolderChecked();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString OwncloudWizard::ocUrl() const
|
QString OwncloudWizard::ocUrl() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ public:
|
|||||||
QString ocUrl() const;
|
QString ocUrl() const;
|
||||||
QString localFolder() const;
|
QString localFolder() const;
|
||||||
QStringList selectiveSyncBlacklist() const;
|
QStringList selectiveSyncBlacklist() const;
|
||||||
bool isConfirmBigFolderChecked() const;
|
|
||||||
|
|
||||||
void enableFinishOnResultWidget(bool enable);
|
void enableFinishOnResultWidget(bool enable);
|
||||||
|
|
||||||
|
|||||||
@@ -172,6 +172,7 @@ void AbstractNetworkJob::slotFinished()
|
|||||||
|
|
||||||
// get the Date timestamp from reply
|
// get the Date timestamp from reply
|
||||||
_responseTimestamp = _reply->rawHeader("Date");
|
_responseTimestamp = _reply->rawHeader("Date");
|
||||||
|
_duration = _durationTimer.elapsed();
|
||||||
|
|
||||||
if (_followRedirects) {
|
if (_followRedirects) {
|
||||||
// ### the qWarnings here should be exported via displayErrors() so they
|
// ### the qWarnings here should be exported via displayErrors() so they
|
||||||
@@ -205,6 +206,11 @@ void AbstractNetworkJob::slotFinished()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quint64 AbstractNetworkJob::duration()
|
||||||
|
{
|
||||||
|
return _duration;
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray AbstractNetworkJob::responseTimestamp()
|
QByteArray AbstractNetworkJob::responseTimestamp()
|
||||||
{
|
{
|
||||||
return _responseTimestamp;
|
return _responseTimestamp;
|
||||||
@@ -218,6 +224,8 @@ AbstractNetworkJob::~AbstractNetworkJob()
|
|||||||
void AbstractNetworkJob::start()
|
void AbstractNetworkJob::start()
|
||||||
{
|
{
|
||||||
_timer.start();
|
_timer.start();
|
||||||
|
_durationTimer.start();
|
||||||
|
_duration = 0;
|
||||||
|
|
||||||
const QUrl url = account()->url();
|
const QUrl url = account()->url();
|
||||||
const QString displayUrl = QString( "%1://%2%3").arg(url.scheme()).arg(url.host()).arg(url.path());
|
const QString displayUrl = QString( "%1://%2%3").arg(url.scheme()).arg(url.host()).arg(url.path());
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ public:
|
|||||||
bool ignoreCredentialFailure() const { return _ignoreCredentialFailure; }
|
bool ignoreCredentialFailure() const { return _ignoreCredentialFailure; }
|
||||||
|
|
||||||
QByteArray responseTimestamp();
|
QByteArray responseTimestamp();
|
||||||
|
quint64 duration();
|
||||||
|
|
||||||
qint64 timeoutMsec() { return _timer.interval(); }
|
qint64 timeoutMsec() { return _timer.interval(); }
|
||||||
|
|
||||||
@@ -81,6 +82,8 @@ protected:
|
|||||||
int maxRedirects() const { return 10; }
|
int maxRedirects() const { return 10; }
|
||||||
virtual bool finished() = 0;
|
virtual bool finished() = 0;
|
||||||
QByteArray _responseTimestamp;
|
QByteArray _responseTimestamp;
|
||||||
|
QElapsedTimer _durationTimer;
|
||||||
|
quint64 _duration;
|
||||||
bool _timedout; // set to true when the timeout slot is received
|
bool _timedout; // set to true when the timeout slot is received
|
||||||
|
|
||||||
// Automatically follows redirects. Note that this only works for
|
// Automatically follows redirects. Note that this only works for
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
#include "creds/abstractcredentials.h"
|
#include "creds/abstractcredentials.h"
|
||||||
#include "capabilities.h"
|
#include "capabilities.h"
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
#include "asserts.h"
|
|
||||||
|
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
@@ -154,9 +153,8 @@ QUrl Account::davUrl() const
|
|||||||
*/
|
*/
|
||||||
void Account::clearCookieJar()
|
void Account::clearCookieJar()
|
||||||
{
|
{
|
||||||
auto jar = qobject_cast<CookieJar*>(_am->cookieJar());
|
Q_ASSERT(qobject_cast<CookieJar*>(_am->cookieJar()));
|
||||||
ASSERT(jar);
|
static_cast<CookieJar*>(_am->cookieJar())->setAllCookies(QList<QNetworkCookie>());
|
||||||
jar->setAllCookies(QList<QNetworkCookie>());
|
|
||||||
emit wantsAccountSaved(this);
|
emit wantsAccountSaved(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,12 +169,6 @@ void Account::lendCookieJarTo(QNetworkAccessManager *guest)
|
|||||||
jar->setParent(oldParent); // takes it back
|
jar->setParent(oldParent); // takes it back
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Account::cookieJarPath()
|
|
||||||
{
|
|
||||||
ConfigFile cfg;
|
|
||||||
return cfg.configPath() + "/cookies" + id() + ".db";
|
|
||||||
}
|
|
||||||
|
|
||||||
void Account::resetNetworkAccessManager()
|
void Account::resetNetworkAccessManager()
|
||||||
{
|
{
|
||||||
if (!_credentials || !_am) {
|
if (!_credentials || !_am) {
|
||||||
@@ -212,6 +204,7 @@ QNetworkReply *Account::headRequest(const QUrl &url)
|
|||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
#if QT_VERSION > QT_VERSION_CHECK(4, 8, 4)
|
#if QT_VERSION > QT_VERSION_CHECK(4, 8, 4)
|
||||||
request.setSslConfiguration(this->getOrCreateSslConfig());
|
request.setSslConfiguration(this->getOrCreateSslConfig());
|
||||||
|
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true);
|
||||||
#endif
|
#endif
|
||||||
return _am->head(request);
|
return _am->head(request);
|
||||||
}
|
}
|
||||||
@@ -226,6 +219,7 @@ QNetworkReply *Account::getRequest(const QUrl &url)
|
|||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
#if QT_VERSION > QT_VERSION_CHECK(4, 8, 4)
|
#if QT_VERSION > QT_VERSION_CHECK(4, 8, 4)
|
||||||
request.setSslConfiguration(this->getOrCreateSslConfig());
|
request.setSslConfiguration(this->getOrCreateSslConfig());
|
||||||
|
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true);
|
||||||
#endif
|
#endif
|
||||||
return _am->get(request);
|
return _am->get(request);
|
||||||
}
|
}
|
||||||
@@ -235,6 +229,7 @@ QNetworkReply *Account::deleteRequest( const QUrl &url)
|
|||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
#if QT_VERSION > QT_VERSION_CHECK(4, 8, 4)
|
#if QT_VERSION > QT_VERSION_CHECK(4, 8, 4)
|
||||||
request.setSslConfiguration(this->getOrCreateSslConfig());
|
request.setSslConfiguration(this->getOrCreateSslConfig());
|
||||||
|
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true);
|
||||||
#endif
|
#endif
|
||||||
return _am->deleteResource(request);
|
return _am->deleteResource(request);
|
||||||
}
|
}
|
||||||
@@ -249,6 +244,7 @@ QNetworkReply *Account::davRequest(const QByteArray &verb, const QUrl &url, QNet
|
|||||||
req.setUrl(url);
|
req.setUrl(url);
|
||||||
#if QT_VERSION > QT_VERSION_CHECK(4, 8, 4)
|
#if QT_VERSION > QT_VERSION_CHECK(4, 8, 4)
|
||||||
req.setSslConfiguration(this->getOrCreateSslConfig());
|
req.setSslConfiguration(this->getOrCreateSslConfig());
|
||||||
|
req.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true);
|
||||||
#endif
|
#endif
|
||||||
return _am->sendCustomRequest(req, verb, data);
|
return _am->sendCustomRequest(req, verb, data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,7 +172,6 @@ public:
|
|||||||
|
|
||||||
void clearCookieJar();
|
void clearCookieJar();
|
||||||
void lendCookieJarTo(QNetworkAccessManager *guest);
|
void lendCookieJarTo(QNetworkAccessManager *guest);
|
||||||
QString cookieJarPath();
|
|
||||||
|
|
||||||
void resetNetworkAccessManager();
|
void resetNetworkAccessManager();
|
||||||
QNetworkAccessManager* networkAccessManager();
|
QNetworkAccessManager* networkAccessManager();
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
#ifndef OWNCLOUD_ASSERTS_H
|
|
||||||
#define OWNCLOUD_ASSERTS_H
|
|
||||||
|
|
||||||
#include <qglobal.h>
|
|
||||||
|
|
||||||
#if defined(QT_FORCE_ASSERTS) || !defined(QT_NO_DEBUG)
|
|
||||||
#define OC_ASSERT_MSG qFatal
|
|
||||||
#else
|
|
||||||
#define OC_ASSERT_MSG qWarning
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// For overloading macros by argument count
|
|
||||||
// See stackoverflow.com/questions/16683146/can-macros-be-overloaded-by-number-of-arguments
|
|
||||||
#define OC_ASSERT_CAT(A, B) A ## B
|
|
||||||
#define OC_ASSERT_SELECT(NAME, NUM) OC_ASSERT_CAT(NAME ## _, NUM)
|
|
||||||
#define OC_ASSERT_GET_COUNT(_1, _2, _3, COUNT, ...) COUNT
|
|
||||||
#define OC_ASSERT_VA_SIZE(...) OC_ASSERT_GET_COUNT(__VA_ARGS__, 3, 2, 1, 0)
|
|
||||||
|
|
||||||
#define OC_ASSERT_OVERLOAD(NAME, ...) OC_ASSERT_SELECT(NAME, OC_ASSERT_VA_SIZE(__VA_ARGS__))(__VA_ARGS__)
|
|
||||||
|
|
||||||
// Default assert: If the condition is false in debug builds, terminate.
|
|
||||||
//
|
|
||||||
// Prints a message on failure, even in release builds.
|
|
||||||
#define ASSERT(...) OC_ASSERT_OVERLOAD(ASSERT, __VA_ARGS__)
|
|
||||||
#define ASSERT_1(cond) \
|
|
||||||
if (!(cond)) { \
|
|
||||||
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
|
||||||
} else {}
|
|
||||||
#define ASSERT_2(cond, message) \
|
|
||||||
if (!(cond)) { \
|
|
||||||
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
|
||||||
} else {}
|
|
||||||
|
|
||||||
// Enforce condition to be true, even in release builds.
|
|
||||||
//
|
|
||||||
// Prints 'message' and aborts execution if 'cond' is false.
|
|
||||||
#define ENFORCE(...) OC_ASSERT_OVERLOAD(ENFORCE, __VA_ARGS__)
|
|
||||||
#define ENFORCE_1(cond) \
|
|
||||||
if (!(cond)) { \
|
|
||||||
qFatal("ENFORCE: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
|
||||||
} else {}
|
|
||||||
#define ENFORCE_2(cond, message) \
|
|
||||||
if (!(cond)) { \
|
|
||||||
qFatal("ENFORCE: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
|
||||||
} else {}
|
|
||||||
|
|
||||||
// An assert that is only present in debug builds: typically used for
|
|
||||||
// asserts that are too expensive for release mode.
|
|
||||||
//
|
|
||||||
// Q_ASSERT
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -121,13 +121,4 @@ bool Capabilities::chunkingParallelUploadDisabled() const
|
|||||||
return _capabilities["dav"].toMap()["chunkingParallelUploadDisabled"].toBool();
|
return _capabilities["dav"].toMap()["chunkingParallelUploadDisabled"].toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<int> Capabilities::httpErrorCodesThatResetFailingChunkedUploads() const
|
|
||||||
{
|
|
||||||
QList<int> list;
|
|
||||||
foreach (const auto & t, _capabilities["dav"].toMap()["httpErrorCodesThatResetFailingChunkedUploads"].toList()) {
|
|
||||||
list.push_back(t.toInt());
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,25 +81,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
QByteArray uploadChecksumType() const;
|
QByteArray uploadChecksumType() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* List of HTTP error codes should be guaranteed to eventually reset
|
|
||||||
* failing chunked uploads.
|
|
||||||
*
|
|
||||||
* The resetting works by tracking UploadInfo::errorCount.
|
|
||||||
*
|
|
||||||
* Note that other error codes than the ones listed here may reset the
|
|
||||||
* upload as well.
|
|
||||||
*
|
|
||||||
* Motivation: See #5344. They should always be reset on 412 (possibly
|
|
||||||
* checksum error), but broken servers may also require resets on
|
|
||||||
* unusual error codes such as 503.
|
|
||||||
*
|
|
||||||
* Path: dav/httpErrorCodesThatResetFailingChunkedUploads
|
|
||||||
* Default: []
|
|
||||||
* Example: [503, 500]
|
|
||||||
*/
|
|
||||||
QList<int> httpErrorCodesThatResetFailingChunkedUploads() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVariantMap _capabilities;
|
QVariantMap _capabilities;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -111,11 +111,11 @@ bool uploadChecksumEnabled()
|
|||||||
QByteArray contentChecksumType()
|
QByteArray contentChecksumType()
|
||||||
{
|
{
|
||||||
static QByteArray type = qgetenv("OWNCLOUD_CONTENT_CHECKSUM_TYPE");
|
static QByteArray type = qgetenv("OWNCLOUD_CONTENT_CHECKSUM_TYPE");
|
||||||
if (type.isNull()) { // can set to "" to disable checksumming
|
if (!type.isNull()) { // can set to "" to disable checksumming
|
||||||
type = "SHA1";
|
|
||||||
}
|
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
return "SHA1";
|
||||||
|
}
|
||||||
|
|
||||||
ComputeChecksum::ComputeChecksum(QObject* parent)
|
ComputeChecksum::ComputeChecksum(QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
#include "configfile.h"
|
#include "configfile.h"
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "asserts.h"
|
|
||||||
|
|
||||||
#include "creds/abstractcredentials.h"
|
#include "creds/abstractcredentials.h"
|
||||||
|
|
||||||
@@ -68,7 +67,6 @@ static const char downloadLimitC[] = "BWLimit/downloadLimit";
|
|||||||
|
|
||||||
static const char newBigFolderSizeLimitC[] = "newBigFolderSizeLimit";
|
static const char newBigFolderSizeLimitC[] = "newBigFolderSizeLimit";
|
||||||
static const char useNewBigFolderSizeLimitC[] = "useNewBigFolderSizeLimit";
|
static const char useNewBigFolderSizeLimitC[] = "useNewBigFolderSizeLimit";
|
||||||
static const char confirmExternalStorageC[] = "confirmExternalStorage";
|
|
||||||
|
|
||||||
static const char maxLogLinesC[] = "Logging/maxLogLines";
|
static const char maxLogLinesC[] = "Logging/maxLogLines";
|
||||||
|
|
||||||
@@ -140,7 +138,7 @@ void ConfigFile::setOptionalDesktopNotifications(bool show)
|
|||||||
void ConfigFile::saveGeometry(QWidget *w)
|
void ConfigFile::saveGeometry(QWidget *w)
|
||||||
{
|
{
|
||||||
#ifndef TOKEN_AUTH_ONLY
|
#ifndef TOKEN_AUTH_ONLY
|
||||||
ASSERT(!w->objectName().isNull());
|
Q_ASSERT(!w->objectName().isNull());
|
||||||
QSettings settings(configFile(), QSettings::IniFormat);
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.beginGroup(w->objectName());
|
settings.beginGroup(w->objectName());
|
||||||
settings.setValue(QLatin1String(geometryC), w->saveGeometry());
|
settings.setValue(QLatin1String(geometryC), w->saveGeometry());
|
||||||
@@ -159,7 +157,7 @@ void ConfigFile::saveGeometryHeader(QHeaderView *header)
|
|||||||
{
|
{
|
||||||
#ifndef TOKEN_AUTH_ONLY
|
#ifndef TOKEN_AUTH_ONLY
|
||||||
if(!header) return;
|
if(!header) return;
|
||||||
ASSERT(!header->objectName().isEmpty());
|
Q_ASSERT(!header->objectName().isEmpty());
|
||||||
|
|
||||||
QSettings settings(configFile(), QSettings::IniFormat);
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.beginGroup(header->objectName());
|
settings.beginGroup(header->objectName());
|
||||||
@@ -172,7 +170,7 @@ void ConfigFile::restoreGeometryHeader(QHeaderView *header)
|
|||||||
{
|
{
|
||||||
#ifndef TOKEN_AUTH_ONLY
|
#ifndef TOKEN_AUTH_ONLY
|
||||||
if(!header) return;
|
if(!header) return;
|
||||||
ASSERT(!header->objectName().isNull());
|
Q_ASSERT(!header->objectName().isNull());
|
||||||
|
|
||||||
QSettings settings(configFile(), QSettings::IniFormat);
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
settings.beginGroup(header->objectName());
|
settings.beginGroup(header->objectName());
|
||||||
@@ -231,8 +229,8 @@ QString ConfigFile::excludeFile(Scope scope) const
|
|||||||
// directories.
|
// directories.
|
||||||
QFileInfo fi;
|
QFileInfo fi;
|
||||||
|
|
||||||
switch (scope) {
|
if (scope != SystemScope) {
|
||||||
case UserScope:
|
QFileInfo fi;
|
||||||
fi.setFile( configPath(), exclFile );
|
fi.setFile( configPath(), exclFile );
|
||||||
|
|
||||||
if( ! fi.isReadable() ) {
|
if( ! fi.isReadable() ) {
|
||||||
@@ -242,12 +240,12 @@ QString ConfigFile::excludeFile(Scope scope) const
|
|||||||
fi.setFile( configPath(), exclFile );
|
fi.setFile( configPath(), exclFile );
|
||||||
}
|
}
|
||||||
return fi.absoluteFilePath();
|
return fi.absoluteFilePath();
|
||||||
case SystemScope:
|
} else if (scope != UserScope) {
|
||||||
return ConfigFile::excludeFileFromSystem();
|
return ConfigFile::excludeFileFromSystem();
|
||||||
|
} else {
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return QString(); // unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(false);
|
|
||||||
return QString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ConfigFile::excludeFileFromSystem()
|
QString ConfigFile::excludeFileFromSystem()
|
||||||
@@ -598,16 +596,6 @@ void ConfigFile::setNewBigFolderSizeLimit(bool isChecked, quint64 mbytes)
|
|||||||
setValue(useNewBigFolderSizeLimitC, isChecked);
|
setValue(useNewBigFolderSizeLimitC, isChecked);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConfigFile::confirmExternalStorage() const
|
|
||||||
{
|
|
||||||
return getValue(confirmExternalStorageC, QString(), true).toBool();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigFile::setConfirmExternalStorage(bool isChecked)
|
|
||||||
{
|
|
||||||
setValue(confirmExternalStorageC, isChecked);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ConfigFile::promptDeleteFiles() const
|
bool ConfigFile::promptDeleteFiles() const
|
||||||
{
|
{
|
||||||
QSettings settings(configFile(), QSettings::IniFormat);
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
|
|||||||
@@ -105,8 +105,6 @@ public:
|
|||||||
/** [checked, size in MB] **/
|
/** [checked, size in MB] **/
|
||||||
QPair<bool, quint64> newBigFolderSizeLimit() const;
|
QPair<bool, quint64> newBigFolderSizeLimit() const;
|
||||||
void setNewBigFolderSizeLimit(bool isChecked, quint64 mbytes);
|
void setNewBigFolderSizeLimit(bool isChecked, quint64 mbytes);
|
||||||
bool confirmExternalStorage() const;
|
|
||||||
void setConfirmExternalStorage(bool);
|
|
||||||
|
|
||||||
static bool setConfDir(const QString &value);
|
static bool setConfDir(const QString &value);
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ QDataStream &operator>>(QDataStream &stream, QList<QNetworkCookie> &list)
|
|||||||
CookieJar::CookieJar(QObject *parent) :
|
CookieJar::CookieJar(QObject *parent) :
|
||||||
QNetworkCookieJar(parent)
|
QNetworkCookieJar(parent)
|
||||||
{
|
{
|
||||||
|
restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
CookieJar::~CookieJar()
|
CookieJar::~CookieJar()
|
||||||
@@ -96,21 +97,21 @@ void CookieJar::clearSessionCookies()
|
|||||||
setAllCookies(removeExpired(allCookies()));
|
setAllCookies(removeExpired(allCookies()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CookieJar::save(const QString &fileName)
|
void CookieJar::save()
|
||||||
{
|
{
|
||||||
QFile file;
|
QFile file;
|
||||||
file.setFileName(fileName);
|
file.setFileName(storagePath());
|
||||||
qDebug() << fileName;
|
qDebug() << storagePath();
|
||||||
file.open(QIODevice::WriteOnly);
|
file.open(QIODevice::WriteOnly);
|
||||||
QDataStream stream(&file);
|
QDataStream stream(&file);
|
||||||
stream << removeExpired(allCookies());
|
stream << removeExpired(allCookies());
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CookieJar::restore(const QString &fileName)
|
void CookieJar::restore()
|
||||||
{
|
{
|
||||||
QFile file;
|
QFile file;
|
||||||
file.setFileName(fileName);
|
file.setFileName(storagePath());
|
||||||
file.open(QIODevice::ReadOnly);
|
file.open(QIODevice::ReadOnly);
|
||||||
QDataStream stream(&file);
|
QDataStream stream(&file);
|
||||||
QList<QNetworkCookie> list;
|
QList<QNetworkCookie> list;
|
||||||
@@ -130,4 +131,10 @@ QList<QNetworkCookie> CookieJar::removeExpired(const QList<QNetworkCookie> &cook
|
|||||||
return updatedList;
|
return updatedList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString CookieJar::storagePath() const
|
||||||
|
{
|
||||||
|
ConfigFile cfg;
|
||||||
|
return cfg.configPath() + "/cookies.db";
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|||||||
@@ -39,13 +39,15 @@ public:
|
|||||||
using QNetworkCookieJar::setAllCookies;
|
using QNetworkCookieJar::setAllCookies;
|
||||||
using QNetworkCookieJar::allCookies;
|
using QNetworkCookieJar::allCookies;
|
||||||
|
|
||||||
void save(const QString &fileName);
|
void save();
|
||||||
void restore(const QString &fileName);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void newCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
|
void newCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
|
||||||
private:
|
private:
|
||||||
|
void restore();
|
||||||
QList<QNetworkCookie> removeExpired(const QList<QNetworkCookie> &cookies);
|
QList<QNetworkCookie> removeExpired(const QList<QNetworkCookie> &cookies);
|
||||||
|
QString storagePath() const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
* for more details.
|
* for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "asserts.h"
|
|
||||||
#include "creds/abstractcredentials.h"
|
#include "creds/abstractcredentials.h"
|
||||||
|
|
||||||
namespace OCC
|
namespace OCC
|
||||||
@@ -28,7 +28,7 @@ AbstractCredentials::AbstractCredentials()
|
|||||||
|
|
||||||
void AbstractCredentials::setAccount(Account *account)
|
void AbstractCredentials::setAccount(Account *account)
|
||||||
{
|
{
|
||||||
ENFORCE(!_account, "should only setAccount once");
|
Q_ASSERT(!_account);
|
||||||
_account = account;
|
_account = account;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,19 +13,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "discoveryphase.h"
|
#include "discoveryphase.h"
|
||||||
|
|
||||||
#include "account.h"
|
|
||||||
#include "theme.h"
|
|
||||||
#include "asserts.h"
|
|
||||||
|
|
||||||
#include <csync_private.h>
|
#include <csync_private.h>
|
||||||
#include <csync_rename.h>
|
#include <csync_rename.h>
|
||||||
|
|
||||||
#include <qdebug.h>
|
#include <qdebug.h>
|
||||||
#include <QUrl>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
|
#include <QUrl>
|
||||||
|
#include "account.h"
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
@@ -87,32 +81,14 @@ int DiscoveryJob::isInSelectiveSyncBlackListCallback(void *data, const char *pat
|
|||||||
return static_cast<DiscoveryJob*>(data)->isInSelectiveSyncBlackList(path);
|
return static_cast<DiscoveryJob*>(data)->isInSelectiveSyncBlackList(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiscoveryJob::checkSelectiveSyncNewFolder(const QString& path, const char *remotePerm)
|
bool DiscoveryJob::checkSelectiveSyncNewFolder(const QString& path)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (_syncOptions._confirmExternalStorage && std::strchr(remotePerm, 'M')) {
|
|
||||||
// 'M' in the permission means external storage.
|
|
||||||
|
|
||||||
/* Note: DiscoverySingleDirectoryJob::directoryListingIteratedSlot make sure that only the
|
|
||||||
* root of a mounted storage has 'M', all sub entries have 'm' */
|
|
||||||
|
|
||||||
// Only allow it if the white list contains exactly this path (not parents)
|
|
||||||
// We want to ask confirmation for external storage even if the parents where selected
|
|
||||||
if (_selectiveSyncWhiteList.contains(path + QLatin1Char('/'))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit newBigFolder(path, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this path or the parent is in the white list, then we do not block this file
|
// If this path or the parent is in the white list, then we do not block this file
|
||||||
if (findPathInList(_selectiveSyncWhiteList, path)) {
|
if (findPathInList(_selectiveSyncWhiteList, path)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto limit = _syncOptions._newBigFolderSizeLimit;
|
if (_newBigFolderSizeLimit < 0) {
|
||||||
if (limit < 0) {
|
|
||||||
// no limit, everything is allowed;
|
// no limit, everything is allowed;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -126,9 +102,10 @@ bool DiscoveryJob::checkSelectiveSyncNewFolder(const QString& path, const char *
|
|||||||
_vioWaitCondition.wait(&_vioMutex);
|
_vioWaitCondition.wait(&_vioMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto limit = _newBigFolderSizeLimit;
|
||||||
if (result >= limit) {
|
if (result >= limit) {
|
||||||
// we tell the UI there is a new folder
|
// we tell the UI there is a new folder
|
||||||
emit newBigFolder(path, false);
|
emit newBigFolder(path);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// it is not too big, put it in the white list (so we will not do more query for the children)
|
// it is not too big, put it in the white list (so we will not do more query for the children)
|
||||||
@@ -142,9 +119,9 @@ bool DiscoveryJob::checkSelectiveSyncNewFolder(const QString& path, const char *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int DiscoveryJob::checkSelectiveSyncNewFolderCallback(void *data, const char *path, const char *remotePerm)
|
int DiscoveryJob::checkSelectiveSyncNewFolderCallback(void *data, const char *path)
|
||||||
{
|
{
|
||||||
return static_cast<DiscoveryJob*>(data)->checkSelectiveSyncNewFolder(QString::fromUtf8(path), remotePerm);
|
return static_cast<DiscoveryJob*>(data)->checkSelectiveSyncNewFolder(QString::fromUtf8(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -247,7 +224,7 @@ int get_errno_from_http_errcode( int err, const QString & reason ) {
|
|||||||
|
|
||||||
|
|
||||||
DiscoverySingleDirectoryJob::DiscoverySingleDirectoryJob(const AccountPtr &account, const QString &path, QObject *parent)
|
DiscoverySingleDirectoryJob::DiscoverySingleDirectoryJob(const AccountPtr &account, const QString &path, QObject *parent)
|
||||||
: QObject(parent), _subPath(path), _account(account), _ignoredFirst(false), _isRootPath(false), _isExternalStorage(false)
|
: QObject(parent), _subPath(path), _account(account), _ignoredFirst(false), _isRootPath(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,9 +321,7 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(QString file, con
|
|||||||
// The first entry is for the folder itself, we should process it differently.
|
// The first entry is for the folder itself, we should process it differently.
|
||||||
_ignoredFirst = true;
|
_ignoredFirst = true;
|
||||||
if (map.contains("permissions")) {
|
if (map.contains("permissions")) {
|
||||||
auto perm = map.value("permissions");
|
emit firstDirectoryPermissions(map.value("permissions"));
|
||||||
emit firstDirectoryPermissions(perm);
|
|
||||||
_isExternalStorage = perm.contains(QLatin1Char('M'));
|
|
||||||
}
|
}
|
||||||
if (map.contains("data-fingerprint")) {
|
if (map.contains("data-fingerprint")) {
|
||||||
_dataFingerprint = map.value("data-fingerprint").toUtf8();
|
_dataFingerprint = map.value("data-fingerprint").toUtf8();
|
||||||
@@ -369,13 +344,6 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(QString file, con
|
|||||||
if (!file_stat->etag || strlen(file_stat->etag) == 0) {
|
if (!file_stat->etag || strlen(file_stat->etag) == 0) {
|
||||||
qDebug() << "WARNING: etag of" << file_stat->name << "is" << file_stat->etag << " This must not happen.";
|
qDebug() << "WARNING: etag of" << file_stat->name << "is" << file_stat->etag << " This must not happen.";
|
||||||
}
|
}
|
||||||
if (_isExternalStorage) {
|
|
||||||
/* All the entries in a external storage have 'M' in their permission. However, for all
|
|
||||||
purposes in the desktop client, we only need to know about the mount points.
|
|
||||||
So replace the 'M' by a 'm' for every sub entries in an external storage */
|
|
||||||
std::replace(file_stat->remotePerm, file_stat->remotePerm + strlen(file_stat->remotePerm),
|
|
||||||
'M', 'm');
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringRef fileRef(&file);
|
QStringRef fileRef(&file);
|
||||||
int slashPos = file.lastIndexOf(QLatin1Char('/'));
|
int slashPos = file.lastIndexOf(QLatin1Char('/'));
|
||||||
|
|||||||
@@ -34,16 +34,6 @@ class Account;
|
|||||||
* if the files are new, or changed.
|
* if the files are new, or changed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct SyncOptions {
|
|
||||||
SyncOptions() : _newBigFolderSizeLimit(-1), _confirmExternalStorage(false) {}
|
|
||||||
/** Maximum size (in Bytes) a folder can have without asking for confirmation.
|
|
||||||
* -1 means infinite */
|
|
||||||
qint64 _newBigFolderSizeLimit;
|
|
||||||
/** If a confirmation should be asked for external storages */
|
|
||||||
bool _confirmExternalStorage;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The FileStatPointer class
|
* @brief The FileStatPointer class
|
||||||
* @ingroup libsync
|
* @ingroup libsync
|
||||||
@@ -117,8 +107,6 @@ private:
|
|||||||
bool _ignoredFirst;
|
bool _ignoredFirst;
|
||||||
// Set to true if this is the root path and we need to check the data-fingerprint
|
// Set to true if this is the root path and we need to check the data-fingerprint
|
||||||
bool _isRootPath;
|
bool _isRootPath;
|
||||||
// If this directory is an external storage (The first item has 'M' in its permission)
|
|
||||||
bool _isExternalStorage;
|
|
||||||
QPointer<LsColJob> _lsColJob;
|
QPointer<LsColJob> _lsColJob;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -188,8 +176,8 @@ class DiscoveryJob : public QObject {
|
|||||||
*/
|
*/
|
||||||
bool isInSelectiveSyncBlackList(const char* path) const;
|
bool isInSelectiveSyncBlackList(const char* path) const;
|
||||||
static int isInSelectiveSyncBlackListCallback(void *, const char *);
|
static int isInSelectiveSyncBlackListCallback(void *, const char *);
|
||||||
bool checkSelectiveSyncNewFolder(const QString &path, const char *remotePerm);
|
bool checkSelectiveSyncNewFolder(const QString &path);
|
||||||
static int checkSelectiveSyncNewFolderCallback(void* data, const char* path, const char* remotePerm);
|
static int checkSelectiveSyncNewFolderCallback(void*, const char*);
|
||||||
|
|
||||||
// Just for progress
|
// Just for progress
|
||||||
static void update_job_update_callback (bool local,
|
static void update_job_update_callback (bool local,
|
||||||
@@ -209,7 +197,7 @@ class DiscoveryJob : public QObject {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DiscoveryJob(CSYNC *ctx, QObject* parent = 0)
|
explicit DiscoveryJob(CSYNC *ctx, QObject* parent = 0)
|
||||||
: QObject(parent), _csync_ctx(ctx) {
|
: QObject(parent), _csync_ctx(ctx), _newBigFolderSizeLimit(-1) {
|
||||||
// We need to forward the log property as csync uses thread local
|
// We need to forward the log property as csync uses thread local
|
||||||
// and updates run in another thread
|
// and updates run in another thread
|
||||||
_log_callback = csync_get_log_callback();
|
_log_callback = csync_get_log_callback();
|
||||||
@@ -219,7 +207,7 @@ public:
|
|||||||
|
|
||||||
QStringList _selectiveSyncBlackList;
|
QStringList _selectiveSyncBlackList;
|
||||||
QStringList _selectiveSyncWhiteList;
|
QStringList _selectiveSyncWhiteList;
|
||||||
SyncOptions _syncOptions;
|
qint64 _newBigFolderSizeLimit;
|
||||||
Q_INVOKABLE void start();
|
Q_INVOKABLE void start();
|
||||||
signals:
|
signals:
|
||||||
void finished(int result);
|
void finished(int result);
|
||||||
@@ -230,7 +218,7 @@ signals:
|
|||||||
void doGetSizeSignal(const QString &path, qint64 *result);
|
void doGetSizeSignal(const QString &path, qint64 *result);
|
||||||
|
|
||||||
// A new folder was discovered and was not synced because of the confirmation feature
|
// A new folder was discovered and was not synced because of the confirmation feature
|
||||||
void newBigFolder(const QString &folder, bool isExternal);
|
void newBigFolder(const QString &folder);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ void ExcludedFiles::addExcludeFilePath(const QString& path)
|
|||||||
_excludeFiles.insert(path);
|
_excludeFiles.insert(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_TESTING
|
#ifdef WITH_UNIT_TESTING
|
||||||
void ExcludedFiles::addExcludeExpr(const QString &expr)
|
void ExcludedFiles::addExcludeExpr(const QString &expr)
|
||||||
{
|
{
|
||||||
_csync_exclude_add(_excludesPtr, expr.toLatin1().constData());
|
_csync_exclude_add(_excludesPtr, expr.toLatin1().constData());
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public:
|
|||||||
const QString& basePath,
|
const QString& basePath,
|
||||||
bool excludeHidden) const;
|
bool excludeHidden) const;
|
||||||
|
|
||||||
#ifdef WITH_TESTING
|
#ifdef WITH_UNIT_TESTING
|
||||||
void addExcludeExpr(const QString &expr);
|
void addExcludeExpr(const QString &expr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ QString OWNCLOUDSYNC_EXPORT longWinPath( const QString& inpath );
|
|||||||
*/
|
*/
|
||||||
time_t OWNCLOUDSYNC_EXPORT getModTime(const QString& filename);
|
time_t OWNCLOUDSYNC_EXPORT getModTime(const QString& filename);
|
||||||
|
|
||||||
bool OWNCLOUDSYNC_EXPORT setModTime(const QString &filename, time_t modTime);
|
bool setModTime(const QString &filename, time_t modTime);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the size for a file
|
* @brief Get the size for a file
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#include "configfile.h"
|
#include "configfile.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "account.h"
|
#include "account.h"
|
||||||
#include "asserts.h"
|
|
||||||
#include <json.h>
|
#include <json.h>
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
@@ -100,7 +99,7 @@ int OwncloudPropagator::hardMaximumActiveJob()
|
|||||||
|
|
||||||
/** Updates, creates or removes a blacklist entry for the given item.
|
/** Updates, creates or removes a blacklist entry for the given item.
|
||||||
*
|
*
|
||||||
* Returns whether the error should be suppressed.
|
* Returns whether the file is in the blacklist now.
|
||||||
*/
|
*/
|
||||||
static bool blacklistCheck(SyncJournalDb* journal, const SyncFileItem& item)
|
static bool blacklistCheck(SyncJournalDb* journal, const SyncFileItem& item)
|
||||||
{
|
{
|
||||||
@@ -109,13 +108,16 @@ static bool blacklistCheck(SyncJournalDb* journal, const SyncFileItem& item)
|
|||||||
|
|
||||||
if (newEntry.isValid()) {
|
if (newEntry.isValid()) {
|
||||||
journal->updateErrorBlacklistEntry(newEntry);
|
journal->updateErrorBlacklistEntry(newEntry);
|
||||||
|
// Also clear upload info if any so we don't resume from the same transfer-id if there was too many failures (#5344)
|
||||||
|
// (maybe the reason is that the state for this transfer id is broken on the server.)
|
||||||
|
if (newEntry._retryCount > 3) {
|
||||||
|
journal->setUploadInfo(item._file, SyncJournalDb::UploadInfo());
|
||||||
|
}
|
||||||
} else if (oldEntry.isValid()) {
|
} else if (oldEntry.isValid()) {
|
||||||
journal->wipeErrorBlacklistEntry(item._file);
|
journal->wipeErrorBlacklistEntry(item._file);
|
||||||
}
|
}
|
||||||
|
|
||||||
// In some cases we add errors to the blacklist for tracking, but don't
|
return newEntry.isValid();
|
||||||
// want to actively suppress them.
|
|
||||||
return newEntry.isValid() && newEntry._ignoreDuration > 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorString)
|
void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorString)
|
||||||
@@ -133,7 +135,7 @@ void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorStr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( propagator()->_abortRequested.fetchAndAddRelaxed(0) &&
|
if( _propagator->_abortRequested.fetchAndAddRelaxed(0) &&
|
||||||
(status == SyncFileItem::NormalError || status == SyncFileItem::FatalError)) {
|
(status == SyncFileItem::NormalError || status == SyncFileItem::FatalError)) {
|
||||||
// an abort request is ongoing. Change the status to Soft-Error
|
// an abort request is ongoing. Change the status to Soft-Error
|
||||||
status = SyncFileItem::SoftError;
|
status = SyncFileItem::SoftError;
|
||||||
@@ -142,12 +144,10 @@ void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorStr
|
|||||||
switch( status ) {
|
switch( status ) {
|
||||||
case SyncFileItem::SoftError:
|
case SyncFileItem::SoftError:
|
||||||
case SyncFileItem::FatalError:
|
case SyncFileItem::FatalError:
|
||||||
|
// do not blacklist in case of soft error or fatal error.
|
||||||
|
break;
|
||||||
case SyncFileItem::NormalError:
|
case SyncFileItem::NormalError:
|
||||||
// For normal errors, we blacklist aggressively, otherwise only on
|
if (blacklistCheck(_propagator->_journal, *_item) && _item->_hasBlacklistEntry) {
|
||||||
// explicit request.
|
|
||||||
if ((status == SyncFileItem::NormalError || _item->_errorMayBeBlacklisted)
|
|
||||||
&& blacklistCheck(propagator()->_journal, *_item)
|
|
||||||
&& _item->_hasBlacklistEntry) {
|
|
||||||
// do not error if the item was, and continues to be, blacklisted
|
// do not error if the item was, and continues to be, blacklisted
|
||||||
status = SyncFileItem::FileIgnored;
|
status = SyncFileItem::FileIgnored;
|
||||||
_item->_errorString.prepend(tr("Continue blacklisting:") + " ");
|
_item->_errorString.prepend(tr("Continue blacklisting:") + " ");
|
||||||
@@ -157,10 +157,10 @@ void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorStr
|
|||||||
case SyncFileItem::Restoration:
|
case SyncFileItem::Restoration:
|
||||||
if( _item->_hasBlacklistEntry ) {
|
if( _item->_hasBlacklistEntry ) {
|
||||||
// wipe blacklist entry.
|
// wipe blacklist entry.
|
||||||
propagator()->_journal->wipeErrorBlacklistEntry(_item->_file);
|
_propagator->_journal->wipeErrorBlacklistEntry(_item->_file);
|
||||||
// remove a blacklist entry in case the file was moved.
|
// remove a blacklist entry in case the file was moved.
|
||||||
if( _item->_originalFile != _item->_file ) {
|
if( _item->_originalFile != _item->_file ) {
|
||||||
propagator()->_journal->wipeErrorBlacklistEntry(_item->_originalFile);
|
_propagator->_journal->wipeErrorBlacklistEntry(_item->_originalFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -173,7 +173,7 @@ void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorStr
|
|||||||
|
|
||||||
_item->_status = status;
|
_item->_status = status;
|
||||||
|
|
||||||
emit itemCompleted(_item);
|
emit itemCompleted(*_item, *this);
|
||||||
emit finished(status);
|
emit finished(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@ bool PropagateItemJob::checkForProblemsWithShared(int httpStatusCode, const QStr
|
|||||||
{
|
{
|
||||||
PropagateItemJob *newJob = NULL;
|
PropagateItemJob *newJob = NULL;
|
||||||
|
|
||||||
if( httpStatusCode == 403 && propagator()->isInSharedDirectory(_item->_file )) {
|
if( httpStatusCode == 403 && _propagator->isInSharedDirectory(_item->_file )) {
|
||||||
if( !_item->_isDirectory ) {
|
if( !_item->_isDirectory ) {
|
||||||
SyncFileItemPtr downloadItem(new SyncFileItem(*_item));
|
SyncFileItemPtr downloadItem(new SyncFileItem(*_item));
|
||||||
if (downloadItem->_instruction == CSYNC_INSTRUCTION_NEW
|
if (downloadItem->_instruction == CSYNC_INSTRUCTION_NEW
|
||||||
@@ -206,23 +206,23 @@ bool PropagateItemJob::checkForProblemsWithShared(int httpStatusCode, const QStr
|
|||||||
downloadItem->_instruction = CSYNC_INSTRUCTION_SYNC;
|
downloadItem->_instruction = CSYNC_INSTRUCTION_SYNC;
|
||||||
}
|
}
|
||||||
downloadItem->_direction = SyncFileItem::Down;
|
downloadItem->_direction = SyncFileItem::Down;
|
||||||
newJob = new PropagateDownloadFile(propagator(), downloadItem);
|
newJob = new PropagateDownloadFile(_propagator, downloadItem);
|
||||||
} else {
|
} else {
|
||||||
// Directories are harder to recover.
|
// Directories are harder to recover.
|
||||||
// But just re-create the directory, next sync will be able to recover the files
|
// But just re-create the directory, next sync will be able to recover the files
|
||||||
SyncFileItemPtr mkdirItem(new SyncFileItem(*_item));
|
SyncFileItemPtr mkdirItem(new SyncFileItem(*_item));
|
||||||
mkdirItem->_instruction = CSYNC_INSTRUCTION_NEW;
|
mkdirItem->_instruction = CSYNC_INSTRUCTION_NEW;
|
||||||
mkdirItem->_direction = SyncFileItem::Down;
|
mkdirItem->_direction = SyncFileItem::Down;
|
||||||
newJob = new PropagateLocalMkdir(propagator(), mkdirItem);
|
newJob = new PropagateLocalMkdir(_propagator, mkdirItem);
|
||||||
// Also remove the inodes and fileid from the db so no further renames are tried for
|
// Also remove the inodes and fileid from the db so no further renames are tried for
|
||||||
// this item.
|
// this item.
|
||||||
propagator()->_journal->avoidRenamesOnNextSync(_item->_file);
|
_propagator->_journal->avoidRenamesOnNextSync(_item->_file);
|
||||||
propagator()->_anotherSyncNeeded = true;
|
_propagator->_anotherSyncNeeded = true;
|
||||||
}
|
}
|
||||||
if( newJob ) {
|
if( newJob ) {
|
||||||
newJob->setRestoreJobMsg(msg);
|
newJob->setRestoreJobMsg(msg);
|
||||||
_restoreJob.reset(newJob);
|
_restoreJob.reset(newJob);
|
||||||
connect(_restoreJob.data(), SIGNAL(itemCompleted(const SyncFileItemPtr &)),
|
connect(_restoreJob.data(), SIGNAL(itemCompleted(const SyncFileItemPtr &, const PropagatorJob &)),
|
||||||
this, SLOT(slotRestoreJobCompleted(const SyncFileItemPtr &)));
|
this, SLOT(slotRestoreJobCompleted(const SyncFileItemPtr &)));
|
||||||
QMetaObject::invokeMethod(newJob, "start");
|
QMetaObject::invokeMethod(newJob, "start");
|
||||||
}
|
}
|
||||||
@@ -404,8 +404,8 @@ void OwncloudPropagator::start(const SyncFileItemVector& items)
|
|||||||
_rootJob->append(it);
|
_rootJob->append(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(_rootJob.data(), SIGNAL(itemCompleted(const SyncFileItemPtr &)),
|
connect(_rootJob.data(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)),
|
||||||
this, SIGNAL(itemCompleted(const SyncFileItemPtr &)));
|
this, SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||||
connect(_rootJob.data(), SIGNAL(progress(const SyncFileItem &,quint64)), this, SIGNAL(progress(const SyncFileItem &,quint64)));
|
connect(_rootJob.data(), SIGNAL(progress(const SyncFileItem &,quint64)), this, SIGNAL(progress(const SyncFileItem &,quint64)));
|
||||||
connect(_rootJob.data(), SIGNAL(finished(SyncFileItem::Status)), this, SLOT(emitFinished(SyncFileItem::Status)));
|
connect(_rootJob.data(), SIGNAL(finished(SyncFileItem::Status)), this, SLOT(emitFinished(SyncFileItem::Status)));
|
||||||
connect(_rootJob.data(), SIGNAL(ready()), this, SLOT(scheduleNextJob()), Qt::QueuedConnection);
|
connect(_rootJob.data(), SIGNAL(ready()), this, SLOT(scheduleNextJob()), Qt::QueuedConnection);
|
||||||
@@ -574,27 +574,20 @@ OwncloudPropagator::DiskSpaceResult OwncloudPropagator::diskSpaceCheck() const
|
|||||||
|
|
||||||
// ================================================================================
|
// ================================================================================
|
||||||
|
|
||||||
PropagatorJob::PropagatorJob(OwncloudPropagator *propagator)
|
|
||||||
: QObject(propagator)
|
|
||||||
, _state(NotYetStarted)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
OwncloudPropagator *PropagatorJob::propagator() const
|
|
||||||
{
|
|
||||||
return qobject_cast<OwncloudPropagator*>(parent());
|
|
||||||
}
|
|
||||||
|
|
||||||
PropagatorJob::JobParallelism PropagateDirectory::parallelism()
|
PropagatorJob::JobParallelism PropagateDirectory::parallelism()
|
||||||
{
|
{
|
||||||
// If any of the non-finished sub jobs is not parallel, we have to wait
|
// If any of the non-finished sub jobs is not parallel, we have to wait
|
||||||
if (_firstJob && _firstJob->parallelism() != FullParallelism) {
|
|
||||||
|
// FIXME! we should probably cache this result
|
||||||
|
|
||||||
|
if (_firstJob && _firstJob->_state != Finished) {
|
||||||
|
if (_firstJob->parallelism() != FullParallelism)
|
||||||
return WaitForFinished;
|
return WaitForFinished;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: use the cached value of finished job
|
||||||
for (int i = 0; i < _subJobs.count(); ++i) {
|
for (int i = 0; i < _subJobs.count(); ++i) {
|
||||||
if (_subJobs.at(i)->parallelism() != FullParallelism) {
|
if (_subJobs.at(i)->_state != Finished && _subJobs.at(i)->parallelism() != FullParallelism) {
|
||||||
return WaitForFinished;
|
return WaitForFinished;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -625,8 +618,15 @@ bool PropagateDirectory::scheduleNextJob()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cache the value of first unfinished subjob
|
||||||
bool stopAtDirectory = false;
|
bool stopAtDirectory = false;
|
||||||
for (int i = 0; i < _subJobs.size(); ++i) {
|
int i = _firstUnfinishedSubJob;
|
||||||
|
int subJobsCount = _subJobs.count();
|
||||||
|
while (i < subJobsCount && _subJobs.at(i)->_state == Finished) {
|
||||||
|
_firstUnfinishedSubJob = ++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = _firstUnfinishedSubJob; i < subJobsCount; ++i) {
|
||||||
if (_subJobs.at(i)->_state == Finished) {
|
if (_subJobs.at(i)->_state == Finished) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -639,7 +639,7 @@ bool PropagateDirectory::scheduleNextJob()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(_subJobs.at(i)->_state == Running);
|
Q_ASSERT(_subJobs.at(i)->_state == Running);
|
||||||
|
|
||||||
auto paral = _subJobs.at(i)->parallelism();
|
auto paral = _subJobs.at(i)->parallelism();
|
||||||
if (paral == WaitForFinished) {
|
if (paral == WaitForFinished) {
|
||||||
@@ -654,23 +654,8 @@ bool PropagateDirectory::scheduleNextJob()
|
|||||||
|
|
||||||
void PropagateDirectory::slotSubJobFinished(SyncFileItem::Status status)
|
void PropagateDirectory::slotSubJobFinished(SyncFileItem::Status status)
|
||||||
{
|
{
|
||||||
PropagatorJob *subJob = static_cast<PropagatorJob *>(sender());
|
|
||||||
ASSERT(subJob);
|
|
||||||
|
|
||||||
// Delete the job and remove it from our list of jobs.
|
|
||||||
subJob->deleteLater();
|
|
||||||
bool wasFirstJob = false;
|
|
||||||
if (subJob == _firstJob.data()) {
|
|
||||||
wasFirstJob = true;
|
|
||||||
_firstJob.take();
|
|
||||||
} else {
|
|
||||||
int i = _subJobs.indexOf(subJob);
|
|
||||||
ASSERT(i >= 0);
|
|
||||||
_subJobs.remove(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == SyncFileItem::FatalError ||
|
if (status == SyncFileItem::FatalError ||
|
||||||
(wasFirstJob && status != SyncFileItem::Success && status != SyncFileItem::Restoration)) {
|
(sender() == _firstJob.data() && status != SyncFileItem::Success && status != SyncFileItem::Restoration)) {
|
||||||
abort();
|
abort();
|
||||||
_state = Finished;
|
_state = Finished;
|
||||||
emit finished(status);
|
emit finished(status);
|
||||||
@@ -678,10 +663,18 @@ void PropagateDirectory::slotSubJobFinished(SyncFileItem::Status status)
|
|||||||
} else if (status == SyncFileItem::NormalError || status == SyncFileItem::SoftError) {
|
} else if (status == SyncFileItem::NormalError || status == SyncFileItem::SoftError) {
|
||||||
_hasError = status;
|
_hasError = status;
|
||||||
}
|
}
|
||||||
|
_runningNow--;
|
||||||
|
_jobsFinished++;
|
||||||
|
|
||||||
|
int totalJobs = _subJobs.count();
|
||||||
|
if (_firstJob) {
|
||||||
|
totalJobs++;
|
||||||
|
}
|
||||||
|
|
||||||
// We finished processing all the jobs
|
// We finished processing all the jobs
|
||||||
// check if we finished
|
// check if we finished
|
||||||
if (!_firstJob && _subJobs.isEmpty()) {
|
if (_jobsFinished >= totalJobs) {
|
||||||
|
Q_ASSERT(!_runningNow); // how can we be finished if there are still jobs running now
|
||||||
finalize();
|
finalize();
|
||||||
} else {
|
} else {
|
||||||
emit ready();
|
emit ready();
|
||||||
@@ -696,7 +689,7 @@ void PropagateDirectory::finalize()
|
|||||||
if(_item->_instruction == CSYNC_INSTRUCTION_RENAME
|
if(_item->_instruction == CSYNC_INSTRUCTION_RENAME
|
||||||
&& _item->_originalFile != _item->_renameTarget) {
|
&& _item->_originalFile != _item->_renameTarget) {
|
||||||
// Remove the stale entries from the database.
|
// Remove the stale entries from the database.
|
||||||
propagator()->_journal->deleteFileRecord(_item->_originalFile, true);
|
_propagator->_journal->deleteFileRecord(_item->_originalFile, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
_item->_file = _item->_renameTarget;
|
_item->_file = _item->_renameTarget;
|
||||||
@@ -714,8 +707,8 @@ void PropagateDirectory::finalize()
|
|||||||
_item->_fileId = mkdir->_item->_fileId;
|
_item->_fileId = mkdir->_item->_fileId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SyncJournalFileRecord record(*_item, propagator()->_localDir + _item->_file);
|
SyncJournalFileRecord record(*_item, _propagator->_localDir + _item->_file);
|
||||||
ok = propagator()->_journal->setFileRecordMetadata(record);
|
ok = _propagator->_journal->setFileRecordMetadata(record);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
_hasError = _item->_status = SyncFileItem::FatalError;
|
_hasError = _item->_status = SyncFileItem::FatalError;
|
||||||
_item->_errorString = tr("Error writing metadata to the database");
|
_item->_errorString = tr("Error writing metadata to the database");
|
||||||
@@ -761,7 +754,7 @@ void CleanupPollsJob::start()
|
|||||||
void CleanupPollsJob::slotPollFinished()
|
void CleanupPollsJob::slotPollFinished()
|
||||||
{
|
{
|
||||||
PollJob *job = qobject_cast<PollJob *>(sender());
|
PollJob *job = qobject_cast<PollJob *>(sender());
|
||||||
ASSERT(job);
|
Q_ASSERT(job);
|
||||||
if (job->_item->_status == SyncFileItem::FatalError) {
|
if (job->_item->_status == SyncFileItem::FatalError) {
|
||||||
emit aborted(job->_item->_errorString);
|
emit aborted(job->_item->_errorString);
|
||||||
deleteLater();
|
deleteLater();
|
||||||
|
|||||||
@@ -56,9 +56,11 @@ class OwncloudPropagator;
|
|||||||
*/
|
*/
|
||||||
class PropagatorJob : public QObject {
|
class PropagatorJob : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
protected:
|
||||||
|
OwncloudPropagator *_propagator;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PropagatorJob(OwncloudPropagator* propagator);
|
explicit PropagatorJob(OwncloudPropagator* propagator) : _propagator(propagator), _state(NotYetStarted) {}
|
||||||
|
|
||||||
enum JobState {
|
enum JobState {
|
||||||
NotYetStarted,
|
NotYetStarted,
|
||||||
@@ -114,7 +116,7 @@ signals:
|
|||||||
/**
|
/**
|
||||||
* Emitted when one item has been completed within a job.
|
* Emitted when one item has been completed within a job.
|
||||||
*/
|
*/
|
||||||
void itemCompleted(const SyncFileItemPtr &);
|
void itemCompleted(const SyncFileItem &, const PropagatorJob &);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emitted when all the sub-jobs have been finished and
|
* Emitted when all the sub-jobs have been finished and
|
||||||
@@ -124,8 +126,6 @@ signals:
|
|||||||
|
|
||||||
void progress(const SyncFileItem& item, quint64 bytes);
|
void progress(const SyncFileItem& item, quint64 bytes);
|
||||||
|
|
||||||
protected:
|
|
||||||
OwncloudPropagator *propagator() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -192,11 +192,14 @@ public:
|
|||||||
|
|
||||||
SyncFileItemPtr _item;
|
SyncFileItemPtr _item;
|
||||||
|
|
||||||
|
int _jobsFinished; // number of jobs that have completed
|
||||||
|
int _runningNow; // number of subJobs running right now
|
||||||
SyncFileItem::Status _hasError; // NoStatus, or NormalError / SoftError if there was an error
|
SyncFileItem::Status _hasError; // NoStatus, or NormalError / SoftError if there was an error
|
||||||
|
int _firstUnfinishedSubJob;
|
||||||
|
|
||||||
explicit PropagateDirectory(OwncloudPropagator *propagator, const SyncFileItemPtr &item = SyncFileItemPtr(new SyncFileItem))
|
explicit PropagateDirectory(OwncloudPropagator *propagator, const SyncFileItemPtr &item = SyncFileItemPtr(new SyncFileItem))
|
||||||
: PropagatorJob(propagator)
|
: PropagatorJob(propagator)
|
||||||
, _item(item), _hasError(SyncFileItem::NoStatus)
|
, _firstJob(0), _item(item), _jobsFinished(0), _runningNow(0), _hasError(SyncFileItem::NoStatus), _firstUnfinishedSubJob(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual ~PropagateDirectory() {
|
virtual ~PropagateDirectory() {
|
||||||
@@ -227,10 +230,12 @@ public:
|
|||||||
private slots:
|
private slots:
|
||||||
bool possiblyRunNextJob(PropagatorJob *next) {
|
bool possiblyRunNextJob(PropagatorJob *next) {
|
||||||
if (next->_state == NotYetStarted) {
|
if (next->_state == NotYetStarted) {
|
||||||
connect(next, SIGNAL(finished(SyncFileItem::Status)), this, SLOT(slotSubJobFinished(SyncFileItem::Status)));
|
connect(next, SIGNAL(finished(SyncFileItem::Status)), this, SLOT(slotSubJobFinished(SyncFileItem::Status)), Qt::QueuedConnection);
|
||||||
connect(next, SIGNAL(itemCompleted(const SyncFileItemPtr &)), this, SIGNAL(itemCompleted(const SyncFileItemPtr &)));
|
connect(next, SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)),
|
||||||
|
this, SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||||
connect(next, SIGNAL(progress(const SyncFileItem &,quint64)), this, SIGNAL(progress(const SyncFileItem &,quint64)));
|
connect(next, SIGNAL(progress(const SyncFileItem &,quint64)), this, SIGNAL(progress(const SyncFileItem &,quint64)));
|
||||||
connect(next, SIGNAL(ready()), this, SIGNAL(ready()));
|
connect(next, SIGNAL(ready()), this, SIGNAL(ready()));
|
||||||
|
_runningNow++;
|
||||||
}
|
}
|
||||||
return next->scheduleNextJob();
|
return next->scheduleNextJob();
|
||||||
}
|
}
|
||||||
@@ -351,7 +356,7 @@ private slots:
|
|||||||
void scheduleNextJob();
|
void scheduleNextJob();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void itemCompleted(const SyncFileItemPtr &);
|
void itemCompleted(const SyncFileItem &, const PropagatorJob &);
|
||||||
void progress(const SyncFileItem&, quint64 bytes);
|
void progress(const SyncFileItem&, quint64 bytes);
|
||||||
void finished(bool success);
|
void finished(bool success);
|
||||||
|
|
||||||
|
|||||||
+13
-10
@@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
#include "ownsql.h"
|
#include "ownsql.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "asserts.h"
|
|
||||||
|
|
||||||
#define SQLITE_SLEEP_TIME_USEC 100000
|
#define SQLITE_SLEEP_TIME_USEC 100000
|
||||||
#define SQLITE_REPEAT_COUNT 20
|
#define SQLITE_REPEAT_COUNT 20
|
||||||
@@ -148,8 +147,10 @@ void SqlDatabase::close()
|
|||||||
{
|
{
|
||||||
if( _db ) {
|
if( _db ) {
|
||||||
SQLITE_DO(sqlite3_close(_db) );
|
SQLITE_DO(sqlite3_close(_db) );
|
||||||
// Fatal because reopening an unclosed db might be problematic.
|
if (_errId != SQLITE_OK) {
|
||||||
ENFORCE(_errId == SQLITE_OK, "Error when closing DB");
|
qWarning() << "ERROR When closing DB" << _error;
|
||||||
|
Q_ASSERT(!"SQLite Close Error");
|
||||||
|
}
|
||||||
_db = 0;
|
_db = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,7 +223,11 @@ int SqlQuery::prepare( const QString& sql, bool allow_failure )
|
|||||||
if( _errId != SQLITE_OK ) {
|
if( _errId != SQLITE_OK ) {
|
||||||
_error = QString::fromUtf8(sqlite3_errmsg(_db));
|
_error = QString::fromUtf8(sqlite3_errmsg(_db));
|
||||||
qWarning() << "Sqlite prepare statement error:" << _error << "in" <<_sql;
|
qWarning() << "Sqlite prepare statement error:" << _error << "in" <<_sql;
|
||||||
ENFORCE(allow_failure, "SQLITE Prepare error");
|
if (!allow_failure) {
|
||||||
|
qFatal("SQLITE Prepare error: %s in %s",
|
||||||
|
_error.toLocal8Bit().data(),
|
||||||
|
sql.toLocal8Bit().data());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _errId;
|
return _errId;
|
||||||
@@ -279,11 +284,8 @@ bool SqlQuery::next()
|
|||||||
void SqlQuery::bindValue(int pos, const QVariant& value)
|
void SqlQuery::bindValue(int pos, const QVariant& value)
|
||||||
{
|
{
|
||||||
int res = -1;
|
int res = -1;
|
||||||
if (!_stmt) {
|
Q_ASSERT(_stmt);
|
||||||
ASSERT(false);
|
if( _stmt ) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (value.type()) {
|
switch (value.type()) {
|
||||||
case QVariant::Int:
|
case QVariant::Int:
|
||||||
case QVariant::Bool:
|
case QVariant::Bool:
|
||||||
@@ -332,10 +334,11 @@ void SqlQuery::bindValue(int pos, const QVariant& value)
|
|||||||
(str.size()) * sizeof(QChar), SQLITE_TRANSIENT);
|
(str.size()) * sizeof(QChar), SQLITE_TRANSIENT);
|
||||||
break; }
|
break; }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (res != SQLITE_OK) {
|
if (res != SQLITE_OK) {
|
||||||
qDebug() << Q_FUNC_INFO << "ERROR" << value << res;
|
qDebug() << Q_FUNC_INFO << "ERROR" << value << res;
|
||||||
}
|
}
|
||||||
ASSERT( res == SQLITE_OK );
|
Q_ASSERT( res == SQLITE_OK );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SqlQuery::nullValue(int index)
|
bool SqlQuery::nullValue(int index)
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
|
class PropagatorJob;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The ProgressInfo class
|
* @brief The ProgressInfo class
|
||||||
* @ingroup libsync
|
* @ingroup libsync
|
||||||
@@ -250,7 +252,9 @@ signals:
|
|||||||
/**
|
/**
|
||||||
* @brief: the item was completed by a job
|
* @brief: the item was completed by a job
|
||||||
*/
|
*/
|
||||||
void itemCompleted(const QString &folder, const SyncFileItemPtr & item);
|
void itemCompleted(const QString &folder,
|
||||||
|
const SyncFileItem & item,
|
||||||
|
const PropagatorJob & job);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setProgressInfo(const QString& folder, const ProgressInfo& progress);
|
void setProgressInfo(const QString& folder, const ProgressInfo& progress);
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
#include "propagatorjobs.h"
|
#include "propagatorjobs.h"
|
||||||
#include "checksums.h"
|
#include "checksums.h"
|
||||||
#include "asserts.h"
|
|
||||||
|
|
||||||
#include <json.h>
|
#include <json.h>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
@@ -311,10 +310,10 @@ QString GETFileJob::errorString() const
|
|||||||
|
|
||||||
void PropagateDownloadFile::start()
|
void PropagateDownloadFile::start()
|
||||||
{
|
{
|
||||||
if (propagator()->_abortRequested.fetchAndAddRelaxed(0))
|
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << _item->_file << propagator()->_activeJobList.count();
|
qDebug() << Q_FUNC_INFO << _item->_file << _propagator->_activeJobList.count();
|
||||||
_stopwatch.start();
|
_stopwatch.start();
|
||||||
|
|
||||||
if (_deleteExisting) {
|
if (_deleteExisting) {
|
||||||
@@ -327,7 +326,7 @@ void PropagateDownloadFile::start()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// do a klaas' case clash check.
|
// do a klaas' case clash check.
|
||||||
if( propagator()->localFileNameClash(_item->_file) ) {
|
if( _propagator->localFileNameClash(_item->_file) ) {
|
||||||
done( SyncFileItem::NormalError, tr("File %1 can not be downloaded because of a local file name clash!")
|
done( SyncFileItem::NormalError, tr("File %1 can not be downloaded because of a local file name clash!")
|
||||||
.arg(QDir::toNativeSeparators(_item->_file)) );
|
.arg(QDir::toNativeSeparators(_item->_file)) );
|
||||||
return;
|
return;
|
||||||
@@ -337,12 +336,12 @@ void PropagateDownloadFile::start()
|
|||||||
|
|
||||||
QString tmpFileName;
|
QString tmpFileName;
|
||||||
QByteArray expectedEtagForResume;
|
QByteArray expectedEtagForResume;
|
||||||
const SyncJournalDb::DownloadInfo progressInfo = propagator()->_journal->getDownloadInfo(_item->_file);
|
const SyncJournalDb::DownloadInfo progressInfo = _propagator->_journal->getDownloadInfo(_item->_file);
|
||||||
if (progressInfo._valid) {
|
if (progressInfo._valid) {
|
||||||
// if the etag has changed meanwhile, remove the already downloaded part.
|
// if the etag has changed meanwhile, remove the already downloaded part.
|
||||||
if (progressInfo._etag != _item->_etag) {
|
if (progressInfo._etag != _item->_etag) {
|
||||||
FileSystem::remove(propagator()->getFilePath(progressInfo._tmpfile));
|
FileSystem::remove(_propagator->getFilePath(progressInfo._tmpfile));
|
||||||
propagator()->_journal->setDownloadInfo(_item->_file, SyncJournalDb::DownloadInfo());
|
_propagator->_journal->setDownloadInfo(_item->_file, SyncJournalDb::DownloadInfo());
|
||||||
} else {
|
} else {
|
||||||
tmpFileName = progressInfo._tmpfile;
|
tmpFileName = progressInfo._tmpfile;
|
||||||
expectedEtagForResume = progressInfo._etag;
|
expectedEtagForResume = progressInfo._etag;
|
||||||
@@ -354,7 +353,7 @@ void PropagateDownloadFile::start()
|
|||||||
tmpFileName = createDownloadTmpFileName(_item->_file);
|
tmpFileName = createDownloadTmpFileName(_item->_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
_tmpFile.setFileName(propagator()->getFilePath(tmpFileName));
|
_tmpFile.setFileName(_propagator->getFilePath(tmpFileName));
|
||||||
if (!_tmpFile.open(QIODevice::Append | QIODevice::Unbuffered)) {
|
if (!_tmpFile.open(QIODevice::Append | QIODevice::Unbuffered)) {
|
||||||
done(SyncFileItem::NormalError, _tmpFile.errorString());
|
done(SyncFileItem::NormalError, _tmpFile.errorString());
|
||||||
return;
|
return;
|
||||||
@@ -373,7 +372,7 @@ void PropagateDownloadFile::start()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If there's not enough space to fully download this file, stop.
|
// If there's not enough space to fully download this file, stop.
|
||||||
const auto diskSpaceResult = propagator()->diskSpaceCheck();
|
const auto diskSpaceResult = _propagator->diskSpaceCheck();
|
||||||
if (diskSpaceResult == OwncloudPropagator::DiskSpaceFailure) {
|
if (diskSpaceResult == OwncloudPropagator::DiskSpaceFailure) {
|
||||||
_item->_errorMayBeBlacklisted = true;
|
_item->_errorMayBeBlacklisted = true;
|
||||||
done(SyncFileItem::NormalError,
|
done(SyncFileItem::NormalError,
|
||||||
@@ -392,16 +391,16 @@ void PropagateDownloadFile::start()
|
|||||||
pi._etag = _item->_etag;
|
pi._etag = _item->_etag;
|
||||||
pi._tmpfile = tmpFileName;
|
pi._tmpfile = tmpFileName;
|
||||||
pi._valid = true;
|
pi._valid = true;
|
||||||
propagator()->_journal->setDownloadInfo(_item->_file, pi);
|
_propagator->_journal->setDownloadInfo(_item->_file, pi);
|
||||||
propagator()->_journal->commit("download file start");
|
_propagator->_journal->commit("download file start");
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QByteArray, QByteArray> headers;
|
QMap<QByteArray, QByteArray> headers;
|
||||||
|
|
||||||
if (_item->_directDownloadUrl.isEmpty()) {
|
if (_item->_directDownloadUrl.isEmpty()) {
|
||||||
// Normal job, download from oC instance
|
// Normal job, download from oC instance
|
||||||
_job = new GETFileJob(propagator()->account(),
|
_job = new GETFileJob(_propagator->account(),
|
||||||
propagator()->_remoteFolder + _item->_file,
|
_propagator->_remoteFolder + _item->_file,
|
||||||
&_tmpFile, headers, expectedEtagForResume, _resumeStart, this);
|
&_tmpFile, headers, expectedEtagForResume, _resumeStart, this);
|
||||||
} else {
|
} else {
|
||||||
// We were provided a direct URL, use that one
|
// We were provided a direct URL, use that one
|
||||||
@@ -412,14 +411,14 @@ void PropagateDownloadFile::start()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QUrl url = QUrl::fromUserInput(_item->_directDownloadUrl);
|
QUrl url = QUrl::fromUserInput(_item->_directDownloadUrl);
|
||||||
_job = new GETFileJob(propagator()->account(),
|
_job = new GETFileJob(_propagator->account(),
|
||||||
url,
|
url,
|
||||||
&_tmpFile, headers, expectedEtagForResume, _resumeStart, this);
|
&_tmpFile, headers, expectedEtagForResume, _resumeStart, this);
|
||||||
}
|
}
|
||||||
_job->setBandwidthManager(&propagator()->_bandwidthManager);
|
_job->setBandwidthManager(&_propagator->_bandwidthManager);
|
||||||
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
|
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
|
||||||
connect(_job, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slotDownloadProgress(qint64,qint64)));
|
connect(_job, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slotDownloadProgress(qint64,qint64)));
|
||||||
propagator()->_activeJobList.append(this);
|
_propagator->_activeJobList.append(this);
|
||||||
_job->start();
|
_job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,10 +438,10 @@ void PropagateDownloadFile::setDeleteExistingFolder(bool enabled)
|
|||||||
const char owncloudCustomSoftErrorStringC[] = "owncloud-custom-soft-error-string";
|
const char owncloudCustomSoftErrorStringC[] = "owncloud-custom-soft-error-string";
|
||||||
void PropagateDownloadFile::slotGetFinished()
|
void PropagateDownloadFile::slotGetFinished()
|
||||||
{
|
{
|
||||||
propagator()->_activeJobList.removeOne(this);
|
_propagator->_activeJobList.removeOne(this);
|
||||||
|
|
||||||
GETFileJob *job = qobject_cast<GETFileJob *>(sender());
|
GETFileJob *job = qobject_cast<GETFileJob *>(sender());
|
||||||
ASSERT(job);
|
Q_ASSERT(job);
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << job->reply()->request().url() << "FINISHED WITH STATUS"
|
qDebug() << Q_FUNC_INFO << job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||||
<< job->reply()->error()
|
<< job->reply()->error()
|
||||||
@@ -460,7 +459,7 @@ void PropagateDownloadFile::slotGetFinished()
|
|||||||
const bool badRangeHeader = job->resumeStart() > 0 && _item->_httpErrorCode == 416;
|
const bool badRangeHeader = job->resumeStart() > 0 && _item->_httpErrorCode == 416;
|
||||||
if (badRangeHeader) {
|
if (badRangeHeader) {
|
||||||
qDebug() << Q_FUNC_INFO << "server replied 416 to our range request, trying again without";
|
qDebug() << Q_FUNC_INFO << "server replied 416 to our range request, trying again without";
|
||||||
propagator()->_anotherSyncNeeded = true;
|
_propagator->_anotherSyncNeeded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getting a 404 probably means that the file was deleted on the server.
|
// Getting a 404 probably means that the file was deleted on the server.
|
||||||
@@ -474,7 +473,7 @@ void PropagateDownloadFile::slotGetFinished()
|
|||||||
if (_tmpFile.size() == 0 || badRangeHeader || fileNotFound) {
|
if (_tmpFile.size() == 0 || badRangeHeader || fileNotFound) {
|
||||||
_tmpFile.close();
|
_tmpFile.close();
|
||||||
FileSystem::remove(_tmpFile.fileName());
|
FileSystem::remove(_tmpFile.fileName());
|
||||||
propagator()->_journal->setDownloadInfo(_item->_file, SyncJournalDb::DownloadInfo());
|
_propagator->_journal->setDownloadInfo(_item->_file, SyncJournalDb::DownloadInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!_item->_directDownloadUrl.isEmpty() && err != QNetworkReply::OperationCanceledError) {
|
if(!_item->_directDownloadUrl.isEmpty() && err != QNetworkReply::OperationCanceledError) {
|
||||||
@@ -504,7 +503,7 @@ void PropagateDownloadFile::slotGetFinished()
|
|||||||
SyncFileItem::Status status = job->errorStatus();
|
SyncFileItem::Status status = job->errorStatus();
|
||||||
if (status == SyncFileItem::NoStatus) {
|
if (status == SyncFileItem::NoStatus) {
|
||||||
status = classifyError(err, _item->_httpErrorCode,
|
status = classifyError(err, _item->_httpErrorCode,
|
||||||
&propagator()->_anotherSyncNeeded);
|
&_propagator->_anotherSyncNeeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
done(status, job->errorString());
|
done(status, job->errorString());
|
||||||
@@ -521,6 +520,7 @@ void PropagateDownloadFile::slotGetFinished()
|
|||||||
// so make sure we have the up-to-date time
|
// so make sure we have the up-to-date time
|
||||||
_item->_modtime = job->lastModified();
|
_item->_modtime = job->lastModified();
|
||||||
}
|
}
|
||||||
|
_item->_requestDuration = job->duration();
|
||||||
_item->_responseTimeStamp = job->responseTimestamp();
|
_item->_responseTimeStamp = job->responseTimestamp();
|
||||||
|
|
||||||
_tmpFile.close();
|
_tmpFile.close();
|
||||||
@@ -544,7 +544,7 @@ void PropagateDownloadFile::slotGetFinished()
|
|||||||
|
|
||||||
if(bodySize > 0 && bodySize != _tmpFile.size() - job->resumeStart() ) {
|
if(bodySize > 0 && bodySize != _tmpFile.size() - job->resumeStart() ) {
|
||||||
qDebug() << bodySize << _tmpFile.size() << job->resumeStart();
|
qDebug() << bodySize << _tmpFile.size() << job->resumeStart();
|
||||||
propagator()->_anotherSyncNeeded = true;
|
_propagator->_anotherSyncNeeded = true;
|
||||||
done(SyncFileItem::SoftError, tr("The file could not be downloaded completely."));
|
done(SyncFileItem::SoftError, tr("The file could not be downloaded completely."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -572,13 +572,13 @@ void PropagateDownloadFile::slotGetFinished()
|
|||||||
void PropagateDownloadFile::slotChecksumFail( const QString& errMsg )
|
void PropagateDownloadFile::slotChecksumFail( const QString& errMsg )
|
||||||
{
|
{
|
||||||
FileSystem::remove(_tmpFile.fileName());
|
FileSystem::remove(_tmpFile.fileName());
|
||||||
propagator()->_anotherSyncNeeded = true;
|
_propagator->_anotherSyncNeeded = true;
|
||||||
done(SyncFileItem::SoftError, errMsg ); // tr("The file downloaded with a broken checksum, will be redownloaded."));
|
done(SyncFileItem::SoftError, errMsg ); // tr("The file downloaded with a broken checksum, will be redownloaded."));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PropagateDownloadFile::deleteExistingFolder()
|
void PropagateDownloadFile::deleteExistingFolder()
|
||||||
{
|
{
|
||||||
QString existingDir = propagator()->getFilePath(_item->_file);
|
QString existingDir = _propagator->getFilePath(_item->_file);
|
||||||
if (!QFileInfo(existingDir).isDir()) {
|
if (!QFileInfo(existingDir).isDir()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -595,8 +595,8 @@ void PropagateDownloadFile::deleteExistingFolder()
|
|||||||
QString conflictDir = FileSystem::makeConflictFileName(
|
QString conflictDir = FileSystem::makeConflictFileName(
|
||||||
existingDir, Utility::qDateTimeFromTime_t(FileSystem::getModTime(existingDir)));
|
existingDir, Utility::qDateTimeFromTime_t(FileSystem::getModTime(existingDir)));
|
||||||
|
|
||||||
emit propagator()->touchedFile(existingDir);
|
emit _propagator->touchedFile(existingDir);
|
||||||
emit propagator()->touchedFile(conflictDir);
|
emit _propagator->touchedFile(conflictDir);
|
||||||
QString renameError;
|
QString renameError;
|
||||||
if (!FileSystem::rename(existingDir, conflictDir, &renameError)) {
|
if (!FileSystem::rename(existingDir, conflictDir, &renameError)) {
|
||||||
done(SyncFileItem::NormalError, renameError);
|
done(SyncFileItem::NormalError, renameError);
|
||||||
@@ -706,11 +706,11 @@ void PropagateDownloadFile::contentChecksumComputed(const QByteArray &checksumTy
|
|||||||
|
|
||||||
void PropagateDownloadFile::downloadFinished()
|
void PropagateDownloadFile::downloadFinished()
|
||||||
{
|
{
|
||||||
QString fn = propagator()->getFilePath(_item->_file);
|
QString fn = _propagator->getFilePath(_item->_file);
|
||||||
|
|
||||||
// In case of file name clash, report an error
|
// In case of file name clash, report an error
|
||||||
// This can happen if another parallel download saved a clashing file.
|
// This can happen if another parallel download saved a clashing file.
|
||||||
if (propagator()->localFileNameClash(_item->_file)) {
|
if (_propagator->localFileNameClash(_item->_file)) {
|
||||||
done( SyncFileItem::NormalError, tr("File %1 cannot be saved because of a local file name clash!")
|
done( SyncFileItem::NormalError, tr("File %1 cannot be saved because of a local file name clash!")
|
||||||
.arg(QDir::toNativeSeparators(_item->_file)) );
|
.arg(QDir::toNativeSeparators(_item->_file)) );
|
||||||
return;
|
return;
|
||||||
@@ -730,7 +730,7 @@ void PropagateDownloadFile::downloadFinished()
|
|||||||
// If the file is locked, we want to retry this sync when it
|
// If the file is locked, we want to retry this sync when it
|
||||||
// becomes available again.
|
// becomes available again.
|
||||||
if (FileSystem::isFileLocked(fn)) {
|
if (FileSystem::isFileLocked(fn)) {
|
||||||
emit propagator()->seenLockedFile(fn);
|
emit _propagator->seenLockedFile(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
done(SyncFileItem::SoftError, renameError);
|
done(SyncFileItem::SoftError, renameError);
|
||||||
@@ -759,7 +759,7 @@ void PropagateDownloadFile::downloadFinished()
|
|||||||
const qint64 expectedSize = _item->log._other_size;
|
const qint64 expectedSize = _item->log._other_size;
|
||||||
const time_t expectedMtime = _item->log._other_modtime;
|
const time_t expectedMtime = _item->log._other_modtime;
|
||||||
if (! FileSystem::verifyFileUnchanged(fn, expectedSize, expectedMtime)) {
|
if (! FileSystem::verifyFileUnchanged(fn, expectedSize, expectedMtime)) {
|
||||||
propagator()->_anotherSyncNeeded = true;
|
_propagator->_anotherSyncNeeded = true;
|
||||||
done(SyncFileItem::SoftError, tr("File has changed since discovery"));
|
done(SyncFileItem::SoftError, tr("File has changed since discovery"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -769,13 +769,13 @@ void PropagateDownloadFile::downloadFinished()
|
|||||||
// Older server versions sometimes provide empty remote permissions
|
// Older server versions sometimes provide empty remote permissions
|
||||||
// see #4450 - don't adjust the write permissions there.
|
// see #4450 - don't adjust the write permissions there.
|
||||||
const int serverVersionGoodRemotePerm = 0x070000; // 7.0.0
|
const int serverVersionGoodRemotePerm = 0x070000; // 7.0.0
|
||||||
if (propagator()->account()->serverVersionInt() >= serverVersionGoodRemotePerm) {
|
if (_propagator->account()->serverVersionInt() >= serverVersionGoodRemotePerm) {
|
||||||
FileSystem::setFileReadOnlyWeak(_tmpFile.fileName(),
|
FileSystem::setFileReadOnlyWeak(_tmpFile.fileName(),
|
||||||
!_item->_remotePerm.contains('W'));
|
!_item->_remotePerm.contains('W'));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString error;
|
QString error;
|
||||||
emit propagator()->touchedFile(fn);
|
emit _propagator->touchedFile(fn);
|
||||||
// The fileChanged() check is done above to generate better error messages.
|
// The fileChanged() check is done above to generate better error messages.
|
||||||
if (!FileSystem::uncheckedRenameReplace(_tmpFile.fileName(), fn, &error)) {
|
if (!FileSystem::uncheckedRenameReplace(_tmpFile.fileName(), fn, &error)) {
|
||||||
qDebug() << Q_FUNC_INFO << QString("Rename failed: %1 => %2").arg(_tmpFile.fileName()).arg(fn);
|
qDebug() << Q_FUNC_INFO << QString("Rename failed: %1 => %2").arg(_tmpFile.fileName()).arg(fn);
|
||||||
@@ -788,16 +788,16 @@ void PropagateDownloadFile::downloadFinished()
|
|||||||
// which makes it look like we're just about to initially download
|
// which makes it look like we're just about to initially download
|
||||||
// it.
|
// it.
|
||||||
if (isConflict) {
|
if (isConflict) {
|
||||||
propagator()->_journal->deleteFileRecord(fn);
|
_propagator->_journal->deleteFileRecord(fn);
|
||||||
propagator()->_journal->commit("download finished");
|
_propagator->_journal->commit("download finished");
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the file is locked, we want to retry this sync when it
|
// If the file is locked, we want to retry this sync when it
|
||||||
// becomes available again, otherwise try again directly
|
// becomes available again, otherwise try again directly
|
||||||
if (FileSystem::isFileLocked(fn)) {
|
if (FileSystem::isFileLocked(fn)) {
|
||||||
emit propagator()->seenLockedFile(fn);
|
emit _propagator->seenLockedFile(fn);
|
||||||
} else {
|
} else {
|
||||||
propagator()->_anotherSyncNeeded = true;
|
_propagator->_anotherSyncNeeded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
done(SyncFileItem::SoftError, error);
|
done(SyncFileItem::SoftError, error);
|
||||||
@@ -809,19 +809,19 @@ void PropagateDownloadFile::downloadFinished()
|
|||||||
// Get up to date information for the journal.
|
// Get up to date information for the journal.
|
||||||
_item->_size = FileSystem::getSize(fn);
|
_item->_size = FileSystem::getSize(fn);
|
||||||
|
|
||||||
if (!propagator()->_journal->setFileRecord(SyncJournalFileRecord(*_item, fn))) {
|
if (!_propagator->_journal->setFileRecord(SyncJournalFileRecord(*_item, fn))) {
|
||||||
done(SyncFileItem::FatalError, tr("Error writing metadata to the database"));
|
done(SyncFileItem::FatalError, tr("Error writing metadata to the database"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
propagator()->_journal->setDownloadInfo(_item->_file, SyncJournalDb::DownloadInfo());
|
_propagator->_journal->setDownloadInfo(_item->_file, SyncJournalDb::DownloadInfo());
|
||||||
propagator()->_journal->commit("download file start2");
|
_propagator->_journal->commit("download file start2");
|
||||||
done(isConflict ? SyncFileItem::Conflict : SyncFileItem::Success);
|
done(isConflict ? SyncFileItem::Conflict : SyncFileItem::Success);
|
||||||
|
|
||||||
// handle the special recall file
|
// handle the special recall file
|
||||||
if(!_item->_remotePerm.contains("S")
|
if(!_item->_remotePerm.contains("S")
|
||||||
&& (_item->_file == QLatin1String(".sys.admin#recall#")
|
&& (_item->_file == QLatin1String(".sys.admin#recall#")
|
||||||
|| _item->_file.endsWith("/.sys.admin#recall#"))) {
|
|| _item->_file.endsWith("/.sys.admin#recall#"))) {
|
||||||
handleRecallFile(fn, propagator()->_localDir, *propagator()->_journal);
|
handleRecallFile(fn, _propagator->_localDir, *_propagator->_journal);
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 duration = _stopwatch.elapsed();
|
qint64 duration = _stopwatch.elapsed();
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
#include "propagateremotedelete.h"
|
#include "propagateremotedelete.h"
|
||||||
#include "owncloudpropagator_p.h"
|
#include "owncloudpropagator_p.h"
|
||||||
#include "account.h"
|
#include "account.h"
|
||||||
#include "asserts.h"
|
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
@@ -59,16 +58,16 @@ bool DeleteJob::finished()
|
|||||||
|
|
||||||
void PropagateRemoteDelete::start()
|
void PropagateRemoteDelete::start()
|
||||||
{
|
{
|
||||||
if (propagator()->_abortRequested.fetchAndAddRelaxed(0))
|
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << _item->_file;
|
qDebug() << Q_FUNC_INFO << _item->_file;
|
||||||
|
|
||||||
_job = new DeleteJob(propagator()->account(),
|
_job = new DeleteJob(_propagator->account(),
|
||||||
propagator()->_remoteFolder + _item->_file,
|
_propagator->_remoteFolder + _item->_file,
|
||||||
this);
|
this);
|
||||||
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotDeleteJobFinished()));
|
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotDeleteJobFinished()));
|
||||||
propagator()->_activeJobList.append(this);
|
_propagator->_activeJobList.append(this);
|
||||||
_job->start();
|
_job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,9 +79,9 @@ void PropagateRemoteDelete::abort()
|
|||||||
|
|
||||||
void PropagateRemoteDelete::slotDeleteJobFinished()
|
void PropagateRemoteDelete::slotDeleteJobFinished()
|
||||||
{
|
{
|
||||||
propagator()->_activeJobList.removeOne(this);
|
_propagator->_activeJobList.removeOne(this);
|
||||||
|
|
||||||
ASSERT(_job);
|
Q_ASSERT(_job);
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << _job->reply()->request().url() << "FINISHED WITH STATUS"
|
qDebug() << Q_FUNC_INFO << _job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||||
<< _job->reply()->error()
|
<< _job->reply()->error()
|
||||||
@@ -100,11 +99,12 @@ void PropagateRemoteDelete::slotDeleteJobFinished()
|
|||||||
}
|
}
|
||||||
|
|
||||||
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
||||||
&propagator()->_anotherSyncNeeded);
|
&_propagator->_anotherSyncNeeded);
|
||||||
done(status, _job->errorString());
|
done(status, _job->errorString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_item->_requestDuration = _job->duration();
|
||||||
_item->_responseTimeStamp = _job->responseTimestamp();
|
_item->_responseTimeStamp = _job->responseTimestamp();
|
||||||
|
|
||||||
// A 404 reply is also considered a success here: We want to make sure
|
// A 404 reply is also considered a success here: We want to make sure
|
||||||
@@ -120,8 +120,8 @@ void PropagateRemoteDelete::slotDeleteJobFinished()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
propagator()->_journal->deleteFileRecord(_item->_originalFile, _item->_isDirectory);
|
_propagator->_journal->deleteFileRecord(_item->_originalFile, _item->_isDirectory);
|
||||||
propagator()->_journal->commit("Remote Remove");
|
_propagator->_journal->commit("Remote Remove");
|
||||||
done(SyncFileItem::Success);
|
done(SyncFileItem::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,26 +17,25 @@
|
|||||||
#include "account.h"
|
#include "account.h"
|
||||||
#include "syncjournalfilerecord.h"
|
#include "syncjournalfilerecord.h"
|
||||||
#include "propagateremotedelete.h"
|
#include "propagateremotedelete.h"
|
||||||
#include "asserts.h"
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
void PropagateRemoteMkdir::start()
|
void PropagateRemoteMkdir::start()
|
||||||
{
|
{
|
||||||
if (propagator()->_abortRequested.fetchAndAddRelaxed(0))
|
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << _item->_file;
|
qDebug() << Q_FUNC_INFO << _item->_file;
|
||||||
|
|
||||||
propagator()->_activeJobList.append(this);
|
_propagator->_activeJobList.append(this);
|
||||||
|
|
||||||
if (!_deleteExisting) {
|
if (!_deleteExisting) {
|
||||||
return slotStartMkcolJob();
|
return slotStartMkcolJob();
|
||||||
}
|
}
|
||||||
|
|
||||||
_job = new DeleteJob(propagator()->account(),
|
_job = new DeleteJob(_propagator->account(),
|
||||||
propagator()->_remoteFolder + _item->_file,
|
_propagator->_remoteFolder + _item->_file,
|
||||||
this);
|
this);
|
||||||
connect(_job, SIGNAL(finishedSignal()), SLOT(slotStartMkcolJob()));
|
connect(_job, SIGNAL(finishedSignal()), SLOT(slotStartMkcolJob()));
|
||||||
_job->start();
|
_job->start();
|
||||||
@@ -44,13 +43,13 @@ void PropagateRemoteMkdir::start()
|
|||||||
|
|
||||||
void PropagateRemoteMkdir::slotStartMkcolJob()
|
void PropagateRemoteMkdir::slotStartMkcolJob()
|
||||||
{
|
{
|
||||||
if (propagator()->_abortRequested.fetchAndAddRelaxed(0))
|
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << _item->_file;
|
qDebug() << Q_FUNC_INFO << _item->_file;
|
||||||
|
|
||||||
_job = new MkColJob(propagator()->account(),
|
_job = new MkColJob(_propagator->account(),
|
||||||
propagator()->_remoteFolder + _item->_file,
|
_propagator->_remoteFolder + _item->_file,
|
||||||
this);
|
this);
|
||||||
connect(_job, SIGNAL(finished(QNetworkReply::NetworkError)), this, SLOT(slotMkcolJobFinished()));
|
connect(_job, SIGNAL(finished(QNetworkReply::NetworkError)), this, SLOT(slotMkcolJobFinished()));
|
||||||
_job->start();
|
_job->start();
|
||||||
@@ -69,9 +68,9 @@ void PropagateRemoteMkdir::setDeleteExisting(bool enabled)
|
|||||||
|
|
||||||
void PropagateRemoteMkdir::slotMkcolJobFinished()
|
void PropagateRemoteMkdir::slotMkcolJobFinished()
|
||||||
{
|
{
|
||||||
propagator()->_activeJobList.removeOne(this);
|
_propagator->_activeJobList.removeOne(this);
|
||||||
|
|
||||||
ASSERT(_job);
|
Q_ASSERT(_job);
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << _job->reply()->request().url() << "FINISHED WITH STATUS"
|
qDebug() << Q_FUNC_INFO << _job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||||
<< _job->reply()->error()
|
<< _job->reply()->error()
|
||||||
@@ -84,7 +83,7 @@ void PropagateRemoteMkdir::slotMkcolJobFinished()
|
|||||||
// This happens when the directory already exists. Nothing to do.
|
// This happens when the directory already exists. Nothing to do.
|
||||||
} else if (err != QNetworkReply::NoError) {
|
} else if (err != QNetworkReply::NoError) {
|
||||||
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
||||||
&propagator()->_anotherSyncNeeded);
|
&_propagator->_anotherSyncNeeded);
|
||||||
auto errorString = _job->reply()->errorString();
|
auto errorString = _job->reply()->errorString();
|
||||||
if (_job->reply()->hasRawHeader("OC-ErrorString")) {
|
if (_job->reply()->hasRawHeader("OC-ErrorString")) {
|
||||||
errorString = _job->reply()->rawHeader("OC-ErrorString");
|
errorString = _job->reply()->rawHeader("OC-ErrorString");
|
||||||
@@ -100,6 +99,7 @@ void PropagateRemoteMkdir::slotMkcolJobFinished()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_item->_requestDuration = _job->duration();
|
||||||
_item->_responseTimeStamp = _job->responseTimestamp();
|
_item->_responseTimeStamp = _job->responseTimestamp();
|
||||||
_item->_fileId = _job->reply()->rawHeader("OC-FileId");
|
_item->_fileId = _job->reply()->rawHeader("OC-FileId");
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ void PropagateRemoteMkdir::slotMkcolJobFinished()
|
|||||||
// So we must get the file id using a PROPFIND
|
// So we must get the file id using a PROPFIND
|
||||||
// This is required so that we can detect moves even if the folder is renamed on the server
|
// This is required so that we can detect moves even if the folder is renamed on the server
|
||||||
// while files are still uploading
|
// while files are still uploading
|
||||||
propagator()->_activeJobList.append(this);
|
_propagator->_activeJobList.append(this);
|
||||||
auto propfindJob = new PropfindJob(_job->account(), _job->path(), this);
|
auto propfindJob = new PropfindJob(_job->account(), _job->path(), this);
|
||||||
propfindJob->setProperties(QList<QByteArray>() << "getetag" << "http://owncloud.org/ns:id");
|
propfindJob->setProperties(QList<QByteArray>() << "getetag" << "http://owncloud.org/ns:id");
|
||||||
QObject::connect(propfindJob, SIGNAL(result(QVariantMap)), this, SLOT(propfindResult(QVariantMap)));
|
QObject::connect(propfindJob, SIGNAL(result(QVariantMap)), this, SLOT(propfindResult(QVariantMap)));
|
||||||
@@ -123,7 +123,7 @@ void PropagateRemoteMkdir::slotMkcolJobFinished()
|
|||||||
|
|
||||||
void PropagateRemoteMkdir::propfindResult(const QVariantMap &result)
|
void PropagateRemoteMkdir::propfindResult(const QVariantMap &result)
|
||||||
{
|
{
|
||||||
propagator()->_activeJobList.removeOne(this);
|
_propagator->_activeJobList.removeOne(this);
|
||||||
if (result.contains("getetag")) {
|
if (result.contains("getetag")) {
|
||||||
_item->_etag = result["getetag"].toByteArray();
|
_item->_etag = result["getetag"].toByteArray();
|
||||||
}
|
}
|
||||||
@@ -136,15 +136,15 @@ void PropagateRemoteMkdir::propfindResult(const QVariantMap &result)
|
|||||||
void PropagateRemoteMkdir::propfindError()
|
void PropagateRemoteMkdir::propfindError()
|
||||||
{
|
{
|
||||||
// ignore the PROPFIND error
|
// ignore the PROPFIND error
|
||||||
propagator()->_activeJobList.removeOne(this);
|
_propagator->_activeJobList.removeOne(this);
|
||||||
done(SyncFileItem::Success);
|
done(SyncFileItem::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PropagateRemoteMkdir::success()
|
void PropagateRemoteMkdir::success()
|
||||||
{
|
{
|
||||||
// save the file id already so we can detect rename or remove
|
// save the file id already so we can detect rename or remove
|
||||||
SyncJournalFileRecord record(*_item, propagator()->_localDir + _item->destination());
|
SyncJournalFileRecord record(*_item, _propagator->_localDir + _item->destination());
|
||||||
if (!propagator()->_journal->setFileRecord(record)) {
|
if (!_propagator->_journal->setFileRecord(record)) {
|
||||||
done(SyncFileItem::FatalError, tr("Error writing metadata to the database"));
|
done(SyncFileItem::FatalError, tr("Error writing metadata to the database"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
#include "account.h"
|
#include "account.h"
|
||||||
#include "syncjournalfilerecord.h"
|
#include "syncjournalfilerecord.h"
|
||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
#include "asserts.h"
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
@@ -72,12 +71,12 @@ bool MoveJob::finished()
|
|||||||
|
|
||||||
void PropagateRemoteMove::start()
|
void PropagateRemoteMove::start()
|
||||||
{
|
{
|
||||||
if (propagator()->_abortRequested.fetchAndAddRelaxed(0))
|
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << _item->_file << _item->_renameTarget;
|
qDebug() << Q_FUNC_INFO << _item->_file << _item->_renameTarget;
|
||||||
|
|
||||||
QString targetFile(propagator()->getFilePath(_item->_renameTarget));
|
QString targetFile(_propagator->getFilePath(_item->_renameTarget));
|
||||||
|
|
||||||
if (_item->_file == _item->_renameTarget) {
|
if (_item->_file == _item->_renameTarget) {
|
||||||
// The parent has been renamed already so there is nothing more to do.
|
// The parent has been renamed already so there is nothing more to do.
|
||||||
@@ -88,11 +87,11 @@ void PropagateRemoteMove::start()
|
|||||||
// Before owncloud 7, there was no permissions system. At the time all the shared files were
|
// Before owncloud 7, there was no permissions system. At the time all the shared files were
|
||||||
// in a directory called "Shared" and were not supposed to be moved, otherwise bad things happened
|
// in a directory called "Shared" and were not supposed to be moved, otherwise bad things happened
|
||||||
|
|
||||||
QString versionString = propagator()->account()->serverVersion();
|
QString versionString = _propagator->account()->serverVersion();
|
||||||
if (versionString.contains('.') && versionString.split('.')[0].toInt() < 7) {
|
if (versionString.contains('.') && versionString.split('.')[0].toInt() < 7) {
|
||||||
QString originalFile(propagator()->getFilePath(QLatin1String("Shared")));
|
QString originalFile(_propagator->getFilePath(QLatin1String("Shared")));
|
||||||
emit propagator()->touchedFile(originalFile);
|
emit _propagator->touchedFile(originalFile);
|
||||||
emit propagator()->touchedFile(targetFile);
|
emit _propagator->touchedFile(targetFile);
|
||||||
QString renameError;
|
QString renameError;
|
||||||
if( FileSystem::rename(targetFile, originalFile, &renameError) ) {
|
if( FileSystem::rename(targetFile, originalFile, &renameError) ) {
|
||||||
done(SyncFileItem::NormalError, tr("This folder must not be renamed. It is renamed back to its original name."));
|
done(SyncFileItem::NormalError, tr("This folder must not be renamed. It is renamed back to its original name."));
|
||||||
@@ -103,13 +102,13 @@ void PropagateRemoteMove::start()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString destination = QDir::cleanPath(propagator()->account()->url().path() + QLatin1Char('/')
|
QString destination = QDir::cleanPath(_propagator->account()->url().path() + QLatin1Char('/')
|
||||||
+ propagator()->account()->davPath() + propagator()->_remoteFolder + _item->_renameTarget);
|
+ _propagator->account()->davPath() + _propagator->_remoteFolder + _item->_renameTarget);
|
||||||
_job = new MoveJob(propagator()->account(),
|
_job = new MoveJob(_propagator->account(),
|
||||||
propagator()->_remoteFolder + _item->_file,
|
_propagator->_remoteFolder + _item->_file,
|
||||||
destination, this);
|
destination, this);
|
||||||
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotMoveJobFinished()));
|
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotMoveJobFinished()));
|
||||||
propagator()->_activeJobList.append(this);
|
_propagator->_activeJobList.append(this);
|
||||||
_job->start();
|
_job->start();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -122,9 +121,9 @@ void PropagateRemoteMove::abort()
|
|||||||
|
|
||||||
void PropagateRemoteMove::slotMoveJobFinished()
|
void PropagateRemoteMove::slotMoveJobFinished()
|
||||||
{
|
{
|
||||||
propagator()->_activeJobList.removeOne(this);
|
_propagator->_activeJobList.removeOne(this);
|
||||||
|
|
||||||
ASSERT(_job);
|
Q_ASSERT(_job);
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << _job->reply()->request().url() << "FINISHED WITH STATUS"
|
qDebug() << Q_FUNC_INFO << _job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||||
<< _job->reply()->error()
|
<< _job->reply()->error()
|
||||||
@@ -141,11 +140,12 @@ void PropagateRemoteMove::slotMoveJobFinished()
|
|||||||
}
|
}
|
||||||
|
|
||||||
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
||||||
&propagator()->_anotherSyncNeeded);
|
&_propagator->_anotherSyncNeeded);
|
||||||
done(status, _job->errorString());
|
done(status, _job->errorString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_item->_requestDuration = _job->duration();
|
||||||
_item->_responseTimeStamp = _job->responseTimestamp();
|
_item->_responseTimeStamp = _job->responseTimestamp();
|
||||||
|
|
||||||
if (_item->_httpErrorCode != 201 ) {
|
if (_item->_httpErrorCode != 201 ) {
|
||||||
@@ -164,14 +164,14 @@ void PropagateRemoteMove::slotMoveJobFinished()
|
|||||||
void PropagateRemoteMove::finalize()
|
void PropagateRemoteMove::finalize()
|
||||||
{
|
{
|
||||||
SyncJournalFileRecord oldRecord =
|
SyncJournalFileRecord oldRecord =
|
||||||
propagator()->_journal->getFileRecord(_item->_originalFile);
|
_propagator->_journal->getFileRecord(_item->_originalFile);
|
||||||
// if reading from db failed still continue hoping that deleteFileRecord
|
// if reading from db failed still continue hoping that deleteFileRecord
|
||||||
// reopens the db successfully.
|
// reopens the db successfully.
|
||||||
// The db is only queried to transfer the content checksum from the old
|
// The db is only queried to transfer the content checksum from the old
|
||||||
// to the new record. It is not a problem to skip it here.
|
// to the new record. It is not a problem to skip it here.
|
||||||
propagator()->_journal->deleteFileRecord(_item->_originalFile);
|
_propagator->_journal->deleteFileRecord(_item->_originalFile);
|
||||||
|
|
||||||
SyncJournalFileRecord record(*_item, propagator()->getFilePath(_item->_renameTarget));
|
SyncJournalFileRecord record(*_item, _propagator->getFilePath(_item->_renameTarget));
|
||||||
record._path = _item->_renameTarget;
|
record._path = _item->_renameTarget;
|
||||||
if (oldRecord.isValid()) {
|
if (oldRecord.isValid()) {
|
||||||
record._contentChecksum = oldRecord._contentChecksum;
|
record._contentChecksum = oldRecord._contentChecksum;
|
||||||
@@ -182,19 +182,19 @@ void PropagateRemoteMove::finalize()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!propagator()->_journal->setFileRecord(record)) {
|
if (!_propagator->_journal->setFileRecord(record)) {
|
||||||
done(SyncFileItem::FatalError, tr("Error writing metadata to the database"));
|
done(SyncFileItem::FatalError, tr("Error writing metadata to the database"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_item->_isDirectory) {
|
if (_item->_isDirectory) {
|
||||||
if (!adjustSelectiveSync(propagator()->_journal, _item->_file, _item->_renameTarget)) {
|
if (!adjustSelectiveSync(_propagator->_journal, _item->_file, _item->_renameTarget)) {
|
||||||
done(SyncFileItem::FatalError, tr("Error writing metadata to the database"));
|
done(SyncFileItem::FatalError, tr("Error writing metadata to the database"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
propagator()->_journal->commit("Remote Rename");
|
_propagator->_journal->commit("Remote Rename");
|
||||||
done(SyncFileItem::Success);
|
done(SyncFileItem::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,8 +208,8 @@ bool PropagateRemoteMove::adjustSelectiveSync(SyncJournalDb *journal, const QStr
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
ASSERT(!from_.endsWith(QLatin1String("/")));
|
Q_ASSERT(!from_.endsWith(QLatin1String("/")));
|
||||||
ASSERT(!to_.endsWith(QLatin1String("/")));
|
Q_ASSERT(!to_.endsWith(QLatin1String("/")));
|
||||||
QString from = from_ + QLatin1String("/");
|
QString from = from_ + QLatin1String("/");
|
||||||
QString to = to_ + QLatin1String("/");
|
QString to = to_ + QLatin1String("/");
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#include "checksums.h"
|
#include "checksums.h"
|
||||||
#include "syncengine.h"
|
#include "syncengine.h"
|
||||||
#include "propagateremotedelete.h"
|
#include "propagateremotedelete.h"
|
||||||
#include "asserts.h"
|
|
||||||
|
|
||||||
#include <json.h>
|
#include <json.h>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
@@ -194,18 +193,18 @@ void PropagateUploadFileCommon::setDeleteExisting(bool enabled)
|
|||||||
|
|
||||||
void PropagateUploadFileCommon::start()
|
void PropagateUploadFileCommon::start()
|
||||||
{
|
{
|
||||||
if (propagator()->_abortRequested.fetchAndAddRelaxed(0)) {
|
if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
propagator()->_activeJobList.append(this);
|
_propagator->_activeJobList.append(this);
|
||||||
|
|
||||||
if (!_deleteExisting) {
|
if (!_deleteExisting) {
|
||||||
return slotComputeContentChecksum();
|
return slotComputeContentChecksum();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto job = new DeleteJob(propagator()->account(),
|
auto job = new DeleteJob(_propagator->account(),
|
||||||
propagator()->_remoteFolder + _item->_file,
|
_propagator->_remoteFolder + _item->_file,
|
||||||
this);
|
this);
|
||||||
_jobs.append(job);
|
_jobs.append(job);
|
||||||
connect(job, SIGNAL(finishedSignal()), SLOT(slotComputeContentChecksum()));
|
connect(job, SIGNAL(finishedSignal()), SLOT(slotComputeContentChecksum()));
|
||||||
@@ -215,19 +214,17 @@ void PropagateUploadFileCommon::start()
|
|||||||
|
|
||||||
void PropagateUploadFileCommon::slotComputeContentChecksum()
|
void PropagateUploadFileCommon::slotComputeContentChecksum()
|
||||||
{
|
{
|
||||||
if (propagator()->_abortRequested.fetchAndAddRelaxed(0)) {
|
if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString filePath = propagator()->getFilePath(_item->_file);
|
const QString filePath = _propagator->getFilePath(_item->_file);
|
||||||
|
|
||||||
// remember the modtime before checksumming to be able to detect a file
|
// remember the modtime before checksumming to be able to detect a file
|
||||||
// change during the checksum calculation
|
// change during the checksum calculation
|
||||||
_item->_modtime = FileSystem::getModTime(filePath);
|
_item->_modtime = FileSystem::getModTime(filePath);
|
||||||
|
|
||||||
#ifdef WITH_TESTING
|
|
||||||
_stopWatch.start();
|
_stopWatch.start();
|
||||||
#endif
|
|
||||||
|
|
||||||
QByteArray checksumType = contentChecksumType();
|
QByteArray checksumType = contentChecksumType();
|
||||||
|
|
||||||
@@ -254,14 +251,12 @@ void PropagateUploadFileCommon::slotComputeTransmissionChecksum(const QByteArray
|
|||||||
_item->_contentChecksum = contentChecksum;
|
_item->_contentChecksum = contentChecksum;
|
||||||
_item->_contentChecksumType = contentChecksumType;
|
_item->_contentChecksumType = contentChecksumType;
|
||||||
|
|
||||||
#ifdef WITH_TESTING
|
|
||||||
_stopWatch.addLapTime(QLatin1String("ContentChecksum"));
|
_stopWatch.addLapTime(QLatin1String("ContentChecksum"));
|
||||||
_stopWatch.start();
|
_stopWatch.start();
|
||||||
#endif
|
|
||||||
|
|
||||||
// Reuse the content checksum as the transmission checksum if possible
|
// Reuse the content checksum as the transmission checksum if possible
|
||||||
const auto supportedTransmissionChecksums =
|
const auto supportedTransmissionChecksums =
|
||||||
propagator()->account()->capabilities().supportedChecksumTypes();
|
_propagator->account()->capabilities().supportedChecksumTypes();
|
||||||
if (supportedTransmissionChecksums.contains(contentChecksumType)) {
|
if (supportedTransmissionChecksums.contains(contentChecksumType)) {
|
||||||
slotStartUpload(contentChecksumType, contentChecksum);
|
slotStartUpload(contentChecksumType, contentChecksum);
|
||||||
return;
|
return;
|
||||||
@@ -270,7 +265,7 @@ void PropagateUploadFileCommon::slotComputeTransmissionChecksum(const QByteArray
|
|||||||
// Compute the transmission checksum.
|
// Compute the transmission checksum.
|
||||||
auto computeChecksum = new ComputeChecksum(this);
|
auto computeChecksum = new ComputeChecksum(this);
|
||||||
if (uploadChecksumEnabled()) {
|
if (uploadChecksumEnabled()) {
|
||||||
computeChecksum->setChecksumType(propagator()->account()->capabilities().uploadChecksumType());
|
computeChecksum->setChecksumType(_propagator->account()->capabilities().uploadChecksumType());
|
||||||
} else {
|
} else {
|
||||||
computeChecksum->setChecksumType(QByteArray());
|
computeChecksum->setChecksumType(QByteArray());
|
||||||
}
|
}
|
||||||
@@ -279,7 +274,7 @@ void PropagateUploadFileCommon::slotComputeTransmissionChecksum(const QByteArray
|
|||||||
SLOT(slotStartUpload(QByteArray,QByteArray)));
|
SLOT(slotStartUpload(QByteArray,QByteArray)));
|
||||||
connect(computeChecksum, SIGNAL(done(QByteArray,QByteArray)),
|
connect(computeChecksum, SIGNAL(done(QByteArray,QByteArray)),
|
||||||
computeChecksum, SLOT(deleteLater()));
|
computeChecksum, SLOT(deleteLater()));
|
||||||
const QString filePath = propagator()->getFilePath(_item->_file);
|
const QString filePath = _propagator->getFilePath(_item->_file);
|
||||||
computeChecksum->start(filePath);
|
computeChecksum->start(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,7 +282,7 @@ void PropagateUploadFileCommon::slotStartUpload(const QByteArray& transmissionCh
|
|||||||
{
|
{
|
||||||
// Remove ourselfs from the list of active job, before any posible call to done()
|
// Remove ourselfs from the list of active job, before any posible call to done()
|
||||||
// When we start chunks, we will add it again, once for every chunks.
|
// When we start chunks, we will add it again, once for every chunks.
|
||||||
propagator()->_activeJobList.removeOne(this);
|
_propagator->_activeJobList.removeOne(this);
|
||||||
|
|
||||||
_transmissionChecksum = transmissionChecksum;
|
_transmissionChecksum = transmissionChecksum;
|
||||||
_transmissionChecksumType = transmissionChecksumType;
|
_transmissionChecksumType = transmissionChecksumType;
|
||||||
@@ -298,15 +293,13 @@ void PropagateUploadFileCommon::slotStartUpload(const QByteArray& transmissionCh
|
|||||||
_item->_contentChecksumType = transmissionChecksumType;
|
_item->_contentChecksumType = transmissionChecksumType;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString fullFilePath = propagator()->getFilePath(_item->_file);
|
const QString fullFilePath = _propagator->getFilePath(_item->_file);
|
||||||
|
|
||||||
if (!FileSystem::fileExists(fullFilePath)) {
|
if (!FileSystem::fileExists(fullFilePath)) {
|
||||||
done(SyncFileItem::SoftError, tr("File Removed"));
|
done(SyncFileItem::SoftError, tr("File Removed"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifdef WITH_TESTING
|
|
||||||
_stopWatch.addLapTime(QLatin1String("TransmissionChecksum"));
|
_stopWatch.addLapTime(QLatin1String("TransmissionChecksum"));
|
||||||
#endif
|
|
||||||
|
|
||||||
time_t prevModtime = _item->_modtime; // the _item value was set in PropagateUploadFile::start()
|
time_t prevModtime = _item->_modtime; // the _item value was set in PropagateUploadFile::start()
|
||||||
// but a potential checksum calculation could have taken some time during which the file could
|
// but a potential checksum calculation could have taken some time during which the file could
|
||||||
@@ -314,7 +307,7 @@ void PropagateUploadFileCommon::slotStartUpload(const QByteArray& transmissionCh
|
|||||||
|
|
||||||
_item->_modtime = FileSystem::getModTime(fullFilePath);
|
_item->_modtime = FileSystem::getModTime(fullFilePath);
|
||||||
if( prevModtime != _item->_modtime ) {
|
if( prevModtime != _item->_modtime ) {
|
||||||
propagator()->_anotherSyncNeeded = true;
|
_propagator->_anotherSyncNeeded = true;
|
||||||
done(SyncFileItem::SoftError, tr("Local file changed during syncing. It will be resumed."));
|
done(SyncFileItem::SoftError, tr("Local file changed during syncing. It will be resumed."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -326,7 +319,7 @@ void PropagateUploadFileCommon::slotStartUpload(const QByteArray& transmissionCh
|
|||||||
// That usually indicates a file that is still being changed
|
// That usually indicates a file that is still being changed
|
||||||
// or not yet fully copied to the destination.
|
// or not yet fully copied to the destination.
|
||||||
if (fileIsStillChanging(*_item)) {
|
if (fileIsStillChanging(*_item)) {
|
||||||
propagator()->_anotherSyncNeeded = true;
|
_propagator->_anotherSyncNeeded = true;
|
||||||
done(SyncFileItem::SoftError, tr("Local file changed during sync."));
|
done(SyncFileItem::SoftError, tr("Local file changed during sync."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -376,7 +369,7 @@ bool UploadDevice::prepareAndOpen(const QString& fileName, qint64 start, qint64
|
|||||||
|
|
||||||
|
|
||||||
qint64 UploadDevice::writeData(const char* , qint64 ) {
|
qint64 UploadDevice::writeData(const char* , qint64 ) {
|
||||||
ASSERT(false, "write to read only device");
|
Q_ASSERT(!"write to read only device");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,25 +464,25 @@ void UploadDevice::setChoked(bool b) {
|
|||||||
|
|
||||||
void PropagateUploadFileCommon::startPollJob(const QString& path)
|
void PropagateUploadFileCommon::startPollJob(const QString& path)
|
||||||
{
|
{
|
||||||
PollJob* job = new PollJob(propagator()->account(), path, _item,
|
PollJob* job = new PollJob(_propagator->account(), path, _item,
|
||||||
propagator()->_journal, propagator()->_localDir, this);
|
_propagator->_journal, _propagator->_localDir, this);
|
||||||
connect(job, SIGNAL(finishedSignal()), SLOT(slotPollFinished()));
|
connect(job, SIGNAL(finishedSignal()), SLOT(slotPollFinished()));
|
||||||
SyncJournalDb::PollInfo info;
|
SyncJournalDb::PollInfo info;
|
||||||
info._file = _item->_file;
|
info._file = _item->_file;
|
||||||
info._url = path;
|
info._url = path;
|
||||||
info._modtime = _item->_modtime;
|
info._modtime = _item->_modtime;
|
||||||
propagator()->_journal->setPollInfo(info);
|
_propagator->_journal->setPollInfo(info);
|
||||||
propagator()->_journal->commit("add poll info");
|
_propagator->_journal->commit("add poll info");
|
||||||
propagator()->_activeJobList.append(this);
|
_propagator->_activeJobList.append(this);
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PropagateUploadFileCommon::slotPollFinished()
|
void PropagateUploadFileCommon::slotPollFinished()
|
||||||
{
|
{
|
||||||
PollJob *job = qobject_cast<PollJob *>(sender());
|
PollJob *job = qobject_cast<PollJob *>(sender());
|
||||||
ASSERT(job);
|
Q_ASSERT(job);
|
||||||
|
|
||||||
propagator()->_activeJobList.removeOne(this);
|
_propagator->_activeJobList.removeOne(this);
|
||||||
|
|
||||||
if (job->_item->_status != SyncFileItem::Success) {
|
if (job->_item->_status != SyncFileItem::Success) {
|
||||||
_finished = true;
|
_finished = true;
|
||||||
@@ -500,27 +493,6 @@ void PropagateUploadFileCommon::slotPollFinished()
|
|||||||
finalize();
|
finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PropagateUploadFileCommon::checkResettingErrors()
|
|
||||||
{
|
|
||||||
if (_item->_httpErrorCode == 412
|
|
||||||
|| propagator()->account()->capabilities().httpErrorCodesThatResetFailingChunkedUploads()
|
|
||||||
.contains(_item->_httpErrorCode)) {
|
|
||||||
auto uploadInfo = propagator()->_journal->getUploadInfo(_item->_file);
|
|
||||||
uploadInfo._errorCount += 1;
|
|
||||||
if (uploadInfo._errorCount > 3) {
|
|
||||||
qDebug() << "Reset transfer of" << _item->_file
|
|
||||||
<< "due to repeated error" << _item->_httpErrorCode;
|
|
||||||
uploadInfo = SyncJournalDb::UploadInfo();
|
|
||||||
} else {
|
|
||||||
qDebug() << "Error count for maybe-reset error" << _item->_httpErrorCode
|
|
||||||
<< "on file" << _item->_file
|
|
||||||
<< "is" << uploadInfo._errorCount;
|
|
||||||
}
|
|
||||||
propagator()->_journal->setUploadInfo(_item->_file, uploadInfo);
|
|
||||||
propagator()->_journal->commit("Upload info");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PropagateUploadFileCommon::slotJobDestroyed(QObject* job)
|
void PropagateUploadFileCommon::slotJobDestroyed(QObject* job)
|
||||||
{
|
{
|
||||||
_jobs.erase(std::remove(_jobs.begin(), _jobs.end(), job) , _jobs.end());
|
_jobs.erase(std::remove(_jobs.begin(), _jobs.end(), job) , _jobs.end());
|
||||||
@@ -576,15 +548,16 @@ QMap<QByteArray, QByteArray> PropagateUploadFileCommon::headers()
|
|||||||
|
|
||||||
void PropagateUploadFileCommon::finalize()
|
void PropagateUploadFileCommon::finalize()
|
||||||
{
|
{
|
||||||
|
_item->_requestDuration = _duration.elapsed();
|
||||||
_finished = true;
|
_finished = true;
|
||||||
|
|
||||||
if (!propagator()->_journal->setFileRecord(SyncJournalFileRecord(*_item, propagator()->getFilePath(_item->_file)))) {
|
if (!_propagator->_journal->setFileRecord(SyncJournalFileRecord(*_item, _propagator->getFilePath(_item->_file)))) {
|
||||||
done(SyncFileItem::FatalError, tr("Error writing metadata to the database"));
|
done(SyncFileItem::FatalError, tr("Error writing metadata to the database"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Remove from the progress database:
|
// Remove from the progress database:
|
||||||
propagator()->_journal->setUploadInfo(_item->_file, SyncJournalDb::UploadInfo());
|
_propagator->_journal->setUploadInfo(_item->_file, SyncJournalDb::UploadInfo());
|
||||||
propagator()->_journal->commit("upload file start");
|
_propagator->_journal->commit("upload file start");
|
||||||
|
|
||||||
done(SyncFileItem::Success);
|
done(SyncFileItem::Success);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,14 +183,13 @@ class PropagateUploadFileCommon : public PropagateItemJob {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
QElapsedTimer _duration;
|
||||||
QVector<AbstractNetworkJob*> _jobs; /// network jobs that are currently in transit
|
QVector<AbstractNetworkJob*> _jobs; /// network jobs that are currently in transit
|
||||||
bool _finished BITFIELD(1); /// Tells that all the jobs have been finished
|
bool _finished; /// Tells that all the jobs have been finished
|
||||||
bool _deleteExisting BITFIELD(1);
|
bool _deleteExisting;
|
||||||
|
|
||||||
// measure the performance of checksum calc and upload
|
// measure the performance of checksum calc and upload
|
||||||
#ifdef WITH_TESTING
|
|
||||||
Utility::StopWatch _stopWatch;
|
Utility::StopWatch _stopWatch;
|
||||||
#endif
|
|
||||||
|
|
||||||
QByteArray _transmissionChecksum;
|
QByteArray _transmissionChecksum;
|
||||||
QByteArray _transmissionChecksumType;
|
QByteArray _transmissionChecksumType;
|
||||||
@@ -233,13 +232,6 @@ private slots:
|
|||||||
void slotPollFinished();
|
void slotPollFinished();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
|
||||||
* Checks whether the current error is one that should reset the whole
|
|
||||||
* transfer if it happens too often. If so: Bump UploadInfo::errorCount
|
|
||||||
* and maybe perform the reset.
|
|
||||||
*/
|
|
||||||
void checkResettingErrors();
|
|
||||||
|
|
||||||
// Bases headers that need to be sent with every chunk
|
// Bases headers that need to be sent with every chunk
|
||||||
QMap<QByteArray, QByteArray> headers();
|
QMap<QByteArray, QByteArray> headers();
|
||||||
|
|
||||||
@@ -270,7 +262,7 @@ private:
|
|||||||
int _chunkCount; /// Total number of chunks for this file
|
int _chunkCount; /// Total number of chunks for this file
|
||||||
int _transferId; /// transfer id (part of the url)
|
int _transferId; /// transfer id (part of the url)
|
||||||
|
|
||||||
quint64 chunkSize() const { return propagator()->chunkSize(); }
|
quint64 chunkSize() const { return _propagator->chunkSize(); }
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -301,10 +293,9 @@ private:
|
|||||||
|
|
||||||
// Map chunk number with its size from the PROPFIND on resume.
|
// Map chunk number with its size from the PROPFIND on resume.
|
||||||
// (Only used from slotPropfindIterate/slotPropfindFinished because the LsColJob use signals to report data.)
|
// (Only used from slotPropfindIterate/slotPropfindFinished because the LsColJob use signals to report data.)
|
||||||
struct ServerChunkInfo { quint64 size; QString originalName; };
|
QMap<int, quint64> _serverChunks;
|
||||||
QMap<int, ServerChunkInfo> _serverChunks;
|
|
||||||
|
|
||||||
quint64 chunkSize() const { return propagator()->chunkSize(); }
|
quint64 chunkSize() const { return _propagator->chunkSize(); }
|
||||||
/**
|
/**
|
||||||
* Return the URL of a chunk.
|
* Return the URL of a chunk.
|
||||||
* If chunk == -1, returns the URL of the parent folder containing the chunks
|
* If chunk == -1, returns the URL of the parent folder containing the chunks
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
#include "syncengine.h"
|
#include "syncengine.h"
|
||||||
#include "propagateremotemove.h"
|
#include "propagateremotemove.h"
|
||||||
#include "propagateremotedelete.h"
|
#include "propagateremotedelete.h"
|
||||||
#include "asserts.h"
|
|
||||||
|
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
@@ -38,13 +38,12 @@ namespace OCC {
|
|||||||
QUrl PropagateUploadFileNG::chunkUrl(int chunk)
|
QUrl PropagateUploadFileNG::chunkUrl(int chunk)
|
||||||
{
|
{
|
||||||
QString path = QLatin1String("remote.php/dav/uploads/")
|
QString path = QLatin1String("remote.php/dav/uploads/")
|
||||||
+ propagator()->account()->davUser()
|
+ _propagator->account()->davUser()
|
||||||
+ QLatin1Char('/') + QString::number(_transferId);
|
+ QLatin1Char('/') + QString::number(_transferId);
|
||||||
if (chunk >= 0) {
|
if (chunk >= 0) {
|
||||||
// We need to do add leading 0 because the server orders the chunk alphabetically
|
path += QLatin1Char('/') + QString::number(chunk);
|
||||||
path += QLatin1Char('/') + QString::number(chunk).rightJustified(8, '0');
|
|
||||||
}
|
}
|
||||||
return Utility::concatUrlPath(propagator()->account()->url(), path);
|
return Utility::concatUrlPath(_propagator->account()->url(), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -80,13 +79,14 @@ QUrl PropagateUploadFileNG::chunkUrl(int chunk)
|
|||||||
|
|
||||||
void PropagateUploadFileNG::doStartUpload()
|
void PropagateUploadFileNG::doStartUpload()
|
||||||
{
|
{
|
||||||
propagator()->_activeJobList.append(this);
|
_duration.start();
|
||||||
|
_propagator->_activeJobList.append(this);
|
||||||
|
|
||||||
const SyncJournalDb::UploadInfo progressInfo = propagator()->_journal->getUploadInfo(_item->_file);
|
const SyncJournalDb::UploadInfo progressInfo = _propagator->_journal->getUploadInfo(_item->_file);
|
||||||
if (progressInfo._valid && Utility::qDateTimeToTime_t(progressInfo._modtime) == _item->_modtime ) {
|
if (progressInfo._valid && Utility::qDateTimeToTime_t(progressInfo._modtime) == _item->_modtime ) {
|
||||||
_transferId = progressInfo._transferid;
|
_transferId = progressInfo._transferid;
|
||||||
auto url = chunkUrl();
|
auto url = chunkUrl();
|
||||||
auto job = new LsColJob(propagator()->account(), url, this);
|
auto job = new LsColJob(_propagator->account(), url, this);
|
||||||
_jobs.append(job);
|
_jobs.append(job);
|
||||||
job->setProperties(QList<QByteArray>() << "resourcetype" << "getcontentlength");
|
job->setProperties(QList<QByteArray>() << "resourcetype" << "getcontentlength");
|
||||||
connect(job, SIGNAL(finishedWithoutError()), this, SLOT(slotPropfindFinished()));
|
connect(job, SIGNAL(finishedWithoutError()), this, SLOT(slotPropfindFinished()));
|
||||||
@@ -97,12 +97,6 @@ void PropagateUploadFileNG::doStartUpload()
|
|||||||
this, SLOT(slotPropfindIterate(QString,QMap<QString,QString>)));
|
this, SLOT(slotPropfindIterate(QString,QMap<QString,QString>)));
|
||||||
job->start();
|
job->start();
|
||||||
return;
|
return;
|
||||||
} else if (progressInfo._valid) {
|
|
||||||
// The upload info is stale. remove the stale chunks on the server
|
|
||||||
_transferId = progressInfo._transferid;
|
|
||||||
// Fire and forget. Any error will be ignored.
|
|
||||||
(new DeleteJob(propagator()->account(), chunkUrl(), this))->start();
|
|
||||||
// startNewUpload will reset the _transferId and the UploadInfo in the db.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
startNewUpload();
|
startNewUpload();
|
||||||
@@ -114,11 +108,9 @@ void PropagateUploadFileNG::slotPropfindIterate(const QString &name, const QMap<
|
|||||||
return; // skip the info about the path itself
|
return; // skip the info about the path itself
|
||||||
}
|
}
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
QString chunkName = name.mid(name.lastIndexOf('/')+1);
|
auto chunkId = name.mid(name.lastIndexOf('/')+1).toUInt(&ok);
|
||||||
auto chunkId = chunkName.toUInt(&ok);
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
ServerChunkInfo chunkinfo = { properties["getcontentlength"].toULongLong(), chunkName };
|
_serverChunks[chunkId] = properties["getcontentlength"].toULongLong();
|
||||||
_serverChunks[chunkId] = chunkinfo;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,12 +118,12 @@ void PropagateUploadFileNG::slotPropfindFinished()
|
|||||||
{
|
{
|
||||||
auto job = qobject_cast<LsColJob *>(sender());
|
auto job = qobject_cast<LsColJob *>(sender());
|
||||||
slotJobDestroyed(job); // remove it from the _jobs list
|
slotJobDestroyed(job); // remove it from the _jobs list
|
||||||
propagator()->_activeJobList.removeOne(this);
|
_propagator->_activeJobList.removeOne(this);
|
||||||
|
|
||||||
_currentChunk = 0;
|
_currentChunk = 0;
|
||||||
_sent = 0;
|
_sent = 0;
|
||||||
while (_serverChunks.contains(_currentChunk)) {
|
while (_serverChunks.contains(_currentChunk)) {
|
||||||
_sent += _serverChunks[_currentChunk].size;
|
_sent += _serverChunks[_currentChunk];
|
||||||
_serverChunks.remove(_currentChunk);
|
_serverChunks.remove(_currentChunk);
|
||||||
++_currentChunk;
|
++_currentChunk;
|
||||||
}
|
}
|
||||||
@@ -149,20 +141,19 @@ void PropagateUploadFileNG::slotPropfindFinished()
|
|||||||
qDebug() << "Resuming "<< _item->_file << " from chunk " << _currentChunk << "; sent ="<< _sent;
|
qDebug() << "Resuming "<< _item->_file << " from chunk " << _currentChunk << "; sent ="<< _sent;
|
||||||
|
|
||||||
if (!_serverChunks.isEmpty()) {
|
if (!_serverChunks.isEmpty()) {
|
||||||
qDebug() << "To Delete" << _serverChunks.keys();
|
qDebug() << "To Delete" << _serverChunks;
|
||||||
propagator()->_activeJobList.append(this);
|
_propagator->_activeJobList.append(this);
|
||||||
_removeJobError = false;
|
_removeJobError = false;
|
||||||
|
|
||||||
// Make sure that if there is a "hole" and then a few more chunks, on the server
|
// Make sure that if there is a "hole" and then a few more chunks, on the server
|
||||||
// we should remove the later chunks. Otherwise when we do dynamic chunk sizing, we may end up
|
// we should remove the later chunks. Otherwise when we do dynamic chunk sizing, we may end up
|
||||||
// with corruptions if there are too many chunks, or if we abort and there are still stale chunks.
|
// with corruptions if there are too many chunks, or if we abort and there are still stale chunks.
|
||||||
for (auto it = _serverChunks.begin(); it != _serverChunks.end(); ++it) {
|
for (auto it = _serverChunks.begin(); it != _serverChunks.end(); ++it) {
|
||||||
auto job = new DeleteJob(propagator()->account(), Utility::concatUrlPath(chunkUrl(), it->originalName), this);
|
auto job = new DeleteJob(_propagator->account(), Utility::concatUrlPath(chunkUrl(), QString::number(it.key())), this);
|
||||||
QObject::connect(job, SIGNAL(finishedSignal()), this, SLOT(slotDeleteJobFinished()));
|
QObject::connect(job, SIGNAL(finishedSignal()), this, SLOT(slotDeleteJobFinished()));
|
||||||
_jobs.append(job);
|
_jobs.append(job);
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
_serverChunks.clear();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,9 +166,9 @@ void PropagateUploadFileNG::slotPropfindFinishedWithError()
|
|||||||
slotJobDestroyed(job); // remove it from the _jobs list
|
slotJobDestroyed(job); // remove it from the _jobs list
|
||||||
QNetworkReply::NetworkError err = job->reply()->error();
|
QNetworkReply::NetworkError err = job->reply()->error();
|
||||||
auto httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
auto httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
auto status = classifyError(err, httpErrorCode, &propagator()->_anotherSyncNeeded);
|
auto status = classifyError(err, httpErrorCode, &_propagator->_anotherSyncNeeded);
|
||||||
if (status == SyncFileItem::FatalError) {
|
if (status == SyncFileItem::FatalError) {
|
||||||
propagator()->_activeJobList.removeOne(this);
|
_propagator->_activeJobList.removeOne(this);
|
||||||
QString errorString = errorMessage(job->reply()->errorString(), job->reply()->readAll());
|
QString errorString = errorMessage(job->reply()->errorString(), job->reply()->readAll());
|
||||||
abortWithError(status, errorString);
|
abortWithError(status, errorString);
|
||||||
return;
|
return;
|
||||||
@@ -188,7 +179,7 @@ void PropagateUploadFileNG::slotPropfindFinishedWithError()
|
|||||||
void PropagateUploadFileNG::slotDeleteJobFinished()
|
void PropagateUploadFileNG::slotDeleteJobFinished()
|
||||||
{
|
{
|
||||||
auto job = qobject_cast<DeleteJob *>(sender());
|
auto job = qobject_cast<DeleteJob *>(sender());
|
||||||
ASSERT(job);
|
Q_ASSERT(job);
|
||||||
_jobs.remove(_jobs.indexOf(job));
|
_jobs.remove(_jobs.indexOf(job));
|
||||||
|
|
||||||
QNetworkReply::NetworkError err = job->reply()->error();
|
QNetworkReply::NetworkError err = job->reply()->error();
|
||||||
@@ -206,7 +197,7 @@ void PropagateUploadFileNG::slotDeleteJobFinished()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_jobs.isEmpty()) {
|
if (_jobs.isEmpty()) {
|
||||||
propagator()->_activeJobList.removeOne(this);
|
_propagator->_activeJobList.removeOne(this);
|
||||||
if (_removeJobError) {
|
if (_removeJobError) {
|
||||||
// There was an error removing some files, just start over
|
// There was an error removing some files, just start over
|
||||||
startNewUpload();
|
startNewUpload();
|
||||||
@@ -220,7 +211,7 @@ void PropagateUploadFileNG::slotDeleteJobFinished()
|
|||||||
|
|
||||||
void PropagateUploadFileNG::startNewUpload()
|
void PropagateUploadFileNG::startNewUpload()
|
||||||
{
|
{
|
||||||
ASSERT(propagator()->_activeJobList.count(this) == 1);
|
Q_ASSERT(_propagator->_activeJobList.count(this) == 1);
|
||||||
_transferId = qrand() ^ _item->_modtime ^ (_item->_size << 16) ^ qHash(_item->_file);
|
_transferId = qrand() ^ _item->_modtime ^ (_item->_size << 16) ^ qHash(_item->_file);
|
||||||
_sent = 0;
|
_sent = 0;
|
||||||
_currentChunk = 0;
|
_currentChunk = 0;
|
||||||
@@ -231,11 +222,11 @@ void PropagateUploadFileNG::startNewUpload()
|
|||||||
pi._valid = true;
|
pi._valid = true;
|
||||||
pi._transferid = _transferId;
|
pi._transferid = _transferId;
|
||||||
pi._modtime = Utility::qDateTimeFromTime_t(_item->_modtime);
|
pi._modtime = Utility::qDateTimeFromTime_t(_item->_modtime);
|
||||||
propagator()->_journal->setUploadInfo(_item->_file, pi);
|
_propagator->_journal->setUploadInfo(_item->_file, pi);
|
||||||
propagator()->_journal->commit("Upload info");
|
_propagator->_journal->commit("Upload info");
|
||||||
QMap<QByteArray, QByteArray> headers;
|
QMap<QByteArray, QByteArray> headers;
|
||||||
headers["OC-Total-Length"] = QByteArray::number(_item->_size);
|
headers["OC-Total-Length"] = QByteArray::number(_item->_size);
|
||||||
auto job = new MkColJob(propagator()->account(), chunkUrl(), headers, this);
|
auto job = new MkColJob(_propagator->account(), chunkUrl(), headers, this);
|
||||||
|
|
||||||
connect(job, SIGNAL(finished(QNetworkReply::NetworkError)),
|
connect(job, SIGNAL(finished(QNetworkReply::NetworkError)),
|
||||||
this, SLOT(slotMkColFinished(QNetworkReply::NetworkError)));
|
this, SLOT(slotMkColFinished(QNetworkReply::NetworkError)));
|
||||||
@@ -245,7 +236,7 @@ void PropagateUploadFileNG::startNewUpload()
|
|||||||
|
|
||||||
void PropagateUploadFileNG::slotMkColFinished(QNetworkReply::NetworkError)
|
void PropagateUploadFileNG::slotMkColFinished(QNetworkReply::NetworkError)
|
||||||
{
|
{
|
||||||
propagator()->_activeJobList.removeOne(this);
|
_propagator->_activeJobList.removeOne(this);
|
||||||
auto job = qobject_cast<MkColJob *>(sender());
|
auto job = qobject_cast<MkColJob *>(sender());
|
||||||
slotJobDestroyed(job); // remove it from the _jobs list
|
slotJobDestroyed(job); // remove it from the _jobs list
|
||||||
QNetworkReply::NetworkError err = job->reply()->error();
|
QNetworkReply::NetworkError err = job->reply()->error();
|
||||||
@@ -253,7 +244,7 @@ void PropagateUploadFileNG::slotMkColFinished(QNetworkReply::NetworkError)
|
|||||||
|
|
||||||
if (err != QNetworkReply::NoError || _item->_httpErrorCode != 201) {
|
if (err != QNetworkReply::NoError || _item->_httpErrorCode != 201) {
|
||||||
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
||||||
&propagator()->_anotherSyncNeeded);
|
&_propagator->_anotherSyncNeeded);
|
||||||
QString errorString = errorMessage(job->reply()->errorString(), job->reply()->readAll());
|
QString errorString = errorMessage(job->reply()->errorString(), job->reply()->readAll());
|
||||||
if (job->reply()->hasRawHeader("OC-ErrorString")) {
|
if (job->reply()->hasRawHeader("OC-ErrorString")) {
|
||||||
errorString = job->reply()->rawHeader("OC-ErrorString");
|
errorString = job->reply()->rawHeader("OC-ErrorString");
|
||||||
@@ -266,20 +257,19 @@ void PropagateUploadFileNG::slotMkColFinished(QNetworkReply::NetworkError)
|
|||||||
|
|
||||||
void PropagateUploadFileNG::startNextChunk()
|
void PropagateUploadFileNG::startNextChunk()
|
||||||
{
|
{
|
||||||
if (propagator()->_abortRequested.fetchAndAddRelaxed(0))
|
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
quint64 fileSize = _item->_size;
|
quint64 fileSize = _item->_size;
|
||||||
ENFORCE(fileSize >= _sent, "Sent data exceeds file size");
|
Q_ASSERT(fileSize >= _sent);
|
||||||
|
|
||||||
quint64 currentChunkSize = qMin(chunkSize(), fileSize - _sent);
|
quint64 currentChunkSize = qMin(chunkSize(), fileSize - _sent);
|
||||||
|
|
||||||
if (currentChunkSize == 0) {
|
if (currentChunkSize == 0) {
|
||||||
ASSERT(_jobs.isEmpty());
|
Q_ASSERT(_jobs.isEmpty()); // There should be no running job anymore
|
||||||
_finished = true;
|
_finished = true;
|
||||||
// Finish with a MOVE
|
// Finish with a MOVE
|
||||||
QString destination = QDir::cleanPath(propagator()->account()->url().path() + QLatin1Char('/')
|
QString destination = QDir::cleanPath(_propagator->account()->url().path() + QLatin1Char('/')
|
||||||
+ propagator()->account()->davPath() + propagator()->_remoteFolder + _item->_file);
|
+ _propagator->account()->davPath() + _propagator->_remoteFolder + _item->_file);
|
||||||
auto headers = PropagateUploadFileCommon::headers();
|
auto headers = PropagateUploadFileCommon::headers();
|
||||||
|
|
||||||
// "If-Match applies to the source, but we are interested in comparing the etag of the destination
|
// "If-Match applies to the source, but we are interested in comparing the etag of the destination
|
||||||
@@ -292,18 +282,18 @@ void PropagateUploadFileNG::startNextChunk()
|
|||||||
_transmissionChecksumType, _transmissionChecksum);
|
_transmissionChecksumType, _transmissionChecksum);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto job = new MoveJob(propagator()->account(), Utility::concatUrlPath(chunkUrl(), "/.file"),
|
auto job = new MoveJob(_propagator->account(), Utility::concatUrlPath(chunkUrl(), "/.file"),
|
||||||
destination, headers, this);
|
destination, headers, this);
|
||||||
_jobs.append(job);
|
_jobs.append(job);
|
||||||
connect(job, SIGNAL(finishedSignal()), this, SLOT(slotMoveJobFinished()));
|
connect(job, SIGNAL(finishedSignal()), this, SLOT(slotMoveJobFinished()));
|
||||||
connect(job, SIGNAL(destroyed(QObject*)), this, SLOT(slotJobDestroyed(QObject*)));
|
connect(job, SIGNAL(destroyed(QObject*)), this, SLOT(slotJobDestroyed(QObject*)));
|
||||||
propagator()->_activeJobList.append(this);
|
_propagator->_activeJobList.append(this);
|
||||||
job->start();
|
job->start();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto device = new UploadDevice(&propagator()->_bandwidthManager);
|
auto device = new UploadDevice(&_propagator->_bandwidthManager);
|
||||||
const QString fileName = propagator()->getFilePath(_item->_file);
|
const QString fileName = _propagator->getFilePath(_item->_file);
|
||||||
|
|
||||||
if (! device->prepareAndOpen(fileName, _sent, currentChunkSize)) {
|
if (! device->prepareAndOpen(fileName, _sent, currentChunkSize)) {
|
||||||
qDebug() << "ERR: Could not prepare upload device: " << device->errorString();
|
qDebug() << "ERR: Could not prepare upload device: " << device->errorString();
|
||||||
@@ -311,7 +301,7 @@ void PropagateUploadFileNG::startNextChunk()
|
|||||||
// If the file is currently locked, we want to retry the sync
|
// If the file is currently locked, we want to retry the sync
|
||||||
// when it becomes available again.
|
// when it becomes available again.
|
||||||
if (FileSystem::isFileLocked(fileName)) {
|
if (FileSystem::isFileLocked(fileName)) {
|
||||||
emit propagator()->seenLockedFile(fileName);
|
emit _propagator->seenLockedFile(fileName);
|
||||||
}
|
}
|
||||||
// Soft error because this is likely caused by the user modifying his files while syncing
|
// Soft error because this is likely caused by the user modifying his files while syncing
|
||||||
abortWithError( SyncFileItem::SoftError, device->errorString() );
|
abortWithError( SyncFileItem::SoftError, device->errorString() );
|
||||||
@@ -325,7 +315,7 @@ void PropagateUploadFileNG::startNextChunk()
|
|||||||
QUrl url = chunkUrl(_currentChunk);
|
QUrl url = chunkUrl(_currentChunk);
|
||||||
|
|
||||||
// job takes ownership of device via a QScopedPointer. Job deletes itself when finishing
|
// job takes ownership of device via a QScopedPointer. Job deletes itself when finishing
|
||||||
PUTFileJob* job = new PUTFileJob(propagator()->account(), url, device, headers, _currentChunk, this);
|
PUTFileJob* job = new PUTFileJob(_propagator->account(), url, device, headers, _currentChunk, this);
|
||||||
_jobs.append(job);
|
_jobs.append(job);
|
||||||
connect(job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
|
connect(job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
|
||||||
connect(job, SIGNAL(uploadProgress(qint64,qint64)),
|
connect(job, SIGNAL(uploadProgress(qint64,qint64)),
|
||||||
@@ -334,7 +324,7 @@ void PropagateUploadFileNG::startNextChunk()
|
|||||||
device, SLOT(slotJobUploadProgress(qint64,qint64)));
|
device, SLOT(slotJobUploadProgress(qint64,qint64)));
|
||||||
connect(job, SIGNAL(destroyed(QObject*)), this, SLOT(slotJobDestroyed(QObject*)));
|
connect(job, SIGNAL(destroyed(QObject*)), this, SLOT(slotJobDestroyed(QObject*)));
|
||||||
job->start();
|
job->start();
|
||||||
propagator()->_activeJobList.append(this);
|
_propagator->_activeJobList.append(this);
|
||||||
_currentChunk++;
|
_currentChunk++;
|
||||||
|
|
||||||
// FIXME! parallel chunk?
|
// FIXME! parallel chunk?
|
||||||
@@ -344,8 +334,7 @@ void PropagateUploadFileNG::startNextChunk()
|
|||||||
void PropagateUploadFileNG::slotPutFinished()
|
void PropagateUploadFileNG::slotPutFinished()
|
||||||
{
|
{
|
||||||
PUTFileJob *job = qobject_cast<PUTFileJob *>(sender());
|
PUTFileJob *job = qobject_cast<PUTFileJob *>(sender());
|
||||||
ASSERT(job);
|
Q_ASSERT(job);
|
||||||
|
|
||||||
slotJobDestroyed(job); // remove it from the _jobs list
|
slotJobDestroyed(job); // remove it from the _jobs list
|
||||||
|
|
||||||
qDebug() << job->reply()->request().url() << "FINISHED WITH STATUS"
|
qDebug() << job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||||
@@ -354,7 +343,7 @@ void PropagateUploadFileNG::slotPutFinished()
|
|||||||
<< job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute)
|
<< job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute)
|
||||||
<< job->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute);
|
<< job->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute);
|
||||||
|
|
||||||
propagator()->_activeJobList.removeOne(this);
|
_propagator->_activeJobList.removeOne(this);
|
||||||
|
|
||||||
if (_finished) {
|
if (_finished) {
|
||||||
// We have sent the finished signal already. We don't need to handle any remaining jobs
|
// We have sent the finished signal already. We don't need to handle any remaining jobs
|
||||||
@@ -368,7 +357,7 @@ void PropagateUploadFileNG::slotPutFinished()
|
|||||||
// Abort the job and try again later.
|
// Abort the job and try again later.
|
||||||
// This works around a bug in QNAM wich might reuse a non-empty buffer for the next request.
|
// This works around a bug in QNAM wich might reuse a non-empty buffer for the next request.
|
||||||
qDebug() << "Forcing job abort on HTTP connection reset with Qt < 5.4.2.";
|
qDebug() << "Forcing job abort on HTTP connection reset with Qt < 5.4.2.";
|
||||||
propagator()->_anotherSyncNeeded = true;
|
_propagator->_anotherSyncNeeded = true;
|
||||||
abortWithError(SyncFileItem::SoftError, tr("Forcing job abort on HTTP connection reset with Qt < 5.4.2."));
|
abortWithError(SyncFileItem::SoftError, tr("Forcing job abort on HTTP connection reset with Qt < 5.4.2."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -384,32 +373,37 @@ void PropagateUploadFileNG::slotPutFinished()
|
|||||||
errorString = job->reply()->rawHeader("OC-ErrorString");
|
errorString = job->reply()->rawHeader("OC-ErrorString");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure errors that should eventually reset the chunked upload are tracked.
|
// FIXME! can this happen for the chunks?
|
||||||
checkResettingErrors();
|
if (_item->_httpErrorCode == 412) {
|
||||||
|
// Precondition Failed: Maybe the bad etag is in the database, we need to clear the
|
||||||
|
// parent folder etag so we won't read from DB next sync.
|
||||||
|
_propagator->_journal->avoidReadFromDbOnNextSync(_item->_file);
|
||||||
|
_propagator->_anotherSyncNeeded = true;
|
||||||
|
}
|
||||||
|
|
||||||
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
||||||
&propagator()->_anotherSyncNeeded);
|
&_propagator->_anotherSyncNeeded);
|
||||||
abortWithError(status, errorString);
|
abortWithError(status, errorString);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ENFORCE(_sent <= _item->_size, "can't send more than size");
|
Q_ASSERT(_sent <= _item->_size);
|
||||||
bool finished = _sent == _item->_size;
|
bool finished = _sent == _item->_size;
|
||||||
|
|
||||||
// Check if the file still exists
|
// Check if the file still exists
|
||||||
const QString fullFilePath(propagator()->getFilePath(_item->_file));
|
const QString fullFilePath(_propagator->getFilePath(_item->_file));
|
||||||
if( !FileSystem::fileExists(fullFilePath) ) {
|
if( !FileSystem::fileExists(fullFilePath) ) {
|
||||||
if (!finished) {
|
if (!finished) {
|
||||||
abortWithError(SyncFileItem::SoftError, tr("The local file was removed during sync."));
|
abortWithError(SyncFileItem::SoftError, tr("The local file was removed during sync."));
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
propagator()->_anotherSyncNeeded = true;
|
_propagator->_anotherSyncNeeded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the file changed since discovery.
|
// Check whether the file changed since discovery.
|
||||||
if (! FileSystem::verifyFileUnchanged(fullFilePath, _item->_size, _item->_modtime)) {
|
if (! FileSystem::verifyFileUnchanged(fullFilePath, _item->_size, _item->_modtime)) {
|
||||||
propagator()->_anotherSyncNeeded = true;
|
_propagator->_anotherSyncNeeded = true;
|
||||||
if( !finished ) {
|
if( !finished ) {
|
||||||
abortWithError(SyncFileItem::SoftError, tr("Local file changed during sync."));
|
abortWithError(SyncFileItem::SoftError, tr("Local file changed during sync."));
|
||||||
return;
|
return;
|
||||||
@@ -419,42 +413,24 @@ void PropagateUploadFileNG::slotPutFinished()
|
|||||||
if (!finished) {
|
if (!finished) {
|
||||||
// Deletes an existing blacklist entry on successful chunk upload
|
// Deletes an existing blacklist entry on successful chunk upload
|
||||||
if (_item->_hasBlacklistEntry) {
|
if (_item->_hasBlacklistEntry) {
|
||||||
propagator()->_journal->wipeErrorBlacklistEntry(_item->_file);
|
_propagator->_journal->wipeErrorBlacklistEntry(_item->_file);
|
||||||
_item->_hasBlacklistEntry = false;
|
_item->_hasBlacklistEntry = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the error count on successful chunk upload
|
|
||||||
auto uploadInfo = propagator()->_journal->getUploadInfo(_item->_file);
|
|
||||||
uploadInfo._errorCount = 0;
|
|
||||||
propagator()->_journal->setUploadInfo(_item->_file, uploadInfo);
|
|
||||||
propagator()->_journal->commit("Upload info");
|
|
||||||
}
|
}
|
||||||
startNextChunk();
|
startNextChunk();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PropagateUploadFileNG::slotMoveJobFinished()
|
void PropagateUploadFileNG::slotMoveJobFinished()
|
||||||
{
|
{
|
||||||
propagator()->_activeJobList.removeOne(this);
|
_propagator->_activeJobList.removeOne(this);
|
||||||
auto job = qobject_cast<MoveJob *>(sender());
|
auto job = qobject_cast<MoveJob *>(sender());
|
||||||
slotJobDestroyed(job); // remove it from the _jobs list
|
slotJobDestroyed(job); // remove it from the _jobs list
|
||||||
QNetworkReply::NetworkError err = job->reply()->error();
|
QNetworkReply::NetworkError err = job->reply()->error();
|
||||||
_item->_httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
_item->_httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
if (err != QNetworkReply::NoError) {
|
if (err != QNetworkReply::NoError) {
|
||||||
if (_item->_httpErrorCode == 412) {
|
|
||||||
// Precondition Failed: Either an etag or a checksum mismatch.
|
|
||||||
|
|
||||||
// Maybe the bad etag is in the database, we need to clear the
|
|
||||||
// parent folder etag so we won't read from DB next sync.
|
|
||||||
propagator()->_journal->avoidReadFromDbOnNextSync(_item->_file);
|
|
||||||
propagator()->_anotherSyncNeeded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure errors that should eventually reset the chunked upload are tracked.
|
|
||||||
checkResettingErrors();
|
|
||||||
|
|
||||||
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
SyncFileItem::Status status = classifyError(err, _item->_httpErrorCode,
|
||||||
&propagator()->_anotherSyncNeeded);
|
&_propagator->_anotherSyncNeeded);
|
||||||
QString errorString = errorMessage(job->errorString(), job->reply()->readAll());
|
QString errorString = errorMessage(job->errorString(), job->reply()->readAll());
|
||||||
abortWithError(status, errorString);
|
abortWithError(status, errorString);
|
||||||
return;
|
return;
|
||||||
@@ -485,16 +461,14 @@ void PropagateUploadFileNG::slotMoveJobFinished()
|
|||||||
}
|
}
|
||||||
_item->_responseTimeStamp = job->responseTimestamp();
|
_item->_responseTimeStamp = job->responseTimestamp();
|
||||||
|
|
||||||
#ifdef WITH_TESTING
|
|
||||||
// performance logging
|
// performance logging
|
||||||
quint64 duration = _stopWatch.stop();
|
_item->_requestDuration = _stopWatch.stop();
|
||||||
qDebug() << "*==* duration UPLOAD" << _item->_size
|
qDebug() << "*==* duration UPLOAD" << _item->_size
|
||||||
<< _stopWatch.durationOfLap(QLatin1String("ContentChecksum"))
|
<< _stopWatch.durationOfLap(QLatin1String("ContentChecksum"))
|
||||||
<< _stopWatch.durationOfLap(QLatin1String("TransmissionChecksum"))
|
<< _stopWatch.durationOfLap(QLatin1String("TransmissionChecksum"))
|
||||||
<< duration;
|
<< _item->_requestDuration;
|
||||||
// The job might stay alive for the whole sync, release this tiny bit of memory.
|
// The job might stay alive for the whole sync, release this tiny bit of memory.
|
||||||
_stopWatch.reset();
|
_stopWatch.reset();
|
||||||
#endif
|
|
||||||
finalize();
|
finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário