1
0
mirror of https://github.com/chylex/Nextcloud-Desktop.git synced 2026-04-08 03:46:49 +02:00

Compare commits

...

172 Commits

Author SHA1 Message Date
Daniel Molkentin
63712de170 1.7.1 rc1 2014-12-16 07:30:23 +01:00
Jenkins for ownCloud
43673d6694 [tx-robot] updated from transifex 2014-12-16 01:25:24 -05:00
Markus Goetz
f195648b90 OS X: Fix overlay icons
a3e7f513e6 broke them.
2014-12-15 11:34:44 +01:00
Jenkins for ownCloud
06f77acfa1 [tx-robot] updated from transifex 2014-12-15 01:25:23 -05:00
Jenkins for ownCloud
f04a693fbe [tx-robot] updated from transifex 2014-12-14 01:25:21 -05:00
Jenkins for ownCloud
c012711763 [tx-robot] updated from transifex 2014-12-13 01:25:29 -05:00
Klaas Freitag
c6daa8e59b Overlays: In case of folders, make sure to append slashes at end.
This fixes #2373
2014-12-12 16:38:07 +01:00
Klaas Freitag
7cc6c1a10f Theme: Add a missing dot. 2014-12-12 13:37:02 +01:00
Klaas Freitag
7f73cc1694 Theme: split the about string apart to have small translation units. 2014-12-12 13:33:38 +01:00
Jenkins for ownCloud
87973ac692 [tx-robot] updated from transifex 2014-12-12 01:25:26 -05:00
Christian Kamm
84e5ad7346 FolderMan: Delete old journal file when adding folder. #2606 2014-12-11 12:28:01 +01:00
Christian Kamm
4559bb5553 Fix counting of affected files. #1132
* Also ensure the maximum is always >= the current value.
* Take care to handle the ULLONG_MAX value that's sometimes used
  as _completedFileCount.
2014-12-11 11:33:42 +01:00
Jenkins for ownCloud
2d51a78ee7 [tx-robot] updated from transifex 2014-12-11 01:25:23 -05:00
Carla Schroder
95a380ae9e fix typos 2014-12-10 08:24:12 -08:00
Jenkins for ownCloud
f0ce8b8fd4 [tx-robot] updated from transifex 2014-12-10 01:25:29 -05:00
Daniel Molkentin
aeb1f10621 NSIS: Reload shell after registering shellextension, use blackslashes
It also registers and unregisters the shell extensions properly and
forces explorer to reload/unload the DLLs so they can be removed.
This obsoletes #2377.

Fixes #2487
Fixes #2377
2014-12-09 23:52:07 +01:00
Olivier Goffart
a3e7f513e6 SocketAPI: use the canonical path
Issue #2591
2014-12-09 20:48:51 +01:00
Klaas Freitag
8b63a6f29b Adding changelog 2014-12-09 20:27:38 +01:00
Klaas Freitag
133a8ec225 Added a fixme for an edge case detected by QuickCheck. 2014-12-09 17:02:51 +01:00
Klaas Freitag
131747ea4b Bumped version to 1.7.1 beta1 2014-12-09 15:25:37 +01:00
Jenkins for ownCloud
a7f1f886d3 [tx-robot] updated from transifex 2014-12-09 01:25:28 -05:00
Klaas Freitag
72a90199db Wizard: Removed superflous text, as it is already in the header.
This fixes mirall#2358
2014-12-08 11:12:15 +01:00
Jenkins for ownCloud
e69702799f [tx-robot] updated from transifex 2014-12-08 01:25:21 -05:00
Jenkins for ownCloud
118aead9b9 [tx-robot] updated from transifex 2014-12-07 01:25:25 -05:00
Klaas Freitag
49bb861045 Removed useless debug output 2014-12-06 12:37:53 +01:00
Klaas Freitag
1d6661e7e4 Fix the number of displayed items in progress display for removes.
This fixes mirall#1132

A variable that counts the affected items of the propagator operation
done on a item was added to SyncFileItem. Usually that is 1 because
most operations affect only the item itself. But for removes, the
number can be higher for directories (one remove removes a whole tree).

Some rearrangements were needed.
2014-12-06 12:31:45 +01:00
Jenkins for ownCloud
a43173fa90 [tx-robot] updated from transifex 2014-12-06 01:25:23 -05:00
Jenkins for ownCloud
d2a24b5186 [tx-robot] updated from transifex 2014-12-05 01:25:29 -05:00
Christian Kamm
40f44c2389 DB: Delete corrupt database. #2547
* Also use readonly DB access for SocketAPI.
2014-12-04 15:35:55 +01:00
Olivier Goffart
441b5bd1dc Setup Wizard: remove all folder definition before starting a new sync
Issue #1989
2014-12-04 15:18:27 +01:00
Christian Kamm
dc2f0d59cb FolderWizard: Clean up naming of 'add folder' button. #2371 2014-12-04 10:47:26 +01:00
Christian Kamm
4dcfacf2d5 Fix compile. :/ 2014-12-04 09:59:24 +01:00
Christian Kamm
b7485106ef NetworkJobs: Set timeout to 5 minutes everywhere. 2014-12-04 09:54:17 +01:00
Christian Kamm
f82893496b Fix typo. 2014-12-04 09:54:15 +01:00
Christian Kamm
c418e58f88 Etag job scheduling: Silence warnings, make prettier. 2014-12-04 09:52:13 +01:00
Jenkins for ownCloud
3020dc75ab [tx-robot] updated from transifex 2014-12-04 01:25:22 -05:00
Klaas Freitag
9ea359de52 GUI: Check if there are sync folders configured and how proper msg.
This fixes #2264
2014-12-03 17:11:42 +01:00
Klaas Freitag
c5daf7d1b6 Mac installer: Make the installer background brandable for MacOSX. 2014-12-03 14:37:59 +01:00
Christian Kamm
b7d7f424c5 FolderMan: only touch _currentSyncFolder when done #2407
Also simplity terminateSyncProcess() to always terminate the
*current* sync run. Only one can be running at a time anyway.
2014-12-03 13:46:37 +01:00
Daniel Molkentin
e1fa6f1a0d fix_frameworks is no longer required
This is taken care of by macdeployqt.py, which is
run during "make install"
2014-12-03 13:41:12 +01:00
Olivier Goffart
a23e0fef8d Update binary submodule 2014-12-03 11:18:01 +01:00
Olivier Goffart
0fd0b08c09 Windows shell integration: Always release the lock before calling win32 API
May help for 2515
2014-12-03 09:11:38 +01:00
Jenkins for ownCloud
ce1690b450 [tx-robot] updated from transifex 2014-12-03 01:25:27 -05:00
Markus Goetz
46bd473664 Folders: Move ETag check scheduling to FolderMan
Only 1 check per time is able to run now.
For #2553
Might improve #2479 #2485 #2534
2014-12-02 22:32:54 +01:00
Olivier Goffart
8fbb55a0c8 Wizard: Fix escaping of error message.
An url can contains % signs, so if it does, the errors formating was wrong
because of the use of QString::args

Also, the error is in html format, and we need to let the message box know
that, otherwise we will just see <br/>
2014-12-02 10:22:46 +01:00
Olivier Goffart
f046a7e7fe Wizard: Attempts to really close the database when starting the backup
Still for issue #1989
2014-12-02 10:22:46 +01:00
Olivier Goffart
b154e1baa1 Nautilus shell integration: Use fallback when XDG_RUNTIME_DIR is not defined
Same fallback as in Qt5

Task #2477
2014-12-01 12:06:09 +01:00
Jenkins for ownCloud
119a9983a9 [tx-robot] updated from transifex 2014-11-30 01:25:22 -05:00
Jenkins for ownCloud
2e06b4be66 [tx-robot] updated from transifex 2014-11-29 01:25:23 -05:00
Jenkins for ownCloud
0ec2e71f58 [tx-robot] updated from transifex 2014-11-28 01:25:25 -05:00
Olivier Goffart
2ed2ef3b28 Propagator QNAM: Fix resuming
We forgot to account the fact that we could have been resuming when
comparing the size of the Content-lenght to the size of the temporary file
2014-11-27 14:50:49 +01:00
Olivier Goffart
e7e91b6931 Revert "Folder: Don't blindly trigger sync on first EtagJob result"
We need to do a sync even if the etag was empty because we do not know
if this is because the etag really changed or because it was new.

Also, some part of the code rely on this fact to schedule a sync.

The fact that there is two sync with 30 sec at the beginning is not
a big problem, because we also need to do the sync the put the directory
etag in the db.

This reverts commit 1c001ee138.
2014-11-27 12:50:36 +01:00
Olivier Goffart
1f9d02e7fa Shibboleth: Fix our implemtnation of CookieJar::deleteCookie
It was deleting too many cookies.
That function is virtual in Qt5 and is used when adding cookie.
But some Shibboleth have several cookies with the same name, and we need to keep them.

Our implementaiton was meant to delete all the shiboleth cookies when we want to log out
2014-11-27 12:26:59 +01:00
Jenkins for ownCloud
2ee70db7cd [tx-robot] updated from transifex 2014-11-26 01:25:24 -05:00
Klaas Freitag
3e34d000f2 Propagator: Add the chunk size to PUT requests. 2014-11-25 10:21:33 +01:00
Jenkins for ownCloud
7f520a6f28 [tx-robot] updated from transifex 2014-11-24 01:25:22 -05:00
Jenkins for ownCloud
23f72ecf7b [tx-robot] updated from transifex 2014-11-23 01:25:22 -05:00
Jenkins for ownCloud
8c57e7621b [tx-robot] updated from transifex 2014-11-22 01:25:37 -05:00
Markus Goetz
1c001ee138 Folder: Don't blindly trigger sync on first EtagJob result
For #2352
2014-11-21 16:47:15 +01:00
Markus Goetz
fab82107bb OS X: Don't use hardcoded name in packages file 2014-11-21 16:34:30 +01:00
Olivier Goffart
41568c885d Propagator: only check the content-lenght if it is there
If content-lenght is 0, don't chack it is the size we recieved.
It can be zero when using HTTP chunk encoding.

Also do not remove the temporary file so it can be re-used on the next sync
and ask for a new sync immediatly to re-do the sync.

Fixup the fix to task #2528
2014-11-21 11:03:14 +01:00
Jenkins for ownCloud
dba2efe367 [tx-robot] updated from transifex 2014-11-21 02:52:45 -05:00
Christian Kamm
e3b07f569a FolderWatcherTest: Use Utility::usleep. 2014-11-21 08:21:36 +01:00
Klaas Freitag
65a307970b Propagator: Compare the actual file size with the request content length
The values must match. Otherwise the request did succeed, but the file
was not downloaded completely.

This fixes https://github.com/owncloud/mirall/issues/2528
2014-11-20 18:49:34 +01:00
Christian Kamm
3e3ca14b4c Print ssl library version only on Qt >=5.0.0. 2014-11-20 13:46:44 +01:00
Christian Kamm
d4e0941c27 Windows filewatcher: switch to ReadDirectoryChangesW.
Based on danimo's #2454 fix for #2455 and related to #2297.
2014-11-20 12:36:17 +01:00
Christian Kamm
9dc57359b9 csync db files: Hide after some commit/transactions. #2461
The shm and wal files are only created later.
2014-11-20 12:30:04 +01:00
Jenkins for ownCloud
06b31d7cf0 [tx-robot] updated from transifex 2014-11-20 01:25:20 -05:00
Christian Kamm
421a8cc6b7 Windows: Make unit tests compile. 2014-11-19 14:18:37 +01:00
Christian Kamm
3a448fda91 Windows mingw32: Fix finding of windres binary. 2014-11-19 14:16:56 +01:00
Markus Goetz
e890c4ae1b OS X: Move previous fix to proper location 2014-11-17 18:30:32 +01:00
Markus Goetz
7ada625161 OS X: Fix packages file 2014-11-17 17:48:29 +01:00
Olivier Goffart
7d8dd54b19 Merge pull request #2504 from owncloud/revert-2454-fswatcher_readdirectorychanges_port
Revert "WiP: switch to ReadDirectoryChangesW"
2014-11-17 11:11:39 +01:00
Olivier Goffart
0b275c4933 Revert "WiP: switch to ReadDirectoryChangesW" 2014-11-17 11:11:13 +01:00
Olivier Goffart
e529bbed90 Merge pull request #2454 from owncloud/fswatcher_readdirectorychanges_port
switch to ReadDirectoryChangesW
2014-11-17 09:43:29 +01:00
Jenkins for ownCloud
39e97779ec [tx-robot] updated from transifex 2014-11-17 01:25:22 -05:00
Jenkins for ownCloud
629d46ca25 [tx-robot] updated from transifex 2014-11-16 01:25:22 -05:00
Daniel Molkentin
c5a35ad56f Merge pull request #2499 from owncloud/revert-2412-nsis_shortcuts_all_users
Revert "Install shortcuts for all users"
2014-11-15 21:05:05 +01:00
Daniel Molkentin
1e94161ec1 Revert "Install shortcuts for all users" 2014-11-15 21:04:33 +01:00
Daniel Molkentin
6f78ff200c Merge pull request #2412 from owncloud/nsis_shortcuts_all_users
Install shortcuts for all users
2014-11-15 20:09:29 +01:00
Daniel Molkentin
02e96484a8 Install shortcuts for all users 2014-11-15 17:07:39 +01:00
Jenkins for ownCloud
67b0e4dd15 [tx-robot] updated from transifex 2014-11-15 01:25:23 -05:00
Markus Goetz
5b7ec19778 SyncEngine: Also output the neon version 2014-11-14 15:02:09 +01:00
Jenkins for ownCloud
e71c617bfd [tx-robot] updated from transifex 2014-11-14 01:25:20 -05:00
Jenkins for ownCloud
f1432992d3 [tx-robot] updated from transifex 2014-11-13 01:25:30 -05:00
Markus Goetz
348b7bf4eb SyncEngine: Output versions used 2014-11-12 09:21:37 +01:00
Markus Goetz
30479cc5a2 Wizard: Properly show error message 2014-11-12 09:21:37 +01:00
Jenkins for ownCloud
1ba1bdec2d [tx-robot] updated from transifex 2014-11-12 01:25:29 -05:00
Daniel Molkentin
8993af4378 Bump version in readme 2014-11-12 00:32:28 +01:00
Daniel Molkentin
9a58d0e559 Merge pull request #2469 from owncloud/fixing_indent
Fixing indent and make nautilus script python3 compatible.
2014-11-12 00:08:46 +01:00
Olivier Goffart
b04cb23ed5 t8.pl: fix the test for me
On localhost, the other file (the bigger one) was downloaded first
2014-11-11 16:38:20 +01:00
Jenkins for ownCloud
ced986e010 [tx-robot] updated from transifex 2014-11-11 01:25:22 -05:00
Jenkins for ownCloud
cde9b3ac85 [tx-robot] updated from transifex 2014-11-10 01:25:22 -05:00
hefee
f9dfdd58df Fixing indent and make nautilus script python3 compatible. 2014-11-09 16:59:01 +01:00
Jenkins for ownCloud
c9f9388ef6 [tx-robot] updated from transifex 2014-11-09 01:25:21 -05:00
Jenkins for ownCloud
b8cb180e4b [tx-robot] updated from transifex 2014-11-08 01:25:22 -05:00
Daniel Molkentin
e579504181 Merge pull request #2370 from owncloud/icons-overlay-doc
Add section on Overlay Icons to 'Using the Synchronization Client'
2014-11-07 16:52:26 +01:00
Daniel Molkentin
7c034b427e Handle invalid handle & fix an issue found during code review 2014-11-07 14:52:31 +01:00
Jenkins for ownCloud
08868594ae [tx-robot] updated from transifex 2014-11-07 01:25:32 -05:00
Daniel Molkentin
cc6e548a78 Merge pull request #2419 from owncloud/updater
Update and correct doc/autoupdate.rst
2014-11-06 19:53:33 +01:00
Daniel Molkentin
17a4299f74 Fix nautilus python integration 2014-11-06 19:26:43 +01:00
Daniel Molkentin
776f4dc316 v1.7.0 2014-11-06 15:53:17 +01:00
Daniel Molkentin
5db55d9e29 Prettify Changelog 2014-11-06 15:41:23 +01:00
Christian Kamm
5c9564ac08 Add to 1.7 changelog. 2014-11-06 15:31:09 +01:00
Daniel Molkentin
5c5a89c1a4 Revert "Bump binary directory to current master"
This reverts commit af4e9c30f5.

This is consistent with 176413d312.
2014-11-06 15:21:39 +01:00
Daniel Molkentin
176413d312 Revert "Windows Shell Integration: Show status icon for root folder"
This reverts commit 5805ffebec.

There is no good way to fix this on the Mirall side without risk.
Delay until after 1.7.0
2014-11-06 15:18:54 +01:00
Olivier Goffart
b70ecc3dd3 Never overwrite the mtime from the local file system in the db when updating the metadata
Attempt to fix #2431
2014-11-06 15:13:10 +01:00
Daniel Molkentin
89670e5ce4 Folderwatcher_win: handle conversion error 2014-11-06 12:54:33 +01:00
Christian Kamm
174e1acbc7 Folder::wipe(): Remove partial downloads and -shm,-wal db files. 2014-11-06 12:49:02 +01:00
Christian Kamm
1f09a24a72 Resync button: Remove partial downloads too. #2445 2014-11-06 12:17:04 +01:00
Christian Kamm
eed91ddf46 Legacy propagator: Don't use mtime retrieved via _fstat64.
May be the cause of #2431
2014-11-06 12:16:55 +01:00
Daniel Molkentin
96a7118d05 WiP: switch to ReadDirectoryChangesW 2014-11-06 12:04:33 +01:00
Klaas Freitag
6eec896282 FolderWatcher: Check for hidden outside of loop 2014-11-06 09:23:30 +01:00
Klaas Freitag
a78bb252de Nautilus shell: Remove some useless logging. 2014-11-06 09:23:30 +01:00
Jenkins for ownCloud
0ba07f19f7 [tx-robot] updated from transifex 2014-11-06 01:25:24 -05:00
Christian Kamm
a49a6bfd88 Logging: Report setModTime failures.
Ths may be helpful for #2252 and maybe even #2431.
2014-11-05 13:20:19 +01:00
Christian Kamm
b87931c0a9 Logging: Print etags, not just result of comparison. 2014-11-05 13:08:53 +01:00
Christian Kamm
9b640d586b Wizard: Fix local folder warning in advanced setup wizard. #2362
The _oldLocalFolder should always be the previously configured
folder, not the one that was most recently chosen on the wizard
page.
2014-11-05 12:10:41 +01:00
Christian Kamm
7440ffc0e6 Download: Fix data loss when rename fails. #2428 2014-11-05 11:00:46 +01:00
Jenkins for ownCloud
63e901cd0b [tx-robot] updated from transifex 2014-11-05 01:25:23 -05:00
Daniel Molkentin
af4e9c30f5 Bump binary directory to current master 2014-11-04 09:33:04 +01:00
Daniel Molkentin
5805ffebec Windows Shell Integration: Show status icon for root folder 2014-11-04 09:30:29 +01:00
Jenkins for ownCloud
39bfacf1d5 [tx-robot] updated from transifex 2014-11-04 01:25:23 -05:00
Daniel Molkentin
8d30fc2718 Update binary subrepo to master 2014-11-03 22:51:55 +01:00
Daniel Molkentin
19daff36b0 Windows Overlay: Fix icon refresh
The condition for the refresh was inverse of what it should have been.
2014-11-03 20:46:35 +01:00
Daniel Molkentin
c34c8ff358 Windows Overlay: Use FLUSHNOW everywhere to speed up updates 2014-11-03 20:45:38 +01:00
Daniel Molkentin
af68cb6029 Move binary submodule to current master 2014-11-03 11:17:04 +01:00
Jenkins for ownCloud
6b6b212643 [tx-robot] updated from transifex 2014-11-03 01:25:21 -05:00
Jenkins for ownCloud
dd2a71fa8f [tx-robot] updated from transifex 2014-11-02 01:25:21 -04:00
Jenkins for ownCloud
cd72d133a3 [tx-robot] updated from transifex 2014-11-01 01:25:22 -04:00
Jenkins for ownCloud
d3662d0e34 [tx-robot] updated from transifex 2014-10-31 01:25:27 -04:00
Markus Goetz
cf6219bb6f NetworkJobs: Improve timeout handling and increase timeout by 5 sec 2014-10-30 11:54:58 +01:00
Christian Kamm
45eeb5065f Download: Avoid overwriting file with case conflict. #1914 2014-10-30 09:06:53 +01:00
Jenkins for ownCloud
f563eb1f63 [tx-robot] updated from transifex 2014-10-30 01:25:30 -04:00
Carla Schroder
2c1f31cecb Update autoupdate.rst
Corrected configuration file location
2014-10-29 09:56:17 -07:00
Klaas Freitag
1029f9521c tests: exit t5.pl if running against ownCloud 6
t5.pl checks the environment variable SERVER_VERSION and if that equals
"owncloud6" it bails out after a check of the sharing ocs api.
2014-10-29 14:24:36 +01:00
Klaas Freitag
825eca078d tests: make t1.pl work on jenkins, for that disable a size compare. 2014-10-29 14:01:58 +01:00
Olivier Goffart
1eccfb798f Add missing license headers
Part of #2068
2014-10-29 13:30:46 +01:00
Olivier Goffart
7810da51a8 Propagator: report error when deleting directories
Will help to understand why a directory cannot be removed

