Comparar commits

...

209 Commits

Autor SHA1 Mensagem Data
Olivier Goffart a228b8cbb1 Polling: Fix a crash while resuming poll from previous sync
Since last patch, PollJob takes a reference to the SyncItem, assuming that the
item outlive the poll job.  But in case of resume, it was on the stack.

This patch is not needed in the 2.x branche for the same reason the previous
patch was not.
2016-07-11 14:45:17 +02:00
Markus Goetz eb83832d70 Propagator: On remove move, take size from DB
Some servers can claim different sizes for on-the-fly protected/encrypted
MS Office files during discovery.

(cherry picked from commit 9d5307d04c)
2016-03-17 10:38:23 +01:00
Olivier Goffart e4deca4231 PollJob: take a reference to the SyncItem so setting httpErrorCode works
In case of error, we need to update the original SyncFileItem

This patch is not required in 2.x because the SyncFileItem is taken by pointer
2016-01-22 11:29:23 +01:00
Daniel Molkentin a57c017f44 Force linkage against libc++
(cherry picked from commit 1d8c919645)
2015-11-19 17:27:22 +01:00
Olivier Goffart e0e793fb14 User-Agent: put the actual version string in there
It contains the build id in addition
2015-11-05 10:19:43 +01:00
Olivier Goffart 9222db6df9 Never overwrite the size from the db when updating the metadata
the size on the server might be different from the size on the client
with certain backend so it should be ignored.
2015-10-08 09:54:43 +02:00
Olivier Goffart 3fc9bf59d1 PropagateLocalRemove: remove entries from the DB even if there was an error.
Previously, in case of an error while deleting a directory, we would not
remove the entries from the local db, despite most of the files would
be deleted.

Which means that if the files re-appear on the server with the same etag,
we would think the file were deleted from the client and propagate the change.

In 1.8.0 we had this bug that we would not see some directory in the server in
some cases. This would lead us to delete the file on the client.  Normaly the
files are deleted from the local database and next sync would re-download the files.
But in the cases where there was an error deleting one of the file (for example
if it was locked) we would then propagate the delete to the server.

Fix this by always deleting from the database the files that we deleted.

Issue #3206

(cherry picked from commit e54253d845)
2015-09-02 18:59:35 +02:00
Daniel Molkentin dd8c2ba94a Merge pull request #3523 from owncloud/doc-help-button
Add new Help link to docs
2015-08-04 16:59:16 +02:00
Daniel Molkentin 180084da94 win32: libwebp has been bumped to version 5 2015-08-03 19:45:54 +02:00
Jenkins for ownCloud fb79fe1e11 [tx-robot] updated from transifex 2015-08-01 01:15:33 -04:00
Jenkins for ownCloud 2ace075579 [tx-robot] updated from transifex 2015-07-31 02:18:49 -04:00
Jenkins for ownCloud a3fd341dac [tx-robot] updated from transifex 2015-07-31 01:15:32 -04:00
Vincent Petry 65933d5a2e cmd: properly initialize random seed to avoid transferid collisions #3522
(cherry picked from commit 79d895ed9e)
2015-07-30 18:30:13 +02:00
Carla Schroder fbcfef175e Add new Help link to docs 2015-07-30 09:30:12 -07:00
Jenkins for ownCloud 2b085f693d [tx-robot] updated from transifex 2015-07-30 02:18:54 -04:00
Jenkins for ownCloud dc89dc0703 [tx-robot] updated from transifex 2015-07-29 02:18:59 -04:00
Olivier Goffart 4bbf766909 csync: ignore files/folder for which stat fails
instead of pretending it suicceed and not recursing in it.

This fixes a bug in which a folder with a too long name would be properly
created, then removed on the server in the next sync.
2015-07-28 14:38:57 +02:00
Jenkins for ownCloud 31b0553b8f [tx-robot] updated from transifex 2015-07-28 02:18:49 -04:00
Jenkins for ownCloud 2efb4d9d17 [tx-robot] updated from transifex 2015-07-25 02:18:39 -04:00
Jenkins for ownCloud 5eb098b3ca [tx-robot] updated from transifex 2015-07-23 02:18:45 -04:00
Jenkins for ownCloud 518006cba0 [tx-robot] updated from transifex 2015-07-21 02:18:57 -04:00
Jenkins for ownCloud 6a83a65048 [tx-robot] updated from transifex 2015-07-20 02:18:59 -04:00
Jenkins for ownCloud 9e7da1f154 [tx-robot] updated from transifex 2015-07-12 02:18:55 -04:00
Jenkins for ownCloud c5f99f9179 [tx-robot] updated from transifex 2015-07-11 02:18:57 -04:00
Jenkins for ownCloud e4ef04a793 [tx-robot] updated from transifex 2015-07-10 02:19:02 -04:00
Jenkins for ownCloud 02cc76870a [tx-robot] updated from transifex 2015-07-09 02:19:02 -04:00
Jenkins for ownCloud affe2f13ff [tx-robot] updated from transifex 2015-07-07 02:18:57 -04:00
Jenkins for ownCloud 30926c0aa5 [tx-robot] updated from transifex 2015-07-04 02:19:54 -04:00
Jenkins for ownCloud 972aa6d329 [tx-robot] updated from transifex 2015-07-03 02:20:20 -04:00
Christian Kamm d1e0fbeca9 Tray: Show as offline if server is 503. #3392
See also #3200.
2015-07-02 14:35:30 +02:00
Jenkins for ownCloud 64369c7303 [tx-robot] updated from transifex 2015-07-02 02:19:56 -04:00
Olivier Goffart b888242db8 Test for transchecksumvalidator: Do not use arbitrary waiting time
Just stop the loop when we have the result.

This will hopefully fix the jenkins build

(cherry picked from commit d7555cc14e
 and 7332afa171)
2015-06-30 11:32:18 +02:00
Markus Goetz 8f359f339d VERSION.cmake: This branch is for 1.8.4 from now on 2015-06-29 12:34:16 +02:00
Jenkins for ownCloud e88582166c [tx-robot] updated from transifex 2015-06-29 02:20:23 -04:00
Jenkins for ownCloud f0b8066e71 [tx-robot] updated from transifex 2015-06-29 01:15:12 -04:00
Jenkins for ownCloud b362a0a84a [tx-robot] updated from transifex 2015-06-27 01:15:31 -04:00
Olivier Goffart 516509b4ed csync_statedb: fix leak
Spotted by coverity (CID 98061)
2015-06-26 17:01:43 +02:00
Jenkins for ownCloud 13a15a6256 [tx-robot] updated from transifex 2015-06-25 02:18:56 -04:00
Jenkins for ownCloud 678b6affa2 [tx-robot] updated from transifex 2015-06-24 02:18:58 -04:00
Klaas Freitag 1fa5fa91a8 Added removal of *.tmp to Changelog. 2015-06-23 14:31:06 +02:00
Klaas Freitag fc99070b54 Revert "Exclude *.tmp (as requested in #2424 )"
Too many people complained about that the entry can not be removed
if this should be synced. Users that want that one be synced please
add it to the user exclude list.

This reverts commit 5860e5a46b.
2015-06-23 14:08:46 +02:00
Jenkins for ownCloud eca3d48510 [tx-robot] updated from transifex 2015-06-23 02:19:02 -04:00
Daniel Molkentin bf9bb26d19 Bump to 1.8.3 final 2015-06-22 16:28:35 +02:00
Daniel Molkentin 01efba99af Bump to 1.8.3rc3, update ChangeLog 2015-06-22 08:44:29 +02:00
Jenkins for ownCloud 6e469662d3 [tx-robot] updated from transifex 2015-06-22 02:18:53 -04:00
Jenkins for ownCloud 4bc94c17ea [tx-robot] updated from transifex 2015-06-21 02:18:54 -04:00
Jenkins for ownCloud 1820d4018e [tx-robot] updated from transifex 2015-06-20 02:19:01 -04:00
Christian Kamm f130a2716e Update: Check exclusion when reading from db. #3172 2015-06-19 14:58:47 +02:00
Christian Kamm deb5e68e15 Ignores: Force a remote discovery after ignore list change #3172
The problem was that the modified ignore pattern was not applied
to the parts of the remote tree we simply retrieve from the db
because the folder etag didn't change.

Even worse, if one removed an ignore pattern, the un-ignored
files would not be synced correctly.

With this change, a modification to the ignore list always results
in a full remote discovery. This guarantees that we find un-ignored
files.
2015-06-19 14:58:47 +02:00
Jocelyn Turcotte 9a9897ea1e Shibboleth: Let the webview use its own QNAM #3359
Since we periodically recreatet the QNAM owned by the Account,
the web view could end up holding a dangling pointer to it.

Let the web view use its own QNAM, but make sure that the cookie
jars are shared so that we can grab the session token given
by the server.
2015-06-19 12:33:11 +02:00
Jenkins for ownCloud deea902c4f [tx-robot] updated from transifex 2015-06-18 02:18:59 -04:00
Daniel Molkentin 42513af536 Bump to rc2 2015-06-17 17:13:22 +02:00
Jenkins for ownCloud 676a2ff8ca [tx-robot] updated from transifex 2015-06-17 02:18:55 -04:00
Jenkins for ownCloud 1e56349838 [tx-robot] updated from transifex 2015-06-16 02:19:00 -04:00
Jenkins for ownCloud 33b8064042 [tx-robot] updated from transifex 2015-06-15 02:18:42 -04:00
Jenkins for ownCloud 1f5170253c [tx-robot] updated from transifex 2015-06-14 02:18:42 -04:00
Daniel Molkentin ad6f2e03c9 1.8.3-rc1 2015-06-11 15:45:48 +02:00
Daniel Molkentin 4c3daf7927 Update ChangeLog for 1.8.3 2015-06-11 15:04:41 +02:00
Jenkins for ownCloud 4936f70d20 [tx-robot] updated from transifex 2015-06-11 02:18:59 -04:00
Markus Goetz ecd2da185d Update VERSION.cmake for 1.8.3 2015-06-10 17:40:49 +02:00
Jocelyn Turcotte 7a7bf4c561 NSIS: Force an update of the shell_extension #3320
Since our DLLs version number aren't bumped, a same file size could
cause a DLL not to be installed to replace an old one.
This eventually can cause a crash of explorer if an incompatible version
of OCUtil.dll is installed alone.

Fix the issue by defining LIBRARY_IGNORE_VERSION. This also makes sure
that installing an old version of the client over a more recent one
if we decide to add version numbers to those DLLs.
2015-06-10 17:01:08 +02:00
Markus Goetz 827e07700d Documentation: Mention the git submodules 2015-06-10 16:48:34 +02:00
Jenkins for ownCloud d142c554d1 [tx-robot] updated from transifex 2015-06-10 02:18:40 -04:00
Daniel Molkentin 69f2b2da7c Bump version to 1.8.2 final 2015-06-08 14:10:08 +02:00
Daniel Molkentin 4000993200 Finish 1.8.2 ChangeLog 2015-06-08 14:06:57 +02:00
Olivier Goffart 2c6c21d753 AccountState: do not change the state when we stay connected
This would cause a full sync every 30 seconds.
2015-06-08 12:14:37 +02:00
Jenkins for ownCloud 34384e3613 [tx-robot] updated from transifex 2015-06-08 02:18:37 -04:00
Jenkins for ownCloud a42856ef84 [tx-robot] updated from transifex 2015-06-07 02:18:54 -04:00
Jenkins for ownCloud e7f01b9a95 [tx-robot] updated from transifex 2015-06-07 01:15:27 -04:00
Klaas Freitag fc2ceb88fb Rename thread to SyncEngine Thread to avoid confusion about Neon. 2015-06-06 10:49:47 +02:00
Jenkins for ownCloud 36f62f7fd4 [tx-robot] updated from transifex 2015-06-06 02:18:54 -04:00
Christian Kamm ee08b3759d SyncScheduling: Avoid new resyncs on local mkdir.
(cherry picked from commit bacf6166c1)
2015-06-05 10:27:28 +02:00
Klaas Freitag c73110e3c7 Added changes between beta1 and rc1 to Changelog. 2015-06-05 09:39:56 +02:00
Klaas Freitag 9ced5fb9a3 Set version postfix to RC1 2015-06-05 09:26:22 +02:00
Daniel Molkentin f9659d80c9 Revert "NSIS: depend on nsProcess instead of Processes NSIS plugin"
This reverts commit e1a36b53dc.
2015-06-05 09:17:46 +02:00
Daniel Molkentin 553e831121 Revert "Adjust to new version of NSIS UAC"
This reverts commit 1d600ceecc.
2015-06-05 09:17:39 +02:00
Daniel Molkentin e9ff471e1c Revert "NSIS: Star Trek taught me: "Reversing the polarity will fix it". It's true."
This reverts commit 0f7773ff99.
2015-06-05 09:16:14 +02:00
Daniel Molkentin eb6d29a223 Revert "NSIS: Fix NSIS error handling"
This reverts commit 3df26ef189.
2015-06-05 09:15:14 +02:00
Daniel Molkentin 3df26ef189 NSIS: Fix NSIS error handling 2015-06-05 08:45:23 +02:00
Jenkins for ownCloud 25767bee0b [tx-robot] updated from transifex 2015-06-05 02:18:54 -04:00
Daniel Molkentin 0f7773ff99 NSIS: Star Trek taught me: "Reversing the polarity will fix it". It's true. 2015-06-04 12:53:42 +02:00
Christian Kamm 2ed329e025 Improve reporting of server error messages. #3220
In particular the 'unsupported client version' error message
is now visible to the user when trying to connect to a
server that no longer supports the current client version.
2015-06-04 10:07:24 +02:00
Christian Kamm e04882cc7c Discovery: Ignore folders with any 503. #3113 2015-06-04 09:24:53 +02:00
Jenkins for ownCloud 40818920d1 [tx-robot] updated from transifex 2015-06-04 02:18:53 -04:00
Daniel Molkentin 1bec652822 Merge pull request #3303 from owncloud/new_nsis_modules
NSIS installer module updates
2015-06-03 21:05:47 +02:00
Christian Kamm 4c10f1e40c Wizard: Show server error message if possible. #3220 2015-06-03 16:33:09 +02:00
Klaas Freitag 53154bcd1e Merge pull request #3301 from owncloud/fix_3283
Abort the request and reset the QNAM if user does not ACK a new cert.
2015-06-03 10:22:13 +02:00
Daniel Molkentin 1d600ceecc Adjust to new version of NSIS UAC 2015-06-03 08:21:10 +02:00
Daniel Molkentin e1a36b53dc NSIS: depend on nsProcess instead of Processes NSIS plugin
The Processes plugin is no longer maintained, and OBS
compiles an up-to-date version of nsProcess for us.
2015-06-03 08:21:10 +02:00
Jenkins for ownCloud 5f91abd7c6 [tx-robot] updated from transifex 2015-06-03 02:18:34 -04:00
Klaas Freitag 75b38d1a2f Abort the request and reset the QNAM if user does not ACK a new cert.
This is supposed to fix bug #3283
2015-06-02 12:21:49 +02:00
Jenkins for ownCloud 7f597e5dd2 [tx-robot] updated from transifex 2015-06-01 02:18:41 -04:00
Jenkins for ownCloud e3be1a176d [tx-robot] updated from transifex 2015-05-30 02:18:51 -04:00
Daniel Molkentin b1658cb1cf Merge pull request #3291 from RealRancor/backport_3004_2978_1.8
Backport #3004 and #2978 to 1.8
2015-05-28 17:22:06 +02:00
RealRancor 6ba3324035 Backport #3004 and #2978 to 1.8 2015-05-28 17:11:03 +02:00
Daniel Molkentin e2a26f0eaf Merge pull request #3289 from RealRancor/backport_3279_1.8
Backport #3279 to 1.8
2015-05-28 17:03:27 +02:00
RealRancor 8cfb17bca6 Backport #3279 to 1.8 2015-05-28 17:00:59 +02:00
Jenkins for ownCloud 211e5ec82e [tx-robot] updated from transifex 2015-05-28 02:18:51 -04:00
Christian Kamm 2435ba7e7d Windows: Fix unit test build. 2015-05-27 14:59:28 +02:00
Jenkins for ownCloud be77e4f57e [tx-robot] updated from transifex 2015-05-27 02:18:51 -04:00
Jenkins for ownCloud f344b42aa9 [tx-robot] updated from transifex 2015-05-26 02:19:54 -04:00
Jenkins for ownCloud 90f4a20a50 [tx-robot] updated from transifex 2015-05-26 01:15:28 -04:00
Daniel Molkentin 793130a533 Win32: Make Setup/Update Mutex theme-unique (2/2)
Fixes #3272
2015-05-25 21:54:03 +02:00
Vidar Tysse 1ddb162338 Adding Norwegian translation to Client 2015-05-25 21:50:33 +02:00
Daniel Molkentin 070d9d3147 NSIS Installer: Fix Basque, Galician, Slovak, Turkish
Not sure when this broke, but those languages could never have worked...
2015-05-25 21:48:21 +02:00
Daniel Molkentin 9b73308edd NSIS: Add Norwegian (Bokmål) translation 2015-05-25 21:41:23 +02:00
Daniel Molkentin b46a8239e2 NSIS installer tx: Sort/de-whitespace translation file config 2015-05-25 19:45:02 +02:00
Jenkins for ownCloud e9d0f5a022 [tx-robot] updated from transifex 2015-05-25 02:18:46 -04:00
Jenkins for ownCloud 5721d8eb64 [tx-robot] updated from transifex 2015-05-24 02:18:48 -04:00
Daniel Molkentin e708c145fa Win32: Make Setup/Update Mutex theme-unique
Fixes #3272
2015-05-23 09:40:31 +02:00
Jenkins for ownCloud 713beeb2a5 [tx-robot] updated from transifex 2015-05-23 02:18:53 -04:00
Klaas Freitag 6c46713701 include qtconcurrentrun header rather than QtConcurrent for Qt4 2015-05-22 14:46:29 +02:00
Olivier Goffart 3754e6c781 Disable the curruption workaround on mac and windows
The binaries we ship have a patched Qt
2015-05-22 14:19:44 +02:00
Klaas Freitag 6401b1cfc3 Updated Changelog and set version to 1.8.2 beta1 2015-05-22 12:25:40 +02:00
Olivier Goffart 6b9e123816 Merge remote-tracking branch 'origin/checksum_1.8' into 1.8 2015-05-22 10:32:37 +02:00
Olivier Goffart fb2295fcec Merge branch 'recall' into 1.8 2015-05-22 10:32:26 +02:00
Christian Kamm 0af2f7e5ed ConValidator: Always run with new credentials. #3266 2015-05-22 09:38:44 +02:00
Christian Kamm 1c84d01584 Windows: Fix build of tests. 2015-05-22 09:17:24 +02:00
Olivier Goffart 3fcce08a22 recall: move the recall code in a namespace 2015-05-21 16:23:54 +02:00
Olivier Goffart 289800c1ba Recall: make it work even if it is not in the root directory 2015-05-21 16:06:53 +02:00
Olivier Goffart 49fb37fefc t_recall.pl: add a test for the recall feature 2015-05-21 16:06:53 +02:00
Olivier Goffart 9a02a0f3a8 Recall feature: Fix some style issues 2015-05-21 16:06:52 +02:00
Jakub Moscicki 4e79093f84 recall file prototype 2015-05-21 16:06:52 +02:00
Klaas Freitag d2fff2c3e3 Theme: Allow to change the transmission checksum through theming. 2015-05-21 15:59:24 +02:00
Klaas Freitag 8f277e46d6 TransmissionChecksumming: Remove SyncFileItem dependency. 2015-05-21 15:51:48 +02:00
Klaas Freitag c33d962712 TransmissonChecksumValidator: Add documentation. 2015-05-21 14:32:08 +02:00
Klaas Freitag 3870915118 TransmissionChecksumValidator: Reduce verbosity. 2015-05-21 14:31:39 +02:00
Klaas Freitag b05ca526a4 In case of empty checksum type, emit validated. 2015-05-21 14:31:18 +02:00
Klaas Freitag 4e28a24af3 Let checksumType() read the config to destinguish checksum type. 2015-05-21 14:30:21 +02:00
Olivier Goffart aebadfcda2 FolderWizard: Add missing Q_OBJECT which prevent translations from working 2015-05-21 12:53:55 +02:00
Jenkins for ownCloud c975954a9a [tx-robot] updated from transifex 2015-05-21 02:18:50 -04:00
Klaas Freitag dec3bd4a02 Some more minor cleanups based on the pull request review. 2015-05-20 22:44:12 +02:00
Klaas Freitag 64ce0cd7a2 Improved implementation efficiency of checksum calculation.
Based on Oliviers suggestions the file read routine now reuses
one buffer to read the entire file.

Other cleanups.
2015-05-20 21:42:08 +02:00
Klaas Freitag 34593cccb6 Remove QtConcurrent from component list for Qt4.
According to Olivier QtConcurrent was part of QtCore in Qt4.
2015-05-20 17:00:27 +02:00
Klaas Freitag 5b5a636cc1 Make TransmissionChecksumValidator child of the job for auto delete.
That way no explicit memory management is needed as the allocation
is freed when the job (parent) is deleted automatically.
2015-05-20 16:54:04 +02:00
Daniel Molkentin 5c6a6529a6 Merge pull request #3258 from binwiederhier/bugfix/issue3256-mkcol
Add 'Content-Length: 0' header to MKCOL request; fixes #3256
2015-05-20 15:48:33 +02:00
Philipp Heckel 68fa190cf7 Add 'Content-Length: 0' header 2015-05-20 14:40:20 +01:00
Olivier Goffart d148464efe SyncJournalDb::updateErrorBlacklistEntry: lock the mutext at the beginning
The mutex need to be locked before checkConnect, that's what all the other functions are doing
2015-05-20 15:30:19 +02:00
Olivier Goffart 6a7f2089e8 tests: Make them more verbose in case of failures 2015-05-20 14:34:11 +02:00
Klaas Freitag 17fe4c3b29 PropagateUpload: Fix typo in warn message. 2015-05-20 12:30:00 +02:00
Klaas Freitag dd6c97abb6 Propagator: Added a log that tells if transmission checksumming is used. 2015-05-20 12:27:54 +02:00
Klaas Freitag ddfe3fa7ab TransmissionChecksum: Fix identation. 2015-05-20 10:49:18 +02:00
Klaas Freitag 1f7274c2f2 TransmissionChecksum: Removed "pseudo" thread worker functions
Removed the Worker postfix from the method names to reflect their non
threaded character, they moved into a thread in the Validator class.

Thanks ckamm for review.
2015-05-20 10:45:20 +02:00
Klaas Freitag 4d87f30434 Transmission checksum: Adopt unit test to latest changes. 2015-05-19 17:09:40 +02:00
Klaas Freitag 8b371c42b7 Propagate Download: Handle malformed checksum header as error.
Plus some cleanup, bool ok was not needed actually.
2015-05-19 17:09:40 +02:00
Klaas Freitag c7f759fedf Propagator: Use the TransmissionChecksumValidator class. 2015-05-19 17:09:40 +02:00
Klaas Freitag 830daa40d1 Add a class TransmissionChecksumValidator, incl. unit test.
This does all needed to manage checksums that go with http headers
ensuring that the transmission was correct.
2015-05-19 17:09:40 +02:00
Klaas Freitag f016d25b4c Propagate downloads: Handle checksum transmission header.
Read a checksum from the HTTP header, and if its there, compare the
downloaded tmp file against it. In case of corruption, schedule a
redownload.
2015-05-19 17:09:40 +02:00
Klaas Freitag e18fd62f34 Propagator: checksum constants go to propatorjobs header.
So they can be used from both up- and download propagator jobs.
2015-05-19 17:09:40 +02:00
Klaas Freitag 3701fbcbfe PropagateUpload: Add checksum calculation if required by config.
If the config file has an transmissionChecksum entry, a checksum
is added to the PUT requests in a header.
2015-05-19 17:09:39 +02:00
Klaas Freitag 823f9fa0d1 Checksum Calculation: Add unit test. 2015-05-19 17:09:39 +02:00
Klaas Freitag 67d38bc87b Filesystem Utilities: Add Checksum calculation methods. 2015-05-19 17:09:39 +02:00
Klaas Freitag b36ff1ed1d Changelog: Add User Agent string. 2015-05-19 17:09:39 +02:00
Klaas Freitag ec83295b99 Branding: Append the appName short to the user agent string. 2015-05-19 17:09:39 +02:00
Klaas Freitag e36252a845 Theme: (minor) remove some more mirall's 2015-05-19 17:09:39 +02:00
Klaas Freitag d0d8de9f2f MirallConfigFile: Add an option of transmission checksumming. 2015-05-19 17:09:39 +02:00
Daniel Molkentin 9693048f78 Find & use QtConcurrent 2015-05-19 17:09:39 +02:00
Klaas Freitag 101d2268ff SyncFileItem class: Add member _checksum 2015-05-19 17:09:39 +02:00
Klaas Freitag 2fcad760b9 StopWatch: return the duration from the stop() command. 2015-05-19 17:09:39 +02:00
Jenkins for ownCloud 52eb6c95cf [tx-robot] updated from transifex 2015-05-19 02:18:46 -04:00
Jenkins for ownCloud 35169e3de4 [tx-robot] updated from transifex 2015-05-18 02:18:48 -04:00
Jenkins for ownCloud 650b201b33 [tx-robot] updated from transifex 2015-05-16 02:18:48 -04:00
Olivier Goffart f595fc2f9c Fix opening external links for some labels
Issue #3135
2015-05-15 18:44:19 +02:00
Markus Goetz 06c889630c AccountState: Run only a single validator, allow error message overriding #3236 #3153 2015-05-15 12:27:35 +02:00
Jenkins for ownCloud d6dbabfbc4 [tx-robot] updated from transifex 2015-05-15 02:18:51 -04:00
Jenkins for ownCloud bcae146444 [tx-robot] updated from transifex 2015-05-14 02:18:47 -04:00
Markus Goetz 8a39748654 SyncJournalDB: Don't use NULL value
Olivier says we should try to not be the same as the possible value
for not existing entries.
2015-05-13 14:57:14 +02:00
Markus Goetz 3556ed416c SyncJournalDB: Simplify code 2015-05-13 13:15:53 +02:00
Markus Goetz e5e2ce2b22 SyncEngine: Force re-read of folder Etags for upgrades from 1.8.0 and 1.8.1
This is a better fix than the previous one for the local-files-missing bug
because it does not depend on the sync run to run fully through.
2015-05-13 12:54:49 +02:00
Markus Goetz 39d103adf7 OwnSql: Fix numRowsAffected() 2015-05-13 12:54:03 +02:00
Markus Goetz afd1406e61 Update VERSION.cmake to 1.8.2 2015-05-13 12:52:13 +02:00
Jenkins for ownCloud a4c411af99 [tx-robot] updated from transifex 2015-05-13 02:18:48 -04:00
Markus Goetz bcc896fb6e Qt4: Fix test 2015-05-12 22:55:54 +02:00
Olivier Goffart 76166c6252 SyncEngine: Fix comment
A comment should descibe the code, and not a patch.
2015-05-12 17:53:02 +02:00
Olivier Goffart dd5a49bc78 Application: Disable to workaround of QLockFile bug for Qt versions that are fixed 2015-05-12 17:26:32 +02:00
Markus Goetz cdfafa2180 Propagator: Mention name of conflict file (for debugging) 2015-05-12 17:11:21 +02:00
Markus Goetz 6b16e18eb8 tx.pl: Use HTTP Keep-Alive 2015-05-12 17:11:21 +02:00
Olivier Goffart c2dacd03a5 BandwidthManager: fix warnings
Unused variables
2015-05-12 16:35:27 +02:00
Olivier Goffart 505dba5b23 csync walk tree: Try to find the 'other_node' in the source directory in case of renames
This fixes t2.pl
2015-05-12 16:32:00 +02:00
Jenkins for ownCloud af5a7063c9 [tx-robot] updated from transifex 2015-05-12 02:18:49 -04:00
Markus Goetz 9e7779a476 Bandwidth Manager: Comment out qDebug
We have not received any grave bug reports for it, not needed anymore.
2015-05-11 16:07:34 +02:00
Markus Goetz 625e61516f Propagator: Limit length of temporary file name #2789 (fixup)
Fix 22c35c4d15
2015-05-11 15:42:35 +02:00
Klaas Freitag 41614ec851 Application: ifdef lock file issue as it only happens on Qt>5.1
However, the fix breaks Qt4 compile, so it needs to be ifdefed.
Not viel hilft viel.
2015-05-11 13:35:04 +02:00
Jenkins for ownCloud 4d3a0ed250 [tx-robot] updated from transifex 2015-05-11 02:18:44 -04:00
Jenkins for ownCloud cac15988f0 [tx-robot] updated from transifex 2015-05-10 02:18:49 -04:00
Jenkins for ownCloud 1e131f4732 [tx-robot] updated from transifex 2015-05-09 02:18:53 -04:00
Markus Goetz 22c35c4d15 Propagator: Limit length of temporary file name #2789 2015-05-08 16:42:03 +02:00
Christian Kamm 9507bb4be6 ShareDialog: Password ui fixes. #3189
* Change the textedit-empty text to be just "Password"
* Hide the 'Copy link' button when the share isn't created yet
* Show the checked and disabled 'Password required' checkbox
  when a password is required.
