mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2026-04-25 21:12:24 +02:00
Compare commits
156 Commits
v1.8.1-bet
...
v1.8.2-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c46713701 | ||
|
|
3754e6c781 | ||
|
|
6401b1cfc3 | ||
|
|
6b9e123816 | ||
|
|
fb2295fcec | ||
|
|
0af2f7e5ed | ||
|
|
1c84d01584 | ||
|
|
3fcce08a22 | ||
|
|
289800c1ba | ||
|
|
49fb37fefc | ||
|
|
9a02a0f3a8 | ||
|
|
4e79093f84 | ||
|
|
d2fff2c3e3 | ||
|
|
8f277e46d6 | ||
|
|
c33d962712 | ||
|
|
3870915118 | ||
|
|
b05ca526a4 | ||
|
|
4e28a24af3 | ||
|
|
aebadfcda2 | ||
|
|
c975954a9a | ||
|
|
dec3bd4a02 | ||
|
|
64ce0cd7a2 | ||
|
|
34593cccb6 | ||
|
|
5b5a636cc1 | ||
|
|
5c6a6529a6 | ||
|
|
68fa190cf7 | ||
|
|
d148464efe | ||
|
|
6a7f2089e8 | ||
|
|
17fe4c3b29 | ||
|
|
dd6c97abb6 | ||
|
|
ddfe3fa7ab | ||
|
|
1f7274c2f2 | ||
|
|
4d87f30434 | ||
|
|
8b371c42b7 | ||
|
|
c7f759fedf | ||
|
|
830daa40d1 | ||
|
|
f016d25b4c | ||
|
|
e18fd62f34 | ||
|
|
3701fbcbfe | ||
|
|
823f9fa0d1 | ||
|
|
67d38bc87b | ||
|
|
b36ff1ed1d | ||
|
|
ec83295b99 | ||
|
|
e36252a845 | ||
|
|
d0d8de9f2f | ||
|
|
9693048f78 | ||
|
|
101d2268ff | ||
|
|
2fcad760b9 | ||
|
|
52eb6c95cf | ||
|
|
35169e3de4 | ||
|
|
650b201b33 | ||
|
|
f595fc2f9c | ||
|
|
06c889630c | ||
|
|
d6dbabfbc4 | ||
|
|
bcae146444 | ||
|
|
8a39748654 | ||
|
|
3556ed416c | ||
|
|
e5e2ce2b22 | ||
|
|
39d103adf7 | ||
|
|
afd1406e61 | ||
|
|
a4c411af99 | ||
|
|
bcc896fb6e | ||
|
|
76166c6252 | ||
|
|
dd5a49bc78 | ||
|
|
cdfafa2180 | ||
|
|
6b16e18eb8 | ||
|
|
c2dacd03a5 | ||
|
|
505dba5b23 | ||
|
|
af5a7063c9 | ||
|
|
9e7779a476 | ||
|
|
625e61516f | ||
|
|
41614ec851 | ||
|
|
4d3a0ed250 | ||
|
|
cac15988f0 | ||
|
|
1e131f4732 | ||
|
|
22c35c4d15 | ||
|
|
9507bb4be6 | ||
|
|
e1c370a9a2 | ||
|
|
b9eafaaf24 | ||
|
|
909368025f | ||
|
|
15bfa46023 | ||
|
|
0359c775e0 | ||
|
|
1053153ec4 | ||
|
|
79ac61684c | ||
|
|
441eca86c4 | ||
|
|
f07d3d069e | ||
|
|
e300e3c744 | ||
|
|
b9df8290c9 | ||
|
|
73e2254a80 | ||
|
|
352c2957b2 | ||
|
|
23b6426dfa | ||
|
|
9ef8658122 | ||
|
|
0a67719f2f | ||
|
|
04d820f9cf | ||
|
|
931dd59844 | ||
|
|
a6500d8068 | ||
|
|
0d5d2c578d | ||
|
|
77679790db | ||
|
|
ee71024496 | ||
|
|
b1f326054f | ||
|
|
bceb40ed80 | ||
|
|
fd684eda52 | ||
|
|
9e3c3353bd | ||
|
|
07ffff3d77 | ||
|
|
9b34427a1c | ||
|
|
5fba476076 | ||
|
|
d63abef718 | ||
|
|
cdba8a7f2f | ||
|
|
21967a130b | ||
|
|
08e78d5d6f | ||
|
|
fe68e1e82c | ||
|
|
25ac3bfdb7 | ||
|
|
4700c604b1 | ||
|
|
356fa737c5 | ||
|
|
520e2eb392 | ||
|
|
e0d2bd4830 | ||
|
|
1dc05f99bf | ||
|
|
b2b176bcd0 | ||
|
|
fde5ccd0df | ||
|
|
d1fe25cc31 | ||
|
|
60c18f75b5 | ||
|
|
c7f3791f3d | ||
|
|
ee9d5e6bf0 | ||
|
|
96fa3a3a1a | ||
|
|
7c4deec800 | ||
|
|
78e82eb920 | ||
|
|
3c91a1ace4 | ||
|
|
3a52db46ad | ||
|
|
137bce6dd0 | ||
|
|
f000e6ce6a | ||
|
|
7c1281dd06 | ||
|
|
60729f2bbd | ||
|
|
0b0ecfcbe4 | ||
|
|
1fe86bced2 | ||
|
|
c6a62a497d | ||
|
|
8be6881093 | ||
|
|
99c8118229 | ||
|
|
6c5ca055c4 | ||
|
|
a6ec8f3090 | ||
|
|
b039c2ce86 | ||
|
|
5a6d286c41 | ||
|
|
ba65187ad3 | ||
|
|
a91f54f0a8 | ||
|
|
d77c1f3e4a | ||
|
|
7390ddbd98 | ||
|
|
32a4b40f0a | ||
|
|
bc1bc2a4f8 | ||
|
|
155c965866 | ||
|
|
6c73f25747 | ||
|
|
2518fd7059 | ||
|
|
56edae6958 | ||
|
|
d8275cd4e1 | ||
|
|
c3dca7a288 | ||
|
|
96ff0076c7 | ||
|
|
8bb4af067a | ||
|
|
df0df76b51 |
@@ -165,13 +165,13 @@ endif()
|
|||||||
find_package(Sphinx)
|
find_package(Sphinx)
|
||||||
find_package(PdfLatex)
|
find_package(PdfLatex)
|
||||||
|
|
||||||
|
|
||||||
find_package(SQLite3 3.8.0 REQUIRED)
|
find_package(SQLite3 3.8.0 REQUIRED)
|
||||||
# On some OS, we want to use our own, not the system sqlite
|
# On some OS, we want to use our own, not the system sqlite
|
||||||
if (USE_OUR_OWN_SQLITE3)
|
if (USE_OUR_OWN_SQLITE3)
|
||||||
include_directories(BEFORE ${SQLITE3_INCLUDE_DIR})
|
include_directories(BEFORE ${SQLITE3_INCLUDE_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
find_package(ZLIB)
|
||||||
|
|
||||||
configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||||
|
|
||||||
|
|||||||
79
ChangeLog
79
ChangeLog
@@ -1,6 +1,83 @@
|
|||||||
ChangeLog
|
ChangeLog
|
||||||
=========
|
=========
|
||||||
version 1.8.0 (release 2015-03-xx)
|
version 1.8.2 (release 2015-05-xx)
|
||||||
|
* HTTP: Add the branding name to the UserAgent string.
|
||||||
|
* ConnectonValidator: Always run with new credentials. (#3266)
|
||||||
|
* Recall Feature: Admins can trigger an upload of a file from
|
||||||
|
client to server again
|
||||||
|
* Propagator: Add 'Content-Length: 0' header to MKCOL request
|
||||||
|
* Switch on checksum verification through branding or config
|
||||||
|
* Add ability for checksum verification of up and download
|
||||||
|
* Fix opening external links for some labels (#3135)
|
||||||
|
* AccountState: Run only a single validator, allow error message
|
||||||
|
overriding (#3236 #3153)
|
||||||
|
* SyncJournalDB: Minor fixes and simplificatons
|
||||||
|
* SyncEngine: Force re-read of folder Etags for upgrades from
|
||||||
|
1.8.0 and 1.8.1
|
||||||
|
* Propagator: Limit length of temporary file name #2789
|
||||||
|
* ShareDialog: Password ui fixes. #3189
|
||||||
|
* Fix startup hang by removing QSettings lock file. (#3175)
|
||||||
|
* Wizard: Allow SSL cert dialog to show twice. (#3168)
|
||||||
|
* ProtocolWidget: Fix rename message. (#3210)
|
||||||
|
* Discovery: Test better, treat invalid hrefs as error (#3176)
|
||||||
|
* Propagator: Overwrite local data only if unchanged. (#3156)
|
||||||
|
* ShareDialog: Improve error reporting for share API fails
|
||||||
|
* OSX Updater: Only allow if in /Applications (#2931)
|
||||||
|
* Wizard: Fix lock icon (#1447)
|
||||||
|
* Fix compile with gcc 5
|
||||||
|
* Treat any 503 error as temporary (#3113)
|
||||||
|
* Work around for the Qt PUT corruption bug (#2425)
|
||||||
|
* OSX Shell integration: Optimizations
|
||||||
|
* Windows Shell integration: Optimizations
|
||||||
|
.. more than 250 commits since 1.8.1
|
||||||
|
|
||||||
|
version 1.8.1 (release 2015-05-07)
|
||||||
|
* Make "operation canceled" error a soft error
|
||||||
|
* Do not throw an error for files that are scheduled to be removed,
|
||||||
|
but can not be found on the server. #2919
|
||||||
|
* Windows: Reset QNAM to proper function after hibernation. #2899 #2895 #2973
|
||||||
|
* Fix argument verification of --confdir #2453
|
||||||
|
* Fix a crash when accessing a dangling UploadDevice pointer #2984
|
||||||
|
* Add-folder wizard: Make sure there is a scrollbar if folder names
|
||||||
|
are too long #2962
|
||||||
|
* Add-folder Wizard: Select the newly created folder
|
||||||
|
* Activity: Correctly restore column sizes #3005
|
||||||
|
* SSL Button: do not crash on empty certificate chain
|
||||||
|
* SSL Button: Make menu creation lazy #3007 #2990
|
||||||
|
* Lookup system proxy async to avoid hangs #2993 #2802
|
||||||
|
* ShareDialog: Some GUI refinements
|
||||||
|
* ShareDialog: On creation of a share always retrieve the share
|
||||||
|
This makes sure that if a default expiration date is set this is reflected
|
||||||
|
in the dialog. #2889
|
||||||
|
* ShareDialog: Only show share dialog if we are connected.
|
||||||
|
* HttpCreds: Fill pw dialog with previous password. #2848 #2879
|
||||||
|
* HttpCreds: Delete password from old location. #2186
|
||||||
|
* Do not store Session Cookies in the client cookie storage
|
||||||
|
* CookieJar: Don't accidentally overwrite cookies. #2808
|
||||||
|
* ProtocolWidget: Always add seconds to the DateTime locale. #2535
|
||||||
|
* Updater: Give context as to which app is about to be updated #3040
|
||||||
|
* Windows: Add version information for owncloud.exe. This should help us know
|
||||||
|
what version or build number a crash report was generated with.
|
||||||
|
* Fix a crash on shutdown in ~SocketApi #3057
|
||||||
|
* SyncEngine: Show more timing measurements #3064
|
||||||
|
* Discovery: Add warning if returned etag is 0
|
||||||
|
* Fix a crash caused by an invalid DiscoveryDirectoryResult::iterator #3051
|
||||||
|
* Sync: Fix sync of deletions during 503. #2894
|
||||||
|
* Handle redirect of auth request. #3082
|
||||||
|
* Discovery: Fix parsing of broken XML replies, which fixes local file disappearing #3102
|
||||||
|
* Migration: Silently restore files that were deleted locally by bug #3102
|
||||||
|
* Sort folder sizes SelectiveSyncTreeView numerically #3112
|
||||||
|
* Sync: PropagateDownload: Read the mtime from the file system after writing it #3103
|
||||||
|
* Sync: Propagate download: Fix restoring files for which the conflict file exists #3106
|
||||||
|
* Use identical User Agents and version for csync and the Qt parts
|
||||||
|
* Prevent another crash in ~SocketApi #3118
|
||||||
|
* Windows: Fix rename of finished file. #3073
|
||||||
|
* AccountWizard: Fix auth error handling. #3155
|
||||||
|
* Documentation fixes
|
||||||
|
* Infrastructure/build fixes
|
||||||
|
* Win32/OS X: Apply patch from OpenSSL to handle oudated intermediates gracefully #3087
|
||||||
|
|
||||||
|
version 1.8.0 (release 2015-03-17)
|
||||||
* Mac OS: HIDPI support
|
* Mac OS: HIDPI support
|
||||||
* Support Sharing from desktop: Added a share dialog that can be
|
* Support Sharing from desktop: Added a share dialog that can be
|
||||||
opened by context menu in the file managers (Win, Mac, Nautilus)
|
opened by context menu in the file managers (Win, Mac, Nautilus)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
set( MIRALL_VERSION_MAJOR 1 )
|
set( MIRALL_VERSION_MAJOR 1 )
|
||||||
set( MIRALL_VERSION_MINOR 8 )
|
set( MIRALL_VERSION_MINOR 8 )
|
||||||
set( MIRALL_VERSION_PATCH 1 )
|
set( MIRALL_VERSION_PATCH 2 )
|
||||||
set( MIRALL_SOVERSION 0 )
|
set( MIRALL_SOVERSION 0 )
|
||||||
|
|
||||||
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ if [ ! -z "$identity" ]; then
|
|||||||
echo "Will try to sign the installer"
|
echo "Will try to sign the installer"
|
||||||
pushd $install_path
|
pushd $install_path
|
||||||
productsign --sign "$identity" "$installer_file" "$installer_file.new"
|
productsign --sign "$identity" "$installer_file" "$installer_file.new"
|
||||||
mv "$installer_file".new $installer_file
|
mv "$installer_file".new "$installer_file"
|
||||||
popd
|
popd
|
||||||
else
|
else
|
||||||
echo "No certificate given, will not sign the pkg"
|
echo "No certificate given, will not sign the pkg"
|
||||||
|
|||||||
@@ -260,12 +260,18 @@ def CopyFramework(path):
|
|||||||
commands.append(args)
|
commands.append(args)
|
||||||
args = ['chmod', 'u+w', os.path.join(full_path, parts[-1])]
|
args = ['chmod', 'u+w', os.path.join(full_path, parts[-1])]
|
||||||
commands.append(args)
|
commands.append(args)
|
||||||
args = ['chmod', 'u+w', os.path.join(frameworks_dir, framework, "Resources")]
|
resources_dir = os.path.join(frameworks_dir, framework, "Resources")
|
||||||
|
|
||||||
|
args = ['mkdir', resources_dir]
|
||||||
|
commands.append(args)
|
||||||
|
args = ['chmod', 'u+w', resources_dir]
|
||||||
commands.append(args)
|
commands.append(args)
|
||||||
|
|
||||||
info_plist = os.path.join(os.path.split(path)[0], '..', '..', 'Contents', 'Info.plist')
|
info_plist = os.path.join(os.path.split(path)[0], '..', '..', 'Contents', 'Info.plist')
|
||||||
|
if not os.path.exists(info_plist):
|
||||||
|
info_plist = os.path.join(os.path.split(path)[0], 'Resources', 'Info.plist')
|
||||||
if os.path.exists(info_plist):
|
if os.path.exists(info_plist):
|
||||||
args = ['cp', '-r', info_plist, os.path.join(frameworks_dir, framework, "Resources")]
|
args = ['cp', '-r', info_plist, resources_dir]
|
||||||
commands.append(args)
|
commands.append(args)
|
||||||
return os.path.join(full_path, parts[-1])
|
return os.path.join(full_path, parts[-1])
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh -x
|
#!/bin/sh -xe
|
||||||
|
|
||||||
[ "$#" -lt 2 ] && echo "Usage: sign_app.sh <app> <identity>" && exit
|
[ "$#" -lt 2 ] && echo "Usage: sign_app.sh <app> <identity>" && exit
|
||||||
|
|
||||||
@@ -7,6 +7,6 @@ identity="$2"
|
|||||||
|
|
||||||
codesign -s "$identity" --force --verbose=4 --deep "$src_app"
|
codesign -s "$identity" --force --verbose=4 --deep "$src_app"
|
||||||
|
|
||||||
# Just for our debug purposes:
|
# Verify the signature
|
||||||
spctl -a -t exec -vv $src_app
|
spctl -a -t exec -vv $src_app
|
||||||
codesign -dv $src_app
|
codesign -dv $src_app
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ StrCpy $UNINSTALL_ABORT "A desinstalaci
|
|||||||
StrCpy $INIT_NO_QUICK_LAUNCH "Acceso de inicio rápido (n/d)"
|
StrCpy $INIT_NO_QUICK_LAUNCH "Acceso de inicio rápido (n/d)"
|
||||||
StrCpy $INIT_NO_DESKTOP "Atallo no escritorio (sobrescribe o existente)"
|
StrCpy $INIT_NO_DESKTOP "Atallo no escritorio (sobrescribe o existente)"
|
||||||
StrCpy $UAC_ERROR_ELEVATE "Non foi posíbel elevalo, erro:"
|
StrCpy $UAC_ERROR_ELEVATE "Non foi posíbel elevalo, erro:"
|
||||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Este instalador require acceso de administrador, tenteo de novo"
|
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Este instalador require acceso de administrador, ténteo de novo"
|
||||||
StrCpy $INIT_INSTALLER_RUNNING "O instalador xa está en execución."
|
StrCpy $INIT_INSTALLER_RUNNING "O instalador xa está en execución."
|
||||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Este desinstalador require acceso de administrador, tenteo de novo"
|
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Este desinstalador require acceso de administrador, ténteo de novo"
|
||||||
StrCpy $INIT_UNINSTALLER_RUNNING "O desinstalador xa está en execución."
|
StrCpy $INIT_UNINSTALLER_RUNNING "O desinstalador xa está en execución."
|
||||||
StrCpy $SectionGroup_Shortcuts "Atallos"
|
StrCpy $SectionGroup_Shortcuts "Atallos"
|
||||||
|
|||||||
2
binary
2
binary
Submodule binary updated: 1fb9ddfa9a...8b72648a93
@@ -17,6 +17,7 @@ if( Qt5Core_FOUND )
|
|||||||
message(STATUS "Found Qt5 core, checking for further dependencies...")
|
message(STATUS "Found Qt5 core, checking for further dependencies...")
|
||||||
find_package(Qt5Network REQUIRED)
|
find_package(Qt5Network REQUIRED)
|
||||||
find_package(Qt5Xml REQUIRED)
|
find_package(Qt5Xml REQUIRED)
|
||||||
|
find_package(Qt5Concurrent REQUIRED)
|
||||||
if(NOT TOKEN_AUTH_ONLY)
|
if(NOT TOKEN_AUTH_ONLY)
|
||||||
find_package(Qt5WebKitWidgets REQUIRED)
|
find_package(Qt5WebKitWidgets REQUIRED)
|
||||||
find_package(Qt5WebKit REQUIRED)
|
find_package(Qt5WebKit REQUIRED)
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
#cmakedefine APPLICATION_EXECUTABLE "@APPLICATION_EXECUTABLE@"
|
#cmakedefine APPLICATION_EXECUTABLE "@APPLICATION_EXECUTABLE@"
|
||||||
#cmakedefine APPLICATION_UPDATE_URL "@APPLICATION_UPDATE_URL@"
|
#cmakedefine APPLICATION_UPDATE_URL "@APPLICATION_UPDATE_URL@"
|
||||||
|
|
||||||
|
#cmakedefine ZLIB_FOUND @ZLIB_FOUND@
|
||||||
|
|
||||||
#cmakedefine SYSCONFDIR "@SYSCONFDIR@"
|
#cmakedefine SYSCONFDIR "@SYSCONFDIR@"
|
||||||
#cmakedefine DATADIR "@DATADIR@"
|
#cmakedefine DATADIR "@DATADIR@"
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,7 @@
|
|||||||
# global needed variables
|
# global needed variables
|
||||||
set(APPLICATION_NAME "ocsync")
|
set(APPLICATION_NAME "ocsync")
|
||||||
|
|
||||||
set(APPLICATION_VERSION_MAJOR "0")
|
set(LIBRARY_VERSION ${MIRALL_VERSION})
|
||||||
set(APPLICATION_VERSION_MINOR "91")
|
|
||||||
set(APPLICATION_VERSION_PATCH "5")
|
|
||||||
|
|
||||||
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}")
|
|
||||||
|
|
||||||
set(LIBRARY_VERSION "0.2.1")
|
|
||||||
set(LIBRARY_SOVERSION "0")
|
set(LIBRARY_SOVERSION "0")
|
||||||
|
|
||||||
# add definitions
|
# add definitions
|
||||||
|
|||||||
@@ -386,6 +386,20 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
|
|||||||
SAFE_FREE(renamed_path);
|
SAFE_FREE(renamed_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!other_node) {
|
||||||
|
/* Check the source path as well. */
|
||||||
|
int len;
|
||||||
|
uint64_t h = 0;
|
||||||
|
char *renamed_path = csync_rename_adjust_path_source(ctx, cur->path);
|
||||||
|
|
||||||
|
if (!c_streq(renamed_path, cur->path)) {
|
||||||
|
len = strlen( renamed_path );
|
||||||
|
h = c_jhash64((uint8_t *) renamed_path, len, 0);
|
||||||
|
other_node = c_rbtree_find(other_tree, &h);
|
||||||
|
}
|
||||||
|
SAFE_FREE(renamed_path);
|
||||||
|
}
|
||||||
|
|
||||||
if (obj == NULL || data == NULL) {
|
if (obj == NULL || data == NULL) {
|
||||||
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
|
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -40,8 +40,6 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <config_csync.h>
|
#include <config_csync.h>
|
||||||
|
|
||||||
#include "csync_version.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -233,6 +233,7 @@ CSYNC_EXCLUDE_TYPE csync_excluded_no_ctx(c_strlist_t *excludes, const char *path
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check the strlen and ignore the file if its name is longer than 254 chars.
|
// check the strlen and ignore the file if its name is longer than 254 chars.
|
||||||
|
// whenever changing this also check createDownloadTmpFileName
|
||||||
if (strlen(bname) > 254) {
|
if (strlen(bname) > 254) {
|
||||||
match = CSYNC_FILE_EXCLUDE_LONG_FILENAME;
|
match = CSYNC_FILE_EXCLUDE_LONG_FILENAME;
|
||||||
SAFE_FREE(bname);
|
SAFE_FREE(bname);
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ enum csync_log_priority_e {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define CSYNC_LOG(priority, ...) \
|
#define CSYNC_LOG(priority, ...) \
|
||||||
csync_log(priority, __FUNCTION__, __VA_ARGS__)
|
csync_log(priority, __func__, __VA_ARGS__)
|
||||||
|
|
||||||
void csync_log(int verbosity,
|
void csync_log(int verbosity,
|
||||||
const char *function,
|
const char *function,
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
|
|
||||||
#include "csync_private.h"
|
#include "csync_private.h"
|
||||||
|
|
||||||
|
#include "csync_version.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* helper method to build up a user text for SSL problems, called from the
|
* helper method to build up a user text for SSL problems, called from the
|
||||||
@@ -437,8 +439,8 @@ int dav_connect(CSYNC *csyncCtx, const char *base_url) {
|
|||||||
// Should never take more than some seconds, 30 is really a max.
|
// Should never take more than some seconds, 30 is really a max.
|
||||||
ne_set_connect_timeout(ctx->dav_session.ctx, 30);
|
ne_set_connect_timeout(ctx->dav_session.ctx, 30);
|
||||||
|
|
||||||
snprintf( uaBuf, sizeof(uaBuf), "Mozilla/5.0 (%s) csyncoC/%s",
|
snprintf( uaBuf, sizeof(uaBuf), "Mozilla/5.0 (%s) mirall/%s (csyncoC)",
|
||||||
csync_owncloud_get_platform(), CSYNC_STRINGIFY( LIBCSYNC_VERSION ));
|
CSYNC_STRINGIFY( MIRALL_VERSION ), csync_owncloud_get_platform() );
|
||||||
ne_set_useragent( ctx->dav_session.ctx, uaBuf);
|
ne_set_useragent( ctx->dav_session.ctx, uaBuf);
|
||||||
ne_set_server_auth(ctx->dav_session.ctx, authentication_callback_by_neon, ctx);
|
ne_set_server_auth(ctx->dav_session.ctx, authentication_callback_by_neon, ctx);
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ struct csync_rename_s {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, std::string> folder_renamed_to; // map from->to
|
std::map<std::string, std::string> folder_renamed_to; // map from->to
|
||||||
|
std::map<std::string, std::string> folder_renamed_from; // map to->from
|
||||||
|
|
||||||
struct renameop {
|
struct renameop {
|
||||||
csync_file_stat_t *st;
|
csync_file_stat_t *st;
|
||||||
@@ -63,6 +64,7 @@ void csync_rename_destroy(CSYNC* ctx)
|
|||||||
void csync_rename_record(CSYNC* ctx, const char* from, const char* to)
|
void csync_rename_record(CSYNC* ctx, const char* from, const char* to)
|
||||||
{
|
{
|
||||||
csync_rename_s::get(ctx)->folder_renamed_to[from] = to;
|
csync_rename_s::get(ctx)->folder_renamed_to[from] = to;
|
||||||
|
csync_rename_s::get(ctx)->folder_renamed_from[to] = from;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* csync_rename_adjust_path(CSYNC* ctx, const char* path)
|
char* csync_rename_adjust_path(CSYNC* ctx, const char* path)
|
||||||
@@ -78,4 +80,18 @@ char* csync_rename_adjust_path(CSYNC* ctx, const char* path)
|
|||||||
return c_strdup(path);
|
return c_strdup(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* csync_rename_adjust_path_source(CSYNC* ctx, const char* path)
|
||||||
|
{
|
||||||
|
csync_rename_s* d = csync_rename_s::get(ctx);
|
||||||
|
for (std::string p = _parentDir(path); !p.empty(); p = _parentDir(p)) {
|
||||||
|
std::map< std::string, std::string >::iterator it = d->folder_renamed_from.find(p);
|
||||||
|
if (it != d->folder_renamed_from.end()) {
|
||||||
|
std::string rep = it->second + (path + p.length());
|
||||||
|
return c_strdup(rep.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c_strdup(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,10 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Return the final destination path of a given patch in case of renames */
|
||||||
char *csync_rename_adjust_path(CSYNC *ctx, const char *path);
|
char *csync_rename_adjust_path(CSYNC *ctx, const char *path);
|
||||||
|
/* Return the source of a given path in case of renames */
|
||||||
|
char *csync_rename_adjust_path_source(CSYNC *ctx, const char *path);
|
||||||
void csync_rename_destroy(CSYNC *ctx);
|
void csync_rename_destroy(CSYNC *ctx);
|
||||||
void csync_rename_record(CSYNC *ctx, const char *from, const char *to);
|
void csync_rename_record(CSYNC *ctx, const char *from, const char *to);
|
||||||
|
|
||||||
|
|||||||
@@ -28,22 +28,7 @@ extern "C" {
|
|||||||
#define CSYNC_STRINGIFY(s) CSYNC_TOSTRING(s)
|
#define CSYNC_STRINGIFY(s) CSYNC_TOSTRING(s)
|
||||||
#define CSYNC_TOSTRING(s) #s
|
#define CSYNC_TOSTRING(s) #s
|
||||||
|
|
||||||
/* csync version macros */
|
#define MIRALL_VERSION @MIRALL_VERSION@
|
||||||
#define CSYNC_VERSION_INT(a, b, c) ((a) << 16 | (b) << 8 | (c))
|
|
||||||
#define CSYNC_VERSION_DOT(a, b, c) a ##.## b ##.## c
|
|
||||||
#define CSYNC_VERSION(a, b, c) CSYNC_VERSION_DOT(a, b, c)
|
|
||||||
|
|
||||||
/* csync version */
|
|
||||||
#define LIBCSYNC_VERSION_MAJOR @APPLICATION_VERSION_MAJOR@
|
|
||||||
#define LIBCSYNC_VERSION_MINOR @APPLICATION_VERSION_MINOR@
|
|
||||||
#define LIBCSYNC_VERSION_MICRO @APPLICATION_VERSION_PATCH@
|
|
||||||
|
|
||||||
#define LIBCSYNC_VERSION_INT CSYNC_VERSION_INT(LIBCSYNC_VERSION_MAJOR, \
|
|
||||||
LIBCSYNC_VERSION_MINOR, \
|
|
||||||
LIBCSYNC_VERSION_MICRO)
|
|
||||||
#define LIBCSYNC_VERSION CSYNC_VERSION(LIBCSYNC_VERSION_MAJOR, \
|
|
||||||
LIBCSYNC_VERSION_MINOR, \
|
|
||||||
LIBCSYNC_VERSION_MICRO)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
#define DEBUG_HBF(...) { if(transfer->log_cb) { \
|
#define DEBUG_HBF(...) { if(transfer->log_cb) { \
|
||||||
char buf[1024]; \
|
char buf[1024]; \
|
||||||
snprintf(buf, 1024, __VA_ARGS__); \
|
snprintf(buf, 1024, __VA_ARGS__); \
|
||||||
transfer->log_cb(__FUNCTION__, buf, transfer->user_data); \
|
transfer->log_cb(__func__, buf, transfer->user_data); \
|
||||||
} }
|
} }
|
||||||
|
|
||||||
// #endif
|
// #endif
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ static void check_logging(void **state)
|
|||||||
rc = csync_set_log_callback(check_log_callback);
|
rc = csync_set_log_callback(check_log_callback);
|
||||||
assert_int_equal(rc, 0);
|
assert_int_equal(rc, 0);
|
||||||
|
|
||||||
csync_log(1, __FUNCTION__, "rc = %d", rc);
|
csync_log(1, __func__, "rc = %d", rc);
|
||||||
|
|
||||||
rc = _tstat(path, &sb);
|
rc = _tstat(path, &sb);
|
||||||
|
|
||||||
|
|||||||
@@ -124,7 +124,8 @@ sub initTesting(;$)
|
|||||||
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0
|
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
$d = HTTP::DAV->new();
|
my $ua = HTTP::DAV::UserAgent->new(keep_alive => 1 );
|
||||||
|
$d = HTTP::DAV->new(-useragent => $ua);
|
||||||
|
|
||||||
$d->credentials( -url=> $owncloud, -realm=>"ownCloud",
|
$d->credentials( -url=> $owncloud, -realm=>"ownCloud",
|
||||||
-user=> $user,
|
-user=> $user,
|
||||||
@@ -191,7 +192,6 @@ sub removeRemoteDir($;$)
|
|||||||
my ($dir, $optionsRef) = @_;
|
my ($dir, $optionsRef) = @_;
|
||||||
|
|
||||||
my $url = testDirUrl() . $dir;
|
my $url = testDirUrl() . $dir;
|
||||||
|
|
||||||
if( $optionsRef && $optionsRef->{user} && $optionsRef->{passwd} ) {
|
if( $optionsRef && $optionsRef->{user} && $optionsRef->{passwd} ) {
|
||||||
$d->credentials( -url=> $owncloud, -realm=>"ownCloud",
|
$d->credentials( -url=> $owncloud, -realm=>"ownCloud",
|
||||||
-user=> $optionsRef->{user},
|
-user=> $optionsRef->{user},
|
||||||
@@ -326,11 +326,11 @@ sub assertLocalDirs( $$ )
|
|||||||
|
|
||||||
opendir(my $dh, $dir1 ) || die;
|
opendir(my $dh, $dir1 ) || die;
|
||||||
while(readdir $dh) {
|
while(readdir $dh) {
|
||||||
assert( -e "$dir2/$_" );
|
assert( -e "$dir2/$_", " $dir2/$_ do not exist" );
|
||||||
next if( -d "$dir1/$_"); # don't compare directory sizes.
|
next if( -d "$dir1/$_"); # don't compare directory sizes.
|
||||||
my $s1 = -s "$dir1/$_";
|
my $s1 = -s "$dir1/$_";
|
||||||
my $s2 = -s "$dir2/$_";
|
my $s2 = -s "$dir2/$_";
|
||||||
assert( $s1 == $s2, "$dir1/$_ <-> $dir2/$_" );
|
assert( $s1 == $s2, "$dir1/$_ <-> $dir2/$_ size not equal ($s1 != $s2)" );
|
||||||
}
|
}
|
||||||
closedir $dh;
|
closedir $dh;
|
||||||
}
|
}
|
||||||
@@ -524,7 +524,9 @@ sub put_to_dir( $$;$ )
|
|||||||
|
|
||||||
my $filename = $file;
|
my $filename = $file;
|
||||||
$filename =~ s/^.*\///;
|
$filename =~ s/^.*\///;
|
||||||
|
$filename =~ s/#/%23/g; # poor man's URI encoder
|
||||||
my $puturl = $targetUrl . $dir. $filename;
|
my $puturl = $targetUrl . $dir. $filename;
|
||||||
|
|
||||||
print "put_to_dir puts to $puturl\n";
|
print "put_to_dir puts to $puturl\n";
|
||||||
unless ($d->put( -local => $file, -url => $puturl )) {
|
unless ($d->put( -local => $file, -url => $puturl )) {
|
||||||
print " ### FAILED to put a single file!\n";
|
print " ### FAILED to put a single file!\n";
|
||||||
|
|||||||
85
csync/tests/ownCloud/t_recall.pl
Executable file
85
csync/tests/ownCloud/t_recall.pl
Executable file
@@ -0,0 +1,85 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
#
|
||||||
|
# Test script for the ownCloud module of csync.
|
||||||
|
# This script requires a running ownCloud instance accessible via HTTP.
|
||||||
|
# It does quite some fancy tests and asserts the results.
|
||||||
|
#
|
||||||
|
# Copyright (C) by Olivier Goffart <ogoffart@woboq.com>
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
#
|
||||||
|
|
||||||
|
use lib ".";
|
||||||
|
|
||||||
|
|
||||||
|
use File::Copy;
|
||||||
|
use ownCloud::Test;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
print "Hello, this is t_recall, a tester for the recall feature\n";
|
||||||
|
|
||||||
|
initTesting();
|
||||||
|
|
||||||
|
printInfo( "Syncing two files with the same name that differ with case" );
|
||||||
|
|
||||||
|
#create some files
|
||||||
|
my $tmpdir = "/tmp/t_recall/";
|
||||||
|
mkdir($tmpdir);
|
||||||
|
createLocalFile( $tmpdir . "file1.dat", 100 );
|
||||||
|
createLocalFile( $tmpdir . "file2.dat", 150 );
|
||||||
|
createLocalFile( $tmpdir . "file3.dat", 110 );
|
||||||
|
createLocalFile( $tmpdir . "file4.dat", 170 );
|
||||||
|
|
||||||
|
#put them in some directories
|
||||||
|
createRemoteDir( "dir" );
|
||||||
|
glob_put( "$tmpdir/*", "dir" );
|
||||||
|
|
||||||
|
csync();
|
||||||
|
|
||||||
|
assertLocalAndRemoteDir( '', 0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
printInfo( "Testing with a .sys.admin#recall#" );
|
||||||
|
system("echo 'dir/file2.dat' > ". $tmpdir . ".sys.admin\#recall\#");
|
||||||
|
system("echo 'dir/file3.dat' >> ". $tmpdir . ".sys.admin\#recall\#");
|
||||||
|
glob_put( "$tmpdir/.sys.admin\#recall\#", "" );
|
||||||
|
|
||||||
|
csync();
|
||||||
|
|
||||||
|
#test that the recall files have been created
|
||||||
|
assert( -e glob(localDir().'dir/file2_.sys.admin#recall#-*.dat' ) );
|
||||||
|
assert( -e glob(localDir().'dir/file3_.sys.admin#recall#-*.dat' ) );
|
||||||
|
|
||||||
|
#Remove the recall file
|
||||||
|
unlink(localDir() . ".sys.admin#recall#");
|
||||||
|
|
||||||
|
# 2 sync necessary for the recall to be uploaded
|
||||||
|
csync();
|
||||||
|
|
||||||
|
assertLocalAndRemoteDir( '', 0);
|
||||||
|
|
||||||
|
printInfo( "Testing with a dir/.sys.admin#recall#" );
|
||||||
|
system("echo 'file4.dat' > ". $tmpdir . ".sys.admin\#recall\#");
|
||||||
|
glob_put( "$tmpdir/.sys.admin\#recall\#", "dir" );
|
||||||
|
|
||||||
|
csync();
|
||||||
|
assert( -e glob(localDir().'dir/file4_.sys.admin#recall#-*.dat' ) );
|
||||||
|
|
||||||
|
|
||||||
|
cleanup();
|
||||||
|
system("rm -r " . $tmpdir);
|
||||||
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
==============
|
||||||
Advanced Usage
|
Advanced Usage
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
=====================
|
||||||
The Automatic Updater
|
The Automatic Updater
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
@@ -9,11 +10,15 @@ users only need to use their normal package managers. However, on Linux systems
|
|||||||
the Updater will check for updates and notify you when a new version is
|
the Updater will check for updates and notify you when a new version is
|
||||||
available.
|
available.
|
||||||
|
|
||||||
|
.. note:: Because of various technical issues, desktop sync clients older than
|
||||||
|
1.7 will not be allowed to connect and sync with the ownCloud 8.1 server. It is
|
||||||
|
highly recommended to keep your client updated.
|
||||||
|
|
||||||
Basic Workflow
|
Basic Workflow
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
The following sections describe how to use the Automatic Updater on different
|
The following sections describe how to use the Automatic Updater on different
|
||||||
operating systems:
|
operating systems.
|
||||||
|
|
||||||
Windows
|
Windows
|
||||||
^^^^^^^
|
^^^^^^^
|
||||||
@@ -26,6 +31,9 @@ If an update is available, and has been successfully downloaded, the ownCloud
|
|||||||
client starts a silent update prior to its next launch and then restarts
|
client starts a silent update prior to its next launch and then restarts
|
||||||
itself. Should the silent update fail, the client offers a manual download.
|
itself. Should the silent update fail, the client offers a manual download.
|
||||||
|
|
||||||
|
When you upgrade from 1.7 you should restart Windows to ensure that all the new
|
||||||
|
features in 1.8 are enabled.
|
||||||
|
|
||||||
.. note:: Administrative privileges are required to perform the update.
|
.. note:: Administrative privileges are required to perform the update.
|
||||||
|
|
||||||
Mac OS X
|
Mac OS X
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ including:
|
|||||||
and Nautilus on Linux.
|
and Nautilus on Linux.
|
||||||
* Faster uploads and downloads.
|
* Faster uploads and downloads.
|
||||||
|
|
||||||
|
.. note:: When you upgrade from 1.7, restart Windows to ensure that all new
|
||||||
|
features are visible.
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|||||||
@@ -11,3 +11,6 @@ Desktop Sync client enables you to:
|
|||||||
Your files are always automatically synchronized between your ownCloud server
|
Your files are always automatically synchronized between your ownCloud server
|
||||||
and local PC.
|
and local PC.
|
||||||
|
|
||||||
|
.. note:: Because of various technical issues, desktop sync clients older than
|
||||||
|
1.7 will not allowed to connect and sync with the ownCloud 8.1 server. It is
|
||||||
|
highly recommended to keep your client updated.
|
||||||
|
|||||||
@@ -1,23 +1,28 @@
|
|||||||
When invoking the client from the command line, the following options are supported:
|
You have the option of starting your ownCloud desktop client with the
|
||||||
|
``owncloud`` command. The following options are supported:
|
||||||
|
|
||||||
``-h``, ``--help``
|
``owncloud -h`` or ``owncloud --help``
|
||||||
Displays all command options.
|
Displays all command options.
|
||||||
|
|
||||||
|
The other options are:
|
||||||
|
|
||||||
``--logwindow``
|
``--logwindow``
|
||||||
Opens a window displaying log output.
|
Opens a window displaying log output.
|
||||||
|
|
||||||
``--logfile`` `<filename>`
|
``--logfile`` `<filename>`
|
||||||
Write log output to the file specified. To write to stdout, specify `-` as the filename.
|
Write log output to the file specified. To write to stdout, specify `-`
|
||||||
|
as the filename.
|
||||||
|
|
||||||
``--logdir`` `<name>`
|
``--logdir`` `<name>`
|
||||||
Writes each synchronization log output in a new file in the specified directory.
|
Writes each synchronization log output in a new file in the specified
|
||||||
|
directory.
|
||||||
|
|
||||||
``--logexpire`` `<hours>`
|
``--logexpire`` `<hours>`
|
||||||
Removes logs older than the value specified (in hours). This command is used with ``--logdir``.
|
Removes logs older than the value specified (in hours). This command is
|
||||||
|
used with ``--logdir``.
|
||||||
|
|
||||||
``--logflush``
|
``--logflush``
|
||||||
Clears (flushes) the log file after each write action.
|
Clears (flushes) the log file after each write action.
|
||||||
|
|
||||||
``--confdir`` `<dirname>`
|
``--confdir`` `<dirname>`
|
||||||
Uses the specified configuration directory.
|
Uses the specified configuration directory.
|
||||||
|
|
||||||
@@ -1,16 +1,14 @@
|
|||||||
The ownCloud Client packages contain a command line client that can be used to
|
The ownCloud Client packages contain a command line client, ``owncloudcmd``, that can
|
||||||
synchronize ownCloud files to client machines. The command line client is
|
be used to synchronize ownCloud files to client machines.
|
||||||
called ``owncloudcmd``.
|
|
||||||
|
|
||||||
owncloudcmd performs a single *sync run* and then exits the synchronization
|
``owncloudcmd`` performs a single *sync run* and then exits the synchronization
|
||||||
process. In this manner, owncloudcmd processes the differences between client
|
process. In this manner, ``owncloudcmd`` processes the differences between
|
||||||
and server directories and propagates the files to bring both repositories to
|
client and server directories and propagates the files to bring both
|
||||||
the same state. Contrary to the GUI-based client, ``owncloudcmd`` does not
|
repositories to the same state. Contrary to the GUI-based client,
|
||||||
repeat
|
``owncloudcmd`` does not repeat synchronizations on its own. It also does not
|
||||||
synchronizations on its own. It also does not monitor for file system changes.
|
monitor for file system changes.
|
||||||
|
|
||||||
To invoke ``owncloudcmd``, you must provide the local and the remote
|
To invoke ``owncloudcmd``, you must provide the local and the remote repository
|
||||||
repository
|
|
||||||
URL using the following command::
|
URL using the following command::
|
||||||
|
|
||||||
owncloudcmd [OPTIONS...] sourcedir owncloudurl
|
owncloudcmd [OPTIONS...] sourcedir owncloudurl
|
||||||
@@ -18,45 +16,41 @@ URL using the following command::
|
|||||||
where ``sourcedir`` is the local directory and ``owncloudurl`` is
|
where ``sourcedir`` is the local directory and ``owncloudurl`` is
|
||||||
the server URL.
|
the server URL.
|
||||||
|
|
||||||
.. note:: Prior to the 1.6 version of owncloudcmd, the tool only accepted
|
Other command line switches supported by ``owncloudcmd`` include the following:
|
||||||
``owncloud://`` or ``ownclouds://`` in place of ``http://`` and ``https://`` as
|
|
||||||
a scheme. See ``Examples`` for details.
|
|
||||||
|
|
||||||
Other comand line switches supported by owncloudcmd include the following:
|
|
||||||
|
|
||||||
``--user``, ``-u`` ``[user]``
|
``--user``, ``-u`` ``[user]``
|
||||||
Use ``user`` as the login name.
|
Specify the user's login name.
|
||||||
|
|
||||||
``--password``, ``-p`` ``[password]``
|
``--password``, ``-p`` ``[password]``
|
||||||
Use ``password`` as the password.
|
Specify the user's password.
|
||||||
|
|
||||||
``-n``
|
``-n``
|
||||||
Use ``netrc (5)`` for login.
|
Use ``netrc (5)`` for login.
|
||||||
|
|
||||||
``--non-interactive``
|
``--non-interactive``
|
||||||
Do not prompt for questions.
|
Do not prompt for questions.
|
||||||
|
|
||||||
``--silent``, ``-s``
|
``--silent``, ``-s``
|
||||||
Inhibits verbose log output.
|
Inhibits verbose log output.
|
||||||
|
|
||||||
``--trust``
|
``--trust``
|
||||||
Trust any SSL certificate, including invalid ones.
|
Trust any SSL certificate, including invalid ones.
|
||||||
|
|
||||||
``--httpproxy http://[user@pass:]<server>:<port>``
|
``--httpproxy http://[user@pass:]<server>:<port>``
|
||||||
Uses the specified ``server`` as the HTTP proxy.
|
Uses the specified ``server`` as the HTTP proxy.
|
||||||
|
|
||||||
|
``--unsyncedfolders [file]``
|
||||||
|
File containing list of folders to not sync
|
||||||
|
|
||||||
Credential Handling
|
Credential Handling
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
By default, ``owncloudcmd`` reads the client configuration and uses the
|
By default, ``owncloudcmd`` reads the client configuration and uses the
|
||||||
credentials of the GUI synchronization client. If no client is configured, or if you choose
|
credentials of the GUI synchronization client. If no client is configured, or if
|
||||||
to use a different user to synchronize, you can specify the user password
|
you choose to use a different user to synchronize, you can specify the user
|
||||||
setting with the usual URL pattern. For example::
|
password setting with the usual URL pattern. For example::
|
||||||
|
|
||||||
https://user:secret@192.168.178.2/remote.php/webdav
|
$ owncloudcmd / https://carla:secret@server/owncloud/remote.php/webdav/
|
||||||
|
|
||||||
Example
|
|
||||||
~~~~~~~
|
|
||||||
|
|
||||||
To synchronize the ownCloud directory ``Music`` to the local directory
|
To synchronize the ownCloud directory ``Music`` to the local directory
|
||||||
``media/music``, through a proxy listening on port ``8080``, and on a gateway
|
``media/music``, through a proxy listening on port ``8080``, and on a gateway
|
||||||
@@ -66,13 +60,5 @@ machine using IP address ``192.168.178.1``, the command line would be::
|
|||||||
$HOME/media/music \
|
$HOME/media/music \
|
||||||
https://server/owncloud/remote.php/webdav/Music
|
https://server/owncloud/remote.php/webdav/Music
|
||||||
|
|
||||||
``owncloudcmd`` will enquire user name and password, unless they have
|
``owncloudcmd`` will prompt for the user name and password, unless they have
|
||||||
been specified on the command line or ``-n`` has been passed.
|
been specified on the command line or ``-n`` has been passed.
|
||||||
|
|
||||||
Using the legacy scheme, the command line would be::
|
|
||||||
|
|
||||||
$ owncloudcmd --httpproxy http://192.168.178.1:8080 \
|
|
||||||
$HOME/media/music \
|
|
||||||
ownclouds://server/owncloud/remote.php/webdav/Music
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
@interface ContentManager : NSObject
|
@interface ContentManager : NSObject
|
||||||
{
|
{
|
||||||
NSMutableDictionary* _fileNamesCache;
|
NSMutableDictionary* _fileNamesCache;
|
||||||
|
NSMutableDictionary* _oldFileNamesCache;
|
||||||
BOOL _fileIconsEnabled;
|
BOOL _fileIconsEnabled;
|
||||||
BOOL _hasChangedContent;
|
BOOL _hasChangedContent;
|
||||||
|
|
||||||
@@ -35,10 +36,9 @@
|
|||||||
- (void)enableFileIcons:(BOOL)enable;
|
- (void)enableFileIcons:(BOOL)enable;
|
||||||
- (NSNumber*)iconByPath:(NSString*)path isDirectory:(BOOL)isDir;
|
- (NSNumber*)iconByPath:(NSString*)path isDirectory:(BOOL)isDir;
|
||||||
- (void)removeAllIcons;
|
- (void)removeAllIcons;
|
||||||
- (void)removeIcons:(NSArray*)paths;
|
|
||||||
- (void)setIcons:(NSDictionary*)iconDictionary filterByFolder:(NSString*)filterFolder;
|
- (void)setIcons:(NSDictionary*)iconDictionary filterByFolder:(NSString*)filterFolder;
|
||||||
- (void)setResultForPath:(NSString*)path result:(NSString*)result;
|
- (void)setResultForPath:(NSString*)path result:(NSString*)result;
|
||||||
- (void)clearFileNameCacheForPath:(NSString*)path;
|
- (void)clearFileNameCache;
|
||||||
- (void)reFetchFileNameCacheForPath:(NSString*)path;
|
- (void)reFetchFileNameCacheForPath:(NSString*)path;
|
||||||
- (void)repaintAllWindows;
|
- (void)repaintAllWindows;
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ static ContentManager* sharedInstance = nil;
|
|||||||
if (self)
|
if (self)
|
||||||
{
|
{
|
||||||
_fileNamesCache = [[NSMutableDictionary alloc] init];
|
_fileNamesCache = [[NSMutableDictionary alloc] init];
|
||||||
|
_oldFileNamesCache = [[NSMutableDictionary alloc] init];
|
||||||
_fileIconsEnabled = TRUE;
|
_fileIconsEnabled = TRUE;
|
||||||
_hasChangedContent = TRUE;
|
_hasChangedContent = TRUE;
|
||||||
}
|
}
|
||||||
@@ -41,6 +42,7 @@ static ContentManager* sharedInstance = nil;
|
|||||||
{
|
{
|
||||||
[self removeAllIcons];
|
[self removeAllIcons];
|
||||||
[_fileNamesCache release];
|
[_fileNamesCache release];
|
||||||
|
[_oldFileNamesCache release];
|
||||||
sharedInstance = nil;
|
sharedInstance = nil;
|
||||||
|
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
@@ -148,84 +150,48 @@ static ContentManager* sharedInstance = nil;
|
|||||||
|
|
||||||
if( result == nil ) {
|
if( result == nil ) {
|
||||||
// start the async call
|
// start the async call
|
||||||
NSNumber *askState = [[RequestManager sharedInstance] askForIcon:normalizedPath isDirectory:isDir];
|
[[RequestManager sharedInstance] askForIcon:normalizedPath isDirectory:isDir];
|
||||||
[_fileNamesCache setObject:askState forKey:normalizedPath];
|
|
||||||
|
|
||||||
result = [NSNumber numberWithInt:0];
|
result = [NSNumber numberWithInt:0];
|
||||||
} else if( [result intValue] == -1 ) {
|
// Set 0 into the cache, meaning "don't have an icon, but already requested it"
|
||||||
// the socket call is underways.
|
[_fileNamesCache setObject:result forKey:normalizedPath];
|
||||||
result = [NSNumber numberWithInt:0];
|
|
||||||
} else {
|
|
||||||
// there is a proper icon index
|
|
||||||
}
|
}
|
||||||
// NSLog(@"iconByPath return value %d", [result intValue]);
|
if ([result intValue] == 0) {
|
||||||
|
// Show the old state while we wait for the new one
|
||||||
|
NSNumber* oldResult = [_oldFileNamesCache objectForKey:normalizedPath];
|
||||||
|
if (oldResult)
|
||||||
|
result = oldResult;
|
||||||
|
}
|
||||||
|
// NSLog(@"iconByPath return value %d", [result intValue]);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// called as a result of an UPDATE_VIEW message.
|
// Clears the entries from the hash to make it call again home to the desktop client.
|
||||||
// it clears the entries from the hash to make it call again home to the desktop client.
|
- (void)clearFileNameCache
|
||||||
- (void)clearFileNameCacheForPath:(NSString*)path
|
|
||||||
{
|
{
|
||||||
//NSLog(@"%@", NSStringFromSelector(_cmd));
|
[_fileNamesCache release];
|
||||||
NSMutableArray *keysToDelete = [NSMutableArray array];
|
_fileNamesCache = [[NSMutableDictionary alloc] init];
|
||||||
|
[_oldFileNamesCache removeAllObjects];
|
||||||
if( path != nil ) {
|
|
||||||
for (id p in [_fileNamesCache keyEnumerator]) {
|
|
||||||
//do stuff with obj
|
|
||||||
if ( [p hasPrefix:path] ) {
|
|
||||||
[keysToDelete addObject:p];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// clear the entire fileNameCache
|
|
||||||
[_fileNamesCache release];
|
|
||||||
_fileNamesCache = [[NSMutableDictionary alloc] init];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( [keysToDelete count] > 0 ) {
|
|
||||||
NSLog( @"Entries to delete: %lu", (unsigned long)[keysToDelete count]);
|
|
||||||
[_fileNamesCache removeObjectsForKeys:keysToDelete];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)reFetchFileNameCacheForPath:(NSString*)path
|
- (void)reFetchFileNameCacheForPath:(NSString*)path
|
||||||
{
|
{
|
||||||
NSLog(@"%@", NSStringFromSelector(_cmd));
|
//NSLog(@"%@", NSStringFromSelector(_cmd));
|
||||||
|
|
||||||
for (id p in [_fileNamesCache keyEnumerator]) {
|
// We won't request the new state if if finds the path in _fileNamesCache
|
||||||
if ( path && [p hasPrefix:path] ) {
|
// Move all entries to _oldFileNamesCache so that the get re-requested, but
|
||||||
[[RequestManager sharedInstance] askForIcon:p isDirectory:false]; // FIXME isDirectory parameter
|
// still available while we refill the cache
|
||||||
//[_fileNamesCache setObject:askState forKey:p]; We don't do this since we want to keep the old icon meanwhile
|
[_oldFileNamesCache addEntriesFromDictionary:_fileNamesCache];
|
||||||
//NSLog(@"%@ %@", NSStringFromSelector(_cmd), p);
|
[_fileNamesCache removeAllObjects];
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ask for directory itself
|
[self repaintAllWindows];
|
||||||
if ([path hasSuffix:@"/"]) {
|
|
||||||
path = [path substringToIndex:path.length - 1];
|
|
||||||
}
|
|
||||||
[[RequestManager sharedInstance] askForIcon:path isDirectory:true];
|
|
||||||
//NSLog(@"%@ %@", NSStringFromSelector(_cmd), path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)removeAllIcons
|
- (void)removeAllIcons
|
||||||
{
|
{
|
||||||
[_fileNamesCache removeAllObjects];
|
[_fileNamesCache removeAllObjects];
|
||||||
|
[_oldFileNamesCache removeAllObjects];
|
||||||
[self repaintAllWindows];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)removeIcons:(NSArray*)paths
|
|
||||||
{
|
|
||||||
for (NSString* path in paths)
|
|
||||||
{
|
|
||||||
NSString* normalizedPath = [path decomposedStringWithCanonicalMapping];
|
|
||||||
|
|
||||||
[_fileNamesCache removeObjectForKey:normalizedPath];
|
|
||||||
}
|
|
||||||
|
|
||||||
[self repaintAllWindows];
|
[self repaintAllWindows];
|
||||||
}
|
}
|
||||||
@@ -361,6 +327,7 @@ static ContentManager* sharedInstance = nil;
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
[_oldFileNamesCache removeObjectForKey:normalizedPath];
|
||||||
[_fileNamesCache setObject:iconId forKey:normalizedPath];
|
[_fileNamesCache setObject:iconId forKey:normalizedPath];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
NSMutableArray* _requestQueue;
|
NSMutableArray* _requestQueue;
|
||||||
NSMutableDictionary* _registeredPathes;
|
NSMutableDictionary* _registeredPathes;
|
||||||
|
NSMutableSet* _requestedPaths;
|
||||||
|
|
||||||
NSString *_shareMenuTitle;
|
NSString *_shareMenuTitle;
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@
|
|||||||
|
|
||||||
- (BOOL)isRegisteredPath:(NSString*)path isDirectory:(BOOL)isDir;
|
- (BOOL)isRegisteredPath:(NSString*)path isDirectory:(BOOL)isDir;
|
||||||
- (void)askOnSocket:(NSString*)path query:(NSString*)verb;
|
- (void)askOnSocket:(NSString*)path query:(NSString*)verb;
|
||||||
- (NSNumber*)askForIcon:(NSString*)path isDirectory:(BOOL)isDir;
|
- (void)askForIcon:(NSString*)path isDirectory:(BOOL)isDir;
|
||||||
- (void)menuItemClicked:(NSDictionary*)actionDictionary;
|
- (void)menuItemClicked:(NSDictionary*)actionDictionary;
|
||||||
- (void)start;
|
- (void)start;
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ static RequestManager* sharedInstance = nil;
|
|||||||
_isConnected = NO;
|
_isConnected = NO;
|
||||||
|
|
||||||
_registeredPathes = [[NSMutableDictionary alloc] init];
|
_registeredPathes = [[NSMutableDictionary alloc] init];
|
||||||
|
_requestedPaths = [[NSMutableSet alloc] init];
|
||||||
|
|
||||||
_shareMenuTitle = nil;
|
_shareMenuTitle = nil;
|
||||||
|
|
||||||
@@ -101,28 +102,23 @@ static RequestManager* sharedInstance = nil;
|
|||||||
return registered;
|
return registered;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSNumber*)askForIcon:(NSString*)path isDirectory:(BOOL)isDir
|
- (void)askForIcon:(NSString*)path isDirectory:(BOOL)isDir
|
||||||
{
|
{
|
||||||
NSString *verb = @"RETRIEVE_FILE_STATUS";
|
NSString *verb = @"RETRIEVE_FILE_STATUS";
|
||||||
NSNumber *res = [NSNumber numberWithInt:0];
|
|
||||||
|
|
||||||
if( [self isRegisteredPath:path isDirectory:isDir] ) {
|
if( [self isRegisteredPath:path isDirectory:isDir] ) {
|
||||||
|
[_requestedPaths addObject:path];
|
||||||
if( _isConnected ) {
|
if( _isConnected ) {
|
||||||
if(isDir) {
|
if(isDir) {
|
||||||
verb = @"RETRIEVE_FOLDER_STATUS";
|
verb = @"RETRIEVE_FOLDER_STATUS";
|
||||||
}
|
}
|
||||||
|
|
||||||
[self askOnSocket:path query:verb];
|
[self askOnSocket:path query:verb];
|
||||||
|
|
||||||
NSNumber *res_minus_one = [NSNumber numberWithInt:0];
|
|
||||||
|
|
||||||
return res_minus_one;
|
|
||||||
} else {
|
} else {
|
||||||
[_requestQueue addObject:path];
|
[_requestQueue addObject:path];
|
||||||
[self start]; // try again to connect
|
[self start]; // try again to connect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -147,9 +143,13 @@ static RequestManager* sharedInstance = nil;
|
|||||||
path, [chunks objectAtIndex:i+1] ];
|
path, [chunks objectAtIndex:i+1] ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[contentman setResultForPath:path result:[chunks objectAtIndex:1]];
|
// The client will broadcast all changes, do not fill the cache for paths that Finder didn't ask for.
|
||||||
|
if ([_requestedPaths containsObject:path]) {
|
||||||
|
[contentman setResultForPath:path result:[chunks objectAtIndex:1]];
|
||||||
|
}
|
||||||
} else if( [[chunks objectAtIndex:0] isEqualToString:@"UPDATE_VIEW"] ) {
|
} else if( [[chunks objectAtIndex:0] isEqualToString:@"UPDATE_VIEW"] ) {
|
||||||
NSString *path = [chunks objectAtIndex:1];
|
NSString *path = [chunks objectAtIndex:1];
|
||||||
|
[_requestedPaths removeAllObjects];
|
||||||
[contentman reFetchFileNameCacheForPath:path];
|
[contentman reFetchFileNameCacheForPath:path];
|
||||||
} else if( [[chunks objectAtIndex:0 ] isEqualToString:@"REGISTER_PATH"] ) {
|
} else if( [[chunks objectAtIndex:0 ] isEqualToString:@"REGISTER_PATH"] ) {
|
||||||
NSNumber *one = [NSNumber numberWithInt:1];
|
NSNumber *one = [NSNumber numberWithInt:1];
|
||||||
@@ -198,10 +198,11 @@ static RequestManager* sharedInstance = nil;
|
|||||||
for( NSString *path in _requestQueue ) {
|
for( NSString *path in _requestQueue ) {
|
||||||
[self askOnSocket:path query:@"RETRIEVE_FILE_STATUS"];
|
[self askOnSocket:path query:@"RETRIEVE_FILE_STATUS"];
|
||||||
}
|
}
|
||||||
|
[_requestQueue removeAllObjects];
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentManager *contentman = [ContentManager sharedInstance];
|
ContentManager *contentman = [ContentManager sharedInstance];
|
||||||
[contentman clearFileNameCacheForPath:nil];
|
[contentman clearFileNameCache];
|
||||||
[contentman repaintAllWindows];
|
[contentman repaintAllWindows];
|
||||||
|
|
||||||
// Read for the UPDATE_VIEW requests
|
// Read for the UPDATE_VIEW requests
|
||||||
@@ -218,10 +219,11 @@ static RequestManager* sharedInstance = nil;
|
|||||||
// clear the registered pathes.
|
// clear the registered pathes.
|
||||||
[_registeredPathes release];
|
[_registeredPathes release];
|
||||||
_registeredPathes = [[NSMutableDictionary alloc] init];
|
_registeredPathes = [[NSMutableDictionary alloc] init];
|
||||||
|
[_requestedPaths removeAllObjects];
|
||||||
|
|
||||||
// clear the caches in conent manager
|
// clear the caches in conent manager
|
||||||
ContentManager *contentman = [ContentManager sharedInstance];
|
ContentManager *contentman = [ContentManager sharedInstance];
|
||||||
[contentman clearFileNameCacheForPath:nil];
|
[contentman clearFileNameCache];
|
||||||
[contentman repaintAllWindows];
|
[contentman repaintAllWindows];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# osascript $HOME/owncloud.com/client/shell_integration/MacOSX/unload.scpt
|
SELFPATH=`dirname $0`
|
||||||
|
# osascript $SELFPATH/unload.scpt
|
||||||
|
|
||||||
sudo rm -rf /Library/ScriptingAdditions/SyncStateFinder.osax
|
sudo rm -rf /Library/ScriptingAdditions/SyncStateFinder.osax
|
||||||
# Klaas' machine
|
# Klaas' machine
|
||||||
@@ -12,6 +13,6 @@ OSAXDIR=$HOME/Library/Developer/Xcode/DerivedData/OwnCloud-*/Build/Products/Debu
|
|||||||
|
|
||||||
sudo killall Finder
|
sudo killall Finder
|
||||||
sleep 1
|
sleep 1
|
||||||
osascript $HOME/owncloud.com/client/shell_integration/MacOSX/load.scpt
|
osascript $SELFPATH/load.scpt
|
||||||
osascript $HOME/owncloud.com/client/shell_integration/MacOSX/check.scpt
|
osascript $SELFPATH/check.scpt
|
||||||
|
|
||||||
|
|||||||
@@ -98,6 +98,8 @@ void RemotePathChecker::workerThreadLoop()
|
|||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Assume that we won't need this at this point, UNREGISTER_PATH is rare
|
||||||
|
_oldCache.clear();
|
||||||
}
|
}
|
||||||
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"STATUS:")) ||
|
} else if (StringUtil::begins_with(response, wstring(L"STATUS:")) ||
|
||||||
@@ -115,13 +117,16 @@ void RemotePathChecker::workerThreadLoop()
|
|||||||
auto responseStatus = response.substr(statusBegin+1, statusEnd - statusBegin-1);
|
auto responseStatus = response.substr(statusBegin+1, statusEnd - statusBegin-1);
|
||||||
auto responsePath = response.substr(statusEnd+1);
|
auto responsePath = response.substr(statusEnd+1);
|
||||||
auto state = _StrToFileState(responseStatus);
|
auto state = _StrToFileState(responseStatus);
|
||||||
auto erased = asked.erase(responsePath);
|
bool wasAsked = asked.erase(responsePath) > 0;
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
{ std::unique_lock<std::mutex> lock(_mutex);
|
{ std::unique_lock<std::mutex> lock(_mutex);
|
||||||
auto &it = _cache[responsePath];
|
bool wasCached = _cache.find(responsePath) != _cache.end();
|
||||||
changed = (it != state);
|
if (wasAsked || wasCached) {
|
||||||
it = state;
|
auto &it = _cache[responsePath];
|
||||||
|
changed = (it != state);
|
||||||
|
it = state;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (changed) {
|
if (changed) {
|
||||||
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
|
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
|
||||||
@@ -129,20 +134,25 @@ void RemotePathChecker::workerThreadLoop()
|
|||||||
}
|
}
|
||||||
else if (StringUtil::begins_with(response, wstring(L"UPDATE_VIEW"))) {
|
else if (StringUtil::begins_with(response, wstring(L"UPDATE_VIEW"))) {
|
||||||
std::unique_lock<std::mutex> lock(_mutex);
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
auto cache = _cache; // Make a copy of the cache under the mutex
|
// 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.
|
||||||
|
std::unordered_map<std::wstring, FileState> cache;
|
||||||
|
swap(cache, _cache);
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
// Request a status for all the items in the cache.
|
// 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) {
|
||||||
if (!socket.SendMsg(wstring(L"RETRIEVE_FILE_STATUS:" + it->first + L'\n').data())) {
|
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, it->first.data(), NULL);
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (socket.Event() == INVALID_HANDLE_VALUE) {
|
if (socket.Event() == INVALID_HANDLE_VALUE) {
|
||||||
std::unique_lock<std::mutex> lock(_mutex);
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
_cache.clear();
|
_cache.clear();
|
||||||
|
_oldCache.clear();
|
||||||
_watchedDirectories.clear();
|
_watchedDirectories.clear();
|
||||||
_connected = connected = false;
|
_connected = connected = false;
|
||||||
}
|
}
|
||||||
@@ -195,11 +205,17 @@ bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state)
|
|||||||
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)
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ 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;
|
||||||
|
std::unordered_map<std::wstring, FileState> _oldCache;
|
||||||
std::vector<std::wstring> _watchedDirectories;
|
std::vector<std::wstring> _watchedDirectories;
|
||||||
bool _connected;
|
bool _connected;
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "qtlocalpeer.h"
|
#include "qtlocalpeer.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
#include <QDataStream>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
|
|||||||
@@ -28,9 +28,6 @@ public:
|
|||||||
* @return the list of migrated folder definitions
|
* @return the list of migrated folder definitions
|
||||||
*/
|
*/
|
||||||
QStringList migrateFolderDefinitons();
|
QStringList migrateFolderDefinitons();
|
||||||
signals:
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ void AccountSettings::slotAddFolder( Folder *folder )
|
|||||||
if( ! folder || folder->alias().isEmpty() ) return;
|
if( ! folder || folder->alias().isEmpty() ) return;
|
||||||
|
|
||||||
QStandardItem *item = new QStandardItem();
|
QStandardItem *item = new QStandardItem();
|
||||||
folderToModelItem( item, folder, _accountState && _accountState->isConnectedOrMaintenance());
|
folderToModelItem( item, folder, _accountState && _accountState->isConnectedOrTemporarilyUnavailable());
|
||||||
_model->appendRow( item );
|
_model->appendRow( item );
|
||||||
// in order to update the enabled state of the "Sync now" button
|
// in order to update the enabled state of the "Sync now" button
|
||||||
connect(folder, SIGNAL(syncStateChange()), this, SLOT(slotFolderSyncStateChange()), Qt::UniqueConnection);
|
connect(folder, SIGNAL(syncStateChange()), this, SLOT(slotFolderSyncStateChange()), Qt::UniqueConnection);
|
||||||
@@ -537,7 +537,7 @@ void AccountSettings::slotUpdateFolderState( Folder *folder )
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( item ) {
|
if( item ) {
|
||||||
folderToModelItem( item, folder, _accountState->isConnectedOrMaintenance() );
|
folderToModelItem( item, folder, _accountState->isConnectedOrTemporarilyUnavailable() );
|
||||||
} else {
|
} else {
|
||||||
// the dialog is not visible.
|
// the dialog is not visible.
|
||||||
}
|
}
|
||||||
@@ -794,7 +794,7 @@ void AccountSettings::slotAccountStateChanged(int state)
|
|||||||
foreach (Folder *folder, folderMan->map().values()) {
|
foreach (Folder *folder, folderMan->map().values()) {
|
||||||
slotUpdateFolderState(folder);
|
slotUpdateFolderState(folder);
|
||||||
}
|
}
|
||||||
if (state == AccountState::Connected || state == AccountState::ServerMaintenance) {
|
if (state == AccountState::Connected || state == AccountState::ServiceUnavailable) {
|
||||||
QString user;
|
QString user;
|
||||||
if (AbstractCredentials *cred = account->credentials()) {
|
if (AbstractCredentials *cred = account->credentials()) {
|
||||||
user = cred->user();
|
user = cred->user();
|
||||||
|
|||||||
@@ -40,6 +40,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Connected with <server> as <user></string>
|
<string>Connected with <server> as <user></string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
|||||||
@@ -114,9 +114,10 @@ void AccountState::setState(State state)
|
|||||||
} else if (oldState == SignedOut && _state == Disconnected) {
|
} else if (oldState == SignedOut && _state == Disconnected) {
|
||||||
checkConnectivity();
|
checkConnectivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
emit stateChanged(_state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// might not have changed but the underlying _connectionErrors might have
|
||||||
|
emit stateChanged(_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AccountState::stateString(State state)
|
QString AccountState::stateString(State state)
|
||||||
@@ -129,8 +130,8 @@ QString AccountState::stateString(State state)
|
|||||||
return QLatin1String("Disconnected");
|
return QLatin1String("Disconnected");
|
||||||
case Connected:
|
case Connected:
|
||||||
return QLatin1String("Connected");
|
return QLatin1String("Connected");
|
||||||
case ServerMaintenance:
|
case ServiceUnavailable:
|
||||||
return QLatin1String("ServerMaintenance");
|
return QLatin1String("ServiceUnavailable");
|
||||||
case NetworkError:
|
case NetworkError:
|
||||||
return QLatin1String("NetworkError");
|
return QLatin1String("NetworkError");
|
||||||
case ConfigurationError:
|
case ConfigurationError:
|
||||||
@@ -158,9 +159,9 @@ bool AccountState::isConnected() const
|
|||||||
return _state == Connected;
|
return _state == Connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AccountState::isConnectedOrMaintenance() const
|
bool AccountState::isConnectedOrTemporarilyUnavailable() const
|
||||||
{
|
{
|
||||||
return isConnected() || _state == ServerMaintenance;
|
return isConnected() || _state == ServiceUnavailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
QuotaInfo *AccountState::quotaInfo()
|
QuotaInfo *AccountState::quotaInfo()
|
||||||
@@ -174,7 +175,12 @@ void AccountState::checkConnectivity()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_connectionValidator) {
|
||||||
|
qDebug() << "ConnectionValidator already running, ignoring";
|
||||||
|
return;
|
||||||
|
}
|
||||||
ConnectionValidator * conValidator = new ConnectionValidator(account());
|
ConnectionValidator * conValidator = new ConnectionValidator(account());
|
||||||
|
_connectionValidator = conValidator;
|
||||||
connect(conValidator, SIGNAL(connectionResult(ConnectionValidator::Status,QStringList)),
|
connect(conValidator, SIGNAL(connectionResult(ConnectionValidator::Status,QStringList)),
|
||||||
SLOT(slotConnectionValidatorResult(ConnectionValidator::Status,QStringList)));
|
SLOT(slotConnectionValidatorResult(ConnectionValidator::Status,QStringList)));
|
||||||
if (isConnected()) {
|
if (isConnected()) {
|
||||||
@@ -234,8 +240,8 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
|
|||||||
case ConnectionValidator::UserCanceledCredentials:
|
case ConnectionValidator::UserCanceledCredentials:
|
||||||
setState(SignedOut);
|
setState(SignedOut);
|
||||||
break;
|
break;
|
||||||
case ConnectionValidator::ServerMaintenance:
|
case ConnectionValidator::ServiceUnavailable:
|
||||||
setState(ServerMaintenance);
|
setState(ServiceUnavailable);
|
||||||
break;
|
break;
|
||||||
case ConnectionValidator::Timeout:
|
case ConnectionValidator::Timeout:
|
||||||
setState(NetworkError);
|
setState(NetworkError);
|
||||||
@@ -263,6 +269,12 @@ void AccountState::slotCredentialsFetched(AbstractCredentials* credentials)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When new credentials become available we always want to restart the
|
||||||
|
// connection validation, even if it's currently running.
|
||||||
|
if (_connectionValidator) {
|
||||||
|
delete _connectionValidator;
|
||||||
|
}
|
||||||
|
|
||||||
checkConnectivity();
|
checkConnectivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#define ACCOUNTINFO_H
|
#define ACCOUNTINFO_H
|
||||||
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
#include <QPointer>
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "connectionvalidator.h"
|
#include "connectionvalidator.h"
|
||||||
|
|
||||||
@@ -67,9 +68,9 @@ public:
|
|||||||
/// The account is successfully talking to the server.
|
/// The account is successfully talking to the server.
|
||||||
Connected,
|
Connected,
|
||||||
|
|
||||||
/// The account is talking to the server, but the server is in
|
/// There's a temporary problem with talking to the server,
|
||||||
/// maintenance mode.
|
/// don't bother the user too much and try again.
|
||||||
ServerMaintenance,
|
ServiceUnavailable,
|
||||||
|
|
||||||
/// Could not communicate with the server for some reason.
|
/// Could not communicate with the server for some reason.
|
||||||
/// We assume this may resolve itself over time and will try
|
/// We assume this may resolve itself over time and will try
|
||||||
@@ -100,7 +101,7 @@ public:
|
|||||||
void setSignedOut(bool signedOut);
|
void setSignedOut(bool signedOut);
|
||||||
|
|
||||||
bool isConnected() const;
|
bool isConnected() const;
|
||||||
bool isConnectedOrMaintenance() const;
|
bool isConnectedOrTemporarilyUnavailable() const;
|
||||||
|
|
||||||
QuotaInfo *quotaInfo();
|
QuotaInfo *quotaInfo();
|
||||||
|
|
||||||
@@ -128,6 +129,7 @@ private:
|
|||||||
ConnectionStatus _connectionStatus;
|
ConnectionStatus _connectionStatus;
|
||||||
QStringList _connectionErrors;
|
QStringList _connectionErrors;
|
||||||
bool _waitingForNewCredentials;
|
bool _waitingForNewCredentials;
|
||||||
|
QPointer<ConnectionValidator> _connectionValidator;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,6 +110,15 @@ Application::Application(int &argc, char **argv) :
|
|||||||
if (isRunning())
|
if (isRunning())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) && QT_VERSION < QT_VERSION_CHECK(5, 4, 2)
|
||||||
|
// Workaround for QTBUG-44576: Make sure a stale QSettings lock file
|
||||||
|
// is deleted. (Introduced in Qt 5.4.0 and fixed in Qt 5.4.2)
|
||||||
|
{
|
||||||
|
QString lockFilePath = ConfigFile().configFile() + QLatin1String(".lock");
|
||||||
|
QLockFile(lockFilePath).removeStaleLockFile();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(WITH_CRASHREPORTER)
|
#if defined(WITH_CRASHREPORTER)
|
||||||
if (ConfigFile().crashReporter())
|
if (ConfigFile().crashReporter())
|
||||||
_crashHandler.reset(new CrashReporter::Handler( QDir::tempPath(), true, CRASHREPORTER_EXECUTABLE ));
|
_crashHandler.reset(new CrashReporter::Handler( QDir::tempPath(), true, CRASHREPORTER_EXECUTABLE ));
|
||||||
@@ -270,7 +279,7 @@ void Application::slotAccountStateChanged(int state)
|
|||||||
folderMan->setSyncEnabled(true);
|
folderMan->setSyncEnabled(true);
|
||||||
folderMan->slotScheduleAllFolders();
|
folderMan->slotScheduleAllFolders();
|
||||||
break;
|
break;
|
||||||
case AccountState::ServerMaintenance:
|
case AccountState::ServiceUnavailable:
|
||||||
case AccountState::SignedOut:
|
case AccountState::SignedOut:
|
||||||
case AccountState::ConfigurationError:
|
case AccountState::ConfigurationError:
|
||||||
case AccountState::NetworkError:
|
case AccountState::NetworkError:
|
||||||
|
|||||||
@@ -772,6 +772,7 @@ void Folder::startSync(const QStringList &pathList)
|
|||||||
_timeSinceLastSyncStart.restart();
|
_timeSinceLastSyncStart.restart();
|
||||||
_syncResult.clearErrors();
|
_syncResult.clearErrors();
|
||||||
_syncResult.setStatus( SyncResult::SyncPrepare );
|
_syncResult.setStatus( SyncResult::SyncPrepare );
|
||||||
|
_syncResult.setSyncFileItemVector(SyncFileItemVector());
|
||||||
emit syncStateChange();
|
emit syncStateChange();
|
||||||
|
|
||||||
qDebug() << "*** Start syncing - client version"
|
qDebug() << "*** Start syncing - client version"
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ class SelectiveSyncTreeView;
|
|||||||
class ownCloudInfo;
|
class ownCloudInfo;
|
||||||
|
|
||||||
class FormatWarningsWizardPage : public QWizardPage {
|
class FormatWarningsWizardPage : public QWizardPage {
|
||||||
|
Q_OBJECT
|
||||||
protected:
|
protected:
|
||||||
QString formatWarnings(const QStringList &warnings) const;
|
QString formatWarnings(const QStringList &warnings) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ IgnoreListEditor::IgnoreListEditor(QWidget *parent) :
|
|||||||
connect(this, SIGNAL(accepted()), SLOT(slotUpdateLocalIgnoreList()));
|
connect(this, SIGNAL(accepted()), SLOT(slotUpdateLocalIgnoreList()));
|
||||||
ui->removePushButton->setEnabled(false);
|
ui->removePushButton->setEnabled(false);
|
||||||
connect(ui->listWidget, SIGNAL(itemSelectionChanged()), SLOT(slotItemSelectionChanged()));
|
connect(ui->listWidget, SIGNAL(itemSelectionChanged()), SLOT(slotItemSelectionChanged()));
|
||||||
connect(ui->listWidget, SIGNAL(itemActivated(QListWidgetItem*)), SLOT(slotItemChanged(QListWidgetItem*)));
|
|
||||||
connect(ui->removePushButton, SIGNAL(clicked()), SLOT(slotRemoveCurrentItem()));
|
connect(ui->removePushButton, SIGNAL(clicked()), SLOT(slotRemoveCurrentItem()));
|
||||||
connect(ui->addPushButton, SIGNAL(clicked()), SLOT(slotAddPattern()));
|
connect(ui->addPushButton, SIGNAL(clicked()), SLOT(slotAddPattern()));
|
||||||
connect(ui->listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), SLOT(slotEditPattern(QListWidgetItem*)));
|
connect(ui->listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), SLOT(slotEditPattern(QListWidgetItem*)));
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ void ownCloudGui::slotComputeOverallSyncStatus()
|
|||||||
_tray->setToolTip(tr("Please sign in"));
|
_tray->setToolTip(tr("Please sign in"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!a->isConnectedOrMaintenance()) {
|
if (!a->isConnectedOrTemporarilyUnavailable()) {
|
||||||
_tray->setIcon(Theme::instance()->folderOfflineIcon(true));
|
_tray->setIcon(Theme::instance()->folderOfflineIcon(true));
|
||||||
_tray->setToolTip(tr("Disconnected from server"));
|
_tray->setToolTip(tr("Disconnected from server"));
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -189,6 +189,10 @@ void OwncloudSetupWizard::slotNoOwnCloudFoundAuth(QNetworkReply *reply)
|
|||||||
.arg(Theme::instance()->appNameGUI(),
|
.arg(Theme::instance()->appNameGUI(),
|
||||||
reply->url().toString(),
|
reply->url().toString(),
|
||||||
reply->errorString()), checkDowngradeAdvised(reply));
|
reply->errorString()), checkDowngradeAdvised(reply));
|
||||||
|
|
||||||
|
// Allow the credentials dialog to pop up again for the same URL.
|
||||||
|
// Maybe the user just clicked 'Cancel' by accident or changed his mind.
|
||||||
|
_ocWizard->account()->resetSslCertErrorState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OwncloudSetupWizard::slotNoOwnCloudFoundAuthTimeout(const QUrl&url)
|
void OwncloudSetupWizard::slotNoOwnCloudFoundAuthTimeout(const QUrl&url)
|
||||||
@@ -219,7 +223,6 @@ void OwncloudSetupWizard::testOwnCloudConnect()
|
|||||||
job->setProperties(QList<QByteArray>() << "getlastmodified");
|
job->setProperties(QList<QByteArray>() << "getlastmodified");
|
||||||
connect(job, SIGNAL(result(QVariantMap)), _ocWizard, SLOT(successfulStep()));
|
connect(job, SIGNAL(result(QVariantMap)), _ocWizard, SLOT(successfulStep()));
|
||||||
connect(job, SIGNAL(finishedWithError()), this, SLOT(slotAuthError()));
|
connect(job, SIGNAL(finishedWithError()), this, SLOT(slotAuthError()));
|
||||||
connect(job, SIGNAL(networkError(QNetworkReply*)), this, SLOT(slotAuthNetworkError(QNetworkReply*)));
|
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,10 +235,11 @@ void OwncloudSetupWizard::slotAuthError()
|
|||||||
qWarning() << "Can't check for authed redirects. This slot should be invoked from PropfindJob!";
|
qWarning() << "Can't check for authed redirects. This slot should be invoked from PropfindJob!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
QNetworkReply* reply = job->reply();
|
||||||
|
|
||||||
// If there were redirects on the *authed* requests, also store
|
// If there were redirects on the *authed* requests, also store
|
||||||
// the updated server URL, similar to redirects on status.php.
|
// the updated server URL, similar to redirects on status.php.
|
||||||
QUrl redirectUrl = job->reply()->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
|
QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
|
||||||
if (!redirectUrl.isEmpty()) {
|
if (!redirectUrl.isEmpty()) {
|
||||||
qDebug() << "authed request was redirected to" << redirectUrl.toString();
|
qDebug() << "authed request was redirected to" << redirectUrl.toString();
|
||||||
|
|
||||||
@@ -250,18 +254,36 @@ void OwncloudSetupWizard::slotAuthError()
|
|||||||
_ocWizard->account()->setUrl(redirectUrl);
|
_ocWizard->account()->setUrl(redirectUrl);
|
||||||
testOwnCloudConnect();
|
testOwnCloudConnect();
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
errorMsg = tr("The authenticated request to the server was redirected to "
|
|
||||||
"'%1'. The URL is bad, the server is misconfigured.")
|
|
||||||
.arg(redirectUrl.toString());
|
|
||||||
}
|
}
|
||||||
}
|
errorMsg = tr("The authenticated request to the server was redirected to "
|
||||||
|
"'%1'. The URL is bad, the server is misconfigured.")
|
||||||
|
.arg(redirectUrl.toString());
|
||||||
|
|
||||||
if (errorMsg.isEmpty()) {
|
// A 404 is actually a success: we were authorized to know that the folder does
|
||||||
|
// not exist. It will be created later...
|
||||||
|
} else if (reply->error() == QNetworkReply::ContentNotFoundError) {
|
||||||
|
_ocWizard->successfulStep();
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Provide messages for other errors, such as invalid credentials.
|
||||||
|
} else if (reply->error() != QNetworkReply::NoError) {
|
||||||
|
errorMsg = reply->errorString();
|
||||||
|
if (!_ocWizard->account()->credentials()->stillValid(reply)) {
|
||||||
|
errorMsg = tr("Access forbidden by server. To verify that you have proper access, "
|
||||||
|
"<a href=\"%1\">click here</a> to access the service with your browser.")
|
||||||
|
.arg(_ocWizard->account()->url().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Something else went wrong, maybe the response was 200 but with invalid data.
|
||||||
|
} else {
|
||||||
errorMsg = tr("There was an invalid response to an authenticated webdav request");
|
errorMsg = tr("There was an invalid response to an authenticated webdav request");
|
||||||
}
|
}
|
||||||
_ocWizard->displayError(errorMsg, false);
|
|
||||||
_ocWizard->show();
|
_ocWizard->show();
|
||||||
|
if (_ocWizard->currentId() == WizardCommon::Page_ShibbolethCreds) {
|
||||||
|
_ocWizard->back();
|
||||||
|
}
|
||||||
|
_ocWizard->displayError(errorMsg, _ocWizard->currentId() == WizardCommon::Page_ServerSetup && checkDowngradeAdvised(reply));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OwncloudSetupWizard::checkDowngradeAdvised(QNetworkReply* reply)
|
bool OwncloudSetupWizard::checkDowngradeAdvised(QNetworkReply* reply)
|
||||||
@@ -287,29 +309,6 @@ bool OwncloudSetupWizard::checkDowngradeAdvised(QNetworkReply* reply)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OwncloudSetupWizard::slotAuthNetworkError(QNetworkReply* reply)
|
|
||||||
{
|
|
||||||
QString msg = reply->errorString();
|
|
||||||
switch (reply->error()) {
|
|
||||||
case QNetworkReply::NoError:
|
|
||||||
case QNetworkReply::ContentNotFoundError:
|
|
||||||
_ocWizard->successfulStep();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (!_ocWizard->account()->credentials()->stillValid(reply)) {
|
|
||||||
msg = tr("Access forbidden by server. To verify that you have proper access, "
|
|
||||||
"<a href=\"%1\">click here</a> to access the service with your browser.")
|
|
||||||
.arg(_ocWizard->account()->url().toString());
|
|
||||||
}
|
|
||||||
_ocWizard->show();
|
|
||||||
if (_ocWizard->currentId() == WizardCommon::Page_ShibbolethCreds) {
|
|
||||||
_ocWizard->back();
|
|
||||||
}
|
|
||||||
_ocWizard->displayError(msg, _ocWizard->currentId() == WizardCommon::Page_ServerSetup && checkDowngradeAdvised(reply));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString& localFolder, const QString& remoteFolder)
|
void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString& localFolder, const QString& remoteFolder)
|
||||||
{
|
{
|
||||||
qDebug() << "Setup local sync folder for new oC connection " << localFolder;
|
qDebug() << "Setup local sync folder for new oC connection " << localFolder;
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ private slots:
|
|||||||
void slotNoOwnCloudFoundAuthTimeout(const QUrl&url);
|
void slotNoOwnCloudFoundAuthTimeout(const QUrl&url);
|
||||||
|
|
||||||
void slotConnectToOCUrl(const QString&);
|
void slotConnectToOCUrl(const QString&);
|
||||||
void slotAuthNetworkError(QNetworkReply*);
|
|
||||||
void slotAuthError();
|
void slotAuthError();
|
||||||
|
|
||||||
void slotCreateLocalAndRemoteFolders(const QString&, const QString&);
|
void slotCreateLocalAndRemoteFolders(const QString&, const QString&);
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ QTreeWidgetItem* ProtocolWidget::createCompletedTreewidgetItem(const QString& fo
|
|||||||
const QString longTimeStr = timeString(timestamp, QLocale::LongFormat);
|
const QString longTimeStr = timeString(timestamp, QLocale::LongFormat);
|
||||||
|
|
||||||
columns << timeStr;
|
columns << timeStr;
|
||||||
columns << fixupFilename(item._file);
|
columns << fixupFilename(item._originalFile);
|
||||||
columns << folder;
|
columns << folder;
|
||||||
|
|
||||||
// If the error string is set, it's prefered because it is a useful user message.
|
// If the error string is set, it's prefered because it is a useful user message.
|
||||||
|
|||||||
@@ -144,6 +144,15 @@ void ShareDialog::done( int r ) {
|
|||||||
QDialog::done(r);
|
QDialog::done(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int getJsonReturnCode(const QVariantMap &json, QString &message)
|
||||||
|
{
|
||||||
|
//TODO proper checking
|
||||||
|
int code = json.value("ocs").toMap().value("meta").toMap().value("statuscode").toInt();
|
||||||
|
message = json.value("ocs").toMap().value("meta").toMap().value("message").toString();
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
void ShareDialog::setExpireDate(const QDate &date)
|
void ShareDialog::setExpireDate(const QDate &date)
|
||||||
{
|
{
|
||||||
if( _public_share_id == 0 ) {
|
if( _public_share_id == 0 ) {
|
||||||
@@ -162,16 +171,14 @@ void ShareDialog::setExpireDate(const QDate &date)
|
|||||||
|
|
||||||
OcsShareJob *job = new OcsShareJob("PUT", url, _account, this);
|
OcsShareJob *job = new OcsShareJob("PUT", url, _account, this);
|
||||||
job->setPostParams(postParams);
|
job->setPostParams(postParams);
|
||||||
connect(job, SIGNAL(jobFinished(QString)), this, SLOT(slotExpireSet(QString)));
|
connect(job, SIGNAL(jobFinished(QVariantMap)), this, SLOT(slotExpireSet(QVariantMap)));
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShareDialog::slotExpireSet(const QString &reply)
|
void ShareDialog::slotExpireSet(const QVariantMap &reply)
|
||||||
{
|
{
|
||||||
QString message;
|
QString message;
|
||||||
int code = checkJsonReturnCode(reply, message);
|
int code = getJsonReturnCode(reply, message);
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << "Status code: " << code;
|
|
||||||
if (code != 100) {
|
if (code != 100) {
|
||||||
displayError(code);
|
displayError(code);
|
||||||
}
|
}
|
||||||
@@ -234,18 +241,15 @@ void ShareDialog::setPassword(const QString &password)
|
|||||||
}
|
}
|
||||||
OcsShareJob *job = new OcsShareJob(verb, url, _account, this);
|
OcsShareJob *job = new OcsShareJob(verb, url, _account, this);
|
||||||
job->setPostParams(requestParams);
|
job->setPostParams(requestParams);
|
||||||
connect(job, SIGNAL(jobFinished(QString)), this, SLOT(slotPasswordSet(QString)));
|
connect(job, SIGNAL(jobFinished(QVariantMap)), this, SLOT(slotPasswordSet(QVariantMap)));
|
||||||
job->start();
|
job->start();
|
||||||
_passwordJobRunning = true;
|
_passwordJobRunning = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShareDialog::slotPasswordSet(const QString &reply)
|
void ShareDialog::slotPasswordSet(const QVariantMap &reply)
|
||||||
{
|
{
|
||||||
QString message;
|
QString message;
|
||||||
int code = checkJsonReturnCode(reply, message);
|
int code = getJsonReturnCode(reply, message);
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << "Status code: " << code;
|
|
||||||
|
|
||||||
if (code != 100) {
|
if (code != 100) {
|
||||||
displayError(code);
|
displayError(code);
|
||||||
}
|
}
|
||||||
@@ -267,23 +271,20 @@ void ShareDialog::getShares()
|
|||||||
params.append(qMakePair(QString::fromLatin1("path"), _sharePath));
|
params.append(qMakePair(QString::fromLatin1("path"), _sharePath));
|
||||||
url.setQueryItems(params);
|
url.setQueryItems(params);
|
||||||
OcsShareJob *job = new OcsShareJob("GET", url, _account, this);
|
OcsShareJob *job = new OcsShareJob("GET", url, _account, this);
|
||||||
connect(job, SIGNAL(jobFinished(QString)), this, SLOT(slotSharesFetched(QString)));
|
job->addPassStatusCode(404); // don't report error if share doesn't exist yet
|
||||||
|
connect(job, SIGNAL(jobFinished(QVariantMap)), this, SLOT(slotSharesFetched(QVariantMap)));
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShareDialog::slotSharesFetched(const QString &reply)
|
void ShareDialog::slotSharesFetched(const QVariantMap &reply)
|
||||||
{
|
{
|
||||||
QString message;
|
QString message;
|
||||||
int code = checkJsonReturnCode(reply, message);
|
int code = getJsonReturnCode(reply, message);
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << "Status code: " << code;
|
|
||||||
if (code != 100 && code != 404) {
|
if (code != 100 && code != 404) {
|
||||||
displayError(code);
|
displayError(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = false;
|
ShareDialog::_shares = reply.value("ocs").toMap().value("data").toList();
|
||||||
QVariantMap json = QtJson::parse(reply, success).toMap();
|
|
||||||
ShareDialog::_shares = json.value("ocs").toMap().value("data").toList();
|
|
||||||
const QString versionString = AccountManager::instance()->account()->serverVersion();
|
const QString versionString = AccountManager::instance()->account()->serverVersion();
|
||||||
|
|
||||||
Q_FOREACH(auto share, ShareDialog::_shares) {
|
Q_FOREACH(auto share, ShareDialog::_shares) {
|
||||||
@@ -291,6 +292,7 @@ void ShareDialog::slotSharesFetched(const QString &reply)
|
|||||||
|
|
||||||
if (data.value("share_type").toInt() == SHARETYPE_PUBLIC) {
|
if (data.value("share_type").toInt() == SHARETYPE_PUBLIC) {
|
||||||
_public_share_id = data.value("id").toULongLong();
|
_public_share_id = data.value("id").toULongLong();
|
||||||
|
_ui->pushButton_copy->show();
|
||||||
|
|
||||||
_ui->widget_shareLink->show();
|
_ui->widget_shareLink->show();
|
||||||
_ui->checkBox_shareLink->setChecked(true);
|
_ui->checkBox_shareLink->setChecked(true);
|
||||||
@@ -384,12 +386,10 @@ void ShareDialog::setShareLink( const QString& url )
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShareDialog::slotDeleteShareFetched(const QString &reply)
|
void ShareDialog::slotDeleteShareFetched(const QVariantMap &reply)
|
||||||
{
|
{
|
||||||
QString message;
|
QString message;
|
||||||
int code = checkJsonReturnCode(reply, message);
|
int code = getJsonReturnCode(reply, message);
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << "Status code: " << code;
|
|
||||||
if (code != 100) {
|
if (code != 100) {
|
||||||
displayError(code);
|
displayError(code);
|
||||||
}
|
}
|
||||||
@@ -423,29 +423,31 @@ void ShareDialog::slotCheckBoxShareLinkClicked()
|
|||||||
postParams.append(qMakePair(QString::fromLatin1("shareType"), QString::number(SHARETYPE_PUBLIC)));
|
postParams.append(qMakePair(QString::fromLatin1("shareType"), QString::number(SHARETYPE_PUBLIC)));
|
||||||
OcsShareJob *job = new OcsShareJob("POST", url, _account, this);
|
OcsShareJob *job = new OcsShareJob("POST", url, _account, this);
|
||||||
job->setPostParams(postParams);
|
job->setPostParams(postParams);
|
||||||
connect(job, SIGNAL(jobFinished(QString)), this, SLOT(slotCreateShareFetched(QString)));
|
job->addPassStatusCode(403); // "password required" is not an error
|
||||||
|
connect(job, SIGNAL(jobFinished(QVariantMap)), this, SLOT(slotCreateShareFetched(QVariantMap)));
|
||||||
job->start();
|
job->start();
|
||||||
} else {
|
} else {
|
||||||
_pi_link->startAnimation();
|
_pi_link->startAnimation();
|
||||||
QUrl url = Account::concatUrlPath(_account->url(), QString("ocs/v1.php/apps/files_sharing/api/v1/shares/%1").arg(_public_share_id));
|
QUrl url = Account::concatUrlPath(_account->url(), QString("ocs/v1.php/apps/files_sharing/api/v1/shares/%1").arg(_public_share_id));
|
||||||
OcsShareJob *job = new OcsShareJob("DELETE", url, _account, this);
|
OcsShareJob *job = new OcsShareJob("DELETE", url, _account, this);
|
||||||
connect(job, SIGNAL(jobFinished(QString)), this, SLOT(slotDeleteShareFetched(QString)));
|
connect(job, SIGNAL(jobFinished(QVariantMap)), this, SLOT(slotDeleteShareFetched(QVariantMap)));
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShareDialog::slotCreateShareFetched(const QString &reply)
|
void ShareDialog::slotCreateShareFetched(const QVariantMap &reply)
|
||||||
{
|
{
|
||||||
QString message;
|
QString message;
|
||||||
int code = checkJsonReturnCode(reply, message);
|
int code = getJsonReturnCode(reply, message);
|
||||||
_pi_link->stopAnimation();
|
_pi_link->stopAnimation();
|
||||||
|
|
||||||
if (code == 403) {
|
if (code == 403) {
|
||||||
// there needs to be a password
|
// there needs to be a password
|
||||||
_ui->checkBox_password->setChecked(true);
|
_ui->checkBox_password->setChecked(true);
|
||||||
_ui->checkBox_password->setVisible(false);
|
_ui->checkBox_password->setEnabled(false);
|
||||||
_ui->checkBox_password->setText(tr("Public shå requires a password:"));
|
_ui->checkBox_password->setText(tr("Public shå requires a password"));
|
||||||
_ui->lineEdit_password->setFocus();
|
_ui->lineEdit_password->setFocus();
|
||||||
|
_ui->pushButton_copy->hide();
|
||||||
_ui->widget_shareLink->show();
|
_ui->widget_shareLink->show();
|
||||||
|
|
||||||
slotCheckBoxPasswordClicked();
|
slotCheckBoxPasswordClicked();
|
||||||
@@ -455,9 +457,8 @@ void ShareDialog::slotCreateShareFetched(const QString &reply)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success;
|
_public_share_id = reply.value("ocs").toMap().values("data")[0].toMap().value("id").toULongLong();
|
||||||
QVariantMap json = QtJson::parse(reply, success).toMap();
|
_ui->pushButton_copy->show();
|
||||||
_public_share_id = json.value("ocs").toMap().values("data")[0].toMap().value("id").toULongLong();
|
|
||||||
getShares();
|
getShares();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,7 +467,7 @@ void ShareDialog::slotCheckBoxPasswordClicked()
|
|||||||
if (_ui->checkBox_password->checkState() == Qt::Checked) {
|
if (_ui->checkBox_password->checkState() == Qt::Checked) {
|
||||||
_ui->lineEdit_password->show();
|
_ui->lineEdit_password->show();
|
||||||
_ui->pushButton_setPassword->show();
|
_ui->pushButton_setPassword->show();
|
||||||
_ui->lineEdit_password->setPlaceholderText(tr("Choose a password for the public link"));
|
_ui->lineEdit_password->setPlaceholderText(tr("Password"));
|
||||||
_ui->lineEdit_password->setFocus();
|
_ui->lineEdit_password->setFocus();
|
||||||
} else {
|
} else {
|
||||||
ShareDialog::setPassword(QString());
|
ShareDialog::setPassword(QString());
|
||||||
@@ -500,22 +501,6 @@ void ShareDialog::slotPushButtonCopyLinkPressed()
|
|||||||
clipboard->setText(_shareUrl);
|
clipboard->setText(_shareUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ShareDialog::checkJsonReturnCode(const QString &reply, QString &message)
|
|
||||||
{
|
|
||||||
bool success;
|
|
||||||
QVariantMap json = QtJson::parse(reply, success).toMap();
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
qDebug() << Q_FUNC_INFO << "Failed to parse reply";
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO proper checking
|
|
||||||
int code = json.value("ocs").toMap().value("meta").toMap().value("statuscode").toInt();
|
|
||||||
message = json.value("ocs").toMap().value("meta").toMap().value("message").toString();
|
|
||||||
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShareDialog::setShareCheckBoxTitle(bool haveShares)
|
void ShareDialog::setShareCheckBoxTitle(bool haveShares)
|
||||||
{
|
{
|
||||||
const QString noSharesTitle(tr("&Share link"));
|
const QString noSharesTitle(tr("&Share link"));
|
||||||
@@ -672,6 +657,7 @@ OcsShareJob::OcsShareJob(const QByteArray &verb, const QUrl &url, AccountPtr acc
|
|||||||
_verb(verb),
|
_verb(verb),
|
||||||
_url(url)
|
_url(url)
|
||||||
{
|
{
|
||||||
|
_passStatusCodes.append(100);
|
||||||
setIgnoreCredentialFailure(true);
|
setIgnoreCredentialFailure(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -680,6 +666,11 @@ void OcsShareJob::setPostParams(const QList<QPair<QString, QString> >& postParam
|
|||||||
_postParams = postParams;
|
_postParams = postParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OcsShareJob::addPassStatusCode(int code)
|
||||||
|
{
|
||||||
|
_passStatusCodes.append(code);
|
||||||
|
}
|
||||||
|
|
||||||
void OcsShareJob::start()
|
void OcsShareJob::start()
|
||||||
{
|
{
|
||||||
QNetworkRequest req;
|
QNetworkRequest req;
|
||||||
@@ -711,7 +702,23 @@ void OcsShareJob::start()
|
|||||||
|
|
||||||
bool OcsShareJob::finished()
|
bool OcsShareJob::finished()
|
||||||
{
|
{
|
||||||
emit jobFinished(reply()->readAll());
|
const QString replyData = reply()->readAll();
|
||||||
|
|
||||||
|
bool success;
|
||||||
|
QVariantMap json = QtJson::parse(replyData, success).toMap();
|
||||||
|
if (!success) {
|
||||||
|
qDebug() << "Could not parse reply to" << _verb << _url << _postParams
|
||||||
|
<< ":" << replyData;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString message;
|
||||||
|
const int statusCode = getJsonReturnCode(json, message);
|
||||||
|
if (!_passStatusCodes.contains(statusCode)) {
|
||||||
|
qDebug() << "Reply to" << _verb << _url << _postParams
|
||||||
|
<< "has unexpected status code:" << statusCode << replyData;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit jobFinished(json);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,17 +29,19 @@ public:
|
|||||||
explicit OcsShareJob(const QByteArray& verb, const QUrl& url, AccountPtr account, QObject* parent = 0);
|
explicit OcsShareJob(const QByteArray& verb, const QUrl& url, AccountPtr account, QObject* parent = 0);
|
||||||
|
|
||||||
void setPostParams(const QList<QPair<QString, QString> >& postParams);
|
void setPostParams(const QList<QPair<QString, QString> >& postParams);
|
||||||
|
void addPassStatusCode(int code);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void start() Q_DECL_OVERRIDE;
|
void start() Q_DECL_OVERRIDE;
|
||||||
signals:
|
signals:
|
||||||
void jobFinished(QString reply);
|
void jobFinished(QVariantMap reply);
|
||||||
private slots:
|
private slots:
|
||||||
virtual bool finished() Q_DECL_OVERRIDE;
|
virtual bool finished() Q_DECL_OVERRIDE;
|
||||||
private:
|
private:
|
||||||
QByteArray _verb;
|
QByteArray _verb;
|
||||||
QUrl _url;
|
QUrl _url;
|
||||||
QList<QPair<QString, QString> > _postParams;
|
QList<QPair<QString, QString> > _postParams;
|
||||||
|
QVector<int> _passStatusCodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -49,7 +51,6 @@ class ShareDialog;
|
|||||||
|
|
||||||
class AbstractCredentials;
|
class AbstractCredentials;
|
||||||
class QuotaInfo;
|
class QuotaInfo;
|
||||||
class MirallAccessManager;
|
|
||||||
class SyncResult;
|
class SyncResult;
|
||||||
|
|
||||||
class ShareDialog : public QDialog
|
class ShareDialog : public QDialog
|
||||||
@@ -63,11 +64,11 @@ public:
|
|||||||
void getShares();
|
void getShares();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void slotSharesFetched(const QString &reply);
|
void slotSharesFetched(const QVariantMap &reply);
|
||||||
void slotCreateShareFetched(const QString &reply);
|
void slotCreateShareFetched(const QVariantMap &reply);
|
||||||
void slotDeleteShareFetched(const QString &reply);
|
void slotDeleteShareFetched(const QVariantMap &reply);
|
||||||
void slotPasswordSet(const QString &reply);
|
void slotPasswordSet(const QVariantMap &reply);
|
||||||
void slotExpireSet(const QString &reply);
|
void slotExpireSet(const QVariantMap &reply);
|
||||||
void slotCalendarClicked(const QDate &date);
|
void slotCalendarClicked(const QDate &date);
|
||||||
void slotCheckBoxShareLinkClicked();
|
void slotCheckBoxShareLinkClicked();
|
||||||
void slotCheckBoxPasswordClicked();
|
void slotCheckBoxPasswordClicked();
|
||||||
@@ -102,7 +103,6 @@ private:
|
|||||||
qulonglong _public_share_id;
|
qulonglong _public_share_id;
|
||||||
void setPassword(const QString &password);
|
void setPassword(const QString &password);
|
||||||
void setExpireDate(const QDate &date);
|
void setExpireDate(const QDate &date);
|
||||||
int checkJsonReturnCode(const QString &reply, QString &message);
|
|
||||||
|
|
||||||
QProgressIndicator *_pi_link;
|
QProgressIndicator *_pi_link;
|
||||||
QProgressIndicator *_pi_password;
|
QProgressIndicator *_pi_password;
|
||||||
|
|||||||
@@ -82,8 +82,8 @@ private:
|
|||||||
Q_INVOKABLE void command_SHARE_MENU_TITLE(const QString& argument, QLocalSocket* socket);
|
Q_INVOKABLE void command_SHARE_MENU_TITLE(const QString& argument, QLocalSocket* socket);
|
||||||
QString buildRegisterPathMessage(const QString& path);
|
QString buildRegisterPathMessage(const QString& path);
|
||||||
|
|
||||||
QLocalServer _localServer;
|
|
||||||
QList<QLocalSocket*> _listeners;
|
QList<QLocalSocket*> _listeners;
|
||||||
|
QLocalServer _localServer;
|
||||||
c_strlist_t *_excludes;
|
c_strlist_t *_excludes;
|
||||||
QHash<Folder*, SqlQuery*> _dbQueries;
|
QHash<Folder*, SqlQuery*> _dbQueries;
|
||||||
QHash<Folder*, SqlDatabase*> _openDbs;
|
QHash<Folder*, SqlDatabase*> _openDbs;
|
||||||
|
|||||||
@@ -111,15 +111,33 @@ SparkleUpdater::~SparkleUpdater()
|
|||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool autoUpdaterAllowed()
|
||||||
|
{
|
||||||
|
// See https://github.com/owncloud/client/issues/2931
|
||||||
|
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
|
||||||
|
NSString *expectedPath = [NSString stringWithFormat:@"/Applications/%@", [bundlePath lastPathComponent]];
|
||||||
|
if ([expectedPath isEqualTo:bundlePath]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
qWarning() << "ERROR: We are not in /Applications, won't check for update!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SparkleUpdater::checkForUpdate()
|
void SparkleUpdater::checkForUpdate()
|
||||||
{
|
{
|
||||||
[d->updater checkForUpdates: NSApp];
|
if (autoUpdaterAllowed()) {
|
||||||
|
[d->updater checkForUpdates: NSApp];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SparkleUpdater::backgroundCheckForUpdate()
|
void SparkleUpdater::backgroundCheckForUpdate()
|
||||||
{
|
{
|
||||||
qDebug() << Q_FUNC_INFO << "launching background check";
|
qDebug() << Q_FUNC_INFO << "launching background check";
|
||||||
[d->updater checkForUpdatesInBackground];
|
if (autoUpdaterAllowed()) {
|
||||||
|
[d->updater checkForUpdatesInBackground];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|||||||
@@ -57,6 +57,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Error Label</string>
|
<string>Error Label</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ OwncloudSetupPage::OwncloudSetupPage(QWidget *parent)
|
|||||||
|
|
||||||
setupCustomization();
|
setupCustomization();
|
||||||
|
|
||||||
|
slotUrlChanged(QLatin1String("")); // don't jitter UI
|
||||||
connect(_ui.leUrl, SIGNAL(textChanged(QString)), SLOT(slotUrlChanged(QString)));
|
connect(_ui.leUrl, SIGNAL(textChanged(QString)), SLOT(slotUrlChanged(QString)));
|
||||||
connect(_ui.leUrl, SIGNAL(editingFinished()), SLOT(slotUrlEditFinished()));
|
connect(_ui.leUrl, SIGNAL(editingFinished()), SLOT(slotUrlEditFinished()));
|
||||||
|
|
||||||
@@ -115,7 +116,7 @@ void OwncloudSetupPage::slotUrlChanged(const QString& url)
|
|||||||
_ui.leUrl->setText(newUrl);
|
_ui.leUrl->setText(newUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url.startsWith(QLatin1String("http://"))) {
|
if (!url.startsWith(QLatin1String("https://"))) {
|
||||||
_ui.urlLabel->setPixmap(QPixmap(Theme::hidpiFileName(":/client/resources/lock-http.png")));
|
_ui.urlLabel->setPixmap(QPixmap(Theme::hidpiFileName(":/client/resources/lock-http.png")));
|
||||||
_ui.urlLabel->setToolTip(tr("This url is NOT secure as it is not encrypted.\n"
|
_ui.urlLabel->setToolTip(tr("This url is NOT secure as it is not encrypted.\n"
|
||||||
"It is not advisable to use it."));
|
"It is not advisable to use it."));
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ set(libsync_SRCS
|
|||||||
theme.cpp
|
theme.cpp
|
||||||
utility.cpp
|
utility.cpp
|
||||||
ownsql.cpp
|
ownsql.cpp
|
||||||
|
transmissionchecksumvalidator.cpp
|
||||||
creds/dummycredentials.cpp
|
creds/dummycredentials.cpp
|
||||||
creds/abstractcredentials.cpp
|
creds/abstractcredentials.cpp
|
||||||
creds/credentialsfactory.cpp
|
creds/credentialsfactory.cpp
|
||||||
@@ -141,6 +142,11 @@ if(NEON_FOUND)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(ZLIB_FOUND)
|
||||||
|
list(APPEND libsync_LINK_TARGETS ${ZLIB_LIBRARIES})
|
||||||
|
include_directories(${ZLIB_INCLUDE_DIRS})
|
||||||
|
endif(ZLIB_FOUND)
|
||||||
|
|
||||||
add_library(${synclib_NAME} SHARED ${libsync_SRCS} ${syncMoc})
|
add_library(${synclib_NAME} SHARED ${libsync_SRCS} ${syncMoc})
|
||||||
GENERATE_EXPORT_HEADER( ${synclib_NAME}
|
GENERATE_EXPORT_HEADER( ${synclib_NAME}
|
||||||
BASE_NAME ${synclib_NAME}
|
BASE_NAME ${synclib_NAME}
|
||||||
@@ -151,9 +157,9 @@ GENERATE_EXPORT_HEADER( ${synclib_NAME}
|
|||||||
|
|
||||||
|
|
||||||
if(TOKEN_AUTH_ONLY)
|
if(TOKEN_AUTH_ONLY)
|
||||||
qt5_use_modules(${synclib_NAME} Network)
|
qt5_use_modules(${synclib_NAME} Network Concurrent)
|
||||||
else()
|
else()
|
||||||
qt5_use_modules(${synclib_NAME} Widgets Network WebKitWidgets)
|
qt5_use_modules(${synclib_NAME} Widgets Network WebKitWidgets Concurrent)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set_target_properties( ${synclib_NAME} PROPERTIES
|
set_target_properties( ${synclib_NAME} PROPERTIES
|
||||||
|
|||||||
@@ -321,7 +321,9 @@ QNetworkReply *Account::getRequest(const QString &relPath)
|
|||||||
QNetworkReply *Account::getRequest(const QUrl &url)
|
QNetworkReply *Account::getRequest(const QUrl &url)
|
||||||
{
|
{
|
||||||
QNetworkRequest request(url);
|
QNetworkRequest request(url);
|
||||||
|
#if QT_VERSION > QT_VERSION_CHECK(4, 8, 4)
|
||||||
request.setSslConfiguration(this->createSslConfig());
|
request.setSslConfiguration(this->createSslConfig());
|
||||||
|
#endif
|
||||||
return _am->get(request);
|
return _am->get(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +335,9 @@ QNetworkReply *Account::davRequest(const QByteArray &verb, const QString &relPat
|
|||||||
QNetworkReply *Account::davRequest(const QByteArray &verb, const QUrl &url, QNetworkRequest req, QIODevice *data)
|
QNetworkReply *Account::davRequest(const QByteArray &verb, const QUrl &url, QNetworkRequest req, QIODevice *data)
|
||||||
{
|
{
|
||||||
req.setUrl(url);
|
req.setUrl(url);
|
||||||
|
#if QT_VERSION > QT_VERSION_CHECK(4, 8, 4)
|
||||||
req.setSslConfiguration(this->createSslConfig());
|
req.setSslConfiguration(this->createSslConfig());
|
||||||
|
#endif
|
||||||
return _am->sendCustomRequest(req, verb, data);
|
return _am->sendCustomRequest(req, verb, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,6 +400,11 @@ void Account::addApprovedCerts(const QList<QSslCertificate> certs)
|
|||||||
_approvedCerts += certs;
|
_approvedCerts += certs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Account::resetSslCertErrorState()
|
||||||
|
{
|
||||||
|
_treatSslErrorsAsFailure = false;
|
||||||
|
}
|
||||||
|
|
||||||
void Account::setSslErrorHandler(AbstractSslErrorHandler *handler)
|
void Account::setSslErrorHandler(AbstractSslErrorHandler *handler)
|
||||||
{
|
{
|
||||||
_sslErrorHandler.reset(handler);
|
_sslErrorHandler.reset(handler);
|
||||||
|
|||||||
@@ -132,6 +132,11 @@ public:
|
|||||||
void setApprovedCerts(const QList<QSslCertificate> certs);
|
void setApprovedCerts(const QList<QSslCertificate> certs);
|
||||||
void addApprovedCerts(const QList<QSslCertificate> certs);
|
void addApprovedCerts(const QList<QSslCertificate> certs);
|
||||||
|
|
||||||
|
// Usually when a user explicitly rejects a certificate we don't
|
||||||
|
// ask again. After this call, a dialog will again be shown when
|
||||||
|
// the next unknown certificate is encountered.
|
||||||
|
void resetSslCertErrorState();
|
||||||
|
|
||||||
// pluggable handler
|
// pluggable handler
|
||||||
void setSslErrorHandler(AbstractSslErrorHandler *handler);
|
void setSslErrorHandler(AbstractSslErrorHandler *handler);
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ BandwidthManager::~BandwidthManager()
|
|||||||
|
|
||||||
void BandwidthManager::registerUploadDevice(UploadDevice *p)
|
void BandwidthManager::registerUploadDevice(UploadDevice *p)
|
||||||
{
|
{
|
||||||
qDebug() << Q_FUNC_INFO << p;
|
//qDebug() << Q_FUNC_INFO << p;
|
||||||
_absoluteUploadDeviceList.append(p);
|
_absoluteUploadDeviceList.append(p);
|
||||||
_relativeUploadDeviceList.append(p);
|
_relativeUploadDeviceList.append(p);
|
||||||
QObject::connect(p, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterUploadDevice(QObject*)));
|
QObject::connect(p, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterUploadDevice(QObject*)));
|
||||||
@@ -117,7 +117,7 @@ void BandwidthManager::unregisterUploadDevice(QObject *o)
|
|||||||
|
|
||||||
void BandwidthManager::unregisterUploadDevice(UploadDevice* p)
|
void BandwidthManager::unregisterUploadDevice(UploadDevice* p)
|
||||||
{
|
{
|
||||||
qDebug() << Q_FUNC_INFO << p;
|
//qDebug() << Q_FUNC_INFO << p;
|
||||||
_absoluteUploadDeviceList.removeAll(p);
|
_absoluteUploadDeviceList.removeAll(p);
|
||||||
_relativeUploadDeviceList.removeAll(p);
|
_relativeUploadDeviceList.removeAll(p);
|
||||||
if (p == _relativeLimitCurrentMeasuredDevice) {
|
if (p == _relativeLimitCurrentMeasuredDevice) {
|
||||||
@@ -128,7 +128,7 @@ void BandwidthManager::unregisterUploadDevice(UploadDevice* p)
|
|||||||
|
|
||||||
void BandwidthManager::registerDownloadJob(GETFileJob* j)
|
void BandwidthManager::registerDownloadJob(GETFileJob* j)
|
||||||
{
|
{
|
||||||
qDebug() << Q_FUNC_INFO << j;
|
//qDebug() << Q_FUNC_INFO << j;
|
||||||
_downloadJobList.append(j);
|
_downloadJobList.append(j);
|
||||||
QObject::connect(j, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterDownloadJob(QObject*)));
|
QObject::connect(j, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterDownloadJob(QObject*)));
|
||||||
|
|
||||||
@@ -176,19 +176,19 @@ void BandwidthManager::relativeUploadMeasuringTimerExpired()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << _relativeUploadDeviceList.count() << "Starting Delay";
|
// qDebug() << Q_FUNC_INFO << _relativeUploadDeviceList.count() << "Starting Delay";
|
||||||
|
|
||||||
qint64 relativeLimitProgressMeasured = (_relativeLimitCurrentMeasuredDevice->_readWithProgress
|
qint64 relativeLimitProgressMeasured = (_relativeLimitCurrentMeasuredDevice->_readWithProgress
|
||||||
+ _relativeLimitCurrentMeasuredDevice->_read) / 2;
|
+ _relativeLimitCurrentMeasuredDevice->_read) / 2;
|
||||||
qint64 relativeLimitProgressDifference = relativeLimitProgressMeasured - _relativeUploadLimitProgressAtMeasuringRestart;
|
qint64 relativeLimitProgressDifference = relativeLimitProgressMeasured - _relativeUploadLimitProgressAtMeasuringRestart;
|
||||||
qDebug() << Q_FUNC_INFO << _relativeUploadLimitProgressAtMeasuringRestart
|
// qDebug() << Q_FUNC_INFO << _relativeUploadLimitProgressAtMeasuringRestart
|
||||||
<< relativeLimitProgressMeasured << relativeLimitProgressDifference;
|
// << relativeLimitProgressMeasured << relativeLimitProgressDifference;
|
||||||
|
|
||||||
qint64 speedkBPerSec = (relativeLimitProgressDifference / relativeLimitMeasuringTimerIntervalMsec*1000.0) / 1024.0;
|
// qint64 speedkBPerSec = (relativeLimitProgressDifference / relativeLimitMeasuringTimerIntervalMsec*1000.0) / 1024.0;
|
||||||
qDebug() << Q_FUNC_INFO << relativeLimitProgressDifference/1024 <<"kB =>" << speedkBPerSec << "kB/sec on full speed ("
|
// qDebug() << Q_FUNC_INFO << relativeLimitProgressDifference/1024 <<"kB =>" << speedkBPerSec << "kB/sec on full speed ("
|
||||||
<< _relativeLimitCurrentMeasuredDevice->_readWithProgress << _relativeLimitCurrentMeasuredDevice->_read
|
// << _relativeLimitCurrentMeasuredDevice->_readWithProgress << _relativeLimitCurrentMeasuredDevice->_read
|
||||||
<< qAbs(_relativeLimitCurrentMeasuredDevice->_readWithProgress
|
// << qAbs(_relativeLimitCurrentMeasuredDevice->_readWithProgress
|
||||||
- _relativeLimitCurrentMeasuredDevice->_read) << ")";
|
// - _relativeLimitCurrentMeasuredDevice->_read) << ")";
|
||||||
|
|
||||||
qint64 uploadLimitPercent = -_currentUploadLimit;
|
qint64 uploadLimitPercent = -_currentUploadLimit;
|
||||||
// don't use too extreme values
|
// don't use too extreme values
|
||||||
@@ -197,9 +197,9 @@ void BandwidthManager::relativeUploadMeasuringTimerExpired()
|
|||||||
qint64 wholeTimeMsec = (100.0 / uploadLimitPercent) * relativeLimitMeasuringTimerIntervalMsec;
|
qint64 wholeTimeMsec = (100.0 / uploadLimitPercent) * relativeLimitMeasuringTimerIntervalMsec;
|
||||||
qint64 waitTimeMsec = wholeTimeMsec - relativeLimitMeasuringTimerIntervalMsec;
|
qint64 waitTimeMsec = wholeTimeMsec - relativeLimitMeasuringTimerIntervalMsec;
|
||||||
qint64 realWaitTimeMsec = waitTimeMsec + wholeTimeMsec;
|
qint64 realWaitTimeMsec = waitTimeMsec + wholeTimeMsec;
|
||||||
qDebug() << Q_FUNC_INFO << waitTimeMsec << " - "<< realWaitTimeMsec <<
|
// qDebug() << Q_FUNC_INFO << waitTimeMsec << " - "<< realWaitTimeMsec <<
|
||||||
" msec for " << uploadLimitPercent << "%";
|
// " msec for " << uploadLimitPercent << "%";
|
||||||
qDebug() << Q_FUNC_INFO << "XXXX" << uploadLimitPercent << relativeLimitMeasuringTimerIntervalMsec;
|
// qDebug() << Q_FUNC_INFO << "XXXX" << uploadLimitPercent << relativeLimitMeasuringTimerIntervalMsec;
|
||||||
|
|
||||||
// We want to wait twice as long since we want to give all
|
// We want to wait twice as long since we want to give all
|
||||||
// devices the same quota we used now since we don't want
|
// devices the same quota we used now since we don't want
|
||||||
@@ -209,12 +209,12 @@ void BandwidthManager::relativeUploadMeasuringTimerExpired()
|
|||||||
|
|
||||||
int deviceCount = _relativeUploadDeviceList.count();
|
int deviceCount = _relativeUploadDeviceList.count();
|
||||||
qint64 quotaPerDevice = relativeLimitProgressDifference * (uploadLimitPercent / 100.0) / deviceCount + 1.0;
|
qint64 quotaPerDevice = relativeLimitProgressDifference * (uploadLimitPercent / 100.0) / deviceCount + 1.0;
|
||||||
qDebug() << Q_FUNC_INFO << "YYYY" << relativeLimitProgressDifference << uploadLimitPercent << deviceCount;
|
// qDebug() << Q_FUNC_INFO << "YYYY" << relativeLimitProgressDifference << uploadLimitPercent << deviceCount;
|
||||||
Q_FOREACH(UploadDevice *ud, _relativeUploadDeviceList) {
|
Q_FOREACH(UploadDevice *ud, _relativeUploadDeviceList) {
|
||||||
ud->setBandwidthLimited(true);
|
ud->setBandwidthLimited(true);
|
||||||
ud->setChoked(false);
|
ud->setChoked(false);
|
||||||
ud->giveBandwidthQuota(quotaPerDevice);
|
ud->giveBandwidthQuota(quotaPerDevice);
|
||||||
qDebug() << Q_FUNC_INFO << "Gave" << quotaPerDevice/1024.0 << "kB to" << ud;
|
// qDebug() << Q_FUNC_INFO << "Gave" << quotaPerDevice/1024.0 << "kB to" << ud;
|
||||||
}
|
}
|
||||||
_relativeLimitCurrentMeasuredDevice = 0;
|
_relativeLimitCurrentMeasuredDevice = 0;
|
||||||
}
|
}
|
||||||
@@ -232,7 +232,7 @@ void BandwidthManager::relativeUploadDelayTimerExpired()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << _relativeUploadDeviceList.count() << "Starting measuring";
|
// qDebug() << Q_FUNC_INFO << _relativeUploadDeviceList.count() << "Starting measuring";
|
||||||
|
|
||||||
// Take first device and then append it again (= we round robin all devices)
|
// Take first device and then append it again (= we round robin all devices)
|
||||||
_relativeLimitCurrentMeasuredDevice = _relativeUploadDeviceList.takeFirst();
|
_relativeLimitCurrentMeasuredDevice = _relativeUploadDeviceList.takeFirst();
|
||||||
@@ -270,16 +270,16 @@ void BandwidthManager::relativeDownloadMeasuringTimerExpired()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "Starting Delay";
|
// qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "Starting Delay";
|
||||||
|
|
||||||
qint64 relativeLimitProgressMeasured = _relativeLimitCurrentMeasuredJob->currentDownloadPosition();
|
qint64 relativeLimitProgressMeasured = _relativeLimitCurrentMeasuredJob->currentDownloadPosition();
|
||||||
qint64 relativeLimitProgressDifference = relativeLimitProgressMeasured - _relativeDownloadLimitProgressAtMeasuringRestart;
|
qint64 relativeLimitProgressDifference = relativeLimitProgressMeasured - _relativeDownloadLimitProgressAtMeasuringRestart;
|
||||||
qDebug() << Q_FUNC_INFO << _relativeDownloadLimitProgressAtMeasuringRestart
|
qDebug() << Q_FUNC_INFO << _relativeDownloadLimitProgressAtMeasuringRestart
|
||||||
<< relativeLimitProgressMeasured << relativeLimitProgressDifference;
|
<< relativeLimitProgressMeasured << relativeLimitProgressDifference;
|
||||||
|
|
||||||
qint64 speedkBPerSec = (relativeLimitProgressDifference / relativeLimitMeasuringTimerIntervalMsec*1000.0) / 1024.0;
|
// qint64 speedkBPerSec = (relativeLimitProgressDifference / relativeLimitMeasuringTimerIntervalMsec*1000.0) / 1024.0;
|
||||||
qDebug() << Q_FUNC_INFO << relativeLimitProgressDifference/1024 <<"kB =>" << speedkBPerSec << "kB/sec on full speed ("
|
// qDebug() << Q_FUNC_INFO << relativeLimitProgressDifference/1024 <<"kB =>" << speedkBPerSec << "kB/sec on full speed ("
|
||||||
<< _relativeLimitCurrentMeasuredJob->currentDownloadPosition() ;
|
// << _relativeLimitCurrentMeasuredJob->currentDownloadPosition() ;
|
||||||
|
|
||||||
qint64 downloadLimitPercent = -_currentDownloadLimit;
|
qint64 downloadLimitPercent = -_currentDownloadLimit;
|
||||||
// don't use too extreme values
|
// don't use too extreme values
|
||||||
@@ -288,9 +288,9 @@ void BandwidthManager::relativeDownloadMeasuringTimerExpired()
|
|||||||
qint64 wholeTimeMsec = (100.0 / downloadLimitPercent) * relativeLimitMeasuringTimerIntervalMsec;
|
qint64 wholeTimeMsec = (100.0 / downloadLimitPercent) * relativeLimitMeasuringTimerIntervalMsec;
|
||||||
qint64 waitTimeMsec = wholeTimeMsec - relativeLimitMeasuringTimerIntervalMsec;
|
qint64 waitTimeMsec = wholeTimeMsec - relativeLimitMeasuringTimerIntervalMsec;
|
||||||
qint64 realWaitTimeMsec = waitTimeMsec + wholeTimeMsec;
|
qint64 realWaitTimeMsec = waitTimeMsec + wholeTimeMsec;
|
||||||
qDebug() << Q_FUNC_INFO << waitTimeMsec << " - "<< realWaitTimeMsec <<
|
// qDebug() << Q_FUNC_INFO << waitTimeMsec << " - "<< realWaitTimeMsec <<
|
||||||
" msec for " << downloadLimitPercent << "%";
|
// " msec for " << downloadLimitPercent << "%";
|
||||||
qDebug() << Q_FUNC_INFO << "XXXX" << downloadLimitPercent << relativeLimitMeasuringTimerIntervalMsec;
|
// qDebug() << Q_FUNC_INFO << "XXXX" << downloadLimitPercent << relativeLimitMeasuringTimerIntervalMsec;
|
||||||
|
|
||||||
// We want to wait twice as long since we want to give all
|
// We want to wait twice as long since we want to give all
|
||||||
// devices the same quota we used now since we don't want
|
// devices the same quota we used now since we don't want
|
||||||
@@ -305,12 +305,12 @@ void BandwidthManager::relativeDownloadMeasuringTimerExpired()
|
|||||||
// quota -= 20*1024;
|
// quota -= 20*1024;
|
||||||
// }
|
// }
|
||||||
qint64 quotaPerJob = quota / jobCount + 1.0;
|
qint64 quotaPerJob = quota / jobCount + 1.0;
|
||||||
qDebug() << Q_FUNC_INFO << "YYYY" << relativeLimitProgressDifference << downloadLimitPercent << jobCount;
|
// qDebug() << Q_FUNC_INFO << "YYYY" << relativeLimitProgressDifference << downloadLimitPercent << jobCount;
|
||||||
Q_FOREACH(GETFileJob *gfj, _downloadJobList) {
|
Q_FOREACH(GETFileJob *gfj, _downloadJobList) {
|
||||||
gfj->setBandwidthLimited(true);
|
gfj->setBandwidthLimited(true);
|
||||||
gfj->setChoked(false);
|
gfj->setChoked(false);
|
||||||
gfj->giveBandwidthQuota(quotaPerJob);
|
gfj->giveBandwidthQuota(quotaPerJob);
|
||||||
qDebug() << Q_FUNC_INFO << "Gave" << quotaPerJob/1024.0 << "kB to" << gfj;
|
// qDebug() << Q_FUNC_INFO << "Gave" << quotaPerJob/1024.0 << "kB to" << gfj;
|
||||||
}
|
}
|
||||||
_relativeLimitCurrentMeasuredDevice = 0;
|
_relativeLimitCurrentMeasuredDevice = 0;
|
||||||
}
|
}
|
||||||
@@ -329,7 +329,7 @@ void BandwidthManager::relativeDownloadDelayTimerExpired()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "Starting measuring";
|
// qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "Starting measuring";
|
||||||
|
|
||||||
// Take first device and then append it again (= we round robin all devices)
|
// Take first device and then append it again (= we round robin all devices)
|
||||||
_relativeLimitCurrentMeasuredJob = _downloadJobList.takeFirst();
|
_relativeLimitCurrentMeasuredJob = _downloadJobList.takeFirst();
|
||||||
@@ -393,18 +393,18 @@ void BandwidthManager::absoluteLimitTimerExpired()
|
|||||||
{
|
{
|
||||||
if (usingAbsoluteUploadLimit() && _absoluteUploadDeviceList.count() > 0) {
|
if (usingAbsoluteUploadLimit() && _absoluteUploadDeviceList.count() > 0) {
|
||||||
qint64 quotaPerDevice = _currentUploadLimit / qMax(1, _absoluteUploadDeviceList.count());
|
qint64 quotaPerDevice = _currentUploadLimit / qMax(1, _absoluteUploadDeviceList.count());
|
||||||
qDebug() << Q_FUNC_INFO << quotaPerDevice << _absoluteUploadDeviceList.count() << _currentUploadLimit;
|
// qDebug() << Q_FUNC_INFO << quotaPerDevice << _absoluteUploadDeviceList.count() << _currentUploadLimit;
|
||||||
Q_FOREACH(UploadDevice *device, _absoluteUploadDeviceList) {
|
Q_FOREACH(UploadDevice *device, _absoluteUploadDeviceList) {
|
||||||
device->giveBandwidthQuota(quotaPerDevice);
|
device->giveBandwidthQuota(quotaPerDevice);
|
||||||
qDebug() << Q_FUNC_INFO << "Gave " << quotaPerDevice/1024.0 << " kB to" << device;
|
// qDebug() << Q_FUNC_INFO << "Gave " << quotaPerDevice/1024.0 << " kB to" << device;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (usingAbsoluteDownloadLimit() && _downloadJobList.count() > 0) {
|
if (usingAbsoluteDownloadLimit() && _downloadJobList.count() > 0) {
|
||||||
qint64 quotaPerJob = _currentDownloadLimit / qMax(1, _downloadJobList.count());
|
qint64 quotaPerJob = _currentDownloadLimit / qMax(1, _downloadJobList.count());
|
||||||
qDebug() << Q_FUNC_INFO << quotaPerJob << _downloadJobList.count() << _currentDownloadLimit;
|
// qDebug() << Q_FUNC_INFO << quotaPerJob << _downloadJobList.count() << _currentDownloadLimit;
|
||||||
Q_FOREACH(GETFileJob *j, _downloadJobList) {
|
Q_FOREACH(GETFileJob *j, _downloadJobList) {
|
||||||
j->giveBandwidthQuota(quotaPerJob);
|
j->giveBandwidthQuota(quotaPerJob);
|
||||||
qDebug() << Q_FUNC_INFO << "Gave " << quotaPerJob/1024.0 << " kB to" << j;
|
// qDebug() << Q_FUNC_INFO << "Gave " << quotaPerJob/1024.0 << " kB to" << j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ SystemProxyRunnable::SystemProxyRunnable(const QUrl &url) : QObject(), QRunnable
|
|||||||
void SystemProxyRunnable::run()
|
void SystemProxyRunnable::run()
|
||||||
{
|
{
|
||||||
qDebug() << Q_FUNC_INFO << "Starting system proxy lookup";
|
qDebug() << Q_FUNC_INFO << "Starting system proxy lookup";
|
||||||
|
qRegisterMetaType<QNetworkProxy>("QNetworkProxy");
|
||||||
QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery(QNetworkProxyQuery(_url));
|
QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery(QNetworkProxyQuery(_url));
|
||||||
|
|
||||||
if (proxies.isEmpty()) {
|
if (proxies.isEmpty()) {
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ static const char optionalDesktopNoficationsC[] = "optionalDesktopNotifications"
|
|||||||
static const char skipUpdateCheckC[] = "skipUpdateCheck";
|
static const char skipUpdateCheckC[] = "skipUpdateCheck";
|
||||||
static const char geometryC[] = "geometry";
|
static const char geometryC[] = "geometry";
|
||||||
static const char timeoutC[] = "timeout";
|
static const char timeoutC[] = "timeout";
|
||||||
|
static const char transmissionChecksumC[] = "transmissionChecksum";
|
||||||
|
|
||||||
static const char proxyHostC[] = "Proxy/host";
|
static const char proxyHostC[] = "Proxy/host";
|
||||||
static const char proxyTypeC[] = "Proxy/type";
|
static const char proxyTypeC[] = "Proxy/type";
|
||||||
@@ -118,6 +119,20 @@ int ConfigFile::timeout() const
|
|||||||
return settings.value(QLatin1String(timeoutC), 300).toInt(); // default to 5 min
|
return settings.value(QLatin1String(timeoutC), 300).toInt(); // default to 5 min
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ConfigFile::transmissionChecksum() const
|
||||||
|
{
|
||||||
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
|
|
||||||
|
QString checksum = settings.value(QLatin1String(transmissionChecksumC), QString()).toString();
|
||||||
|
|
||||||
|
if( checksum.isEmpty() ) {
|
||||||
|
// if the config file setting is empty, maybe the Branding requires it.
|
||||||
|
checksum = Theme::instance()->transmissionChecksum();
|
||||||
|
}
|
||||||
|
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
|
||||||
void ConfigFile::setOptionalDesktopNotifications(bool show)
|
void ConfigFile::setOptionalDesktopNotifications(bool show)
|
||||||
{
|
{
|
||||||
QSettings settings(configFile(), QSettings::IniFormat);
|
QSettings settings(configFile(), QSettings::IniFormat);
|
||||||
|
|||||||
@@ -103,6 +103,12 @@ public:
|
|||||||
|
|
||||||
int timeout() const;
|
int timeout() const;
|
||||||
|
|
||||||
|
// send a checksum as a header along with the transmission or not.
|
||||||
|
// possible values:
|
||||||
|
// empty: no checksum calculated or expected.
|
||||||
|
// or "Adler32", "MD5", "SHA1"
|
||||||
|
QString transmissionChecksum() const;
|
||||||
|
|
||||||
void saveGeometry(QWidget *w);
|
void saveGeometry(QWidget *w);
|
||||||
void restoreGeometry(QWidget *w);
|
void restoreGeometry(QWidget *w);
|
||||||
|
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ QString ConnectionValidator::statusString( Status stat )
|
|||||||
return QLatin1String("Status not found");
|
return QLatin1String("Status not found");
|
||||||
case UserCanceledCredentials:
|
case UserCanceledCredentials:
|
||||||
return QLatin1String("User canceled credentials");
|
return QLatin1String("User canceled credentials");
|
||||||
case ServerMaintenance:
|
case ServiceUnavailable:
|
||||||
return QLatin1String("Server in maintenance mode");
|
return QLatin1String("Service unavailable");
|
||||||
case Timeout:
|
case Timeout:
|
||||||
return QLatin1String("Timeout");
|
return QLatin1String("Timeout");
|
||||||
}
|
}
|
||||||
@@ -192,13 +192,8 @@ void ConnectionValidator::slotAuthFailed(QNetworkReply *reply)
|
|||||||
const int httpStatus =
|
const int httpStatus =
|
||||||
reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
if ( httpStatus == 503 ) {
|
if ( httpStatus == 503 ) {
|
||||||
// Is this a maintenance mode reply from the server
|
_errors.clear();
|
||||||
// or a regular 503 from somewhere else?
|
stat = ServiceUnavailable;
|
||||||
QByteArray body = reply->readAll();
|
|
||||||
if ( body.contains("Sabre\\DAV\\Exception\\ServiceUnavailable") ) {
|
|
||||||
_errors.clear();
|
|
||||||
stat = ServerMaintenance;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public:
|
|||||||
CredentialsWrong,
|
CredentialsWrong,
|
||||||
StatusNotFound,
|
StatusNotFound,
|
||||||
UserCanceledCredentials,
|
UserCanceledCredentials,
|
||||||
ServerMaintenance,
|
ServiceUnavailable,
|
||||||
// actually also used for other errors on the authed request
|
// actually also used for other errors on the authed request
|
||||||
Timeout
|
Timeout
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QNetworkCookie>
|
#include <QNetworkCookie>
|
||||||
|
#include <QDataStream>
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class OWNCLOUDSYNC_EXPORT HttpCredentialsGui : public HttpCredentials {
|
class OWNCLOUDSYNC_EXPORT HttpCredentialsGui : public HttpCredentials {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit HttpCredentialsGui() : HttpCredentials() {}
|
explicit HttpCredentialsGui() : HttpCredentials() {}
|
||||||
HttpCredentialsGui(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd) : HttpCredentials(user, password, certificatePath, certificatePasswd) {}
|
HttpCredentialsGui(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd) : HttpCredentials(user, password, certificatePath, certificatePasswd) {}
|
||||||
|
|||||||
@@ -83,21 +83,11 @@ void DiscoveryJob::update_job_update_callback (bool local,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only use for error cases! It will always set an error errno
|
||||||
int get_errno_from_http_errcode( int err, const QString & reason ) {
|
int get_errno_from_http_errcode( int err, const QString & reason ) {
|
||||||
int new_errno = 0;
|
int new_errno = EIO;
|
||||||
|
|
||||||
switch(err) {
|
switch(err) {
|
||||||
case 200: /* OK */
|
|
||||||
case 201: /* Created */
|
|
||||||
case 202: /* Accepted */
|
|
||||||
case 203: /* Non-Authoritative Information */
|
|
||||||
case 204: /* No Content */
|
|
||||||
case 205: /* Reset Content */
|
|
||||||
case 207: /* Multi-Status */
|
|
||||||
case 304: /* Not Modified */
|
|
||||||
new_errno = 0;
|
|
||||||
break;
|
|
||||||
case 401: /* Unauthorized */
|
case 401: /* Unauthorized */
|
||||||
case 402: /* Payment Required */
|
case 402: /* Payment Required */
|
||||||
case 407: /* Proxy Authentication Required */
|
case 407: /* Proxy Authentication Required */
|
||||||
@@ -316,7 +306,7 @@ void DiscoverySingleDirectoryJob::lsJobFinishedWithErrorSlot(QNetworkReply *r)
|
|||||||
// Default keep at EIO, see above
|
// Default keep at EIO, see above
|
||||||
}
|
}
|
||||||
|
|
||||||
emit finishedWithError(errnoCode, msg);
|
emit finishedWithError(errnoCode == 0 ? EIO : errnoCode, msg);
|
||||||
deleteLater();
|
deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,13 @@
|
|||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QCoreApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
|
||||||
|
#ifdef ZLIB_FOUND
|
||||||
|
#include <zlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||||
#include <qabstractfileengine.h>
|
#include <qabstractfileengine.h>
|
||||||
@@ -155,7 +161,50 @@ bool FileSystem::rename(const QString &originFileName,
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileSystem::renameReplace(const QString& originFileName, const QString& destinationFileName, QString* errorString)
|
bool FileSystem::fileChanged(const QString& fileName,
|
||||||
|
qint64 previousSize,
|
||||||
|
time_t previousMtime)
|
||||||
|
{
|
||||||
|
return getSize(fileName) != previousSize
|
||||||
|
|| getModTime(fileName) != previousMtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileSystem::verifyFileUnchanged(const QString& fileName,
|
||||||
|
qint64 previousSize,
|
||||||
|
time_t previousMtime)
|
||||||
|
{
|
||||||
|
const qint64 actualSize = getSize(fileName);
|
||||||
|
const time_t actualMtime = getModTime(fileName);
|
||||||
|
if (actualSize != previousSize || actualMtime != previousMtime) {
|
||||||
|
qDebug() << "File" << fileName << "has changed:"
|
||||||
|
<< "size: " << previousSize << "<->" << actualSize
|
||||||
|
<< ", mtime: " << previousMtime << "<->" << actualMtime;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileSystem::renameReplace(const QString& originFileName,
|
||||||
|
const QString& destinationFileName,
|
||||||
|
qint64 destinationSize,
|
||||||
|
time_t destinationMtime,
|
||||||
|
QString* errorString)
|
||||||
|
{
|
||||||
|
if (fileExists(destinationFileName)
|
||||||
|
&& fileChanged(destinationFileName, destinationSize, destinationMtime)) {
|
||||||
|
if (errorString) {
|
||||||
|
*errorString = qApp->translate("FileSystem",
|
||||||
|
"The destination file has an unexpected size or modification time");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uncheckedRenameReplace(originFileName, destinationFileName, errorString);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileSystem::uncheckedRenameReplace(const QString& originFileName,
|
||||||
|
const QString& destinationFileName,
|
||||||
|
QString* errorString)
|
||||||
{
|
{
|
||||||
#ifndef Q_OS_WIN
|
#ifndef Q_OS_WIN
|
||||||
bool success;
|
bool success;
|
||||||
@@ -350,4 +399,58 @@ QString FileSystem::fileSystemForPath(const QString & path)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define BUFSIZE 1024*1024*10
|
||||||
|
|
||||||
|
static QByteArray readToCrypto( const QString& filename, QCryptographicHash::Algorithm algo )
|
||||||
|
{
|
||||||
|
const qint64 bufSize = BUFSIZE;
|
||||||
|
QByteArray buf(bufSize,0);
|
||||||
|
QByteArray arr;
|
||||||
|
QCryptographicHash crypto( algo );
|
||||||
|
|
||||||
|
QFile file(filename);
|
||||||
|
if (file.open(QIODevice::ReadOnly)) {
|
||||||
|
qint64 size;
|
||||||
|
while (!file.atEnd()) {
|
||||||
|
size = file.read( buf.data(), bufSize );
|
||||||
|
if( size > 0 ) {
|
||||||
|
crypto.addData(buf.data(), size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr = crypto.result().toHex();
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray FileSystem::calcMd5( const QString& filename )
|
||||||
|
{
|
||||||
|
return readToCrypto( filename, QCryptographicHash::Md5 );
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray FileSystem::calcSha1( const QString& filename )
|
||||||
|
{
|
||||||
|
return readToCrypto( filename, QCryptographicHash::Sha1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ZLIB_FOUND
|
||||||
|
QByteArray FileSystem::calcAdler32( const QString& filename )
|
||||||
|
{
|
||||||
|
unsigned int adler = adler32(0L, Z_NULL, 0);
|
||||||
|
const qint64 bufSize = BUFSIZE;
|
||||||
|
QByteArray buf(bufSize, 0);
|
||||||
|
|
||||||
|
QFile file(filename);
|
||||||
|
if (file.open(QIODevice::ReadOnly)) {
|
||||||
|
qint64 size;
|
||||||
|
while (!file.atEnd()) {
|
||||||
|
size = file.read(buf.data(), bufSize);
|
||||||
|
if( size > 0 )
|
||||||
|
adler = adler32(adler, (const Bytef*) buf.data(), size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QByteArray::number( adler, 16 );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|||||||
@@ -13,8 +13,11 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
|
||||||
#include <owncloudlib.h>
|
#include <owncloudlib.h>
|
||||||
|
|
||||||
@@ -67,13 +70,44 @@ bool OWNCLOUDSYNC_EXPORT fileExists(const QString& filename);
|
|||||||
bool OWNCLOUDSYNC_EXPORT rename(const QString& originFileName,
|
bool OWNCLOUDSYNC_EXPORT rename(const QString& originFileName,
|
||||||
const QString& destinationFileName,
|
const QString& destinationFileName,
|
||||||
QString* errorString = NULL);
|
QString* errorString = NULL);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rename the file \a originFileName to \a destinationFileName, and overwrite the destination if it
|
* Returns true if the file's mtime or size are not what is expected.
|
||||||
* already exists
|
* Nonexisting files are covered through mtime: they have an mtime of -1.
|
||||||
*/
|
*/
|
||||||
bool renameReplace(const QString &originFileName, const QString &destinationFileName,
|
bool fileChanged(const QString& fileName,
|
||||||
|
qint64 previousSize,
|
||||||
|
time_t previousMtime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like !fileChanged() but with verbose logging if the file *did* change.
|
||||||
|
*/
|
||||||
|
bool verifyFileUnchanged(const QString& fileName,
|
||||||
|
qint64 previousSize,
|
||||||
|
time_t previousMtime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename the file \a originFileName to \a destinationFileName, and
|
||||||
|
* overwrite the destination if it already exists - as long as the
|
||||||
|
* destination file has the expected \a destinationSize and
|
||||||
|
* \a destinationMtime.
|
||||||
|
* If the destination file does not exist, the given size and mtime are
|
||||||
|
* ignored.
|
||||||
|
*/
|
||||||
|
bool renameReplace(const QString &originFileName,
|
||||||
|
const QString &destinationFileName,
|
||||||
|
qint64 destinationSize,
|
||||||
|
time_t destinationMtime,
|
||||||
QString *errorString);
|
QString *errorString);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename the file \a originFileName to \a destinationFileName, and
|
||||||
|
* overwrite the destination if it already exists - without extra checks.
|
||||||
|
*/
|
||||||
|
bool uncheckedRenameReplace(const QString &originFileName,
|
||||||
|
const QString &destinationFileName,
|
||||||
|
QString *errorString);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replacement for QFile::open(ReadOnly) followed by a seek().
|
* Replacement for QFile::open(ReadOnly) followed by a seek().
|
||||||
* This version sets a more permissive sharing mode on Windows.
|
* This version sets a more permissive sharing mode on Windows.
|
||||||
@@ -90,4 +124,10 @@ bool openAndSeekFileSharedRead(QFile* file, QString* error, qint64 seek);
|
|||||||
QString fileSystemForPath(const QString & path);
|
QString fileSystemForPath(const QString & path);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
QByteArray calcMd5( const QString& fileName );
|
||||||
|
QByteArray calcSha1( const QString& fileName );
|
||||||
|
#ifdef ZLIB_FOUND
|
||||||
|
QByteArray calcAdler32( const QString& fileName );
|
||||||
|
#endif
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ namespace OCC {
|
|||||||
|
|
||||||
AbstractNetworkJob::AbstractNetworkJob(AccountPtr account, const QString &path, QObject *parent)
|
AbstractNetworkJob::AbstractNetworkJob(AccountPtr account, const QString &path, QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, _duration(0)
|
|
||||||
, _timedout(false)
|
, _timedout(false)
|
||||||
, _followRedirects(false)
|
, _followRedirects(false)
|
||||||
, _ignoreCredentialFailure(false)
|
, _ignoreCredentialFailure(false)
|
||||||
@@ -307,8 +306,12 @@ MkColJob::MkColJob(AccountPtr account, const QString &path, QObject *parent)
|
|||||||
|
|
||||||
void MkColJob::start()
|
void MkColJob::start()
|
||||||
{
|
{
|
||||||
// assumes ownership
|
// add 'Content-Length: 0' header (see https://github.com/owncloud/client/issues/3256)
|
||||||
QNetworkReply *reply = davRequest("MKCOL", path());
|
QNetworkRequest req;
|
||||||
|
req.setRawHeader("Content-Length", "0");
|
||||||
|
|
||||||
|
// assumes ownership
|
||||||
|
QNetworkReply *reply = davRequest("MKCOL", path(), req);
|
||||||
setReply(reply);
|
setReply(reply);
|
||||||
setupConnections(reply);
|
setupConnections(reply);
|
||||||
AbstractNetworkJob::start();
|
AbstractNetworkJob::start();
|
||||||
@@ -350,7 +353,7 @@ LsColXMLParser::LsColXMLParser()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LsColXMLParser::parse( const QByteArray& xml, QHash<QString, qint64> *sizes)
|
bool LsColXMLParser::parse( const QByteArray& xml, QHash<QString, qint64> *sizes, const QString& expectedPath)
|
||||||
{
|
{
|
||||||
// Parse DAV response
|
// Parse DAV response
|
||||||
QXmlStreamReader reader(xml);
|
QXmlStreamReader reader(xml);
|
||||||
@@ -371,7 +374,14 @@ bool LsColXMLParser::parse( const QByteArray& xml, QHash<QString, qint64> *sizes
|
|||||||
// Start elements with DAV:
|
// Start elements with DAV:
|
||||||
if (type == QXmlStreamReader::StartElement && reader.namespaceUri() == QLatin1String("DAV:")) {
|
if (type == QXmlStreamReader::StartElement && reader.namespaceUri() == QLatin1String("DAV:")) {
|
||||||
if (name == QLatin1String("href")) {
|
if (name == QLatin1String("href")) {
|
||||||
currentHref = QUrl::fromPercentEncoding(reader.readElementText().toUtf8());
|
// We don't use URL encoding in our request URL (which is the expected path) (QNAM will do it for us)
|
||||||
|
// but the result will have URL encoding..
|
||||||
|
QString hrefString = QString::fromUtf8(QByteArray::fromPercentEncoding(reader.readElementText().toUtf8()));
|
||||||
|
if (!hrefString.startsWith(expectedPath)) {
|
||||||
|
qDebug() << "Invalid href" << hrefString << "expected starting with" << expectedPath;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
currentHref = hrefString;
|
||||||
} else if (name == QLatin1String("response")) {
|
} else if (name == QLatin1String("response")) {
|
||||||
} else if (name == QLatin1String("propstat")) {
|
} else if (name == QLatin1String("propstat")) {
|
||||||
insidePropstat = true;
|
insidePropstat = true;
|
||||||
@@ -520,7 +530,8 @@ bool LsColJob::finished()
|
|||||||
connect( &parser, SIGNAL(finishedWithoutError()),
|
connect( &parser, SIGNAL(finishedWithoutError()),
|
||||||
this, SIGNAL(finishedWithoutError()) );
|
this, SIGNAL(finishedWithoutError()) );
|
||||||
|
|
||||||
if( !parser.parse( reply()->readAll(), &_sizes ) ) {
|
QString expectedPath = reply()->request().url().path(); // something like "/owncloud/remote.php/webdav/folder"
|
||||||
|
if( !parser.parse( reply()->readAll(), &_sizes, expectedPath ) ) {
|
||||||
// XML parse error
|
// XML parse error
|
||||||
emit finishedWithError(reply());
|
emit finishedWithError(reply());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ class OWNCLOUDSYNC_EXPORT LsColXMLParser : public QObject {
|
|||||||
public:
|
public:
|
||||||
explicit LsColXMLParser();
|
explicit LsColXMLParser();
|
||||||
|
|
||||||
bool parse(const QByteArray &xml, QHash<QString, qint64> *sizes);
|
bool parse(const QByteArray &xml, QHash<QString, qint64> *sizes, const QString& expectedPath);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void directoryListingSubfolders(const QStringList &items);
|
void directoryListingSubfolders(const QStringList &items);
|
||||||
|
|||||||
@@ -259,6 +259,21 @@ void OwncloudPropagator::start(const SyncFileItemVector& items)
|
|||||||
{
|
{
|
||||||
Q_ASSERT(std::is_sorted(items.begin(), items.end()));
|
Q_ASSERT(std::is_sorted(items.begin(), items.end()));
|
||||||
|
|
||||||
|
/* Check and log the transmission checksum type */
|
||||||
|
ConfigFile cfg;
|
||||||
|
const QString checksumType = cfg.transmissionChecksum().toUpper();
|
||||||
|
|
||||||
|
/* if the checksum type is empty, it is not send. No error */
|
||||||
|
if( !checksumType.isEmpty() ) {
|
||||||
|
if( checksumType == checkSumAdlerUpperC ||
|
||||||
|
checksumType == checkSumMD5C ||
|
||||||
|
checksumType == checkSumSHA1C ) {
|
||||||
|
qDebug() << "Client sends and expects transmission checksum type" << checksumType;
|
||||||
|
} else {
|
||||||
|
qWarning() << "Unknown transmission checksum type from config" << checksumType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* This builds all the job needed for the propagation.
|
/* This builds all the job needed for the propagation.
|
||||||
* Each directories is a PropagateDirectory job, which contains the files in it.
|
* Each directories is a PropagateDirectory job, which contains the files in it.
|
||||||
* In order to do that we loop over the items. (which are sorted by destination)
|
* In order to do that we loop over the items. (which are sorted by destination)
|
||||||
|
|||||||
@@ -345,7 +345,7 @@ QString SqlQuery::lastQuery() const
|
|||||||
|
|
||||||
int SqlQuery::numRowsAffected()
|
int SqlQuery::numRowsAffected()
|
||||||
{
|
{
|
||||||
return 1;
|
return sqlite3_changes(_db);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SqlQuery::finish()
|
void SqlQuery::finish()
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
* for more details.
|
* for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "owncloudpropagator_p.h"
|
#include "owncloudpropagator_p.h"
|
||||||
#include "propagatedownload.h"
|
#include "propagatedownload.h"
|
||||||
#include "networkjobs.h"
|
#include "networkjobs.h"
|
||||||
@@ -21,6 +22,8 @@
|
|||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
#include "propagatorjobs.h"
|
#include "propagatorjobs.h"
|
||||||
|
#include "transmissionchecksumvalidator.h"
|
||||||
|
|
||||||
#include <json.h>
|
#include <json.h>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
@@ -30,6 +33,30 @@
|
|||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
|
// Always coming in with forward slashes.
|
||||||
|
// In csync_excluded_no_ctx we ignore all files with longer than 254 chars
|
||||||
|
// This function also adds a dot at the begining of the filename to hide the file on OS X and Linux
|
||||||
|
QString OWNCLOUDSYNC_EXPORT createDownloadTmpFileName(const QString &previous) {
|
||||||
|
QString tmpFileName;
|
||||||
|
QString tmpPath;
|
||||||
|
int slashPos = previous.lastIndexOf('/');
|
||||||
|
// work with both pathed filenames and only filenames
|
||||||
|
if (slashPos == -1) {
|
||||||
|
tmpFileName = previous;
|
||||||
|
tmpPath = QString();
|
||||||
|
} else {
|
||||||
|
tmpFileName = previous.mid(slashPos+1);
|
||||||
|
tmpPath = previous.left(slashPos);
|
||||||
|
}
|
||||||
|
int overhead = 1 + 1 + 2 + 8; // slash dot dot-tilde ffffffff"
|
||||||
|
int spaceForFileName = qMin(254, tmpFileName.length() + overhead) - overhead;
|
||||||
|
if (tmpPath.length() > 0) {
|
||||||
|
return tmpPath + '/' + '.' + tmpFileName.left(spaceForFileName) + ".~" + (QString::number(uint(qrand() % 0xFFFFFFFF), 16));
|
||||||
|
} else {
|
||||||
|
return '.' + tmpFileName.left(spaceForFileName) + ".~" + (QString::number(uint(qrand() % 0xFFFFFFFF), 16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DOES NOT take owncership of the device.
|
// DOES NOT take owncership of the device.
|
||||||
GETFileJob::GETFileJob(AccountPtr account, const QString& path, QFile *device,
|
GETFileJob::GETFileJob(AccountPtr account, const QString& path, QFile *device,
|
||||||
const QMap<QByteArray, QByteArray> &headers, const QByteArray &expectedEtagForResume,
|
const QMap<QByteArray, QByteArray> &headers, const QByteArray &expectedEtagForResume,
|
||||||
@@ -307,12 +334,7 @@ void PropagateDownloadFileQNAM::start()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tmpFileName.isEmpty()) {
|
if (tmpFileName.isEmpty()) {
|
||||||
tmpFileName = _item._file;
|
tmpFileName = createDownloadTmpFileName(_item._file);
|
||||||
//add a dot at the begining of the filename to hide the file.
|
|
||||||
int slashPos = tmpFileName.lastIndexOf('/');
|
|
||||||
tmpFileName.insert(slashPos+1, '.');
|
|
||||||
//add the suffix
|
|
||||||
tmpFileName += ".~" + QString::number(uint(qrand()), 16);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_tmpFile.setFileName(_propagator->getFilePath(tmpFileName));
|
_tmpFile.setFileName(_propagator->getFilePath(tmpFileName));
|
||||||
@@ -339,6 +361,7 @@ void PropagateDownloadFileQNAM::start()
|
|||||||
if (startSize > 0) {
|
if (startSize > 0) {
|
||||||
if (startSize == _item._size) {
|
if (startSize == _item._size) {
|
||||||
qDebug() << "File is already complete, no need to download";
|
qDebug() << "File is already complete, no need to download";
|
||||||
|
_tmpFile.close();
|
||||||
downloadFinished();
|
downloadFinished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -463,7 +486,21 @@ void PropagateDownloadFileQNAM::slotGetFinished()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadFinished();
|
// Do checksum validation for the download. If there is no checksum header, the validator
|
||||||
|
// will also emit the validated() signal to continue the flow in slot downloadFinished()
|
||||||
|
// as this is (still) also correct.
|
||||||
|
TransmissionChecksumValidator *validator = new TransmissionChecksumValidator(_tmpFile.fileName(), this);
|
||||||
|
connect(validator, SIGNAL(validated(QByteArray)), this, SLOT(downloadFinished()));
|
||||||
|
connect(validator, SIGNAL(validationFailed(QString)), this, SLOT(slotChecksumFail(QString)));
|
||||||
|
validator->downloadValidation(job->reply()->rawHeader(checkSumHeaderC));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropagateDownloadFileQNAM::slotChecksumFail( const QString& errMsg )
|
||||||
|
{
|
||||||
|
_tmpFile.remove();
|
||||||
|
_propagator->_anotherSyncNeeded = true;
|
||||||
|
done(SyncFileItem::SoftError, errMsg ); // tr("The file downloaded with a broken checksum, will be redownloaded."));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString makeConflictFileName(const QString &fn, const QDateTime &dt)
|
QString makeConflictFileName(const QString &fn, const QDateTime &dt)
|
||||||
@@ -487,9 +524,54 @@ QString makeConflictFileName(const QString &fn, const QDateTime &dt)
|
|||||||
return conflictFileName;
|
return conflictFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace { // Anonymous namespace for the recall feature
|
||||||
|
static QString makeRecallFileName(const QString &fn)
|
||||||
|
{
|
||||||
|
QString recallFileName(fn);
|
||||||
|
// Add _recall-XXXX before the extention.
|
||||||
|
int dotLocation = recallFileName.lastIndexOf('.');
|
||||||
|
// If no extention, add it at the end (take care of cases like foo/.hidden or foo.bar/file)
|
||||||
|
if (dotLocation <= recallFileName.lastIndexOf('/') + 1) {
|
||||||
|
dotLocation = recallFileName.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString timeString = QDateTime::currentDateTime().toString("yyyyMMdd-hhmmss");
|
||||||
|
recallFileName.insert(dotLocation, "_.sys.admin#recall#-" + timeString);
|
||||||
|
|
||||||
|
return recallFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleRecallFile(const QString &fn)
|
||||||
|
{
|
||||||
|
qDebug() << "handleRecallFile: " << fn;
|
||||||
|
|
||||||
|
FileSystem::setFileHidden(fn, true);
|
||||||
|
|
||||||
|
QFile file(fn);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
qWarning() << "Could not open recall file" << file.errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QFileInfo existingFile(fn);
|
||||||
|
QDir thisDir = existingFile.dir();
|
||||||
|
|
||||||
|
while (!file.atEnd()) {
|
||||||
|
QByteArray line = file.readLine();
|
||||||
|
line.chop(1); // remove trailing \n
|
||||||
|
QString fpath = thisDir.filePath(line);
|
||||||
|
QString rpath = makeRecallFileName(fpath);
|
||||||
|
|
||||||
|
// if previously recalled file exists then remove it (copy will not overwrite it)
|
||||||
|
QFile(rpath).remove();
|
||||||
|
qDebug() << "Copy recall file: " << fpath << " -> " << rpath;
|
||||||
|
QFile::copy(fpath,rpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // end namespace
|
||||||
|
|
||||||
void PropagateDownloadFileQNAM::downloadFinished()
|
void PropagateDownloadFileQNAM::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
|
||||||
@@ -512,11 +594,7 @@ void PropagateDownloadFileQNAM::downloadFinished()
|
|||||||
done(SyncFileItem::SoftError, renameError);
|
done(SyncFileItem::SoftError, renameError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
qDebug() << "Created conflict file" << fn << "->" << conflictFileName;
|
||||||
|
|
||||||
QFileInfo existingFile(fn);
|
|
||||||
if(FileSystem::fileExists(fn) && existingFile.permissions() != _tmpFile.permissions()) {
|
|
||||||
_tmpFile.setPermissions(existingFile.permissions());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSystem::setModTime(_tmpFile.fileName(), _item._modtime);
|
FileSystem::setModTime(_tmpFile.fileName(), _item._modtime);
|
||||||
@@ -524,11 +602,32 @@ void PropagateDownloadFileQNAM::downloadFinished()
|
|||||||
// Accuracy, and we really need the time from the file system. (#3103)
|
// Accuracy, and we really need the time from the file system. (#3103)
|
||||||
_item._modtime = FileSystem::getModTime(_tmpFile.fileName());
|
_item._modtime = FileSystem::getModTime(_tmpFile.fileName());
|
||||||
|
|
||||||
|
if (FileSystem::fileExists(fn)) {
|
||||||
|
// Preserve the existing file permissions.
|
||||||
|
QFileInfo existingFile(fn);
|
||||||
|
if (existingFile.permissions() != _tmpFile.permissions()) {
|
||||||
|
_tmpFile.setPermissions(existingFile.permissions());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether the existing file has changed since the discovery
|
||||||
|
// phase by comparing size and mtime to the previous values. This
|
||||||
|
// is necessary to avoid overwriting user changes that happened between
|
||||||
|
// the discovery phase and now.
|
||||||
|
const qint64 expectedSize = _item.log._other_size;
|
||||||
|
const time_t expectedMtime = _item.log._other_modtime;
|
||||||
|
if (! FileSystem::verifyFileUnchanged(fn, expectedSize, expectedMtime)) {
|
||||||
|
_propagator->_anotherSyncNeeded = true;
|
||||||
|
done(SyncFileItem::SoftError, tr("File has changed since discovery"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString error;
|
QString error;
|
||||||
_propagator->addTouchedFile(fn);
|
_propagator->addTouchedFile(fn);
|
||||||
FileSystem::setFileHidden(_tmpFile.fileName(), false);
|
// The fileChanged() check is done above to generate better error messages.
|
||||||
if (!FileSystem::renameReplace(_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);
|
||||||
|
|
||||||
// If we moved away the original file due to a conflict but can't
|
// If we moved away the original file due to a conflict but can't
|
||||||
// put the downloaded file in its place, we are in a bad spot:
|
// put the downloaded file in its place, we are in a bad spot:
|
||||||
// If we do nothing the next sync run will assume the user deleted
|
// If we do nothing the next sync run will assume the user deleted
|
||||||
@@ -540,10 +639,12 @@ void PropagateDownloadFileQNAM::downloadFinished()
|
|||||||
_propagator->_journal->deleteFileRecord(fn);
|
_propagator->_journal->deleteFileRecord(fn);
|
||||||
_propagator->_journal->commit("download finished");
|
_propagator->_journal->commit("download finished");
|
||||||
}
|
}
|
||||||
|
|
||||||
_propagator->_anotherSyncNeeded = true;
|
_propagator->_anotherSyncNeeded = true;
|
||||||
done(SyncFileItem::SoftError, error);
|
done(SyncFileItem::SoftError, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
FileSystem::setFileHidden(fn, false);
|
||||||
|
|
||||||
// Maybe we downloaded a newer version of the file than we thought we would...
|
// Maybe we downloaded a newer version of the file than we thought we would...
|
||||||
// Get up to date information for the journal.
|
// Get up to date information for the journal.
|
||||||
@@ -553,6 +654,11 @@ void PropagateDownloadFileQNAM::downloadFinished()
|
|||||||
_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
|
||||||
|
if(_item._file == QLatin1String(".sys.admin#recall#") || _item._file.endsWith("/.sys.admin#recall#")) {
|
||||||
|
handleRecallFile(fn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PropagateDownloadFileQNAM::slotDownloadProgress(qint64 received, qint64)
|
void PropagateDownloadFileQNAM::slotDownloadProgress(qint64 received, qint64)
|
||||||
|
|||||||
@@ -101,19 +101,21 @@ private slots:
|
|||||||
|
|
||||||
class PropagateDownloadFileQNAM : public PropagateItemJob {
|
class PropagateDownloadFileQNAM : public PropagateItemJob {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QPointer<GETFileJob> _job;
|
|
||||||
|
|
||||||
// QFile *_file;
|
|
||||||
QFile _tmpFile;
|
|
||||||
public:
|
public:
|
||||||
PropagateDownloadFileQNAM(OwncloudPropagator* propagator,const SyncFileItem& item)
|
PropagateDownloadFileQNAM(OwncloudPropagator* propagator,const SyncFileItem& item)
|
||||||
: PropagateItemJob(propagator, item) {}
|
: PropagateItemJob(propagator, item) {}
|
||||||
void start() Q_DECL_OVERRIDE;
|
void start() Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void slotGetFinished();
|
void slotGetFinished();
|
||||||
void abort() Q_DECL_OVERRIDE;
|
void abort() Q_DECL_OVERRIDE;
|
||||||
void downloadFinished();
|
void downloadFinished();
|
||||||
void slotDownloadProgress(qint64,qint64);
|
void slotDownloadProgress(qint64,qint64);
|
||||||
|
void slotChecksumFail( const QString& errMsg );
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPointer<GETFileJob> _job;
|
||||||
|
QFile _tmpFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
* for more details.
|
* for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "propagateupload.h"
|
#include "propagateupload.h"
|
||||||
#include "owncloudpropagator_p.h"
|
#include "owncloudpropagator_p.h"
|
||||||
#include "networkjobs.h"
|
#include "networkjobs.h"
|
||||||
@@ -21,6 +22,8 @@
|
|||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
#include "propagatorjobs.h"
|
#include "propagatorjobs.h"
|
||||||
|
#include "transmissionchecksumvalidator.h"
|
||||||
|
|
||||||
#include <json.h>
|
#include <json.h>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
@@ -32,6 +35,12 @@
|
|||||||
#include "propagator_legacy.h"
|
#include "propagator_legacy.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5, 4, 2)
|
||||||
|
namespace {
|
||||||
|
const char owncloudShouldSoftCancelPropertyName[] = "owncloud-should-soft-cancel";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -86,6 +95,17 @@ void PUTFileJob::start() {
|
|||||||
connect(reply(), SIGNAL(uploadProgress(qint64,qint64)), this, SIGNAL(uploadProgress(qint64,qint64)));
|
connect(reply(), SIGNAL(uploadProgress(qint64,qint64)), this, SIGNAL(uploadProgress(qint64,qint64)));
|
||||||
connect(this, SIGNAL(networkActivity()), account().data(), SIGNAL(propagatorNetworkActivity()));
|
connect(this, SIGNAL(networkActivity()), account().data(), SIGNAL(propagatorNetworkActivity()));
|
||||||
|
|
||||||
|
// For Qt versions not including https://codereview.qt-project.org/110150
|
||||||
|
// Also do the runtime check if compiled with an old Qt but running with fixed one.
|
||||||
|
// (workaround disabled on windows and mac because the binaries we ship have patched qt)
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(4, 8, 7)
|
||||||
|
if (QLatin1String(qVersion()) < QLatin1String("4.8.7"))
|
||||||
|
connect(_device.data(), SIGNAL(wasReset()), this, SLOT(slotSoftAbort()));
|
||||||
|
#elif QT_VERSION > QT_VERSION_CHECK(5, 0, 0) && QT_VERSION < QT_VERSION_CHECK(5, 4, 2) && !defined Q_OS_WIN && !defined Q_OS_MAC
|
||||||
|
if (QLatin1String(qVersion()) < QLatin1String("5.4.2"))
|
||||||
|
connect(_device.data(), SIGNAL(wasReset()), this, SLOT(slotSoftAbort()));
|
||||||
|
#endif
|
||||||
|
|
||||||
AbstractNetworkJob::start();
|
AbstractNetworkJob::start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +114,13 @@ void PUTFileJob::slotTimeout() {
|
|||||||
reply()->abort();
|
reply()->abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5, 4, 2)
|
||||||
|
void PUTFileJob::slotSoftAbort() {
|
||||||
|
reply()->setProperty(owncloudShouldSoftCancelPropertyName, true);
|
||||||
|
reply()->abort();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void PollJob::start()
|
void PollJob::start()
|
||||||
{
|
{
|
||||||
setTimeout(120 * 1000);
|
setTimeout(120 * 1000);
|
||||||
@@ -167,22 +194,51 @@ bool PollJob::finished()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PropagateUploadFileQNAM::start()
|
void PropagateUploadFileQNAM::start()
|
||||||
{
|
{
|
||||||
if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) {
|
if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QString filePath = _propagator->getFilePath(_item._file);
|
||||||
|
|
||||||
|
// remember the modtime before checksumming to be able to detect a file
|
||||||
|
// change during the checksum calculation
|
||||||
|
_item._modtime = FileSystem::getModTime(filePath);
|
||||||
|
|
||||||
|
_stopWatch.start();
|
||||||
|
|
||||||
|
// do whatever is needed to add a checksum to the http upload request.
|
||||||
|
// in any case, the validator will emit signal startUpload to let the flow
|
||||||
|
// continue in slotStartUpload here.
|
||||||
|
TransmissionChecksumValidator *validator = new TransmissionChecksumValidator(filePath, this);
|
||||||
|
connect(validator, SIGNAL(validated(QByteArray)), this, SLOT(slotStartUpload(QByteArray)));
|
||||||
|
validator->uploadValidation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropagateUploadFileQNAM::slotStartUpload(const QByteArray& checksum)
|
||||||
|
{
|
||||||
const QString fullFilePath(_propagator->getFilePath(_item._file));
|
const QString fullFilePath(_propagator->getFilePath(_item._file));
|
||||||
|
|
||||||
|
_item._checksum = checksum;
|
||||||
|
|
||||||
if (!FileSystem::fileExists(fullFilePath)) {
|
if (!FileSystem::fileExists(fullFilePath)) {
|
||||||
done(SyncFileItem::SoftError, tr("File Removed"));
|
done(SyncFileItem::SoftError, tr("File Removed"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
_stopWatch.addLapTime(QLatin1String("Checksum"));
|
||||||
|
|
||||||
|
time_t prevModtime = _item._modtime; // the _item value was set in PropagateUploadFileQNAM::start()
|
||||||
|
// but a potential checksum calculation could have taken some time during which the file could
|
||||||
|
// have been changed again, so better check again here.
|
||||||
|
|
||||||
// Update the mtime and size, it might have changed since discovery.
|
|
||||||
_item._modtime = FileSystem::getModTime(fullFilePath);
|
_item._modtime = FileSystem::getModTime(fullFilePath);
|
||||||
|
if( prevModtime != _item._modtime ) {
|
||||||
|
_propagator->_anotherSyncNeeded = true;
|
||||||
|
done(SyncFileItem::SoftError, tr("Local file changed during syncing. It will be resumed."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
quint64 fileSize = FileSystem::getSize(fullFilePath);
|
quint64 fileSize = FileSystem::getSize(fullFilePath);
|
||||||
_item._size = fileSize;
|
_item._size = fileSize;
|
||||||
|
|
||||||
@@ -369,6 +425,18 @@ void PropagateUploadFileQNAM::startNextChunk()
|
|||||||
headers["OC-Chunk-Size"]= QByteArray::number(quint64(chunkSize()));
|
headers["OC-Chunk-Size"]= QByteArray::number(quint64(chunkSize()));
|
||||||
headers["Content-Type"] = "application/octet-stream";
|
headers["Content-Type"] = "application/octet-stream";
|
||||||
headers["X-OC-Mtime"] = QByteArray::number(qint64(_item._modtime));
|
headers["X-OC-Mtime"] = QByteArray::number(qint64(_item._modtime));
|
||||||
|
|
||||||
|
if(_item._file.contains(".sys.admin#recall#")) {
|
||||||
|
// This is a file recall triggered by the admin. Note: the
|
||||||
|
// recall list file created by the admin and downloaded by the
|
||||||
|
// client (.sys.admin#recall#) also falls into this category
|
||||||
|
// (albeit users are not supposed to mess up with it)
|
||||||
|
|
||||||
|
// We use a special tag header so that the server may decide to store this file away in some admin stage area
|
||||||
|
// And not directly in the user's area (what would trigger redownloads etc).
|
||||||
|
headers["OC-Tag"] = ".sys.admin#recall#";
|
||||||
|
}
|
||||||
|
|
||||||
if (!_item._etag.isEmpty() && _item._etag != "empty_etag" &&
|
if (!_item._etag.isEmpty() && _item._etag != "empty_etag" &&
|
||||||
_item._instruction != CSYNC_INSTRUCTION_NEW // On new files never send a If-Match
|
_item._instruction != CSYNC_INSTRUCTION_NEW // On new files never send a If-Match
|
||||||
) {
|
) {
|
||||||
@@ -397,6 +465,14 @@ void PropagateUploadFileQNAM::startNextChunk()
|
|||||||
if( currentChunkSize == 0 ) { // if the last chunk pretents to be 0, its actually the full chunk size.
|
if( currentChunkSize == 0 ) { // if the last chunk pretents to be 0, its actually the full chunk size.
|
||||||
currentChunkSize = chunkSize();
|
currentChunkSize = chunkSize();
|
||||||
}
|
}
|
||||||
|
if( !_item._checksum.isEmpty() ) {
|
||||||
|
headers[checkSumHeaderC] = _item._checksum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// checksum if its only one chunk
|
||||||
|
if( !_item._checksum.isEmpty() ) {
|
||||||
|
headers[checkSumHeaderC] = _item._checksum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,6 +547,18 @@ void PropagateUploadFileQNAM::slotPutFinished()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QNetworkReply::NetworkError err = job->reply()->error();
|
QNetworkReply::NetworkError err = job->reply()->error();
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5, 4, 2)
|
||||||
|
if (err == QNetworkReply::OperationCanceledError && job->reply()->property(owncloudShouldSoftCancelPropertyName).isValid()) {
|
||||||
|
// 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.
|
||||||
|
qDebug() << "Forcing job abort on HTTP connection reset with Qt < 5.4.2.";
|
||||||
|
_propagator->_anotherSyncNeeded = true;
|
||||||
|
done(SyncFileItem::SoftError, tr("Forcing job abort on HTTP connection reset with Qt < 5.4.2."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (err != QNetworkReply::NoError) {
|
if (err != QNetworkReply::NoError) {
|
||||||
_item._httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
_item._httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
if(checkForProblemsWithShared(_item._httpErrorCode,
|
if(checkForProblemsWithShared(_item._httpErrorCode,
|
||||||
@@ -538,15 +626,8 @@ void PropagateUploadFileQNAM::slotPutFinished()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// compare expected and real modification time of the file and size
|
// Check whether the file changed since discovery.
|
||||||
const time_t new_mtime = FileSystem::getModTime(fullFilePath);
|
if (! FileSystem::verifyFileUnchanged(fullFilePath, _item._size, _item._modtime)) {
|
||||||
const quint64 new_size = static_cast<quint64>(FileSystem::getSize(fullFilePath));
|
|
||||||
QFileInfo fi(_propagator->getFilePath(_item._file));
|
|
||||||
if (new_mtime != _item._modtime || new_size != _item._size) {
|
|
||||||
qDebug() << "The local file has changed during upload:"
|
|
||||||
<< "mtime: " << _item._modtime << "<->" << new_mtime
|
|
||||||
<< ", size: " << _item._size << "<->" << new_size
|
|
||||||
<< ", QFileInfo: " << Utility::qDateTimeToTime_t(fi.lastModified()) << fi.lastModified();
|
|
||||||
_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."));
|
||||||
@@ -612,6 +693,11 @@ void PropagateUploadFileQNAM::slotPutFinished()
|
|||||||
// Well, the mtime was not set
|
// Well, the mtime was not set
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// performance logging
|
||||||
|
_item._requestDuration = _stopWatch.stop();
|
||||||
|
qDebug() << "*==* duration UPLOAD" << _item._size << _stopWatch.durationOfLap(QLatin1String("Checksum")) << _item._requestDuration;
|
||||||
|
|
||||||
finalize(_item);
|
finalize(_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
class BandwidthManager;
|
class BandwidthManager;
|
||||||
|
|
||||||
@@ -40,11 +41,21 @@ public:
|
|||||||
bool isSequential() const Q_DECL_OVERRIDE;
|
bool isSequential() const Q_DECL_OVERRIDE;
|
||||||
bool seek ( qint64 pos ) Q_DECL_OVERRIDE;
|
bool seek ( qint64 pos ) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5, 4, 2)
|
||||||
|
bool reset() Q_DECL_OVERRIDE { emit wasReset(); return QIODevice::reset(); }
|
||||||
|
#endif
|
||||||
|
|
||||||
void setBandwidthLimited(bool);
|
void setBandwidthLimited(bool);
|
||||||
bool isBandwidthLimited() { return _bandwidthLimited; }
|
bool isBandwidthLimited() { return _bandwidthLimited; }
|
||||||
void setChoked(bool);
|
void setChoked(bool);
|
||||||
bool isChoked() { return _choked; }
|
bool isChoked() { return _choked; }
|
||||||
void giveBandwidthQuota(qint64 bwq);
|
void giveBandwidthQuota(qint64 bwq);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
#if QT_VERSION < 0x050402
|
||||||
|
void wasReset();
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// The file data
|
// The file data
|
||||||
@@ -65,6 +76,8 @@ protected slots:
|
|||||||
|
|
||||||
class PUTFileJob : public AbstractNetworkJob {
|
class PUTFileJob : public AbstractNetworkJob {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
QScopedPointer<QIODevice> _device;
|
QScopedPointer<QIODevice> _device;
|
||||||
QMap<QByteArray, QByteArray> _headers;
|
QMap<QByteArray, QByteArray> _headers;
|
||||||
QString _errorString;
|
QString _errorString;
|
||||||
@@ -95,6 +108,11 @@ public:
|
|||||||
signals:
|
signals:
|
||||||
void finishedSignal();
|
void finishedSignal();
|
||||||
void uploadProgress(qint64,qint64);
|
void uploadProgress(qint64,qint64);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
#if QT_VERSION < 0x050402
|
||||||
|
void slotSoftAbort();
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -131,6 +149,7 @@ signals:
|
|||||||
class PropagateUploadFileQNAM : public PropagateItemJob {
|
class PropagateUploadFileQNAM : public PropagateItemJob {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
/**
|
/**
|
||||||
* That's the start chunk that was stored in the database for resuming.
|
* That's the start chunk that was stored in the database for resuming.
|
||||||
* In the non-resuming case it is 0.
|
* In the non-resuming case it is 0.
|
||||||
@@ -148,6 +167,10 @@ class PropagateUploadFileQNAM : public PropagateItemJob {
|
|||||||
QElapsedTimer _duration;
|
QElapsedTimer _duration;
|
||||||
QVector<PUTFileJob*> _jobs; /// network jobs that are currently in transit
|
QVector<PUTFileJob*> _jobs; /// network jobs that are currently in transit
|
||||||
bool _finished; // Tells that all the jobs have been finished
|
bool _finished; // Tells that all the jobs have been finished
|
||||||
|
|
||||||
|
// measure the performance of checksum calc and upload
|
||||||
|
Utility::StopWatch _stopWatch;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PropagateUploadFileQNAM(OwncloudPropagator* propagator,const SyncFileItem& item)
|
PropagateUploadFileQNAM(OwncloudPropagator* propagator,const SyncFileItem& item)
|
||||||
: PropagateItemJob(propagator, item), _startChunk(0), _currentChunk(0), _chunkCount(0), _transferId(0), _finished(false) {}
|
: PropagateItemJob(propagator, item), _startChunk(0), _currentChunk(0), _chunkCount(0), _transferId(0), _finished(false) {}
|
||||||
@@ -160,6 +183,8 @@ private slots:
|
|||||||
void startNextChunk();
|
void startNextChunk();
|
||||||
void finalize(const SyncFileItem&);
|
void finalize(const SyncFileItem&);
|
||||||
void slotJobDestroyed(QObject *job);
|
void slotJobDestroyed(QObject *job);
|
||||||
|
void slotStartUpload(const QByteArray &checksum);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void startPollJob(const QString& path);
|
void startPollJob(const QString& path);
|
||||||
void abortWithError(SyncFileItem::Status status, const QString &error);
|
void abortWithError(SyncFileItem::Status status, const QString &error);
|
||||||
|
|||||||
@@ -695,7 +695,8 @@ void PropagateDownloadFileLegacy::start()
|
|||||||
&& !FileSystem::fileEquals(fn, tmpFile.fileName()); // compare the files to see if there was an actual conflict.
|
&& !FileSystem::fileEquals(fn, tmpFile.fileName()); // compare the files to see if there was an actual conflict.
|
||||||
//In case of conflict, make a backup of the old file
|
//In case of conflict, make a backup of the old file
|
||||||
if (isConflict) {
|
if (isConflict) {
|
||||||
QString conflictFileName = makeConflictFileName(fn, Utility::qDateTimeFromTime_t(_item._modtime));
|
auto conflictDate = FileSystem::fileExists(fn) ? FileSystem::getModTime(fn) : _item._modtime;
|
||||||
|
QString conflictFileName = makeConflictFileName(fn, Utility::qDateTimeFromTime_t(conflictDate));
|
||||||
QString renameError;
|
QString renameError;
|
||||||
if (!FileSystem::rename(fn, conflictFileName, &renameError)) {
|
if (!FileSystem::rename(fn, conflictFileName, &renameError)) {
|
||||||
//If the rename fails, don't replace it.
|
//If the rename fails, don't replace it.
|
||||||
@@ -713,7 +714,11 @@ void PropagateDownloadFileLegacy::start()
|
|||||||
|
|
||||||
QString error;
|
QString error;
|
||||||
_propagator->addTouchedFile(fn);
|
_propagator->addTouchedFile(fn);
|
||||||
if (!FileSystem::renameReplace(tmpFile.fileName(), fn, &error)) {
|
const qint64 expectedFileSize = _item.log._other_size;
|
||||||
|
const time_t expectedFileMtime = _item.log._other_modtime;
|
||||||
|
if (!FileSystem::renameReplace(tmpFile.fileName(), fn,
|
||||||
|
expectedFileSize, expectedFileMtime,
|
||||||
|
&error)) {
|
||||||
done(SyncFileItem::NormalError, error);
|
done(SyncFileItem::NormalError, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,22 @@
|
|||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tags for checksum headers.
|
||||||
|
* They are here for being shared between Upload- and Download Job
|
||||||
|
*/
|
||||||
|
|
||||||
|
// the header itself
|
||||||
|
static const char checkSumHeaderC[] = "OC-Checksum";
|
||||||
|
// ...and it's values
|
||||||
|
static const char checkSumMD5C[] = "MD5";
|
||||||
|
static const char checkSumSHA1C[] = "SHA1";
|
||||||
|
static const char checkSumAdlerC[] = "Adler32";
|
||||||
|
static const char checkSumAdlerUpperC[] = "ADLER32";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declaration of the other propagation jobs
|
||||||
|
*/
|
||||||
class PropagateLocalRemove : public PropagateItemJob {
|
class PropagateLocalRemove : public PropagateItemJob {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -595,7 +595,6 @@ void SyncEngine::startSync()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
fileRecordCount = _journal->getFileRecordCount(); // this creates the DB if it does not exist yet
|
fileRecordCount = _journal->getFileRecordCount(); // this creates the DB if it does not exist yet
|
||||||
bool isUpdateFrom_1_5 = _journal->isUpdateFrom_1_5();
|
|
||||||
|
|
||||||
if( fileRecordCount == -1 ) {
|
if( fileRecordCount == -1 ) {
|
||||||
qDebug() << "No way to create a sync journal!";
|
qDebug() << "No way to create a sync journal!";
|
||||||
@@ -605,13 +604,7 @@ void SyncEngine::startSync()
|
|||||||
// database creation error!
|
// database creation error!
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileRecordCount >= 1 && isUpdateFrom_1_5) {
|
_csync_ctx->read_remote_from_db = true;
|
||||||
qDebug() << "detected update from 1.5" << fileRecordCount << isUpdateFrom_1_5;
|
|
||||||
// Disable the read from DB to be sure to re-read all the fileid and etags.
|
|
||||||
_csync_ctx->read_remote_from_db = false;
|
|
||||||
} else {
|
|
||||||
_csync_ctx->read_remote_from_db = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This tells csync to never read from the DB if it is empty
|
// This tells csync to never read from the DB if it is empty
|
||||||
// thereby speeding up the initial discovery significantly.
|
// thereby speeding up the initial discovery significantly.
|
||||||
@@ -999,8 +992,8 @@ void SyncEngine::checkForPermission()
|
|||||||
it->_direction = SyncFileItem::Down;
|
it->_direction = SyncFileItem::Down;
|
||||||
it->_isRestoration = true;
|
it->_isRestoration = true;
|
||||||
// take the things to write to the db from the "other" node (i.e: info from server)
|
// take the things to write to the db from the "other" node (i.e: info from server)
|
||||||
// ^^ FIXME This might not be needed anymore since we merge the info in treewalkFile
|
|
||||||
it->_modtime = it->log._other_modtime;
|
it->_modtime = it->log._other_modtime;
|
||||||
|
it->_size = it->log._other_size;
|
||||||
it->_fileId = it->log._other_fileId;
|
it->_fileId = it->log._other_fileId;
|
||||||
it->_etag = it->log._other_etag;
|
it->_etag = it->log._other_etag;
|
||||||
it->_errorString = tr("Not allowed to upload this file because it is read-only on the server, restoring");
|
it->_errorString = tr("Not allowed to upload this file because it is read-only on the server, restoring");
|
||||||
|
|||||||
@@ -150,6 +150,7 @@ public:
|
|||||||
quint64 _inode;
|
quint64 _inode;
|
||||||
QByteArray _fileId;
|
QByteArray _fileId;
|
||||||
QByteArray _remotePerm;
|
QByteArray _remotePerm;
|
||||||
|
QByteArray _checksum;
|
||||||
QString _directDownloadUrl;
|
QString _directDownloadUrl;
|
||||||
QString _directDownloadCookies;
|
QString _directDownloadCookies;
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
SyncJournalDb::SyncJournalDb(const QString& path, QObject *parent) :
|
SyncJournalDb::SyncJournalDb(const QString& path, QObject *parent) :
|
||||||
QObject(parent), _transaction(0), _possibleUpgradeFromMirall_1_5(false)
|
QObject(parent), _transaction(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
_dbFile = path;
|
_dbFile = path;
|
||||||
@@ -272,19 +272,20 @@ bool SyncJournalDb::checkConnect()
|
|||||||
return sqlFail("Create table version", createQuery);
|
return sqlFail("Create table version", createQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
_possibleUpgradeFromMirall_1_5 = false;
|
bool forceRemoteDiscovery = false;
|
||||||
|
|
||||||
SqlQuery versionQuery("SELECT major, minor, patch FROM version;", _db);
|
SqlQuery versionQuery("SELECT major, minor, patch FROM version;", _db);
|
||||||
if (!versionQuery.next()) {
|
if (!versionQuery.next()) {
|
||||||
// If there was no entry in the table, it means we are likely upgrading from 1.5
|
// If there was no entry in the table, it means we are likely upgrading from 1.5
|
||||||
if (!isNewDb) {
|
if (!isNewDb) {
|
||||||
qDebug() << Q_FUNC_INFO << "_possibleUpgradeFromMirall_1_5 detected!";
|
qDebug() << Q_FUNC_INFO << "possibleUpgradeFromMirall_1_5 detected!";
|
||||||
_possibleUpgradeFromMirall_1_5 = true;
|
forceRemoteDiscovery = true;
|
||||||
}
|
}
|
||||||
createQuery.prepare("INSERT INTO version VALUES (?1, ?2, ?3, ?4);");
|
createQuery.prepare("INSERT INTO version VALUES (?1, ?2, ?3, ?4);");
|
||||||
createQuery.bindValue(1, MIRALL_VERSION_MAJOR);
|
createQuery.bindValue(1, MIRALL_VERSION_MAJOR);
|
||||||
createQuery.bindValue(2, MIRALL_VERSION_MINOR);
|
createQuery.bindValue(2, MIRALL_VERSION_MINOR);
|
||||||
createQuery.bindValue(3, MIRALL_VERSION_PATCH);
|
createQuery.bindValue(3, MIRALL_VERSION_PATCH);
|
||||||
createQuery.bindValue(3, MIRALL_VERSION_BUILD);
|
createQuery.bindValue(4, MIRALL_VERSION_BUILD);
|
||||||
createQuery.exec();
|
createQuery.exec();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -292,6 +293,10 @@ bool SyncJournalDb::checkConnect()
|
|||||||
int minor = versionQuery.intValue(1);
|
int minor = versionQuery.intValue(1);
|
||||||
int patch = versionQuery.intValue(2);
|
int patch = versionQuery.intValue(2);
|
||||||
|
|
||||||
|
if( major == 1 && minor == 8 && (patch == 0 || patch == 1) ) {
|
||||||
|
qDebug() << Q_FUNC_INFO << "possibleUpgradeFromMirall_1_8_0_or_1 detected!";
|
||||||
|
forceRemoteDiscovery = true;
|
||||||
|
}
|
||||||
// Not comparing the BUILD id here, correct?
|
// Not comparing the BUILD id here, correct?
|
||||||
if( !(major == MIRALL_VERSION_MAJOR && minor == MIRALL_VERSION_MINOR && patch == MIRALL_VERSION_PATCH) ) {
|
if( !(major == MIRALL_VERSION_MAJOR && minor == MIRALL_VERSION_MINOR && patch == MIRALL_VERSION_PATCH) ) {
|
||||||
createQuery.prepare("UPDATE version SET major=?1, minor=?2, patch =?3, custom=?4 "
|
createQuery.prepare("UPDATE version SET major=?1, minor=?2, patch =?3, custom=?4 "
|
||||||
@@ -317,6 +322,25 @@ bool SyncJournalDb::checkConnect()
|
|||||||
qDebug() << "WARN: Failed to update the database structure!";
|
qDebug() << "WARN: Failed to update the database structure!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we are upgrading from a client version older than 1.5 is found,
|
||||||
|
* we cannot read from the database because we need to fetch the files id and etags.
|
||||||
|
*
|
||||||
|
* If 1.8.0 caused missing data in the local tree, so we also don't read from DB
|
||||||
|
* to get back the files that were gone.
|
||||||
|
* In 1.8.1 we had a fix to re-get the data, but this one here is better
|
||||||
|
*/
|
||||||
|
if (forceRemoteDiscovery) {
|
||||||
|
qDebug() << "Forcing remote re-discovery by deleting folder Etags";
|
||||||
|
SqlQuery deleteRemoteFolderEtagsQuery(_db);
|
||||||
|
deleteRemoteFolderEtagsQuery.prepare("UPDATE metadata SET md5='_invalid_' WHERE type=2;");
|
||||||
|
if( !deleteRemoteFolderEtagsQuery.exec() ) {
|
||||||
|
qDebug() << "ERROR: Query failed" << deleteRemoteFolderEtagsQuery.error();
|
||||||
|
} else {
|
||||||
|
qDebug() << "Cleared" << deleteRemoteFolderEtagsQuery.numRowsAffected() << "folder ETags";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_getFileRecordQuery.reset(new SqlQuery(_db));
|
_getFileRecordQuery.reset(new SqlQuery(_db));
|
||||||
_getFileRecordQuery->prepare("SELECT path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize FROM "
|
_getFileRecordQuery->prepare("SELECT path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize FROM "
|
||||||
"metadata WHERE phash=?1" );
|
"metadata WHERE phash=?1" );
|
||||||
@@ -403,7 +427,6 @@ void SyncJournalDb::close()
|
|||||||
_deleteFileRecordRecursively.reset(0);
|
_deleteFileRecordRecursively.reset(0);
|
||||||
_getErrorBlacklistQuery.reset(0);
|
_getErrorBlacklistQuery.reset(0);
|
||||||
_setErrorBlacklistQuery.reset(0);
|
_setErrorBlacklistQuery.reset(0);
|
||||||
_possibleUpgradeFromMirall_1_5 = false;
|
|
||||||
|
|
||||||
_db.close();
|
_db.close();
|
||||||
_avoidReadFromDbOnNextSyncFilter.clear();
|
_avoidReadFromDbOnNextSyncFilter.clear();
|
||||||
@@ -749,10 +772,6 @@ bool SyncJournalDb::postSyncCleanup(const QSet<QString>& filepathsToKeep,
|
|||||||
// Incoroporate results back into main DB
|
// Incoroporate results back into main DB
|
||||||
walCheckpoint();
|
walCheckpoint();
|
||||||
|
|
||||||
if (_possibleUpgradeFromMirall_1_5) {
|
|
||||||
_possibleUpgradeFromMirall_1_5 = false; // should be handled now
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1145,12 +1164,11 @@ void SyncJournalDb::wipeErrorBlacklistEntry( const QString& file )
|
|||||||
|
|
||||||
void SyncJournalDb::updateErrorBlacklistEntry( const SyncJournalErrorBlacklistRecord& item )
|
void SyncJournalDb::updateErrorBlacklistEntry( const SyncJournalErrorBlacklistRecord& item )
|
||||||
{
|
{
|
||||||
|
QMutexLocker locker(&_mutex);
|
||||||
if( !checkConnect() ) {
|
if( !checkConnect() ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMutexLocker locker(&_mutex);
|
|
||||||
|
|
||||||
_setErrorBlacklistQuery->bindValue(1, item._file);
|
_setErrorBlacklistQuery->bindValue(1, item._file);
|
||||||
_setErrorBlacklistQuery->bindValue(2, item._lastTryEtag);
|
_setErrorBlacklistQuery->bindValue(2, item._lastTryEtag);
|
||||||
_setErrorBlacklistQuery->bindValue(3, QString::number(item._lastTryModtime));
|
_setErrorBlacklistQuery->bindValue(3, QString::number(item._lastTryModtime));
|
||||||
@@ -1315,13 +1333,6 @@ bool SyncJournalDb::isConnected()
|
|||||||
return checkConnect();
|
return checkConnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SyncJournalDb::isUpdateFrom_1_5()
|
|
||||||
{
|
|
||||||
QMutexLocker lock(&_mutex);
|
|
||||||
checkConnect();
|
|
||||||
return _possibleUpgradeFromMirall_1_5;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const SyncJournalDb::DownloadInfo & lhs,
|
bool operator==(const SyncJournalDb::DownloadInfo & lhs,
|
||||||
const SyncJournalDb::DownloadInfo & rhs)
|
const SyncJournalDb::DownloadInfo & rhs)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -113,12 +113,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool isConnected();
|
bool isConnected();
|
||||||
|
|
||||||
/**
|
|
||||||
* Tell the sync engine if we need to disable the fetch from db to be sure that the fileid
|
|
||||||
* are updated.
|
|
||||||
*/
|
|
||||||
bool isUpdateFrom_1_5();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool updateDatabaseStructure();
|
bool updateDatabaseStructure();
|
||||||
bool updateMetadataTableStructure();
|
bool updateMetadataTableStructure();
|
||||||
@@ -134,7 +128,6 @@ private:
|
|||||||
QString _dbFile;
|
QString _dbFile;
|
||||||
QMutex _mutex; // Public functions are protected with the mutex.
|
QMutex _mutex; // Public functions are protected with the mutex.
|
||||||
int _transaction;
|
int _transaction;
|
||||||
bool _possibleUpgradeFromMirall_1_5;
|
|
||||||
QScopedPointer<SqlQuery> _getFileRecordQuery;
|
QScopedPointer<SqlQuery> _getFileRecordQuery;
|
||||||
QScopedPointer<SqlQuery> _setFileRecordQuery;
|
QScopedPointer<SqlQuery> _setFileRecordQuery;
|
||||||
QScopedPointer<SqlQuery> _getDownloadInfoQuery;
|
QScopedPointer<SqlQuery> _getDownloadInfoQuery;
|
||||||
|
|||||||
@@ -241,12 +241,17 @@ QString Theme::updateCheckUrl() const
|
|||||||
return QLatin1String("https://updates.owncloud.com/client/");
|
return QLatin1String("https://updates.owncloud.com/client/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Theme::transmissionChecksum() const
|
||||||
|
{
|
||||||
|
return QString::null; // No transmission by default.
|
||||||
|
}
|
||||||
|
|
||||||
QString Theme::gitSHA1() const
|
QString Theme::gitSHA1() const
|
||||||
{
|
{
|
||||||
QString devString;
|
QString devString;
|
||||||
#ifdef GIT_SHA1
|
#ifdef GIT_SHA1
|
||||||
const QString githubPrefix(QLatin1String(
|
const QString githubPrefix(QLatin1String(
|
||||||
"https://github.com/owncloud/mirall/commit/"));
|
"https://github.com/owncloud/client/commit/"));
|
||||||
const QString gitSha1(QLatin1String(GIT_SHA1));
|
const QString gitSha1(QLatin1String(GIT_SHA1));
|
||||||
devString = QCoreApplication::translate("ownCloudTheme::about()",
|
devString = QCoreApplication::translate("ownCloudTheme::about()",
|
||||||
"<p><small>Built from Git revision <a href=\"%1\">%2</a>"
|
"<p><small>Built from Git revision <a href=\"%1\">%2</a>"
|
||||||
@@ -389,5 +394,5 @@ bool Theme::wizardSelectiveSyncDefaultNothing() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // end namespace mirall
|
} // end namespace client
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#ifndef _THEME_H
|
#ifndef _THEME_H
|
||||||
#define _THEME_H
|
#define _THEME_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
#include "syncresult.h"
|
#include "syncresult.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -188,12 +189,19 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual QString updateCheckUrl() const;
|
virtual QString updateCheckUrl() const;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When true, the setup wizard will show the selective sync dialog by default and default
|
* When true, the setup wizard will show the selective sync dialog by default and default
|
||||||
* to nothing selected
|
* to nothing selected
|
||||||
*/
|
*/
|
||||||
virtual bool wizardSelectiveSyncDefaultNothing() const;
|
virtual bool wizardSelectiveSyncDefaultNothing() const;
|
||||||
|
/**
|
||||||
|
* @brief Add an additional checksum header to PUT requests and compare them
|
||||||
|
* if they come with GET requests.
|
||||||
|
* This value sets the checksum type (SHA1, MD5 or Adler32) or is left empty
|
||||||
|
* if no checksumming is wanted. In that case it can still be overwritten in
|
||||||
|
* the client config file.
|
||||||
|
*/
|
||||||
|
virtual QString transmissionChecksum() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
#ifndef TOKEN_AUTH_ONLY
|
#ifndef TOKEN_AUTH_ONLY
|
||||||
|
|||||||
151
src/libsync/transmissionchecksumvalidator.cpp
Normal file
151
src/libsync/transmissionchecksumvalidator.cpp
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
#include "filesystem.h"
|
||||||
|
#include "transmissionchecksumvalidator.h"
|
||||||
|
#include "syncfileitem.h"
|
||||||
|
#include "propagatorjobs.h"
|
||||||
|
#include "configfile.h"
|
||||||
|
|
||||||
|
#include <qtconcurrentrun.h>
|
||||||
|
|
||||||
|
namespace OCC {
|
||||||
|
|
||||||
|
TransmissionChecksumValidator::TransmissionChecksumValidator(const QString& filePath, QObject *parent)
|
||||||
|
:QObject(parent),
|
||||||
|
_filePath(filePath)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransmissionChecksumValidator::setChecksumType( const QByteArray& type )
|
||||||
|
{
|
||||||
|
_checksumType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString TransmissionChecksumValidator::checksumType() const
|
||||||
|
{
|
||||||
|
QString checksumType = _checksumType;
|
||||||
|
if( checksumType.isEmpty() ) {
|
||||||
|
ConfigFile cfg;
|
||||||
|
checksumType = cfg.transmissionChecksum();
|
||||||
|
}
|
||||||
|
|
||||||
|
return checksumType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransmissionChecksumValidator::uploadValidation()
|
||||||
|
{
|
||||||
|
const QString csType = checksumType();
|
||||||
|
|
||||||
|
if( csType.isEmpty() ) {
|
||||||
|
// if there is no checksum defined, continue to upload
|
||||||
|
emit validated(QByteArray());
|
||||||
|
} else {
|
||||||
|
// Calculate the checksum in a different thread first.
|
||||||
|
|
||||||
|
connect( &_watcher, SIGNAL(finished()),
|
||||||
|
this, SLOT(slotUploadChecksumCalculated()));
|
||||||
|
if( csType == checkSumMD5C ) {
|
||||||
|
_checksumHeader = checkSumMD5C;
|
||||||
|
_checksumHeader += ":";
|
||||||
|
_watcher.setFuture(QtConcurrent::run(FileSystem::calcMd5, _filePath));
|
||||||
|
|
||||||
|
} else if( csType == checkSumSHA1C ) {
|
||||||
|
_checksumHeader = checkSumSHA1C;
|
||||||
|
_checksumHeader += ":";
|
||||||
|
_watcher.setFuture(QtConcurrent::run( FileSystem::calcSha1, _filePath));
|
||||||
|
}
|
||||||
|
#ifdef ZLIB_FOUND
|
||||||
|
else if( csType == checkSumAdlerC) {
|
||||||
|
_checksumHeader = checkSumAdlerC;
|
||||||
|
_checksumHeader += ":";
|
||||||
|
_watcher.setFuture(QtConcurrent::run(FileSystem::calcAdler32, _filePath));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
|
// for an unknown checksum, continue to upload
|
||||||
|
emit validated(QByteArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransmissionChecksumValidator::slotUploadChecksumCalculated( )
|
||||||
|
{
|
||||||
|
QByteArray checksum = _watcher.future().result();
|
||||||
|
|
||||||
|
if( !checksum.isEmpty() ) {
|
||||||
|
checksum.prepend( _checksumHeader );
|
||||||
|
}
|
||||||
|
|
||||||
|
emit validated(checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TransmissionChecksumValidator::downloadValidation( const QByteArray& checksumHeader )
|
||||||
|
{
|
||||||
|
// if the incoming header is empty, there was no checksum header, and
|
||||||
|
// no validation can happen. Just continue.
|
||||||
|
const QString csType = checksumType();
|
||||||
|
|
||||||
|
// for empty checksum type, everything is valid.
|
||||||
|
if( csType.isEmpty() ) {
|
||||||
|
emit validated(QByteArray());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int indx = checksumHeader.indexOf(':');
|
||||||
|
if( indx < 0 ) {
|
||||||
|
qDebug() << "Checksum header malformed:" << checksumHeader;
|
||||||
|
emit validationFailed(tr("The checksum header is malformed.")); // show must go on - even not validated.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QByteArray type = checksumHeader.left(indx).toUpper();
|
||||||
|
_expectedHash = checksumHeader.mid(indx+1);
|
||||||
|
|
||||||
|
connect( &_watcher, SIGNAL(finished()), this, SLOT(slotDownloadChecksumCalculated()) );
|
||||||
|
|
||||||
|
// start the calculation in different thread
|
||||||
|
if( type == checkSumMD5C ) {
|
||||||
|
_watcher.setFuture(QtConcurrent::run(FileSystem::calcMd5, _filePath));
|
||||||
|
} else if( type == checkSumSHA1C ) {
|
||||||
|
_watcher.setFuture(QtConcurrent::run(FileSystem::calcSha1, _filePath));
|
||||||
|
}
|
||||||
|
#ifdef ZLIB_FOUND
|
||||||
|
else if( type == checkSumAdlerUpperC ) {
|
||||||
|
_watcher.setFuture(QtConcurrent::run(FileSystem::calcAdler32, _filePath));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
|
qDebug() << "Unknown checksum type" << type;
|
||||||
|
emit validationFailed(tr("The checksum header is malformed."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransmissionChecksumValidator::slotDownloadChecksumCalculated()
|
||||||
|
{
|
||||||
|
const QByteArray hash = _watcher.future().result();
|
||||||
|
|
||||||
|
if( hash != _expectedHash ) {
|
||||||
|
emit validationFailed(tr("The downloaded file does not match the checksum, it will be resumed."));
|
||||||
|
} else {
|
||||||
|
// qDebug() << "Checksum checked and matching: " << _expectedHash;
|
||||||
|
emit validated(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
74
src/libsync/transmissionchecksumvalidator.h
Normal file
74
src/libsync/transmissionchecksumvalidator.h
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QFutureWatcher>
|
||||||
|
|
||||||
|
namespace OCC {
|
||||||
|
|
||||||
|
class TransmissionChecksumValidator : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit TransmissionChecksumValidator(const QString& filePath, QObject *parent = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* method to prepare a checksum for transmission and save it to the _checksum
|
||||||
|
* member of the SyncFileItem *item.
|
||||||
|
* The kind of requested checksum is taken from config. No need to set from outside.
|
||||||
|
*
|
||||||
|
* In any case of processing (checksum set, no checksum required and also unusual error)
|
||||||
|
* the object will emit the signal validated(). The item->_checksum is than either
|
||||||
|
* set to a proper value or empty.
|
||||||
|
*/
|
||||||
|
void uploadValidation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* method to verify the checksum coming with requests in a checksum header. The required
|
||||||
|
* checksum method is read from config.
|
||||||
|
*
|
||||||
|
* If no checksum is there, or if a correct checksum is there, the signal validated()
|
||||||
|
* will be emitted. In case of any kind of error, the signal validationFailed() will
|
||||||
|
* be emitted.
|
||||||
|
*/
|
||||||
|
void downloadValidation( const QByteArray& checksumHeader );
|
||||||
|
|
||||||
|
// This is only used in test cases (by now). This class reads the required
|
||||||
|
// test case from the config file.
|
||||||
|
void setChecksumType(const QByteArray &type );
|
||||||
|
QString checksumType() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void validated(const QByteArray& checksum);
|
||||||
|
void validationFailed( const QString& errMsg );
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotUploadChecksumCalculated();
|
||||||
|
void slotDownloadChecksumCalculated();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QByteArray _checksumType;
|
||||||
|
QByteArray _expectedHash;
|
||||||
|
QByteArray _checksumHeader;
|
||||||
|
|
||||||
|
QString _filePath;
|
||||||
|
|
||||||
|
// watcher for the checksum calculation thread
|
||||||
|
QFutureWatcher<QByteArray> _watcher;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
|
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "theme.h"
|
||||||
|
|
||||||
// Note: This file must compile without QtGui
|
// Note: This file must compile without QtGui
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
@@ -154,10 +155,19 @@ QString Utility::platform()
|
|||||||
|
|
||||||
QByteArray Utility::userAgentString()
|
QByteArray Utility::userAgentString()
|
||||||
{
|
{
|
||||||
return QString::fromLatin1("Mozilla/5.0 (%1) mirall/%2")
|
QString re = QString::fromLatin1("Mozilla/5.0 (%1) mirall/%2")
|
||||||
.arg(Utility::platform())
|
.arg(Utility::platform())
|
||||||
.arg(QLatin1String(MIRALL_STRINGIFY(MIRALL_VERSION)))
|
.arg(QLatin1String(MIRALL_STRINGIFY(MIRALL_VERSION)));
|
||||||
.toLatin1();
|
|
||||||
|
const QString appName = Theme::instance()->appName();
|
||||||
|
|
||||||
|
// this constant "ownCloud" is defined in the default OEM theming
|
||||||
|
// that is used for the standard client. If it is changed there,
|
||||||
|
// it needs to be adjusted here.
|
||||||
|
if( appName != QLatin1String("ownCloud") ) {
|
||||||
|
re += QString(" (%1)").arg(appName);
|
||||||
|
}
|
||||||
|
return re.toLatin1();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Utility::hasLaunchOnStartup(const QString &appName)
|
bool Utility::hasLaunchOnStartup(const QString &appName)
|
||||||
@@ -401,10 +411,12 @@ void Utility::StopWatch::start()
|
|||||||
_timer.start();
|
_timer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Utility::StopWatch::stop()
|
quint64 Utility::StopWatch::stop()
|
||||||
{
|
{
|
||||||
addLapTime(QLatin1String(STOPWATCH_END_TAG));
|
addLapTime(QLatin1String(STOPWATCH_END_TAG));
|
||||||
|
quint64 duration = _timer.elapsed();
|
||||||
_timer.invalidate();
|
_timer.invalidate();
|
||||||
|
return duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Utility::StopWatch::reset()
|
void Utility::StopWatch::reset()
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ namespace Utility
|
|||||||
QElapsedTimer _timer;
|
QElapsedTimer _timer;
|
||||||
public:
|
public:
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
quint64 stop();
|
||||||
quint64 addLapTime( const QString& lapName );
|
quint64 addLapTime( const QString& lapName );
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
|||||||
@@ -33,4 +33,6 @@ owncloud_add_test(SyncFileItem "")
|
|||||||
owncloud_add_test(ConcatUrl "")
|
owncloud_add_test(ConcatUrl "")
|
||||||
|
|
||||||
owncloud_add_test(XmlParse "")
|
owncloud_add_test(XmlParse "")
|
||||||
|
owncloud_add_test(FileSystem "")
|
||||||
|
owncloud_add_test(TransChecksumValidator "")
|
||||||
|
|
||||||
|
|||||||
93
test/testfilesystem.h
Normal file
93
test/testfilesystem.h
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
This software is in the public domain, furnished "as is", without technical
|
||||||
|
support, and with no warranty, express or implied, as to its usefulness for
|
||||||
|
any purpose.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MIRALL_TESTFILESYSTEM_H
|
||||||
|
#define MIRALL_TESTFILESYSTEM_H
|
||||||
|
|
||||||
|
#include <QtTest>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "filesystem.h"
|
||||||
|
#include "utility.h"
|
||||||
|
|
||||||
|
using namespace OCC::Utility;
|
||||||
|
using namespace OCC::FileSystem;
|
||||||
|
|
||||||
|
class TestFileSystem : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
QString _root;
|
||||||
|
|
||||||
|
|
||||||
|
QByteArray shellSum( const QByteArray& cmd, const QString& file )
|
||||||
|
{
|
||||||
|
QProcess md5;
|
||||||
|
QStringList args;
|
||||||
|
args.append(file);
|
||||||
|
md5.start(cmd, args);
|
||||||
|
QByteArray sumShell;
|
||||||
|
qDebug() << "File: "<< file;
|
||||||
|
|
||||||
|
if( md5.waitForFinished() ) {
|
||||||
|
|
||||||
|
sumShell = md5.readAll();
|
||||||
|
sumShell = sumShell.left( sumShell.indexOf(' '));
|
||||||
|
}
|
||||||
|
return sumShell;
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void initTestCase() {
|
||||||
|
qsrand(QTime::currentTime().msec());
|
||||||
|
|
||||||
|
QString subdir("test_"+QString::number(qrand()));
|
||||||
|
_root = QDir::tempPath() + "/" + subdir;
|
||||||
|
|
||||||
|
QDir dir("/tmp");
|
||||||
|
dir.mkdir(subdir);
|
||||||
|
qDebug() << "creating test directory " << _root;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanupTestCase()
|
||||||
|
{
|
||||||
|
if( !_root.isEmpty() )
|
||||||
|
system(QString("rm -rf "+_root).toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
void testMd5Calc()
|
||||||
|
{
|
||||||
|
QString file( _root+"/file_a.bin");
|
||||||
|
writeRandomFile(file);
|
||||||
|
QFileInfo fi(file);
|
||||||
|
QVERIFY(fi.exists());
|
||||||
|
QByteArray sum = calcMd5(file);
|
||||||
|
|
||||||
|
QByteArray sSum = shellSum("/usr/bin/md5sum", file);
|
||||||
|
qDebug() << "calulated" << sum << "versus md5sum:"<< sSum;
|
||||||
|
QVERIFY(!sSum.isEmpty());
|
||||||
|
QVERIFY(!sum.isEmpty());
|
||||||
|
QVERIFY(sSum == sum );
|
||||||
|
}
|
||||||
|
|
||||||
|
void testSha1Calc()
|
||||||
|
{
|
||||||
|
QString file( _root+"/file_b.bin");
|
||||||
|
writeRandomFile(file);
|
||||||
|
QFileInfo fi(file);
|
||||||
|
QVERIFY(fi.exists());
|
||||||
|
QByteArray sum = calcSha1(file);
|
||||||
|
|
||||||
|
QByteArray sSum = shellSum("/usr/bin/sha1sum", file);
|
||||||
|
qDebug() << "calulated" << sum << "versus sha1sum:"<< sSum;
|
||||||
|
QVERIFY(!sSum.isEmpty());
|
||||||
|
QVERIFY(!sum.isEmpty());
|
||||||
|
QVERIFY(sSum == sum );
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -8,7 +8,14 @@
|
|||||||
#define MIRALL_TESTOWNCLOUDPROPAGATOR_H
|
#define MIRALL_TESTOWNCLOUDPROPAGATOR_H
|
||||||
|
|
||||||
#include <QtTest>
|
#include <QtTest>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "propagatedownload.h"
|
||||||
|
|
||||||
|
using namespace OCC;
|
||||||
|
namespace OCC {
|
||||||
|
QString OWNCLOUDSYNC_EXPORT createDownloadTmpFileName(const QString &previous);
|
||||||
|
}
|
||||||
|
|
||||||
class TestOwncloudPropagator : public QObject
|
class TestOwncloudPropagator : public QObject
|
||||||
{
|
{
|
||||||
@@ -20,6 +27,43 @@ private slots:
|
|||||||
// OwncloudPropagator propagator( NULL, QLatin1String("test1"), QLatin1String("test2"), new ProgressDatabase);
|
// OwncloudPropagator propagator( NULL, QLatin1String("test1"), QLatin1String("test2"), new ProgressDatabase);
|
||||||
QVERIFY( true );
|
QVERIFY( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testTmpDownloadFileNameGeneration()
|
||||||
|
{
|
||||||
|
QString fn;
|
||||||
|
// without dir
|
||||||
|
for (int i = 1; i <= 1000; i++) {
|
||||||
|
fn+="F";
|
||||||
|
QString tmpFileName = createDownloadTmpFileName(fn);
|
||||||
|
if (tmpFileName.contains('/')) {
|
||||||
|
tmpFileName = tmpFileName.mid(tmpFileName.lastIndexOf('/')+1);
|
||||||
|
}
|
||||||
|
QVERIFY( tmpFileName.length() > 0);
|
||||||
|
QVERIFY( tmpFileName.length() <= 254);
|
||||||
|
}
|
||||||
|
// with absolute dir
|
||||||
|
fn = "/Users/guruz/ownCloud/rocks/GPL";
|
||||||
|
for (int i = 1; i < 1000; i++) {
|
||||||
|
fn+="F";
|
||||||
|
QString tmpFileName = createDownloadTmpFileName(fn);
|
||||||
|
if (tmpFileName.contains('/')) {
|
||||||
|
tmpFileName = tmpFileName.mid(tmpFileName.lastIndexOf('/')+1);
|
||||||
|
}
|
||||||
|
QVERIFY( tmpFileName.length() > 0);
|
||||||
|
QVERIFY( tmpFileName.length() <= 254);
|
||||||
|
}
|
||||||
|
// with relative dir
|
||||||
|
fn = "rocks/GPL";
|
||||||
|
for (int i = 1; i < 1000; i++) {
|
||||||
|
fn+="F";
|
||||||
|
QString tmpFileName = createDownloadTmpFileName(fn);
|
||||||
|
if (tmpFileName.contains('/')) {
|
||||||
|
tmpFileName = tmpFileName.mid(tmpFileName.lastIndexOf('/')+1);
|
||||||
|
}
|
||||||
|
QVERIFY( tmpFileName.length() > 0);
|
||||||
|
QVERIFY( tmpFileName.length() <= 254);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
159
test/testtranschecksumvalidator.h
Normal file
159
test/testtranschecksumvalidator.h
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* This software is in the public domain, furnished "as is", without technical
|
||||||
|
* support, and with no warranty, express or implied, as to its usefulness for
|
||||||
|
* any purpose.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QtTest>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "transmissionchecksumvalidator.h"
|
||||||
|
#include "networkjobs.h"
|
||||||
|
#include "utility.h"
|
||||||
|
#include "filesystem.h"
|
||||||
|
#include "propagatorjobs.h"
|
||||||
|
|
||||||
|
using namespace OCC;
|
||||||
|
|
||||||
|
class TestTransChecksumValidator : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString _root;
|
||||||
|
QString _testfile;
|
||||||
|
QString _expectedError;
|
||||||
|
QEventLoop _loop;
|
||||||
|
QByteArray _expected;
|
||||||
|
bool _successDown;
|
||||||
|
bool _errorSeen;
|
||||||
|
|
||||||
|
void processAndWait() {
|
||||||
|
_loop.processEvents();
|
||||||
|
Utility::usleep(200000);
|
||||||
|
_loop.processEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void slotUpValidated(const QByteArray& checksum) {
|
||||||
|
qDebug() << "Checksum: " << checksum;
|
||||||
|
QVERIFY(_expected == checksum );
|
||||||
|
}
|
||||||
|
|
||||||
|
void slotDownValidated() {
|
||||||
|
_successDown = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void slotDownError( const QString& errMsg ) {
|
||||||
|
QVERIFY(_expectedError == errMsg );
|
||||||
|
_errorSeen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void initTestCase() {
|
||||||
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
_root = QDir::tempPath() + "/" + "test_" + QString::number(qrand());
|
||||||
|
QDir rootDir(_root);
|
||||||
|
|
||||||
|
rootDir.mkpath(_root );
|
||||||
|
_testfile = _root+"/csFile";
|
||||||
|
Utility::writeRandomFile( _testfile);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void testUploadChecksummingAdler() {
|
||||||
|
|
||||||
|
TransmissionChecksumValidator *vali = new TransmissionChecksumValidator(_testfile, this);
|
||||||
|
vali->setChecksumType("Adler32");
|
||||||
|
|
||||||
|
connect(vali, SIGNAL(validated(QByteArray)), this, SLOT(slotUpValidated(QByteArray)));
|
||||||
|
|
||||||
|
QString testfile = _testfile;
|
||||||
|
_expected = "Adler32:"+FileSystem::calcAdler32( testfile );
|
||||||
|
qDebug() << "XX Expected Checksum: " << _expected;
|
||||||
|
vali->uploadValidation();
|
||||||
|
|
||||||
|
usleep(5000);
|
||||||
|
|
||||||
|
_loop.processEvents();
|
||||||
|
delete vali;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testUploadChecksummingMd5() {
|
||||||
|
|
||||||
|
TransmissionChecksumValidator *vali = new TransmissionChecksumValidator(_testfile, this);
|
||||||
|
vali->setChecksumType( OCC::checkSumMD5C );
|
||||||
|
connect(vali, SIGNAL(validated(QByteArray)), this, SLOT(slotUpValidated(QByteArray)));
|
||||||
|
|
||||||
|
_expected = checkSumMD5C;
|
||||||
|
_expected.append(":"+FileSystem::calcMd5( _testfile ));
|
||||||
|
vali->uploadValidation();
|
||||||
|
|
||||||
|
usleep(2000);
|
||||||
|
|
||||||
|
_loop.processEvents();
|
||||||
|
delete vali;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testUploadChecksummingSha1() {
|
||||||
|
|
||||||
|
TransmissionChecksumValidator *vali = new TransmissionChecksumValidator(_testfile, this);
|
||||||
|
vali->setChecksumType( OCC::checkSumSHA1C );
|
||||||
|
connect(vali, SIGNAL(validated(QByteArray)), this, SLOT(slotUpValidated(QByteArray)));
|
||||||
|
|
||||||
|
_expected = checkSumSHA1C;
|
||||||
|
_expected.append(":"+FileSystem::calcSha1( _testfile ));
|
||||||
|
|
||||||
|
vali->uploadValidation();
|
||||||
|
|
||||||
|
usleep(2000);
|
||||||
|
|
||||||
|
_loop.processEvents();
|
||||||
|
delete vali;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testDownloadChecksummingAdler() {
|
||||||
|
|
||||||
|
QByteArray adler = checkSumAdlerC;
|
||||||
|
adler.append(":");
|
||||||
|
adler.append(FileSystem::calcAdler32( _testfile ));
|
||||||
|
_successDown = false;
|
||||||
|
|
||||||
|
TransmissionChecksumValidator *vali = new TransmissionChecksumValidator(_testfile, this);
|
||||||
|
vali->setChecksumType("Adler32");
|
||||||
|
connect(vali, SIGNAL(validated(QByteArray)), this, SLOT(slotDownValidated()));
|
||||||
|
connect(vali, SIGNAL(validationFailed(QString)), this, SLOT(slotDownError(QString)));
|
||||||
|
vali->downloadValidation(adler);
|
||||||
|
|
||||||
|
usleep(2000);
|
||||||
|
|
||||||
|
_loop.processEvents();
|
||||||
|
QVERIFY(_successDown);
|
||||||
|
|
||||||
|
_expectedError = QLatin1String("The downloaded file does not match the checksum, it will be resumed.");
|
||||||
|
_errorSeen = false;
|
||||||
|
vali->downloadValidation("Adler32:543345");
|
||||||
|
usleep(2000);
|
||||||
|
_loop.processEvents();
|
||||||
|
QVERIFY(_errorSeen);
|
||||||
|
|
||||||
|
_expectedError = QLatin1String("The checksum header is malformed.");
|
||||||
|
_errorSeen = false;
|
||||||
|
vali->downloadValidation("Klaas32:543345");
|
||||||
|
usleep(2000);
|
||||||
|
_loop.processEvents();
|
||||||
|
QVERIFY(_errorSeen);
|
||||||
|
|
||||||
|
delete vali;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void cleanupTestCase() {
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -113,7 +113,7 @@ private slots:
|
|||||||
this, SLOT(slotFinishedSuccessfully()) );
|
this, SLOT(slotFinishedSuccessfully()) );
|
||||||
|
|
||||||
QHash <QString, qint64> sizes;
|
QHash <QString, qint64> sizes;
|
||||||
QVERIFY(parser.parse( testXml, &sizes ));
|
QVERIFY(parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" ));
|
||||||
|
|
||||||
QVERIFY(_success);
|
QVERIFY(_success);
|
||||||
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
|
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
|
||||||
@@ -187,7 +187,7 @@ private slots:
|
|||||||
this, SLOT(slotFinishedSuccessfully()) );
|
this, SLOT(slotFinishedSuccessfully()) );
|
||||||
|
|
||||||
QHash <QString, qint64> sizes;
|
QHash <QString, qint64> sizes;
|
||||||
QVERIFY(false == parser.parse( testXml, &sizes )); // verify false
|
QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); // verify false
|
||||||
|
|
||||||
QVERIFY(!_success);
|
QVERIFY(!_success);
|
||||||
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
|
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
|
||||||
@@ -210,7 +210,7 @@ private slots:
|
|||||||
this, SLOT(slotFinishedSuccessfully()) );
|
this, SLOT(slotFinishedSuccessfully()) );
|
||||||
|
|
||||||
QHash <QString, qint64> sizes;
|
QHash <QString, qint64> sizes;
|
||||||
QVERIFY(false == parser.parse( testXml, &sizes )); // verify false
|
QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); // verify false
|
||||||
|
|
||||||
QVERIFY(!_success);
|
QVERIFY(!_success);
|
||||||
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
|
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
|
||||||
@@ -232,7 +232,7 @@ private slots:
|
|||||||
this, SLOT(slotFinishedSuccessfully()) );
|
this, SLOT(slotFinishedSuccessfully()) );
|
||||||
|
|
||||||
QHash <QString, qint64> sizes;
|
QHash <QString, qint64> sizes;
|
||||||
QVERIFY(false == parser.parse( testXml, &sizes )); // verify false
|
QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); // verify false
|
||||||
|
|
||||||
QVERIFY(!_success);
|
QVERIFY(!_success);
|
||||||
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
|
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
|
||||||
@@ -240,6 +240,208 @@ private slots:
|
|||||||
QVERIFY(_items.size() == 0 ); // FIXME: We should change the parser to not emit during parsing but at the end
|
QVERIFY(_items.size() == 0 ); // FIXME: We should change the parser to not emit during parsing but at the end
|
||||||
QVERIFY(_subdirs.size() == 0);
|
QVERIFY(_subdirs.size() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testParserBogfusHref1() {
|
||||||
|
const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>"
|
||||||
|
"<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
|
||||||
|
"<d:response>"
|
||||||
|
"<d:href>http://127.0.0.1:81/oc/remote.php/webdav/sharefolder/</d:href>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<oc:id>00004213ocobzus5kn6s</oc:id>"
|
||||||
|
"<oc:permissions>RDNVCK</oc:permissions>"
|
||||||
|
"<oc:size>121780</oc:size>"
|
||||||
|
"<d:getetag>\"5527beb0400b0\"</d:getetag>"
|
||||||
|
"<d:resourcetype>"
|
||||||
|
"<d:collection/>"
|
||||||
|
"</d:resourcetype>"
|
||||||
|
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 200 OK</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<d:getcontentlength/>"
|
||||||
|
"<oc:downloadURL/>"
|
||||||
|
"<oc:dDC/>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 404 Not Found</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"</d:response>"
|
||||||
|
"<d:response>"
|
||||||
|
"<d:href>http://127.0.0.1:81/oc/remote.php/webdav/sharefolder/quitte.pdf</d:href>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<oc:id>00004215ocobzus5kn6s</oc:id>"
|
||||||
|
"<oc:permissions>RDNVW</oc:permissions>"
|
||||||
|
"<d:getetag>\"2fa2f0d9ed49ea0c3e409d49e652dea0\"</d:getetag>"
|
||||||
|
"<d:resourcetype/>"
|
||||||
|
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
|
||||||
|
"<d:getcontentlength>121780</d:getcontentlength>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 200 OK</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<oc:downloadURL/>"
|
||||||
|
"<oc:dDC/>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 404 Not Found</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"</d:response>"
|
||||||
|
"</d:multistatus>";
|
||||||
|
|
||||||
|
|
||||||
|
LsColXMLParser parser;
|
||||||
|
|
||||||
|
connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
|
||||||
|
this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
|
||||||
|
connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
|
||||||
|
this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
|
||||||
|
connect( &parser, SIGNAL(finishedWithoutError()),
|
||||||
|
this, SLOT(slotFinishedSuccessfully()) );
|
||||||
|
|
||||||
|
QHash <QString, qint64> sizes;
|
||||||
|
QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" ));
|
||||||
|
QVERIFY(!_success);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testParserBogfusHref2() {
|
||||||
|
const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>"
|
||||||
|
"<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
|
||||||
|
"<d:response>"
|
||||||
|
"<d:href>/sharefolder</d:href>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<oc:id>00004213ocobzus5kn6s</oc:id>"
|
||||||
|
"<oc:permissions>RDNVCK</oc:permissions>"
|
||||||
|
"<oc:size>121780</oc:size>"
|
||||||
|
"<d:getetag>\"5527beb0400b0\"</d:getetag>"
|
||||||
|
"<d:resourcetype>"
|
||||||
|
"<d:collection/>"
|
||||||
|
"</d:resourcetype>"
|
||||||
|
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 200 OK</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<d:getcontentlength/>"
|
||||||
|
"<oc:downloadURL/>"
|
||||||
|
"<oc:dDC/>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 404 Not Found</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"</d:response>"
|
||||||
|
"<d:response>"
|
||||||
|
"<d:href>/sharefolder/quitte.pdf</d:href>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<oc:id>00004215ocobzus5kn6s</oc:id>"
|
||||||
|
"<oc:permissions>RDNVW</oc:permissions>"
|
||||||
|
"<d:getetag>\"2fa2f0d9ed49ea0c3e409d49e652dea0\"</d:getetag>"
|
||||||
|
"<d:resourcetype/>"
|
||||||
|
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
|
||||||
|
"<d:getcontentlength>121780</d:getcontentlength>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 200 OK</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<oc:downloadURL/>"
|
||||||
|
"<oc:dDC/>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 404 Not Found</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"</d:response>"
|
||||||
|
"</d:multistatus>";
|
||||||
|
|
||||||
|
|
||||||
|
LsColXMLParser parser;
|
||||||
|
|
||||||
|
connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
|
||||||
|
this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
|
||||||
|
connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
|
||||||
|
this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
|
||||||
|
connect( &parser, SIGNAL(finishedWithoutError()),
|
||||||
|
this, SLOT(slotFinishedSuccessfully()) );
|
||||||
|
|
||||||
|
QHash <QString, qint64> sizes;
|
||||||
|
QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" ));
|
||||||
|
QVERIFY(!_success);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testHrefUrlEncoding() {
|
||||||
|
const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>"
|
||||||
|
"<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
|
||||||
|
"<d:response>"
|
||||||
|
"<d:href>/%C3%A4</d:href>" // a-umlaut utf8
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<oc:id>00004213ocobzus5kn6s</oc:id>"
|
||||||
|
"<oc:permissions>RDNVCK</oc:permissions>"
|
||||||
|
"<oc:size>121780</oc:size>"
|
||||||
|
"<d:getetag>\"5527beb0400b0\"</d:getetag>"
|
||||||
|
"<d:resourcetype>"
|
||||||
|
"<d:collection/>"
|
||||||
|
"</d:resourcetype>"
|
||||||
|
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 200 OK</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<d:getcontentlength/>"
|
||||||
|
"<oc:downloadURL/>"
|
||||||
|
"<oc:dDC/>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 404 Not Found</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"</d:response>"
|
||||||
|
"<d:response>"
|
||||||
|
"<d:href>/%C3%A4/%C3%A4.pdf</d:href>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<oc:id>00004215ocobzus5kn6s</oc:id>"
|
||||||
|
"<oc:permissions>RDNVW</oc:permissions>"
|
||||||
|
"<d:getetag>\"2fa2f0d9ed49ea0c3e409d49e652dea0\"</d:getetag>"
|
||||||
|
"<d:resourcetype/>"
|
||||||
|
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
|
||||||
|
"<d:getcontentlength>121780</d:getcontentlength>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 200 OK</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"<d:propstat>"
|
||||||
|
"<d:prop>"
|
||||||
|
"<oc:downloadURL/>"
|
||||||
|
"<oc:dDC/>"
|
||||||
|
"</d:prop>"
|
||||||
|
"<d:status>HTTP/1.1 404 Not Found</d:status>"
|
||||||
|
"</d:propstat>"
|
||||||
|
"</d:response>"
|
||||||
|
"</d:multistatus>";
|
||||||
|
|
||||||
|
LsColXMLParser parser;
|
||||||
|
|
||||||
|
connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
|
||||||
|
this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
|
||||||
|
connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
|
||||||
|
this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
|
||||||
|
connect( &parser, SIGNAL(finishedWithoutError()),
|
||||||
|
this, SLOT(slotFinishedSuccessfully()) );
|
||||||
|
|
||||||
|
QHash <QString, qint64> sizes;
|
||||||
|
QVERIFY(parser.parse( testXml, &sizes, QString::fromUtf8("/ä") ));
|
||||||
|
QVERIFY(_success);
|
||||||
|
|
||||||
|
QVERIFY(_items.contains(QString::fromUtf8("/ä/ä.pdf")));
|
||||||
|
QVERIFY(_items.contains(QString::fromUtf8("/ä")));
|
||||||
|
QVERIFY(_items.size() == 2 );
|
||||||
|
|
||||||
|
QVERIFY(_subdirs.contains(QString::fromUtf8("/ä")));
|
||||||
|
QVERIFY(_subdirs.size() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user