Will help for #2348
2014-10-29 12:23:48 +01:00
Olivier Goffart
a470138450 Windows Shell Integration: refresh the cache on UPDATE_VIEW
Attempt to fix #2383
2014-10-29 11:00:51 +01:00
Markus Goetz
7bad731ad2 CheckServerJob: Guard again null reply
Lucia had reported a crash in this function
2014-10-29 09:38:20 +01:00
Jenkins for ownCloud
eeb54290b3 [tx-robot] updated from transifex 2014-10-29 01:25:27 -04:00
Carla Schroder
94be12b9e4 Merge branch 'updater' of https://github.com/owncloud/mirall into updater 2014-10-28 15:01:34 -07:00
Carla Schroder
1862fb77ff Correct Linux section on disabling update notifications 2014-10-28 14:57:18 -07:00
Markus Goetz
782463589e ownSql: Also mention filename 2014-10-28 21:50:09 +01:00
Markus Goetz
ff570c4a6b ownSql: Don't set busy timeout on bad object 2014-10-28 21:46:30 +01:00
Carla Schroder
06b619f0ed Update autoupdate.rst
Typo correction
2014-10-28 12:19:05 -07:00
Carla Schroder
f5cc6cfd07 Fix typos and clean up wording 2014-10-28 11:56:49 -07:00
Carla Schroder
0f5cf00e35 Update The Automatic Updater manual page with current information 2014-10-28 11:52:58 -07:00
Klaas Freitag
105ff694f2 SyncEngine: Handle 503 condition as soft error to properly handle etags.
Otherwise the ETags could be removed from the db and cause file
deletes.
2014-10-28 17:13:21 +01:00
Jenkins for ownCloud
26ff6be63c [tx-robot] updated from transifex 2014-10-28 01:25:42 -04:00
Daniel Molkentin
47e3da9ebf Merge pull request #2414 from owncloud/fix_2365
Doc: Fix build documentation, adjust it to 1.7.
2014-10-27 16:15:14 -04:00
Daniel Molkentin
b7ce5ba82a Doc: Fix build documentation, adjust it to 1.7.
Fixes #2365
2014-10-27 16:14:32 -04:00
Olivier Goffart
5723abe6eb Merge remote-tracking branch 'origin/fix_service_unavailable' into 1.7 2014-10-27 20:49:46 +01:00
Daniel Molkentin
95a9b0427c doc: Fix markup in build.rst 2014-10-27 14:54:23 -04:00
Klaas Freitag
0692fea9d8 discovery: handle 503 reply code from server for directories
503 for directories means that the dir is a mounted directory from an
external mount which currently is not available. The directory is
ignored and not traversed into during discovery phase.
2014-10-27 19:21:12 +01:00
Markus Goetz
b0882a5cd2 Fix compile 2014-10-27 17:18:49 +01:00
Markus Goetz
4c1a0005e6 Make two more asserts usable in nondebug 2014-10-27 16:01:18 +01:00
Markus Goetz
05ceed926c SyncEngine: Log for an assert, return -1 for nondebug compile 2014-10-27 15:52:17 +01:00
Klaas Freitag
b691521662 tests: Fix CSync Journal test, use real CSYNC struct from csync_private.
This fixes bug #2396
2014-10-27 13:15:33 +01:00
Olivier Goffart
ce300d88ee Wizard: show the choice to start a clean sync if the directory exist even on new accounts
Task #2406
2014-10-27 13:05:17 +01:00
Brandon Coleman
05c0249672 correct spelling on user is empty error. 2014-10-27 07:59:31 -04:00
Brandon Coleman
2498c13078 options are required at the beginning of owncloudcmd.
Conflicts:
	src/owncloudcmd/owncloudcmd.cpp
2014-10-27 07:59:31 -04:00
Klaas Freitag
ab5dae741a Show GIT SHA sum in cmake output. 2014-10-27 11:54:22 +01:00
Olivier Goffart
cddad94e45 Selective Sync: change the label text
to specify that the files will be removed from the local folder

Task #2404
2014-10-27 11:33:25 +01:00
Jenkins for ownCloud
2f0a40c1c8 [tx-robot] updated from transifex 2014-10-27 01:25:20 -04:00
Jenkins for ownCloud
3b1ff5bf41 [tx-robot] updated from transifex 2014-10-26 01:25:20 -04:00
Daniel Molkentin
1bd1c61c3c Merge pull request #2399 from r2evans/patch-1
add 64-bit windows registry location
2014-10-25 10:31:04 -04:00
r2evans
9cd81d87b2 add 64-bit windows registry location 2014-10-25 07:25:18 -07:00
Jenkins for ownCloud
59efea1b0e [tx-robot] updated from transifex 2014-10-25 01:25:22 -04:00
Carla Schroder
b5da8423a6 Update navigating.rst 2014-10-22 19:24:19 -07:00
Carla Schroder
c3de0a2d4b Add section on Overlay Icons to 'Using the Synchronization Client' 2014-10-22 19:20:58 -07:00
116 changed files with 8152 additions and 6483 deletions

View File

@@ -14,6 +14,12 @@ if ( EXISTS ${OEM_THEME_DIR}/OEM.cmake )
else ()
include ( ${CMAKE_SOURCE_DIR}/OWNCLOUD.cmake )
endif()
# need this logic to not mess with re/uninstallations via macosx.pkgproj
if(${APPLICATION_REV_DOMAIN} STREQUAL "com.owncloud.desktopclient")
set(APPLICATION_REV_DOMAIN_INSTALLER "com.ownCloud.client")
else()
set(APPLICATION_REV_DOMAIN_INSTALLER ${APPLICATION_REV_DOMAIN})
endif()
if (NOT DEFINED APPLICATION_SHORTNAME)
set ( APPLICATION_SHORTNAME ${APPLICATION_NAME} )
@@ -52,6 +58,7 @@ if (${GIT_SHA1} STREQUAL "GITDIR-NOTFOUND")
set (GIT_SHA1 "${sha1_candidate}")
endif()
endif()
message(STATUS "GIT_SHA1 ${GIT_SHA1}")
endif()
set(SYSCONFDIR ${SYSCONF_INSTALL_DIR})

View File

@@ -1,19 +1,42 @@
ChangeLog
=========
version 1.7.0 (release 2014-10-xx)
version 1.7.1 (release 2014-12-xx)
* Win32: improved filesystem watcher
* Documentation fixes and updates
* Nautilus python plugin fixed for python 3
* GUI wording fixes plus improved log messages
* Win32: Install shortcuts for all users
* MacOSX: Fixed branding of the pkg file
* Fix hidning of the database files in the sync directories
* Compare http download size with the header value to avoid broken
downloads, bug #2528
* Avoid initial ETag fetch job at startup, which is not needed.
* Add chunk size http header to PUT requests
* Fixed deteteCookie method of our CookieJar, fix for Shibboleth
* Added fallback for distros where XDG_RUNTIME_DIR is undefined
* Fix the setup wizard, bug #1989, #2264
* Fix scheduling of ETag check jobs, bug #2553
* Win32: Improve threading with shell integration
* Fix to avoid syncing more than one folder at a time, bug #2407
* Use fife minutes timeout for all network jobs
* Cleanup for Folderwizard wording
* Improve journal check: Remove corrupted journal files, bug #2547
* Fix item count in progress dialog for deletes, bug #1132
* oC7 Sharing: Handle new sharing options of ownCloud 7 correctly.
version 1.7.0 (release 2014-11-07)
* oC7 Sharing: Handle new sharing options of ownCloud 7 correctly.
* Added Selective sync: Ability to unselect server folders which are
excluded from syncing, plus GUI and setup GUI
* Added overlay icons for Windows Explorer, Mac OS Finder and GNOME Nautilus.
Information is provided by the client via a local socket / named pipe API
which provides information about the sync status of files.
* Improved local change detection: consider file size, detect files
with ongoing changes and do not upload immediately
* Improved HTTP request timeout handler: all successful requests reset
the timeout counter
* Improvements for syncing command line tool: netrc support, improved
SSL support, non interactive mode
* Added a socket based API to provide file management shells with status
information about the sync status of files. That is a prerequisite for
the overlay icons in the file managers.
* Permission system: ownCloud 7 delivers file and folder permissions,
added ability to deal with it for shared folders and more.
* Ignore handling: Do not recurse into ignored or excluded directories
@@ -23,9 +46,17 @@ version 1.7.0 (release 2014-10-xx)
* Blacklist improvements
* Improved logging: more useful meta info, removed noise
* Updated to latest Qt5 versions on Windows and OS X
* Fixed data loss when renaming a download temporary fails and there was
a conflict at the same time.
* Fixed missing warnings about reusing a sync folder when the back button
was used in the advanced folder setup wizard.
* The 'Retry Sync' button now also restarts all downloads.
* Clean up temporary downloads and some extra database files when wiping a
folder.
* OS X: Sparkle update to provide pkg format properly
* OS X: Change distribution format from dmg to pkg with new installer.
* Win: Fix handling of filenames with trailing dot or space
* Windows: Fix handling of filenames with trailing dot or space
* Windows: Don't use the wrong way to get file mtimes in the legacy propagator.
version 1.6.4 (release 2014-10-22)
* Fix startup logic, fixes bug #1989

View File

@@ -8,5 +8,9 @@ set( APPLICATION_UPDATE_URL "https://updates.owncloud.com/client/" CACHE string
set( THEME_CLASS "ownCloudTheme" )
set( APPLICATION_REV_DOMAIN "com.owncloud.desktopclient" )
set( WIN_SETUP_BITMAP_PATH "${CMAKE_SOURCE_DIR}/admin/win/nsi" )
set( MAC_INSTALLER_BACKGROUND_FILE "${CMAKE_SOURCE_DIR}/admin/osx/installer-background.png" CACHE STRING "The MacOSX installer background image")
# set( THEME_INCLUDE "${OEM_THEME_DIR}/mytheme.h" )
# set( APPLICATION_LICENSE "${OEM_THEME_DIR}/license.txt )

View File

@@ -18,7 +18,7 @@ It uses OCSync as its syncing backend.
## Building the source code
Please refer to doc/building.rst, or
[Building the Client](http://doc.owncloud.org/desktop/1.5/building.html)
[Building the Client](http://doc.owncloud.org/desktop/1.7/building.html)
in the ownCloud client manual.
## Authors

View File

@@ -1,6 +1,6 @@
set( MIRALL_VERSION_MAJOR 1 )
set( MIRALL_VERSION_MINOR 7 )
set( MIRALL_VERSION_PATCH 0 )
set( MIRALL_VERSION_PATCH 1 )
set( MIRALL_SOVERSION 0 )
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )

View File

@@ -1,3 +1,15 @@
# Check if varialbe MAC_INSTALLER_BACKGROUND_FILE is defined. That might come
# from the OEM.cmake for branded clients or from OWNCLOUD.cmake for the non
# branded client.
# Make sure that the MAC_INSTALLER_BACKGROUND_FILE contains the full path, ie.
# includes CMAKE_SOURCE_DIR or so.
if (DEFINED MAC_INSTALLER_BACKGROUND_FILE )
set(MAC_INSTALLER_DO_CUSTOM_BACKGROUND "1")
else()
set(MAC_INSTALLER_DO_CUSTOM_BACKGROUND "0")
endif()
configure_file(create_mac_pkg.sh.cmake ${CMAKE_CURRENT_BINARY_DIR}/create_mac.sh)
configure_file(macosx.pkgproj ${CMAKE_CURRENT_BINARY_DIR}/macosx.pkgproj)
configure_file(macosx.pkgproj ${CMAKE_CURRENT_BINARY_DIR}/macosx.pkgproj)

View File

@@ -485,9 +485,9 @@
<key>CONCLUSION_ACTION</key>
<integer>0</integer>
<key>IDENTIFIER</key>
<string>com.ownCloud.client</string>
<string>@APPLICATION_REV_DOMAIN_INSTALLER@</string>
<key>NAME</key>
<string>ownCloud Client</string>
<string>@APPLICATION_NAME@</string>
<key>OVERWRITE_PERMISSIONS</key>
<false/>
<key>VERSION</key>
@@ -1055,12 +1055,12 @@
<key>BACKGROUND_PATH</key>
<dict>
<key>PATH</key>
<string>@CMAKE_SOURCE_DIR@/admin/osx/installer-background.png</string>
<string>@MAC_INSTALLER_BACKGROUND_FILE@</string>
<key>PATH_TYPE</key>
<integer>0</integer>
</dict>
<key>CUSTOM</key>
<integer>1</integer>
<integer>@MAC_INSTALLER_DO_CUSTOM_BACKGROUND@</integer>
<key>SCALING</key>
<integer>0</integer>
</dict>
@@ -1213,7 +1213,7 @@
<key>LANGUAGE</key>
<string>English</string>
<key>VALUE</key>
<string>ownCloud Client</string>
<string>@APPLICATION_NAME@ Client</string>
</dict>
</array>
</dict>
@@ -1413,7 +1413,7 @@
</dict>
</array>
<key>NAME</key>
<string>ownCloud Installer</string>
<string>@APPLICATION_NAME@ Installer</string>
<key>REFERENCE_FOLDER_PATH</key>
<string>@CMAKE_INSTALL_DIR@</string>
</dict>

View File

@@ -5,26 +5,6 @@
src_app="$1"
identity="$2"
QT_FMWK_VERSION="5"
fix_frameworks() {
TMP_APP=$1
QT_FMWK_PATH=$2
QT_FMWKS=$3/Qt*.framework
echo "Patching Qt frameworks..."
for FMWK in $QT_FMWKS; do
FMWK_NAME=`basename -s .framework $FMWK`
FMWK=`basename $FMWK`
FMWK_PATH="${TMP_APP}/Contents/Frameworks/${FMWK}"
mkdir -p "${FMWK_PATH}/Versions/${QT_FMWK_VERSION}/Resources/"
cp -avf "${QT_FMWK_PATH}/${FMWK}/Contents/Info.plist" "${FMWK_PATH}/Versions/${QT_FMWK_VERSION}/Resources"
(cd "${FMWK_PATH}" && ln -sf "Versions/${QT_FMWK_VERSION}/Resources" "Resources")
perl -pi -e "s/${FMWK_NAME}_debug/${FMWK_NAME}/" "${FMWK_PATH}/Resources/Info.plist"
done
}
fix_frameworks "$src_app" `qmake -query QT_INSTALL_LIBS` "$src_app"/Contents/Frameworks
codesign -s "$identity" --force --verbose=4 --deep "$src_app"
# Just for our debug purposes:

2
binary

Submodule binary updated: 18d9ac810b...139acd195b

View File

@@ -1,4 +1,4 @@
SET(WINDRES_EXECUTABLE ${CMAKE_RC_COMPILER})
SET(WINDRES_EXECUTABLE_BASE ${CMAKE_RC_COMPILER})
# This macro is taken from kdelibs/cmake/modules/KDE4Macros.cmake.
#
@@ -21,7 +21,7 @@ macro (KDE4_ADD_APP_ICON appsources pattern)
else(NOT WINCE)
find_program(PNG2ICO_EXECUTABLE NAMES png2ico PATHS ${HOST_BINDIR} NO_DEFAULT_PATH )
endif(NOT WINCE)
find_program(WINDRES_EXECUTABLE NAMES windres)
find_program(WINDRES_EXECUTABLE NAMES ${WINDRES_EXECUTABLE_BASE})
if(MSVC)
set(WINDRES_EXECUTABLE TRUE)
endif(MSVC)

View File

@@ -476,6 +476,8 @@ SectionEnd
File "${BUILD_PATH}\vcredist_x64.exe"
Call InstallRedistributables
CreateDirectory "$INSTDIR\shellext"
!define LIBRARY_COM
!define LIBRARY_SHELL_EXTENSION
${If} ${RunningX64}
!define LIBRARY_X64
!insertmacro InstallLib DLL NOTSHARED REBOOT_PROTECTED "${SOURCE_PATH}\binary\shell_integration\windows\Release\x64\OCUtil_x64.dll" "$INSTDIR\shellext\OCUtil_x64.dll" "$INSTDIR\shellext"
@@ -485,6 +487,8 @@ SectionEnd
!insertmacro InstallLib DLL NOTSHARED REBOOT_PROTECTED "${SOURCE_PATH}\binary\shell_integration\windows\Release\Win32\OCUtil_x86.dll" "$INSTDIR\shellext\OCUtil_x86.dll" "$INSTDIR\shellext"
!insertmacro InstallLib REGDLL NOTSHARED REBOOT_PROTECTED "${SOURCE_PATH}\binary\shell_integration\windows\Release\Win32\OCOverlays_x86.dll" "$INSTDIR\shellext\OCOverlays_x86.dll" "$INSTDIR\shellext"
${Endif}
!undef LIBRARY_COM
!undef LIBRARY_SHELL_EXTENSION
${MementoSectionEnd}
!endif
@@ -640,15 +644,19 @@ Section Uninstall
!define LIBRARY_COM
!define LIBRARY_SHELL_EXTENSION
${If} ${HasSection} SEC_SHELL_EXT
DetailPrint "Uninstalling x64 overlay DLLs"
!define LIBRARY_X64
!insertmacro UnInstallLib DLL NOTSHARED REBOOT_PROTECTED "$INSTDIR/shellext/OCUtil_x64.dll"
!insertmacro UnInstallLib REGDLL NOTSHARED REBOOT_PROTECTED "$INSTDIR/shellext/OCOverlays_x64.dll"
!insertmacro UnInstallLib REGDLL NOTSHARED REBOOT_PROTECTED "$INSTDIR\shellext\OCOverlays_x64.dll"
!insertmacro UnInstallLib DLL NOTSHARED REBOOT_PROTECTED "$INSTDIR\shellext\OCUtil_x64.dll"
!undef LIBRARY_X64
${Else}
!insertmacro UnInstallLib DLL NOTSHARED REBOOT_PROTECTED "$INSTDIR/shellext/OCUtil_x86.dll"
!insertmacro UnInstallLib REGDLL NOTSHARED REBOOT_PROTECTED "$INSTDIR/shellext/OCOverlays_x86.dll"
DetailPrint "Uninstalling x86 overlay DLLs"
!insertmacro UnInstallLib REGDLL NOTSHARED REBOOT_PROTECTED "$INSTDIR\shellext\OCOverlays_x86.dll"
!insertmacro UnInstallLib DLL NOTSHARED REBOOT_PROTECTED "$INSTDIR\shellext\OCUtil_x86.dll"
${EndIf}
!endif
!undef LIBRARY_COM
!undef LIBRARY_SHELL_EXTENSION
!endif
;Start menu shortcut
!ifdef OPTION_SECTION_SC_START_MENU

View File

@@ -254,6 +254,10 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
is_equal_files = (other->modtime == cur->modtime);
} else {
is_equal_files = ((other->size == cur->size) && (other->modtime == cur->modtime));
// FIXME: do a binary comparision of the file here because of the following
// edge case:
// The files could still have different content, even though the mtime
// and size are the same.
}
if (is_equal_files) {
/* The files are considered equal. */

View File

@@ -581,6 +581,17 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
if (asp < 0) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!");
}
} else if(errno == ERRNO_SERVICE_UNAVAILABLE) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Service was not available!");
if (ctx->current_fs) {
ctx->current_fs->instruction = CSYNC_INSTRUCTION_IGNORE;
ctx->current_fs->error_status = CSYNC_STATUS_SERVICE_UNAVAILABLE;
/* If a directory has ignored files, put the flag on the parent directory as well */
if( previous_fs ) {
previous_fs->has_ignored_files = true;
}
goto done;
}
} else {
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "opendir failed for %s - errno %d", uri, errno);
}

View File