2015-05-08 14:53:38 +02:00
Christian Kamm e1c370a9a2 Fix startup hang by removing QSettings lock file. #3175
In some situations the .lock file would stay around and
cause subsequent starts of the client to get stuck before
showing the ui.
2015-05-08 14:02:44 +02:00
Christian Kamm b9eafaaf24 Wizard: Allow SSL cert dialog to show twice. #3168
Normally we never ask twice for the same url, but in the setup wizard
it makes sense to do so.
2015-05-08 12:32:14 +02:00
Christian Kamm 909368025f ProtocolWidget: Fix rename message. #3210
For remote renames that are replicated locally the _file member is
overwritten by the target file name when the new entry is added to
the metadata table. Using _originalFile here guarantees that
the affected local file is mentioned.
2015-05-08 11:33:34 +02:00
Jenkins for ownCloud 15bfa46023 [tx-robot] updated from transifex 2015-05-08 02:18:56 -04:00
Markus Goetz 0359c775e0 Discovery: Test better, treat invalid hrefs as error #3176 2015-05-07 17:19:48 +02:00
Jocelyn Turcotte 1053153ec4 Fix the Qt4 build
Following a6500d8068
Qt4's moc doesn't expand macros and wouldn't evaluate QT_VERSION_CHECK.
2015-05-07 14:49:01 +02:00
Christian Kamm 79ac61684c Propagator: Overwrite local data only if unchanged. #3156 2015-05-07 14:43:33 +02:00
Christian Kamm 441eca86c4 ShareDialog: Improve error reporting for share API fails.
This would have made debugging #3204 and #3136 easier.
2015-05-07 14:16:13 +02:00
Markus Goetz f07d3d069e Updater on OS X: Only allow if in /Applications #2931 2015-05-07 13:04:25 +02:00
Markus Goetz e300e3c744 Wizard: Fix lock icon #1447 2015-05-07 13:04:25 +02:00
Klaas Freitag b9df8290c9 Merge pull request #3208 from owncloud/dev/gcc5
Compile with GCC 5 - thanks for the pr
2015-05-07 09:52:36 +02:00
Christian Kamm 73e2254a80 AccountState: Treat *any* 503 as a temporary error. #3113 2015-05-07 09:21:52 +02:00
Jenkins for ownCloud 352c2957b2 [tx-robot] updated from transifex 2015-05-07 02:18:55 -04:00
Hefee 23b6426dfa Compile with GCC 5
this fixes the error and makes complete oCC compile with GCC 5.
error: ISO C does not support '__FUNCTION__' predefined identifier
[-Wpedantic]

According to the porting guide:
The fix is either to use the standard predefined identifier __func__
(since C99), or to use the __extension__ keyword.
2015-05-07 01:15:55 +02:00
Jocelyn Turcotte 9ef8658122 shell_integration on OSX: Avoid too many RETRIEVE_FILE_STATUS following UPDATE_VIEW #3122
Do not request the status of all entries in the cache. Instead force Finder
to request the ones that it deems necessary by keeping the old statuses
in a separate dictionary which are only used while the new status arrives.
2015-05-06 16:56:50 +02:00
Jocelyn Turcotte 0a67719f2f shell_integration on OSX: Do not fill the cache with unsolicited statuses #3122 2015-05-06 16:56:50 +02:00
Jocelyn Turcotte 04d820f9cf shell_integration on OSX: Remove dead code
removeIcons isn't called and clearFileNameCacheForPath was always
called with a "nil" path.

Remove the return value of askForIcon which was always 0, and use
that value explicitly at the only call site.

