Comparar commits

..

1 Commits

Autor SHA1 Mensagem Data
Piotr M 43e071aea9 add http2 support 2017-01-12 17:49:05 +01:00
183 arquivos alterados com 11874 adições e 14643 exclusões
+3 -2
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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)
+1 -1
Ver Arquivo
@@ -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 '''
+1 -1
Ver Arquivo
@@ -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
+7 -8
Ver Arquivo
@@ -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"
+2 -1
Ver Arquivo
@@ -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)
+1 -1
Ver Arquivo
@@ -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
+1 -1
Ver Arquivo
@@ -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) {
+1 -1
Ver Arquivo
@@ -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
+2 -2
Ver Arquivo
@@ -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
+7 -5
Ver Arquivo
@@ -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.
+1 -1
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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.
-15
Ver Arquivo
@@ -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
---------------------- ----------------------
+2 -2
Ver Arquivo
@@ -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
-4
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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
+6 -7
Ver Arquivo
@@ -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
+1 -1
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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)
+7 -19
Ver Arquivo
@@ -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());
+1 -3
Ver Arquivo
@@ -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();
+2 -7
Ver Arquivo
@@ -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;
+1 -17
Ver Arquivo
@@ -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);
+3 -3
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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;
+1 -1
Ver Arquivo
@@ -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 );
+20 -42
Ver Arquivo
@@ -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) {
+1 -3
Ver Arquivo
@@ -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();
+6 -9
Ver Arquivo
@@ -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();
} }
+2 -2
Ver Arquivo
@@ -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;
}; };
+2 -20
Ver Arquivo
@@ -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)
+1 -2
Ver Arquivo
@@ -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;
}; };
+25 -19
Ver Arquivo
@@ -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 &amp;Ignored Files</string> <string>Edit &amp;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 &amp;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 &quot;Ask confirmation before syncing folder larger than&quot; ">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
Ver Arquivo
@@ -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;
} }
+1 -2
Ver Arquivo
@@ -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() );
-2
Ver Arquivo
@@ -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));
} }
} }
+10 -5
Ver Arquivo
@@ -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 {
+1 -1
Ver Arquivo
@@ -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:
+54 -70
Ver Arquivo
@@ -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();
} }
} }
+7 -17
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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;
}; };
+7 -7
Ver Arquivo
@@ -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;
+10 -13
Ver Arquivo
@@ -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
+4 -4
Ver Arquivo
@@ -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;
-4
Ver Arquivo
@@ -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"));
+1 -3
Ver Arquivo
@@ -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();
-27
Ver Arquivo
@@ -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 {
-1
Ver Arquivo
@@ -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();
+7 -133
Ver Arquivo
@@ -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&amp;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 &quot;Ask confirmation before syncing folder larger than&quot; ">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&amp;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>
+4 -7
Ver Arquivo
@@ -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&amp;ver Address</string> <string>Server &amp;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);
+1 -4
Ver Arquivo
@@ -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
{ {
-1
Ver Arquivo
@@ -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);
+8
Ver Arquivo
@@ -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());
+3
Ver Arquivo
@@ -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
+6 -10
Ver Arquivo
@@ -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);
} }
-1
Ver Arquivo
@@ -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();
-52
Ver Arquivo
@@ -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
-9
Ver Arquivo
@@ -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;
}
} }
-19
Ver Arquivo
@@ -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;
}; };
+3 -3
Ver Arquivo
@@ -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)
+9 -21
Ver Arquivo
@@ -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);
-2
Ver Arquivo
@@ -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);
+12 -5
Ver Arquivo
@@ -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
+4 -2
Ver Arquivo
@@ -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
+2 -2
Ver Arquivo
@@ -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;
} }
+11 -43
Ver Arquivo
@@ -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('/'));
+5 -17
Ver Arquivo
@@ -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);
}; };
} }
+1 -1
Ver Arquivo
@@ -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());
+1 -1
Ver Arquivo
@@ -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
+1 -1
Ver Arquivo
@@ -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
+52 -59
Ver Arquivo
@@ -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();
+13 -8
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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)
+5 -1
Ver Arquivo
@@ -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);
+40 -40
Ver Arquivo
@@ -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();
+10 -10
Ver Arquivo
@@ -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);
} }
+16 -16
Ver Arquivo
@@ -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;
} }
+23 -23
Ver Arquivo
@@ -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 -52
Ver Arquivo
@@ -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);
} }
+6 -15
Ver Arquivo
@@ -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
+57 -83
Ver Arquivo
@@ -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