@@ -96,6 +96,7 @@ hbf_transfer_t *hbf_init_transfer( const char *dest_uri ) {
transfer->block_size = DEFAULT_BLOCK_SIZE;
transfer->threshold = transfer->block_size;
transfer->modtime_accepted = 0;
transfer->oc_header_modtime = 0;
return transfer;
}
@@ -491,8 +492,8 @@ Hbf_State hbf_transfer( ne_session *session, hbf_transfer_t *transfer, const cha
snprintf(buf, sizeof(buf), "%"PRId64, transfer->stat_size);
ne_add_request_header(req, "OC-Total-Length", buf);
if( transfer->modtime > 0 ) {
snprintf(buf, sizeof(buf), "%"PRId64, transfer->modtime);
if( transfer->oc_header_modtime > 0 ) {
snprintf(buf, sizeof(buf), "%"PRId64, transfer->oc_header_modtime);
ne_add_request_header(req, "X-OC-Mtime", buf);
}
@@ -502,6 +503,8 @@ Hbf_State hbf_transfer( ne_session *session, hbf_transfer_t *transfer, const cha
if( transfer->block_cnt > 1 ) {
ne_add_request_header(req, "OC-Chunked", "1");
snprintf(buf, sizeof(buf), "%"PRId64, transfer->threshold);
ne_add_request_header(req, "OC-Chunk-Size", buf);
}
ne_add_request_header( req, "Content-Type", "application/octet-stream");

View File

@@ -92,6 +92,7 @@ struct hbf_transfer_s {
int64_t stat_size;
time_t modtime;
time_t oc_header_modtime;
int64_t block_size;
int64_t threshold;

View File

@@ -362,6 +362,8 @@ sub assertFile($$)
}
my $stat_ok = stat( $localFile2 );
print " *** STAT failed for $localFile2\n" unless( $stat_ok );
assert($stat_ok, "Stat failed for file $localFile");
my @info = stat( $localFile2 );
my $localModTime = $info[9];
assert( $remoteModTime == $localModTime, "Modified-Times differ: remote: $remoteModTime <-> local: $localModTime" );
@@ -371,7 +373,7 @@ sub assertFile($$)
my $remoteSize = $res->get_property( "getcontentlength" );
if( $remoteSize ) { # directories do not have a contentlength
print "Local versus Remote size: $localSize <-> $remoteSize\n";
assert( $localSize == $remoteSize, "File sizes differ" );
# assert( $localSize == $remoteSize, "File sizes differ" ); # FIXME enable this again but it causes trouble on Jenkins all the time.
}
}

View File

@@ -51,6 +51,11 @@ print "Created share with id <$shareId>\n";
assert( $shareId > 0 );
if( $ENV{SERVER_VERSION} eq "owncloud6" ) {
print "This test does not make more sense for ownCloud6, leaving for good!\n\n";
exit;
}
# put a couple of files into the shared directory in the sharer account
glob_put( 'sharing/*', $share_dir, $sharee);
@@ -62,7 +67,6 @@ moveRemoteFile( server() . $share_dir, localDir(), 1 );
printInfo("Initial sync, sync stuff down.");
csync();
assertLocalAndRemoteDir( '', 0 );
# Local file to a read/write share should be synced up

View File

@@ -35,7 +35,7 @@ print "Hello, this is t8, a tester for syncing of files on a case sensitive FS\n
# The test is run on a 'normal' file system, but we tell pwncloud that it is case preserving anyway
$ENV{OWNCLOUD_TEST_CASE_PRESERVING} = "1";
# FIXME! the code does not work with parallelism
# No parallelism for more deterministic action.
$ENV{OWNCLOUD_MAX_PARALLEL}="1";
initTesting();
@@ -112,6 +112,25 @@ assert( !-e localDir() . 'dir' );
# dir/NORMAL.dat is still on the server
printInfo( "Attempt downloading two clashing files in parallel" );
# Enable parallelism
$ENV{OWNCLOUD_MAX_PARALLEL}="2";
my $tmpdir2 = "/tmp/t8/parallel/";
mkdir($tmpdir2);
createLocalFile( $tmpdir2 . "FILE.dat", 23251233 );
createLocalFile( $tmpdir2 . "file.dat", 33 );
createRemoteDir( "parallel" );
glob_put( "$tmpdir2/*", "parallel" );
csync();
# only one file must exist
assert( (!-e localDir() . 'parallel/FILE.dat' ) or (!-e localDir() . 'parallel/file.dat') );
assert( (-e localDir() . 'parallel/FILE.dat' ) or (-e localDir() . 'parallel/file.dat') );
cleanup();
system("rm -r " . $tmpdir);

View File

@@ -1,16 +1,19 @@
The Automatic Updater
=====================
To ensure that you are always using the latest version of the ownCloud client,
an auto-update mechanism has been added in Version 1.5.1. The Automatic Updater
ensures that you automatically profit from the latest features and bugfixes.
The Automatic Updater ensures that you always have the
latest features and bugfixes for your ownCloud synchronization client.
.. note:: The Automatic Updater functions differently, depending on the operating system.
The Automatic Updater updates only on Mac OS X and Windows computers; Linux
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
available.
Basic Workflow
--------------
The following sections describe how to use the Automatic Updater on different operating systems:
The following sections describe how to use the Automatic Updater on different
operating systems:
Windows
^^^^^^^
@@ -36,7 +39,7 @@ process for Mac OS X applications.
Linux
^^^^^
Linux distributions provide their own update tool, so ownCloud clients that use
Linux distributions provide their own update tools, so ownCloud clients that use
the Linux operating system do not perform any updates on their own. Linux
operating systems do, however, check for the latest version of the ownCloud
client and passively notify the user (``Settings -> General -> Updates``) when
@@ -52,7 +55,7 @@ deployment tools and policies. To address this case, it is possible to disable
the auto-updater entirely. The following sections describe how to disable the
auto-update mechanism for different operating systems.
Preventing Automatic Updates in Windows Environents
Preventing Automatic Updates in Windows Environments
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can prevent automatic updates from occuring in Windows environments using
@@ -61,9 +64,10 @@ update check mechanism whereas the second method prevents any manual overrides.
To prevent automatic updates, but allow manual overrides:
1. Migrate to the following directory::
1. Migrate to the following directory:
HKEY_LOCAL_MACHINE\Software\ownCloud\ownCloud
a. (32-bit) ``HKEY_LOCAL_MACHINE\Software\ownCloud\ownCloud``
b. (64-bit) ``HKEY_LOCAL_MACHINE\Software\Wow6432Node\ownCloud\ownCloud``
2. Add the key ``skipUpdateCheck`` (of type DWORD).
@@ -73,7 +77,8 @@ To manually override this key, use the same value in ``HKEY_CURRENT_USER``.
To prevent automatic updates and disallow manual overrides:
.. note::This is the preferred method of controlling the updater behavior using Group Policies.
.. note::This is the preferred method of controlling the updater behavior using
Group Policies.
1. Migrate to the following directory::
@@ -111,16 +116,10 @@ to ``/Library/Preferences/com.owncloud.desktopclient.plist``.
Preventing Automatic Updates in Linux Environments
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Because Linux does not provide automatic updating functionality, there is no
need to remove the automatic-update check. However, if you want to disable
this check:
Because the Linux client does not provide automatic updating functionality, there is no
need to remove the automatic-update check. However, if you want to disable it edit your desktop
client configuration file, ``$HOME/.local/share/data/ownCloud/owncloud.cfg``. Add these lines:
1. Locate and open the following file::
/etc/ownCloud/ownCloud.conf
2. Add the following content to the file::
[General]
skipUpdateCheck=true
[General]
skipUpdateCheck=true

View File

@@ -8,9 +8,9 @@ major platforms. You should read this section if you want to develop for the
desktop client.
.. note:: Building instruction are subject to change as development proceeds.
Please check the version for which you want to built.
Please check the version for which you want to build.
The instructions contained in this topic were updated to work with version 1.5 of the ownCloud Client.
The instructions contained in this topic were updated to work with version 1.7 of the ownCloud Client.
Linux
-----
@@ -24,6 +24,11 @@ Linux
3. Follow the `generic build instructions`_.
4. (Optional) Call ``make install`` to install the client to the ``/usr/local/bin`` directory.
.. note:: This step requires the ``mingw32-cross-nsis`` packages be installed on
Windows.
Mac OS X
--------
@@ -41,17 +46,30 @@ To set up your build enviroment for development using HomeBrew_:
1. Add the ownCloud repository using the following command::
brew tap owncloud/owncloud
brew tap owncloud/owncloud
2. Install any missing dependencies::
brew install $(brew deps mirall)
brew install $(brew deps mirall)
To build mirall, follow the `generic build instructions`_.
3. Add Qt from brew to the path::
.. note:: Because the product from the mirall build is an app bundle, do not
call ``make install`` at any time. Instead, call ``make package`` to create an
install-ready disk image.
export PATH=/usr/local/Cellar/qt5/5.x.y/bin/qmake
Where ``x.z`` is the current version of Qt 5 that brew has installed
on your machine.
5. For compilation of mirall, follow the `generic build instructions`_.
6. In the build directory, run ``admin/osx/create_mac.sh <build_dir>
<install_dir>``. If you have a developer signing certificate, you can specify
its Common Name as a third parameter (use quotes) to have the package
signed automatically.
.. note:: Contrary to earlier versions, ownCloud 1.7 and later are packaged
as a ``pkg`` installer. Do not call "make package" at any time when
compiling for OS X, as this will build a disk image, and will not
work correctly.
Windows (Cross-Compile)
-----------------------
@@ -63,15 +81,14 @@ have it installed already.
To cross-compile:
1. Add the following repositories using YaST or ``zypper ar`` (adjust when using openSUSE 12.2 or 13.1):
1. Add the following repositories using YaST or ``zypper ar`` (adjust when using openSUSE 12.2 or 13.1)::
- ``zypper ar http://download.opensuse.org/repositories/windows:/mingw:/win32/openSUSE_13.1/windows:mingw:win32.repo``
- ``zypper ar http://download.opensuse.org/repositories/windows:/mingw/openSUSE_13.1/windows:mingw.repo``
zypper ar http://download.opensuse.org/repositories/windows:/mingw:/win32/openSUSE_13.1/windows:mingw:win32.repo
zypper ar http://download.opensuse.org/repositories/windows:/mingw/openSUSE_13.1/windows:mingw.repo
2. Install the cross-compiler packages and the cross-compiled dependencies::
``zypper install cmake make mingw32-cross-binutils mingw32-cross-cpp mingw32-cross-gcc \
zypper install cmake make mingw32-cross-binutils mingw32-cross-cpp mingw32-cross-gcc \
mingw32-cross-gcc-c++ mingw32-cross-pkg-config mingw32-filesystem \
mingw32-headers mingw32-runtime site-config mingw32-libqt4-sql \
mingw32-libqt4-sql-sqlite mingw32-sqlite mingw32-libsqlite-devel \
@@ -82,42 +99,44 @@ To cross-compile:
mingw32-libpng-devel mingw32-libsqlite mingw32-qtkeychain \
mingw32-qtkeychain-devel mingw32-dlfcn mingw32-libintl-devel \
mingw32-libneon-devel mingw32-libopenssl-devel mingw32-libproxy-devel \
mingw32-libxml2-devel mingw32-zlib-devel``
mingw32-libxml2-devel mingw32-zlib-devel
3. For the installer, install the NSIS installer package::
``zypper install mingw32-cross-nsis``
zypper install mingw32-cross-nsis
4. Install the following plugin::
``mingw32-cross-nsis-plugin-processes mingw32-cross-nsis-plugin-uac``
mingw32-cross-nsis-plugin-processes mingw32-cross-nsis-plugin-uac
.. note:: This plugin is typically required. However, due to a current bug
in ``mingw``, the plugins do not currently build properly from source.
5. Manually download and install the following files using ``rpm -ivh <package>``:
..note:: These files operate using openSUSE 12.2 and newer.
.. note:: These files also work for more recent openSUSE versions!
- ``rpm -ihv http://download.tomahawk-player.org/packman/mingw:32/openSUSE_12.1/x86_64/mingw32-cross-nsis-plugin-processes-0-1.1.x86_64.rpm``
::
- ``rpm -ihv http://download.tomahawk-player.org/packman/mingw:32/openSUSE_12.1/x86_64/mingw32-cross-nsis-plugin-uac-0-3.1.x86_64.rpm``
rpm -ivh http://download.tomahawk-player.org/packman/mingw:32/openSUSE_12.1/x86_64/mingw32-cross-nsis-plugin-processes-0-1.1.x86_64.rpm
rpm -ivh http://download.tomahawk-player.org/packman/mingw:32/openSUSE_12.1/x86_64/mingw32-cross-nsis-plugin-uac-0-3.1.x86_64.rpm
6. Follow the `generic build instructions`_
.. note:: When building for Windows platforms, you must specify a special
toolchain file that enables cmake to locate the platform-specific tools. To add
this parameter to the call to cmake, enter
``DCMAKE_TOOLCHAIN_FILE=../mirall/admin/win/Toolchain-mingw32-openSUSE.cmake``.
``-DCMAKE_TOOLCHAIN_FILE=../mirall/admin/win/Toolchain-mingw32-openSUSE.cmake``.
7. Build by running ``make``.
..note:: Using ``make package`` produces an NSIS-based installer, provided
.. note:: Using ``make package`` produces an NSIS-based installer, provided
the NSIS mingw32 packages are installed.
.. _`generic build instructions`:
Generic Build Instructions
--------------------------
.. _`generic build instructions`
Compared to previous versions, building Mirall has become easier. Unlike
earlier versions, CSync, which is the sync engine library of Mirall, is now
@@ -140,33 +159,32 @@ To build the most up to date version of the client:
``cd ../mirall-build``
``cmake -DCMAKE_BUILD_TYPE="Debug" ../mirall``
..note:: You must use absolute pathes for the ``include`` and ``library`` directories.
..note:: You must use absolute paths for the ``include`` and ``library``
directories.
..note:: On Mac OS X, you need to specify ``-DCMAKE_INSTALL_PREFIX=target``,
where ``target`` is a private location, i.e. in parallel to your build
dir by specifying ``../install``.
4. Call ``make``.
The owncloud binary appear in the ``bin`` directory.
5. (Optional) Call ``make install`` to install the client to the ``/usr/local/bin`` directory.
6. (Optional) Call ``make package`` to build an installer/app bundle
..note:: This step requires the ``mingw32-cross-nsis`` packages be installed on Windows.
The following are known cmake parameters:
* ``QTKEYCHAIN_LIBRARY=/path/to/qtkeychain.dylib -DQTKEYCHAIN_INCLUDE_DIR=/path/to/qtkeychain/``:
Used for stored credentials. When compiling with Qt5, the library is called ``qt5keychain.dylib.``
You need to compile QtKeychain with the same Qt version.
* ``WITH_DOC=TRUE``: Creates doc and manpages through running ``make``; also
* adds install statements, providing the ability to install using ``make
* install``.
* ``WITH_DOC=TRUE``: Creates doc and manpages through running ``make``; also adds install statements,
providing the ability to install using ``make install``.
* ``CMAKE_PREFIX_PATH=/path/to/Qt5.2.0/5.2.0/yourarch/lib/cmake/``: Builds using Qt5.
* ``BUILD_WITH_QT4=ON``: Builds using Qt4 (even if Qt5 is found).
* ``CMAKE_INSTALL_PREFIX=path``: Set an install prefix. This is mandatory on Mac OS
.. _`ownCloud repository from OBS`: http://software.opensuse.org/download/package?project=isv:ownCloud:devel&package=owncloud-client
.. _`ownCloud repository from OBS`: http://software.opensuse.org/download/package?project=isv:ownCloud:desktop&package=owncloud-client
.. _CSync: http://www.csync.org
.. _`Client Download Page`: http://owncloud.org/sync-clients/
.. _Git: http://git-scm.com
.. _MacPorts: http://www.macports.org
.. _Homebrew: http://mxcl.github.com/homebrew/
.. _QtKeychain https://github.com/frankosterfeld/qtkeychain
.. _QtKeychain: https://github.com/frankosterfeld/qtkeychain

BIN
doc/images/icon-error.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
doc/images/icon-offline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
doc/images/icon-paused.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
doc/images/icon-syncing.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -5,16 +5,44 @@ Using the Synchronization Client
The ownCloud Client remains in the background and is visible as an icon in the
system tray (Windows, KDE), status bar (MAC OS X), or notification area
(Ubuntu).
(Linux).
.. image:: images/icon.png
**ownCloud Desktop Client icon**
This is a status indicator which uses overlay icons to indicate the
current status of your synchronization. The green circle with the white checkmark
tells you that your synchronization is current and you are connected to your
ownCloud server.
.. image:: images/icon-syncing.png
The blue icon with the white semi-circles means synchronization is in progress.
.. image:: images/icon-paused.png
The yellow overlay icon with the parallel lines tells you your synchronization
has been paused. (Most likely by you, by opening the client and clicking
Account > Pause.)
.. image:: images/icon-offline.png
The gray icon with three white dots means your sync client has lost its
connection with your ownCloud server.
.. image:: images/icon-information.png
When you see a white circle with the letter "i" that is the informational icon,
so you should click it to see what it has to tell you.
.. image:: images/icon-error.png
The red circle with the white "x" indicates a configuration error, such as an
incorrect login or server URL.
Using the Desktop Client Menu
-----------------------------
A right click on the icon (left click on Ubuntu and Mac OS X) provides the
A left-click on the icon (right-click on Windows) opens the
following menu:
.. image:: images/menu.png
@@ -24,13 +52,19 @@ following menu:
The Desktop Client menu provides the following options:
* ``Open ownCloud in browser``: Launches the ownCloud WEB interface.
* ``Open folder 'ownCloud'``: Opens the ownCloud local folder. If you have defined multiple synchronization targets, the window displays each local folder.
* **Disk space indicator**: Indicates the amount of space currently used on the server.
* Operation indicator: Displays the status of the current synchronization process or indicates ``Up to date`` if the server and client are in sync.
* **Recent Changes**: Displays the last six files modified by the synchronization operations and provides access to the current synchronization status listing all changes since the last restart of the ownCloud client.
* ``Settings...``: Provides access to the settings menu.
* ``Open folder 'ownCloud'``: Opens the ownCloud local folder. If you have
defined multiple synchronization targets, the window displays each local
folder.
* **Disk space indicator**: Indicates the amount of space currently used on the
server.
* Operation indicator: Displays the status of the current synchronization
process or indicates ``Up to date`` if the server and client are in sync.
* **Recent Changes**: Displays the last six files modified, and shows the
current synchronization status listing all changes since the last restart of the
ownCloud client.
* ``Settings...``: The settings menu.
* ``Help``: Opens a browser to display ownCloud Desktop Client Guide.
* ``Sign out``: Disables the client from continued synchronizations.
* ``Sign out``: Stops synchronization.
* ``Quit ownCloud``: Quits the ownCloud Client, ending any currently running
synchronizations.
@@ -39,7 +73,9 @@ Using the Account Settings Window
.. index:: account settings, user, password, Server URL
The ``Account`` window provides a summary for general settings associated with the ownCloud account. This window enalbes you to manage any synchronized folders in the account and enables you to modify them.
The ``Account`` window provides a summary for general settings associated with
the ownCloud account. This window enables you to manage any synchronized
folders in the account, and to modify which folders you want to sync.
To access and modify the account settings:
@@ -48,25 +84,34 @@ To access and modify the account settings:
The fields and options in this window include:
* ``Connected to <ownCloud instance> as <user>`` field: Indicates the ownCloud server to which the client is synchronizing and the user account on that server.
* ``Connected to <ownCloud instance> as <user>`` field: Your user account on an ownCloud
server.
* ``Add Folder...`` button: Provides the ability to add another folder to the synchronization process (see ``Adding a Folder``).
* ``Add Folder...`` button: Add another folder to the
synchronization process (see ``Adding a Folder``).
* ``Pause/Resume`` button: Pauses the current sync (or prevents the client from starting a new sync) or resumes the sync process.
* ``Pause/Resume`` button: Pauses the current sync (or prevents the client from
starting a new sync), or resumes the sync process.
* ``Remove`` button: Removes the selected folder from the sync process. This button is used when you want to synchronize only a few folders and not the root folder. If only the root folder is available, you must first remove the root from the synchronization and then add individual folders that you want to synchronize as desired.
* ``Remove`` button: Removes the selected folder from the sync process. This
button is used when you want to synchronize only a few folders and not the
root folder.
* ``Storage Usage`` field: Indicates the storage utilization on the ownCloud server.
* ``Storage Usage`` field: Indicates the storage utilization on the ownCloud
server.
* ``Edit Ignored Files`` button: Launches the Ignored Files Editor.
* ``Modify Account`` button: Enables you to change the ownCloud server to which you are synchronizing. This option launches the ``Setting up an Account`` windows (See ??).
* ``Modify Account`` button: Use this to change the ownCloud server to which
you are synchronizing. This option launches the ``Setting up an Account``
dialog (see :doc:`accountsetup`).
Adding a Folder
^^^^^^^^^^^^^^^
The ``Add a Folder ...`` button enables you to add a new folder to the syncrhonization process.
The ``Add a Folder ...`` button enables you to add a new folder to the
syncrhonization process.
To add a new folder:
@@ -74,66 +119,62 @@ To add a new folder:
The ``Add Folder...`` window opens
.. image:: images/folderwizard_local.png
:scale: 50 %
.. image:: images/folderwizard_local.png
**``Add Folder...`` window (local folder)**
2. Specify a *unique* path and alias name to the folder or use the ``Choose...``
button to locate the new folder on your system to which you want to
synchronize.
2. Specify a *unique* path and alias name to the folder or use the ``Choose...`` button to locate the new folder on your system to which you want to synchronize.
..note:: Nested synchronizations are not supported. In other words, you
.. note:: Nested synchronizations are not supported. In other words, you
cannot add a folder that is already contained within another synchronized
folder. In addition, you cannot add a higher level (parent) folder that
contains a folder to which you are already synchronizing. By default, the
ownCloud Set Up Wizard syncrhonizes your entire ownCloud account to the root
folder of the ownCloud server. Due to this default setup, you must first remove
the top-level folder prior to specifying new synchronizations.
ownCloud Set Up Wizard synchronizes your entire ownCloud account to the root
folder of the ownCloud server. If you wish to sync certain specific folders and not
the entire root, you must first remove the root folder.
3. Click 'Next' to continue.
A window opens prompting you to select a remote destination folder on the
ownCloud server to which you want to synchronize.
.. image:: images/folderwizard_remote.png
:scale: 50 %
.. image:: images/folderwizard_remote.png
**``Add Folder...`` window (remote destination)**
4. Select a folder on the ownCloud server to which you want to synchronize your
newly added folder.
4. Select a folder on the ownCloud server to which you want to synchronize your newly added folder.
..note:: A server folder can only be synchronized with a particular client once.
If you attempt to sync the root directory, you cannot sync with other folders
on the server. Similarly, if you sync with folder ``/a``, you cannot create
another sync with ``/a/b``, since ``b`` is already being synched.
.. note:: A server folder can only be synchronized with a particular client
once. If you attempt to sync the root directory, you cannot sync with
other folders on the server. Similarly, if you sync with folder ``/a``, you
cannot create another sync with ``/a/b``, since ``b`` is already being
synched.
Editing Ignored Files
^^^^^^^^^^^^^^^^^^^^^
The :guilabel:`Ignored Files Editor` provides a list of preconfigured files
that are ignored (that is, not synchronized) by the client and server during
synchronizations. The Ignored Files Editor enables you to add patterns for
files or directories that you want to exclude from the synchronization process.
In addition to using standard characters, the Ignored Files Editor enables you
to use wild cards (for example, using an asterisk * to indicate multiple
characters or a question mark ? to incidate a single character).
The :guilabel:`Ignored Files Editor` provides a list of preconfigured files that are
ignored (that is, not synchronized) by the client and server during synchronizations. You
may add additional files or directories that you want to exclude from the synchronization
process. In addition to using standard characters, the Ignored Files Editor enables you
to
use wild cards (for example, using an asterisk * to indicate multiple characters or a
question mark ? to incidate a single character).
For additional information about this editor, see `Using the Ignored Files Editor`_
For additional information see `Using the Ignored Files
Editor`_
Using the Activity Settings Window
----------------------------------
.. index:: activity, recent changes, sync activity
The Activity window provides an in-depth account of recent synchronization
activity. It shows files that have not been synchronized because they are on
the ignored files list or because they cannot be synced in a cross-platform
manner due to containing special characters that cannot be stored on certain
file systems.
The Activity window provides an in-depth account of recent synchronization activity. It
shows files that have not been synchronized because they are on the ignored files list,
or
because they cannot be synced due to containing special characters that cannot be stored
on certain file systems.
.. image:: images/settings_activity.png
:scale: 50 %
**Activity settings window**
You can open the Activity window in one of the following ways:
@@ -148,88 +189,71 @@ Using the General Settings Window
.. index:: general settings, auto start, startup, desktop notifications
The General settings window enables you to set general settings for the
ownCloud Desktop Client and provides information about the software version,
its creator, and the existance of any updates.
ownCloud Desktop Client, provides information about the software version,
its creator, and the existence of any updates.
.. image:: images/settings_general.png
:scale: 50 %
**General settings window**
The settings and information contained in this window are as follows:
* ``Launch on System Startup`` checkbox: Provides the option to check (enable)
or uncheck (disable) whether the ownCloud Desktop Client launches upon system
startup. By default, this option is enabled (checked)once you have configured
or uncheck (disable) whether the ownCloud Desktop Client launches at system
startup. By default, this option is enabled (checked) after you have configured
your account.
* ``Show Desktop Nofications`` checkbox: Provides the option to check (enable)
or uncheck (disable) bubble notifications alerting you as to when a set of
synchronization operations is performed.
or uncheck (disable) notifications about sync activity.
* ``Use Monochrome Icons`` checkbox: Provides the option to check (enable) or
uncheck (disable) the use of monochrome (visually less obtrusive) icons.
.. note:: This option can be useful on MAC OSX platforms.
.. note:: This option can be useful on MAC OSX platforms.
* ``About`` field: Provides information about the software authors along with
pertinent build conditions.
.. note:: Information in this field can be valuable when submitting a support request.
.. note:: Information in this field can be valuable when submitting a support
request.
* ``Updates`` field: Provides information about any available updates for the
ownCloud Desktop Client.
* ``Updates`` field: Notifies you of any available updates for the ownCloud Desktop
Client.
Using the Network Settings Window
---------------------------------
.. index:: proxy settings, SOCKS, bandwith, throttling, limiting
The Network settings window enables you to define network proxy settings as
well as limit the download and upload bandwidth utilization of file
synchronizations.
The Network settings window enables you to define network proxy settings, and also to
limit download and upload bandwidth.
.. image:: images/settings_network.png
:scale: 50 %
**Network settings window**
Specifying Proxy Settings
^^^^^^^^^^^^^^^^^^^^^^^^^
A proxy server is a server (for example, a computer system or an application)
that functions as an intermediary contact for requests from clients that are
seeking resources from other servers. For the ownCloud Desktop Client, you can
define the following proxy settings:
* ``No Proxy`` option: Specifies that the ownCloud Client circumvent the default proxy configured on the system.
* ``No Proxy`` option: Do not use a proxy.
* ``Use system proxy`` option: Default setting. Follows the systems proxy
settings. On Linux systems, this setting uses the value of the variable
``http_proxy``.
settings.
* ``Specify proxy manually as`` option: Enables you to specify
the following custom proxy settings:
- ``HTTP(S)``: Used when you are required to use an HTTP(S) proxy server (for example, Squid or Microsoft Forefront TMG).
- ``SOCKSv5``: Typically used in special company LAN setups, or in combination with the OpenSSH
- ``HTTP(S)``: Used when you are required to use an HTTP(S) proxy server (for
example, Squid or Microsoft Forefront TMG).
- ``SOCKSv5``: Typically used in special company LAN setups, or in combination
with the OpenSSH
dynamic application level forwarding feature (see ``ssh -D``).
- ``Host``: Host name or IP address of the proxy server along with the port number. HTTP proxies
typically listen over Ports 8080 (default) or 3128. SOCKS servers typically listen over port 1080.
* ``Proxy Server requires authentication`` checkbox: Provides the option to check (enable/require) or
uncheck (disable/not require) proxy server authentication. When not checked, the proxy server must
be configured to allow anonymous usage. When checked, a proxy server username and password is required.
- ``Host``: Host name or IP address of the proxy server along with the port
number. HTTP proxies typically listen over Ports 8080 (default) or 3128.
SOCKS servers typically listen over port 1080.
* ``Proxy Server requires authentication`` checkbox: Provides the option to
check (enable/require) or
uncheck (disable/not require) proxy server authentication. When not checked,
the proxy server must
be configured to allow anonymous usage. When checked, a proxy server username
and password is required.
Bandwidth Limiting
^^^^^^^^^^^^^^^^^^
Synchronization of files between a client and server can utilized a lot of
bandwidth. Bandwidth limiting can assist in shaping the total download or
upload bandwidth (or both) of your client/server connection to a more
manageable level. By limiting your bandwidth usage, you can maintain free
bandwidth for other applications to use.
The ownCloud Desktop Client enables you to limit (throttle) the bandwidth usage
for both file downloads and file uploads. The Download Bandwidth field (for
data flowing from the ownCloud server to the client) provides the following
options:
Synchronization of files between a client and server can use a lot of
bandwidth, so you can limit how much your ownCloud sync client uses.
- ``No limit`` option: The default setting for the client; specifies that there
are no limit settings on the amount of data downloaded from the server.
@@ -261,18 +285,12 @@ Using the Ignored Files Editor
You might have some files or directories that you do not want to backup and
store on the server. To identify and exclude these files or directories, you
can use the *Ignored Files Editor* that is embedded in the ownCloud Desktop
Client.
can use the *Ignored Files Editor*.
.. image:: images/ignored_files_editor.png
:scale: 50%
Ignored Files Editor window
The :guilabel:`Ignored Files Editor` enables you to define customized patterns that the
ownCloud Client uses to identify files and directories that you want to exclude
from the synchronization process. For your convenience, the editor is
pre-populated with a default list of typically ignore patterns. These patterns
For your convenience, the editor is
pre-populated with a default list of typical ignore patterns. These patterns
are contained in a system file (typically ``sync-exclude.lst``) located in the
ownCloud Client application directory. You cannot modify these pre-populated
patterns directly from the editor. However, if necessary, you can hover over
@@ -285,14 +303,15 @@ pattern, locate the file, and edit the ``sync-exclude.lst`` file.
Each line in the editor contains an ignore pattern string. When creating custom
patterns, in addition to being able to use normal characters to define an
ignore pattern, you can use wildcards characters for matching values. As an
example, you can use an asterisk (``*``) to idenfify an arbitrary number of
example, you can use an asterisk (``*``) to identify an arbitrary number of
characters or a question mark (``?``) to identify a single character.
Patterns that end with a slash character (``/``) are applied to only directory
components of the path being checked.
.. note:: Custom entries are currently not validated for syntactical
correctness by the editor, but might fail to load correctly.
correctness by the editor, so you will not see any warnings for bad
syntax. If your synchronization does not work as you expected, check your syntax.
Each pattern string in the list is preceded by a checkbox. When the check box
contains a check mark, in addition to ignoring the file or directory component
@@ -305,9 +324,8 @@ this list:
- The ownCloud Client always excludes files containing characters that cannot
be synchronized to other file systems.
- As of ownCloud Desktop Client version 1.5.0, files are removed that cause
individual errors three times during a synchronization. However, the client
provides the option of retrying a synchronization three additional times on
files that produce errors.
- Files are removed that cause individual errors three times during a synchronization.
However, the client provides the option of retrying a synchronization three additional
times on files that produce errors.
For more detailed information see :ref:`ignored-files-label`.

View File

@@ -63,14 +63,14 @@ static ContentManager* sharedInstance = nil;
{
NSString *base = path;
_icnOk = [[IconCache sharedInstance] registerIcon:[base stringByAppendingString:@"ok.icns"]];
_icnSync = [[IconCache sharedInstance] registerIcon:[base stringByAppendingString:@"sync.icns"]];
_icnWarn = [[IconCache sharedInstance] registerIcon:[base stringByAppendingString:@"warning.icns"]];
_icnErr = [[IconCache sharedInstance] registerIcon:[base stringByAppendingString:@"error.icns"]];
_icnOkSwm = [[IconCache sharedInstance] registerIcon:[base stringByAppendingString:@"ok_swm.icns"]];
_icnSyncSwm = [[IconCache sharedInstance] registerIcon:[base stringByAppendingString:@"sync_swm.icns"]];
_icnWarnSwm = [[IconCache sharedInstance] registerIcon:[base stringByAppendingString:@"warning_swm.icns"]];
_icnErrSwm = [[IconCache sharedInstance] registerIcon:[base stringByAppendingString:@"error_swm.icns"]];
_icnOk = [[IconCache sharedInstance] registerIcon:[base stringByAppendingPathComponent:@"ok.icns"]];
_icnSync = [[IconCache sharedInstance] registerIcon:[base stringByAppendingPathComponent:@"sync.icns"]];
_icnWarn = [[IconCache sharedInstance] registerIcon:[base stringByAppendingPathComponent:@"warning.icns"]];
_icnErr = [[IconCache sharedInstance] registerIcon:[base stringByAppendingPathComponent:@"error.icns"]];
_icnOkSwm = [[IconCache sharedInstance] registerIcon:[base stringByAppendingPathComponent:@"ok_swm.icns"]];
_icnSyncSwm = [[IconCache sharedInstance] registerIcon:[base stringByAppendingPathComponent:@"sync_swm.icns"]];
_icnWarnSwm = [[IconCache sharedInstance] registerIcon:[base stringByAppendingPathComponent:@"warning_swm.icns"]];
_icnErrSwm = [[IconCache sharedInstance] registerIcon:[base stringByAppendingPathComponent:@"error_swm.icns"]];
NSLog(@"Icon ok identifier: %d from %@", [_icnOk intValue], [base stringByAppendingString:@"ok.icns"]);
}

View File

@@ -18,6 +18,19 @@ import socket
from gi.repository import GObject, Nautilus
def get_runtime_dir():
"""Returns the value of $XDG_RUNTIME_DIR, a directory path.
If the value is not set, returns the same default as in Qt5
"""
try:
return os.environ['XDG_RUNTIME_DIR']
except KeyError:
fallback = '/tmp/runtime-' + os.environ['USER']
return fallback
class syncStateExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.InfoProvider):
nautilusVFSFile_table = {}
@@ -38,21 +51,21 @@ class syncStateExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.Info
try:
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
postfix = "/"+self.appname+"/socket"
sock_file = os.environ["XDG_RUNTIME_DIR"]+postfix
sock_file = get_runtime_dir()+postfix
print ("XXXX " + sock_file + " <=> " + postfix)
if sock_file != postfix:
try:
print("Socket File: "+sock_file)
self.sock.connect(sock_file)
self.connected = True
print("Setting connected to %r" % self.connected )
self.watch_id = GObject.io_add_watch(self.sock, GObject.IO_IN, self.handle_notify)
do_reconnect = False
except Exception, e:
print("Could not connect to unix socket." + str(e))
else:
print("Sock-File not valid: "+sock_file)
except Exception, e:
try:
print("Socket File: "+sock_file)
self.sock.connect(sock_file)
self.connected = True
print("Setting connected to %r" % self.connected )
self.watch_id = GObject.io_add_watch(self.sock, GObject.IO_IN, self.handle_notify)
do_reconnect = False
except Exception as e:
print("Could not connect to unix socket." + str(e))
else:
print("Sock-File not valid: "+sock_file)
except Exception as e:
print("Connect could not be established, try again later " + str(e))
self.sock.close()
# print("Returning %r" % do_reconnect)
@@ -75,7 +88,7 @@ class syncStateExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.Info
return None
def askForOverlay(self, file):
# print("Asking for overlay for "+file)
# print("Asking for overlay for "+file)
if os.path.isdir(file):
folderStatus = self.sendCommand("RETRIEVE_FOLDER_STATUS:"+file+"\n");
@@ -85,15 +98,15 @@ class syncStateExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.Info
def invalidate_items_underneath(self, path):
update_items = []
if not self.nautilusVFSFile_table:
self.askForOverlay(path)
else:
for p in self.nautilusVFSFile_table:
if p == path or p.startswith(path):
item = self.nautilusVFSFile_table[p]['item']
update_items.append(item)
self.askForOverlay(path)
else:
for p in self.nautilusVFSFile_table:
if p == path or p.startswith(path):
item = self.nautilusVFSFile_table[p]['item']
update_items.append(item)
for item in update_items:
item.invalidate_extension_info()
for item in update_items:
item.invalidate_extension_info()
# Handles a single line of server respoonse and sets the emblem
def handle_server_response(self, l):
@@ -118,16 +131,16 @@ class syncStateExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.Info
# file = parts[1]
# print "Action for " + file + ": "+parts[0]
if action == 'STATUS':
newState = parts[1]
newState = parts[1]
emblem = Emblems[newState]
if emblem:
itemStore = self.find_item_for_file(parts[2])
if itemStore:
if( not itemStore['state'] or newState != itemStore['state'] ):
item = itemStore['item']
item.add_emblem(emblem)
# print "Setting emblem on " + parts[2]+ "<>"+emblem+"<>"
self.nautilusVFSFile_table[parts[2]] = {'item': item, 'state':newState}
if( not itemStore['state'] or newState != itemStore['state'] ):
item = itemStore['item']
item.add_emblem(emblem)
# print "Setting emblem on " + parts[2]+ "<>"+emblem+"<>"
self.nautilusVFSFile_table[parts[2]] = {'item': item, 'state':newState}
elif action == 'UPDATE_VIEW':
# Search all items underneath this path and invalidate them
@@ -195,4 +208,5 @@ class syncStateExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.Info
self.askForOverlay(filename)
break
else:
print("Not in scope:"+filename)
# print("Not in scope:"+filename)
pass

View File

@@ -1,3 +1,16 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <QApplication>
#include <QLocalSocket>
#include <QDir>

View File

@@ -1,3 +1,15 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "socketclient.h"

View File

@@ -1,3 +1,16 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef SOCKETCLIENT_H
#define SOCKETCLIENT_H

View File

@@ -1,3 +1,16 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "window.h"
#include "ui_window.h"

View File

@@ -1,3 +1,16 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef WINDOW_H
#define WINDOW_H

View File

@@ -16,6 +16,8 @@
#include "RemotePathChecker.h"
#include "StringUtil.h"
#include <shlobj.h>
#include <algorithm>
#include <iostream>
#include <sstream>
@@ -77,7 +79,7 @@ void RemotePathChecker::workerThreadLoop()
{ std::unique_lock<std::mutex> lock(_mutex);
_watchedDirectories.push_back(responsePath);
}
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH, responsePath.data(), NULL);
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
} else if (StringUtil::begins_with(response, wstring(L"UNREGISTER_PATH:"))) {
wstring responsePath = response.substr(16); // length of UNREGISTER_PATH:
@@ -95,7 +97,7 @@ void RemotePathChecker::workerThreadLoop()
}
}
}
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH, responsePath.data(), NULL);
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
} else if (StringUtil::begins_with(response, wstring(L"STATUS:")) ||
StringUtil::begins_with(response, wstring(L"BROADCAST:"))) {
@@ -116,14 +118,25 @@ void RemotePathChecker::workerThreadLoop()
bool changed = false;
{ std::unique_lock<std::mutex> lock(_mutex);
auto &it = _cache[responsePath];
changed = it == state;
changed = (it != state);
it = state;
}
if (changed) {
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
}
}
}
}
else if (StringUtil::begins_with(response, wstring(L"UPDATE_VIEW"))) {
std::unique_lock<std::mutex> lock(_mutex);
auto cache = _cache; // Make a copy of the cache under the mutex
lock.unlock();
// Request a status for all the items in the cache.
for (auto it = cache.begin(); it != cache.end(); ++it) {
if (!socket.SendMsg(wstring(L"RETRIEVE_FILE_STATUS:" + it->first + L'\n').data())) {
break;
}
}
}
}
if (socket.Event() == INVALID_HANDLE_VALUE) {
std::unique_lock<std::mutex> lock(_mutex);
@@ -181,6 +194,7 @@ bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state)
}
_pending.push(filePath);
lock.unlock();
SetEvent(_newQueries);
return false;