Remove the "-1" code path in iconByPath since setIcons prevents
-1 from getting into _fileNamesCache in all cases.
2015-05-06 16:56:50 +02:00
Jocelyn Turcotte 931dd59844 Don't hardcode the source directory in deploy.sh 2015-05-06 16:56:50 +02:00
Jocelyn Turcotte a6500d8068 Work around the Qt PUT corruption bug with Qt < 5.4.2 #2425
Since QNonContiguousByteDeviceThreadForwardImpl::reset will
call UploadDevice::reset with a BlockingQueuedConnection, this
allows us to reset the HTTP channel along with its buffers
before they get the chance to be reused with a subsequent request.
2015-05-06 16:56:50 +02:00
Jocelyn Turcotte 0d5d2c578d shell_integration on Windows: Avoid too many RETRIEVE_FILE_STATUS following UPDATE_VIEW #3122
Do not request the status of all entries in the cache. Instead force
explorer to request the ones that it deems necessary by keeping the old
statuses in a separate dictionary which are only used while the new status
arrives.
2015-05-06 16:48:34 +02:00
Jocelyn Turcotte 77679790db shell_integration on Windows: Don't fill the cache with unsolicited statuses #3122
Only keep the status updates if explorer is going to display it.
2015-05-06 16:48:33 +02:00
131 arquivos alterados com 12183 adições e 6041 exclusões
+1 -1
Ver Arquivo
@@ -165,13 +165,13 @@ endif()
find_package(Sphinx)
find_package(PdfLatex)
find_package(SQLite3 3.8.0 REQUIRED)
# On some OS, we want to use our own, not the system sqlite
if (USE_OUR_OWN_SQLITE3)
include_directories(BEFORE ${SQLITE3_INCLUDE_DIR})
endif()
find_package(ZLIB)
configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+48
Ver Arquivo
@@ -1,5 +1,53 @@
ChangeLog
=========
version 1.8.3 (release 2015-06-23)
* Fix a bug in the Windows Installer that could crash explorer (#3320)
* Reduce 'Connection closed' errors (#3318, #3313, #3298)
* Ignores: Force a remote discovery after ignore list change (#3172)
* Shibboleth: Avoid crash by letting the webview use its own QNAM (#3359)
* System Ignores: Removed *.tmp from system ignore again. If a user
wants to ignore *.tmp, it needs to be added to the user ignore list.
ChangeLog
=========
version 1.8.2 (release 2015-06-08)
* Improve reporting of server error messages (#3220)
* Discovery: Ignore folders with any 503 (#3113)
* Wizard: Show server error message if possible (#3220)
* QNAM: Fix handling of mitm cert changes (#3283)
* Win32: Installer translations added (#3277)
* Win32: Allow concurrent OEM (un-)installers (#3272)
* Win32: Make Setup/Update Mutex theme-unique (#3272)
* HTTP: Add the branding name to the UserAgent string
* ConnectonValidator: Always run with new credentials (#3266)
* Recall Feature: Admins can trigger an upload of a file from
client to server again (#3246)
* Propagator: Add 'Content-Length: 0' header to MKCOL request (#3256)
* Switch on checksum verification through branding or config
* Add ability for checksum verification of up and download
* Fix opening external links for some labels (#3135)
* AccountState: Run only a single validator, allow error message
overriding (#3236, #3153)
* SyncJournalDB: Minor fixes and simplificatons
* SyncEngine: Force re-read of folder Etags for upgrades from
1.8.0 and 1.8.1
* Propagator: Limit length of temporary file name (#2789)
* ShareDialog: Password ui fixes (#3189)
* Fix startup hang by removing QSettings lock file (#3175)
* Wizard: Allow SSL cert dialog to show twice (#3168)
* ProtocolWidget: Fix rename message (#3210)
* Discovery: Test better, treat invalid hrefs as error (#3176)
* Propagator: Overwrite local data only if unchanged (#3156)
* ShareDialog: Improve error reporting for share API fails
* OSX Updater: Only allow updates only if in /Applications (#2931)
* Wizard: Fix lock icon (#1447)
* Fix compilation with GCC 5
* Treat any 503 error as temporary (#3113)
* Work around for the Qt PUT corruption bug (#2425)
* OSX Shell integration: Optimizations
* Windows Shell integration: Optimizations
.. more than 250 commits since 1.8.1
version 1.8.1 (release 2015-05-07)
* Make "operation canceled" error a soft error
* Do not throw an error for files that are scheduled to be removed,
+1 -1
Ver Arquivo
@@ -1,6 +1,6 @@
set( MIRALL_VERSION_MAJOR 1 )
set( MIRALL_VERSION_MINOR 8 )
set( MIRALL_VERSION_PATCH 1 )
set( MIRALL_VERSION_PATCH 4 )
set( MIRALL_SOVERSION 0 )
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
+24 -24
Ver Arquivo
@@ -10,24 +10,25 @@ minimum_perc = 5
# simple one-to-one language mappings
trans.ca = pofiles/ca.po
trans.el = pofiles/el.po
trans.es = pofiles/es.po
trans.es_AR = pofiles/es_AR.po
trans.eu = pofiles/eu.po
trans.fa = pofiles/fa.po
trans.fr = pofiles/fr.po
trans.gl = pofiles/gl.po
trans.it = pofiles/it.po
trans.nl = pofiles/nl.po
trans.pl = pofiles/pl.po
trans.pt_BR = pofiles/pt_BR.po
trans.ru = pofiles/ru.po
trans.el = pofiles/el.po
trans.es_AR = pofiles/es_AR.po
trans.es = pofiles/es.po
trans.eu = pofiles/eu.po
trans.fa = pofiles/fa.po
trans.fr = pofiles/fr.po
trans.gl = pofiles/gl.po
trans.it = pofiles/it.po
trans.nb_NO = pofiles/nb_NO.po
trans.nl = pofiles/nl.po
trans.pl = pofiles/pl.po
trans.pt_BR = pofiles/pt_BR.po
trans.ru = pofiles/ru.po
trans.sl = pofiles/sl.po
trans.sv = pofiles/sv.po
trans.tr = pofiles/tr.po
trans.uk = pofiles/uk.po
trans.zh_TW = pofiles/zh_TW.po
trans.zh_CN = pofiles/zh_CN.po
trans.uk = pofiles/uk.po
trans.zh_CN = pofiles/zh_CN.po
trans.zh_TW = pofiles/zh_TW.po
# special handling below
@@ -35,14 +36,13 @@ trans.zh_CN = pofiles/zh_CN.po
trans.de_DE = pofiles/de.po
# choose one of the given translations on transifex as default
trans.pt_PT = pofiles/pt.po
trans.pt_PT = pofiles/pt.po
# choose a special language as more generic default
trans.cs_CZ = pofiles/cs.po
trans.et_EE = pofiles/et.po
trans.fi_FI = pofiles/fi.po
trans.ja_JP = pofiles/ja.po
trans.hu_HU = pofiles/hu.po
trans.sk_SK = pofiles/sk.po
trans.th_TH = pofiles/th.po
trans.cs_CZ = pofiles/cs.po
trans.et_EE = pofiles/et.po
trans.fi_FI = pofiles/fi.po
trans.hu_HU = pofiles/hu.po
trans.ja_JP = pofiles/ja.po
trans.sk_SK = pofiles/sk.po
trans.th_TH = pofiles/th.po
+11 -11
Ver Arquivo
@@ -15,16 +15,18 @@ StrCpy $PageReinstall_SAME_Field_3 "Desinstalli ${APPLICATION_NAME}"
StrCpy $UNINSTALLER_APPDATA_TITLE "Desinstalli ${APPLICATION_NAME}"
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Vali hooldustegevus, mida sa soovid sooritada."
StrCpy $SEC_APPLICATION_DETAILS "Paigaldan ${APPLICATION_NAME} põhiosa."
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Start Menüü Programmide viit"
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Lisan ${APPLICATION_NAME} viida Start menüüsse."
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Integreerimine Windows Exploreriga"
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Paigalda Windows Exploreriga integreerimine"
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Start Menüü programmide otsetee"
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Lisan ${APPLICATION_NAME} otsetee Start menüüsse."
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Töölaua otsetee"
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "Töölaua otseteede loomine"
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Kiirvaliku nupp"
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Kiirvaliku nupu loomine"
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Kiirvaliku otsetee"
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Kiirvaliku otsetee loomine"
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} põhiosa."
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "${APPLICATION_NAME} otsetee."
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Töölaua viit rakendusele ${APPLICATION_NAME}."
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Kiirvaliku viit rakendusele ${APPLICATION_NAME}."
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Töölaua otsetee rakendusele ${APPLICATION_NAME}."
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Kiirvaliku otsetee rakendusele ${APPLICATION_NAME}."
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Eemalda arvutist rakenduse ${APPLICATION_NAME} andmete kataloog."
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "Kas soovid kustutada ${APPLICATION_NAME} andmete kataloogi?"
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Jäta märkimata säilitamaks andmete kataloog hilisemaks kasutuseks või märgi andmete kataloogi kustutamiseks."
@@ -34,13 +36,11 @@ StrCpy $UNINSTALLER_REGISTRY_Detail "Kirjutan paigaldaja registri v
StrCpy $UNINSTALLER_FINISHED_Detail "Lõpetatud"
StrCpy $UNINSTALL_MESSAGEBOX "Ei leia, et ${APPLICATION_NAME} oleks paigaldatud kataloogi '$INSTDIR'.$\n$\nJätkata sellele vaatamata (pole soovitav)?"
StrCpy $UNINSTALL_ABORT "Desinstallimine on kasutaja poolt katkestatud"
StrCpy $INIT_NO_QUICK_LAUNCH "Kiirvaliku viit (N/A)"
StrCpy $INIT_NO_QUICK_LAUNCH "Kiirvaliku otsetee (N/A)"
StrCpy $INIT_NO_DESKTOP "Ikoon töölaual (kirjutab olemasoleva üle)"
StrCpy $UAC_ERROR_ELEVATE "Ei suuda ülendada õigusi, viga: "
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "See paigaldaja vajab admini ligipääsu, proovi uuesti"
StrCpy $INIT_INSTALLER_RUNNING "Paigaldaja on juba käimas."
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "See desinstallija vajab admini ligipääsu, proovi uuesti"
StrCpy $INIT_UNINSTALLER_RUNNING "See desinstallija on juba käimas"
StrCpy $SectionGroup_Shortcuts "Viidad"
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Integration for Windows Explorer"
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing Integration for Windows Explorer"
StrCpy $INIT_UNINSTALLER_RUNNING "See desinstallija on juba käimas."
StrCpy $SectionGroup_Shortcuts "Otseteed"
+17 -17
Ver Arquivo
@@ -1,22 +1,38 @@
# Auto-generated - do not modify
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "نمایش پادداشت های انتشار نسخه"
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "پردازش برای از بین بردن یافت نشد!"
StrCpy $PageReinstall_NEW_Field_2 "عمل حذف را قبل از نصب انجام دهید"
StrCpy $PageReinstall_NEW_Field_3 "حذف نکن"
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "از قبل نصب شده است"
StrCpy $PageReinstall_SAME_Field_2 "افزودن/نصب مجدد اجزا"
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "بازکردن میانبر منو برنامه"
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "افزودن میانبر ${APPLICATION_NAME} به استارت منو ."
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "میانبر دسکتاپ"
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "ایجاد میانبر دسکتاپ"
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "میانبر بازکردن سریع"
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "ایجاد میانبر اجرای سریع"
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "ملزومات ${APPLICATION_NAME}"
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "میانبر ${APPLICATION_NAME} "
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "میانبر دسکتاپ برای ${APPLICATION_NAME} ."
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "میانبر اجرای سریع برای ${APPLICATION_NAME}"
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "حذف پوشه ی data نرم افزار ${APPLICATION_NAME} از روی سیستم شما ."
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "آیا می خواهید پوشه ی data نرم افزار ${APPLICATION_NAME} را حذف نمایید ؟"
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "بله، این پوشه داده را حذف کن."
StrCpy $UNINSTALLER_FILE_Detail "نوشتن حذف کننده"
StrCpy $UNINSTALLER_REGISTRY_Detail "در حال نوشتن کلید های رجیستری نصاب"
StrCpy $UNINSTALLER_FINISHED_Detail "اتمام"
StrCpy $UNINSTALL_MESSAGEBOX "به نظر نمی رسد نرم افزار ${APPLICATION_NAME} در '$INSTDIR'.$\n$\nنصب شده باشد.\nآیا می خواهید ادامه دهید ( توصیه نشده است ) ؟"
StrCpy $UNINSTALL_ABORT "عمل حذف توسط کاربر متوقف شد"
StrCpy $INIT_NO_QUICK_LAUNCH "میانبر بازکردن سریع ( N/A )"
StrCpy $INIT_NO_DESKTOP "میانبر دسکتاپ (رونویسی وجود دارد)"
StrCpy $UAC_ERROR_ELEVATE "مشکل در بالااوردن ، خطا : "
StrCpy $INIT_INSTALLER_RUNNING "نصاب از قبل در حال اجراست."
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "حذف برنامه نیاز به دسترسی مدیر دارد ، لطفا دوباره سعی کنید"
StrCpy $INIT_UNINSTALLER_RUNNING "حذف کننده از قبل در حال اجراست."
StrCpy $SectionGroup_Shortcuts "میانبرها"
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Found ${APPLICATION_EXECUTABLE} process(s) which need to be stopped.$\nDo you want the installer to stop these for you?"
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Killing ${APPLICATION_EXECUTABLE} processes."
StrCpy $PageReinstall_NEW_Field_1 "An older version of ${APPLICATION_NAME} is installed on your system. It is recommended that you uninstall the current version before installing. Select the operation you want to perform and click Next to continue."
StrCpy $PageReinstall_NEW_Field_2 "Uninstall before installing"
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Choose how you want to install ${APPLICATION_NAME}."
StrCpy $PageReinstall_OLD_Field_1 "A newer version of ${APPLICATION_NAME} is already installed! It is not recommended that you install an older version. If you really want to install this older version, it is better to uninstall the current version first. Select the operation you want to perform and click Next to continue."
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.\r\nSelect the operation you want to perform and click Next to continue."
@@ -26,21 +42,5 @@ StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Choose the maintenance opti
StrCpy $SEC_APPLICATION_DETAILS "Installing ${APPLICATION_NAME} essentials."
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Integration for Windows Explorer"
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing Integration for Windows Explorer"
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Start Menu Program Shortcut"
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Adding shortcut for ${APPLICATION_NAME} to the Start Menu."
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Creating Quick Launch Shortcut"
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} essentials."
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "${APPLICATION_NAME} shortcut."
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Desktop shortcut for ${APPLICATION_NAME}."
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Quick Launch shortcut for ${APPLICATION_NAME}."
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Remove ${APPLICATION_NAME}'s data folder from your computer."
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "Do you want to delete ${APPLICATION_NAME}'s data folder?"
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Leave unchecked to keep the data folder for later use or check to delete the data folder."
StrCpy $UNINSTALLER_REGISTRY_Detail "Writing Installer Registry Keys"
StrCpy $UNINSTALL_MESSAGEBOX "It does not appear that ${APPLICATION_NAME} is installed in the directory '$INSTDIR'.$\r$\nContinue anyway (not recommended)?"
StrCpy $UNINSTALL_ABORT "Uninstall aborted by user"
StrCpy $INIT_NO_QUICK_LAUNCH "Quick Launch Shortcut (N/A)"
StrCpy $INIT_NO_DESKTOP "Desktop Shortcut (overwrites existing)"
StrCpy $UAC_ERROR_ELEVATE "Unable to elevate, error:"
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "This installer requires admin access, try again"
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "This uninstaller requires admin access, try again"
+28 -28
Ver Arquivo
@@ -1,46 +1,46 @@
# Auto-generated - do not modify
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Kiadási jegyzetek megtekintése"
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "A következő folyamatot(okat) meg kell állítani ${APPLICATION_EXECUTABLE}.$\nSzeretné ha a telepítő program megállítani ezeket a folyamatokat?"
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Folyamat ${APPLICATION_EXECUTABLE} kilövése."
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Kilövésre szánt folyamat nem található."
StrCpy $PageReinstall_NEW_Field_1 "Az ${APPLICATION_NAME} alkalmazás egy régebbi verziója telepítva van a rendszeren. Ajánlott a régi alkalmazás eltávolítása mielőtt a legfrissebb verziót telepítané. Válassza ki milyen műveletet szeretne végrehajtani, és nyomja meg a $\"Következő$\" gombot a folytatáshoz."
StrCpy $PageReinstall_NEW_Field_2 "Eltávolítás telepítés előtt"
StrCpy $PageReinstall_NEW_Field_3 "Ne távolítsa el"
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Már telepítve"
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Válaszd ki, hogy szeretnéd telepíteni a következő alkalmazást ${APPLICATION_NAME}."
StrCpy $PageReinstall_OLD_Field_1 "Az ${APPLICATION_NAME} alklamazás egy újabb verziója már megtalálható a rendszeren. Nem ajánlott egy régebbi verzió telepítése. Ha valóban szeretné a régebbi verziót telepíteni, akkor ajánlott a jelenleg telepített verzió eltávolítása. Válassza ki milyen műveletet szeretne végrehajtani, és nyomja meg a $\"Következő$\" gombot a folytatáshoz."
StrCpy $PageReinstall_SAME_Field_1 "Az ${APPLICATION_NAME} alkalmazás ${VERSION} verziója már telepítve van.\nKérem válassza ki milyen műveletet szeretne végrehajtan, és nyomja meg a $\"Következő$\" gombot."
StrCpy $PageReinstall_SAME_Field_2 "Komponens hozzáadása/újratelepítése"
StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} eltávolítása"
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} eltávolítása"
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Kérem válassza ki milyen karbantartási műveletet szeretne elvégezni?"
StrCpy $SEC_APPLICATION_DETAILS "Az ${APPLICATION_NAME} alkalmazás lényeges komponenseinek telepítése."
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Windows Explorer Integráció"
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Windows Explorer Integráció Telepítése"
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Start Menü Parancsikonok"
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "A ${APPLICATION_NAME} parancsikon hozzáadása a Start Menühöz"
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Asztali Parancsikon"
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "Asztali Parancsikon Létrehozása"
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Gyorsindítás Eszköztár Parancsikon"
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Gyorsindítás Eszköztár Parancsikon Létrehozása"
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} lényeges komponensek."
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "${APPLICATION_NAME} parancsikon"
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Asztali parancsikon a ${APPLICATION_NAME} alkalmazásnak."
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Gyorsindítás eszköztár parancsikon a ${APPLICATION_NAME} alkalmazásnak."
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Az ${APPLICATION_NAME} alkalmazás adatkönyvtárának eltávolítása a számítógépről."
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "El szeretné távolítani az ${APPLICATION_NAME} alkalmazás adatkönyvtárát?"
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Hagyja bejelelöletlenül, hogy megtartsa az adatkönyvtárat későbbi használatra, vagy jelölje be az adatkönyvtár törléséhez."
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "Igen, törölje ezt az adatkönyvtárat."
StrCpy $UNINSTALLER_FILE_Detail "Program Eltávolító Írása"
StrCpy $UNINSTALLER_REGISTRY_Detail "Telepítési registry kulcsok írása"
StrCpy $UNINSTALLER_FINISHED_Detail "Befejezve"
StrCpy $UNINSTALL_MESSAGEBOX "Nem sikerült az ${APPLICATION_NAME} alkalmazás telepítése a '$INSTDIR' könyvtárba.$\n$\nSzeretné mindenképpen folytatni (nem ajánlott)?"
StrCpy $UNINSTALL_ABORT "Az eltávolítást egy felhasználó megszakította"
StrCpy $INIT_NO_QUICK_LAUNCH "Gyorsindító Hivatkozás (N/A)"
StrCpy $INIT_NO_DESKTOP "Asztali Hivatkozás (felülírja a meglévőt)"
StrCpy $UAC_ERROR_ELEVATE "Nem sikerült felemelni, hiba:"
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "A telepítő futtatásához adminisztrátori hozzáférés szükséges, próbáld újra."
StrCpy $INIT_INSTALLER_RUNNING "A telepítő már fut."
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Az eltávolító futtatásához adminisztrátori hozzáférés szükséges, próbáld újra."
StrCpy $INIT_UNINSTALLER_RUNNING "Az eltávolító már fut."
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Found ${APPLICATION_EXECUTABLE} process(s) which need to be stopped.$\nDo you want the installer to stop these for you?"
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Killing ${APPLICATION_EXECUTABLE} processes."
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Process to kill not found!"
StrCpy $PageReinstall_NEW_Field_1 "An older version of ${APPLICATION_NAME} is installed on your system. It is recommended that you uninstall the current version before installing. Select the operation you want to perform and click Next to continue."
StrCpy $PageReinstall_OLD_Field_1 "A newer version of ${APPLICATION_NAME} is already installed! It is not recommended that you install an older version. If you really want to install this older version, it is better to uninstall the current version first. Select the operation you want to perform and click Next to continue."
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.\r\nSelect the operation you want to perform and click Next to continue."
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Choose the maintenance option to perform."
StrCpy $SEC_APPLICATION_DETAILS "Installing ${APPLICATION_NAME} essentials."
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Integration for Windows Explorer"
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing Integration for Windows Explorer"
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Start Menu Program Shortcut"
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Adding shortcut for ${APPLICATION_NAME} to the Start Menu."
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Desktop Shortcut"
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "Creating Desktop Shortcuts"
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Quick Launch Shortcut"
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Creating Quick Launch Shortcut"
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} essentials."
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "${APPLICATION_NAME} shortcut."
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Desktop shortcut for ${APPLICATION_NAME}."
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Quick Launch shortcut for ${APPLICATION_NAME}."
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Remove ${APPLICATION_NAME}'s data folder from your computer."
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "Do you want to delete ${APPLICATION_NAME}'s data folder?"
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Leave unchecked to keep the data folder for later use or check to delete the data folder."
StrCpy $UNINSTALLER_FILE_Detail "Writing Uninstaller"
StrCpy $UNINSTALLER_REGISTRY_Detail "Writing Installer Registry Keys"
StrCpy $UNINSTALL_MESSAGEBOX "It does not appear that ${APPLICATION_NAME} is installed in the directory '$INSTDIR'.$\r$\nContinue anyway (not recommended)?"
StrCpy $UAC_ERROR_ELEVATE "Unable to elevate, error:"
StrCpy $SectionGroup_Shortcuts "Shortcuts"
StrCpy $SectionGroup_Shortcuts "Parancsikonok"
+1 -1
Ver Arquivo
@@ -1,6 +1,6 @@
# Auto-generated - do not modify
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "リリースノートを表示"
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "${APPLICATION_EXECUTABLE} のプロセスを終了する必要があります。\nインストーラーがそのプロセスを停止してもよろしいですか?"
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "${APPLICATION_EXECUTABLE} のプロセスを終了する必要があります。$\nインストーラーがそのプロセスを停止してもよろしいですか?"
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "${APPLICATION_EXECUTABLE} プロセスを停止しています。"
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "終了するプロセスがありません"
StrCpy $PageReinstall_NEW_Field_1 "システムに ${APPLICATION_NAME} の旧バージョンがインストールされています。\n旧バージョンをアンインストールし、最新バージョンをインストールするのをお勧めします。\nオペレーションを選択し、次へをクリックする。"
+46
Ver Arquivo
@@ -0,0 +1,46 @@
# Auto-generated - do not modify
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Vis versjonsmerknader"
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Fant ${APPLICATION_EXECUTABLE}-prosess(er) som må stoppes.$\nVil du at installasjonsprogrammet skal stoppe dem for deg?"
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Terminerer ${APPLICATION_EXECUTABLE}-prosesser."
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Fant ikke prosess som skulle termineres!"
StrCpy $PageReinstall_NEW_Field_1 "En eldre versjon av ${APPLICATION_NAME} er installert på systemet ditt. Det anbefales at du avnistallerer den versjonen før installering av ny versjon. Velg hva du vil gjøre og klikk Neste for å fortsette."
StrCpy $PageReinstall_NEW_Field_2 "Avinstaller før installering"
StrCpy $PageReinstall_NEW_Field_3 "Ikke avinstaller"
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Allerede installert"
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Velg hvordan du vil installere ${APPLICATION_NAME}."
StrCpy $PageReinstall_OLD_Field_1 "En nyere versjon av ${APPLICATION_NAME} er allerede installert! Det anbefales ikke at du installerer en eldre versjon. Hvis du virkelig ønsker å installere denne eldre versjonen, er det bedre å avinstallere gjeldende versjon først. Velg hva du vil gjøre og klikk Neste for å fortsette."
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} er allerede installert.\nVelg hva du vil gjøre og klikk Neste for å fortsette."
StrCpy $PageReinstall_SAME_Field_2 "Legg til/installer komponenter på nytt"
StrCpy $PageReinstall_SAME_Field_3 "Avinstaller ${APPLICATION_NAME}"
StrCpy $UNINSTALLER_APPDATA_TITLE "Avinstaller ${APPLICATION_NAME}"
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Velg hva slags vedlikehold som skal utføres."
StrCpy $SEC_APPLICATION_DETAILS "Installerer ${APPLICATION_NAME} grunnleggende."
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Integrering med Windows Utforsker"
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installerer integrering med Windows Utforsker"
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Snarvei i Start-menyen"
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Legger til snarvei for ${APPLICATION_NAME} i Start-menyen."
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Snarvei på skrivebordet"
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "Oppretter snarveier på skrivebordet"
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Snarvei i Hurtigstart"
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Oppretter snarvei i Hurtigstart"
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} grunnleggende."
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "${APPLICATION_NAME}-snarvei."
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Skrivebordssnarvei for ${APPLICATION_NAME}."
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Hurtigstart-snarvei for ${APPLICATION_NAME}."
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Fjern ${APPLICATION_NAME} sin datamappe fra datamaskinen."
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "Ønsker du å slette ${APPLICATION_NAME} sin datamappe?"
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Ikke kryss av dersom du vil beholde datamappen for senere bruk. Kryss av for å slette mappen."
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "Ja, slett denne datamappen."
StrCpy $UNINSTALLER_FILE_Detail "Skriver Avinstallasjonsprogram."
StrCpy $UNINSTALLER_REGISTRY_Detail "Skriver registernøkler for installasjonsprogrammet"
StrCpy $UNINSTALLER_FINISHED_Detail "Ferdig"
StrCpy $UNINSTALL_MESSAGEBOX "Det ser ikke ut som ${APPLICATION_NAME} er installert i mappe '$INSTDIR'.$\n$\nFortsett likevel (ikke anbefalt)?"
StrCpy $UNINSTALL_ABORT "Avinstallering avbrutt av bruker"
StrCpy $INIT_NO_QUICK_LAUNCH "Hurtigstart-snarvei (I/T)"
StrCpy $INIT_NO_DESKTOP "Snarvei på skrivebordet (skriver over eksisterende)"
StrCpy $UAC_ERROR_ELEVATE "Klarte ikke å heve tilgangsnivå. Feil: "
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Dette installasjonsprogrammet krever administrasjonstilgang. Prøv igjen"
StrCpy $INIT_INSTALLER_RUNNING "Installasjonsprogrammet kjører allerede."
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Avinstallasjonsprogrammet krever administrasjonstilgang. Prøv igjen"
StrCpy $INIT_UNINSTALLER_RUNNING "Avinstallasjonsprogrammet kjører allerede."
StrCpy $SectionGroup_Shortcuts "Snarveier"
+46
Ver Arquivo
@@ -0,0 +1,46 @@
# Auto-generated - do not modify
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "แสดงบันทึกประจำรุ่น"
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "พบว่ากระบวนการ ${APPLICATION_EXECUTABLE} จะต้องหยุดทำงาน\nคุณต้องการติดตั้งเพื่อหยุดการทำงานเหล่านี้ของคุณ?"
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "ฆ่ากระบวนการทำงาน ${APPLICATION_EXECUTABLE}"
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "ไม่พบการฆ่ากระบวนการ!"
StrCpy $PageReinstall_NEW_Field_1 "รุ่นเก่าของ ${APPLICATION_NAME} มีการติดตั้งในระบบของคุณ ขอแนะนำให้คุณถอนการติดตั้งรุ่นปัจจุบันออกก่อน เลือกการดำเนินการที่คุณต้องการที่จะดำเนินการและคลิกถัดไปเพื่อดำเนินการต่อ"
StrCpy $PageReinstall_NEW_Field_2 "ถอนการติดตั้งก่อนการติดตั้ง"
StrCpy $PageReinstall_NEW_Field_3 "อย่าถอนการติดตั้ง"
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "ติดตั้งแล้ว"
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "เลือกวิธีที่คุณต้องการติดตั้ง ${APPLICATION_NAME}"
StrCpy $PageReinstall_OLD_Field_1 "รุ่นใหม่ของ ${APPLICATION_NAME} ถูกติดตั้งแล้ว! เราไม่แนะนำให้คุณติดตั้งรุ่นเก่า ถ้าคุณอยากจะติดตั้งรุ่นเก่าก็สามารถสอนการติดตั้งได้"
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} ได้ถูกติดตั้งแล้ว เลือกการดำเนินการที่คุณต้องการที่จะดำเนินการและคลิกถัดไปเพื่อดำเนินการต่อ"
StrCpy $PageReinstall_SAME_Field_2 "ส่วนประกอบ เพิ่ม/ติดตั้งใหม่ "
StrCpy $PageReinstall_SAME_Field_3 "ถอนการติดตั้ง ${APPLICATION_NAME}"
StrCpy $UNINSTALLER_APPDATA_TITLE "ถอนการติดตั้ง ${APPLICATION_NAME}"
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "เลือกตัวเลือกการบำรุงรักษาเพื่อดำเนินการ"
StrCpy $SEC_APPLICATION_DETAILS "กำลังติดตั้งข้อมูลที่เป็นเป็นของ ${APPLICATION_NAME}"
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "บูรณาการสำหรับ Windows Explorer"
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "บูรณาการกำลังติดตั้งสำหรับ Windows Explorer"
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "โปรแกรมทางลัดเมนูเริ่มต้น"
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "เพิ่มทางลัดสำหรับ ${APPLICATION_NAME} ที่เมนูเริ่มต้น"
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "ทางลัดพื้นโต๊ะ"
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "สร้างทางลัดบนเดสก์ทอป"
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "ทางลัดเร่งด่วน"
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "สร้างทางลัดเร่งด่วน"
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} ที่จำเป็น"
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "ทางลัด ${APPLICATION_NAME}"
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "ทางลัดบนเดสก์ทอปสำหรับ ${APPLICATION_NAME}"
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "ทางลัดเร่งด่วนสำหรับ ${APPLICATION_NAME}"
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "ลบ ${APPLICATION_NAME} ของโฟลเดอร์ข้อมูลจากคอมพิวเตอร์ของคุณ"
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "คุณต้องการลบ ${APPLICATION_NAME} ของโฟลเดอร์ข้อมูล?"
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "ปล่อยให้ตรวจสอบสำหรับใช้โฟลเดอร์ข้อมูลในภายหลังหรือตรวจสอบเพื่อลบโฟลเดอร์ข้อมูล"
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "ใช่ลบโฟลเดอร์ข้อมูลนี้"
StrCpy $UNINSTALLER_FILE_Detail "กำลังถอนการติดตั้ง"
StrCpy $UNINSTALLER_REGISTRY_Detail "กำลังติดตั้งรหัสรีจิสทรี"
StrCpy $UNINSTALLER_FINISHED_Detail "เสร็จสิ้น"
StrCpy $UNINSTALL_MESSAGEBOX "มันจะไม่ปรากฏ ${APPLICATION_NAME} ที่มีการติดตั้งในไดเรกทอรี '$INSTDIR' ดำเนินการต่อไป (ไม่แนะนำ)?"
StrCpy $UNINSTALL_ABORT "ถอนการติดตั้งถูกยกเลิกโดยผู้ใช้"
StrCpy $INIT_NO_QUICK_LAUNCH "ทางลัดเร่งด่วน (N/A)"
StrCpy $INIT_NO_DESKTOP "ทางลัดเดสก์ทอป (จะเขียนทับหากมีอยู่แล้ว)"
StrCpy $UAC_ERROR_ELEVATE "ไม่สามารถที่จะยกระดับข้อผิดพลาด:"
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "การติดตั้งนี้จะต้องมีการเข้าถึงผู้ดูแลระบบ กรุณาลองอีกครั้ง"
StrCpy $INIT_INSTALLER_RUNNING "กำลังทำการติดตั้ง"
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "การถอนการติดตั้งนี้จะต้องมีการเข้าถึงส่วนผู้ดูแลระบบ กรุณาลองอีกครั้ง"
StrCpy $INIT_UNINSTALLER_RUNNING "กำลังทำการถอนการติดตั้ง"
StrCpy $SectionGroup_Shortcuts "ทางลัด"
+1 -1
Ver Arquivo
@@ -67,7 +67,7 @@ localeToName = {
"mg" : "Malagasy",
"ms" : "Malay",
"mn" : "Mongolian",
"nb" : "Norwegian",
"nb_NO" : "Norwegian",
"nn" : "NorwegianNynorsk",
"ps" : "Pashto",
"pl" : "Polish",
+1
Ver Arquivo
@@ -44,5 +44,6 @@ iconv -t CP1252 -o Finnish.nsh Finnish.nsh
iconv -t CP932 -o Japanese.nsh Japanese.nsh
iconv -t CP1250 -o Slovak.nsh Slovak.nsh
iconv -t CP1254 -o Turkish.nsh Turkish.nsh
iconv -t CP1252 -o Norwegian.nsh Norwegian.nsh
+3 -1
Ver Arquivo
@@ -8,13 +8,15 @@
!insertmacro MUI_LANGUAGE "Hungarian"
!insertmacro MUI_LANGUAGE "Ukrainian"
!insertmacro MUI_LANGUAGE "French"
!insertmacro MUI_LANGUAGE "Catalan"
!insertmacro MUI_LANGUAGE "Norwegian"
!insertmacro MUI_LANGUAGE "Russian"
!insertmacro MUI_LANGUAGE "Thai"
!insertmacro MUI_LANGUAGE "Finnish"
!insertmacro MUI_LANGUAGE "Basque"
!insertmacro MUI_LANGUAGE "Greek"
!insertmacro MUI_LANGUAGE "SimpChinese"
!insertmacro MUI_LANGUAGE "PortugueseBR"
!insertmacro MUI_LANGUAGE "Catalan"
!insertmacro MUI_LANGUAGE "Italian"
!insertmacro MUI_LANGUAGE "Portuguese"
!insertmacro MUI_LANGUAGE "German"
+1 -1
Submodule binary updated: 1fb9ddfa9a...8b72648a93
+15 -7
Ver Arquivo
@@ -175,10 +175,11 @@ VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "${VERSION}"
StrCmp $LANGUAGE ${LANG_ITALIAN} Italian 0
StrCmp $LANGUAGE ${LANG_ESTONIAN} Estonian 0
StrCmp $LANGUAGE ${LANG_GREEK} Greek 0
StrCmp $LANGUAGE ${LANG_GREEK} Basque 0
StrCmp $LANGUAGE ${LANG_GREEK} Galician 0
StrCmp $LANGUAGE ${LANG_GREEK} Slovak 0
StrCmp $LANGUAGE ${LANG_GREEK} Turkish 0
StrCmp $LANGUAGE ${LANG_BASQUE} Basque 0
StrCmp $LANGUAGE ${LANG_GALICIAN} Galician 0
StrCmp $LANGUAGE ${LANG_SLOVAC} Slovak 0
StrCmp $LANGUAGE ${LANG_TURKISH} Turkish 0
StrCmp $LANGUAGE ${LANG_NORWEGIAN} Norwegian 0
StrCmp $LANGUAGE ${LANG_PORTUGUESEBR} Brazilian EndLanguageCmp
German:
!include "${source_path}/admin/win/nsi/l10n\German.nsh"
@@ -221,6 +222,9 @@ VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "${VERSION}"
Goto EndLanguageCmp
Brazilian:
!include "${source_path}/admin/win/nsi/l10n\PortugueseBR.nsh"
Goto EndLanguageCmp
Norwegian:
!include "${source_path}/admin/win/nsi/l10n\Norwegian.nsh"
EndLanguageCmp:
FunctionEnd
@@ -445,7 +449,7 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
File "${MING_BIN}\libcrypto-10.dll"
File "${MING_BIN}\libssl-10.dll"
File "${MING_BIN}\libstdc++-6.dll"
File "${MING_BIN}\libwebp-4.dll"
File "${MING_BIN}\libwebp-5.dll"
File "${MING_BIN}\libxslt-1.dll"
File "${MING_BIN}\libxml2-2.dll"
File "${MING_BIN}\zlib1.dll"
@@ -475,6 +479,7 @@ SectionEnd
CreateDirectory "$INSTDIR\shellext"
!define LIBRARY_COM
!define LIBRARY_SHELL_EXTENSION
!define LIBRARY_IGNORE_VERSION
${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"
@@ -488,6 +493,7 @@ SectionEnd
${Endif}
!undef LIBRARY_COM
!undef LIBRARY_SHELL_EXTENSION
!undef LIBRARY_IGNORE_VERSION
${MementoSectionEnd}
!endif
@@ -646,6 +652,7 @@ Section Uninstall
!ifdef OPTION_SECTION_SC_SHELL_EXT
!define LIBRARY_COM
!define LIBRARY_SHELL_EXTENSION
!define LIBRARY_IGNORE_VERSION
${If} ${HasSection} SEC_SHELL_EXT
DetailPrint "Uninstalling x64 overlay DLLs"
!define LIBRARY_X64
@@ -661,6 +668,7 @@ Section Uninstall
${EndIf}
!undef LIBRARY_COM
!undef LIBRARY_SHELL_EXTENSION
!undef LIBRARY_IGNORE_VERSION
!endif
;Start menu shortcut
@@ -777,7 +785,7 @@ Function .onInit
goto UAC_Elevate
;Prevent multiple instances.
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "owncloudInstaller") i .r1 ?e'
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${APPLICATION_SHORTNAME}Installer") i .r1 ?e'
Pop $R0
StrCmp $R0 0 +3
MessageBox MB_OK|MB_ICONEXCLAMATION $INIT_INSTALLER_RUNNING
@@ -842,7 +850,7 @@ Function un.onInit
goto UAC_Elevate
;Prevent multiple instances.
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "owncloudUninstaller") i .r1 ?e'
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${APPLICATION_SHORTNAME}Uninstaller") i .r1 ?e'
Pop $R0
StrCmp $R0 0 +3
MessageBox MB_OK|MB_ICONEXCLAMATION $INIT_UNINSTALLER_RUNNING
+1
Ver Arquivo
@@ -17,6 +17,7 @@ if( Qt5Core_FOUND )
message(STATUS "Found Qt5 core, checking for further dependencies...")
find_package(Qt5Network REQUIRED)
find_package(Qt5Xml REQUIRED)
find_package(Qt5Concurrent REQUIRED)
if(NOT TOKEN_AUTH_ONLY)
find_package(Qt5WebKitWidgets REQUIRED)
find_package(Qt5WebKit REQUIRED)
+2
Ver Arquivo
@@ -19,6 +19,8 @@
#cmakedefine APPLICATION_EXECUTABLE "@APPLICATION_EXECUTABLE@"
#cmakedefine APPLICATION_UPDATE_URL "@APPLICATION_UPDATE_URL@"
#cmakedefine ZLIB_FOUND @ZLIB_FOUND@
#cmakedefine SYSCONFDIR "@SYSCONFDIR@"
#cmakedefine DATADIR "@DATADIR@"
+14
Ver Arquivo
@@ -386,6 +386,20 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
SAFE_FREE(renamed_path);
}
if (!other_node) {
/* Check the source path as well. */
int len;
uint64_t h = 0;
char *renamed_path = csync_rename_adjust_path_source(ctx, cur->path);
if (!c_streq(renamed_path, cur->path)) {
len = strlen( renamed_path );
h = c_jhash64((uint8_t *) renamed_path, len, 0);
other_node = c_rbtree_find(other_tree, &h);
}
SAFE_FREE(renamed_path);
}
if (obj == NULL || data == NULL) {
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
return -1;
+2 -1
Ver Arquivo
@@ -104,7 +104,8 @@ enum csync_status_codes_e {
CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST,
CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS,
CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME,
CYSNC_STATUS_FILE_LOCKED_OR_OPEN
CYSNC_STATUS_FILE_LOCKED_OR_OPEN,
CSYNC_STATUS_INDIVIDUAL_STAT_FAILED
};
typedef enum csync_status_codes_e CSYNC_STATUS;
+1
Ver Arquivo
@@ -233,6 +233,7 @@ CSYNC_EXCLUDE_TYPE csync_excluded_no_ctx(c_strlist_t *excludes, const char *path
}
// check the strlen and ignore the file if its name is longer than 254 chars.
// whenever changing this also check createDownloadTmpFileName
if (strlen(bname) > 254) {
match = CSYNC_FILE_EXCLUDE_LONG_FILENAME;
SAFE_FREE(bname);
+2 -1
Ver Arquivo
@@ -27,7 +27,8 @@ enum csync_exclude_type_e {
CSYNC_FILE_EXCLUDE_AND_REMOVE,
CSYNC_FILE_EXCLUDE_LIST,
CSYNC_FILE_EXCLUDE_INVALID_CHAR,
CSYNC_FILE_EXCLUDE_LONG_FILENAME
CSYNC_FILE_EXCLUDE_LONG_FILENAME,
CSYNC_FILE_EXCLUDE_STAT_FAILED
};
typedef enum csync_exclude_type_e CSYNC_EXCLUDE_TYPE;
+1 -1
Ver Arquivo
@@ -61,7 +61,7 @@ enum csync_log_priority_e {
};
#define CSYNC_LOG(priority, ...) \
csync_log(priority, __FUNCTION__, __VA_ARGS__)
csync_log(priority, __func__, __VA_ARGS__)
void csync_log(int verbosity,
const char *function,
+16
Ver Arquivo
@@ -43,6 +43,7 @@ struct csync_rename_s {
}
std::map<std::string, std::string> folder_renamed_to; // map from->to
std::map<std::string, std::string> folder_renamed_from; // map to->from
struct renameop {
csync_file_stat_t *st;
@@ -63,6 +64,7 @@ void csync_rename_destroy(CSYNC* ctx)
void csync_rename_record(CSYNC* ctx, const char* from, const char* to)
{
csync_rename_s::get(ctx)->folder_renamed_to[from] = to;
csync_rename_s::get(ctx)->folder_renamed_from[to] = from;
}
char* csync_rename_adjust_path(CSYNC* ctx, const char* path)
@@ -78,4 +80,18 @@ char* csync_rename_adjust_path(CSYNC* ctx, const char* path)
return c_strdup(path);
}
char* csync_rename_adjust_path_source(CSYNC* ctx, const char* path)
{
csync_rename_s* d = csync_rename_s::get(ctx);
for (std::string p = _parentDir(path); !p.empty(); p = _parentDir(p)) {
std::map< std::string, std::string >::iterator it = d->folder_renamed_from.find(p);
if (it != d->folder_renamed_from.end()) {
std::string rep = it->second + (path + p.length());
return c_strdup(rep.c_str());
}
}
return c_strdup(path);
}
}
+3
Ver Arquivo
@@ -26,7 +26,10 @@
extern "C" {
#endif
/* Return the final destination path of a given patch in case of renames */
char *csync_rename_adjust_path(CSYNC *ctx, const char *path);
/* Return the source of a given path in case of renames */
char *csync_rename_adjust_path_source(CSYNC *ctx, const char *path);
void csync_rename_destroy(CSYNC *ctx);
void csync_rename_record(CSYNC *ctx, const char *from, const char *to);
+17
Ver Arquivo
@@ -39,6 +39,7 @@
#include "csync_statedb.h"
#include "csync_util.h"
#include "csync_misc.h"
#include "csync_exclude.h"
#include "c_string.h"
#include "c_jhash.h"
@@ -481,6 +482,22 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
rc = _csync_file_stat_from_metadata_table( &st, stmt);
if( st ) {
/* Check for exclusion from the tree.
* Note that this is only a safety net in case the ignore list changes
* without a full remote discovery being triggered. */
CSYNC_EXCLUDE_TYPE excluded = csync_excluded(ctx, st->path, st->type);
if (excluded != CSYNC_NOT_EXCLUDED) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded (%d)", st->path, excluded);
if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE
|| excluded == CSYNC_FILE_SILENTLY_EXCLUDED) {
SAFE_FREE(st);
continue;
}
st->instruction = CSYNC_INSTRUCTION_IGNORE;
}
/* store into result list. */
if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) {
SAFE_FREE(st);
+14 -8
Ver Arquivo
@@ -171,8 +171,12 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
return 0;
}
/* Check if file is excluded */
excluded = csync_excluded(ctx, path,type);
if (type == CSYNC_FTW_TYPE_SKIP) {
excluded =CSYNC_FILE_EXCLUDE_STAT_FAILED;
} else {
/* Check if file is excluded */
excluded = csync_excluded(ctx, path,type);
}
if (excluded != CSYNC_NOT_EXCLUDED) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded (%d)", path, excluded);
@@ -241,11 +245,6 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
}
}
/* Ignore non statable files and other strange cases. */
if (type == CSYNC_FTW_TYPE_SKIP) {
st->instruction = CSYNC_INSTRUCTION_NONE;
goto out;
}
if (excluded > CSYNC_NOT_EXCLUDED || type == CSYNC_FTW_TYPE_SLINK) {
if( type == CSYNC_FTW_TYPE_SLINK ) {
st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK; /* Symbolic links are ignored. */
@@ -418,6 +417,8 @@ out:
st->error_status = CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS; /* File contains invalid characters. */
} else if (excluded == CSYNC_FILE_EXCLUDE_LONG_FILENAME) {
st->error_status = CSYNC_STATUS_INDIVIDUAL_EXCLUDE_LONG_FILENAME; /* File name is too long. */
} else if (excluded == CSYNC_FILE_EXCLUDE_STAT_FAILED) {
st->error_status = CSYNC_STATUS_INDIVIDUAL_STAT_FAILED;
}
}
if (st->instruction != CSYNC_INSTRUCTION_NONE && st->instruction != CSYNC_INSTRUCTION_IGNORE
@@ -621,7 +622,12 @@ 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_STORAGE_UNAVAILABLE) {
}
// The server usually replies with the custom "503 Storage not available"
// if some path is temporarily unavailable. But in some cases a standard 503
// is returned too. Thus we can't distinguish the two and will treat any
// 503 as request to ignore the folder. See #3113 #2884.
else if(errno == ERRNO_STORAGE_UNAVAILABLE || errno == ERRNO_SERVICE_UNAVAILABLE) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Storage was not available!");
if (ctx->current_fs) {
ctx->current_fs->instruction = CSYNC_INSTRUCTION_IGNORE;
+1 -1
Ver Arquivo
@@ -42,7 +42,7 @@
#define DEBUG_HBF(...) { if(transfer->log_cb) { \
char buf[1024]; \
snprintf(buf, 1024, __VA_ARGS__); \
transfer->log_cb(__FUNCTION__, buf, transfer->user_data); \
transfer->log_cb(__func__, buf, transfer->user_data); \
} }
// #endif
+1 -1
Ver Arquivo
@@ -131,7 +131,7 @@ static void check_logging(void **state)
rc = csync_set_log_callback(check_log_callback);
assert_int_equal(rc, 0);
csync_log(1, __FUNCTION__, "rc = %d", rc);
csync_log(1, __func__, "rc = %d", rc);
rc = _tstat(path, &sb);
+6 -4
Ver Arquivo
@@ -124,7 +124,8 @@ sub initTesting(;$)
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0
}
$d = HTTP::DAV->new();
my $ua = HTTP::DAV::UserAgent->new(keep_alive => 1 );
$d = HTTP::DAV->new(-useragent => $ua);
$d->credentials( -url=> $owncloud, -realm=>"ownCloud",
-user=> $user,
@@ -191,7 +192,6 @@ sub removeRemoteDir($;$)
my ($dir, $optionsRef) = @_;
my $url = testDirUrl() . $dir;
if( $optionsRef && $optionsRef->{user} && $optionsRef->{passwd} ) {
$d->credentials( -url=> $owncloud, -realm=>"ownCloud",
-user=> $optionsRef->{user},
@@ -326,11 +326,11 @@ sub assertLocalDirs( $$ )
opendir(my $dh, $dir1 ) || die;
while(readdir $dh) {
assert( -e "$dir2/$_" );
assert( -e "$dir2/$_", " $dir2/$_ do not exist" );
next if( -d "$dir1/$_"); # don't compare directory sizes.
my $s1 = -s "$dir1/$_";
my $s2 = -s "$dir2/$_";
assert( $s1 == $s2, "$dir1/$_ <-> $dir2/$_" );
assert( $s1 == $s2, "$dir1/$_ <-> $dir2/$_ size not equal ($s1 != $s2)" );
}
closedir $dh;
}
@@ -524,7 +524,9 @@ sub put_to_dir( $$;$ )
my $filename = $file;
$filename =~ s/^.*\///;
$filename =~ s/#/%23/g; # poor man's URI encoder
my $puturl = $targetUrl . $dir. $filename;
print "put_to_dir puts to $puturl\n";
unless ($d->put( -local => $file, -url => $puturl )) {
print " ### FAILED to put a single file!\n";
+85
Ver Arquivo
@@ -0,0 +1,85 @@
#!/usr/bin/perl
#
# Test script for the ownCloud module of csync.
# This script requires a running ownCloud instance accessible via HTTP.
# It does quite some fancy tests and asserts the results.
#
# Copyright (C) by Olivier Goffart <ogoffart@woboq.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
use lib ".";
use File::Copy;
use ownCloud::Test;
use strict;
print "Hello, this is t_recall, a tester for the recall feature\n";
initTesting();
printInfo( "Syncing two files with the same name that differ with case" );
#create some files
my $tmpdir = "/tmp/t_recall/";
mkdir($tmpdir);
createLocalFile( $tmpdir . "file1.dat", 100 );
createLocalFile( $tmpdir . "file2.dat", 150 );
createLocalFile( $tmpdir . "file3.dat", 110 );
createLocalFile( $tmpdir . "file4.dat", 170 );
#put them in some directories
createRemoteDir( "dir" );
glob_put( "$tmpdir/*", "dir" );
csync();
assertLocalAndRemoteDir( '', 0);
printInfo( "Testing with a .sys.admin#recall#" );
system("echo 'dir/file2.dat' > ". $tmpdir . ".sys.admin\#recall\#");
system("echo 'dir/file3.dat' >> ". $tmpdir . ".sys.admin\#recall\#");
glob_put( "$tmpdir/.sys.admin\#recall\#", "" );
csync();
#test that the recall files have been created
assert( -e glob(localDir().'dir/file2_.sys.admin#recall#-*.dat' ) );
assert( -e glob(localDir().'dir/file3_.sys.admin#recall#-*.dat' ) );
#Remove the recall file
unlink(localDir() . ".sys.admin#recall#");
# 2 sync necessary for the recall to be uploaded
csync();
assertLocalAndRemoteDir( '', 0);
printInfo( "Testing with a dir/.sys.admin#recall#" );
system("echo 'file4.dat' > ". $tmpdir . ".sys.admin\#recall\#");
glob_put( "$tmpdir/.sys.admin\#recall\#", "dir" );
csync();
assert( -e glob(localDir().'dir/file4_.sys.admin#recall#-*.dat' ) );
cleanup();
system("rm -r " . $tmpdir);
+3 -3
Ver Arquivo
@@ -25,9 +25,9 @@ The process of synchronization keeps files in two separate repositories the
same. When synchronized:
- If a file is added to one repository it is copied to the other synchronized repository.
- When a file is changed in one repository, the change is propagated to any
synchronized other repositories- If a file is deleted in one repository, it
is deleted in any other.
- When a file is changed in one repository, the change is propagated to any other
synchronized repository.
- If a file is deleted in one repository, it is deleted in any other.
It is important to note that the ownCloud synchronization process does not use
a typical client/server system where the server is always master. This is a
+2
Ver Arquivo
@@ -214,6 +214,8 @@ To build the most up to date version of the client:
1. Clone the latest versions of the client from Git_ as follows:
``git clone git://github.com/owncloud/client.git``
``git submodule init``
``git submodule update``
2. Create the build directory:
Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 14 KiB

+6 -1
Ver Arquivo
@@ -3,7 +3,7 @@ Installing the Desktop Synchronization Client
=============================================
You can download the latest version of the ownCloud Desktop Synchronization
Client from the `ownCloud Website <https://owncloud.org/install/#desktop>`_.
Client from the `ownCloud Website <https://owncloud.org/install/#>`_.
There are clients for Linux, Mac OS X, and Microsoft Windows.
Installation on Mac OS X and Windows is the same as for any software
@@ -105,3 +105,8 @@ you saw in the installation wizard. If you un-check any folders or files that
you have already synchronized they will be deleted.
.. image:: images/client11.png
Right-click on the systray icon to see more options, such as Open ownCloud in
browser, Open folder 'ownCloud', Recent changes, Help, and Quit ownCloud.
.. image:: images/client12.png
+14 -10
Ver Arquivo
@@ -61,12 +61,12 @@ Other issues can affect synchronization of your ownCloud files:
ensure that the folder to which you are synchronizing is not shared with
other synchronization applications.
- Synchronizing the same directory with ownCloud and other
synchronization software such as Unison, rsync, Microsoft Windows Offline
Folders, or other cloud services such as DropBox or Microsoft SkyDrive is not
supported and should not be attempted. In the worst case, it is possible that
synchronizing folders or files using ownCloud and other synchronization
software or services can result in data loss.
- Synchronizing the same directory with ownCloud and other synchronization
software such as Unison, rsync, Microsoft Windows Offline Folders, or other
cloud services such as DropBox or Microsoft SkyDrive is not supported and
should not be attempted. In the worst case, it is possible that synchronizing
folders or files using ownCloud and other synchronization software or
services can result in data loss.
- If you find that only specific files are not synrchronized, the
synchronization protocol might be having an effect. Some files are
@@ -80,9 +80,13 @@ Other issues can affect synchronization of your ownCloud files:
.. note:: The data directory on the server is exclusive to ownCloud and must not be modified manually.
If you are using a different file backend on the server, you can try to exclude a bug in the
- If you are using a different file backend on the server, you can try to exclude a bug in the
backend by reverting to the built-in backend.
- If you are experiencing slow upload/download speed or similar performance issues
be aware that those could be caused by on-access virus scanning solutions, either
on the server (like the files_antivirus app) or the client.
Log Files
---------
@@ -125,9 +129,9 @@ mentioned above to save the log to a file.
.. note:: You can also open a log window for an already running session, by
restarting the client using the following command:
* Windows: ``C:\Program Files (x86)\ownCloud\owncloud.exe --logwindow``
* Mac OS X: ``/Applications/owncloud.app/Contents/MacOS/owncloud --logwindow``
* Linux: ``owncloud --logwindow``
* Windows: ``C:\Program Files (x86)\ownCloud\owncloud.exe --logwindow``
* Mac OS X: ``/Applications/owncloud.app/Contents/MacOS/owncloud --logwindow``
* Linux: ``owncloud --logwindow``
Saving Files Directly
~~~~~~~~~~~~~~~~~~~~~
@@ -17,6 +17,7 @@
@interface ContentManager : NSObject
{
NSMutableDictionary* _fileNamesCache;
NSMutableDictionary* _oldFileNamesCache;
BOOL _fileIconsEnabled;
BOOL _hasChangedContent;
@@ -35,10 +36,9 @@
- (void)enableFileIcons:(BOOL)enable;
- (NSNumber*)iconByPath:(NSString*)path isDirectory:(BOOL)isDir;
- (void)removeAllIcons;
- (void)removeIcons:(NSArray*)paths;
- (void)setIcons:(NSDictionary*)iconDictionary filterByFolder:(NSString*)filterFolder;
- (void)setResultForPath:(NSString*)path result:(NSString*)result;
- (void)clearFileNameCacheForPath:(NSString*)path;
- (void)clearFileNameCache;
- (void)reFetchFileNameCacheForPath:(NSString*)path;
- (void)repaintAllWindows;
@@ -30,6 +30,7 @@ static ContentManager* sharedInstance = nil;
if (self)
{
_fileNamesCache = [[NSMutableDictionary alloc] init];
_oldFileNamesCache = [[NSMutableDictionary alloc] init];
_fileIconsEnabled = TRUE;
_hasChangedContent = TRUE;
}
@@ -41,6 +42,7 @@ static ContentManager* sharedInstance = nil;
{
[self removeAllIcons];
[_fileNamesCache release];
[_oldFileNamesCache release];
sharedInstance = nil;
[super dealloc];
@@ -148,84 +150,48 @@ static ContentManager* sharedInstance = nil;
if( result == nil ) {
// start the async call
NSNumber *askState = [[RequestManager sharedInstance] askForIcon:normalizedPath isDirectory:isDir];
[_fileNamesCache setObject:askState forKey:normalizedPath];
[[RequestManager sharedInstance] askForIcon:normalizedPath isDirectory:isDir];
result = [NSNumber numberWithInt:0];
} else if( [result intValue] == -1 ) {
// the socket call is underways.
result = [NSNumber numberWithInt:0];
} else {
// there is a proper icon index
// Set 0 into the cache, meaning "don't have an icon, but already requested it"
[_fileNamesCache setObject:result forKey:normalizedPath];
}
// NSLog(@"iconByPath return value %d", [result intValue]);
if ([result intValue] == 0) {
// Show the old state while we wait for the new one
NSNumber* oldResult = [_oldFileNamesCache objectForKey:normalizedPath];
if (oldResult)
result = oldResult;
}
// NSLog(@"iconByPath return value %d", [result intValue]);
return result;
}
// called as a result of an UPDATE_VIEW message.
// it clears the entries from the hash to make it call again home to the desktop client.
- (void)clearFileNameCacheForPath:(NSString*)path
// Clears the entries from the hash to make it call again home to the desktop client.
- (void)clearFileNameCache
{
//NSLog(@"%@", NSStringFromSelector(_cmd));
NSMutableArray *keysToDelete = [NSMutableArray array];
if( path != nil ) {
for (id p in [_fileNamesCache keyEnumerator]) {
//do stuff with obj
if ( [p hasPrefix:path] ) {
[keysToDelete addObject:p];
}
}
} else {
// clear the entire fileNameCache
[_fileNamesCache release];
_fileNamesCache = [[NSMutableDictionary alloc] init];
return;
}
if( [keysToDelete count] > 0 ) {
NSLog( @"Entries to delete: %lu", (unsigned long)[keysToDelete count]);
[_fileNamesCache removeObjectsForKeys:keysToDelete];
}
[_fileNamesCache release];
_fileNamesCache = [[NSMutableDictionary alloc] init];
[_oldFileNamesCache removeAllObjects];
}
- (void)reFetchFileNameCacheForPath:(NSString*)path
{
NSLog(@"%@", NSStringFromSelector(_cmd));
//NSLog(@"%@", NSStringFromSelector(_cmd));
for (id p in [_fileNamesCache keyEnumerator]) {
if ( path && [p hasPrefix:path] ) {
[[RequestManager sharedInstance] askForIcon:p isDirectory:false]; // FIXME isDirectory parameter
//[_fileNamesCache setObject:askState forKey:p]; We don't do this since we want to keep the old icon meanwhile
//NSLog(@"%@ %@", NSStringFromSelector(_cmd), p);
}
}
// We won't request the new state if if finds the path in _fileNamesCache
// Move all entries to _oldFileNamesCache so that the get re-requested, but
// still available while we refill the cache
[_oldFileNamesCache addEntriesFromDictionary:_fileNamesCache];
[_fileNamesCache removeAllObjects];
// Ask for directory itself
if ([path hasSuffix:@"/"]) {
path = [path substringToIndex:path.length - 1];
}
[[RequestManager sharedInstance] askForIcon:path isDirectory:true];
//NSLog(@"%@ %@", NSStringFromSelector(_cmd), path);
[self repaintAllWindows];
}
- (void)removeAllIcons
{
[_fileNamesCache removeAllObjects];
[self repaintAllWindows];
}
- (void)removeIcons:(NSArray*)paths
{
for (NSString* path in paths)
{
NSString* normalizedPath = [path decomposedStringWithCanonicalMapping];
[_fileNamesCache removeObjectForKey:normalizedPath];
}
[_oldFileNamesCache removeAllObjects];
[self repaintAllWindows];
}
@@ -361,6 +327,7 @@ static ContentManager* sharedInstance = nil;
}
else
{
[_oldFileNamesCache removeObjectForKey:normalizedPath];
[_fileNamesCache setObject:iconId forKey:normalizedPath];
}
}
@@ -22,6 +22,7 @@
NSMutableArray* _requestQueue;
NSMutableDictionary* _registeredPathes;
NSMutableSet* _requestedPaths;
NSString *_shareMenuTitle;
@@ -34,7 +35,7 @@
- (BOOL)isRegisteredPath:(NSString*)path isDirectory:(BOOL)isDir;
- (void)askOnSocket:(NSString*)path query:(NSString*)verb;
- (NSNumber*)askForIcon:(NSString*)path isDirectory:(BOOL)isDir;
- (void)askForIcon:(NSString*)path isDirectory:(BOOL)isDir;
- (void)menuItemClicked:(NSDictionary*)actionDictionary;
- (void)start;
@@ -31,6 +31,7 @@ static RequestManager* sharedInstance = nil;
_isConnected = NO;
_registeredPathes = [[NSMutableDictionary alloc] init];
_requestedPaths = [[NSMutableSet alloc] init];
_shareMenuTitle = nil;
@@ -101,28 +102,23 @@ static RequestManager* sharedInstance = nil;
return registered;
}
- (NSNumber*)askForIcon:(NSString*)path isDirectory:(BOOL)isDir
- (void)askForIcon:(NSString*)path isDirectory:(BOOL)isDir
{
NSString *verb = @"RETRIEVE_FILE_STATUS";
NSNumber *res = [NSNumber numberWithInt:0];
if( [self isRegisteredPath:path isDirectory:isDir] ) {
[_requestedPaths addObject:path];
if( _isConnected ) {
if(isDir) {
verb = @"RETRIEVE_FOLDER_STATUS";
}
[self askOnSocket:path query:verb];
NSNumber *res_minus_one = [NSNumber numberWithInt:0];
return res_minus_one;
} else {
[_requestQueue addObject:path];
[self start]; // try again to connect
}
}
return res;
}
@@ -147,9 +143,13 @@ static RequestManager* sharedInstance = nil;
path, [chunks objectAtIndex:i+1] ];
}
}
[contentman setResultForPath:path result:[chunks objectAtIndex:1]];
// The client will broadcast all changes, do not fill the cache for paths that Finder didn't ask for.
if ([_requestedPaths containsObject:path]) {
[contentman setResultForPath:path result:[chunks objectAtIndex:1]];
}
} else if( [[chunks objectAtIndex:0] isEqualToString:@"UPDATE_VIEW"] ) {
NSString *path = [chunks objectAtIndex:1];
[_requestedPaths removeAllObjects];
[contentman reFetchFileNameCacheForPath:path];
} else if( [[chunks objectAtIndex:0 ] isEqualToString:@"REGISTER_PATH"] ) {
NSNumber *one = [NSNumber numberWithInt:1];
@@ -198,10 +198,11 @@ static RequestManager* sharedInstance = nil;
for( NSString *path in _requestQueue ) {
[self askOnSocket:path query:@"RETRIEVE_FILE_STATUS"];
}
[_requestQueue removeAllObjects];
}
ContentManager *contentman = [ContentManager sharedInstance];
[contentman clearFileNameCacheForPath:nil];
[contentman clearFileNameCache];
[contentman repaintAllWindows];
// Read for the UPDATE_VIEW requests
@@ -218,10 +219,11 @@ static RequestManager* sharedInstance = nil;
// clear the registered pathes.
[_registeredPathes release];
_registeredPathes = [[NSMutableDictionary alloc] init];
[_requestedPaths removeAllObjects];
// clear the caches in conent manager
ContentManager *contentman = [ContentManager sharedInstance];
[contentman clearFileNameCacheForPath:nil];
[contentman clearFileNameCache];
[contentman repaintAllWindows];
}
+4 -3
Ver Arquivo
@@ -1,5 +1,6 @@
#!/bin/sh
# osascript $HOME/owncloud.com/client/shell_integration/MacOSX/unload.scpt
SELFPATH=`dirname $0`
# osascript $SELFPATH/unload.scpt
sudo rm -rf /Library/ScriptingAdditions/SyncStateFinder.osax
# Klaas' machine
@@ -12,6 +13,6 @@ OSAXDIR=$HOME/Library/Developer/Xcode/DerivedData/OwnCloud-*/Build/Products/Debu
sudo killall Finder
sleep 1
osascript $HOME/owncloud.com/client/shell_integration/MacOSX/load.scpt
osascript $HOME/owncloud.com/client/shell_integration/MacOSX/check.scpt
osascript $SELFPATH/load.scpt
osascript $SELFPATH/check.scpt
@@ -98,6 +98,8 @@ void RemotePathChecker::workerThreadLoop()
++it;
}
}
// Assume that we won't need this at this point, UNREGISTER_PATH is rare
_oldCache.clear();
}
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
} else if (StringUtil::begins_with(response, wstring(L"STATUS:")) ||
@@ -115,13 +117,16 @@ void RemotePathChecker::workerThreadLoop()
auto responseStatus = response.substr(statusBegin+1, statusEnd - statusBegin-1);
auto responsePath = response.substr(statusEnd+1);
auto state = _StrToFileState(responseStatus);
auto erased = asked.erase(responsePath);
bool wasAsked = asked.erase(responsePath) > 0;
bool changed = false;
{ std::unique_lock<std::mutex> lock(_mutex);
auto &it = _cache[responsePath];
changed = (it != state);
it = state;
bool wasCached = _cache.find(responsePath) != _cache.end();
if (wasAsked || wasCached) {
auto &it = _cache[responsePath];
changed = (it != state);
it = state;
}
}
if (changed) {
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
@@ -129,20 +134,25 @@ void RemotePathChecker::workerThreadLoop()
}
else if (StringUtil::begins_with(response, wstring(L"UPDATE_VIEW"))) {
std::unique_lock<std::mutex> lock(_mutex);
auto cache = _cache; // Make a copy of the cache under the mutex
// Keep the old states to continue having something to display while the new state is
// requested from the client, triggered by clearing _cache.
_oldCache.insert(_cache.cbegin(), _cache.cend());
// Swap to make a copy of the cache under the mutex and clear the one stored.
std::unordered_map<std::wstring, FileState> cache;
swap(cache, _cache);
lock.unlock();
// 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;
}
}
}
// Let explorer know about the invalidated cache entries, it will re-request the ones it needs.
for (auto it = cache.begin(); it != cache.end(); ++it) {
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, it->first.data(), NULL);
}
}
}
if (socket.Event() == INVALID_HANDLE_VALUE) {
std::unique_lock<std::mutex> lock(_mutex);
_cache.clear();
_oldCache.clear();
_watchedDirectories.clear();
_connected = connected = false;
}
@@ -195,11 +205,17 @@ bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state)
return true;
}
// Re-request the status while we display what we have in _oldCache
_pending.push(filePath);
it = _oldCache.find(path);
bool foundInOldCache = it != _oldCache.end();
if (foundInOldCache)
*state = it->second;
lock.unlock();
SetEvent(_newQueries);
return false;
return foundInOldCache;
}
RemotePathChecker::FileState RemotePathChecker::_StrToFileState(const std::wstring &str)
@@ -52,6 +52,7 @@ private:
std::queue<std::wstring> _pending;
std::unordered_map<std::wstring, FileState> _cache;
std::unordered_map<std::wstring, FileState> _oldCache;
std::vector<std::wstring> _watchedDirectories;
bool _connected;
+4
Ver Arquivo
@@ -5,6 +5,10 @@ set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set(synclib_NAME ${APPLICATION_EXECUTABLE}sync)
if (APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif()
add_subdirectory(libsync)
if (NOT BUILD_LIBRARIES_ONLY)
add_subdirectory(gui)
+2
Ver Arquivo
@@ -289,6 +289,8 @@ void selectiveSyncFixup(OCC::SyncJournalDb *journal, const QStringList &newList)
int main(int argc, char **argv) {
QCoreApplication app(argc, argv);
qsrand(QTime::currentTime().msec() * QCoreApplication::applicationPid());
CmdOptions options;
options.silent = false;
options.trustSSL = false;
+16 -3
Ver Arquivo
@@ -234,7 +234,7 @@ void AccountSettings::slotAddFolder( Folder *folder )
if( ! folder || folder->alias().isEmpty() ) return;
QStandardItem *item = new QStandardItem();
folderToModelItem( item, folder, _accountState && _accountState->isConnectedOrMaintenance());
folderToModelItem( item, folder, _accountState && _accountState->isConnectedOrTemporarilyUnavailable());
_model->appendRow( item );
// in order to update the enabled state of the "Sync now" button
connect(folder, SIGNAL(syncStateChange()), this, SLOT(slotFolderSyncStateChange()), Qt::UniqueConnection);
@@ -398,6 +398,18 @@ void AccountSettings::slotSelectiveSync()
}
}
void AccountSettings::slotForceRemoteDiscoveryOnFolders()
{
FolderMan* folders = FolderMan::instance();
foreach (Folder* folder, folders->map()) {
if (folder->accountState() != _accountState) {
continue;
}
folder->journalDb()->forceRemoteDiscoveryNextSync();
}
}
void AccountSettings::slotDoubleClicked( const QModelIndex& indx )
{
if( ! indx.isValid() ) return;
@@ -537,7 +549,7 @@ void AccountSettings::slotUpdateFolderState( Folder *folder )
}
if( item ) {
folderToModelItem( item, folder, _accountState->isConnectedOrMaintenance() );
folderToModelItem( item, folder, _accountState->isConnectedOrTemporarilyUnavailable() );
} else {
// the dialog is not visible.
}
@@ -777,6 +789,7 @@ void AccountSettings::slotIgnoreFilesEditor()
_ignoreEditor = new IgnoreListEditor(this);
_ignoreEditor->setAttribute( Qt::WA_DeleteOnClose, true );
_ignoreEditor->open();
connect(_ignoreEditor, SIGNAL(accepted()), SLOT(slotForceRemoteDiscoveryOnFolders()));
} else {
ownCloudGui::raiseDialog(_ignoreEditor);
}
@@ -794,7 +807,7 @@ void AccountSettings::slotAccountStateChanged(int state)
foreach (Folder *folder, folderMan->map().values()) {
slotUpdateFolderState(folder);
}
if (state == AccountState::Connected || state == AccountState::ServerMaintenance) {
if (state == AccountState::Connected || state == AccountState::ServiceUnavailable) {
QString user;
if (AbstractCredentials *cred = account->credentials()) {
user = cred->user();
+1
Ver Arquivo
@@ -83,6 +83,7 @@ protected slots:
void slotOpenAccountWizard();
void slotHideProgress();
void slotSelectiveSync();
void slotForceRemoteDiscoveryOnFolders();
private:
QString shortenFilename( const QString& folder, const QString& file ) const;
+3
Ver Arquivo
@@ -40,6 +40,9 @@
<property name="text">
<string>Connected with &lt;server&gt; as &lt;user&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
+24 -9
Ver Arquivo
@@ -114,9 +114,10 @@ void AccountState::setState(State state)
} else if (oldState == SignedOut && _state == Disconnected) {
checkConnectivity();
}
emit stateChanged(_state);
}
// might not have changed but the underlying _connectionErrors might have
emit stateChanged(_state);
}
QString AccountState::stateString(State state)
@@ -129,8 +130,8 @@ QString AccountState::stateString(State state)
return QLatin1String("Disconnected");
case Connected:
return QLatin1String("Connected");
case ServerMaintenance:
return QLatin1String("ServerMaintenance");
case ServiceUnavailable:
return QLatin1String("ServiceUnavailable");
case NetworkError:
return QLatin1String("NetworkError");
case ConfigurationError:
@@ -158,9 +159,9 @@ bool AccountState::isConnected() const
return _state == Connected;
}
bool AccountState::isConnectedOrMaintenance() const
bool AccountState::isConnectedOrTemporarilyUnavailable() const
{
return isConnected() || _state == ServerMaintenance;
return isConnected() || _state == ServiceUnavailable;
}
QuotaInfo *AccountState::quotaInfo()
@@ -174,7 +175,12 @@ void AccountState::checkConnectivity()
return;
}
if (_connectionValidator) {
qDebug() << "ConnectionValidator already running, ignoring";
return;
}
ConnectionValidator * conValidator = new ConnectionValidator(account());
_connectionValidator = conValidator;
connect(conValidator, SIGNAL(connectionResult(ConnectionValidator::Status,QStringList)),
SLOT(slotConnectionValidatorResult(ConnectionValidator::Status,QStringList)));
if (isConnected()) {
@@ -202,6 +208,7 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
return;
}
auto oldStatus = _connectionStatus;
if (_connectionStatus != status) {
qDebug() << "AccountState connection status change: "
<< connectionStatusString(_connectionStatus) << "->"
@@ -213,7 +220,9 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
switch (status)
{
case ConnectionValidator::Connected:
setState(Connected);
if (oldStatus != ConnectionValidator::Connected) {
setState(Connected);
}
break;
case ConnectionValidator::Undefined:
case ConnectionValidator::NotConfigured:
@@ -234,8 +243,8 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
case ConnectionValidator::UserCanceledCredentials:
setState(SignedOut);
break;
case ConnectionValidator::ServerMaintenance:
setState(ServerMaintenance);
case ConnectionValidator::ServiceUnavailable:
setState(ServiceUnavailable);
break;
case ConnectionValidator::Timeout:
setState(NetworkError);
@@ -263,6 +272,12 @@ void AccountState::slotCredentialsFetched(AbstractCredentials* credentials)
return;
}
// When new credentials become available we always want to restart the
// connection validation, even if it's currently running.
if (_connectionValidator) {
delete _connectionValidator;
}
checkConnectivity();
}
+6 -4
Ver Arquivo
@@ -16,6 +16,7 @@
#define ACCOUNTINFO_H
#include <QByteArray>
#include <QPointer>
#include "utility.h"
#include "connectionvalidator.h"
@@ -67,9 +68,9 @@ public:
/// The account is successfully talking to the server.
Connected,
/// The account is talking to the server, but the server is in
/// maintenance mode.
ServerMaintenance,
/// There's a temporary problem with talking to the server,
/// don't bother the user too much and try again.
ServiceUnavailable,
/// Could not communicate with the server for some reason.
/// We assume this may resolve itself over time and will try
@@ -100,7 +101,7 @@ public:
void setSignedOut(bool signedOut);
bool isConnected() const;
bool isConnectedOrMaintenance() const;
bool isConnectedOrTemporarilyUnavailable() const;
QuotaInfo *quotaInfo();
@@ -128,6 +129,7 @@ private:
ConnectionStatus _connectionStatus;
QStringList _connectionErrors;
bool _waitingForNewCredentials;
QPointer<ConnectionValidator> _connectionValidator;
};
}
+10 -1
Ver Arquivo
@@ -110,6 +110,15 @@ Application::Application(int &argc, char **argv) :
if (isRunning())
return;
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) && QT_VERSION < QT_VERSION_CHECK(5, 4, 2)
// Workaround for QTBUG-44576: Make sure a stale QSettings lock file
// is deleted. (Introduced in Qt 5.4.0 and fixed in Qt 5.4.2)
{
QString lockFilePath = ConfigFile().configFile() + QLatin1String(".lock");
QLockFile(lockFilePath).removeStaleLockFile();
}
#endif
#if defined(WITH_CRASHREPORTER)
if (ConfigFile().crashReporter())
_crashHandler.reset(new CrashReporter::Handler( QDir::tempPath(), true, CRASHREPORTER_EXECUTABLE ));
@@ -270,7 +279,7 @@ void Application::slotAccountStateChanged(int state)
folderMan->setSyncEnabled(true);
folderMan->slotScheduleAllFolders();
break;
case AccountState::ServerMaintenance:
case AccountState::ServiceUnavailable:
case AccountState::SignedOut:
case AccountState::ConfigurationError:
case AccountState::NetworkError:
+1
Ver Arquivo
@@ -32,6 +32,7 @@ class SelectiveSyncTreeView;
class ownCloudInfo;
class FormatWarningsWizardPage : public QWizardPage {
Q_OBJECT
protected:
QString formatWarnings(const QStringList &warnings) const;
};
+6 -1
Ver Arquivo
@@ -221,7 +221,12 @@ void ownCloudGui::slotComputeOverallSyncStatus()
_tray->setToolTip(tr("Please sign in"));
return;
}
if (!a->isConnectedOrMaintenance()) {
if (a->state() == AccountState::ServiceUnavailable) {
_tray->setIcon(Theme::instance()->folderOfflineIcon(true));
_tray->setToolTip(tr("Server is temporarily unavailable"));
return;
}
if (!a->isConnected()) {
_tray->setIcon(Theme::instance()->folderOfflineIcon(true));
_tray->setToolTip(tr("Disconnected from server"));
return;
+6 -1
Ver Arquivo
@@ -189,6 +189,10 @@ void OwncloudSetupWizard::slotNoOwnCloudFoundAuth(QNetworkReply *reply)
.arg(Theme::instance()->appNameGUI(),
reply->url().toString(),
reply->errorString()), checkDowngradeAdvised(reply));
// Allow the credentials dialog to pop up again for the same URL.
// Maybe the user just clicked 'Cancel' by accident or changed his mind.
_ocWizard->account()->resetSslCertErrorState();
}
void OwncloudSetupWizard::slotNoOwnCloudFoundAuthTimeout(const QUrl&url)
@@ -263,11 +267,12 @@ void OwncloudSetupWizard::slotAuthError()
// Provide messages for other errors, such as invalid credentials.
} else if (reply->error() != QNetworkReply::NoError) {
errorMsg = reply->errorString();
if (!_ocWizard->account()->credentials()->stillValid(reply)) {
errorMsg = tr("Access forbidden by server. To verify that you have proper access, "
"<a href=\"%1\">click here</a> to access the service with your browser.")
.arg(_ocWizard->account()->url().toString());
} else {
errorMsg = errorMessage(reply->errorString(), reply->readAll());
}
// Something else went wrong, maybe the response was 200 but with invalid data.
+1 -1
Ver Arquivo
@@ -206,7 +206,7 @@ QTreeWidgetItem* ProtocolWidget::createCompletedTreewidgetItem(const QString& fo
const QString longTimeStr = timeString(timestamp, QLocale::LongFormat);
columns << timeStr;
columns << fixupFilename(item._file);
columns << fixupFilename(item._originalFile);
columns << folder;
// If the error string is set, it's prefered because it is a useful user message.
+57 -50
Ver Arquivo
@@ -144,6 +144,15 @@ void ShareDialog::done( int r ) {
QDialog::done(r);
}
static int getJsonReturnCode(const QVariantMap &json, QString &message)
{
//TODO proper checking
int code = json.value("ocs").toMap().value("meta").toMap().value("statuscode").toInt();
message = json.value("ocs").toMap().value("meta").toMap().value("message").toString();
return code;
}
void ShareDialog::setExpireDate(const QDate &date)
{
if( _public_share_id == 0 ) {
@@ -162,16 +171,14 @@ void ShareDialog::setExpireDate(const QDate &date)
OcsShareJob *job = new OcsShareJob("PUT", url, _account, this);
job->setPostParams(postParams);
connect(job, SIGNAL(jobFinished(QString)), this, SLOT(slotExpireSet(QString)));
connect(job, SIGNAL(jobFinished(QVariantMap)), this, SLOT(slotExpireSet(QVariantMap)));
job->start();
}
void ShareDialog::slotExpireSet(const QString &reply)
void ShareDialog::slotExpireSet(const QVariantMap &reply)
{
QString message;
int code = checkJsonReturnCode(reply, message);
qDebug() << Q_FUNC_INFO << "Status code: " << code;
int code = getJsonReturnCode(reply, message);
if (code != 100) {
displayError(code);
}
@@ -234,18 +241,15 @@ void ShareDialog::setPassword(const QString &password)
}
OcsShareJob *job = new OcsShareJob(verb, url, _account, this);
job->setPostParams(requestParams);
connect(job, SIGNAL(jobFinished(QString)), this, SLOT(slotPasswordSet(QString)));
connect(job, SIGNAL(jobFinished(QVariantMap)), this, SLOT(slotPasswordSet(QVariantMap)));
job->start();
_passwordJobRunning = true;
}
void ShareDialog::slotPasswordSet(const QString &reply)
void ShareDialog::slotPasswordSet(const QVariantMap &reply)
{
QString message;
int code = checkJsonReturnCode(reply, message);
qDebug() << Q_FUNC_INFO << "Status code: " << code;
int code = getJsonReturnCode(reply, message);
if (code != 100) {
displayError(code);
}
@@ -267,23 +271,20 @@ void ShareDialog::getShares()
params.append(qMakePair(QString::fromLatin1("path"), _sharePath));
url.setQueryItems(params);
OcsShareJob *job = new OcsShareJob("GET", url, _account, this);
connect(job, SIGNAL(jobFinished(QString)), this, SLOT(slotSharesFetched(QString)));
job->addPassStatusCode(404); // don't report error if share doesn't exist yet
connect(job, SIGNAL(jobFinished(QVariantMap)), this, SLOT(slotSharesFetched(QVariantMap)));
job->start();
}
void ShareDialog::slotSharesFetched(const QString &reply)
void ShareDialog::slotSharesFetched(const QVariantMap &reply)
{
QString message;
int code = checkJsonReturnCode(reply, message);
qDebug() << Q_FUNC_INFO << "Status code: " << code;
int code = getJsonReturnCode(reply, message);
if (code != 100 && code != 404) {
displayError(code);
}
bool success = false;
QVariantMap json = QtJson::parse(reply, success).toMap();
ShareDialog::_shares = json.value("ocs").toMap().value("data").toList();
ShareDialog::_shares = reply.value("ocs").toMap().value("data").toList();
const QString versionString = AccountManager::instance()->account()->serverVersion();
Q_FOREACH(auto share, ShareDialog::_shares) {
@@ -291,6 +292,7 @@ void ShareDialog::slotSharesFetched(const QString &reply)
if (data.value("share_type").toInt() == SHARETYPE_PUBLIC) {
_public_share_id = data.value("id").toULongLong();
_ui->pushButton_copy->show();
_ui->widget_shareLink->show();
_ui->checkBox_shareLink->setChecked(true);
@@ -384,12 +386,10 @@ void ShareDialog::setShareLink( const QString& url )
}
void ShareDialog::slotDeleteShareFetched(const QString &reply)
void ShareDialog::slotDeleteShareFetched(const QVariantMap &reply)
{
QString message;
int code = checkJsonReturnCode(reply, message);
qDebug() << Q_FUNC_INFO << "Status code: " << code;
int code = getJsonReturnCode(reply, message);
if (code != 100) {
displayError(code);
}
@@ -423,29 +423,31 @@ void ShareDialog::slotCheckBoxShareLinkClicked()
postParams.append(qMakePair(QString::fromLatin1("shareType"), QString::number(SHARETYPE_PUBLIC)));
OcsShareJob *job = new OcsShareJob("POST", url, _account, this);
job->setPostParams(postParams);
connect(job, SIGNAL(jobFinished(QString)), this, SLOT(slotCreateShareFetched(QString)));
job->addPassStatusCode(403); // "password required" is not an error
connect(job, SIGNAL(jobFinished(QVariantMap)), this, SLOT(slotCreateShareFetched(QVariantMap)));
job->start();
} else {
_pi_link->startAnimation();
QUrl url = Account::concatUrlPath(_account->url(), QString("ocs/v1.php/apps/files_sharing/api/v1/shares/%1").arg(_public_share_id));
OcsShareJob *job = new OcsShareJob("DELETE", url, _account, this);
connect(job, SIGNAL(jobFinished(QString)), this, SLOT(slotDeleteShareFetched(QString)));
connect(job, SIGNAL(jobFinished(QVariantMap)), this, SLOT(slotDeleteShareFetched(QVariantMap)));
job->start();
}
}
void ShareDialog::slotCreateShareFetched(const QString &reply)
void ShareDialog::slotCreateShareFetched(const QVariantMap &reply)
{
QString message;
int code = checkJsonReturnCode(reply, message);
int code = getJsonReturnCode(reply, message);
_pi_link->stopAnimation();
if (code == 403) {
// there needs to be a password
_ui->checkBox_password->setChecked(true);
_ui->checkBox_password->setVisible(false);
_ui->checkBox_password->setText(tr("Public sh&aring requires a password:"));
_ui->checkBox_password->setEnabled(false);
_ui->checkBox_password->setText(tr("Public sh&aring requires a password"));
_ui->lineEdit_password->setFocus();
_ui->pushButton_copy->hide();
_ui->widget_shareLink->show();
slotCheckBoxPasswordClicked();
@@ -455,9 +457,8 @@ void ShareDialog::slotCreateShareFetched(const QString &reply)
return;
}
bool success;
QVariantMap json = QtJson::parse(reply, success).toMap();
_public_share_id = json.value("ocs").toMap().values("data")[0].toMap().value("id").toULongLong();
_public_share_id = reply.value("ocs").toMap().values("data")[0].toMap().value("id").toULongLong();
_ui->pushButton_copy->show();
getShares();
}
@@ -466,7 +467,7 @@ void ShareDialog::slotCheckBoxPasswordClicked()
if (_ui->checkBox_password->checkState() == Qt::Checked) {
_ui->lineEdit_password->show();
_ui->pushButton_setPassword->show();
_ui->lineEdit_password->setPlaceholderText(tr("Choose a password for the public link"));
_ui->lineEdit_password->setPlaceholderText(tr("Password"));
_ui->lineEdit_password->setFocus();
} else {
ShareDialog::setPassword(QString());
@@ -500,22 +501,6 @@ void ShareDialog::slotPushButtonCopyLinkPressed()
clipboard->setText(_shareUrl);
}
int ShareDialog::checkJsonReturnCode(const QString &reply, QString &message)
{
bool success;
QVariantMap json = QtJson::parse(reply, success).toMap();
if (!success) {
qDebug() << Q_FUNC_INFO << "Failed to parse reply";
}
//TODO proper checking
int code = json.value("ocs").toMap().value("meta").toMap().value("statuscode").toInt();
message = json.value("ocs").toMap().value("meta").toMap().value("message").toString();
return code;
}
void ShareDialog::setShareCheckBoxTitle(bool haveShares)
{
const QString noSharesTitle(tr("&Share link"));
@@ -672,6 +657,7 @@ OcsShareJob::OcsShareJob(const QByteArray &verb, const QUrl &url, AccountPtr acc
_verb(verb),
_url(url)
{
_passStatusCodes.append(100);
setIgnoreCredentialFailure(true);
}
@@ -680,6 +666,11 @@ void OcsShareJob::setPostParams(const QList<QPair<QString, QString> >& postParam
_postParams = postParams;
}
void OcsShareJob::addPassStatusCode(int code)
{
_passStatusCodes.append(code);
}
void OcsShareJob::start()
{
QNetworkRequest req;
@@ -711,7 +702,23 @@ void OcsShareJob::start()
bool OcsShareJob::finished()
{
emit jobFinished(reply()->readAll());
const QString replyData = reply()->readAll();
bool success;
QVariantMap json = QtJson::parse(replyData, success).toMap();
if (!success) {
qDebug() << "Could not parse reply to" << _verb << _url << _postParams
<< ":" << replyData;
}
QString message;
const int statusCode = getJsonReturnCode(json, message);
if (!_passStatusCodes.contains(statusCode)) {
qDebug() << "Reply to" << _verb << _url << _postParams
<< "has unexpected status code:" << statusCode << replyData;
}
emit jobFinished(json);
return true;
}
+8 -7
Ver Arquivo
@@ -29,17 +29,19 @@ public:
explicit OcsShareJob(const QByteArray& verb, const QUrl& url, AccountPtr account, QObject* parent = 0);
void setPostParams(const QList<QPair<QString, QString> >& postParams);
void addPassStatusCode(int code);
public slots:
void start() Q_DECL_OVERRIDE;
signals:
void jobFinished(QString reply);
void jobFinished(QVariantMap reply);
private slots:
virtual bool finished() Q_DECL_OVERRIDE;
private:
QByteArray _verb;
QUrl _url;
QList<QPair<QString, QString> > _postParams;
QVector<int> _passStatusCodes;
};
@@ -62,11 +64,11 @@ public:
void getShares();
private slots:
void slotSharesFetched(const QString &reply);
void slotCreateShareFetched(const QString &reply);
void slotDeleteShareFetched(const QString &reply);
void slotPasswordSet(const QString &reply);
void slotExpireSet(const QString &reply);
void slotSharesFetched(const QVariantMap &reply);
void slotCreateShareFetched(const QVariantMap &reply);
void slotDeleteShareFetched(const QVariantMap &reply);
void slotPasswordSet(const QVariantMap &reply);
void slotExpireSet(const QVariantMap &reply);
void slotCalendarClicked(const QDate &date);
void slotCheckBoxShareLinkClicked();
void slotCheckBoxPasswordClicked();
@@ -101,7 +103,6 @@ private:
qulonglong _public_share_id;
void setPassword(const QString &password);
void setExpireDate(const QDate &date);
int checkJsonReturnCode(const QString &reply, QString &message);
QProgressIndicator *_pi_link;
QProgressIndicator *_pi_password;
+20 -2
Ver Arquivo
@@ -111,15 +111,33 @@ SparkleUpdater::~SparkleUpdater()
delete d;
}
bool autoUpdaterAllowed()
{
// See https://github.com/owncloud/client/issues/2931
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSString *expectedPath = [NSString stringWithFormat:@"/Applications/%@", [bundlePath lastPathComponent]];
if ([expectedPath isEqualTo:bundlePath]) {
return true;
}
qWarning() << "ERROR: We are not in /Applications, won't check for update!";
return false;
}
void SparkleUpdater::checkForUpdate()
{
[d->updater checkForUpdates: NSApp];
if (autoUpdaterAllowed()) {
[d->updater checkForUpdates: NSApp];
}
}
void SparkleUpdater::backgroundCheckForUpdate()
{
qDebug() << Q_FUNC_INFO << "launching background check";
[d->updater checkForUpdatesInBackground];
if (autoUpdaterAllowed()) {
[d->updater checkForUpdatesInBackground];
}
}
} // namespace OCC
+3
Ver Arquivo
@@ -57,6 +57,9 @@
<property name="text">
<string>Error Label</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
+2 -1
Ver Arquivo
@@ -61,6 +61,7 @@ OwncloudSetupPage::OwncloudSetupPage(QWidget *parent)
setupCustomization();
slotUrlChanged(QLatin1String("")); // don't jitter UI
connect(_ui.leUrl, SIGNAL(textChanged(QString)), SLOT(slotUrlChanged(QString)));
connect(_ui.leUrl, SIGNAL(editingFinished()), SLOT(slotUrlEditFinished()));
@@ -115,7 +116,7 @@ void OwncloudSetupPage::slotUrlChanged(const QString& url)
_ui.leUrl->setText(newUrl);
}
if (url.startsWith(QLatin1String("http://"))) {
if (!url.startsWith(QLatin1String("https://"))) {
_ui.urlLabel->setPixmap(QPixmap(Theme::hidpiFileName(":/client/resources/lock-http.png")));
_ui.urlLabel->setToolTip(tr("This url is NOT secure as it is not encrypted.\n"
"It is not advisable to use it."));
+8 -2
Ver Arquivo
@@ -61,6 +61,7 @@ set(libsync_SRCS
theme.cpp
utility.cpp
ownsql.cpp
transmissionchecksumvalidator.cpp
creds/dummycredentials.cpp
creds/abstractcredentials.cpp
creds/credentialsfactory.cpp
@@ -141,6 +142,11 @@ if(NEON_FOUND)
endif()
endif()
if(ZLIB_FOUND)
list(APPEND libsync_LINK_TARGETS ${ZLIB_LIBRARIES})
include_directories(${ZLIB_INCLUDE_DIRS})
endif(ZLIB_FOUND)
add_library(${synclib_NAME} SHARED ${libsync_SRCS} ${syncMoc})
GENERATE_EXPORT_HEADER( ${synclib_NAME}
BASE_NAME ${synclib_NAME}
@@ -151,9 +157,9 @@ GENERATE_EXPORT_HEADER( ${synclib_NAME}
if(TOKEN_AUTH_ONLY)
qt5_use_modules(${synclib_NAME} Network)
qt5_use_modules(${synclib_NAME} Network Concurrent)
else()
qt5_use_modules(${synclib_NAME} Widgets Network WebKitWidgets)
qt5_use_modules(${synclib_NAME} Widgets Network WebKitWidgets Concurrent)
endif()
set_target_properties( ${synclib_NAME} PROPERTIES
+23 -1
Ver Arquivo
@@ -279,7 +279,19 @@ QList<QNetworkCookie> Account::lastAuthCookies() const
void Account::clearCookieJar()
{
_am->setCookieJar(new CookieJar);
Q_ASSERT(qobject_cast<CookieJar*>(_am->cookieJar()));
static_cast<CookieJar*>(_am->cookieJar())->clearSessionCookies();
}
/*! This shares our official cookie jar (containing all the tasty
authentication cookies) with another QNAM while making sure
of not loosing its ownership. */
void Account::lendCookieJarTo(QNetworkAccessManager *guest)
{
auto jar = _am->cookieJar();
auto oldParent = jar->parent();
guest->setCookieJar(jar); // takes ownership of our precious cookie jar
jar->setParent(oldParent); // takes it back
}
void Account::resetNetworkAccessManager()
@@ -400,6 +412,11 @@ void Account::addApprovedCerts(const QList<QSslCertificate> certs)
_approvedCerts += certs;
}
void Account::resetSslCertErrorState()
{
_treatSslErrorsAsFailure = false;
}
void Account::setSslErrorHandler(AbstractSslErrorHandler *handler)
{
_sslErrorHandler.reset(handler);
@@ -498,6 +515,11 @@ void Account::slotHandleErrors(QNetworkReply *reply , QList<QSslError> errors)
reply->ignoreSslErrors();
} else {
_treatSslErrorsAsFailure = true;
// if during normal operation, a new certificate was MITM'ed, and the user does not
// ACK it, the running request must be aborted and the QNAM must be reset, to not
// treat the new cert as granted. See bug #3283
reply->abort();
resetNetworkAccessManager();
return;
}
}
+6
Ver Arquivo
@@ -132,6 +132,11 @@ public:
void setApprovedCerts(const QList<QSslCertificate> certs);
void addApprovedCerts(const QList<QSslCertificate> certs);
// Usually when a user explicitly rejects a certificate we don't
// ask again. After this call, a dialog will again be shown when
// the next unknown certificate is encountered.
void resetSslCertErrorState();
// pluggable handler
void setSslErrorHandler(AbstractSslErrorHandler *handler);
@@ -155,6 +160,7 @@ public:
QString serverVersion();
void clearCookieJar();
void lendCookieJarTo(QNetworkAccessManager *guest);
void resetNetworkAccessManager();
QNetworkAccessManager* networkAccessManager();
+31 -31
Ver Arquivo
@@ -90,7 +90,7 @@ BandwidthManager::~BandwidthManager()
void BandwidthManager::registerUploadDevice(UploadDevice *p)
{
qDebug() << Q_FUNC_INFO << p;
//qDebug() << Q_FUNC_INFO << p;
_absoluteUploadDeviceList.append(p);
_relativeUploadDeviceList.append(p);
QObject::connect(p, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterUploadDevice(QObject*)));
@@ -117,7 +117,7 @@ void BandwidthManager::unregisterUploadDevice(QObject *o)
void BandwidthManager::unregisterUploadDevice(UploadDevice* p)
{
qDebug() << Q_FUNC_INFO << p;
//qDebug() << Q_FUNC_INFO << p;
_absoluteUploadDeviceList.removeAll(p);
_relativeUploadDeviceList.removeAll(p);
if (p == _relativeLimitCurrentMeasuredDevice) {
@@ -128,7 +128,7 @@ void BandwidthManager::unregisterUploadDevice(UploadDevice* p)
void BandwidthManager::registerDownloadJob(GETFileJob* j)
{
qDebug() << Q_FUNC_INFO << j;
//qDebug() << Q_FUNC_INFO << j;
_downloadJobList.append(j);
QObject::connect(j, SIGNAL(destroyed(QObject*)), this, SLOT(unregisterDownloadJob(QObject*)));
@@ -176,19 +176,19 @@ void BandwidthManager::relativeUploadMeasuringTimerExpired()
return;
}
qDebug() << Q_FUNC_INFO << _relativeUploadDeviceList.count() << "Starting Delay";
// qDebug() << Q_FUNC_INFO << _relativeUploadDeviceList.count() << "Starting Delay";
qint64 relativeLimitProgressMeasured = (_relativeLimitCurrentMeasuredDevice->_readWithProgress
+ _relativeLimitCurrentMeasuredDevice->_read) / 2;
qint64 relativeLimitProgressDifference = relativeLimitProgressMeasured - _relativeUploadLimitProgressAtMeasuringRestart;
qDebug() << Q_FUNC_INFO << _relativeUploadLimitProgressAtMeasuringRestart
<< relativeLimitProgressMeasured << relativeLimitProgressDifference;
// qDebug() << Q_FUNC_INFO << _relativeUploadLimitProgressAtMeasuringRestart
// << relativeLimitProgressMeasured << relativeLimitProgressDifference;
qint64 speedkBPerSec = (relativeLimitProgressDifference / relativeLimitMeasuringTimerIntervalMsec*1000.0) / 1024.0;
qDebug() << Q_FUNC_INFO << relativeLimitProgressDifference/1024 <<"kB =>" << speedkBPerSec << "kB/sec on full speed ("
<< _relativeLimitCurrentMeasuredDevice->_readWithProgress << _relativeLimitCurrentMeasuredDevice->_read
<< qAbs(_relativeLimitCurrentMeasuredDevice->_readWithProgress
- _relativeLimitCurrentMeasuredDevice->_read) << ")";
// qint64 speedkBPerSec = (relativeLimitProgressDifference / relativeLimitMeasuringTimerIntervalMsec*1000.0) / 1024.0;
// qDebug() << Q_FUNC_INFO << relativeLimitProgressDifference/1024 <<"kB =>" << speedkBPerSec << "kB/sec on full speed ("
// << _relativeLimitCurrentMeasuredDevice->_readWithProgress << _relativeLimitCurrentMeasuredDevice->_read
// << qAbs(_relativeLimitCurrentMeasuredDevice->_readWithProgress
// - _relativeLimitCurrentMeasuredDevice->_read) << ")";
qint64 uploadLimitPercent = -_currentUploadLimit;
// don't use too extreme values
@@ -197,9 +197,9 @@ void BandwidthManager::relativeUploadMeasuringTimerExpired()
qint64 wholeTimeMsec = (100.0 / uploadLimitPercent) * relativeLimitMeasuringTimerIntervalMsec;
qint64 waitTimeMsec = wholeTimeMsec - relativeLimitMeasuringTimerIntervalMsec;
qint64 realWaitTimeMsec = waitTimeMsec + wholeTimeMsec;
qDebug() << Q_FUNC_INFO << waitTimeMsec << " - "<< realWaitTimeMsec <<
" msec for " << uploadLimitPercent << "%";
qDebug() << Q_FUNC_INFO << "XXXX" << uploadLimitPercent << relativeLimitMeasuringTimerIntervalMsec;
// qDebug() << Q_FUNC_INFO << waitTimeMsec << " - "<< realWaitTimeMsec <<
// " msec for " << uploadLimitPercent << "%";
// qDebug() << Q_FUNC_INFO << "XXXX" << uploadLimitPercent << relativeLimitMeasuringTimerIntervalMsec;
// We want to wait twice as long since we want to give all
// devices the same quota we used now since we don't want
@@ -209,12 +209,12 @@ void BandwidthManager::relativeUploadMeasuringTimerExpired()
int deviceCount = _relativeUploadDeviceList.count();
qint64 quotaPerDevice = relativeLimitProgressDifference * (uploadLimitPercent / 100.0) / deviceCount + 1.0;
qDebug() << Q_FUNC_INFO << "YYYY" << relativeLimitProgressDifference << uploadLimitPercent << deviceCount;
// qDebug() << Q_FUNC_INFO << "YYYY" << relativeLimitProgressDifference << uploadLimitPercent << deviceCount;
Q_FOREACH(UploadDevice *ud, _relativeUploadDeviceList) {
ud->setBandwidthLimited(true);
ud->setChoked(false);
ud->giveBandwidthQuota(quotaPerDevice);
qDebug() << Q_FUNC_INFO << "Gave" << quotaPerDevice/1024.0 << "kB to" << ud;
// qDebug() << Q_FUNC_INFO << "Gave" << quotaPerDevice/1024.0 << "kB to" << ud;
}
_relativeLimitCurrentMeasuredDevice = 0;
}
@@ -232,7 +232,7 @@ void BandwidthManager::relativeUploadDelayTimerExpired()
return;
}
qDebug() << Q_FUNC_INFO << _relativeUploadDeviceList.count() << "Starting measuring";
// qDebug() << Q_FUNC_INFO << _relativeUploadDeviceList.count() << "Starting measuring";
// Take first device and then append it again (= we round robin all devices)
_relativeLimitCurrentMeasuredDevice = _relativeUploadDeviceList.takeFirst();
@@ -270,16 +270,16 @@ void BandwidthManager::relativeDownloadMeasuringTimerExpired()
return;
}
qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "Starting Delay";
// qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "Starting Delay";
qint64 relativeLimitProgressMeasured = _relativeLimitCurrentMeasuredJob->currentDownloadPosition();
qint64 relativeLimitProgressDifference = relativeLimitProgressMeasured - _relativeDownloadLimitProgressAtMeasuringRestart;
qDebug() << Q_FUNC_INFO << _relativeDownloadLimitProgressAtMeasuringRestart
<< relativeLimitProgressMeasured << relativeLimitProgressDifference;
qint64 speedkBPerSec = (relativeLimitProgressDifference / relativeLimitMeasuringTimerIntervalMsec*1000.0) / 1024.0;
qDebug() << Q_FUNC_INFO << relativeLimitProgressDifference/1024 <<"kB =>" << speedkBPerSec << "kB/sec on full speed ("
<< _relativeLimitCurrentMeasuredJob->currentDownloadPosition() ;
// qint64 speedkBPerSec = (relativeLimitProgressDifference / relativeLimitMeasuringTimerIntervalMsec*1000.0) / 1024.0;
// qDebug() << Q_FUNC_INFO << relativeLimitProgressDifference/1024 <<"kB =>" << speedkBPerSec << "kB/sec on full speed ("
// << _relativeLimitCurrentMeasuredJob->currentDownloadPosition() ;
qint64 downloadLimitPercent = -_currentDownloadLimit;
// don't use too extreme values
@@ -288,9 +288,9 @@ void BandwidthManager::relativeDownloadMeasuringTimerExpired()
qint64 wholeTimeMsec = (100.0 / downloadLimitPercent) * relativeLimitMeasuringTimerIntervalMsec;
qint64 waitTimeMsec = wholeTimeMsec - relativeLimitMeasuringTimerIntervalMsec;
qint64 realWaitTimeMsec = waitTimeMsec + wholeTimeMsec;
qDebug() << Q_FUNC_INFO << waitTimeMsec << " - "<< realWaitTimeMsec <<
" msec for " << downloadLimitPercent << "%";
qDebug() << Q_FUNC_INFO << "XXXX" << downloadLimitPercent << relativeLimitMeasuringTimerIntervalMsec;
// qDebug() << Q_FUNC_INFO << waitTimeMsec << " - "<< realWaitTimeMsec <<
// " msec for " << downloadLimitPercent << "%";
// qDebug() << Q_FUNC_INFO << "XXXX" << downloadLimitPercent << relativeLimitMeasuringTimerIntervalMsec;
// We want to wait twice as long since we want to give all
// devices the same quota we used now since we don't want
@@ -305,12 +305,12 @@ void BandwidthManager::relativeDownloadMeasuringTimerExpired()
// quota -= 20*1024;
// }
qint64 quotaPerJob = quota / jobCount + 1.0;
qDebug() << Q_FUNC_INFO << "YYYY" << relativeLimitProgressDifference << downloadLimitPercent << jobCount;
// qDebug() << Q_FUNC_INFO << "YYYY" << relativeLimitProgressDifference << downloadLimitPercent << jobCount;
Q_FOREACH(GETFileJob *gfj, _downloadJobList) {
gfj->setBandwidthLimited(true);
gfj->setChoked(false);
gfj->giveBandwidthQuota(quotaPerJob);
qDebug() << Q_FUNC_INFO << "Gave" << quotaPerJob/1024.0 << "kB to" << gfj;
// qDebug() << Q_FUNC_INFO << "Gave" << quotaPerJob/1024.0 << "kB to" << gfj;
}
_relativeLimitCurrentMeasuredDevice = 0;
}
@@ -329,7 +329,7 @@ void BandwidthManager::relativeDownloadDelayTimerExpired()
return;
}
qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "Starting measuring";
// qDebug() << Q_FUNC_INFO << _downloadJobList.count() << "Starting measuring";
// Take first device and then append it again (= we round robin all devices)
_relativeLimitCurrentMeasuredJob = _downloadJobList.takeFirst();
@@ -393,18 +393,18 @@ void BandwidthManager::absoluteLimitTimerExpired()
{
if (usingAbsoluteUploadLimit() && _absoluteUploadDeviceList.count() > 0) {
qint64 quotaPerDevice = _currentUploadLimit / qMax(1, _absoluteUploadDeviceList.count());
qDebug() << Q_FUNC_INFO << quotaPerDevice << _absoluteUploadDeviceList.count() << _currentUploadLimit;
// qDebug() << Q_FUNC_INFO << quotaPerDevice << _absoluteUploadDeviceList.count() << _currentUploadLimit;
Q_FOREACH(UploadDevice *device, _absoluteUploadDeviceList) {
device->giveBandwidthQuota(quotaPerDevice);
qDebug() << Q_FUNC_INFO << "Gave " << quotaPerDevice/1024.0 << " kB to" << device;
// qDebug() << Q_FUNC_INFO << "Gave " << quotaPerDevice/1024.0 << " kB to" << device;
}
}
if (usingAbsoluteDownloadLimit() && _downloadJobList.count() > 0) {
qint64 quotaPerJob = _currentDownloadLimit / qMax(1, _downloadJobList.count());
qDebug() << Q_FUNC_INFO << quotaPerJob << _downloadJobList.count() << _currentDownloadLimit;
// qDebug() << Q_FUNC_INFO << quotaPerJob << _downloadJobList.count() << _currentDownloadLimit;
Q_FOREACH(GETFileJob *j, _downloadJobList) {
j->giveBandwidthQuota(quotaPerJob);
qDebug() << Q_FUNC_INFO << "Gave " << quotaPerJob/1024.0 << " kB to" << j;
// qDebug() << Q_FUNC_INFO << "Gave " << quotaPerJob/1024.0 << " kB to" << j;
}
}
}
+15
Ver Arquivo
@@ -49,6 +49,7 @@ static const char optionalDesktopNoficationsC[] = "optionalDesktopNotifications"
static const char skipUpdateCheckC[] = "skipUpdateCheck";
static const char geometryC[] = "geometry";
static const char timeoutC[] = "timeout";
static const char transmissionChecksumC[] = "transmissionChecksum";
static const char proxyHostC[] = "Proxy/host";
static const char proxyTypeC[] = "Proxy/type";
@@ -118,6 +119,20 @@ int ConfigFile::timeout() const
return settings.value(QLatin1String(timeoutC), 300).toInt(); // default to 5 min
}
QString ConfigFile::transmissionChecksum() const
{
QSettings settings(configFile(), QSettings::IniFormat);
QString checksum = settings.value(QLatin1String(transmissionChecksumC), QString()).toString();
if( checksum.isEmpty() ) {
// if the config file setting is empty, maybe the Branding requires it.
checksum = Theme::instance()->transmissionChecksum();
}
return checksum;
}
void ConfigFile::setOptionalDesktopNotifications(bool show)
{
QSettings settings(configFile(), QSettings::IniFormat);
+6
Ver Arquivo
@@ -103,6 +103,12 @@ public:
int timeout() const;
// send a checksum as a header along with the transmission or not.
// possible values:
// empty: no checksum calculated or expected.
// or "Adler32", "MD5", "SHA1"
QString transmissionChecksum() const;
void saveGeometry(QWidget *w);
void restoreGeometry(QWidget *w);
+5 -10
Ver Arquivo
@@ -48,8 +48,8 @@ QString ConnectionValidator::statusString( Status stat )
return QLatin1String("Status not found");
case UserCanceledCredentials:
return QLatin1String("User canceled credentials");
case ServerMaintenance:
return QLatin1String("Server in maintenance mode");
case ServiceUnavailable:
return QLatin1String("Service unavailable");
case Timeout:
return QLatin1String("Timeout");
}
@@ -187,18 +187,13 @@ void ConnectionValidator::slotAuthFailed(QNetworkReply *reply)
stat = CredentialsWrong;
} else if( reply->error() != QNetworkReply::NoError ) {
_errors << reply->errorString();
_errors << errorMessage(reply->errorString(), reply->readAll());
const int httpStatus =
reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if ( httpStatus == 503 ) {
// Is this a maintenance mode reply from the server
// or a regular 503 from somewhere else?
QByteArray body = reply->readAll();
if ( body.contains("Sabre\\DAV\\Exception\\ServiceUnavailable") ) {
_errors.clear();
stat = ServerMaintenance;
}
_errors.clear();
stat = ServiceUnavailable;
}
}
+1 -1
Ver Arquivo
@@ -77,7 +77,7 @@ public:
CredentialsWrong,
StatusNotFound,
UserCanceledCredentials,
ServerMaintenance,
ServiceUnavailable,
// actually also used for other errors on the authed request
Timeout
};
@@ -47,13 +47,14 @@ ShibbolethWebView::ShibbolethWebView(AccountPtr account, QWidget* parent)
setAttribute(Qt::WA_DeleteOnClose);
QWebPage* page = new QWebPage(this);
page->setNetworkAccessManager(account->networkAccessManager());
connect(page, SIGNAL(loadStarted()),
this, SLOT(slotLoadStarted()));
connect(page, SIGNAL(loadFinished(bool)),
this, SLOT(slotLoadFinished(bool)));
// The Account keeps ownership of the cookie jar, it must outlive this webview.
account->lendCookieJarTo(page->networkAccessManager());
connect(page->networkAccessManager()->cookieJar(),
SIGNAL(newCookiesForUrl (QList<QNetworkCookie>, QUrl)),
this, SLOT(onNewCookiesForUrl (QList<QNetworkCookie>, QUrl)));
+104 -1
Ver Arquivo
@@ -16,7 +16,13 @@
#include "utility.h"
#include <QFile>
#include <QFileInfo>
#include <QCoreApplication>
#include <QDebug>
#include <QCryptographicHash>
#ifdef ZLIB_FOUND
#include <zlib.h>
#endif
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
#include <qabstractfileengine.h>
@@ -155,7 +161,50 @@ bool FileSystem::rename(const QString &originFileName,
return success;
}
bool FileSystem::renameReplace(const QString& originFileName, const QString& destinationFileName, QString* errorString)
bool FileSystem::fileChanged(const QString& fileName,
qint64 previousSize,
time_t previousMtime)
{
return getSize(fileName) != previousSize
|| getModTime(fileName) != previousMtime;
}
bool FileSystem::verifyFileUnchanged(const QString& fileName,
qint64 previousSize,
time_t previousMtime)
{
const qint64 actualSize = getSize(fileName);
const time_t actualMtime = getModTime(fileName);
if (actualSize != previousSize || actualMtime != previousMtime) {
qDebug() << "File" << fileName << "has changed:"
<< "size: " << previousSize << "<->" << actualSize
<< ", mtime: " << previousMtime << "<->" << actualMtime;
return false;
}
return true;
}
bool FileSystem::renameReplace(const QString& originFileName,
const QString& destinationFileName,
qint64 destinationSize,
time_t destinationMtime,
QString* errorString)
{
if (fileExists(destinationFileName)
&& fileChanged(destinationFileName, destinationSize, destinationMtime)) {
if (errorString) {
*errorString = qApp->translate("FileSystem",
"The destination file has an unexpected size or modification time");
}
return false;
}
return uncheckedRenameReplace(originFileName, destinationFileName, errorString);
}
bool FileSystem::uncheckedRenameReplace(const QString& originFileName,
const QString& destinationFileName,
QString* errorString)
{
#ifndef Q_OS_WIN
bool success;
@@ -350,4 +399,58 @@ QString FileSystem::fileSystemForPath(const QString & path)
}
#endif
#define BUFSIZE 1024*1024*10
static QByteArray readToCrypto( const QString& filename, QCryptographicHash::Algorithm algo )
{
const qint64 bufSize = BUFSIZE;
QByteArray buf(bufSize,0);
QByteArray arr;
QCryptographicHash crypto( algo );
QFile file(filename);
if (file.open(QIODevice::ReadOnly)) {
qint64 size;
while (!file.atEnd()) {
size = file.read( buf.data(), bufSize );
if( size > 0 ) {
crypto.addData(buf.data(), size);
}
}
arr = crypto.result().toHex();
}
return arr;
}
QByteArray FileSystem::calcMd5( const QString& filename )
{
return readToCrypto( filename, QCryptographicHash::Md5 );
}
QByteArray FileSystem::calcSha1( const QString& filename )
{
return readToCrypto( filename, QCryptographicHash::Sha1 );
}
#ifdef ZLIB_FOUND
QByteArray FileSystem::calcAdler32( const QString& filename )
{
unsigned int adler = adler32(0L, Z_NULL, 0);
const qint64 bufSize = BUFSIZE;
QByteArray buf(bufSize, 0);
QFile file(filename);
if (file.open(QIODevice::ReadOnly)) {
qint64 size;
while (!file.atEnd()) {
size = file.read(buf.data(), bufSize);
if( size > 0 )
adler = adler32(adler, (const Bytef*) buf.data(), size);
}
}
return QByteArray::number( adler, 16 );
}
#endif
} // namespace OCC
+43 -3
Ver Arquivo
@@ -13,8 +13,11 @@
#pragma once
#include "config.h"
#include <QString>
#include <ctime>
#include <QCryptographicHash>
#include <owncloudlib.h>
@@ -67,13 +70,44 @@ bool OWNCLOUDSYNC_EXPORT fileExists(const QString& filename);
bool OWNCLOUDSYNC_EXPORT rename(const QString& originFileName,
const QString& destinationFileName,
QString* errorString = NULL);
/**
* Rename the file \a originFileName to \a destinationFileName, and overwrite the destination if it
* already exists
* Returns true if the file's mtime or size are not what is expected.
* Nonexisting files are covered through mtime: they have an mtime of -1.
*/
bool renameReplace(const QString &originFileName, const QString &destinationFileName,
bool fileChanged(const QString& fileName,
qint64 previousSize,
time_t previousMtime);
/**
* Like !fileChanged() but with verbose logging if the file *did* change.
*/
bool verifyFileUnchanged(const QString& fileName,
qint64 previousSize,
time_t previousMtime);
/**
* Rename the file \a originFileName to \a destinationFileName, and
* overwrite the destination if it already exists - as long as the
* destination file has the expected \a destinationSize and
* \a destinationMtime.
* If the destination file does not exist, the given size and mtime are
* ignored.
*/
bool renameReplace(const QString &originFileName,
const QString &destinationFileName,
qint64 destinationSize,
time_t destinationMtime,
QString *errorString);
/**
* Rename the file \a originFileName to \a destinationFileName, and
* overwrite the destination if it already exists - without extra checks.
*/
bool uncheckedRenameReplace(const QString &originFileName,
const QString &destinationFileName,
QString *errorString);
/**
* Replacement for QFile::open(ReadOnly) followed by a seek().
* This version sets a more permissive sharing mode on Windows.
@@ -90,4 +124,10 @@ bool openAndSeekFileSharedRead(QFile* file, QString* error, qint64 seek);
QString fileSystemForPath(const QString & path);
#endif
QByteArray OWNCLOUDSYNC_EXPORT calcMd5( const QString& fileName );
QByteArray OWNCLOUDSYNC_EXPORT calcSha1( const QString& fileName );
#ifdef ZLIB_FOUND
QByteArray OWNCLOUDSYNC_EXPORT calcAdler32( const QString& fileName );
#endif
}}
+41 -6
Ver Arquivo
@@ -43,7 +43,6 @@ namespace OCC {
AbstractNetworkJob::AbstractNetworkJob(AccountPtr account, const QString &path, QObject *parent)
: QObject(parent)
, _duration(0)
, _timedout(false)
, _followRedirects(false)
, _ignoreCredentialFailure(false)
@@ -307,8 +306,12 @@ MkColJob::MkColJob(AccountPtr account, const QString &path, QObject *parent)
void MkColJob::start()
{
// assumes ownership
QNetworkReply *reply = davRequest("MKCOL", path());
// add 'Content-Length: 0' header (see https://github.com/owncloud/client/issues/3256)
QNetworkRequest req;
req.setRawHeader("Content-Length", "0");
// assumes ownership
QNetworkReply *reply = davRequest("MKCOL", path(), req);
setReply(reply);
setupConnections(reply);
AbstractNetworkJob::start();
@@ -350,7 +353,7 @@ LsColXMLParser::LsColXMLParser()
}
bool LsColXMLParser::parse( const QByteArray& xml, QHash<QString, qint64> *sizes)
bool LsColXMLParser::parse( const QByteArray& xml, QHash<QString, qint64> *sizes, const QString& expectedPath)
{
// Parse DAV response
QXmlStreamReader reader(xml);
@@ -371,7 +374,14 @@ bool LsColXMLParser::parse( const QByteArray& xml, QHash<QString, qint64> *sizes
// Start elements with DAV:
if (type == QXmlStreamReader::StartElement && reader.namespaceUri() == QLatin1String("DAV:")) {
if (name == QLatin1String("href")) {
currentHref = QUrl::fromPercentEncoding(reader.readElementText().toUtf8());
// We don't use URL encoding in our request URL (which is the expected path) (QNAM will do it for us)
// but the result will have URL encoding..
QString hrefString = QString::fromUtf8(QByteArray::fromPercentEncoding(reader.readElementText().toUtf8()));
if (!hrefString.startsWith(expectedPath)) {
qDebug() << "Invalid href" << hrefString << "expected starting with" << expectedPath;
return false;
}
currentHref = hrefString;
} else if (name == QLatin1String("response")) {
} else if (name == QLatin1String("propstat")) {
insidePropstat = true;
@@ -520,7 +530,8 @@ bool LsColJob::finished()
connect( &parser, SIGNAL(finishedWithoutError()),
this, SIGNAL(finishedWithoutError()) );
if( !parser.parse( reply()->readAll(), &_sizes ) ) {
QString expectedPath = reply()->request().url().path(); // something like "/owncloud/remote.php/webdav/folder"
if( !parser.parse( reply()->readAll(), &_sizes, expectedPath ) ) {
// XML parse error
emit finishedWithError(reply());
}
@@ -840,7 +851,31 @@ bool JsonApiJob::finished()
return true;
}
QString extractErrorMessage(const QByteArray& errorResponse)
{
QXmlStreamReader reader(errorResponse);
reader.readNextStartElement();
if (reader.name() != "error") {
return QString::null;
}
while (!reader.atEnd() && reader.error() == QXmlStreamReader::NoError) {
reader.readNextStartElement();
if (reader.name() == QLatin1String("message")) {
return reader.readElementText();
}
}
return QString::null;
}
QString errorMessage(const QString& baseError, const QByteArray& body)
{
QString msg = baseError;
QString extra = extractErrorMessage(body);
if (!extra.isEmpty()) {
msg += QString::fromLatin1(" (%1)").arg(extra);
}
return msg;
}
} // namespace OCC
+12 -1
Ver Arquivo
@@ -137,7 +137,7 @@ class OWNCLOUDSYNC_EXPORT LsColXMLParser : public QObject {
public:
explicit LsColXMLParser();
bool parse(const QByteArray &xml, QHash<QString, qint64> *sizes);
bool parse(const QByteArray &xml, QHash<QString, qint64> *sizes, const QString& expectedPath);
signals:
void directoryListingSubfolders(const QStringList &items);
@@ -314,6 +314,17 @@ signals:
void jsonRecieved(const QVariantMap &json);
};
/** Gets the SabreDAV-style error message from an error response.
*
* This assumes the response is XML with a 'error' tag that has a
* 'message' tag that contains the data to extract.
*
* Returns a null string if no message was found.
*/
QString OWNCLOUDSYNC_EXPORT extractErrorMessage(const QByteArray& errorResponse);
/** Builds a error message based on the error and the reply body. */
QString OWNCLOUDSYNC_EXPORT errorMessage(const QString& baseError, const QByteArray& body);
} // namespace OCC
+19 -4
Ver Arquivo
@@ -259,6 +259,21 @@ void OwncloudPropagator::start(const SyncFileItemVector& items)
{
Q_ASSERT(std::is_sorted(items.begin(), items.end()));
/* Check and log the transmission checksum type */
ConfigFile cfg;
const QString checksumType = cfg.transmissionChecksum().toUpper();
/* if the checksum type is empty, it is not send. No error */
if( !checksumType.isEmpty() ) {
if( checksumType == checkSumAdlerUpperC ||
checksumType == checkSumMD5C ||
checksumType == checkSumSHA1C ) {
qDebug() << "Client sends and expects transmission checksum type" << checksumType;
} else {
qWarning() << "Unknown transmission checksum type from config" << checksumType;
}
}
/* This builds all the job needed for the propagation.
* Each directories is a PropagateDirectory job, which contains the files in it.
* In order to do that we loop over the items. (which are sorted by destination)
@@ -649,10 +664,10 @@ void CleanupPollsJob::start()
auto info = _pollInfos.first();
_pollInfos.pop_front();
SyncFileItem item;
item._file = info._file;
item._modtime = info._modtime;
PollJob *job = new PollJob(_account, info._url, item, _journal, _localPath, this);
_item = SyncFileItem();
_item._file = info._file;
_item._modtime = info._modtime;
PollJob *job = new PollJob(_account, info._url, _item, _journal, _localPath, this);
connect(job, SIGNAL(finishedSignal()), SLOT(slotPollFinished()));
job->start();
}
+1
Ver Arquivo
@@ -356,6 +356,7 @@ class CleanupPollsJob : public QObject {
AccountPtr _account;
SyncJournalDb *_journal;
QString _localPath;
SyncFileItem _item;
public:
explicit CleanupPollsJob(const QVector< SyncJournalDb::PollInfo > &pollInfos, AccountPtr account,
SyncJournalDb *journal, const QString &localPath, QObject* parent = 0)
+1 -1
Ver Arquivo
@@ -345,7 +345,7 @@ QString SqlQuery::lastQuery() const
int SqlQuery::numRowsAffected()
{
return 1;
return sqlite3_changes(_db);
}
void SqlQuery::finish()
+120 -14
Ver Arquivo
@@ -12,6 +12,7 @@
* for more details.
*/
#include "config.h"
#include "owncloudpropagator_p.h"
#include "propagatedownload.h"
#include "networkjobs.h"
@@ -21,6 +22,8 @@
#include "utility.h"
#include "filesystem.h"
#include "propagatorjobs.h"
#include "transmissionchecksumvalidator.h"
#include <json.h>
#include <QNetworkAccessManager>
#include <QFileInfo>
@@ -30,6 +33,30 @@
namespace OCC {
// Always coming in with forward slashes.
// In csync_excluded_no_ctx we ignore all files with longer than 254 chars
// This function also adds a dot at the begining of the filename to hide the file on OS X and Linux
QString OWNCLOUDSYNC_EXPORT createDownloadTmpFileName(const QString &previous) {
QString tmpFileName;
QString tmpPath;
int slashPos = previous.lastIndexOf('/');
// work with both pathed filenames and only filenames
if (slashPos == -1) {
tmpFileName = previous;
tmpPath = QString();
} else {
tmpFileName = previous.mid(slashPos+1);
tmpPath = previous.left(slashPos);
}
int overhead = 1 + 1 + 2 + 8; // slash dot dot-tilde ffffffff"
int spaceForFileName = qMin(254, tmpFileName.length() + overhead) - overhead;
if (tmpPath.length() > 0) {
return tmpPath + '/' + '.' + tmpFileName.left(spaceForFileName) + ".~" + (QString::number(uint(qrand() % 0xFFFFFFFF), 16));
} else {
return '.' + tmpFileName.left(spaceForFileName) + ".~" + (QString::number(uint(qrand() % 0xFFFFFFFF), 16));
}
}
// DOES NOT take owncership of the device.
GETFileJob::GETFileJob(AccountPtr account, const QString& path, QFile *device,
const QMap<QByteArray, QByteArray> &headers, const QByteArray &expectedEtagForResume,
@@ -307,12 +334,7 @@ void PropagateDownloadFileQNAM::start()
}
if (tmpFileName.isEmpty()) {
tmpFileName = _item._file;
//add a dot at the begining of the filename to hide the file.
int slashPos = tmpFileName.lastIndexOf('/');
tmpFileName.insert(slashPos+1, '.');
//add the suffix
tmpFileName += ".~" + QString::number(uint(qrand()), 16);
tmpFileName = createDownloadTmpFileName(_item._file);
}
_tmpFile.setFileName(_propagator->getFilePath(tmpFileName));
@@ -464,7 +486,21 @@ void PropagateDownloadFileQNAM::slotGetFinished()
return;
}
downloadFinished();
// Do checksum validation for the download. If there is no checksum header, the validator
// will also emit the validated() signal to continue the flow in slot downloadFinished()
// as this is (still) also correct.
TransmissionChecksumValidator *validator = new TransmissionChecksumValidator(_tmpFile.fileName(), this);
connect(validator, SIGNAL(validated(QByteArray)), this, SLOT(downloadFinished()));
connect(validator, SIGNAL(validationFailed(QString)), this, SLOT(slotChecksumFail(QString)));
validator->downloadValidation(job->reply()->rawHeader(checkSumHeaderC));
}
void PropagateDownloadFileQNAM::slotChecksumFail( const QString& errMsg )
{
_tmpFile.remove();
_propagator->_anotherSyncNeeded = true;
done(SyncFileItem::SoftError, errMsg ); // tr("The file downloaded with a broken checksum, will be redownloaded."));
}
QString makeConflictFileName(const QString &fn, const QDateTime &dt)
@@ -488,6 +524,52 @@ QString makeConflictFileName(const QString &fn, const QDateTime &dt)
return conflictFileName;
}
namespace { // Anonymous namespace for the recall feature
static QString makeRecallFileName(const QString &fn)
{
QString recallFileName(fn);
// Add _recall-XXXX before the extention.
int dotLocation = recallFileName.lastIndexOf('.');
// If no extention, add it at the end (take care of cases like foo/.hidden or foo.bar/file)
if (dotLocation <= recallFileName.lastIndexOf('/') + 1) {
dotLocation = recallFileName.size();
}
QString timeString = QDateTime::currentDateTime().toString("yyyyMMdd-hhmmss");
recallFileName.insert(dotLocation, "_.sys.admin#recall#-" + timeString);
return recallFileName;
}
static void handleRecallFile(const QString &fn)
{
qDebug() << "handleRecallFile: " << fn;
FileSystem::setFileHidden(fn, true);
QFile file(fn);
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "Could not open recall file" << file.errorString();
return;
}
QFileInfo existingFile(fn);
QDir thisDir = existingFile.dir();
while (!file.atEnd()) {
QByteArray line = file.readLine();
line.chop(1); // remove trailing \n
QString fpath = thisDir.filePath(line);
QString rpath = makeRecallFileName(fpath);
// if previously recalled file exists then remove it (copy will not overwrite it)
QFile(rpath).remove();
qDebug() << "Copy recall file: " << fpath << " -> " << rpath;
QFile::copy(fpath,rpath);
}
}
} // end namespace
void PropagateDownloadFileQNAM::downloadFinished()
{
QString fn = _propagator->getFilePath(_item._file);
@@ -512,11 +594,7 @@ void PropagateDownloadFileQNAM::downloadFinished()
done(SyncFileItem::SoftError, renameError);
return;
}
}
QFileInfo existingFile(fn);
if(FileSystem::fileExists(fn) && existingFile.permissions() != _tmpFile.permissions()) {
_tmpFile.setPermissions(existingFile.permissions());
qDebug() << "Created conflict file" << fn << "->" << conflictFileName;
}
FileSystem::setModTime(_tmpFile.fileName(), _item._modtime);
@@ -524,11 +602,32 @@ void PropagateDownloadFileQNAM::downloadFinished()
// Accuracy, and we really need the time from the file system. (#3103)
_item._modtime = FileSystem::getModTime(_tmpFile.fileName());
if (FileSystem::fileExists(fn)) {
// Preserve the existing file permissions.
QFileInfo existingFile(fn);
if (existingFile.permissions() != _tmpFile.permissions()) {
_tmpFile.setPermissions(existingFile.permissions());
}
// Check whether the existing file has changed since the discovery
// phase by comparing size and mtime to the previous values. This
// is necessary to avoid overwriting user changes that happened between
// the discovery phase and now.
const qint64 expectedSize = _item.log._other_size;
const time_t expectedMtime = _item.log._other_modtime;
if (! FileSystem::verifyFileUnchanged(fn, expectedSize, expectedMtime)) {
_propagator->_anotherSyncNeeded = true;
done(SyncFileItem::SoftError, tr("File has changed since discovery"));
return;
}
}
QString error;
_propagator->addTouchedFile(fn);
FileSystem::setFileHidden(_tmpFile.fileName(), false);
if (!FileSystem::renameReplace(_tmpFile.fileName(), fn, &error)) {
// The fileChanged() check is done above to generate better error messages.
if (!FileSystem::uncheckedRenameReplace(_tmpFile.fileName(), fn, &error)) {
qDebug() << Q_FUNC_INFO << QString("Rename failed: %1 => %2").arg(_tmpFile.fileName()).arg(fn);
// If we moved away the original file due to a conflict but can't
// 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
@@ -540,10 +639,12 @@ void PropagateDownloadFileQNAM::downloadFinished()
_propagator->_journal->deleteFileRecord(fn);
_propagator->_journal->commit("download finished");
}
_propagator->_anotherSyncNeeded = true;
done(SyncFileItem::SoftError, error);
return;
}
FileSystem::setFileHidden(fn, false);
// Maybe we downloaded a newer version of the file than we thought we would...
// Get up to date information for the journal.
@@ -553,6 +654,11 @@ void PropagateDownloadFileQNAM::downloadFinished()
_propagator->_journal->setDownloadInfo(_item._file, SyncJournalDb::DownloadInfo());
_propagator->_journal->commit("download file start2");
done(isConflict ? SyncFileItem::Conflict : SyncFileItem::Success);
// handle the special recall file
if(_item._file == QLatin1String(".sys.admin#recall#") || _item._file.endsWith("/.sys.admin#recall#")) {
handleRecallFile(fn);
}
}
void PropagateDownloadFileQNAM::slotDownloadProgress(qint64 received, qint64)
+6 -4
Ver Arquivo
@@ -101,19 +101,21 @@ private slots:
class PropagateDownloadFileQNAM : public PropagateItemJob {
Q_OBJECT
QPointer<GETFileJob> _job;
// QFile *_file;
QFile _tmpFile;
public:
PropagateDownloadFileQNAM(OwncloudPropagator* propagator,const SyncFileItem& item)
: PropagateItemJob(propagator, item) {}
void start() Q_DECL_OVERRIDE;
private slots:
void slotGetFinished();
void abort() Q_DECL_OVERRIDE;
void downloadFinished();
void slotDownloadProgress(qint64,qint64);
void slotChecksumFail( const QString& errMsg );
private:
QPointer<GETFileJob> _job;
QFile _tmpFile;
};
}
+7
Ver Arquivo
@@ -151,9 +151,16 @@ void PropagateRemoteMove::slotMoveJobFinished()
void PropagateRemoteMove::finalize()
{
SyncJournalFileRecord oldRecord =
_propagator->_journal->getFileRecord(_item._originalFile);
_propagator->_journal->deleteFileRecord(_item._originalFile);
SyncJournalFileRecord record(_item, _propagator->getFilePath(_item._renameTarget));
record._path = _item._renameTarget;
if (record._fileSize != oldRecord._fileSize) {
qDebug() << "Warning: file sizes differ on server vs csync_journal: " << record._fileSize << oldRecord._fileSize;
record._fileSize = oldRecord._fileSize; // server might have claimed different size, we take the old one from the DB
}
_propagator->_journal->setFileRecord(record);
_propagator->_journal->commit("Remote Rename");
+98 -17
Ver Arquivo
@@ -12,6 +12,7 @@
* for more details.
*/
#include "config.h"
#include "propagateupload.h"
#include "owncloudpropagator_p.h"
#include "networkjobs.h"
@@ -21,6 +22,8 @@
#include "utility.h"
#include "filesystem.h"
#include "propagatorjobs.h"
#include "transmissionchecksumvalidator.h"
#include <json.h>
#include <QNetworkAccessManager>
#include <QFileInfo>
@@ -32,6 +35,12 @@
#include "propagator_legacy.h"
#endif
#if QT_VERSION < QT_VERSION_CHECK(5, 4, 2)
namespace {
const char owncloudShouldSoftCancelPropertyName[] = "owncloud-should-soft-cancel";
}
#endif
namespace OCC {
/**
@@ -86,6 +95,17 @@ void PUTFileJob::start() {
connect(reply(), SIGNAL(uploadProgress(qint64,qint64)), this, SIGNAL(uploadProgress(qint64,qint64)));
connect(this, SIGNAL(networkActivity()), account().data(), SIGNAL(propagatorNetworkActivity()));
// For Qt versions not including https://codereview.qt-project.org/110150
// Also do the runtime check if compiled with an old Qt but running with fixed one.
// (workaround disabled on windows and mac because the binaries we ship have patched qt)
#if QT_VERSION < QT_VERSION_CHECK(4, 8, 7)
if (QLatin1String(qVersion()) < QLatin1String("4.8.7"))
connect(_device.data(), SIGNAL(wasReset()), this, SLOT(slotSoftAbort()));
#elif QT_VERSION > QT_VERSION_CHECK(5, 0, 0) && QT_VERSION < QT_VERSION_CHECK(5, 4, 2) && !defined Q_OS_WIN && !defined Q_OS_MAC
if (QLatin1String(qVersion()) < QLatin1String("5.4.2"))
connect(_device.data(), SIGNAL(wasReset()), this, SLOT(slotSoftAbort()));
#endif
AbstractNetworkJob::start();
}
@@ -94,6 +114,13 @@ void PUTFileJob::slotTimeout() {
reply()->abort();
}
#if QT_VERSION < QT_VERSION_CHECK(5, 4, 2)
void PUTFileJob::slotSoftAbort() {
reply()->setProperty(owncloudShouldSoftCancelPropertyName, true);
reply()->abort();
}
#endif
void PollJob::start()
{
setTimeout(120 * 1000);
@@ -167,22 +194,51 @@ bool PollJob::finished()
return true;
}
void PropagateUploadFileQNAM::start()
{
if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) {
return;
}
const QString filePath = _propagator->getFilePath(_item._file);
// remember the modtime before checksumming to be able to detect a file
// change during the checksum calculation
_item._modtime = FileSystem::getModTime(filePath);
_stopWatch.start();
// do whatever is needed to add a checksum to the http upload request.
// in any case, the validator will emit signal startUpload to let the flow
// continue in slotStartUpload here.
TransmissionChecksumValidator *validator = new TransmissionChecksumValidator(filePath, this);
connect(validator, SIGNAL(validated(QByteArray)), this, SLOT(slotStartUpload(QByteArray)));
validator->uploadValidation();
}
void PropagateUploadFileQNAM::slotStartUpload(const QByteArray& checksum)
{
const QString fullFilePath(_propagator->getFilePath(_item._file));
_item._checksum = checksum;
if (!FileSystem::fileExists(fullFilePath)) {
done(SyncFileItem::SoftError, tr("File Removed"));
return;
}
_stopWatch.addLapTime(QLatin1String("Checksum"));
time_t prevModtime = _item._modtime; // the _item value was set in PropagateUploadFileQNAM::start()
// but a potential checksum calculation could have taken some time during which the file could
// have been changed again, so better check again here.
// Update the mtime and size, it might have changed since discovery.
_item._modtime = FileSystem::getModTime(fullFilePath);
if( prevModtime != _item._modtime ) {
_propagator->_anotherSyncNeeded = true;
done(SyncFileItem::SoftError, tr("Local file changed during syncing. It will be resumed."));
return;
}
quint64 fileSize = FileSystem::getSize(fullFilePath);
_item._size = fileSize;
@@ -369,6 +425,18 @@ void PropagateUploadFileQNAM::startNextChunk()
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._file.contains(".sys.admin#recall#")) {
// This is a file recall triggered by the admin. Note: the
// recall list file created by the admin and downloaded by the
// client (.sys.admin#recall#) also falls into this category
// (albeit users are not supposed to mess up with it)
// We use a special tag header so that the server may decide to store this file away in some admin stage area
// And not directly in the user's area (what would trigger redownloads etc).
headers["OC-Tag"] = ".sys.admin#recall#";
}
if (!_item._etag.isEmpty() && _item._etag != "empty_etag" &&
_item._instruction != CSYNC_INSTRUCTION_NEW // On new files never send a If-Match
) {
@@ -397,6 +465,14 @@ void PropagateUploadFileQNAM::startNextChunk()
if( currentChunkSize == 0 ) { // if the last chunk pretents to be 0, its actually the full chunk size.
currentChunkSize = chunkSize();
}
if( !_item._checksum.isEmpty() ) {
headers[checkSumHeaderC] = _item._checksum;
}
}
} else {
// checksum if its only one chunk
if( !_item._checksum.isEmpty() ) {
headers[checkSumHeaderC] = _item._checksum;
}
}
@@ -471,6 +547,18 @@ void PropagateUploadFileQNAM::slotPutFinished()
}
QNetworkReply::NetworkError err = job->reply()->error();
#if QT_VERSION < QT_VERSION_CHECK(5, 4, 2)
if (err == QNetworkReply::OperationCanceledError && job->reply()->property(owncloudShouldSoftCancelPropertyName).isValid()) {
// Abort the job and try again later.
// This works around a bug in QNAM wich might reuse a non-empty buffer for the next request.
qDebug() << "Forcing job abort on HTTP connection reset with Qt < 5.4.2.";
_propagator->_anotherSyncNeeded = true;
done(SyncFileItem::SoftError, tr("Forcing job abort on HTTP connection reset with Qt < 5.4.2."));
return;
}
#endif
if (err != QNetworkReply::NoError) {
_item._httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if(checkForProblemsWithShared(_item._httpErrorCode,
@@ -478,14 +566,9 @@ void PropagateUploadFileQNAM::slotPutFinished()
"It is restored and your edit is in the conflict file."))) {
return;
}
QString errorString = job->errorString();
QByteArray replyContent = job->reply()->readAll();
qDebug() << replyContent; // display the XML error in the debug
QRegExp rx("<s:message>(.*)</s:message>"); // Issue #1366: display server exception
if (rx.indexIn(QString::fromUtf8(replyContent)) != -1) {
errorString += QLatin1String(" (") + rx.cap(1) + QLatin1Char(')');
}
QString errorString = errorMessage(job->errorString(), replyContent);
if (job->reply()->hasRawHeader("OC-ErrorString")) {
errorString = job->reply()->rawHeader("OC-ErrorString");
@@ -538,15 +621,8 @@ void PropagateUploadFileQNAM::slotPutFinished()
}
}
// compare expected and real modification time of the file and size
const time_t new_mtime = FileSystem::getModTime(fullFilePath);
const quint64 new_size = static_cast<quint64>(FileSystem::getSize(fullFilePath));
QFileInfo fi(_propagator->getFilePath(_item._file));
if (new_mtime != _item._modtime || new_size != _item._size) {
qDebug() << "The local file has changed during upload:"
<< "mtime: " << _item._modtime << "<->" << new_mtime
<< ", size: " << _item._size << "<->" << new_size
<< ", QFileInfo: " << Utility::qDateTimeToTime_t(fi.lastModified()) << fi.lastModified();
// Check whether the file changed since discovery.
if (! FileSystem::verifyFileUnchanged(fullFilePath, _item._size, _item._modtime)) {
_propagator->_anotherSyncNeeded = true;
if( !finished ) {
abortWithError(SyncFileItem::SoftError, tr("Local file changed during sync."));
@@ -612,6 +688,11 @@ void PropagateUploadFileQNAM::slotPutFinished()
// Well, the mtime was not set
#endif
}
// performance logging
_item._requestDuration = _stopWatch.stop();
qDebug() << "*==* duration UPLOAD" << _item._size << _stopWatch.durationOfLap(QLatin1String("Checksum")) << _item._requestDuration;
finalize(_item);
}
+27 -2
Ver Arquivo
@@ -20,6 +20,7 @@
#include <QFile>
#include <QDebug>
namespace OCC {
class BandwidthManager;
@@ -40,11 +41,21 @@ public:
bool isSequential() const Q_DECL_OVERRIDE;
bool seek ( qint64 pos ) Q_DECL_OVERRIDE;
#if QT_VERSION < QT_VERSION_CHECK(5, 4, 2)
bool reset() Q_DECL_OVERRIDE { emit wasReset(); return QIODevice::reset(); }
#endif
void setBandwidthLimited(bool);
bool isBandwidthLimited() { return _bandwidthLimited; }
void setChoked(bool);
bool isChoked() { return _choked; }
void giveBandwidthQuota(qint64 bwq);
signals:
#if QT_VERSION < 0x050402
void wasReset();
#endif
private:
// The file data
@@ -65,6 +76,8 @@ protected slots:
class PUTFileJob : public AbstractNetworkJob {
Q_OBJECT
private:
QScopedPointer<QIODevice> _device;
QMap<QByteArray, QByteArray> _headers;
QString _errorString;
@@ -95,6 +108,11 @@ public:
signals:
void finishedSignal();
void uploadProgress(qint64,qint64);
private slots:
#if QT_VERSION < 0x050402
void slotSoftAbort();
#endif
};
/**
@@ -108,9 +126,9 @@ class PollJob : public AbstractNetworkJob {
SyncJournalDb *_journal;
QString _localPath;
public:
SyncFileItem _item;
SyncFileItem &_item;
// Takes ownership of the device
explicit PollJob(AccountPtr account, const QString &path, const SyncFileItem &item,
explicit PollJob(AccountPtr account, const QString &path, SyncFileItem &item,
SyncJournalDb *journal, const QString &localPath, QObject *parent)
: AbstractNetworkJob(account, path, parent), _journal(journal), _localPath(localPath), _item(item) {}
@@ -131,6 +149,7 @@ signals:
class PropagateUploadFileQNAM : public PropagateItemJob {
Q_OBJECT
private:
/**
* That's the start chunk that was stored in the database for resuming.
* In the non-resuming case it is 0.
@@ -148,6 +167,10 @@ class PropagateUploadFileQNAM : public PropagateItemJob {
QElapsedTimer _duration;
QVector<PUTFileJob*> _jobs; /// network jobs that are currently in transit
bool _finished; // Tells that all the jobs have been finished
// measure the performance of checksum calc and upload
Utility::StopWatch _stopWatch;
public:
PropagateUploadFileQNAM(OwncloudPropagator* propagator,const SyncFileItem& item)
: PropagateItemJob(propagator, item), _startChunk(0), _currentChunk(0), _chunkCount(0), _transferId(0), _finished(false) {}
@@ -160,6 +183,8 @@ private slots:
void startNextChunk();
void finalize(const SyncFileItem&);
void slotJobDestroyed(QObject *job);
void slotStartUpload(const QByteArray &checksum);
private:
void startPollJob(const QString& path);
void abortWithError(SyncFileItem::Status status, const QString &error);
+5 -1
Ver Arquivo
@@ -714,7 +714,11 @@ void PropagateDownloadFileLegacy::start()
QString error;
_propagator->addTouchedFile(fn);
if (!FileSystem::renameReplace(tmpFile.fileName(), fn, &error)) {
const qint64 expectedFileSize = _item.log._other_size;
const time_t expectedFileMtime = _item.log._other_modtime;
if (!FileSystem::renameReplace(tmpFile.fileName(), fn,
expectedFileSize, expectedFileMtime,
&error)) {
done(SyncFileItem::NormalError, error);
return;
}
+42 -15
Ver Arquivo
@@ -39,38 +39,65 @@
namespace OCC {
// Code copied from Qt5's QDir::removeRecursively
// (and modified to report the error)
static bool removeRecursively(const QString &path, QString &error)
/**
* Code inspired from Qt5's QDir::removeRecursively
* The code will update the database in case of error.
* If everything goes well (no error, returns true), the caller is responsible of removing the entries
* in the database. But in case of error, we need to remove the entries from the database of the files
* that were deleted.
*
* \a path is relative to _propagator->_localDir + _item->_file and should start with a slash
*/
bool PropagateLocalRemove::removeRecursively(const QString& path)
{
bool success = true;
QDirIterator di(path, QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot);
QString absolute = _propagator->_localDir + _item._file + path;
QDirIterator di(absolute, QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot);
QVector<QPair<QString, bool>> deleted;
while (di.hasNext()) {
di.next();
const QFileInfo& fi = di.fileInfo();
bool ok;
// The use of isSymLink here is okay:
// we never want to go into this branch for .lnk files
if (fi.isDir() && !fi.isSymLink()) {
ok = removeRecursively(di.filePath(), error); // recursive
bool isDir = fi.isDir() && !fi.isSymLink();
if (isDir) {
ok = removeRecursively(path + QLatin1Char('/') + di.fileName()); // recursive
} else {
QFile f(di.filePath());
ok = f.remove();
if (!ok) {
error += PropagateLocalRemove::tr("Error removing '%1': %2;").
_error += PropagateLocalRemove::tr("Error removing '%1': %2;").
arg(QDir::toNativeSeparators(f.fileName()), f.errorString()) + " ";
qDebug() << "Error removing " << f.fileName() << ':' << f.errorString();
}
}
if (!ok)
if (success && !ok) {
// We need to delete the entries from the database now from the deleted vector
foreach(const auto &it, deleted) {
_propagator->_journal->deleteFileRecord(_item._originalFile + path + QLatin1Char('/') + it.first,
it.second);
}
success = false;
deleted.clear();
}
if (success) {
deleted.append(qMakePair(di.fileName(), isDir));
}
if (!success && ok) {
// This succeeded, so we need to delete it from the database now because the caller won't
_propagator->_journal->deleteFileRecord(_item._originalFile + path + QLatin1Char('/') + di.fileName(),
isDir);
}
}
if (success) {
success = QDir().rmdir(path);
success = QDir().rmdir(absolute);
if (!success) {
error += PropagateLocalRemove::tr("Could not remove directory '%1';")
.arg(QDir::toNativeSeparators(path)) + " ";
qDebug() << "Error removing directory" << path;
_error += PropagateLocalRemove::tr("Could not remove directory '%1';")
.arg(QDir::toNativeSeparators(absolute)) + " ";
qDebug() << "Error removing directory" << absolute;
}
}
return success;
@@ -89,9 +116,8 @@ void PropagateLocalRemove::start()
}
if (_item._isDirectory) {
QString error;
if (QDir(filename).exists() && !removeRecursively(filename, error)) {
done(SyncFileItem::NormalError, error);
if (QDir(filename).exists() && !removeRecursively(QString())) {
done(SyncFileItem::NormalError, _error);
return;
}
} else {
@@ -119,6 +145,7 @@ void PropagateLocalMkdir::start()
done( SyncFileItem::NormalError, tr("Attention, possible case sensitivity clash with %1").arg(newDirStr) );
return;
}
_propagator->addTouchedFile(newDirStr);
QDir localDir(_propagator->_localDir);
if (!localDir.mkpath(_item._file)) {
done( SyncFileItem::NormalError, tr("could not create directory %1").arg(newDirStr) );
+19
Ver Arquivo
@@ -21,11 +21,30 @@
namespace OCC {
/**
* Tags for checksum headers.
* They are here for being shared between Upload- and Download Job
*/
// the header itself
static const char checkSumHeaderC[] = "OC-Checksum";
// ...and it's values
static const char checkSumMD5C[] = "MD5";
static const char checkSumSHA1C[] = "SHA1";
static const char checkSumAdlerC[] = "Adler32";
static const char checkSumAdlerUpperC[] = "ADLER32";
/**
* Declaration of the other propagation jobs
*/
class PropagateLocalRemove : public PropagateItemJob {
Q_OBJECT
public:
PropagateLocalRemove (OwncloudPropagator* propagator,const SyncFileItem& item) : PropagateItemJob(propagator, item) {}
void start() Q_DECL_OVERRIDE;
private:
bool removeRecursively(const QString &path);
QString _error;
};
class PropagateLocalMkdir : public PropagateItemJob {
Q_OBJECT
+7 -16
Ver Arquivo
@@ -75,7 +75,7 @@ SyncEngine::SyncEngine(AccountPtr account, CSYNC *ctx, const QString& localPath,
qRegisterMetaType<SyncFileItem::Status>("SyncFileItem::Status");
qRegisterMetaType<Progress::Info>("Progress::Info");
_thread.setObjectName("CSync_Neon_Thread");
_thread.setObjectName("SyncEngine_Thread");
_thread.start();
}
@@ -378,6 +378,9 @@ 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_INDIVIDUAL_STAT_FAILED:
item._errorString = tr("Stat failed.");
break;
case CSYNC_STATUS_SERVICE_UNAVAILABLE:
item._errorString = QLatin1String("Server temporarily unavailable.");
break;
@@ -438,6 +441,8 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
// 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;
// same for the size
item._size = file->other.size;
_journal->setFileRecord(SyncJournalFileRecord(item, _localPath + item._file));
item._should_update_etag = false;
@@ -595,7 +600,6 @@ void SyncEngine::startSync()
#endif
fileRecordCount = _journal->getFileRecordCount(); // this creates the DB if it does not exist yet
bool isUpdateFrom_1_5 = _journal->isUpdateFrom_1_5();
if( fileRecordCount == -1 ) {
qDebug() << "No way to create a sync journal!";
@@ -605,20 +609,7 @@ void SyncEngine::startSync()
// database creation error!
}
bool isUpdateFrom_1_8 = _journal->isUpdateFrom_1_8_0();
/*
* If 1.8.0 caused missing data in the local tree, this patch gets it
* back. For that, the usage of the journal for remote repository is
* disabled at the first start.
*/
if (fileRecordCount >= 1 && (isUpdateFrom_1_5 || isUpdateFrom_1_8)) {
qDebug() << "detected update from 1.5" << fileRecordCount << isUpdateFrom_1_5;
// Disable the read from DB to be sure to re-read all the fileid and etags.
_csync_ctx->read_remote_from_db = false;
} else {
_csync_ctx->read_remote_from_db = true;
}
_csync_ctx->read_remote_from_db = true;
// This tells csync to never read from the DB if it is empty
// thereby speeding up the initial discovery significantly.
+1
Ver Arquivo
@@ -150,6 +150,7 @@ public:
quint64 _inode;
QByteArray _fileId;
QByteArray _remotePerm;
QByteArray _checksum;
QString _directDownloadUrl;
QString _directDownloadCookies;
+44 -33
Ver Arquivo
@@ -30,7 +30,7 @@
namespace OCC {
SyncJournalDb::SyncJournalDb(const QString& path, QObject *parent) :
QObject(parent), _transaction(0), _possibleUpgradeFromMirall_1_5(false), _possibleUpgradeFromMirall_1_8_0(false)
QObject(parent), _transaction(0)
{
_dbFile = path;
@@ -272,15 +272,14 @@ bool SyncJournalDb::checkConnect()
return sqlFail("Create table version", createQuery);
}
_possibleUpgradeFromMirall_1_5 = false;
_possibleUpgradeFromMirall_1_8_0 = false;
bool forceRemoteDiscovery = false;
SqlQuery versionQuery("SELECT major, minor, patch FROM version;", _db);
if (!versionQuery.next()) {
// If there was no entry in the table, it means we are likely upgrading from 1.5
if (!isNewDb) {
qDebug() << Q_FUNC_INFO << "_possibleUpgradeFromMirall_1_5 detected!";
_possibleUpgradeFromMirall_1_5 = true;
qDebug() << Q_FUNC_INFO << "possibleUpgradeFromMirall_1_5 detected!";
forceRemoteDiscovery = true;
}
createQuery.prepare("INSERT INTO version VALUES (?1, ?2, ?3, ?4);");
createQuery.bindValue(1, MIRALL_VERSION_MAJOR);
@@ -294,9 +293,9 @@ bool SyncJournalDb::checkConnect()
int minor = versionQuery.intValue(1);
int patch = versionQuery.intValue(2);
if( major == 1 && minor == 8 && patch == 0 ) {
qDebug() << Q_FUNC_INFO << "_possibleUpgradeFromMirall_1_8_0 detected!";
_possibleUpgradeFromMirall_1_8_0 = true;
if( major == 1 && minor == 8 && (patch == 0 || patch == 1) ) {
qDebug() << Q_FUNC_INFO << "possibleUpgradeFromMirall_1_8_0_or_1 detected!";
forceRemoteDiscovery = true;
}
// Not comparing the BUILD id here, correct?
if( !(major == MIRALL_VERSION_MAJOR && minor == MIRALL_VERSION_MINOR && patch == MIRALL_VERSION_PATCH) ) {
@@ -323,6 +322,18 @@ bool SyncJournalDb::checkConnect()
qDebug() << "WARN: Failed to update the database structure!";
}
/*
* If we are upgrading from a client version older than 1.5 is found,
* we cannot read from the database because we need to fetch the files id and etags.
*
* If 1.8.0 caused missing data in the local tree, so we also don't read from DB
* to get back the files that were gone.
* In 1.8.1 we had a fix to re-get the data, but this one here is better
*/
if (forceRemoteDiscovery) {
forceRemoteDiscoveryNextSyncLocked();
}
_getFileRecordQuery.reset(new SqlQuery(_db));
_getFileRecordQuery->prepare("SELECT path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize FROM "
"metadata WHERE phash=?1" );
@@ -409,7 +420,6 @@ void SyncJournalDb::close()
_deleteFileRecordRecursively.reset(0);
_getErrorBlacklistQuery.reset(0);
_setErrorBlacklistQuery.reset(0);
_possibleUpgradeFromMirall_1_5 = false;
_db.close();
_avoidReadFromDbOnNextSyncFilter.clear();
@@ -755,14 +765,6 @@ bool SyncJournalDb::postSyncCleanup(const QSet<QString>& filepathsToKeep,
// Incoroporate results back into main DB
walCheckpoint();
if (_possibleUpgradeFromMirall_1_5) {
_possibleUpgradeFromMirall_1_5 = false; // should be handled now
}
if (_possibleUpgradeFromMirall_1_8_0) {
_possibleUpgradeFromMirall_1_8_0 = false; // should be handled now
}
return true;
}
@@ -1155,12 +1157,11 @@ void SyncJournalDb::wipeErrorBlacklistEntry( const QString& file )
void SyncJournalDb::updateErrorBlacklistEntry( const SyncJournalErrorBlacklistRecord& item )
{
QMutexLocker locker(&_mutex);
if( !checkConnect() ) {
return;
}
QMutexLocker locker(&_mutex);
_setErrorBlacklistQuery->bindValue(1, item._file);
_setErrorBlacklistQuery->bindValue(2, item._lastTryEtag);
_setErrorBlacklistQuery->bindValue(3, QString::number(item._lastTryModtime));
@@ -1287,6 +1288,30 @@ void SyncJournalDb::avoidReadFromDbOnNextSync(const QString& fileName)
_avoidReadFromDbOnNextSyncFilter.append(fileName);
}
void SyncJournalDb::forceRemoteDiscoveryNextSync()
{
QMutexLocker locker(&_mutex);
if( !checkConnect() ) {
return;
}
forceRemoteDiscoveryNextSyncLocked();
}
void SyncJournalDb::forceRemoteDiscoveryNextSyncLocked()
{
qDebug() << "Forcing remote re-discovery by deleting folder Etags";
SqlQuery deleteRemoteFolderEtagsQuery(_db);
deleteRemoteFolderEtagsQuery.prepare("UPDATE metadata SET md5='_invalid_' WHERE type=2;");
if( !deleteRemoteFolderEtagsQuery.exec() ) {
qDebug() << "ERROR: Query failed" << deleteRemoteFolderEtagsQuery.error();
} else {
qDebug() << "Cleared" << deleteRemoteFolderEtagsQuery.numRowsAffected() << "folder ETags";
}
}
void SyncJournalDb::commit(const QString& context, bool startTrans)
{
QMutexLocker lock(&_mutex);
@@ -1325,20 +1350,6 @@ bool SyncJournalDb::isConnected()
return checkConnect();
}
bool SyncJournalDb::isUpdateFrom_1_5()
{
QMutexLocker lock(&_mutex);
checkConnect();
return _possibleUpgradeFromMirall_1_5;
}
bool SyncJournalDb::isUpdateFrom_1_8_0()
{
QMutexLocker lock(&_mutex);
checkConnect();
return _possibleUpgradeFromMirall_1_8_0;
}
bool operator==(const SyncJournalDb::DownloadInfo & lhs,
const SyncJournalDb::DownloadInfo & rhs)
{
+10 -9
Ver Arquivo
@@ -97,6 +97,13 @@ public:
*/
void avoidReadFromDbOnNextSync(const QString& fileName);
/**
* Ensures full remote discovery happens on the next sync.
*
* Equivalent to calling avoidReadFromDbOnNextSync() for all files.
*/
void forceRemoteDiscoveryNextSync();
bool postSyncCleanup(const QSet<QString>& filepathsToKeep,
const QSet<QString>& prefixesToKeep);
@@ -113,13 +120,6 @@ public:
*/
bool isConnected();
/**
* Tell the sync engine if we need to disable the fetch from db to be sure that the fileid
* are updated.
*/
bool isUpdateFrom_1_5();
bool isUpdateFrom_1_8_0();
private:
bool updateDatabaseStructure();
bool updateMetadataTableStructure();
@@ -131,12 +131,13 @@ private:
QStringList tableColumns( const QString& table );
bool checkConnect();
// Same as forceRemoteDiscoveryNextSync but without acquiring the lock
void forceRemoteDiscoveryNextSyncLocked();
SqlDatabase _db;
QString _dbFile;
QMutex _mutex; // Public functions are protected with the mutex.
int _transaction;
bool _possibleUpgradeFromMirall_1_5;
bool _possibleUpgradeFromMirall_1_8_0;
QScopedPointer<SqlQuery> _getFileRecordQuery;
QScopedPointer<SqlQuery> _setFileRecordQuery;
QScopedPointer<SqlQuery> _getDownloadInfoQuery;
+7 -2
Ver Arquivo
@@ -241,12 +241,17 @@ QString Theme::updateCheckUrl() const
return QLatin1String("https://updates.owncloud.com/client/");
}
QString Theme::transmissionChecksum() const
{
return QString::null; // No transmission by default.
}
QString Theme::gitSHA1() const
{
QString devString;
#ifdef GIT_SHA1
const QString githubPrefix(QLatin1String(
"https://github.com/owncloud/mirall/commit/"));
"https://github.com/owncloud/client/commit/"));
const QString gitSha1(QLatin1String(GIT_SHA1));
devString = QCoreApplication::translate("ownCloudTheme::about()",
"<p><small>Built from Git revision <a href=\"%1\">%2</a>"
@@ -389,5 +394,5 @@ bool Theme::wizardSelectiveSyncDefaultNothing() const
}
} // end namespace mirall
} // end namespace client
+8 -1
Ver Arquivo
@@ -189,12 +189,19 @@ public:
*/
virtual QString updateCheckUrl() const;
/**
* When true, the setup wizard will show the selective sync dialog by default and default
* to nothing selected
*/
virtual bool wizardSelectiveSyncDefaultNothing() const;
/**
* @brief Add an additional checksum header to PUT requests and compare them
* if they come with GET requests.
* This value sets the checksum type (SHA1, MD5 or Adler32) or is left empty
* if no checksumming is wanted. In that case it can still be overwritten in
* the client config file.
*/
virtual QString transmissionChecksum() const;
protected:
#ifndef TOKEN_AUTH_ONLY
+151
Ver Arquivo
@@ -0,0 +1,151 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "config.h"
#include "filesystem.h"
#include "transmissionchecksumvalidator.h"
#include "syncfileitem.h"
#include "propagatorjobs.h"
#include "configfile.h"
#include <qtconcurrentrun.h>
namespace OCC {
TransmissionChecksumValidator::TransmissionChecksumValidator(const QString& filePath, QObject *parent)
:QObject(parent),
_filePath(filePath)
{
}
void TransmissionChecksumValidator::setChecksumType( const QByteArray& type )
{
_checksumType = type;
}
QString TransmissionChecksumValidator::checksumType() const
{
QString checksumType = _checksumType;
if( checksumType.isEmpty() ) {
ConfigFile cfg;
checksumType = cfg.transmissionChecksum();
}
return checksumType;
}
void TransmissionChecksumValidator::uploadValidation()
{
const QString csType = checksumType();
if( csType.isEmpty() ) {
// if there is no checksum defined, continue to upload
emit validated(QByteArray());
} else {
// Calculate the checksum in a different thread first.
connect( &_watcher, SIGNAL(finished()),
this, SLOT(slotUploadChecksumCalculated()));
if( csType == checkSumMD5C ) {
_checksumHeader = checkSumMD5C;
_checksumHeader += ":";
_watcher.setFuture(QtConcurrent::run(FileSystem::calcMd5, _filePath));
} else if( csType == checkSumSHA1C ) {
_checksumHeader = checkSumSHA1C;
_checksumHeader += ":";
_watcher.setFuture(QtConcurrent::run( FileSystem::calcSha1, _filePath));
}
#ifdef ZLIB_FOUND
else if( csType == checkSumAdlerC) {
_checksumHeader = checkSumAdlerC;
_checksumHeader += ":";
_watcher.setFuture(QtConcurrent::run(FileSystem::calcAdler32, _filePath));
}
#endif
else {
// for an unknown checksum, continue to upload
emit validated(QByteArray());
}
}
}
void TransmissionChecksumValidator::slotUploadChecksumCalculated( )
{
QByteArray checksum = _watcher.future().result();
if( !checksum.isEmpty() ) {
checksum.prepend( _checksumHeader );
}
emit validated(checksum);
}
void TransmissionChecksumValidator::downloadValidation( const QByteArray& checksumHeader )
{
// if the incoming header is empty, there was no checksum header, and
// no validation can happen. Just continue.
const QString csType = checksumType();
// for empty checksum type, everything is valid.
if( csType.isEmpty() ) {
emit validated(QByteArray());
return;
}
int indx = checksumHeader.indexOf(':');
if( indx < 0 ) {
qDebug() << "Checksum header malformed:" << checksumHeader;
emit validationFailed(tr("The checksum header is malformed.")); // show must go on - even not validated.
return;
}
const QByteArray type = checksumHeader.left(indx).toUpper();
_expectedHash = checksumHeader.mid(indx+1);
connect( &_watcher, SIGNAL(finished()), this, SLOT(slotDownloadChecksumCalculated()) );
// start the calculation in different thread
if( type == checkSumMD5C ) {
_watcher.setFuture(QtConcurrent::run(FileSystem::calcMd5, _filePath));
} else if( type == checkSumSHA1C ) {
_watcher.setFuture(QtConcurrent::run(FileSystem::calcSha1, _filePath));
}
#ifdef ZLIB_FOUND
else if( type == checkSumAdlerUpperC ) {
_watcher.setFuture(QtConcurrent::run(FileSystem::calcAdler32, _filePath));
}
#endif
else {
qDebug() << "Unknown checksum type" << type;
emit validationFailed(tr("The checksum header is malformed."));
return;
}
}
void TransmissionChecksumValidator::slotDownloadChecksumCalculated()
{
const QByteArray hash = _watcher.future().result();
if( hash != _expectedHash ) {
emit validationFailed(tr("The downloaded file does not match the checksum, it will be resumed."));
} else {
// qDebug() << "Checksum checked and matching: " << _expectedHash;
emit validated(hash);
}
}
}
+76
Ver Arquivo
@@ -0,0 +1,76 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#pragma once
#include "owncloudlib.h"
#include <QObject>
#include <QByteArray>
#include <QFutureWatcher>
namespace OCC {
class OWNCLOUDSYNC_EXPORT TransmissionChecksumValidator : public QObject
{
Q_OBJECT
public:
explicit TransmissionChecksumValidator(const QString& filePath, QObject *parent = 0);
/**
* method to prepare a checksum for transmission and save it to the _checksum
* member of the SyncFileItem *item.
* The kind of requested checksum is taken from config. No need to set from outside.
*
* In any case of processing (checksum set, no checksum required and also unusual error)
* the object will emit the signal validated(). The item->_checksum is than either
* set to a proper value or empty.
*/
void uploadValidation();
/**
* method to verify the checksum coming with requests in a checksum header. The required
* checksum method is read from config.
*
* If no checksum is there, or if a correct checksum is there, the signal validated()
* will be emitted. In case of any kind of error, the signal validationFailed() will
* be emitted.
*/
void downloadValidation( const QByteArray& checksumHeader );
// This is only used in test cases (by now). This class reads the required
// test case from the config file.
void setChecksumType(const QByteArray &type );
QString checksumType() const;
signals:
void validated(const QByteArray& checksum);
void validationFailed( const QString& errMsg );
private slots:
void slotUploadChecksumCalculated();
void slotDownloadChecksumCalculated();
private:
QByteArray _checksumType;
QByteArray _expectedHash;
QByteArray _checksumHeader;
QString _filePath;
// watcher for the checksum calculation thread
QFutureWatcher<QByteArray> _watcher;
};
}
+16 -4
Ver Arquivo
@@ -15,6 +15,7 @@
#include "utility.h"
#include "version.h"
#include "theme.h"
// Note: This file must compile without QtGui
#include <QCoreApplication>
@@ -154,10 +155,19 @@ QString Utility::platform()
QByteArray Utility::userAgentString()
{
return QString::fromLatin1("Mozilla/5.0 (%1) mirall/%2")
QString re = QString::fromLatin1("Mozilla/5.0 (%1) mirall/%2")
.arg(Utility::platform())
.arg(QLatin1String(MIRALL_STRINGIFY(MIRALL_VERSION)))
.toLatin1();
.arg(QLatin1String(MIRALL_VERSION_STRING));
const QString appName = Theme::instance()->appName();
// this constant "ownCloud" is defined in the default OEM theming
// that is used for the standard client. If it is changed there,
// it needs to be adjusted here.
if( appName != QLatin1String("ownCloud") ) {
re += QString(" (%1)").arg(appName);
}
return re.toLatin1();
}
bool Utility::hasLaunchOnStartup(const QString &appName)
@@ -401,10 +411,12 @@ void Utility::StopWatch::start()
_timer.start();
}
void Utility::StopWatch::stop()
quint64 Utility::StopWatch::stop()
{
addLapTime(QLatin1String(STOPWATCH_END_TAG));
quint64 duration = _timer.elapsed();
_timer.invalidate();
return duration;
}
void Utility::StopWatch::reset()
+1 -1
Ver Arquivo
@@ -105,7 +105,7 @@ namespace Utility
QElapsedTimer _timer;
public:
void start();
void stop();
quint64 stop();
quint64 addLapTime( const QString& lapName );
void reset();
+1 -1
Ver Arquivo
@@ -36,6 +36,6 @@ desktop.ini
~$*
.~lock.*
*.tmp
~*.tmp
*.gnucash.tmp-*
+2
Ver Arquivo
@@ -33,4 +33,6 @@ owncloud_add_test(SyncFileItem "")
owncloud_add_test(ConcatUrl "")
owncloud_add_test(XmlParse "")
owncloud_add_test(FileSystem "")
owncloud_add_test(TransChecksumValidator "")
+93
Ver Arquivo
@@ -0,0 +1,93 @@
/*
This software is in the public domain, furnished "as is", without technical
support, and with no warranty, express or implied, as to its usefulness for
any purpose.
*/
#ifndef MIRALL_TESTFILESYSTEM_H
#define MIRALL_TESTFILESYSTEM_H
#include <QtTest>
#include <QDebug>
#include "filesystem.h"
#include "utility.h"
using namespace OCC::Utility;
using namespace OCC::FileSystem;
class TestFileSystem : public QObject
{
Q_OBJECT
QString _root;
QByteArray shellSum( const QByteArray& cmd, const QString& file )
{
QProcess md5;
QStringList args;
args.append(file);
md5.start(cmd, args);
QByteArray sumShell;
qDebug() << "File: "<< file;
if( md5.waitForFinished() ) {
sumShell = md5.readAll();
sumShell = sumShell.left( sumShell.indexOf(' '));
}
return sumShell;
}
private slots:
void initTestCase() {
qsrand(QTime::currentTime().msec());
QString subdir("test_"+QString::number(qrand()));
_root = QDir::tempPath() + "/" + subdir;
QDir dir("/tmp");
dir.mkdir(subdir);
qDebug() << "creating test directory " << _root;
}
void cleanupTestCase()
{
if( !_root.isEmpty() )
system(QString("rm -rf "+_root).toUtf8());
}
void testMd5Calc()
{
QString file( _root+"/file_a.bin");
writeRandomFile(file);
QFileInfo fi(file);
QVERIFY(fi.exists());
QByteArray sum = calcMd5(file);
QByteArray sSum = shellSum("/usr/bin/md5sum", file);
qDebug() << "calulated" << sum << "versus md5sum:"<< sSum;
QVERIFY(!sSum.isEmpty());
QVERIFY(!sum.isEmpty());
QVERIFY(sSum == sum );
}
void testSha1Calc()
{
QString file( _root+"/file_b.bin");
writeRandomFile(file);
QFileInfo fi(file);
QVERIFY(fi.exists());
QByteArray sum = calcSha1(file);
QByteArray sSum = shellSum("/usr/bin/sha1sum", file);
qDebug() << "calulated" << sum << "versus sha1sum:"<< sSum;
QVERIFY(!sSum.isEmpty());
QVERIFY(!sum.isEmpty());
QVERIFY(sSum == sum );
}
};
#endif
+44
Ver Arquivo
@@ -8,7 +8,14 @@
#define MIRALL_TESTOWNCLOUDPROPAGATOR_H
#include <QtTest>
#include <QDebug>
#include "propagatedownload.h"
using namespace OCC;
namespace OCC {
QString OWNCLOUDSYNC_EXPORT createDownloadTmpFileName(const QString &previous);
}
class TestOwncloudPropagator : public QObject
{
@@ -20,6 +27,43 @@ private slots:
// OwncloudPropagator propagator( NULL, QLatin1String("test1"), QLatin1String("test2"), new ProgressDatabase);
QVERIFY( true );
}
void testTmpDownloadFileNameGeneration()
{
QString fn;
// without dir
for (int i = 1; i <= 1000; i++) {
fn+="F";
QString tmpFileName = createDownloadTmpFileName(fn);
if (tmpFileName.contains('/')) {
tmpFileName = tmpFileName.mid(tmpFileName.lastIndexOf('/')+1);
}
QVERIFY( tmpFileName.length() > 0);
QVERIFY( tmpFileName.length() <= 254);
}
// with absolute dir
fn = "/Users/guruz/ownCloud/rocks/GPL";
for (int i = 1; i < 1000; i++) {
fn+="F";
QString tmpFileName = createDownloadTmpFileName(fn);
if (tmpFileName.contains('/')) {
tmpFileName = tmpFileName.mid(tmpFileName.lastIndexOf('/')+1);
}
QVERIFY( tmpFileName.length() > 0);
QVERIFY( tmpFileName.length() <= 254);
}
// with relative dir
fn = "rocks/GPL";
for (int i = 1; i < 1000; i++) {
fn+="F";
QString tmpFileName = createDownloadTmpFileName(fn);
if (tmpFileName.contains('/')) {
tmpFileName = tmpFileName.mid(tmpFileName.lastIndexOf('/')+1);
}
QVERIFY( tmpFileName.length() > 0);
QVERIFY( tmpFileName.length() <= 254);
}
}
};
#endif
+153
Ver Arquivo
@@ -0,0 +1,153 @@
/*
* This software is in the public domain, furnished "as is", without technical
* support, and with no warranty, express or implied, as to its usefulness for
* any purpose.
*
*/
#pragma once
#include <QtTest>
#include <QDir>
#include <QString>
#include "transmissionchecksumvalidator.h"
#include "networkjobs.h"
#include "utility.h"
#include "filesystem.h"
#include "propagatorjobs.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
// poor man QTRY_VERIFY when Qt5 is not available.
#define QTRY_VERIFY(Cond) QTest::qWait(1000); QVERIFY(Cond)
#endif
using namespace OCC;
class TestTransChecksumValidator : public QObject
{
Q_OBJECT
private:
QString _root;
QString _testfile;
QString _expectedError;
QByteArray _expected;
bool _successDown;
bool _errorSeen;
public slots:
void slotUpValidated(const QByteArray& checksum) {
qDebug() << "Checksum: " << checksum;
QVERIFY(_expected == checksum );
}
void slotDownValidated() {
_successDown = true;
}
void slotDownError( const QString& errMsg ) {
QVERIFY(_expectedError == errMsg );
_errorSeen = true;
}
private slots:
void initTestCase() {
qDebug() << Q_FUNC_INFO;
_root = QDir::tempPath() + "/" + "test_" + QString::number(qrand());
QDir rootDir(_root);
rootDir.mkpath(_root );
_testfile = _root+"/csFile";
Utility::writeRandomFile( _testfile);
}
void testUploadChecksummingAdler() {
TransmissionChecksumValidator *vali = new TransmissionChecksumValidator(_testfile, this);
vali->setChecksumType("Adler32");
connect(vali, SIGNAL(validated(QByteArray)), this, SLOT(slotUpValidated(QByteArray)));
QString testfile = _testfile;
_expected = "Adler32:"+FileSystem::calcAdler32( testfile );
qDebug() << "XX Expected Checksum: " << _expected;
vali->uploadValidation();
QEventLoop loop;
connect(vali, SIGNAL(validated(QByteArray)), &loop, SLOT(quit()), Qt::QueuedConnection);
loop.exec();
delete vali;
}
void testUploadChecksummingMd5() {
TransmissionChecksumValidator *vali = new TransmissionChecksumValidator(_testfile, this);
vali->setChecksumType( OCC::checkSumMD5C );
connect(vali, SIGNAL(validated(QByteArray)), this, SLOT(slotUpValidated(QByteArray)));
_expected = checkSumMD5C;
_expected.append(":"+FileSystem::calcMd5( _testfile ));
vali->uploadValidation();
QEventLoop loop;
connect(vali, SIGNAL(validated(QByteArray)), &loop, SLOT(quit()), Qt::QueuedConnection);
loop.exec();
delete vali;
}
void testUploadChecksummingSha1() {
TransmissionChecksumValidator *vali = new TransmissionChecksumValidator(_testfile, this);
vali->setChecksumType( OCC::checkSumSHA1C );
connect(vali, SIGNAL(validated(QByteArray)), this, SLOT(slotUpValidated(QByteArray)));
_expected = checkSumSHA1C;
_expected.append(":"+FileSystem::calcSha1( _testfile ));
vali->uploadValidation();
QEventLoop loop;
connect(vali, SIGNAL(validated(QByteArray)), &loop, SLOT(quit()), Qt::QueuedConnection);
loop.exec();
delete vali;
}
void testDownloadChecksummingAdler() {
QByteArray adler = checkSumAdlerC;
adler.append(":");
adler.append(FileSystem::calcAdler32( _testfile ));
_successDown = false;
TransmissionChecksumValidator *vali = new TransmissionChecksumValidator(_testfile, this);
vali->setChecksumType("Adler32");
connect(vali, SIGNAL(validated(QByteArray)), this, SLOT(slotDownValidated()));
connect(vali, SIGNAL(validationFailed(QString)), this, SLOT(slotDownError(QString)));
vali->downloadValidation(adler);
QTRY_VERIFY(_successDown);
_expectedError = QLatin1String("The downloaded file does not match the checksum, it will be resumed.");
_errorSeen = false;
vali->downloadValidation("Adler32:543345");
QTRY_VERIFY(_errorSeen);
_expectedError = QLatin1String("The checksum header is malformed.");
_errorSeen = false;
vali->downloadValidation("Klaas32:543345");
QTRY_VERIFY(_errorSeen);
delete vali;
}
void cleanupTestCase() {
}
};
+206 -4
Ver Arquivo
@@ -113,7 +113,7 @@ private slots:
this, SLOT(slotFinishedSuccessfully()) );
QHash <QString, qint64> sizes;
QVERIFY(parser.parse( testXml, &sizes ));
QVERIFY(parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" ));
QVERIFY(_success);
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
@@ -187,7 +187,7 @@ private slots:
this, SLOT(slotFinishedSuccessfully()) );
QHash <QString, qint64> sizes;
QVERIFY(false == parser.parse( testXml, &sizes )); // verify false
QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); // verify false
QVERIFY(!_success);
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
@@ -210,7 +210,7 @@ private slots:
this, SLOT(slotFinishedSuccessfully()) );
QHash <QString, qint64> sizes;
QVERIFY(false == parser.parse( testXml, &sizes )); // verify false
QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); // verify false
QVERIFY(!_success);
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
@@ -232,7 +232,7 @@ private slots:
this, SLOT(slotFinishedSuccessfully()) );
QHash <QString, qint64> sizes;
QVERIFY(false == parser.parse( testXml, &sizes )); // verify false
QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); // verify false
QVERIFY(!_success);
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
@@ -240,6 +240,208 @@ private slots:
QVERIFY(_items.size() == 0 ); // FIXME: We should change the parser to not emit during parsing but at the end
QVERIFY(_subdirs.size() == 0);
}
void testParserBogfusHref1() {
const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>"
"<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
"<d:response>"
"<d:href>http://127.0.0.1:81/oc/remote.php/webdav/sharefolder/</d:href>"
"<d:propstat>"
"<d:prop>"
"<oc:id>00004213ocobzus5kn6s</oc:id>"
"<oc:permissions>RDNVCK</oc:permissions>"
"<oc:size>121780</oc:size>"
"<d:getetag>\"5527beb0400b0\"</d:getetag>"
"<d:resourcetype>"
"<d:collection/>"
"</d:resourcetype>"
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
"</d:prop>"
"<d:status>HTTP/1.1 200 OK</d:status>"
"</d:propstat>"
"<d:propstat>"
"<d:prop>"
"<d:getcontentlength/>"
"<oc:downloadURL/>"
"<oc:dDC/>"
"</d:prop>"
"<d:status>HTTP/1.1 404 Not Found</d:status>"
"</d:propstat>"
"</d:response>"
"<d:response>"
"<d:href>http://127.0.0.1:81/oc/remote.php/webdav/sharefolder/quitte.pdf</d:href>"
"<d:propstat>"
"<d:prop>"
"<oc:id>00004215ocobzus5kn6s</oc:id>"
"<oc:permissions>RDNVW</oc:permissions>"
"<d:getetag>\"2fa2f0d9ed49ea0c3e409d49e652dea0\"</d:getetag>"
"<d:resourcetype/>"
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
"<d:getcontentlength>121780</d:getcontentlength>"
"</d:prop>"
"<d:status>HTTP/1.1 200 OK</d:status>"
"</d:propstat>"
"<d:propstat>"
"<d:prop>"
"<oc:downloadURL/>"
"<oc:dDC/>"
"</d:prop>"
"<d:status>HTTP/1.1 404 Not Found</d:status>"
"</d:propstat>"
"</d:response>"
"</d:multistatus>";
LsColXMLParser parser;
connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
connect( &parser, SIGNAL(finishedWithoutError()),
this, SLOT(slotFinishedSuccessfully()) );
QHash <QString, qint64> sizes;
QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" ));
QVERIFY(!_success);
}
void testParserBogfusHref2() {
const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>"
"<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
"<d:response>"
"<d:href>/sharefolder</d:href>"
"<d:propstat>"
"<d:prop>"
"<oc:id>00004213ocobzus5kn6s</oc:id>"
"<oc:permissions>RDNVCK</oc:permissions>"
"<oc:size>121780</oc:size>"
"<d:getetag>\"5527beb0400b0\"</d:getetag>"
"<d:resourcetype>"
"<d:collection/>"
"</d:resourcetype>"
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
"</d:prop>"
"<d:status>HTTP/1.1 200 OK</d:status>"
"</d:propstat>"
"<d:propstat>"
"<d:prop>"
"<d:getcontentlength/>"
"<oc:downloadURL/>"
"<oc:dDC/>"
"</d:prop>"
"<d:status>HTTP/1.1 404 Not Found</d:status>"
"</d:propstat>"
"</d:response>"
"<d:response>"
"<d:href>/sharefolder/quitte.pdf</d:href>"
"<d:propstat>"
"<d:prop>"
"<oc:id>00004215ocobzus5kn6s</oc:id>"
"<oc:permissions>RDNVW</oc:permissions>"
"<d:getetag>\"2fa2f0d9ed49ea0c3e409d49e652dea0\"</d:getetag>"
"<d:resourcetype/>"
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
"<d:getcontentlength>121780</d:getcontentlength>"
"</d:prop>"
"<d:status>HTTP/1.1 200 OK</d:status>"
"</d:propstat>"
"<d:propstat>"
"<d:prop>"
"<oc:downloadURL/>"
"<oc:dDC/>"
"</d:prop>"
"<d:status>HTTP/1.1 404 Not Found</d:status>"
"</d:propstat>"
"</d:response>"
"</d:multistatus>";
LsColXMLParser parser;
connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
connect( &parser, SIGNAL(finishedWithoutError()),
this, SLOT(slotFinishedSuccessfully()) );
QHash <QString, qint64> sizes;
QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" ));
QVERIFY(!_success);
}
void testHrefUrlEncoding() {
const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>"
"<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
"<d:response>"
"<d:href>/%C3%A4</d:href>" // a-umlaut utf8
"<d:propstat>"
"<d:prop>"
"<oc:id>00004213ocobzus5kn6s</oc:id>"
"<oc:permissions>RDNVCK</oc:permissions>"
"<oc:size>121780</oc:size>"
"<d:getetag>\"5527beb0400b0\"</d:getetag>"
"<d:resourcetype>"
"<d:collection/>"
"</d:resourcetype>"
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
"</d:prop>"
"<d:status>HTTP/1.1 200 OK</d:status>"
"</d:propstat>"
"<d:propstat>"
"<d:prop>"
"<d:getcontentlength/>"
"<oc:downloadURL/>"
"<oc:dDC/>"
"</d:prop>"
"<d:status>HTTP/1.1 404 Not Found</d:status>"
"</d:propstat>"
"</d:response>"
"<d:response>"
"<d:href>/%C3%A4/%C3%A4.pdf</d:href>"
"<d:propstat>"
"<d:prop>"
"<oc:id>00004215ocobzus5kn6s</oc:id>"
"<oc:permissions>RDNVW</oc:permissions>"
"<d:getetag>\"2fa2f0d9ed49ea0c3e409d49e652dea0\"</d:getetag>"
"<d:resourcetype/>"
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
"<d:getcontentlength>121780</d:getcontentlength>"
"</d:prop>"
"<d:status>HTTP/1.1 200 OK</d:status>"
"</d:propstat>"
"<d:propstat>"
"<d:prop>"
"<oc:downloadURL/>"
"<oc:dDC/>"
"</d:prop>"
"<d:status>HTTP/1.1 404 Not Found</d:status>"
"</d:propstat>"
"</d:response>"
"</d:multistatus>";
LsColXMLParser parser;
connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
connect( &parser, SIGNAL(finishedWithoutError()),
this, SLOT(slotFinishedSuccessfully()) );
QHash <QString, qint64> sizes;
QVERIFY(parser.parse( testXml, &sizes, QString::fromUtf8("") ));
QVERIFY(_success);
QVERIFY(_items.contains(QString::fromUtf8("/ä/ä.pdf")));
QVERIFY(_items.contains(QString::fromUtf8("")));
QVERIFY(_items.size() == 2 );
QVERIFY(_subdirs.contains(QString::fromUtf8("")));
QVERIFY(_subdirs.size() == 1);
}
};
#endif
+1
Ver Arquivo
@@ -16,6 +16,7 @@ trans.fa = client_fa.ts
trans.fr = client_fr.ts
trans.gl = client_gl.ts
trans.it = client_it.ts
trans.nb_NO = client_nb_NO.ts
trans.nl = client_nl.ts
trans.pl = client_pl.ts
trans.pt_BR = client_pt_BR.ts

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