View File

@@ -28,7 +28,7 @@ QString AbstractCredentials::keychainKey(const QString &url, const QString &user
return QString::null;
}
if( user.isEmpty() ) {
qDebug() << "Error: User is emty!";
qDebug() << "Error: User is empty!";
return QString::null;
}

View File

@@ -241,7 +241,19 @@ void ShibbolethCredentials::persist(Account* account)
void ShibbolethCredentials::invalidateToken(Account *account)
{
CookieJar *jar = static_cast<CookieJar*>(account->networkAccessManager()->cookieJar());
jar->deleteCookie(_shibCookie);
// Remove the _shibCookie
auto cookies = jar->allCookies();
for (auto it = cookies.begin(); it != cookies.end(); ) {
if (it->name() == _shibCookie.name()) {
it = cookies.erase(it);
} else {
++it;
}
}
jar->setAllCookies(cookies);
// Clear all other temporary cookies
jar->clearSessionCookies();
removeShibCookie(account);
_shibCookie = QNetworkCookie();

View File

@@ -40,7 +40,7 @@ Q_OBJECT
public:
ShibbolethCredentials();
/* create a credidentials for an already connected account */
/* create a credentials for an already connected account */
ShibbolethCredentials(const QNetworkCookie &cookie, Account *acc);
void syncContextPreInit(CSYNC* ctx) Q_DECL_OVERRIDE;

View File

@@ -71,7 +71,7 @@ public:
enum State { Disconnected = 0, /// no network connection
Connected, /// account is online
SignedOut, /// Disconnected + credential token has been discarded
InvalidCredidential /// The credidential are invalids and we are asking for them to the user
InvalidCredential /// The credentials are invalid and we are asking the user for them
};
QString davPath() const { return _davPath; }

View File

@@ -202,10 +202,9 @@ void AccountSettings::slotFolderWizardAccepted()
QStringList selectiveSyncBlackList
= folderWizard->property("selectiveSyncBlackList").toStringList();
if (!FolderMan::ensureJournalGone( sourceFolder ))
if (!folderMan->addFolderDefinition(alias, sourceFolder, targetPath, selectiveSyncBlackList))
return;
folderMan->addFolderDefinition(alias, sourceFolder, targetPath, selectiveSyncBlackList );
Folder *f = folderMan->setupFolderFromConfigFile( alias );
slotAddFolder( f );
folderMan->setSyncEnabled(true);
@@ -662,25 +661,29 @@ void AccountSettings::slotSetProgress(const QString& folder, const Progress::Inf
// overall progress
quint64 completedSize = progress.completedSize();
quint64 currentFile = progress._completedFileCount + progress._currentItems.count();
if (currentFile == ULLONG_MAX)
currentFile = 0;
quint64 totalSize = qMax(completedSize, progress._totalSize);
quint64 totalFileCount = qMax(currentFile, progress._totalFileCount);
QString overallSyncString;
if (progress._totalSize > 0) {
if (totalSize > 0) {
QString s1 = Utility::octetsToString( completedSize );
QString s2 = Utility::octetsToString( progress._totalSize );
QString s2 = Utility::octetsToString( totalSize );
overallSyncString = tr("%1 of %2, file %3 of %4\nTotal time left %5")
.arg(s1, s2)
.arg(currentFile).arg(progress._totalFileCount)
.arg(currentFile).arg(totalFileCount)
.arg( Utility::timeToDescriptiveString(progress.totalEstimate().getEtaEstimate(), 3, " ", true) );
} else if (progress._totalFileCount > 0) {
} else if (totalFileCount > 0) {
// Don't attemt to estimate the time left if there is no kb to transfer.
overallSyncString = tr("file %1 of %2") .arg(currentFile).arg(progress._totalFileCount);
overallSyncString = tr("file %1 of %2") .arg(currentFile).arg(totalFileCount);
}
item->setData( overallSyncString, FolderStatusDelegate::SyncProgressOverallString );
int overallPercent = 0;
if( progress._totalFileCount > 0 ) {
if( totalFileCount > 0 ) {
// Add one 'byte' for each files so the percentage is moving when deleting or renaming files
overallPercent = qRound(double(completedSize + progress._completedFileCount)/double(progress._totalSize + progress._totalFileCount) * 100.0);
overallPercent = qRound(double(completedSize + progress._completedFileCount)/double(totalSize + totalFileCount) * 100.0);
}
item->setData( overallPercent, FolderStatusDelegate::SyncProgressOverallPercent);
}

View File

@@ -225,7 +225,7 @@ void Application::slotCheckConnection()
Account *account = AccountManager::instance()->account();
if( account ) {
if (account->state() == Account::InvalidCredidential
if (account->state() == Account::InvalidCredential
|| account->state() == Account::SignedOut) {
//Do not try to connect if we are logged out
if (!_userTriggeredConnect) {
@@ -252,14 +252,18 @@ void Application::slotCredentialsFetched()
{
Account *account = AccountManager::instance()->account();
Q_ASSERT(account);
if (!account) {
qDebug() << Q_FUNC_INFO << "No account!";
return;
}
disconnect(account->credentials(), SIGNAL(fetched()), this, SLOT(slotCredentialsFetched()));
if (!account->credentials()->ready()) {
// User canceled the connection or did not give a password
account->setState(Account::SignedOut);
return;
}
if (account->state() == Account::InvalidCredidential) {
// Then we ask again for the credidentials if they are wrong again
if (account->state() == Account::InvalidCredential) {
// Then we ask again for the credentials if they are wrong again
account->setState(Account::Disconnected);
}
slotCheckConnection();
@@ -277,12 +281,11 @@ void Application::slotToggleFolderman(int state)
_checkConnectionTimer.start();
// fall through
case Account::SignedOut:
case Account::InvalidCredidential:
case Account::InvalidCredential:
folderMan->setSyncEnabled(false);
folderMan->terminateSyncProcess();
break;
}
}
void Application::slotConnectionValidatorResult(ConnectionValidator::Status status)

View File

@@ -101,6 +101,10 @@ void ClientProxy::setCSyncProxy( const QUrl& url, CSYNC *csync_ctx )
QList<QNetworkProxy> proxies = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(url));
// We set at least one in Application
Q_ASSERT(proxies.count() > 0);
if (proxies.count() == 0) {
qDebug() << Q_FUNC_INFO << "No proxy!";
return;
}
QNetworkProxy proxy = proxies.first();
if (proxy.type() == QNetworkProxy::NoProxy) {
qDebug() << "Passing NO proxy to csync for" << url.toString();

View File

@@ -91,27 +91,11 @@ QList<QNetworkCookie> CookieJar::cookiesForUrl(const QUrl &url) const
return cookies;
}
bool CookieJar::deleteCookie(const QNetworkCookie &delCookie)
{
QList<QNetworkCookie> cookies = allCookies();
bool removeSucceeded = false;
foreach(const QNetworkCookie &cookie, cookies) {
// ### cookies are not identical in attriutes, why?
if (cookie.name() == delCookie.name()) {
cookies.removeOne(cookie);
removeSucceeded = true;
}
}
setAllCookies(cookies);
return removeSucceeded;
}
void CookieJar::clearSessionCookies()
{
setAllCookies(removeExpired(allCookies()));
}
void CookieJar::save()
{
QFile file;

View File

@@ -29,13 +29,11 @@ public:
bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url) Q_DECL_OVERRIDE;
QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const Q_DECL_OVERRIDE;
bool deleteCookie(const QNetworkCookie & cookie)
#if QT_VERSION > QT_VERSION_CHECK(5, 0, 0)
Q_DECL_OVERRIDE //that function is not virtual in Qt4
#endif
;
void clearSessionCookies();
using QNetworkCookieJar::setAllCookies;
using QNetworkCookieJar::allCookies;
signals:
void newCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
private:

View File

@@ -96,12 +96,18 @@ time_t FileSystem::getModTime(const QString &filename)
return result;
}
void FileSystem::setModTime(const QString& filename, time_t modTime)
bool FileSystem::setModTime(const QString& filename, time_t modTime)
{
struct timeval times[2];
times[0].tv_sec = times[1].tv_sec = modTime;
times[0].tv_usec = times[1].tv_usec = 0;
c_utimes(filename.toUtf8().data(), times);
int rc = c_utimes(filename.toUtf8().data(), times);
if (rc != 0) {
qDebug() << "Error setting mtime for" << filename
<< "failed: rc" << rc << ", errno:" << errno;
return false;
}
return true;
}
bool FileSystem::renameReplace(const QString& originFileName, const QString& destinationFileName, QString* errorString)

View File

@@ -40,7 +40,7 @@ void OWNCLOUDSYNC_EXPORT setFileHidden(const QString& filename, bool hidden);
*/
time_t OWNCLOUDSYNC_EXPORT getModTime(const QString &filename);
void setModTime(const QString &filename, time_t modTime);
bool setModTime(const QString &filename, time_t modTime);
/**
* Rename the file \a originFileName to \a destinationFileName, and overwrite the destination if it

View File

@@ -69,19 +69,11 @@ Folder::Folder(const QString &alias, const QString &path, const QString& secondP
qsrand(QTime::currentTime().msec());
_timeSinceLastSync.start();
MirallConfigFile cfg;
_syncResult.setStatus( SyncResult::NotYetStarted );
// check if the local path exists
checkLocalPath();
int polltime = cfg.remotePollInterval();
qDebug() << "setting remote poll timer interval to" << polltime << "msec";
_pollTimer.setInterval( polltime );
QObject::connect(&_pollTimer, SIGNAL(timeout()), this, SLOT(slotPollTimerTimeout()));
_pollTimer.start();
_syncResult.setFolder(alias);
}
@@ -234,7 +226,6 @@ void Folder::setSyncPaused( bool paused )
// do not stop or start the watcher here, that is done internally by
// folder class. Even if the watcher fires, the folder does not
// schedule itself because it checks the var. _enabled before.
_pollTimer.stop();
setSyncState(SyncResult::Paused);
}
}
@@ -255,20 +246,24 @@ void Folder::prepareToSync()
_syncResult.clearErrors();
}
void Folder::slotPollTimerTimeout()
void Folder::slotRunEtagJob()
{
qDebug() << "* Polling" << alias() << "for changes. (time since last sync:" << (_timeSinceLastSync.elapsed() / 1000) << "s)";
qDebug() << "* Trying to check" << alias() << "for changes via ETag check. (time since last sync:" << (_timeSinceLastSync.elapsed() / 1000) << "s)";
Account *account = AccountManager::instance()->account();
if (!account) {
qDebug() << Q_FUNC_INFO << "No valid account object";
qDebug() << Q_FUNC_INFO << alias() << "No valid account object, not trying to sync";
return;
}
if (!_requestEtagJob.isNull()) {
qDebug() << Q_FUNC_INFO << alias() << "has ETag job queued, not trying to sync";
return;
}
if (_paused || account->state() != Account::Connected) {
qDebug() << "Not syncing. :" << _paused << account->state();
qDebug() << "Not syncing. :" << alias() << _paused << account->state();
return;
}
@@ -306,17 +301,18 @@ void Folder::slotPollTimerTimeout()
// Do the ordinary etag check for the root folder and only schedule a real
// sync if it's different.
RequestEtagJob* job = new RequestEtagJob(account, remotePath(), this);
_requestEtagJob = new RequestEtagJob(account, remotePath(), this);
// check if the etag is different
QObject::connect(job, SIGNAL(etagRetreived(QString)), this, SLOT(etagRetreived(QString)));
QObject::connect(job, SIGNAL(networkError(QNetworkReply*)), this, SLOT(slotNetworkUnavailable()));
job->start();
QObject::connect(_requestEtagJob, SIGNAL(etagRetreived(QString)), this, SLOT(etagRetreived(QString)));
QObject::connect(_requestEtagJob, SIGNAL(networkError(QNetworkReply*)), this, SLOT(slotNetworkUnavailable()));
FolderMan::instance()->slotScheduleETagJob(alias(), _requestEtagJob);
// The _requestEtagJob is auto deleting itself on finish. Our guard pointer _requestEtagJob will then be null.
}
}
void Folder::etagRetreived(const QString& etag)
{
qDebug() << "* Compare etag with previous etag: " << (_lastEtag != etag);
qDebug() << "* Compare etag with previous etag: last:" << _lastEtag << ", received:" << etag;
// re-enable sync if it was disabled because network was down
FolderMan::instance()->setSyncEnabled(true);
@@ -506,6 +502,26 @@ void Folder::createGuiLog( const QString& filename, SyncFileStatus status, int c
}
}
int Folder::slotDiscardDownloadProgress()
{
// Delete from journal and from filesystem.
QDir folderpath(_path);
QSet<QString> keep_nothing;
const QVector<SyncJournalDb::DownloadInfo> deleted_infos =
_journal.getAndDeleteStaleDownloadInfos(keep_nothing);
foreach (const SyncJournalDb::DownloadInfo & deleted_info, deleted_infos) {
const QString tmppath = folderpath.filePath(deleted_info._tmpfile);
qDebug() << "Deleting temporary file: " << tmppath;
QFile::remove(tmppath);
}
return deleted_infos.size();
}
int Folder::downloadInfoCount()
{
return _journal.downloadInfoCount();
}
int Folder::blackListEntryCount()
{
return _journal.blackListEntryCount();
@@ -564,6 +580,9 @@ bool Folder::estimateState(QString fn, csync_ftw_type_e t, SyncFileStatus* s)
return true;
}
}
if(!fn.endsWith(QLatin1Char('/'))) {
fn.append(QLatin1Char('/'));
}
if (Utility::doesSetContainPrefix(_stateTaintedFolders, fn)) {
qDebug() << Q_FUNC_INFO << "Folder is tainted, EVAL!" << fn;
s->set(SyncFileStatus::STATUS_EVAL);
@@ -600,6 +619,9 @@ void Folder::watcherSlot(QString fn)
}
// Make it a relative path depending on the folder
QString relativePath = fn.remove(0, path().length());
if( !relativePath.endsWith(QLatin1Char('/'))) {
relativePath.append(QLatin1Char('/'));
}
qDebug() << Q_FUNC_INFO << fi.canonicalFilePath() << fn << relativePath;
_stateTaintedFolders.insert(relativePath);
@@ -629,6 +651,9 @@ void Folder::wipe()
{
QString stateDbFile = path()+QLatin1String(".csync_journal.db");
// Delete files that have been partially downloaded.
slotDiscardDownloadProgress();
_journal.close(); // close the sync journal
QFile file(stateDbFile);
@@ -641,12 +666,11 @@ void Folder::wipe()
} else {
qDebug() << "WRN: statedb is empty, can not remove.";
}
// Check if the tmp database file also exists
QString ctmpName = path() + QLatin1String(".csync_journal.db.ctmp");
QFile ctmpFile( ctmpName );
if( ctmpFile.exists() ) {
ctmpFile.remove();
}
// Also remove other db related files
QFile::remove( stateDbFile + ".ctmp" );
QFile::remove( stateDbFile + "-shm" );
QFile::remove( stateDbFile + "-wal" );
}
bool Folder::setIgnoredFiles()
@@ -753,7 +777,6 @@ void Folder::startSync(const QStringList &pathList)
// disable events until syncing is done
// _watcher->setEventsEnabled(false);
_pollTimer.stop();
emit syncStarted();
}
@@ -884,9 +907,7 @@ void Folder::slotSyncFinished()
// We will make sure that the poll timer occurs soon enough.
// delay 1s, 4s, 9s
int c = _consecutiveFollowUpSyncs;
QTimer::singleShot(c*c * 1000, this, SLOT(slotPollTimerTimeout() ));
} else {
_pollTimer.start();
QTimer::singleShot(c*c * 1000, this, SLOT(slotRunEtagJob() ));
}
}
@@ -956,7 +977,7 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool *cancel)
// speed up next sync
_lastEtag.clear();
_forceSyncOnPollTimeout = true;
QTimer::singleShot(50, this, SLOT(slotPollTimerTimeout()));
QTimer::singleShot(50, this, SLOT(slotRunEtagJob()));
}
}
} // namespace Mirall

View File

@@ -22,6 +22,7 @@
#include "mirall/syncjournaldb.h"
#include "mirall/clientproxy.h"
#include "mirall/syncfilestatus.h"
#include "mirall/networkjobs.h"
#include <csync.h>
@@ -123,6 +124,9 @@ public:
bool estimateState(QString fn, csync_ftw_type_e t, SyncFileStatus* s);
RequestEtagJob *etagJob() { return _requestEtagJob; }
qint64 msecSinceLastSync() { return _timeSinceLastSync.elapsed(); }
signals:
void syncStateChange();
void syncStarted();
@@ -149,6 +153,8 @@ public slots:
void setProxyDirty(bool value);
bool proxyDirty();
int slotDiscardDownloadProgress();
int downloadInfoCount();
int slotWipeBlacklist();
int blackListEntryCount();
@@ -163,7 +169,7 @@ private slots:
void slotJobCompleted(const SyncFileItem&);
void slotSyncItemDiscovered(const SyncFileItem & item);
void slotPollTimerTimeout();
void slotRunEtagJob();
void etagRetreived(const QString &);
void slotNetworkUnavailable();
@@ -199,7 +205,7 @@ private:
bool _csyncUnavail;
bool _wipeDb;
bool _proxyDirty;
QTimer _pollTimer;
QPointer<RequestEtagJob> _requestEtagJob;
QString _lastEtag;
QElapsedTimer _timeSinceLastSync;
bool _forceSyncOnPollTimeout;

View File

@@ -34,6 +34,8 @@
#include <QMessageBox>
#include <QPointer>
#include <QtCore>
#include <QMutableSetIterator>
#include <QSet>
namespace Mirall {
@@ -66,6 +68,13 @@ FolderMan::FolderMan(QObject *parent) :
_socketApi = new SocketApi(this);
_socketApi->slotReadExcludes();
MirallConfigFile cfg;
int polltime = cfg.remotePollInterval();
qDebug() << "setting remote poll timer interval to" << polltime << "msec";
_etagPollTimer.setInterval( polltime );
QObject::connect(&_etagPollTimer, SIGNAL(timeout()), this, SLOT(slotEtagPollTimerTimeout()));
_etagPollTimer.start();
}
FolderMan *FolderMan::instance()
@@ -225,6 +234,7 @@ bool FolderMan::ensureJournalGone(const QString &localPath)
// remove old .csync_journal file
QString stateDbFile = localPath+QLatin1String("/.csync_journal.db");
while (QFile::exists(stateDbFile) && !QFile::remove(stateDbFile)) {
qDebug() << "Could not remove old db file at" << stateDbFile;
int ret = QMessageBox::warning(0, tr("Could not reset folder state"),
tr("An old sync journal '%1' was found, "
"but could not be removed. Please make sure "
@@ -390,21 +400,17 @@ void FolderMan::slotSetFolderPaused( const QString& alias, bool paused )
}
}
// this really terminates, ie. no questions, no prisoners.
// this really terminates the current sync process
// ie. no questions, no prisoners
// csync still remains in a stable state, regardless of that.
void FolderMan::terminateSyncProcess( const QString& alias )
void FolderMan::terminateSyncProcess()
{
QString folderAlias = alias;
if( alias.isEmpty() ) {
folderAlias = _currentSyncFolder;
}
if( ! folderAlias.isEmpty() && _folderMap.contains(folderAlias) ) {
Folder *f = _folderMap[folderAlias];
if( ! _currentSyncFolder.isEmpty() && _folderMap.contains(_currentSyncFolder) ) {
Folder *f = _folderMap[_currentSyncFolder];
if( f ) {
// This will, indirectly and eventually, call slotFolderSyncFinished
// and thereby clear _currentSyncFolder.
f->slotTerminateSync();
if(_currentSyncFolder == folderAlias ) {
_currentSyncFolder.clear();
}
}
}
}
@@ -489,6 +495,41 @@ void FolderMan::slotScheduleSync( const QString& alias )
QTimer::singleShot(msBetweenRequestAndSync, this, SLOT(slotStartScheduledFolderSync()));
}
void FolderMan::slotScheduleETagJob(const QString &/*alias*/, RequestEtagJob *job)
{
QObject::connect(job, SIGNAL(destroyed(QObject*)), this, SLOT(slotEtagJobDestroyed(QObject*)));
QMetaObject::invokeMethod(this, "slotRunOneEtagJob", Qt::QueuedConnection);
// maybe: add to queue
}
void FolderMan::slotEtagJobDestroyed(QObject* /*o*/)
{
// _currentEtagJob is automatically cleared
// maybe: remove from queue
QMetaObject::invokeMethod(this, "slotRunOneEtagJob", Qt::QueuedConnection);
}
void FolderMan::slotRunOneEtagJob()
{
if (_currentEtagJob.isNull()) {
QString alias;
foreach(Folder *f, _folderMap) {
if (f->etagJob()) {
// Caveat: always grabs the first folder with a job, but we think this is Ok for now and avoids us having a seperate queue.
_currentEtagJob = f->etagJob();
alias = f->alias();
break;
}
}
if (_currentEtagJob.isNull()) {
qDebug() << "No more remote ETag check jobs to schedule.";
} else {
qDebug() << "Scheduling" << alias << "to check remote ETag";
_currentEtagJob->start(); // on destroy/end it will continue the queue via slotEtagJobDestroyed
}
}
}
// only enable or disable foldermans will to schedule and do syncs.
// this is not the same as Pause and Resume of folders.
void FolderMan::setSyncEnabled( bool enabled )
@@ -545,6 +586,51 @@ void FolderMan::slotStartScheduledFolderSync()
}
}
void FolderMan::slotEtagPollTimerTimeout()
{
//qDebug() << Q_FUNC_INFO << "Checking if we need to make any folders check the remote ETag";
MirallConfigFile cfg;
int polltime = cfg.remotePollInterval();
QSet<QString> folderAliases = _folderMap.keys().toSet();
QMutableSetIterator<QString> i(folderAliases);
while (i.hasNext()) {
QString alias = i.next();
if (_currentSyncFolder == alias) {
i.remove();
continue;
}
if (_scheduleQueue.contains(alias)) {
i.remove();
continue;
}
Folder *f = _folderMap.value(alias);
if (f && _disabledFolders.contains(f)) {
i.remove();
continue;
}
if (f && (f->etagJob() || f->isBusy() || f->syncPaused())) {
i.remove();
continue;
}
if (f && f->msecSinceLastSync() < polltime) {
i.remove();
continue;
}
}
if (folderAliases.isEmpty()) {
qDebug() << Q_FUNC_INFO << "No folders need to check for the remote ETag";
} else {
qDebug() << Q_FUNC_INFO << "The following folders need to check for the remote ETag:" << folderAliases;
i = folderAliases; // reset
while (i.hasNext()) {
QString alias = i.next();
QMetaObject::invokeMethod(_folderMap.value(alias), "slotRunEtagJob", Qt::QueuedConnection);
}
}
}
void FolderMan::slotFolderSyncStarted( )
{
qDebug() << ">===================================== sync started for " << _currentSyncFolder;
@@ -565,9 +651,12 @@ void FolderMan::slotFolderSyncFinished( const SyncResult& )
QTimer::singleShot(200, this, SLOT(slotStartScheduledFolderSync()));
}
void FolderMan::addFolderDefinition(const QString& alias, const QString& sourceFolder,
const QString& targetPath, const QStringList &selectiveSyncBlackList )
bool FolderMan::addFolderDefinition(const QString& alias, const QString& sourceFolder,
const QString& targetPath, const QStringList& selectiveSyncBlackList)
{
if (! ensureJournalGone(sourceFolder))
return false;
QString escapedAlias = escapeAlias(alias);
// Create a settings file named after the alias
QSettings settings( _folderConfigPath + QLatin1Char('/') + escapedAlias, QSettings::IniFormat);
@@ -579,6 +668,8 @@ void FolderMan::addFolderDefinition(const QString& alias, const QString& sourceF
settings.setValue(QLatin1String("connection"), Theme::instance()->appName());
settings.setValue(QLatin1String("blackList"), selectiveSyncBlackList);
settings.sync();
return true;
}
Folder *FolderMan::folderForPath(const QString &path)
@@ -615,7 +706,7 @@ void FolderMan::slotRemoveFolder( const QString& alias )
if( _currentSyncFolder == alias ) {
// terminate if the sync is currently underway.
terminateSyncProcess( alias );
terminateSyncProcess();
}
removeFolder(alias);
}
@@ -706,6 +797,8 @@ bool FolderMan::startFromScratch( const QString& localFolder )
if( localFolder.startsWith(f->path()) ) {
_socketApi->slotUnregisterPath(f->alias());
}
f->journalDb()->close();
f->slotTerminateSync(); // Normaly it should not be running, but viel hilft viel
}
}

View File

@@ -49,9 +49,13 @@ public:
* QString alias
* QString sourceFolder on local machine
* QString targetPath on remote
*
* Ensures any existing journal in the sourceFolder is deleted.
* Returns true on success.
*/
void addFolderDefinition(const QString&, const QString&, const QString& ,
const QStringList &selectiveSyncBlacklist = QStringList() );
bool addFolderDefinition(const QString& alias, const QString& sourceFolder,
const QString& targetPath,
const QStringList& selectiveSyncBlacklist = QStringList());
/** Returns the folder which the file or directory stored in path is in */
Folder* folderForPath(const QString& path);
@@ -108,11 +112,11 @@ public slots:
void slotFolderSyncFinished( const SyncResult& );
/**
* Terminates the specified folder sync (or the current one).
* Terminates the current folder sync.
*
* It does not switch the folder to paused state.
*/
void terminateSyncProcess( const QString& alias = QString::null );
void terminateSyncProcess();
/* unload and delete on folder object */
void unloadFolder( const QString& alias );
@@ -130,11 +134,16 @@ public slots:
// slot to add a folder to the syncing queue
void slotScheduleSync( const QString & );
// slot to scheule an ETag job
void slotScheduleETagJob ( const QString &alias, RequestEtagJob *job);
void slotEtagJobDestroyed (QObject*);
void slotRunOneEtagJob();
private slots:
// slot to take the next folder from queue and start syncing.
void slotStartScheduledFolderSync();
void slotEtagPollTimerTimeout();
private:
// finds all folder configuration files
@@ -153,6 +162,9 @@ private:
QSignalMapper *_folderWatcherSignalMapper;
QString _currentSyncFolder;
bool _syncEnabled;
QTimer _etagPollTimer;
QPointer<RequestEtagJob> _currentEtagJob; // alias of Folder running the current RequestEtagJob
QMap<QString, FolderWatcher*> _folderWatchers;
QPointer<SocketApi> _socketApi;

View File

@@ -71,6 +71,12 @@ bool FolderWatcher::pathIsIgnored( const QString& path )
{
if( path.isEmpty() ) return true;
QFileInfo fInfo(path);
if( fInfo.isHidden() ) {
qDebug() << "* Discarded as is hidden!" << fInfo.filePath();
return true;
}
// Remember: here only directories are checked!
// If that changes to files too at some day, remember to check
// for the database name as well as the trailing slash rule for
@@ -79,12 +85,6 @@ bool FolderWatcher::pathIsIgnored( const QString& path )
QRegExp regexp(pattern);
regexp.setPatternSyntax(QRegExp::Wildcard);
QFileInfo fInfo(path);
if( fInfo.isHidden() ) {
qDebug() << "* Discarded as is hidden!" << fInfo.filePath();
return true;
}
if(pattern.endsWith('/')) {
// directory only pattern. But since only dirs here, we cut off the trailing dir.
pattern.remove(pattern.length()-1, 1); // remove the last char.

View File

@@ -13,6 +13,7 @@
#include <QThread>
#include <QDebug>
#include <QDir>
#include "mirall/folderwatcher.h"
#include "mirall/folderwatcher_win.h"
@@ -23,52 +24,123 @@
namespace Mirall {
void WatcherThread::run()
void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
bool* increaseBufferSize)
{
_handle = FindFirstChangeNotification((wchar_t*)_path.utf16(),
true, // recursive watch
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_LAST_WRITE);
*increaseBufferSize = false;
_handle = CreateFileW(
(wchar_t*)_path.utf16(),
FILE_LIST_DIRECTORY,
FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL
);
if (_handle == INVALID_HANDLE_VALUE)
{
qDebug() << Q_FUNC_INFO << "FindFirstChangeNotification function failed, stopping watcher!";
FindCloseChangeNotification(_handle);
DWORD errorCode = GetLastError();
qDebug() << Q_FUNC_INFO << "Failed to create handle for" << _path << ", error:" << errorCode;
_handle = 0;
return;
}
if (_handle == NULL)
{
qDebug() << Q_FUNC_INFO << "FindFirstChangeNotification returned null, stopping watcher!";
FindCloseChangeNotification(_handle);
_handle = 0;
return;
}
// QVarLengthArray ensures the stack-buffer is aligned like double and qint64.
QVarLengthArray<char, 4096*10> fileNotifyBuffer;
fileNotifyBuffer.resize(fileNotifyBufferSize);
while(true) {
switch(WaitForSingleObject(_handle, /*wait*/ INFINITE)) {
case WAIT_OBJECT_0:
if (FindNextChangeNotification(_handle) == false) {
qDebug() << Q_FUNC_INFO << "FindFirstChangeNotification returned FALSE, stopping watcher!";
FindCloseChangeNotification(_handle);
_handle = 0;
return;
const size_t fileNameBufferSize = 4096;
TCHAR fileNameBuffer[fileNameBufferSize];
forever {
FILE_NOTIFY_INFORMATION *pFileNotifyBuffer =
(FILE_NOTIFY_INFORMATION*)fileNotifyBuffer.data();
DWORD dwBytesReturned = 0;
SecureZeroMemory(pFileNotifyBuffer, fileNotifyBufferSize);
if(ReadDirectoryChangesW( _handle, (LPVOID)pFileNotifyBuffer,
fileNotifyBufferSize, true,
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_LAST_WRITE,
&dwBytesReturned, NULL, NULL))
{
FILE_NOTIFY_INFORMATION *curEntry = pFileNotifyBuffer;
forever {
size_t len = curEntry->FileNameLength / 2;
QString file = _path + "\\" + QString::fromWCharArray(curEntry->FileName, len);
// Unless the file was removed or renamed, get its full long name
// TODO: We could still try expanding the path in the tricky cases...
QString longfile = file;
if (curEntry->Action != FILE_ACTION_REMOVED
&& curEntry->Action != FILE_ACTION_RENAMED_OLD_NAME) {
size_t longNameSize = GetLongPathNameW(reinterpret_cast<LPCWSTR>(file.utf16()), fileNameBuffer, fileNameBufferSize);
if (longNameSize > 0) {
longfile = QString::fromUtf16(reinterpret_cast<const ushort *>(fileNameBuffer), longNameSize);
} else {
qDebug() << Q_FUNC_INFO << "Error converting file name to full length, keeping original name.";
}
}
longfile = QDir::cleanPath(longfile);
qDebug() << Q_FUNC_INFO << "Found change in" << longfile << "action:" << curEntry->Action;
emit changed(longfile);
if (curEntry->NextEntryOffset == 0) {
break;
}
curEntry = (FILE_NOTIFY_INFORMATION*)(
(char*)curEntry + curEntry->NextEntryOffset);
}
// qDebug() << Q_FUNC_INFO << "Change detected in" << _path << "from" << QThread::currentThread ();
emit changed(_path);
break;
default:
qDebug() << Q_FUNC_INFO << "Error while watching";
} else {
DWORD errorCode = GetLastError();
switch(errorCode) {
case ERROR_NOTIFY_ENUM_DIR:
qDebug() << Q_FUNC_INFO << "The buffer for changes overflowed! Triggering a generic change and resizing";
emit changed(_path);
*increaseBufferSize = true;
break;
default:
qDebug() << Q_FUNC_INFO << "General error" << errorCode << "while watching. Exiting.";
break;
}
CloseHandle(_handle);
_handle = NULL;
return;
}
}
}
void WatcherThread::run()
{
// If this buffer fills up before we've extracted its data we will lose
// change information. Therefore start big.
size_t bufferSize = 4096*10;
size_t maxBuffer = 64*1024;
forever {
bool increaseBufferSize = false;
watchChanges(bufferSize, &increaseBufferSize);
if (increaseBufferSize) {
bufferSize = qMin(bufferSize*2, maxBuffer);
} else {
// Other errors shouldn't actually happen,
// so sleep a bit to avoid running into the same error case in a
// tight loop.
sleep(2);
}
}
}
WatcherThread::~WatcherThread()
{
if (_handle)
FindCloseChangeNotification(_handle);
if (_handle) {
CloseHandle(_handle);
_handle = NULL;
}
}
FolderWatcherPrivate::FolderWatcherPrivate(FolderWatcher *p, const QString& path)

View File

@@ -33,6 +33,8 @@ public:
protected:
void run();
void watchChanges(size_t fileNotifyBufferSize,
bool* increaseBufferSize);
signals:
void changed(const QString &path);

View File

@@ -254,9 +254,9 @@ void FolderWizardRemotePath::slotAddRemoteFolder()
QInputDialog *dlg = new QInputDialog(this);
dlg->setWindowTitle(tr("Add Remote Folder"));
dlg->setLabelText(tr("Enter the name of the new folder:"));
dlg->setTextValue(parent);
dlg->setWindowTitle(tr("Create Remote Folder"));
dlg->setLabelText(tr("Enter the name of the new folder to be created below '%1':")
.arg(parent));
dlg->open(this, SLOT(slotCreateRemoteFolder(QString)));
dlg->setAttribute(Qt::WA_DeleteOnClose);
}
@@ -265,7 +265,14 @@ void FolderWizardRemotePath::slotCreateRemoteFolder(const QString &folder)
{
if( folder.isEmpty() ) return;
MkColJob *job = new MkColJob(AccountManager::instance()->account(), folder, this);
QTreeWidgetItem *current = _ui.folderTreeWidget->currentItem();
QString fullPath;
if (current) {
fullPath = current->data(0, Qt::UserRole).toString();
}
fullPath += "/" + folder;
MkColJob *job = new MkColJob(AccountManager::instance()->account(), fullPath, this);
/* check the owncloud configuration file and query the ownCloud */
connect(job, SIGNAL(finished(QNetworkReply::NetworkError)),
SLOT(slotCreateRemoteFolderFinished(QNetworkReply::NetworkError)));

View File

@@ -137,7 +137,7 @@
<item row="1" column="1">
<widget class="QPushButton" name="addFolderButton">
<property name="text">
<string>Add Folder</string>
<string>Create Folder</string>
</property>
</widget>
</item>

View File

@@ -31,6 +31,7 @@
#include "mirall/networkjobs.h"
#include "mirall/account.h"
#include "mirall/owncloudpropagator.h"
#include "creds/credentialsfactory.h"
#include "creds/abstractcredentials.h"
@@ -50,12 +51,7 @@ AbstractNetworkJob::AbstractNetworkJob(Account *account, const QString &path, QO
, _path(path)
{
_timer.setSingleShot(true);
if (!AbstractNetworkJob::preOc7WasDetected) {
_timer.setInterval(10*1000); // default to 10 seconds.
} else {
qDebug() << "Pre-oc7 server detected, adjusting timeout values";
_timer.setInterval(60*1000); // long PROPFINDs in oc6 might take too long
}
_timer.setInterval(OwncloudPropagator::httpTimeout() * 1000); // default to 5 minutes.
connect(&_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
connect(this, SIGNAL(networkActivity()), SLOT(resetTimeout()));
@@ -104,6 +100,12 @@ void AbstractNetworkJob::setPath(const QString &path)
void AbstractNetworkJob::setupConnections(QNetworkReply *reply)
{
connect(reply, SIGNAL(finished()), SLOT(slotFinished()));
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
connect(reply, SIGNAL(encrypted()), SIGNAL(networkActivity()));
#endif
connect(reply->manager(), SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), SIGNAL(networkActivity()));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SIGNAL(networkActivity()));
connect(reply, SIGNAL(metaDataChanged()), SIGNAL(networkActivity()));
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), SIGNAL(networkActivity()));
connect(reply, SIGNAL(uploadProgress(qint64,qint64)), SIGNAL(networkActivity()));
}
@@ -164,8 +166,8 @@ void AbstractNetworkJob::slotFinished()
bool discard = finished();
AbstractCredentials *creds = _account->credentials();
if (!creds->stillValid(_reply) &&! _ignoreCredentialFailure
&& _account->state() != Account::InvalidCredidential) {
_account->setState(Account::InvalidCredidential);
&& _account->state() != Account::InvalidCredential) {
_account->setState(Account::InvalidCredential);
// invalidate & forget token/password
// but try to re-sign in.
@@ -382,8 +384,11 @@ void CheckServerJob::start()
void CheckServerJob::slotTimeout()
{
qDebug() << "TIMEOUT" << Q_FUNC_INFO;
if (reply()->isRunning())
if (reply() && reply()->isRunning()) {
emit timeout(reply()->url());
} else if (!reply()) {
qDebug() << Q_FUNC_INFO << "Timeout even there was no reply?";
}
deleteLater();
}

View File

@@ -259,16 +259,17 @@ void ownCloudGui::slotComputeOverallSyncStatus()
// create the tray blob message, check if we have an defined state
if( overallResult.status() != SyncResult::Undefined ) {
QStringList allStatusStrings;
foreach(Folder* folder, map.values()) {
qDebug() << "Folder in overallStatus Message: " << folder << " with name " << folder->alias();
QString folderMessage = folderMan->statusToString(folder->syncResult().status(), folder->syncPaused());
allStatusStrings += tr("Folder %1: %2").arg(folder->alias(), folderMessage);
}
if( map.count() > 0 ) {
foreach(Folder* folder, map.values()) {
qDebug() << "Folder in overallStatus Message: " << folder << " with name " << folder->alias();
QString folderMessage = folderMan->statusToString(folder->syncResult().status(), folder->syncPaused());
allStatusStrings += tr("Folder %1: %2").arg(folder->alias(), folderMessage);
}
if( ! allStatusStrings.isEmpty() )
trayMessage = allStatusStrings.join(QLatin1String("\n"));
else
} else {
trayMessage = tr("No sync folders configured.");
}
QIcon statusIcon = Theme::instance()->syncStateIcon( overallResult.status(), true);
_tray->setIcon( statusIcon );
@@ -466,20 +467,21 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const Progress::Info
{
Q_UNUSED(folder);
if (!progress._currentDiscoveredFolder.isEmpty()) {
_actionStatus->setText( tr("Discovering '%1'")
.arg( progress._currentDiscoveredFolder ));
} else if (progress._totalSize == 0 ) {
quint64 currentFile = progress._completedFileCount + progress._currentItems.count();
_actionStatus->setText( tr("Syncing %1 of %2 (%3 left)")
.arg( currentFile ).arg( progress._totalFileCount )
.arg( Utility::timeToDescriptiveString(progress.totalEstimate().getEtaEstimate(), 2, " ",true) ) );
} else {
QString totalSizeStr = Utility::octetsToString( progress._totalSize );
_actionStatus->setText( tr("Syncing %1 (%2 left)")
.arg( totalSizeStr )
.arg( Utility::timeToDescriptiveString(progress.totalEstimate().getEtaEstimate(), 2, " ",true) ) );
}
if (!progress._currentDiscoveredFolder.isEmpty()) {
_actionStatus->setText( tr("Discovering '%1'")
.arg( progress._currentDiscoveredFolder ));
} else if (progress._totalSize == 0 ) {
quint64 currentFile = progress._completedFileCount + progress._currentItems.count();
quint64 totalFileCount = qMax(progress._totalFileCount, currentFile);
_actionStatus->setText( tr("Syncing %1 of %2 (%3 left)")
.arg( currentFile ).arg( totalFileCount )
.arg( Utility::timeToDescriptiveString(progress.totalEstimate().getEtaEstimate(), 2, " ",true) ) );
} else {
QString totalSizeStr = Utility::octetsToString( progress._totalSize );
_actionStatus->setText( tr("Syncing %1 (%2 left)")
.arg( totalSizeStr )
.arg( Utility::timeToDescriptiveString(progress.totalEstimate().getEtaEstimate(), 2, " ",true) ) );
}
@@ -516,7 +518,8 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const Progress::Info
slotRebuildRecentMenus();
}
if (progress._completedFileCount == progress._totalFileCount
if (progress._completedFileCount != ULLONG_MAX
&& progress._completedFileCount >= progress._totalFileCount
&& progress._currentDiscoveredFolder.isEmpty()) {
QTimer::singleShot(2000, this, SLOT(slotDisplayIdle()));
}

View File

@@ -248,13 +248,23 @@ void OwncloudPropagator::start(const SyncFileItemVector& items)
if (!removedDirectory.isEmpty() && item._file.startsWith(removedDirectory)) {
// this is an item in a directory which is going to be removed.
PropagateDirectory *delDirJob = dynamic_cast<PropagateDirectory*>(directoriesToRemove.last());
if (item._instruction == CSYNC_INSTRUCTION_REMOVE) {
//already taken care of. (by the removal of the parent directory)
// increase the number of subjobs that would be there.
if( delDirJob ) {
delDirJob->increaseAffectedCount();
}
continue;
} else if (item._instruction == CSYNC_INSTRUCTION_NEW && item._isDirectory) {
// create a new directory within a deleted directory? That can happen if the directory
// etag were not fetched properly on the previous sync because the sync was aborted
// while uploading this directory (which is now removed). We can ignore it.
if( delDirJob ) {
delDirJob->increaseAffectedCount();
}
continue;
} else if (item._instruction == CSYNC_INSTRUCTION_IGNORE) {
continue;

View File

@@ -71,59 +71,6 @@ signals:
};
/*
* Propagate a directory, and all its sub entries.
*/
class PropagateDirectory : public PropagatorJob {
Q_OBJECT
public:
// e.g: create the directory
QScopedPointer<PropagatorJob>_firstJob;
// all the sub files or sub directories.
QVector<PropagatorJob *> _subJobs;
SyncFileItem _item;
int _current; // index of the current running job
int _runningNow; // number of subJob running now
SyncFileItem::Status _hasError; // NoStatus, or NormalError / SoftError if there was an error
explicit PropagateDirectory(OwncloudPropagator *propagator, const SyncFileItem &item = SyncFileItem())
: PropagatorJob(propagator)
, _firstJob(0), _item(item), _current(-1), _runningNow(0), _hasError(SyncFileItem::NoStatus) { }
virtual ~PropagateDirectory() {
qDeleteAll(_subJobs);
}
void append(PropagatorJob *subJob) {
_subJobs.append(subJob);
}
virtual void start() Q_DECL_OVERRIDE;
virtual void abort() Q_DECL_OVERRIDE {
if (_firstJob)
_firstJob->abort();
foreach (PropagatorJob *j, _subJobs)
j->abort();
}
private slots:
void startJob(PropagatorJob *next) {
connect(next, SIGNAL(finished(SyncFileItem::Status)), this, SLOT(slotSubJobFinished(SyncFileItem::Status)), Qt::QueuedConnection);
connect(next, SIGNAL(completed(SyncFileItem)), this, SIGNAL(completed(SyncFileItem)));
connect(next, SIGNAL(progress(SyncFileItem,quint64)), this, SIGNAL(progress(SyncFileItem,quint64)));
connect(next, SIGNAL(ready()), this, SLOT(slotSubJobReady()));
_runningNow++;
QMetaObject::invokeMethod(next, "start", Qt::QueuedConnection);
}
void slotSubJobFinished(SyncFileItem::Status status);
void slotSubJobReady();
};
/*
* Abstract class to propagate a single item
@@ -148,8 +95,6 @@ protected:
_item._errorString = msg;
}
SyncFileItem _item;
protected slots:
void slotRestoreJobCompleted(const SyncFileItem& );
@@ -160,8 +105,69 @@ public:
PropagateItemJob(OwncloudPropagator* propagator, const SyncFileItem &item)
: PropagatorJob(propagator), _item(item) {}
SyncFileItem _item;
};
/*
* Propagate a directory, and all its sub entries.
*/
class PropagateDirectory : public PropagatorJob {
Q_OBJECT
public:
// e.g: create the directory
QScopedPointer<PropagateItemJob>_firstJob;
// all the sub files or sub directories.
QVector<PropagatorJob *> _subJobs;
SyncFileItem _item;
int _current; // index of the current running job
int _runningNow; // number of subJob running now
SyncFileItem::Status _hasError; // NoStatus, or NormalError / SoftError if there was an error
explicit PropagateDirectory(OwncloudPropagator *propagator, const SyncFileItem &item = SyncFileItem())
: PropagatorJob(propagator)
, _firstJob(0), _item(item), _current(-1), _runningNow(0), _hasError(SyncFileItem::NoStatus)
{ }
virtual ~PropagateDirectory() {
qDeleteAll(_subJobs);
}
void append(PropagatorJob *subJob) {
_subJobs.append(subJob);
}
virtual void start() Q_DECL_OVERRIDE;
virtual void abort() Q_DECL_OVERRIDE {
if (_firstJob)
_firstJob->abort();
foreach (PropagatorJob *j, _subJobs)
j->abort();
}
void increaseAffectedCount() {
_firstJob->_item._affectedItems++;
}
private slots:
void startJob(PropagatorJob *next) {
connect(next, SIGNAL(finished(SyncFileItem::Status)), this, SLOT(slotSubJobFinished(SyncFileItem::Status)), Qt::QueuedConnection);
connect(next, SIGNAL(completed(SyncFileItem)), this, SIGNAL(completed(SyncFileItem)));
connect(next, SIGNAL(progress(SyncFileItem,quint64)), this, SIGNAL(progress(SyncFileItem,quint64)));
connect(next, SIGNAL(ready()), this, SLOT(slotSubJobReady()));
_runningNow++;
QMetaObject::invokeMethod(next, "start", Qt::QueuedConnection);
}
void slotSubJobFinished(SyncFileItem::Status status);
void slotSubJobReady();
};
// Dummy job that just mark it as completed and ignored.
class PropagateIgnoreJob : public PropagateItemJob {
Q_OBJECT

View File

@@ -111,6 +111,7 @@ void OwncloudSetupWizard::startWizard()
}
}
_ocWizard->setProperty("oldLocalFolder", localFolder);
_ocWizard->setProperty("localFolder", localFolder);
// remember the local folder to compare later if it changed, but clean first
@@ -145,7 +146,7 @@ void OwncloudSetupWizard::slotDetermineAuthType(const QString &urlString)
}
Account *account = _ocWizard->account();
account->setUrl(url);
// Set fake credentials beforfe we check what credidential it actually is.
// Set fake credentials beforfe we check what credential it actually is.
account->setCredentials(CredentialsFactory::create("dummy"));
CheckServerJob *job = new CheckServerJob(_ocWizard->account(), false, this);
job->setIgnoreCredentialFailure(true);
@@ -183,17 +184,17 @@ void OwncloudSetupWizard::slotOwnCloudFoundAuth(const QUrl& url, const QVariantM
void OwncloudSetupWizard::slotNoOwnCloudFoundAuth(QNetworkReply *reply)
{
_ocWizard->displayError(tr("Failed to connect to %1 at %2:<br/>%3")
.arg(Theme::instance()->appNameGUI())
.arg(reply->url().toString())
.arg(reply->errorString()));
.arg(Theme::instance()->appNameGUI(),
reply->url().toString(),
reply->errorString()));
}
void OwncloudSetupWizard::slotNoOwnCloudFoundAuthTimeout(const QUrl&url)
{
_ocWizard->displayError(tr("Failed to connect to %1 at %2:<br/>%3")
.arg(Theme::instance()->appNameGUI())
.arg(url.toString())
.arg("Timeout"));
.arg(Theme::instance()->appNameGUI(),
url.toString(),
"Timeout"));
}
void OwncloudSetupWizard::slotConnectToOCUrl( const QString& url )
@@ -412,7 +413,7 @@ void OwncloudSetupWizard::slotAssistantFinished( int result )
Folder *f = folderMan->folderForPath(localFolder);
if( f ) {
folderMan->setSyncEnabled(false);
folderMan->terminateSyncProcess(f->alias());
f->slotTerminateSync();
f->journalDb()->close();
}
@@ -432,21 +433,23 @@ void OwncloudSetupWizard::slotAssistantFinished( int result )
}
// 2. Server URL or user changed, requires reinit of folders
else if (reinitRequired) {
folderMan->removeAllFolderDefinitions();
// 2.1: startFromScratch: (Re)move local data, clean slate sync
if (startFromScratch) {
if (ensureStartFromScratch(localFolder)) {
folderMan->addFolderDefinition(Theme::instance()->appName(),
localFolder, _remoteFolder, _ocWizard->blacklist() );
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
if (folderMan->addFolderDefinition(Theme::instance()->appName(),
localFolder, _remoteFolder, _ocWizard->blacklist() )) {
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
}
replaceDefaultAccountWith(newAccount);
}
}
// 2.2: Reinit: Remove journal and start a sync
else {
folderMan->removeAllFolderDefinitions();
folderMan->addFolderDefinition(Theme::instance()->appName(),
localFolder, _remoteFolder, _ocWizard->blacklist() );
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
if (folderMan->addFolderDefinition(Theme::instance()->appName(),
localFolder, _remoteFolder, _ocWizard->blacklist() )) {
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
}
replaceDefaultAccountWith(newAccount);
}
}

View File

@@ -15,6 +15,7 @@
#include <QDateTime>
#include <QString>
#include <QDebug>
#include <QFile>
#include "ownsql.h"
#include "utility.h"
@@ -40,23 +41,88 @@ bool SqlDatabase::isOpen()
return _db != 0;
}
bool SqlDatabase::open( const QString& filename )
bool SqlDatabase::openHelper( const QString& filename, int sqliteFlags )
{
if(isOpen()) {
if( isOpen() ) {
return true;
}
int flag = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_NOMUTEX;
SQLITE_DO( sqlite3_open_v2(filename.toUtf8().constData(), &_db, flag, 0) );
sqliteFlags |= SQLITE_OPEN_NOMUTEX;
SQLITE_DO( sqlite3_open_v2(filename.toUtf8().constData(), &_db, sqliteFlags, 0) );
if( _errId != SQLITE_OK ) {
close(); // FIXME: Correct?
_db = 0;
qDebug() << "Error:" << _error << "for" << filename;
close();
return false;
}
if( !_db ) {
qDebug() << "Error: no database for" << filename;
return false;
}
sqlite3_busy_timeout(_db, 5000);
return isOpen();
return true;
}
bool SqlDatabase::checkDb()
{
SqlQuery quick_check("PRAGMA quick_check;", *this);
if( !quick_check.exec() ) {
qDebug() << "Error running quick_check on database";
return false;
}
quick_check.next();
QString result = quick_check.stringValue(0);
if( result != "ok" ) {
qDebug() << "quick_check returned failure:" << result;
return false;
}
return true;
}
bool SqlDatabase::openOrCreateReadWrite( const QString& filename )
{
if( isOpen() ) {
return true;
}
if( !openHelper(filename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE) ) {
return false;
}
if( !checkDb() ) {
qDebug() << "Consistency check failed, removing broken db" << filename;
close();
QFile::remove(filename);
return openHelper(filename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
}
return true;
}
bool SqlDatabase::openReadOnly( const QString& filename )
{
if( isOpen() ) {
return true;
}
if( !openHelper(filename, SQLITE_OPEN_READONLY) ) {
return false;
}
if( !checkDb() ) {
qDebug() << "Consistency check failed in readonly mode, giving up" << filename;
close();
return false;
}
return true;
}
QString SqlDatabase::error() const

View File

@@ -30,7 +30,8 @@ public:
explicit SqlDatabase();
bool isOpen();
bool open( const QString& filename );
bool openOrCreateReadWrite( const QString& filename );
bool openReadOnly( const QString& filename );
bool transaction();
bool commit();
void close();
@@ -38,6 +39,9 @@ public:
sqlite3* sqliteDb();
private:
bool openHelper( const QString& filename, int sqliteFlags );
bool checkDb();
sqlite3 *_db;
QString _error; // last error string
int _errId;

View File

@@ -20,6 +20,8 @@
#include <QTime>
#include <QQueue>
#include <QElapsedTimer>
#include <QDebug>
#include "syncfileitem.h"
namespace Mirall {
@@ -112,12 +114,12 @@ namespace Progress
void setProgressComplete(const SyncFileItem &item) {
_currentItems.remove(item._file);
_completedFileCount += item._affectedItems;
if (!item._isDirectory) {
_completedFileCount++;
if (Progress::isSizeDependent(item._instruction)) {
_completedSize += item._size;
}
}
if (Progress::isSizeDependent(item._instruction)) {
_completedSize += item._size;
}
}
_lastCompletedItem = item;
this->updateEstimation();
}

View File

@@ -95,6 +95,12 @@ void PropagateUploadFileLegacy::start()
state = hbf_splitlist(trans.data(), file.handle());
// This is the modtime hbf will announce to the server.
// We don't trust the modtime hbf computes itself via _fstat64
// on windows - hbf may only use it to detect file changes during
// upload.
trans->oc_header_modtime = FileSystem::getModTime(file.fileName());
// If the source file has changed during upload, it is detected and the
// variable _previousFileSize is set accordingly. The propagator waits a
// couple of seconds and retries.
@@ -105,7 +111,7 @@ void PropagateUploadFileLegacy::start()
Q_ARG(qint64, trans->stat_size - _previousFileSize));
// update the item's values to the current from trans. hbf_splitlist does a stat
_item._size = trans->stat_size;
_item._modtime = trans->modtime;
_item._modtime = trans->oc_header_modtime;
}
emit progress(_item, 0);
@@ -185,7 +191,7 @@ void PropagateUploadFileLegacy::start()
if( trans->modtime_accepted ) {
_item._etag = parseEtag(hbf_transfer_etag( trans.data() ));
} else {
if (!updateMTimeAndETag(uri.data(), _item._modtime))
if (!updateMTimeAndETag(uri.data(), trans->oc_header_modtime))
return;
}
@@ -242,7 +248,7 @@ void PropagateUploadFileLegacy::chunk_finished_cb(hbf_transfer_s *trans, int chu
pi._valid = true;
pi._chunk = chunk + 1; // next chunk to start with
pi._transferid = trans->transfer_id;
pi._modtime = Utility::qDateTimeFromTime_t(trans->modtime);
pi._modtime = Utility::qDateTimeFromTime_t(trans->oc_header_modtime);
that->_propagator->_journal->setUploadInfo(that->_item._file, pi);
that->_propagator->_journal->commit("Upload info");
}

View File

@@ -228,6 +228,7 @@ void PropagateUploadFileQNAM::startNextChunk()
quint64 fileSize = _item._size;
QMap<QByteArray, QByteArray> headers;
headers["OC-Total-Length"] = QByteArray::number(fileSize);
headers["OC-Chunk-Size"]= QByteArray::number(quint64(chunkSize()));
headers["Content-Type"] = "application/octet-stream";
headers["X-OC-Mtime"] = QByteArray::number(qint64(_item._modtime));
if (!_item._etag.isEmpty() && _item._etag != "empty_etag" &&
@@ -265,7 +266,6 @@ void PropagateUploadFileQNAM::startNextChunk()
if( isOpen ) {
_job = new PUTFileJob(AccountManager::instance()->account(), _propagator->_remoteFolder + path, device, headers);
_job->setTimeout(_propagator->httpTimeout() * 1000);
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
connect(_job, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(slotUploadProgress(qint64,qint64)));
_job->start();
@@ -679,7 +679,6 @@ void PropagateDownloadFileQNAM::start()
url,
&_tmpFile, headers);
}
_job->setTimeout(_propagator->httpTimeout() * 1000);
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
connect(_job, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slotDownloadProgress(qint64,qint64)));
_propagator->_activeJobs ++;
@@ -742,6 +741,21 @@ void PropagateDownloadFileQNAM::slotGetFinished()
_tmpFile.close();
_tmpFile.flush();
/* Check that the size of the GET reply matches the file size. There have been cases
* reported that if a server breaks behind a proxy, the GET is still a 200 but is
* truncated, as described here: https://github.com/owncloud/mirall/issues/2528
*/
const QByteArray sizeHeader("Content-Length");
quint64 bodySize = job->reply()->rawHeader(sizeHeader).toULongLong();
if(bodySize > 0 && bodySize != _tmpFile.size() - job->resumeStart() ) {
qDebug() << bodySize << _tmpFile.size() << job->resumeStart();
_propagator->_anotherSyncNeeded = true;
done(SyncFileItem::SoftError, tr("The file could not be downloaded completely."));
return;
}
downloadFinished();
}
@@ -771,10 +785,18 @@ void PropagateDownloadFileQNAM::downloadFinished()
QString fn = _propagator->getFilePath(_item._file);
// In case of file name clash, report an error
// This can happen if another parallel download saved a clashing file.
if (_propagator->localFileNameClash(_item._file)) {
done( SyncFileItem::NormalError, tr("File %1 cannot be saved because of a local file name clash!")
.arg(QDir::toNativeSeparators(_item._file)) );
return;
}
// In case of conflict, make a backup of the old file
// Ignore conflicts where both files are binary equal
bool isConflict = _item._instruction == CSYNC_INSTRUCTION_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
&& !FileSystem::fileEquals(fn, _tmpFile.fileName());
if (isConflict) {
QFile f(fn);
QString conflictFileName = makeConflictFileName(fn, Utility::qDateTimeFromTime_t(_item._modtime));
@@ -794,6 +816,19 @@ void PropagateDownloadFileQNAM::downloadFinished()
QString error;
if (!FileSystem::renameReplace(_tmpFile.fileName(), fn, &error)) {
// 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:
// If we do nothing the next sync run will assume the user deleted
// the file!
// To avoid that, the file is removed from the metadata table entirely
// which makes it look like we're just about to initially download
// it.
if (isConflict) {
_propagator->_journal->deleteFileRecord(fn);
_propagator->_journal->commit("download finished");
_propagator->_anotherSyncNeeded = true;
}
done(SyncFileItem::NormalError, error);
return;
}

View File

@@ -50,7 +50,8 @@
namespace Mirall {
// Code copied from Qt5's QDir::removeRecursively
static bool removeRecursively(const QString &path)
// (and modified to report the error)
static bool removeRecursively(const QString &path, QString &error)
{
bool success = true;
QDirIterator di(path, QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot);
@@ -58,15 +59,28 @@ static bool removeRecursively(const QString &path)
di.next();
const QFileInfo& fi = di.fileInfo();
bool ok;
if (fi.isDir() && !fi.isSymLink())
ok = removeRecursively(di.filePath()); // recursive
else
ok = QFile::remove(di.filePath());
if (fi.isDir() && !fi.isSymLink()) {
ok = removeRecursively(di.filePath(), error); // recursive
} else {
QFile f(di.filePath());
ok = f.remove();
if (!ok) {
error += PropagateLocalRemove::tr("Error removing '%1': %2; ").
arg(QDir::toNativeSeparators(f.fileName()), f.errorString());
qDebug() << "Error removing " << f.fileName() << ':' << f.errorString();
}
}
if (!ok)
success = false;
}
if (success)
if (success) {
success = QDir().rmdir(path);
if (!success) {
error += PropagateLocalRemove::tr("Could not remove directory '%1'; ")
.arg(QDir::toNativeSeparators(path));
qDebug() << "Error removing directory" << path;
}
}
return success;
}
@@ -83,9 +97,9 @@ void PropagateLocalRemove::start()
}
if (_item._isDirectory) {
if (QDir(filename).exists() && !removeRecursively(filename)) {
done(SyncFileItem::NormalError, tr("Could not remove directory %1")
.arg(QDir::toNativeSeparators(filename)));
QString error;
if (QDir(filename).exists() && !removeRecursively(filename, error)) {
done(SyncFileItem::NormalError, error);
return;
}
} else {

View File

@@ -65,9 +65,9 @@ ProtocolWidget::ProtocolWidget(QWidget *parent) :
connect(this, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(guiLog(QString,QString)));
_clearBlacklistBtn = _ui->_dialogButtonBox->addButton(tr("Retry Sync"), QDialogButtonBox::ActionRole);
_clearBlacklistBtn->setEnabled(false);
connect(_clearBlacklistBtn, SIGNAL(clicked()), SLOT(slotClearBlacklist()));
_retrySyncBtn = _ui->_dialogButtonBox->addButton(tr("Retry Sync"), QDialogButtonBox::ActionRole);
_retrySyncBtn->setEnabled(false);
connect(_retrySyncBtn, SIGNAL(clicked()), SLOT(slotRetrySync()));
_copyBtn = _ui->_dialogButtonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
_copyBtn->setToolTip( tr("Copy the activity list to the clipboard."));
@@ -118,7 +118,7 @@ void ProtocolWidget::copyToClipboard()
emit guiLog(tr("Copied to clipboard"), tr("The sync status has been copied to the clipboard."));
}
void ProtocolWidget::slotClearBlacklist()
void ProtocolWidget::slotRetrySync()
{
FolderMan *folderMan = FolderMan::instance();
@@ -126,7 +126,12 @@ void ProtocolWidget::slotClearBlacklist()
foreach( Folder *f, folders ) {
int num = f->slotWipeBlacklist();
qDebug() << num << "entries were removed from"<< f->alias() << "blacklist";
qDebug() << num << "entries were removed from"
<< f->alias() << "blacklist";
num = f->slotDiscardDownloadProgress();
qDebug() << num << "temporary files with partial downloads"
<< "were removed from" << f->alias();
}
folderMan->slotScheduleAllFolders();
@@ -247,18 +252,23 @@ void ProtocolWidget::computeResyncButtonEnabled()
FolderMan *folderMan = FolderMan::instance();
Folder::Map folders = folderMan->map();
int cnt = 0;
int blacklist_cnt = 0;
int downloads_cnt = 0;
foreach( Folder *f, folders ) {
cnt += f->blackListEntryCount();
blacklist_cnt += f->blackListEntryCount();
downloads_cnt += f->downloadInfoCount();
}
QString t = tr("Currently no files are ignored because of previous errors.");
if(cnt > 0) {
t = tr("%n files are ignored because of previous errors.\n Try to sync these again.", 0, cnt);
QString t = tr("Currently no files are ignored because of previous errors and no downloads are in progress.");
bool enabled = blacklist_cnt > 0 || downloads_cnt > 0;
if (enabled) {
t = tr("%n files are ignored because of previous errors.\n", 0, blacklist_cnt)
+ tr("%n files are partially downloaded.\n", 0, downloads_cnt)
+ tr("Try to sync these again.");
}
_clearBlacklistBtn->setEnabled(cnt > 0);
_clearBlacklistBtn->setToolTip(t);
_retrySyncBtn->setEnabled(enabled);
_retrySyncBtn->setToolTip(t);
}
@@ -268,7 +278,7 @@ void ProtocolWidget::slotProgressInfo( const QString& folder, const Progress::In
// The sync is restarting, clean the old items
cleanIgnoreItems(folder);
computeResyncButtonEnabled();
} else if (progress._totalFileCount == progress._completedFileCount) {
} else if (progress._completedFileCount >= progress._totalFileCount) {
//Sync completed
computeResyncButtonEnabled();
}

View File

@@ -47,7 +47,7 @@ public slots:
protected slots:
void copyToClipboard();
void slotClearBlacklist();
void slotRetrySync();
signals:
void guiLog(const QString&, const QString&);
@@ -65,7 +65,7 @@ private:
const int IgnoredIndicatorRole;
Ui::ProtocolWidget *_ui;
QPushButton *_clearBlacklistBtn;
QPushButton *_retrySyncBtn;
QPushButton *_copyBtn;
};

View File

@@ -51,7 +51,7 @@ void QuotaInfo::slotAccountStateChanged(int state)
{
switch (state) {
case Account::SignedOut: // fall through
case Account::InvalidCredidential:
case Account::InvalidCredential:
case Account::Disconnected:
_jobRestartTimer->stop();
break;

View File

@@ -271,7 +271,9 @@ void SelectiveSyncDialog::init(Account *account)
setWindowTitle(tr("Choose What to Sync"));
QVBoxLayout *layout = new QVBoxLayout(this);
_treeView = new SelectiveSyncTreeView(account, this);
layout->addWidget(new QLabel(tr("Unchecked folders will not be sync to this computer")));
QLabel *label = new QLabel(tr("Unchecked folders will be <b>removed</b> from your local file system and will not be synchronized to this computer anymore"));
label->setWordWrap(true);
layout->addWidget(label);
layout->addWidget(_treeView);
QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal);
QPushButton *button;

View File

@@ -1,3 +1,16 @@
/*
* Copyright (C) by Denis Dzyubenko
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "settingsdialogmac.h"
#include "macstandardicon.h"

View File

@@ -1,3 +1,17 @@
/*
* Copyright (C) by Denis Dzyubenko
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef SETTINGSDIALOGMAC_H
#define SETTINGSDIALOGMAC_H

View File

@@ -94,6 +94,11 @@ SocketApi::SocketApi(QObject* parent)
runtimeDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
#else
runtimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
if (runtimeDir.isEmpty()) {
runtimeDir = QDir::tempPath() + QLatin1String("/runtime-")
+ QString::fromLocal8Bit(qgetenv("USER"));
QDir().mkdir(runtimeDir);
}
#endif
socketPath = runtimeDir + "/" + Theme::instance()->appName() + "/socket";
} else {
@@ -344,7 +349,12 @@ void SocketApi::broadcastMessage( const QString& verb, const QString& path, cons
}
if( !path.isEmpty() ) {
msg.append(QLatin1Char(':'));
msg.append(QDir::toNativeSeparators(path));
QFileInfo fi(path);
auto canon = fi.canonicalFilePath();
if (canon.isEmpty()) { // just in case the file do not exist
fi = fi.absoluteFilePath();
}
msg.append(QDir::toNativeSeparators(canon));
}
// sendMessage already has a debug output
@@ -417,7 +427,7 @@ SqlQuery* SocketApi::getSqlQuery( Folder *folder )
if( fi.exists() ) {
SqlDatabase *db = new SqlDatabase;
if( db && db->open(dbFileName) ) {
if( db && db->openReadOnly(dbFileName) ) {
_openDbs.insert(folder, db);
SqlQuery *query = new SqlQuery(*db);
@@ -430,6 +440,8 @@ SqlQuery* SocketApi::getSqlQuery( Folder *folder )
}
_dbQueries.insert( folder, query);
return query;
} else {
qDebug() << "Unable to open db" << dbFileName;
}
} else {
qDebug() << Q_FUNC_INFO << "Journal to query does not yet exist.";

View File

@@ -179,7 +179,9 @@ QString SyncEngine::csyncErrorToString(CSYNC_STATUS err)
case CSYNC_STATUS_ABORTED:
errStr = tr("Aborted by the user");
break;
case CSYNC_STATUS_SERVICE_UNAVAILABLE:
errStr = tr("The mounted directory is temporary not available on the server");
break;
default:
errStr = tr("An internal error number %1 happened.").arg( (int) err );
}
@@ -325,7 +327,9 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
item._modtime = file->modtime;
} else {
if (file->instruction != CSYNC_INSTRUCTION_NONE) {
qDebug() << "ERROR: Instruction" << item._instruction << "vs" << file->instruction << "for" << fileUtf8;
Q_ASSERT(!"Instructions are both unequal NONE");
return -1;
}
}
@@ -368,11 +372,15 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
case CYSNC_STATUS_FILE_LOCKED_OR_OPEN:
item._errorString = QLatin1String("File locked"); // don't translate, internal use!
break;
case CSYNC_STATUS_SERVICE_UNAVAILABLE:
item._errorString = QLatin1String("Directory temporarily not available on server.");
item._status = SyncFileItem::SoftError;
break;
default:
Q_ASSERT("Non handled error-status");
/* No error string */
}
item._isDirectory = file->type == CSYNC_FTW_TYPE_DIR;
// The etag is already set in the previous sync phases somewhere. Maybe we should remove it there
@@ -404,12 +412,17 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
switch(file->instruction) {
case CSYNC_INSTRUCTION_NONE:
if (remote && item._should_update_etag && !item._isDirectory && item._instruction == CSYNC_INSTRUCTION_NONE) {
// Update the database now already (new fileid or etag or remotePerm)
// Those are files that were detected as "resolved conflict".
// Update the database now already: New fileid or Etag or RemotePerm
// Or for files that were detected as "resolved conflict".
// They should have been a conflict because they both were new, or both
// had their local mtime or remote etag modified, but the size and mtime
// is the same on the server. This typically happen when the database is removed.
// Nothing will be done for those file, but we still need to update the database.
// Even if the mtime is different on the server, we always want to keep the mtime from
// the file system in the DB, this is to avoid spurious upload on the next sync
item._modtime = file->other.modtime;
_journal->setFileRecord(SyncJournalFileRecord(item, _localPath + item._file));
item._should_update_etag = false;
}
@@ -463,6 +476,9 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
if (Progress::isSizeDependent(file->instruction)) {
_progressInfo._totalSize += file->size;
}
} else if (file->instruction != CSYNC_INSTRUCTION_NONE) {
// Added or removed directories certainly count.
_progressInfo._totalFileCount++;
}
_needsUpdate = true;
@@ -532,6 +548,14 @@ void SyncEngine::startSync()
qDebug() << "=====sync with existing DB";
}
qDebug() << "=====Using Qt" << qVersion();
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
qDebug() << "=====Using SSL library version"
<< QSslSocket::sslLibraryVersionString().toUtf8().data();
#endif
// Note that this seems to output the OpenSSL build version not runtime version:
qDebug() << "=====Using" << ne_version_string();
fileRecordCount = _journal->getFileRecordCount(); // this creates the DB if it does not exist yet
bool isUpdateFrom_1_5 = _journal->isUpdateFrom_1_5();
@@ -1077,9 +1101,16 @@ void SyncEngine::setSelectiveSyncBlackList(const QStringList& list)
bool SyncEngine::estimateState(QString fn, csync_ftw_type_e t, SyncFileStatus* s)
{
Q_UNUSED(t);
QString pat(fn);
if( t == CSYNC_FTW_TYPE_DIR && ! fn.endsWith(QLatin1Char('/'))) {
pat.append(QLatin1Char('/'));
}
Q_FOREACH(const SyncFileItem &item, _syncedItems) {
//qDebug() << Q_FUNC_INFO << fn << item._file << fn.startsWith(item._file) << item._file.startsWith(fn);
if (item._file.startsWith(fn)) {
if (item._file.startsWith(pat) ||
item._file == fn /* the same directory or file */) {
qDebug() << Q_FUNC_INFO << "Setting" << fn << " to STATUS_EVAL";
s->set(SyncFileStatus::STATUS_EVAL);
return true;

View File

@@ -53,7 +53,10 @@ public:
SyncFileItem() : _type(UnknownType), _direction(None), _isDirectory(false),
_instruction(CSYNC_INSTRUCTION_NONE), _modtime(0),
_size(0), _inode(0), _should_update_etag(false), _hasBlacklistEntry(false),
_status(NoStatus), _httpErrorCode(0), _requestDuration(0), _isRestoration(false) {}
_status(NoStatus), _httpErrorCode(0), _requestDuration(0), _isRestoration(false),
_affectedItems(1)
{
}
friend bool operator==(const SyncFileItem& item1, const SyncFileItem& item2) {
return item1._file == item2._file;
@@ -111,7 +114,8 @@ public:
QString _responseTimeStamp;
quint64 _requestDuration;
bool _isRestoration; // The original operation was forbidden, and this is a restoration
int _affectedItems; // the number of affected items by the operation on this item.
// usually this value is 1, but for removes on dirs, it might be much higher.
struct {
quint64 _size;
time_t _modtime;

View File

@@ -120,7 +120,7 @@ bool SyncJournalDb::checkConnect()
bool isNewDb = !QFile::exists(_dbFile);
// The database file is created by this call (SQLITE_OPEN_CREATE)
if( !_db.open(_dbFile) ) {
if( !_db.openOrCreateReadWrite(_dbFile) ) {
QString error = _db.error();
qDebug() << "Error opening the db: " << error;
return false;
@@ -158,11 +158,6 @@ bool SyncJournalDb::checkConnect()
return sqlFail("Set PRAGMA case_sensitivity", pragma1);
}
// Hide 'em all!
FileSystem::setFileHidden(databaseFilePath(), true);
FileSystem::setFileHidden(databaseFilePath() + "-wal", true);
FileSystem::setFileHidden(databaseFilePath() + "-shm", true);
/* Because insert are so slow, e do everything in a transaction, and one need to call commit */
startTransaction();
@@ -335,6 +330,11 @@ bool SyncJournalDb::checkConnect()
// don't start a new transaction now
commitInternal(QString("checkConnect End"), false);
// Hide 'em all!
FileSystem::setFileHidden(databaseFilePath(), true);
FileSystem::setFileHidden(databaseFilePath() + "-wal", true);
FileSystem::setFileHidden(databaseFilePath() + "-shm", true);
return rc;
}
@@ -807,6 +807,24 @@ QVector<SyncJournalDb::DownloadInfo> SyncJournalDb::getAndDeleteStaleDownloadInf
return deleted_entries;
}
int SyncJournalDb::downloadInfoCount()
{
int re = 0;
QMutexLocker locker(&_mutex);
if( checkConnect() ) {
SqlQuery query("SELECT count(*) FROM downloadinfo", _db);
if( ! query.exec() ) {
sqlFail("Count number of downloadinfo entries failed", query);
}
if( query.next() ) {
re = query.intValue(0);
}
}
return re;
}
SyncJournalDb::UploadInfo SyncJournalDb::getUploadInfo(const QString& file)
{
QMutexLocker locker(&_mutex);

View File

@@ -72,6 +72,7 @@ public:
DownloadInfo getDownloadInfo(const QString &file);
void setDownloadInfo(const QString &file, const DownloadInfo &i);
QVector<DownloadInfo> getAndDeleteStaleDownloadInfos(const QSet<QString>& keep);
int downloadInfoCount();
UploadInfo getUploadInfo(const QString &file);
void setUploadInfo(const QString &file, const UploadInfo &i);
@@ -142,10 +143,12 @@ private:
QList<QString> _avoidReadFromDbOnNextSyncFilter;
};
bool operator==(const SyncJournalDb::DownloadInfo & lhs,
const SyncJournalDb::DownloadInfo & rhs);
bool operator==(const SyncJournalDb::UploadInfo & lhs,
const SyncJournalDb::UploadInfo & rhs);
bool OWNCLOUDSYNC_EXPORT
operator==(const SyncJournalDb::DownloadInfo & lhs,
const SyncJournalDb::DownloadInfo & rhs);
bool OWNCLOUDSYNC_EXPORT
operator==(const SyncJournalDb::UploadInfo & lhs,
const SyncJournalDb::UploadInfo & rhs);
} // namespace Mirall
#endif // SYNCJOURNALDB_H

View File

@@ -43,8 +43,9 @@ public:
int _mode;
};
bool operator==(const SyncJournalFileRecord & lhs,
const SyncJournalFileRecord & rhs);
bool OWNCLOUDSYNC_EXPORT
operator==(const SyncJournalFileRecord & lhs,
const SyncJournalFileRecord & rhs);
class SyncJournalBlacklistRecord
{

View File

@@ -230,14 +230,19 @@ QString Theme::gitSHA1() const
QString Theme::about() const
{
return tr("<p>Version %1 For more information please visit <a href='%2'>%3</a>.</p>"
"<p>Copyright ownCloud, Inc.</p>"
"<p>Distributed by %4 and licensed under the GNU General Public License (GPL) Version 2.0.<br/>"
"%5 and the %5 logo are registered trademarks of %4 in the "
"United States, other countries, or both.</p>")
QString re;
re = tr("<p>Version %1. For more information please visit <a href='%2'>%3</a>.</p>")
.arg(MIRALL_VERSION_STRING).arg("http://" MIRALL_STRINGIFY(APPLICATION_DOMAIN))
.arg(MIRALL_STRINGIFY(APPLICATION_DOMAIN)).arg(APPLICATION_VENDOR).arg(APPLICATION_NAME)
+gitSHA1();
.arg(MIRALL_STRINGIFY(APPLICATION_DOMAIN));
re += tr("<p>Copyright ownCloud, Incorparated</p>");
re += tr("<p>Distributed by %1 and licensed under the GNU General Public License (GPL) Version 2.0.<br/>"
"%2 and the %2 logo are registered trademarks of %1 in the "
"United States, other countries, or both.</p>")
.arg(APPLICATION_VENDOR).arg(APPLICATION_NAME);
re += gitSHA1();
return re;
}
#ifndef TOKEN_AUTH_ONLY

View File

@@ -138,7 +138,7 @@ void help()
std::cout << binaryName << " - command line " APPLICATION_NAME " client tool" << std::endl;
std::cout << "" << std::endl;
std::cout << "Usage: " << binaryName << " <sourcedir> <owncloudurl>" << std::endl;
std::cout << "Usage: " << binaryName << " [OPTION] <source_dir> <server_url>" << std::endl;
std::cout << "" << std::endl;
std::cout << "A proxy can either be set manually using --httpproxy or it" << std::endl;
std::cout << "uses the setting from a configured sync client." << std::endl;

View File

@@ -98,7 +98,7 @@ void OwncloudAdvancedSetupPage::initializePage()
_checking = false;
_multipleFoldersExist = false;
_oldLocalFolder = localFolder();
_oldLocalFolder = wizard()->property("oldLocalFolder").toString();
// call to init label
updateStatus();
@@ -152,7 +152,8 @@ bool OwncloudAdvancedSetupPage::dataChanged()
Account *oldAccount = AccountManager::instance()->account();
if (!ocWizard || !oldAccount) {
return false;
// If there was no account configured before, the data is new (hence changed)
return true;
}
const QString url(field("OCUrl").toString());

View File

@@ -224,7 +224,7 @@ void OwncloudSetupPage::setErrorString( const QString& err )
_ui.errorLabel->setVisible(false);
} else {
if (_ui.leUrl->text().startsWith("https://")) {
QString msg = tr("Could not connect securely. Do you want to connect unencrypted instead (not recommended)?").arg(err);
QString msg = tr("<p>Could not connect securely:</p><p>%1</p><p>Do you want to connect unencrypted instead (not recommended)?</p>").arg(err);
QString title = tr("Connection failed");
if (QMessageBox::question(this, title, msg, QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
QUrl url(_ui.leUrl->text());

View File

@@ -71,18 +71,7 @@ bool OwncloudWizardResultPage::isComplete() const
void OwncloudWizardResultPage::initializePage()
{
const QString localFolder = wizard()->property("localFolder").toString();
QString text;
if( _remoteFolder == QLatin1String("/") || _remoteFolder.isEmpty() ) {
text = tr("Your entire account is synced to the local folder <i>%1</i>")
.arg(QDir::toNativeSeparators(localFolder));
} else {
text = tr("%1 folder <i>%1</i> is synced to local folder <i>%2</i>")
.arg(Theme::instance()->appNameGUI())
.arg(_remoteFolder).arg(QDir::toNativeSeparators(localFolder));
}
_ui.localFolderLabel->setText( text );
_ui.localFolderLabel->setText( QString::null );
}
void OwncloudWizardResultPage::setRemoteFolder(const QString &remoteFolder)

View File

@@ -27,8 +27,8 @@ endif(UNIX AND NOT APPLE)
owncloud_add_test(CSyncSqlite "")
owncloud_add_test(NetrcParser ../src/owncloudcmd/netrcparser.cpp)
owncloud_add_test(OwnSql ../src/mirall/ownsql.cpp)
owncloud_add_test(SyncJournalDB ../src/mirall/syncjournaldb.cpp)
owncloud_add_test(OwnSql "")
owncloud_add_test(SyncJournalDB "")

View File

@@ -8,6 +8,7 @@
#define MIRALL_TESTCSYNCSQLITE_H
#include "csync_statedb.h"
#include "csync_private.h"
#include <QtTest>
@@ -16,39 +17,12 @@ class TestCSyncSqlite : public QObject
Q_OBJECT
private:
/* Attention !!!!!!!!!!!!!!!!!!!
* This struct MY_CSYNC has to be a copy of the CSYNC struct defined
* in csync_private.h until the end of struct statedb.
* Subsequent functions cast the struct to CSYNC. In order to get the
* same values as in the original struct, the start must be the same.
*/
typedef struct {
struct {
csync_auth_callback auth_function;
void *userdata;
csync_update_callback update_callback;
void *update_callback_userdata;
} callbacks;
c_strlist_t *excludes;
struct {
char *file;
sqlite3 *db;
int exists;
int disabled;
sqlite3_stmt* by_hash_stmt;
sqlite3_stmt* by_fileid_stmt;
sqlite3_stmt* by_inode_stmt;
} statedb;
} MY_CSYNC;
MY_CSYNC _ctx;
CSYNC _ctx;
private slots:
void initTestCase() {
int rc;
memset(&_ctx, 0, sizeof(MY_CSYNC));
memset(&_ctx, 0, sizeof(CSYNC));
_ctx.statedb.file = c_strdup("./test_journal.db");

View File

@@ -10,7 +10,7 @@
#include <QtTest>
#include "mirall/folderwatcher_linux.h"
#include "mirall/folderwatcher.h"
#include "mirall/utility.h"
using namespace Mirall;
@@ -21,9 +21,12 @@ class TestFolderWatcher : public QObject
public slots:
void slotFolderChanged( const QString& path ) {
qDebug() << "COMPARE: " << path << _checkMark;
QVERIFY(_checkMark == path);
_checkMark.clear();
if (_skipNotifications.contains(path)) {
return;
}
if (_requiredNotifications.contains(path)) {
_receivedNotifications.insert(path);
}
}
void slotEnd() { // in case something goes wrong...
@@ -36,7 +39,16 @@ private:
FolderWatcher *_watcher;
QEventLoop _loop;
QTimer _timer;
QString _checkMark;
QSet<QString> _requiredNotifications;
QSet<QString> _receivedNotifications;
QSet<QString> _skipNotifications;
void processAndWait()
{
_loop.processEvents();
Utility::usleep(200000);
_loop.processEvents();
}
private slots:
void initTestCase() {
@@ -52,68 +64,95 @@ private slots:
rootDir.mkpath(_root + "/a2/b3/c3");
Utility::writeRandomFile( _root+"/a1/random.bin");
Utility::writeRandomFile( _root+"/a1/b2/todelete.bin");
Utility::writeRandomFile( _root+"/a2/movefile");
Utility::writeRandomFile( _root+"/a2/renamefile");
Utility::writeRandomFile( _root+"/a1/movefile");
_watcher = new FolderWatcher(_root);
QObject::connect(_watcher, SIGNAL(folderChanged(QString)), this, SLOT(slotFolderChanged(QString)));
_timer.singleShot(3000, this, SLOT(slotEnd()));
_timer.singleShot(5000, this, SLOT(slotEnd()));
}
void init()
{
_receivedNotifications.clear();
_requiredNotifications.clear();
_skipNotifications.clear();
}
void checkNotifications()
{
processAndWait();
QCOMPARE(_receivedNotifications, _requiredNotifications);
}
void testACreate() { // create a new file
QString cmd;
_checkMark = _root;
_requiredNotifications.insert(_root);
cmd = QString("echo \"xyz\" > %1/foo.txt").arg(_root);
qDebug() << "Command: " << cmd;
system(cmd.toLocal8Bit());
_loop.processEvents();
QVERIFY(_checkMark.isEmpty()); // the slot clears the checkmark.
checkNotifications();
}
void testATouch() { // touch an existing file.
_requiredNotifications.insert(_root+"/a1");
#ifdef Q_OS_WIN
Utility::writeRandomFile(QString("%1/a1/random.bin").arg(_root));
#else
QString cmd;
cmd = QString("/usr/bin/touch %1/a1/random.bin").arg(_root);
_checkMark = _root+"/a1";
qDebug() << "Command: " << cmd;
system(cmd.toLocal8Bit());
#endif
_loop.processEvents();
QVERIFY(_checkMark.isEmpty()); // the slot clears the checkmark.
checkNotifications();
}
void testCreateADir() {
_checkMark = _root+"/a1/b1";
_requiredNotifications.insert(_root+"/a1/b1");
_skipNotifications.insert(_root + "/a1/b1/new_dir");
QDir dir;
dir.mkdir( _root + "/a1/b1/new_dir");
QVERIFY(QFile::exists(_root + "/a1/b1/new_dir"));
_loop.processEvents();
QVERIFY(_checkMark.isEmpty()); // the slot clears the checkmark.
checkNotifications();
}
void testRemoveADir() {
_checkMark = _root+"/a1/b3";
_requiredNotifications.insert(_root+"/a1/b3");
QDir dir;
QVERIFY(dir.rmdir(_root+"/a1/b3/c3"));
_loop.processEvents();
QVERIFY(_checkMark.isEmpty()); // the slot clears the checkmark.
checkNotifications();
}
void testRemoveAFile() {
_checkMark = _root+"/a1/b2";
_requiredNotifications.insert(_root+"/a1/b2");
QVERIFY(QFile::exists(_root+"/a1/b2/todelete.bin"));
QFile::remove(_root+"/a1/b2/todelete.bin");
QVERIFY(!QFile::exists(_root+"/a1/b2/todelete.bin"));
_loop.processEvents();
QVERIFY(_checkMark.isEmpty()); // the slot clears the checkmark.
checkNotifications();
}
void testRenameAFile() {
_requiredNotifications.insert(_root+"/a2");
QVERIFY(QFile::exists(_root+"/a2/renamefile"));
QFile::rename(_root+"/a2/renamefile", _root+"/a2/renamefile.renamed" );
QVERIFY(QFile::exists(_root+"/a2/renamefile.renamed"));
checkNotifications();
}
void testMoveAFile() {
_checkMark = _root+"/a2";
QVERIFY(QFile::exists(_root+"/a2/movefile"));
QFile::rename(_root+"/a2/movefile", _root+"/a2/movefile.renamed" );
_requiredNotifications.insert(_root+"/a1");
_requiredNotifications.insert(_root+"/a2");
QVERIFY(QFile::exists(_root+"/a1/movefile"));
QFile::rename(_root+"/a1/movefile", _root+"/a2/movefile.renamed" );
QVERIFY(QFile::exists(_root+"/a2/movefile.renamed"));
_loop.processEvents();
QVERIFY(_checkMark.isEmpty()); // the slot clears the checkmark.
checkNotifications();
}
void cleanupTestCase() {

View File

@@ -42,7 +42,7 @@ private slots:
void testOpenDb() {
QFileInfo fi( testdbC );
QVERIFY( !fi.exists() ); // must not exist
_db.open(testdbC);
_db.openOrCreateReadWrite(testdbC);
fi.refresh();
QVERIFY(fi.exists());

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

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

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