1
0
mirror of https://github.com/chylex/Nextcloud-Desktop.git synced 2026-04-05 05:34:18 +02:00

Compare commits

..

210 Commits

Author SHA1 Message Date
Daniel Molkentin
7a8a3855b8 Mac: Make <ESC> close the settings dialog again 2014-06-20 16:37:07 +02:00
Daniel Molkentin
603a238eb9 Disable minimize button for Preferences on Mac 2014-06-20 16:31:17 +02:00
Olivier Goffart
b7b6cf4b3f Shibboleth: Always ask for the password if we are going to open the log window
If we don't have the cookie in the keychain (e.g. the keychain is
unavailable) but there is still session cookie in the cookie jar,
showing the browser won't ask for authentication.
2014-06-20 16:25:35 +02:00
Daniel Molkentin
c855b783d9 NSIS: Remove duplicated entry 2014-06-20 15:53:10 +02:00
Daniel Molkentin
f593fc8e4d NSIS: Bump required libpng version to 16 2014-06-20 15:50:42 +02:00
Klaas Freitag
ae5cbb8451 Version: Bumped to rc1 2014-06-20 15:37:50 +02:00
Klaas Freitag
041066a252 Exclude: Add a missing free in case of empty lines.
This fixes Coverity CLT 12893
2014-06-20 15:15:35 +02:00
Daniel Molkentin
9ca82ba14d NSIS: add libwinpthread dependency 2014-06-20 14:58:05 +02:00
Olivier Goffart
b29a757b18 Revert "csync file util: Remove compare file function, not needed anymore."
This break the test.
And the function is aleady gone in master anyway

This reverts commit 407b3bebfe.
2014-06-20 14:29:43 +02:00
Daniel Molkentin
485a6926c5 FancyLineEdit: initialize all members
This fixes Coverity CID 12912
2014-06-20 13:46:57 +02:00
Daniel Molkentin
f3de6f46db Folder: Removed unused member _pathWatcher
This fixes Coverity CID 12914
2014-06-20 13:42:26 +02:00
Daniel Molkentin
1309dc27d9 Remove previously unused member
This fixes Coverity CID 12915
2014-06-20 13:40:55 +02:00
Daniel Molkentin
31469d6a3e Folderwizard: Properly initialize all members
This fixes coverity CID 12916
2014-06-20 13:38:36 +02:00
Daniel Molkentin
88776770f7 Legacy Propagator: Properly initialize members
This fixes coverity CID 12919
2014-06-20 13:36:15 +02:00
Daniel Molkentin
bbf8b9f8dd syncengine: properly initialize all members in ctor
This fixes Coverity CID 12922
2014-06-20 13:28:52 +02:00
Daniel Molkentin
6ff38d8005 Cleanup member initialization in Theme
This fixes coverity issue 12925
2014-06-20 13:28:52 +02:00
Daniel Molkentin
6d13b5cc43 wizard setuppage: Clean up and properly initialize members
This fixes Coverity CID 12926
2014-06-20 13:28:52 +02:00
Daniel Molkentin
73ab2804c4 owncloudwizard: properly initialize _account memember
This fixes Coverity CID 12927
2014-06-20 13:28:52 +02:00
Klaas Freitag
db3d2eed5f csync core: Remove logically dead code: Can never be reached.
This fixes Coverity CID 12881
2014-06-20 13:08:03 +02:00
Klaas Freitag
d995d1190f SyncFileItem: Some more proper member initializations.
This fixes a Coverity CID
2014-06-20 12:54:46 +02:00
Klaas Freitag
3217e42a0f SyncJournalDB: Initialize size member properly with 0
This fixes Coverity CID 12924
2014-06-20 12:37:49 +02:00
Klaas Freitag
1dd58a537e owncloudcmd: Fix structurally dead code.
This fixes Coverity CID 12928
2014-06-20 12:34:15 +02:00
Olivier Goffart
b34afa1afc reconcile: use the proper enum type
thankfully the value hapenned to be the same, but the type
is of CSYNC_FTW_..  and not CSYNC_VIO_FILE_TYPE
Detected by coverity (CID 12887)
2014-06-20 11:51:07 +02:00
Olivier Goffart
b7c9fa6d5f csync_owncloud: silent CID 12883 2014-06-20 11:51:07 +02:00
Olivier Goffart
61ad376bf4 accountsettings: silent coverity warning 12884
We use f anyway, so if we are going to test if it's null we can as
well return
2014-06-20 11:51:07 +02:00
Klaas Freitag
407b3bebfe csync file util: Remove compare file function, not needed anymore.
This also fixes Coverity CID 12890 and CID 12898
2014-06-20 11:39:28 +02:00
Olivier Goffart
f04c80dd0e httpbf: silent coverity issue 12905 2014-06-20 11:33:29 +02:00
Olivier Goffart
1e788d3d60 folderwizard: fix possible use of null pointer
Coverity issue 12907
2014-06-20 11:29:28 +02:00
Olivier Goffart
83171bf025 accountsettings: remove unused function
It was moved into owncloudgui before
And it was broken (bad use of QUrl and use of null pointer
2014-06-20 11:27:37 +02:00
Olivier Goffart
2e51721851 owncloudgui: Fix compilation 2014-06-20 11:26:41 +02:00
Olivier Goffart
4d4a0148e4 owncloudgui: use QUrl::fromLocalFile 2014-06-20 11:21:36 +02:00
Klaas Freitag
b144a5bbf9 csync_exclude: Add a missing free of path components.
This fixes Coverity CID 12895
2014-06-20 11:14:50 +02:00
Olivier Goffart
5225fe07e0 csync_owncloud_recursive_propfind: "fix" possible memory leak
This was only leaking memory if ne_path_parent returns 0, which
should never happen

This fixes coverity issue 12897
2014-06-20 11:12:45 +02:00
Klaas Freitag
85cdbd1f1d stateDB: Close the file descriptor even if stat failed.
This fixes Coverity CID 12897
2014-06-20 11:05:40 +02:00
Klaas Freitag
e4f8a136f1 StateDB: Free locale string also if attribs are invalid.
This fixes Coverity CID 12898
2014-06-20 11:05:40 +02:00
Daniel Molkentin
c263c38cdf statedb.c: fix potential memory leak on win32
This fixes coverity issue 12898
2014-06-20 10:58:03 +02:00
Daniel Molkentin
df8553e878 httpbf.c: Fix resource leak
This fixes Coverity CID 12902
2014-06-20 10:58:03 +02:00
Daniel Molkentin
bec66c85d4 Fix potential memory leak
This fixes Coverity CID 12893
2014-06-20 10:58:03 +02:00
Daniel Molkentin
f9710cc1d5 c_time: Fix resource leak in error case
This fixes Coverity CID 12903
2014-06-20 10:58:03 +02:00
Daniel Molkentin
6b041b0846 Fix use-after-free in QNAM propagator
This fixes Coverity CID 12929
2014-06-20 10:58:03 +02:00
Klaas Freitag
d0c992c991 Updater: Free tmp variable that might point to temp malloced memory
This fixes Coverity CID 12900
2014-06-20 10:41:01 +02:00
Klaas Freitag
9ee86cf06b Fix resource leak in win32 code path, added free of locale filename.
This fixes Coverity CID 12901
2014-06-20 10:25:00 +02:00
Olivier Goffart
646eafb05d Legacy propagator jobs: Do not limit bandwidth when aborting
When aborting, we want the last job to be as fast as possible
as it blocks the UI.  So don't limit the bandwidth in that case
2014-06-18 15:09:19 +02:00
Olivier Goffart
0880444e37 Syncengine: Wait for the neon thead to be finished before destroying the Propagator and calling csync_commit
The legacy job might still need the neon session and the propagator.
We need to make sure the thread exits before.

This fixes crash when pausing a sync made with the legacy jobs
(for example when there is network limitation)
This should fix https://github.com/owncloud/enterprise/issues/200
2014-06-18 15:08:23 +02:00
Olivier Goffart
0a953b91f9 csync_vio_local: fix memory leak on windows 2014-06-17 16:40:38 +02:00
Klaas Freitag
b71881d300 SyncEngine: Use QSet for the seenFiles rather than QHash.
We can save some memory here as the seenFiles list can be long.
2014-06-17 16:30:11 +02:00
Daniel Molkentin
b91967f4d9 Fix regression over 1.5: Fix non-fba auth for Shib IdPs 2014-06-17 14:53:23 +02:00
Klaas Freitag
2d234cd96f Propagator: Handle file open error properly and log error message. 2014-06-16 13:35:50 +02:00
Klaas Freitag
1230e87330 Propagator: Give a more specific error message on file remove.
If the file is removed during it is synced up, there is now a correct
error message saying that, rather than "the file has changed during
upload."
2014-06-16 13:34:59 +02:00
Daniel Molkentin
b2966fecc7 Shib: remove slotLoadFinished() from webview dtor
This is a relict from when the webview was reused.
It is now pointless, since it's now destruct-on-close.
2014-06-14 03:00:18 +02:00
Daniel Molkentin
4abe00ff6c Shib: Ensure browser view gets closed before QNAM
Otherwise, QWebPage tries to delete its QNetworkReplies, which have
already been deleted by the QNAM destruction, who is their parent.

Fixes #1840
2014-06-14 03:00:18 +02:00
Klaas Freitag
e1db834ec9 Add missing cmakedefine for HAVE_ASPRINTF and minor cleanup.
Fixes windows build.
2014-06-13 13:30:59 +02:00
Klaas Freitag
c72c72a106 FolderWizard: Get folder map from FolderMan rather than store locally.
If the Folder::Map object is kept locally in the wizard, changes to
the map are not reflected there, as they happen when signing out.
This fixes bug #1875
2014-06-12 23:17:13 +02:00
Daniel Molkentin
4a5ef8f173 Fix a possible crash caused by a dangling pointer 2014-06-12 10:29:17 +02:00
Klaas Freitag
ed26bcb3e7 Theme: Show the stringified app version rather than the major version.
This was a regression, we changed that by accident in 1.6.0.

(cherry picked from commit 760ecd71fc)
2014-06-10 17:05:15 +02:00
Daniel Molkentin
b814b45e50 Add version and product information to installer properties 2014-06-05 11:51:12 +02:00
Daniel Molkentin
ded8914df2 [Janitor] Bump version to 1.6.1pre 2014-06-05 11:51:12 +02:00
Olivier Goffart
7a7b0e8939 propagator: Ignore new directory inside removed directory.
This fixes te bug if one create a tree of folders and subfolders
and delete them while they are uploading. Some folder would
reappears
2014-06-04 16:37:46 +02:00
Olivier Goffart
a4f6370774 propagator: do not update perent directory etag before sub directories are removed
Direcotries are removed at the end, and we don't want to update
parent directory etag before the delete is performed, or the next
sync may read from db and think the files are not removed.

Issue #1845
2014-06-04 12:31:30 +02:00
Olivier Goffart
6605a89990 csync_statedb: Fix wrong % code in debug output
%ld is for long, but int64_t is larger than long on windows
2014-06-03 18:28:31 +02:00
Olivier Goffart
6e10b8c5c4 Propagator: Recover from 'precondition failed' error
When we detect a precondition failed, it is possible that it is
because the etag in the database is wrong.  We must therefore not
read from the database on the next sync.  In order to avoid that, we
reset the etag of parent directories to invalid values

Fixes #1767
2014-06-03 17:22:40 +02:00
Olivier Goffart
24616bead4 Fix syncing a folder with '#' in the name
Or an url with '#'

Fixes #1838

The problem is a bug fixed in Qt5 now breaks.
In Qt4, QUrl::setPath() did not properly handle path with '#' in them
and QUrl::toString would restitute the '#'.

But csync will blindly do  "uri + path" before passing the path to
VIO.  because csync_update has no idea that the VIO plugin need special
encoding, the encoding cannot be done there.  But csync_owncloud then
encodes the full path.  So if the uri contains '#', it must not be already
encoded or there will be two encoding.
2014-06-03 15:45:10 +02:00
Olivier Goffart
13f9970257 Fix some possible "Precondition Failed" bug
The problem was if there was a false conflict: the file has been touched
both on the server and the client.
 - etag has changed on the server
 - mtime has changed on the server and the client and is the same
 - and file size is the same on both the server and the client

This may also happen if the file is uploaded on the server, but the client
looses connection (or crashes) before it get notified of the etag.

In both tree, the instruction is EVAL, but we reduce it to a NONE because
we detected that the conflict is 'false'.  Still, we need to update the db
with the new etag.  (_should_update_db)
The problem was that we would set the flag on the wrong tree.
This was not a problem when the file was NEW on both side since  we checked
for null etag and used the other one then.
2014-06-03 12:23:30 +02:00
Daniel Molkentin
746c15b4aa Remove debug layout 2014-06-02 19:38:04 +02:00
Daniel Molkentin
7e65c9741e [Shib] Ensure only one fetch job can open the browser 2014-06-02 17:41:49 +02:00
Jenkins for ownCloud
a50e7c1b48 [tx-robot] updated from transifex 2014-06-02 01:25:23 -04:00
Jenkins for ownCloud
0ae82e2041 [tx-robot] updated from transifex 2014-06-01 02:06:11 -04:00
Jenkins for ownCloud
22af756fe3 [tx-robot] updated from transifex 2014-06-01 01:25:21 -04:00
Jenkins for ownCloud
2f1bec28dd [tx-robot] updated from transifex 2014-05-31 01:25:23 -04:00
Markus Goetz
022a3fcd92 OS X: Fix localFileNameClash
We need to compare the other way round and compare only the file name
because our sync directory might be symlinked and then resolve to
another canonical path (but we were only interested in the filename part
anyway)
2014-05-30 15:47:53 +02:00
Daniel Molkentin
064dcdb25a 1.6.0 final 2014-05-30 12:38:44 +02:00
Jenkins for ownCloud
938dce7fa6 [tx-robot] updated from transifex 2014-05-30 01:25:21 -04:00
Olivier Goffart
0151682a53 Make sure that OwncloudPropgator::finished is only emit once
When we abort, each job currently running may result in a call to finished().
It used to cause a crash because we would unlock the _syncMutex twice

Fixes #1793
2014-05-29 12:15:13 +02:00
Olivier Goffart
864f2cdc7d remove the _syncMutex and replace it by a simple bool 2014-05-29 11:35:13 +02:00
Jenkins for ownCloud
77ddedc859 [tx-robot] updated from transifex 2014-05-29 01:25:27 -04:00
Daniel Molkentin
0c1ab533e6 Do not trim serial numbers
This broke in a refactoring. The 'true' was interpreted as length of 1.

Fixes part of #1436
2014-05-28 21:16:00 +02:00
Olivier Goffart
1dd7f736d0 Fix another crash at exit
Fixes #1794
2014-05-28 19:59:35 +02:00
Olivier Goffart
571c199db8 remove broken connection
Fixes #1822
2014-05-28 18:11:39 +02:00
Daniel Molkentin
40715cbc77 Update ChangeLog 2014-05-28 16:33:01 +02:00
Daniel Molkentin
3d2a2df86f Allow to set a smaller timeout value in the config file
Added to debug #1724
2014-05-28 16:28:22 +02:00
Daniel Molkentin
86a48b52e9 Shib: Show a notification whenever the shib session times out
This is designed as a passive popup notification so that it will
not surprise or annoy the users.

Fixes Enterprise issue #179
2014-05-28 15:25:43 +02:00
Olivier Goffart
ebe1f986f1 Only remove session cookies
This should disconnect without loosing long lived cookie
2014-05-28 15:24:14 +02:00
Olivier Goffart
dd1152dd4f Clear all cookies when loging out 2014-05-28 11:41:06 +02:00
Olivier Goffart
ce9bfd319a Fix the sib window re-appearing.
When the windows is accepted, do not emit fetched which means the process is finished
one must first check the username is valid
2014-05-28 10:18:57 +02:00
Daniel Molkentin
f591ac6549 CookieJar: Reduce debug noise 2014-05-28 10:05:32 +02:00
Daniel Molkentin
4fd368c992 ShibCredentials: Ensure that _stillValid is not reset while the browser window is open
This will cause the browser window to open again after it has been told to close
if a network job has run in the background while the browser window was visible.

Fixes #1814
2014-05-28 10:05:32 +02:00
Jenkins for ownCloud
93f453057b [tx-robot] updated from transifex 2014-05-28 01:25:21 -04:00
Klaas Freitag
5a069d274b Pushed version suffix to rc3 2014-05-27 11:41:01 +02:00
Klaas Freitag
e275ad3866 Emit the sync finished signal a bit delayed.
This allows folder watcher events comnig in before the sync is marked
finished. This avoids "endless syncing" as described in bug #1808
2014-05-27 11:35:07 +02:00
Olivier Goffart
5813f63df8 Do not runs the check connection timer when there is no configured account
in order to avoid popup of the wizzard every 32 seconds

Fixes #1812
2014-05-27 11:05:09 +02:00
Jenkins for ownCloud
9a1f8ccf7b [tx-robot] updated from transifex 2014-05-27 01:25:28 -04:00
Klaas Freitag
449c00f019 No need to check for case preserving filesystem here.
That is done in the utility function instead.
2014-05-26 18:28:52 +02:00
Klaas Freitag
6017eb7ca6 Case clash check for local remove plus native separators. 2014-05-26 18:28:25 +02:00
Klaas Freitag
f1b2417967 Add check for case clash for legacy propagator download. 2014-05-26 18:28:25 +02:00
Klaas Freitag
181383e5f1 Check for case preserving file system in localCaseClash 2014-05-26 18:28:25 +02:00
Markus Goetz
c1b9d5c653 Propagator: Implement localFileNameClash for OS X 2014-05-26 17:36:52 +02:00
Klaas Freitag
964c3ac7bf Check for local file name clash before local renaming.
Return a proper error message in case.
2014-05-26 17:00:40 +02:00
Daniel Molkentin
6d8afabf41 Find export macro 2014-05-26 16:33:04 +02:00
Daniel Molkentin
0a7dbeb778 Export CookieJar 2014-05-26 16:29:26 +02:00
Olivier Goffart
3228fde4af Only set should_update_etag for directories in the update case
If there is an error during the local rename for a file, we don't
want to write the entry for the destination before because there might be
an error
2014-05-26 16:11:05 +02:00
Daniel Molkentin
0582abe8dd Shib: Wizard: Return to IdP selection when returning to creds page 2014-05-26 15:57:01 +02:00
Olivier Goffart
81f410970f ammend previous change 2014-05-26 15:01:26 +02:00
Olivier Goffart
e75c5236f2 Properly report errors when renaming a file
That is especially usefull when renaming to an existing file with a different case
2014-05-26 14:51:53 +02:00
Olivier Goffart
8a671c40d1 Make FolderMan a member of the application
The goal here is that it is going to be destroyed with the application
It need to be destoyed so the folder are destroyed, which is required
for properly finishing the sync while exiting.

It must not be destroyed after the application because the QSQLite plugin
may be already destroyed in that case.

Since the constructor of FolderMan is called earlier, we can't call the
config file too early

 fixes 1793
2014-05-26 14:37:15 +02:00
Olivier Goffart
50ce0f9681 Fix crash at exit when there is a log after the Logger has been destroyed
Use a proper static Logger instead of allocating one,  and cleanup
the QTMessageLogger when it is destroyed
2014-05-26 14:37:14 +02:00
Daniel Molkentin
a60902b33d Make sure the settings window is brought up when minimized
Fixes #1804
2014-05-26 14:32:08 +02:00
Olivier Goffart
5220786cf2 do not blacklist fatal error 2014-05-26 12:27:16 +02:00
Olivier Goffart
99cead68f5 Fix crash when aborting
When aborting, the slotFinished will destroy all the Jobs, but they need
one more even loop to finish cleanups

Fixes #1793
2014-05-26 12:23:25 +02:00
Olivier Goffart
7a209ba376 leak fix 2014-05-26 12:07:00 +02:00
Olivier Goffart
f9263da3de Fix crash when the account config is gone and there are still folder
In rare case (due to a bug in QSettings) the account config may disapear
We should not crash in that case
2014-05-26 11:08:32 +02:00
Daniel Molkentin
3f724e1c6a Fix Pref window for good
This was forgotten in 18677dbc3f
2014-05-26 09:37:43 +02:00
Jenkins for ownCloud
c9d3f7a0eb [tx-robot] updated from transifex 2014-05-26 01:25:25 -04:00
Jenkins for ownCloud
072af16f3b [tx-robot] updated from transifex 2014-05-25 02:06:12 -04:00
Jenkins for ownCloud
d2b6c626b5 [tx-robot] updated from transifex 2014-05-25 01:25:28 -04:00
Daniel Molkentin
115276408a Merge pull request #1805 from wakeup/master
Fix some typos
2014-05-24 15:26:06 +02:00
Volkan Gezer
9abffdb1a6 fix typo 2014-05-24 15:04:42 +02:00
Volkan Gezer
5b0307446a fix spacing 2014-05-24 15:03:45 +02:00
Jenkins for ownCloud
0f20a4f546 [tx-robot] updated from transifex 2014-05-24 01:25:29 -04:00
Klaas Freitag
1b2875c20a Use the moved implementation of the name clash detection method. 2014-05-23 18:58:21 +02:00
Klaas Freitag
bbdf7bf955 Check for case clash on downloads. 2014-05-23 18:58:21 +02:00
Klaas Freitag
57359968ed Added method localFileNameClash
Also reordered the implementations a bit.
2014-05-23 18:58:08 +02:00
Klaas Freitag
ea9f302b7a Read the blacklist entries case insensitive in case the file
system is only case preserving.
2014-05-23 16:13:35 +02:00
Klaas Freitag
ef0a3c212e Add a utility function fsCasePreserving.
Returns true if the underlying file system is case preserving instead
of case sensitive. That is true for Mac and Windows currently. Only
Linux has a case sensitive file system usually.
2014-05-23 16:13:35 +02:00
Daniel Molkentin
18677dbc3f Fix on-top/below-others window problem
- Don't give the settings window an always-on-top hint, or else
  sub dialogs will pop-under. Also, people seem to (ab-)use it
  as a status monitor... well

- raiseWidget() can only really do one thing: remove the dialog status
  from dialogs without a parent due to a bug in Qt. The previous
  implementation never really worked. Tested on Mac and Gnome 3 so far.

Fixes #1795
Fixes parts of #1775
2014-05-23 16:00:50 +02:00
Klaas Freitag
7e8b403116 More progress on the CI problem detection. 2014-05-22 17:12:59 +02:00
Klaas Freitag
1303379c9e Remove useless global varialbe for auth callback. 2014-05-22 12:54:14 +02:00
Daniel Molkentin
b995cd318c Fix/cleanup PropagateLocalMkDir::start() 2014-05-22 10:16:33 +02:00
Daniel Molkentin
ed19107161 Remove useless check. QFile::exists() is CI on CI filesystems
Tested on OS X and Windows
2014-05-22 10:06:10 +02:00
Jenkins for ownCloud
1b67f253dc [tx-robot] updated from transifex 2014-05-22 01:25:23 -04:00
Markus Goetz
667c835c49 Revert "remove auth callback setting in the csync module."
This commit broke syncing.
We need the callback to supply the password.

This reverts commit 8738128504.
2014-05-21 20:02:22 +02:00
Daniel Molkentin
5b298abba1 Revert "Set an "active" role for the menubar icon on Mac"
Apart from a small mistake in this commit, there seems to be
something else wrong.

This reverts commit 97362cff32.
2014-05-21 13:00:20 +02:00
Daniel Molkentin
4edbeece49 Fix connection following the update of the QtSingleApplication classes 2014-05-21 12:31:44 +02:00
Daniel Molkentin
97362cff32 Set an "active" role for the menubar icon on Mac
Fixes #1730
2014-05-21 11:19:38 +02:00
Daniel Molkentin
3db3c7b876 Update QtSingleApplication and QtLockedFile
Fixes stale temp file issues, and is needed for blocking support.
2014-05-21 11:19:38 +02:00
Klaas Freitag
8738128504 remove auth callback setting in the csync module. 2014-05-21 11:09:02 +02:00
Klaas Freitag
069eaf9170 Clear the authentication callbacks set before. 2014-05-21 11:09:02 +02:00
Klaas Freitag
d0b9b002e4 Show the sync icon in case the status is not yet defined.
This fixes the problem that on the first sync, no proper status icon is
shown on a potential long update phase.
2014-05-21 11:09:01 +02:00
Olivier Goffart
bdba56f60b Always wait on the thread before emiting finished
This ensure that there would be no way to have two thread running

Refactor all the location where finished is called in a single function
2014-05-20 12:32:06 +02:00
Jenkins for ownCloud
7087dbc445 [tx-robot] updated from transifex 2014-05-20 01:25:31 -04:00
Daniel Molkentin
7ade4bb6e6 AccountSettings: Handle button states more correctly
Fixes #1779
2014-05-19 15:46:23 +02:00
Daniel Molkentin
86117aed0d autostart unix impl: use mkpath instead of mkdir
Fixes TestUtility::testLaunchOnStartup(), if .config/ does not exist.
2014-05-19 12:42:04 +02:00
Jenkins for ownCloud
ed3d9a7479 [tx-robot] updated from transifex 2014-05-19 01:25:29 -04:00
Jenkins for ownCloud
3746a2efff [tx-robot] updated from transifex 2014-05-18 01:25:29 -04:00
Jenkins for ownCloud
9b53cc66e7 [tx-robot] updated from transifex 2014-05-17 01:25:38 -04:00
Klaas Freitag
43fe7b0d55 Detect directory case sensitivity clash on windows 2014-05-16 15:24:01 +02:00
Daniel Molkentin
5aa6f81ef3 1.6.0rc2 2014-05-16 09:50:50 +02:00
Jenkins for ownCloud
f838f28185 [tx-robot] updated from transifex 2014-05-16 01:25:29 -04:00
Olivier Goffart
e1f8eb5aa5 Another way to force a sync when choosing 'Keep files' 2014-05-15 19:36:01 +02:00
Olivier Goffart
f40a054cb7 Revert "Re-sync immediatly after "Keep files" when all files were removed"
This causes infinite sync loops

This reverts commit 8b469d3992.
2014-05-15 19:29:40 +02:00
Daniel Molkentin
adfb163593 1.6.0rc1 2014-05-15 17:22:01 +02:00
Daniel Molkentin
81c768099e Folder: Correctly reflect paused state after restart 2014-05-15 15:04:48 +02:00
Daniel Molkentin
4bcaebb322 Decrease debug noise 2014-05-15 15:04:48 +02:00
Olivier Goffart
8b469d3992 Re-sync immediatly after "Keep files" when all files were removed
Fixes #1710
2014-05-15 11:48:01 +02:00
Olivier Goffart
bb929db7e6 fix warning 2014-05-15 11:29:23 +02:00
Olivier Goffart
90ee274744 We need to call csync_commit in every error cases
Else there will still be outdated tree in the memory and the further sync
will be confused

Relates to #1710
2014-05-15 11:18:06 +02:00
Daniel Molkentin
9f6e9f8e1b Fix crash: if the credentials cannot be cast, don't deref, assume change 2014-05-15 11:12:18 +02:00
Klaas Freitag
943f9f60e3 Documented core dump catching 2014-05-15 11:11:13 +02:00
Klaas Freitag
f89bfce068 Enable core dumping if the env variable OWNCLOUD_CORE_DUMP is defined
Set OWNCLOUD_CORE_DUMP to anything to get a core dump in case of
crashing.
2014-05-15 11:01:21 +02:00
Klaas Freitag
ef44a59bed Better debugability. 2014-05-15 09:45:50 +02:00
Klaas Freitag
d96139f698 Commented verbose logging. 2014-05-15 09:45:50 +02:00
Daniel Molkentin
de970eb0a5 Fix wizard flow with shibboleth 2014-05-15 09:43:26 +02:00
Jenkins for ownCloud
7a28b44128 [tx-robot] updated from transifex 2014-05-15 01:25:29 -04:00
Daniel Molkentin
17a2e224c4 Fix memleak 2014-05-14 12:53:12 +02:00
Klaas Freitag
87386ce001 Fix testcase.
It failed because the directory where change happened triggered a
notification within the second before, so the event was skipped.
2014-05-14 12:49:11 +02:00
Daniel Molkentin
5ed4710d64 Merge pull request #1726 from owncloud/debian_bsd
Make Debian GNU/kFreeBSD compile
2014-05-14 12:20:17 +02:00
Klaas Freitag
5493c22584 Do not dispatch invalid progress information to avoid "unknown" messages 2014-05-14 11:52:22 +02:00
Klaas Freitag
64f4d1b387 Removed block parameter from terminateSync.
Do not pretend to immediately terminate the sync but let csync
finish planfully and free the mutex.
2014-05-14 11:52:22 +02:00
Daniel Molkentin
cdd8c8165b Add missing header to fix Qt5 compilation 2014-05-14 11:22:56 +02:00
Daniel Molkentin
16ffd7fbe4 Merge pull request #1765 from owncloud/shibcookies
CookieJar refactoring required to overcome issues in Shibboleth support
2014-05-14 11:14:42 +02:00
Daniel Molkentin
ba959f7cf9 CookieJar refactoring required to overcome issues in Shibboleth support
The shibboleth implementation no longer maintains its own QNAM.

Instead, MirallAccessManager now holds a custom QNAM implementation
which saves cookies to a file on disk.

This patch also reduces some complexity wrt the browser window,
which used to be deleted via a roundtrip to its callee, which
is not longer required.

Fixes #1764 and Enterprise bug #165

Going forward, AbstractCredentials::getQNAM() could maybe removed entirely.
2014-05-14 11:11:45 +02:00
Jenkins for ownCloud
cf145feed8 [tx-robot] updated from transifex 2014-05-14 01:25:29 -04:00
hefee
07f57b1982 make Debian GNU/kFreeBSD compile 2014-05-13 16:51:42 +02:00
Klaas Freitag
e62eb62a01 Merge pull request #1179 from tomswartz07/master
Add exclusion for OSX ._<filename> files
2014-05-13 15:35:50 +02:00
Olivier Goffart
574e030caf Use a different key than "user" to store the shib user
There is a HACK from commit fa0a2764a4
Which save the http user as a user for all credidentials, but that
cannot work with shibboleth

Fixes https://github.com/owncloud/enterprise/issues/175
2014-05-13 11:54:36 +02:00
Klaas Freitag
3705a42375 Remove misleading error message of "unknown error" for custom errnos. 2014-05-13 10:39:37 +02:00
Jenkins for ownCloud
a9ffd1d0cf [tx-robot] updated from transifex 2014-05-13 01:26:28 -04:00
Klaas Freitag
f86dd1cbbf Merge pull request #1747 from owncloud/doc_optional
install doc targets in any case. Thanks for the patch!
2014-05-12 11:35:59 +02:00
Jenkins for ownCloud
af066cc733 [tx-robot] updated from transifex 2014-05-12 01:26:26 -04:00
hefee
822650719b RemoveADir test should realy test, if it is notified 2014-05-11 17:08:30 +02:00
Jenkins for ownCloud
95747fbaea [tx-robot] updated from transifex 2014-05-10 01:26:26 -04:00
Jenkins for ownCloud
321058ef74 [tx-robot] updated from transifex 2014-05-09 01:26:28 -04:00
hefee
71c11373d8 install doc targets in any case.
If a user only builds some parts of the documentation and afterwards
wants to install owncloud-client afterwards via "make install", the
built parts should be installed in any case.
2014-05-08 13:44:35 +02:00
Jenkins for ownCloud
d5ba288dd5 [tx-robot] updated from transifex 2014-05-08 01:26:27 -04:00
Olivier Goffart
091e9bbd52 Fix crash when _engine is not available
Fixes #1671 and #1675
2014-05-07 16:17:08 +02:00
Olivier Goffart
ce09e11011 Revert "Do not dereference the _engine member variable without check."
bubbleUpSyncResult is only called from slotSyncFinished, so if _engine
is invalid there, it is also invalid in slotSyncFinished

This reverts commit aee7515d42.
2014-05-07 16:13:43 +02:00
Olivier Goffart
d7a226e0e6 Silent warning:
warning: no previous prototype for ‘set_csync_file_locked_or_open_ext’ [-Wmissing-prototypes]
2014-05-07 12:38:57 +02:00
Olivier Goffart
f034bcb9ae only increment the progressbar for files when the file has been fully transfered 2014-05-07 12:35:02 +02:00
Jenkins for ownCloud
4c77a04514 [tx-robot] updated from transifex 2014-05-07 01:26:27 -04:00
Klaas Freitag
a50c39cd0c Maintain the original inode value for renamed files.
In case two renames are done on the same file/folder very quickly we
lost the information that the second operation was also a rename. That
was because we tried to get the inode value from a stat on the file once
the first rename was finished. But at that point, the file was already
gone because of the second rename.

Now the original inode is kept and written to db in case the file can
not be stat'ed.

This fixes bug #1737
2014-05-06 12:55:54 +02:00
Klaas Freitag
370dd99e47 Super useful source comment. 2014-05-06 09:30:50 +02:00
Jenkins for ownCloud
f97fbe868f [tx-robot] updated from transifex 2014-05-05 01:26:30 -04:00
Jenkins for ownCloud
2ce6560b6e [tx-robot] updated from transifex 2014-05-04 01:26:32 -04:00
Jenkins for ownCloud
2b4e14c4fc [tx-robot] updated from transifex 2014-05-03 01:26:31 -04:00
Olivier Goffart
1631cfdaf1 Fix not blacklisting error 5xx 2014-05-02 17:26:28 +02:00
Olivier Goffart
2e76fe87c2 Fix reporting the right error in a GET
We always reported the lack of e-tag instead of the real error
2014-05-02 17:26:28 +02:00
Markus Goetz
6c44f53645 Set network timeout to 300 sec
As per previously used values (see source and changelog)
2014-05-02 15:35:40 +02:00
Olivier Goffart
988c162d2f Have only one place where we read the timeout 2014-05-02 13:04:53 +02:00
Olivier Goffart
3d8d4fecd7 delete dead code 2014-05-02 11:50:20 +02:00
Jenkins for ownCloud
f8525fa5a0 [tx-robot] updated from transifex 2014-05-02 01:27:04 -04:00
Jenkins for ownCloud
6e48eb9397 [tx-robot] updated from transifex 2014-05-01 01:26:48 -04:00
Olivier Goffart
88cb047197 Add a timeout when using the QNAM propagation 2014-04-30 18:17:49 +02:00
Klaas Freitag
7f7154ed40 Auto generate the Export header.
This should fix oem builds.
2014-04-30 13:55:40 +02:00
Klaas Freitag
a8c1ffc2f4 Add a header file for owncloudcmd.cpp to avoid (auto)moc problems. 2014-04-30 13:55:40 +02:00
Klaas Freitag
df8b5b1ea6 Removed unused Q_OBJECT 2014-04-30 13:55:40 +02:00
Olivier Goffart
ce50cdecf1 Add one byte per files in the computation of the progress bar
So it feels like the progress bar is moving when operating of file
that are empty or when deleting or renaming files
2014-04-30 13:20:20 +02:00
Olivier Goffart
77c7439329 Don't include the directory size in the overall progress
We don't include them in the total amout of files so it should
not be included in the progress either.

Also, for some reasons directories seems to be 16kB on windows
2014-04-30 12:57:30 +02:00
Olivier Goffart
752112dbaa Initialize the size properly on windows 2014-04-30 12:06:55 +02:00
Markus Goetz
925c6485e6 Propagator: Dont show silly string for non-error 2014-04-30 11:36:57 +02:00
Tom Swartz
738f026c41 Merge pull request #1 from owncloud/master
Merge with owncloud:master
2013-11-25 12:29:22 -08:00
Tom Swartz
32e205f6ce Add exclusion for OSX ._<filename> files
Exclude older OSX metadata ._<filename> files from sync, improving
cross-platform sync experience.

Tested-on: arcturus <20 Nov 2013>
2013-11-20 10:26:36 -05:00
140 changed files with 6250 additions and 4392 deletions

View File

@@ -1,18 +1,22 @@
ChangeLog
=========
version 1.6.0 (release 2014-04- )
version 1.6.0 (release 2014-05-30 )
* Minor GUI improvements
* Qt5 compile issues fixed
* Ignore sync log file in filewatcher
* Install libocsync to private library dir and use rpath to localize
* Fix reconnect after server disconnect
* Fix crashes
* Fix "unknown action" display in Activity window
* Fix memory leaks
* Respect XDG_CONFIG_HOME environment var
* Handle empty fileids in the journal correctly
* Add abilility to compile libowncloudsync without GUI dependendy
* Fix SSL error with previously-expired CAs on Windows
* Fix incorrect folder pause state after start
* Fix a couple of actual potential crashes
* Improve Cookie support (e.g. for cookie-based load-balancers)
* Introduce a general timeout of 300s for network operations
* Improve error handling, blacklisting
* Job-based change propagation, enables faster parallel up/downloads
(right now only if no bandwidth limit is set and no proxy is used)
* Significantly reduced CPU load when checking for local and remote changes
@@ -30,6 +34,7 @@ version 1.6.0 (release 2014-04- )
* Mac OS X: Fix UI inconsistencies on Mavericks
* Shibboleth: Warn if authenticating with a different user
* Remove vio abstraction in csync
* Avoid data loss when a client file system is not case sensitive
version 1.5.3 (release 2014-03-10 )
* Fix usage of proxies after first sync run (#1502, #1524, #1459, #1521)

View File

@@ -1,10 +1,10 @@
set( MIRALL_VERSION_MAJOR 1 )
set( MIRALL_VERSION_MINOR 6 )
set( MIRALL_VERSION_PATCH 0 )
set( MIRALL_VERSION_PATCH 1 )
set( MIRALL_SOVERSION 0 )
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
set( MIRALL_VERSION_SUFFIX "beta2" ) #e.g. beta1, beta2, rc1
set( MIRALL_VERSION_SUFFIX "rc1") #e.g. beta1, beta2, rc1
endif( NOT DEFINED MIRALL_VERSION_SUFFIX )
if( NOT DEFINED MIRALL_VERSION_BUILD )

View File

@@ -3,13 +3,13 @@ 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_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_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} είναι ήδη εγκατεστημένη.\n\nΕπιλέξτε τη διαδικασία που επιθυμείτε να πραγματοποιείσετε και επιλέξτε Επόμενο για να συνεχίσετε."
StrCpy $PageReinstall_OLD_Field_1 "Μια νεώτερη έκδοση της ${APPLICATION_NAME} είναι ήδη εγκατεστημένη! Δεν συνίσταται να εγκαταστείσετε μια παλαιότερη έκδοση. Εάν θέλετε πραγματικά να εγκαταστήσετε αυτήν την παλαιότερη έκδοση, είναι καλύτερο να απεγκαταστήσετε την τρέχουσα έκδοση πρώτα. Επιλέξτε τη διαδικασία που επιθυμείτε να εκτελέσετε και επιλέξτε Επόμενο για να συνεχίσετε."
StrCpy $PageReinstall_SAME_Field_1 "Η ${APPLICATION_NAME} ${VERSION} είναι ήδη εγκατεστημένη.\n\nΕπιλέξτε τη διαδικασία που επιθυμείτε να εκτελέσετε και επιλέξτε Επόμενο για να συνεχίσετε."
StrCpy $PageReinstall_SAME_Field_2 "Προσθήκη/ Επανεγκατάσταση συνιστωσών"
StrCpy $PageReinstall_SAME_Field_3 "Απεγκατάσταση ${APPLICATION_NAME}"
StrCpy $UNINSTALLER_APPDATA_TITLE "Απεγκατάσταση ${APPLICATION_NAME}"
@@ -23,16 +23,16 @@ 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 "Συντόμευση στην επιφάνεια εργασίας της "
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Συντόμευση Ταχείας Εκκίνησης της "
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Αφαίρεση του φακέλου δεδομένων της ${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_APPDATA_CHECKBOX "Ναι, διαγραφή αυτού του φακέλου δεδομένων."
StrCpy $UNINSTALLER_FILE_Detail "Εγγραφή Εφαρμογής Απεγκατάστασης"
StrCpy $UNINSTALLER_REGISTRY_Detail "Εγγραφή Κλειδιών μητρώου (Registry) της Εφαρμογής Εγκατάστασης"
StrCpy $UNINSTALLER_FINISHED_Detail "Ολοκλήρωση"
StrCpy $UNINSTALL_MESSAGEBOX "Φαίνεται πως η ${APPLICATION_NAME} είναι εγκατεστημένη στον κατάλογο '$INSTDIR'.$\n$\nΣυνέχιση παρ' όλα αυτά (δεν συνίσταται);"
StrCpy $UNINSTALLER_FINISHED_Detail "Ολοκληρώθηκε"
StrCpy $UNINSTALL_MESSAGEBOX "Δεν φαίνεται να είναι εγκατεστημένηη η ${APPLICATION_NAME} στον κατάλογο '$INSTDIR'.$\n$\nΣυνέχιση παρ' όλα αυτά (δεν συνίσταται);"
StrCpy $UNINSTALL_ABORT "Η απεγκατάσταση ματαιώθηκε από το χρήστη"
StrCpy $INIT_NO_QUICK_LAUNCH "Συντόμευση Ταχείας Εκκίνησης (Μ/Δ)"
StrCpy $INIT_NO_DESKTOP "Συντόμευση Επιφάνειας Εργασίας (αντικαθιστά υπάρχουσα)"

View File

@@ -9,7 +9,7 @@ StrCpy $PageReinstall_NEW_Field_3 "Kald
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Zaten Yüklü"
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "${APPLICATION_NAME} uygulamasını nasıl yüklemek istediğinizi seçin."
StrCpy $PageReinstall_OLD_Field_1 "${APPLICATION_NAME} uygulamasının daha yeni sürümü zaten yüklü! Daha eski bir sürümünü yüklemeniz önerilmez. Gerçekten bu eski sürümü yüklemek isterseniz, ilk olarak geçerli sürümü kaldırmanız tavsiye edilir. Yapmak istediğiniz işlemi seçin ve devam etmek üzere İleri tıklayın."
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} zaten yüklü.\nYapmak istediğiniz işlemi seçin ve devam etmek için İleri tıklayın."
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} zaten yüklü.\n\nYapmak istediğiniz işlemi seçin ve devam etmek için İleri tıklayın."
StrCpy $PageReinstall_SAME_Field_2 "Bileşenleri ekle/yeniden yükle"
StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} uygulamasını kaldır"
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} uygulamasını kaldır"

View File

@@ -151,6 +151,12 @@ UninstPage custom un.UnPageUserAppData un.UnPageUserAppDataLeave
!include ${source_path}/admin/win/nsi/l10n/languages.nsh
!include ${source_path}/admin/win/nsi/l10n/declarations.nsh
; Set version strings with english locale
VIProductVersion "${VERSION}"
VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductName" "${APPLICATION_NAME}"
VIAddVersionKey /LANG=${LANG_ENGLISH} "CompanyName" "${APPLICATION_VENDOR}"
VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "${VERSION}"
!macro SETLANG un
Function ${un}SetLang
# load the selected language file
@@ -407,7 +413,7 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
File "${QT_DLL_PATH}\Qt5Xml.dll"
;Qt deps
File "${MING_BIN}\libpng15-15.dll"
File "${MING_BIN}\libpng16-16.dll"
File "${MING_BIN}\icudata51.dll"
File "${MING_BIN}\icui18n51.dll"
File "${MING_BIN}\icuuc51.dll"
@@ -415,7 +421,6 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
File "${MING_BIN}\libGLESv2.dll"
File "${MING_BIN}\libjpeg-8.dll"
File "${MING_BIN}\libpcre16-0.dll"
File "${MING_BIN}\libpng15-15.dll"
File "${MING_BIN}\libproxy.dll"
File "${MING_BIN}\libqt5keychain.dll"
File "${MING_BIN}\libsqlite3-0.dll"
@@ -442,6 +447,7 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
;MinGW stuff
File "${MING_BIN}\libgcc_s_sjlj-1.dll"
File "${MING_BIN}\libstdc++-6.dll"
File "${MING_BIN}\libwinpthread-1.dll"
; CSync configs
File "${SOURCE_PATH}/sync-exclude.lst"

View File

@@ -22,7 +22,6 @@
#cmakedefine HAVE_UTIMES 1
#cmakedefine HAVE_LSTAT 1
#cmakedefine HAVE_FNMATCH 1
#cmakedefine HAVE___MINGW_ASPRINTF 1
#cmakedefine HAVE_ICONV 1
#cmakedefine HAVE_ICONV_CONST 1
@@ -31,5 +30,6 @@
#endif
#cmakedefine HAVE___MINGW_ASPRINTF 1
#cmakedefine HAVE_ASPRINTF 1
#cmakedefine WITH_UNIT_TESTING 1

View File

@@ -191,15 +191,12 @@ int csync_init(CSYNC *ctx) {
ctx->local.type = LOCAL_REPLICA;
if ( !ctx->options.local_only_mode) {
owncloud_init(csync_get_auth_callback(ctx), csync_get_userdata(ctx));
owncloud_init(csync_get_userdata(ctx));
ctx->remote.type = REMOTE_REPLICA;
} else {
ctx->remote.type = LOCAL_REPLICA;
}
if (ctx->options.timeout)
csync_vio_set_property(ctx, "timeout", &ctx->options.timeout);
if (c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp) < 0) {
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
rc = -1;
@@ -280,11 +277,6 @@ int csync_update(CSYNC *ctx) {
c_secdiff(finish, start), c_rbtree_size(ctx->local.tree));
csync_memstat_check();
if (rc < 0) {
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
return -1;
}
/* update detection for remote replica */
if( ! ctx->options.local_only_mode ) {
csync_gettime(&start);
@@ -447,6 +439,7 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
trav.rename_path = cur->destpath;
trav.etag = cur->etag;
trav.file_id = cur->file_id;
trav.inode = cur->inode;
trav.error_status = cur->error_status;
trav.should_update_etag = cur->should_update_etag;

View File

@@ -170,6 +170,7 @@ enum csync_notify_type_e {
struct csync_tree_walk_file_s {
const char *path;
int64_t size;
int64_t inode;
time_t modtime;
#ifdef _WIN32
uint32_t uid;

View File

@@ -229,6 +229,7 @@ CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype) {
type = CSYNC_FILE_EXCLUDE_LIST;
if (strlen(pattern) < 1) {
SAFE_FREE(pattern_stored);
continue;
}
/* Ecludes starting with ']' means it can be cleanup */
@@ -264,6 +265,9 @@ CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype) {
if (bname == NULL || dname == NULL) {
match = CSYNC_NOT_EXCLUDED;
SAFE_FREE(bname);
SAFE_FREE(dname);
SAFE_FREE(pattern_stored);
goto out;
}

View File

@@ -60,7 +60,7 @@ struct dav_session_s dav_session; /* The DAV Session, initialised in dav_connect
int _connected = 0; /* flag to indicate if a connection exists, ie.
the dav_session is valid */
csync_auth_callback _authcb;
void *_userdata;
long long chunked_total_size = 0;
long long chunked_done = 0;
@@ -123,6 +123,7 @@ static int verify_sslcert(void *userdata, int failures,
char buf[MAX(NE_SSL_DIGESTLEN, NE_ABUFSIZ)];
int ret = -1;
const ne_ssl_certificate *cert = certificate;
csync_auth_callback authcb = NULL;
(void) userdata;
memset( problem, 0, LEN );
@@ -160,11 +161,14 @@ static int verify_sslcert(void *userdata, int failures,
}
addSSLWarning( problem, "Do you want to accept the certificate chain anyway?\nAnswer yes to do so and take the risk: ", LEN );
if( _authcb ){
if( dav_session.csync_ctx ) {
authcb = csync_get_auth_callback( dav_session.csync_ctx );
}
if( authcb ){
/* call the csync callback */
DEBUG_WEBDAV("Call the csync callback for SSL problems");
memset( buf, 0, NE_ABUFSIZ );
(*_authcb) ( problem, buf, NE_ABUFSIZ-1, 1, 0, _userdata );
(*authcb) ( problem, buf, NE_ABUFSIZ-1, 1, 0, _userdata );
if( buf[0] == 'y' || buf[0] == 'Y') {
ret = 0;
} else {
@@ -184,6 +188,8 @@ static int ne_auth( void *userdata, const char *realm, int attempt,
char *username, char *password)
{
char buf[NE_ABUFSIZ];
csync_auth_callback authcb = NULL;
int re = attempt;
(void) userdata;
(void) realm;
@@ -199,24 +205,29 @@ static int ne_auth( void *userdata, const char *realm, int attempt,
if( dav_session.pwd && strlen( dav_session.pwd ) < NE_ABUFSIZ ) {
strcpy( password, dav_session.pwd );
}
} else if( _authcb != NULL ){
/* call the csync callback */
DEBUG_WEBDAV("Call the csync callback for %s", realm );
memset( buf, 0, NE_ABUFSIZ );
(*_authcb) ("Enter your username: ", buf, NE_ABUFSIZ-1, 1, 0, _userdata );
if( strlen(buf) < NE_ABUFSIZ ) {
strcpy( username, buf );
}
memset( buf, 0, NE_ABUFSIZ );
(*_authcb) ("Enter your password: ", buf, NE_ABUFSIZ-1, 0, 0, _userdata );
if( strlen(buf) < NE_ABUFSIZ) {
strcpy( password, buf );
}
} else {
DEBUG_WEBDAV("I can not authenticate!");
if( dav_session.csync_ctx ) {
authcb = csync_get_auth_callback( dav_session.csync_ctx );
}
if( authcb != NULL ){
/* call the csync callback */
DEBUG_WEBDAV("Call the csync callback for %s", realm );
memset( buf, 0, NE_ABUFSIZ );
(*authcb) ("Enter your username: ", buf, NE_ABUFSIZ-1, 1, 0, _userdata );
if( strlen(buf) < NE_ABUFSIZ ) {
strcpy( username, buf );
}
memset( buf, 0, NE_ABUFSIZ );
(*authcb) ("Enter your password: ", buf, NE_ABUFSIZ-1, 0, 0, _userdata );
if( strlen(buf) < NE_ABUFSIZ) {
strcpy( password, buf );
}
} else {
re = 1;
}
}
}
return attempt;
return re;
}
/*
@@ -508,10 +519,10 @@ static int dav_connect(const char *base_url) {
goto out;
}
if (dav_session.read_timeout == 0)
dav_session.read_timeout = 300; // set 300 seconds as default.
ne_set_read_timeout(dav_session.ctx, dav_session.read_timeout);
if (dav_session.read_timeout != 0) {
ne_set_read_timeout(dav_session.ctx, dav_session.read_timeout);
DEBUG_WEBDAV("Timeout set to %u seconds", dav_session.read_timeout );
}
snprintf( uaBuf, sizeof(uaBuf), "Mozilla/5.0 (%s) csyncoC/%s",
get_platform(), CSYNC_STRINGIFY( LIBCSYNC_VERSION ));
@@ -685,7 +696,7 @@ static struct listdir_context *fetch_resource_list(const char *uri, int depth)
ret = NE_CONNECT;
set_error_message(req_status->reason_phrase);
}
DEBUG_WEBDAV("Simple propfind result code %d.", req_status->code);
DEBUG_WEBDAV("Simple propfind result code %d.", req_status ? req_status->code : -1);
} else {
if( ret == NE_ERROR && req_status->code == 404) {
errno = ENOENT;
@@ -982,8 +993,10 @@ int owncloud_commit(void) {
clean_caches();
if( dav_session.ctx )
ne_session_destroy( dav_session.ctx );
if( dav_session.ctx ) {
ne_forget_auth(dav_session.ctx);
ne_session_destroy( dav_session.ctx );
}
/* DEBUG_WEBDAV( "********** vio_module_shutdown" ); */
dav_session.ctx = 0;
@@ -1047,10 +1060,9 @@ int owncloud_set_property(const char *key, void *data) {
return -1;
}
void owncloud_init(csync_auth_callback cb, void *userdata) {
void owncloud_init(void *userdata) {
_userdata = userdata;
_authcb = cb;
_connected = 0; /* triggers dav_connect to go through the whole neon setup */
memset(&dav_session, 0, sizeof(dav_session));

View File

@@ -173,7 +173,7 @@ int owncloud_closedir(csync_vio_handle_t *dhandle);
int owncloud_stat(const char *uri, csync_vio_file_stat_t *buf);
int owncloud_commit(void);
char *owncloud_error_string(void);
void owncloud_init(csync_auth_callback cb, void *userdata);
void owncloud_init(void *userdata);
int owncloud_set_property(const char *key, void *data);
#endif /* CSYNC_OWNCLOUD_H */

View File

@@ -236,13 +236,12 @@ static void propfind_results_recursive(void *userdata,
}
/* DEBUG_WEBDAV("results_recursive Added child %s to collection %s", newres->uri, element->self->uri); */
} else {
/* DEBUG_WEBDAV("results_recursive No parent %s found for child %s", parentPath, newres->uri); */
resource_free(newres);
newres = NULL;
return;
}
}
resource_free(newres);
newres = NULL;
}
void fetch_resource_list_recursive(const char *uri, const char *curi)

View File

@@ -183,6 +183,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
if( !c_streq(cur->file_id, "") ) {
csync_vio_set_file_id( other->file_id, cur->file_id );
}
other->inode = cur->inode;
cur->instruction = CSYNC_INSTRUCTION_NONE;
} else if (other->instruction == CSYNC_INSTRUCTION_REMOVE) {
other->instruction = CSYNC_INSTRUCTION_RENAME;
@@ -191,7 +192,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
if( !c_streq(cur->file_id, "") ) {
csync_vio_set_file_id( other->file_id, cur->file_id );
}
other->inode = cur->inode;
cur->instruction = CSYNC_INSTRUCTION_NONE;
} else if (other->instruction == CSYNC_INSTRUCTION_NEW) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "OOOO=> NEW detected in other tree!");
@@ -237,8 +238,8 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
/* file on other replica is changed or new */
case CSYNC_INSTRUCTION_NEW:
case CSYNC_INSTRUCTION_EVAL:
if (other->type == CSYNC_VIO_FILE_TYPE_DIRECTORY &&
cur->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
if (other->type == CSYNC_FTW_TYPE_DIR &&
cur->type == CSYNC_FTW_TYPE_DIR) {
is_equal_files = (other->modtime == cur->modtime);
} else {
is_equal_files = ((other->size == cur->size) && (other->modtime == cur->modtime));
@@ -248,8 +249,12 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
cur->instruction = CSYNC_INSTRUCTION_NONE;
other->instruction = CSYNC_INSTRUCTION_NONE;
if( !cur->etag && other->etag ) cur->etag = c_strdup(other->etag);
cur->should_update_etag = true; /* update DB */
/* update DB with new etag from remote */
if (ctx->current == LOCAL_REPLICA) {
other->should_update_etag = true;
} else {
cur->should_update_etag = true;
}
} else if(ctx->current == REMOTE_REPLICA) {
cur->instruction = CSYNC_INSTRUCTION_CONFLICT;
other->instruction = CSYNC_INSTRUCTION_NONE;

View File

@@ -32,6 +32,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <inttypes.h>
#include "c_lib.h"
#include "csync_private.h"
@@ -68,12 +69,11 @@ static void _csync_win32_hide_file( const char *file ) {
fileName = c_utf8_to_locale( file );
dwAttrs = GetFileAttributesW(fileName);
if (dwAttrs==INVALID_FILE_ATTRIBUTES) return;
if (!(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
SetFileAttributesW(fileName, dwAttrs | FILE_ATTRIBUTE_HIDDEN );
if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
if (!(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
SetFileAttributesW(fileName, dwAttrs | FILE_ATTRIBUTE_HIDDEN );
}
}
c_free_locale_string(fileName);
#else
(void) file;
@@ -155,6 +155,8 @@ static int _csync_statedb_check(const char *statedb) {
}
}
}
} else {
close(fd);
}
/* if it comes here, the database is broken and should be recreated. */
_tunlink(wstatedb);
@@ -529,7 +531,7 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
if( rc != SQLITE_DONE ) {
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
} else {
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "%ld entries read below path %s from db.", cnt, path);
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "%" PRId64 " entries read below path %s from db.", cnt, path);
}
sqlite3_finalize(stmt);
SAFE_FREE(likepath);

View File

@@ -274,8 +274,13 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
} else {
enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
/* tmp might point to malloc mem, so free it here before reusing tmp */
SAFE_FREE(tmp);
/* check if it's a file and has been renamed */
if (ctx->current == LOCAL_REPLICA) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Checking for rename based on inode # %" PRId64 "", (uint64_t) fs->inode);
tmp = csync_statedb_get_stat_by_inode(ctx, fs->inode);
/* translate the file type between the two stat types csync has. */
@@ -476,7 +481,6 @@ static bool fill_tree_from_db(CSYNC *ctx, const char *uri)
/* File tree walker */
int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
unsigned int depth) {
char errbuf[256] = {0};
char *filename = NULL;
char *d_name = NULL;
csync_vio_handle_t *dh = NULL;
@@ -520,10 +524,7 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!");
}
} else {
C_STRERROR(errno, errbuf, sizeof(errbuf));
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
"opendir failed for %s - %s (errno %d)",
uri, errbuf, errno);
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "opendir failed for %s - errno %d", uri, errno);
}
goto error;
}
@@ -671,7 +672,8 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
}
}
if (ctx->current_fs && (ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL ||
if (flag == CSYNC_FTW_FLAG_DIR && ctx->current_fs
&& (ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL ||
ctx->current_fs->instruction == CSYNC_INSTRUCTION_NEW ||
ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL_RENAME)) {
ctx->current_fs->should_update_etag = true;

View File

@@ -113,12 +113,12 @@ void csync_win32_set_file_hidden( const char *file, bool h ) {
fileName = c_utf8_to_locale( file );
dwAttrs = GetFileAttributesW(fileName);
if (dwAttrs==INVALID_FILE_ATTRIBUTES) return;
if (h && !(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
SetFileAttributesW(fileName, dwAttrs | FILE_ATTRIBUTE_HIDDEN );
} else if (!h && (dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
SetFileAttributesW(fileName, dwAttrs & ~FILE_ATTRIBUTE_HIDDEN );
if (dwAttrs != INVALID_FILE_ATTRIBUTES) {
if (h && !(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
SetFileAttributesW(fileName, dwAttrs | FILE_ATTRIBUTE_HIDDEN );
} else if (!h && (dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
SetFileAttributesW(fileName, dwAttrs & ~FILE_ATTRIBUTE_HIDDEN );
}
}
c_free_locale_string(fileName);
@@ -182,6 +182,7 @@ csync_vio_file_stat_t *csync_vio_convert_file_stat(csync_file_stat_t *st) {
}
bool (*csync_file_locked_or_open_ext) (const char*) = 0; // filled in by library user
void set_csync_file_locked_or_open_ext(bool (*f) (const char*));
void set_csync_file_locked_or_open_ext(bool (*f) (const char*)) {
csync_file_locked_or_open_ext = f;
}

View File

@@ -204,9 +204,9 @@ void hbf_free_transfer( hbf_transfer_t *transfer ) {
for( cnt = 0; cnt < transfer->block_cnt; cnt++ ) {
hbf_block_t *block = transfer->block_arr[cnt];
if( !block ) continue;
if( block->http_error_msg ) free( block->http_error_msg );
if( block->etag ) free( block->etag );
if( block ) free(block);
}
free( transfer->block_arr );
free( transfer->url );
@@ -536,8 +536,8 @@ Hbf_State hbf_transfer( ne_session *session, hbf_transfer_t *transfer, const cha
} else {
state = HBF_MEMORY_FAIL;
}
free( transfer_url );
}
free( transfer_url );
}
/* do the source file validation finally (again). */

View File

@@ -55,9 +55,6 @@
/** Get the size of an array */
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
/** Macro to make strerror_r work with -Werror=unused-result */
#define C_STRERROR(errno, buf, size) if(strerror_r(errno, buf, size)) {}
/**
* This is a hack to fix warnings. The idea is to use this everywhere that we
* get the "discarding const" warning by the compiler. That doesn't actually

View File

@@ -135,7 +135,8 @@ int c_utimes(const char *uri, const struct timeval *times) {
if(!SetFileTime(hFile, NULL, &LastAccessTime, &LastModificationTime)) {
//can this happen?
errno=ENOENT;
CloseHandle(hFile);
CloseHandle(hFile);
c_free_locale_string(wuri);
return -1;
}

View File

@@ -113,11 +113,6 @@ int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) {
if (rc < 0) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Local stat failed, errno %d", errno);
}
#ifdef _WIN32
else {
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Win32: STAT-inode for %s: %llu", uri, buf->inode );
}
#endif
break;
default:
break;

View File

@@ -240,6 +240,9 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
/* printf("Index: %I64i\n", FileIndex.QuadPart); */
buf->inode = FileIndex.QuadPart;
buf->size = (fileInfo.nFileSizeHigh * (int64_t)(MAXDWORD+1)) + fileInfo.nFileSizeLow;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
/* Get the file time with a win32 call rather than through stat. See
* http://www.codeproject.com/Articles/1144/Beating-the-Daylight-Savings-Time-bug-and-getting
* for deeper explanation.
@@ -257,6 +260,7 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME;
}
c_free_locale_string(wuri);
CloseHandle(h);
return 0;

View File

@@ -243,19 +243,6 @@ static void check_csync_statedb_get_stat_by_hash_not_found(void **state)
free(tmp);
}
static void check_csync_statedb_get_stat_by_inode(void **state)
{
CSYNC *csync = *state;
csync_file_stat_t *tmp;
tmp = csync_statedb_get_stat_by_inode(csync, (ino_t) 23);
assert_non_null(tmp);
assert_int_equal(tmp->phash, 42);
assert_int_equal(tmp->inode, 23);
free(tmp);
}
static void check_csync_statedb_get_stat_by_inode_not_found(void **state)
{
@@ -272,14 +259,10 @@ int torture_run_tests(void)
unit_test_setup_teardown(check_csync_statedb_query_statement, setup, teardown),
unit_test_setup_teardown(check_csync_statedb_create_error, setup, teardown),
unit_test_setup_teardown(check_csync_statedb_insert_statement, setup, teardown),
/* unit_test_setup_teardown(check_csync_statedb_is_empty, setup, teardown), */
/* unit_test_setup_teardown(check_csync_statedb_create_tables, setup, teardown), */
unit_test_setup_teardown(check_csync_statedb_drop_tables, setup, teardown),
unit_test_setup_teardown(check_csync_statedb_insert_metadata, setup, teardown),
unit_test_setup_teardown(check_csync_statedb_write, setup, teardown),
/* unit_test_setup_teardown(check_csync_statedb_get_stat_by_hash, setup_db, teardown), */
unit_test_setup_teardown(check_csync_statedb_get_stat_by_hash_not_found, setup_db, teardown),
/* unit_test_setup_teardown(check_csync_statedb_get_stat_by_inode, setup_db, teardown), */
unit_test_setup_teardown(check_csync_statedb_get_stat_by_inode_not_found, setup_db, teardown),
};

View File

@@ -12,12 +12,15 @@ if(SPHINX_FOUND)
# assets
set(LATEX_LOGO "${CMAKE_CURRENT_SOURCE_DIR}/logo-blue.pdf")
install(DIRECTORY ${SPHINX_HTML_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR} OPTIONAL)
install(DIRECTORY ${SPHINX_MAN_DIR} DESTINATION ${CMAKE_INSTALL_MANDIR} OPTIONAL)
install(DIRECTORY ${SPHINX_PDF_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR} OPTIONAL)
install(DIRECTORY ${SPHINX_QCH_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR} OPTIONAL)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in" conf.py @ONLY)
if(WITH_DOC)
add_custom_target(doc ALL DEPENDS doc-html doc-man COMMENT "Building documentation...")
install(DIRECTORY ${SPHINX_HTML_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR})
install(DIRECTORY ${SPHINX_MAN_DIR} DESTINATION ${CMAKE_INSTALL_MANDIR})
else(WITH_DOC)
add_custom_target(doc DEPENDS doc-html doc-man COMMENT "Building documentation...")
endif(WITH_DOC)
@@ -39,9 +42,6 @@ if(SPHINX_FOUND)
add_custom_target(doc-pdf $(MAKE) -C ${SPHINX_PDF_DIR} all-pdf
DEPENDS doc-latex )
add_dependencies(doc doc-pdf)
if (WITH_DOC)
install(DIRECTORY ${SPHINX_PDF_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR})
endif (WITH_DOC)
endif(PDFLATEX_FOUND)
if (EXISTS ${QT_QCOLLECTIONGENERATOR_EXECUTABLE})
add_custom_target( doc-qch-sphinx ${SPHINX_EXECUTABLE}
@@ -53,9 +53,6 @@ if(SPHINX_FOUND)
${SPHINX_QCH_DIR}/*.qhcp
DEPENDS doc-qch-sphinx )
add_dependencies(doc doc-qch)
if (WITH_DOC)
install(DIRECTORY ${SPHINX_QCH_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR})
endif (WITH_DOC)
endif()
add_custom_target( doc-html ${SPHINX_EXECUTABLE}
-q -c . -b html

View File

@@ -134,3 +134,25 @@ log line contains a lot of information of every request and it's result.
More information about the apache logging can be found at
``http://httpd.apache.org/docs/current/logs.html``.
Core Dumps
----------
In case of crashes of the client software, having a core dump helps to
debug the issue tremendously.
The client is able to write a core dump in case of crashing on Linux and
MacOSX. To enable that, the environment variable ``OWNCLOUD_CORE_DUMP`` has
to be defined.
For example
```
OWNCLOUD_CORE_DUMP=1 owncloud
```
starts the client with core dumping enabled. Core dumps appear in the
current working directory, and since they can be fairly large, it is
important to have plenty of disk space when running with dumps enabled.
If a core dump file should be transfered back to the developers it
should be compressed properly before.

View File

@@ -317,7 +317,7 @@ void FancyLineEdit::setButtonFocusPolicy(Side side, Qt::FocusPolicy policy)
// IconButton - helper class to represent a clickable icon
IconButton::IconButton(QWidget *parent)
: QAbstractButton(parent), m_autoHide(false)
: QAbstractButton(parent), m_iconOpacity(0), m_autoHide(false)
{
setCursor(Qt::ArrowCursor);
setFocusPolicy(Qt::NoFocus);

View File

@@ -1,5 +1,5 @@
This is the src directory of the QtLockedFile
solution integrated over from Qt's Qt Creator.
solution integrated over from Qt's Qt Creator.
It is required by the QtSingleApplication solution.

View File

@@ -1,32 +1,31 @@
/**************************************************************************
/****************************************************************************
**
** This file is part of Qt Creator
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
****************************************************************************/
#include "qtlockedfile.h"

View File

@@ -1,32 +1,31 @@
/**************************************************************************
/****************************************************************************
**
** This file is part of Qt Creator
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
****************************************************************************/
#ifndef QTLOCKEDFILE_H
#define QTLOCKEDFILE_H

View File

@@ -0,0 +1,11 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
HEADERS += $$PWD/qtlockedfile.h
SOURCES += $$PWD/qtlockedfile.cpp
unix:SOURCES += $$PWD/qtlockedfile_unix.cpp
win32:SOURCES += $$PWD/qtlockedfile_win.cpp
win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
DEFINES += QT_QTLOCKEDFILE_EXPORT=__declspec(dllexport)
}

View File

@@ -1,32 +1,31 @@
/**************************************************************************
/****************************************************************************
**
** This file is part of Qt Creator
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
****************************************************************************/
#include "qtlockedfile.h"
@@ -96,6 +95,7 @@ bool QtLockedFile::unlock()
}
m_lock_mode = NoLock;
remove();
return true;
}

View File

@@ -1,32 +1,31 @@
/**************************************************************************
/****************************************************************************
**
** This file is part of Qt Creator
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
****************************************************************************/
#include "qtlockedfile.h"
@@ -50,7 +49,7 @@ static QString errorCodeToString(DWORD errorCode)
if (data != 0)
LocalFree(data);
if (result.endsWith('\n'))
if (result.endsWith(QLatin1Char('\n')))
result.truncate(result.length() - 1);
return result;
@@ -168,6 +167,7 @@ bool QtLockedFile::unlock()
}
m_lock_mode = QtLockedFile::NoLock;
remove();
return true;
}

View File

@@ -1,5 +1,5 @@
This is the src directory of the QtSingleApplication solution
integrated over from Qt's Qt Creator project.
integrated over from Qt's Qt Creator project.
It additionally requires the QtLockedFile solution.

View File

@@ -1,32 +1,31 @@
/**************************************************************************
/****************************************************************************
**
** This file is part of Qt Creator
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
****************************************************************************/
#include "qtlocalpeer.h"
@@ -47,7 +46,31 @@ static PProcessIdToSessionId pProcessIdToSessionId = 0;
namespace SharedTools {
const char *QtLocalPeer::ack = "ack";
static const char ack[] = "ack";
QString QtLocalPeer::appSessionId(const QString &appId)
{
QByteArray idc = appId.toUtf8();
quint16 idNum = qChecksum(idc.constData(), idc.size());
//### could do: two 16bit checksums over separate halves of id, for a 32bit result - improved uniqeness probability. Every-other-char split would be best.
QString res = QLatin1String("qtsingleapplication-")
+ QString::number(idNum, 16);
#if defined(Q_OS_WIN)
if (!pProcessIdToSessionId) {
QLibrary lib(QLatin1String("kernel32"));
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
}
if (pProcessIdToSessionId) {
DWORD sessionId = 0;
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
res += QLatin1Char('-') + QString::number(sessionId, 16);
}
#else
res += QLatin1Char('-') + QString::number(::getuid(), 16);
#endif
return res;
}
QtLocalPeer::QtLocalPeer(QObject *parent, const QString &appId)
: QObject(parent), id(appId)
@@ -55,26 +78,7 @@ QtLocalPeer::QtLocalPeer(QObject *parent, const QString &appId)
if (id.isEmpty())
id = QCoreApplication::applicationFilePath(); //### On win, check if this returns .../argv[0] without casefolding; .\MYAPP == .\myapp on Win
QByteArray idc = id.toUtf8();
quint16 idNum = qChecksum(idc.constData(), idc.size());
//### could do: two 16bit checksums over separate halves of id, for a 32bit result - improved uniqeness probability. Every-other-char split would be best.
socketName = QLatin1String("qtsingleapplication-")
+ QString::number(idNum, 16);
#if defined(Q_OS_WIN)
if (!pProcessIdToSessionId) {
QLibrary lib("kernel32");
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
}
if (pProcessIdToSessionId) {
DWORD sessionId = 0;
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
socketName += QLatin1Char('-') + QString::number(sessionId, 16);
}
#else
socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
#endif
socketName = appSessionId(id);
server = new QLocalServer(this);
QString lockName = QDir(QDir::tempPath()).absolutePath()
+ QLatin1Char('/') + socketName
@@ -100,7 +104,7 @@ bool QtLocalPeer::isClient()
return false;
}
bool QtLocalPeer::sendMessage(const QString &message, int timeout)
bool QtLocalPeer::sendMessage(const QString &message, int timeout, bool block)
{
if (!isClient())
return false;
@@ -130,6 +134,8 @@ bool QtLocalPeer::sendMessage(const QString &message, int timeout)
bool res = socket.waitForBytesWritten(timeout);
res &= socket.waitForReadyRead(timeout); // wait for ack
res &= (socket.read(qstrlen(ack)) == ack);
if (block) // block until peer disconnects
socket.waitForDisconnected(-1);
return res;
}
@@ -140,8 +146,11 @@ void QtLocalPeer::receiveConnection()
return;
// Why doesn't Qt have a blocking stream that takes care of this shait???
while (socket->bytesAvailable() < static_cast<int>(sizeof(quint32)))
socket->waitForReadyRead();
while (socket->bytesAvailable() < static_cast<int>(sizeof(quint32))) {
if (!socket->isValid()) // stale request
return;
socket->waitForReadyRead(1000);
}
QDataStream ds(socket);
QByteArray uMsg;
quint32 remaining;
@@ -166,8 +175,7 @@ void QtLocalPeer::receiveConnection()
QString message = QString::fromUtf8(uMsg.constData(), uMsg.size());
socket->write(ack, qstrlen(ack));
socket->waitForBytesWritten(1000);
delete socket;
emit messageReceived(message); // ##(might take a long time to return)
emit messageReceived(message, socket); // ##(might take a long time to return)
}
} // namespace SharedTools

View File

@@ -1,34 +1,33 @@
/**************************************************************************
/****************************************************************************
**
** This file is part of Qt Creator
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
****************************************************************************/
#include "qtlockedfile.h"
#include <qtlockedfile.h>
#include <QLocalServer>
#include <QLocalSocket>
@@ -43,12 +42,13 @@ class QtLocalPeer : public QObject
public:
explicit QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
bool isClient();
bool sendMessage(const QString &message, int timeout);
bool sendMessage(const QString &message, int timeout, bool block);
QString applicationId() const
{ return id; }
static QString appSessionId(const QString &appId);
Q_SIGNALS:
void messageReceived(const QString &message);
void messageReceived(const QString &message, QObject *socket);
protected Q_SLOTS:
void receiveConnection();
@@ -58,9 +58,6 @@ protected:
QString socketName;
QLocalServer* server;
QtLockedFile lockFile;
private:
static const char* ack;
};
} // namespace SharedTools

View File

@@ -1,96 +1,123 @@
/**************************************************************************
/****************************************************************************
**
** This file is part of Qt Creator
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
****************************************************************************/
#include "qtsingleapplication.h"
#include "qtlocalpeer.h"
#include <QWidget>
#include <qtlockedfile.h>
#include <QDir>
#include <QFileOpenEvent>
#include <QSharedMemory>
#include <QWidget>
namespace SharedTools {
void QtSingleApplication::sysInit(const QString &appId)
static const int instancesSize = 1024;
static QString instancesLockFilename(const QString &appSessionId)
{
actWin = 0;
firstPeer = new QtLocalPeer(this, appId);
connect(firstPeer, SIGNAL(messageReceived(QString)), SIGNAL(messageReceived(QString)));
pidPeer = new QtLocalPeer(this, appId + QLatin1Char('-') + QString::number(QCoreApplication::applicationPid(), 10));
connect(pidPeer, SIGNAL(messageReceived(QString)), SIGNAL(messageReceived(QString)));
const QChar slash(QLatin1Char('/'));
QString res = QDir::tempPath();
if (!res.endsWith(slash))
res += slash;
return res + appSessionId + QLatin1String("-instances");
}
QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled)
: QApplication(argc, argv, GUIenabled)
{
sysInit();
}
QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv)
: QApplication(argc, argv)
: QApplication(argc, argv),
firstPeer(-1),
pidPeer(0)
{
this->appId = appId;
sysInit(appId);
const QString appSessionId = QtLocalPeer::appSessionId(appId);
// This shared memory holds a zero-terminated array of active (or crashed) instances
instances = new QSharedMemory(appSessionId, this);
actWin = 0;
block = false;
// First instance creates the shared memory, later instances attach to it
const bool created = instances->create(instancesSize);
if (!created) {
if (!instances->attach()) {
qWarning() << "Failed to initialize instances shared memory: "
<< instances->errorString();
delete instances;
instances = 0;
return;
}
}
// QtLockedFile is used to workaround QTBUG-10364
QtLockedFile lockfile(instancesLockFilename(appSessionId));
lockfile.open(QtLockedFile::ReadWrite);
lockfile.lock(QtLockedFile::WriteLock);
qint64 *pids = static_cast<qint64 *>(instances->data());
if (!created) {
// Find the first instance that it still running
// The whole list needs to be iterated in order to append to it
for (; *pids; ++pids) {
if (firstPeer == -1 && isRunning(*pids))
firstPeer = *pids;
}
}
// Add current pid to list and terminate it
*pids++ = QCoreApplication::applicationPid();
*pids = 0;
pidPeer = new QtLocalPeer(this, appId + QLatin1Char('-') +
QString::number(QCoreApplication::applicationPid()));
connect(pidPeer, SIGNAL(messageReceived(QString,QObject*)), SIGNAL(messageReceived(QString,QObject*)));
pidPeer->isClient();
lockfile.unlock();
}
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type)
: QApplication(argc, argv, type)
QtSingleApplication::~QtSingleApplication()
{
sysInit();
if (!instances)
return;
const qint64 appPid = QCoreApplication::applicationPid();
QtLockedFile lockfile(instancesLockFilename(QtLocalPeer::appSessionId(appId)));
lockfile.open(QtLockedFile::ReadWrite);
lockfile.lock(QtLockedFile::WriteLock);
// Rewrite array, removing current pid and previously crashed ones
qint64 *pids = static_cast<qint64 *>(instances->data());
qint64 *newpids = pids;
for (; *pids; ++pids) {
if (*pids != appPid && isRunning(*pids))
*newpids++ = *pids;
}
*newpids = 0;
lockfile.unlock();
}
#endif
#if defined(Q_WS_X11)
QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE colormap)
: QApplication(dpy, visual, colormap)
{
sysInit();
}
QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, argc, argv, visual, cmap)
{
sysInit();
}
QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId,
int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE colormap)
: QApplication(dpy, argc, argv, visual, colormap)
{
this->appId = appId;
sysInit(appId);
}
#endif
bool QtSingleApplication::event(QEvent *event)
{
@@ -104,31 +131,26 @@ bool QtSingleApplication::event(QEvent *event)
bool QtSingleApplication::isRunning(qint64 pid)
{
if (pid == -1)
return firstPeer->isClient();
if (pid == -1) {
pid = firstPeer;
if (pid == -1)
return false;
}
QtLocalPeer peer(this, appId + QLatin1Char('-') + QString::number(pid, 10));
return peer.isClient();
}
void QtSingleApplication::initialize(bool)
{
firstPeer->isClient();
pidPeer->isClient();
}
bool QtSingleApplication::sendMessage(const QString &message, int timeout, qint64 pid)
{
if (pid == -1)
return firstPeer->sendMessage(message, timeout);
if (pid == -1) {
pid = firstPeer;
if (pid == -1)
return false;
}
QtLocalPeer peer(this, appId + QLatin1Char('-') + QString::number(pid, 10));
return peer.sendMessage(message, timeout);
}
QString QtSingleApplication::id() const
{
return firstPeer->applicationId();
return peer.sendMessage(message, timeout, block);
}
QString QtSingleApplication::applicationId() const
@@ -136,16 +158,20 @@ QString QtSingleApplication::applicationId() const
return appId;
}
void QtSingleApplication::setBlock(bool value)
{
block = value;
}
void QtSingleApplication::setActivationWindow(QWidget *aw, bool activateOnMessage)
{
actWin = aw;
if (activateOnMessage) {
connect(firstPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow()));
connect(pidPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow()));
} else {
disconnect(firstPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow()));
disconnect(pidPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow()));
}
if (!pidPeer)
return;
if (activateOnMessage)
connect(pidPeer, SIGNAL(messageReceived(QString,QObject*)), this, SLOT(activateWindow()));
else
disconnect(pidPeer, SIGNAL(messageReceived(QString,QObject*)), this, SLOT(activateWindow()));
}

View File

@@ -1,38 +1,39 @@
/**************************************************************************
/****************************************************************************
**
** This file is part of Qt Creator
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
****************************************************************************/
#ifndef _SHAREDTOOLS_SINGLEAPPLICATION
#define _SHAREDTOOLS_SINGLEAPPLICATION
#ifndef QTSINGLEAPPLICATION_H
#define QTSINGLEAPPLICATION_H
#include <QApplication>
QT_FORWARD_DECLARE_CLASS(QSharedMemory)
namespace SharedTools {
class QtLocalPeer;
@@ -42,50 +43,37 @@ class QtSingleApplication : public QApplication
Q_OBJECT
public:
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
QtSingleApplication(const QString &id, int &argc, char **argv);
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
QtSingleApplication(int &argc, char **argv, Type type);
#endif
#if defined(Q_WS_X11)
explicit QtSingleApplication(Display *dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0);
#endif
~QtSingleApplication();
bool isRunning(qint64 pid = -1);
QString id() const;
void setActivationWindow(QWidget* aw, bool activateOnMessage = true);
QWidget* activationWindow() const;
bool event(QEvent *event);
QString applicationId() const;
void setBlock(bool value);
public Q_SLOTS:
bool sendMessage(const QString &message, int timeout = 5000, qint64 pid = -1);
void activateWindow();
//Obsolete methods:
public:
void initialize(bool = true);
#if defined(Q_WS_X11)
QtSingleApplication(Display* dpy, const QString &id, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
#endif
// end obsolete methods
Q_SIGNALS:
void messageReceived(const QString &message);
void messageReceived(const QString &message, QObject *socket);
void fileOpenRequest(const QString &file);
private:
void sysInit(const QString &appId = QString());
QtLocalPeer *firstPeer;
QString instancesFileName(const QString &appId);
qint64 firstPeer;
QSharedMemory *instances;
QtLocalPeer *pidPeer;
QWidget *actWin;
QString appId;
bool block;
};
} // namespace SharedTools
#endif // _SHAREDTOOLS_SINGLEAPPLICATION
#endif // QTSINGLEAPPLICATION_H

View File

@@ -0,0 +1,15 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
HEADERS += $$PWD/qtsingleapplication.h $$PWD/qtlocalpeer.h
SOURCES += $$PWD/qtsingleapplication.cpp $$PWD/qtlocalpeer.cpp
QT *= network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h)
isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri)
win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
DEFINES += QT_QTSINGLEAPPLICATION_EXPORT=__declspec(dllexport)
}

View File

@@ -1,32 +1,31 @@
/**************************************************************************
/****************************************************************************
**
** This file is part of Qt Creator
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
****************************************************************************/
#include "qtsinglecoreapplication.h"
#include "qtlocalpeer.h"
@@ -37,6 +36,7 @@ QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
: QCoreApplication(argc, argv)
{
peer = new QtLocalPeer(this);
block = false;
connect(peer, SIGNAL(messageReceived(QString)), SIGNAL(messageReceived(QString)));
}
@@ -57,7 +57,7 @@ bool QtSingleCoreApplication::isRunning()
bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout)
{
return peer->sendMessage(message, timeout);
return peer->sendMessage(message, timeout, block);
}
@@ -66,4 +66,9 @@ QString QtSingleCoreApplication::id() const
return peer->applicationId();
}
void QtSingleCoreApplication::setBlock(bool value)
{
block = value;
}
} // namespace SharedTools

View File

@@ -1,32 +1,31 @@
/**************************************************************************
/****************************************************************************
**
** This file is part of Qt Creator
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
****************************************************************************/
#include <QCoreApplication>
@@ -44,6 +43,7 @@ public:
bool isRunning();
QString id() const;
void setBlock(bool value);
public Q_SLOTS:
bool sendMessage(const QString &message, int timeout = 5000);
@@ -55,6 +55,7 @@ Q_SIGNALS:
private:
QtLocalPeer* peer;
bool block;
};
} // namespace SharedTools

View File

@@ -0,0 +1,14 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
HEADERS += $$PWD/qtsinglecoreapplication.h $$PWD/qtlocalpeer.h
SOURCES += $$PWD/qtsinglecoreapplication.cpp $$PWD/qtlocalpeer.cpp
QT *= network
gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h)
isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri)
win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
DEFINES += QT_QTSINGLECOREAPPLICATION_EXPORT=__declspec(dllexport)
}

View File

@@ -1,4 +1,5 @@
set(CMAKE_AUTOMOC TRUE)
include(GenerateExportHeader)
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
@@ -103,6 +104,7 @@ set(libsync_SRCS
mirall/quotainfo.cpp
mirall/clientproxy.cpp
mirall/syncrunfilelog.cpp
mirall/cookiejar.cpp
creds/dummycredentials.cpp
creds/abstractcredentials.cpp
creds/credentialsfactory.cpp
@@ -120,11 +122,8 @@ else()
${libsync_SRCS}
creds/httpcredentials.cpp
creds/shibbolethcredentials.cpp
creds/shibboleth/shibbolethaccessmanager.cpp
creds/shibboleth/shibbolethcookiejar.cpp
creds/shibboleth/shibbolethwebview.cpp
creds/shibboleth/shibbolethrefresher.cpp
creds/shibboleth/shibbolethconfigfile.cpp
creds/shibboleth/authenticationdialog.cpp
creds/shibboleth/shibbolethuserjob.cpp
)
@@ -195,6 +194,14 @@ if(NEON_FOUND)
endif()
add_library(${synclib_NAME} SHARED ${libsync_SRCS} ${syncMoc})
GENERATE_EXPORT_HEADER( ${synclib_NAME}
BASE_NAME ${synclib_NAME}
EXPORT_MACRO_NAME OWNCLOUDSYNC_EXPORT
EXPORT_FILE_NAME owncloudlib.h
STATIC_DEFINE OWNCLOUD_BUILT_AS_STATIC
)
if(TOKEN_AUTH_ONLY)
qt5_use_modules(${synclib_NAME} Network Xml Sql)
else()

View File

@@ -141,7 +141,11 @@ void HttpCredentials::syncContextPreStart (CSYNC* ctx)
bool HttpCredentials::changed(AbstractCredentials* credentials) const
{
HttpCredentials* other(dynamic_cast< HttpCredentials* >(credentials));
HttpCredentials* other(qobject_cast< HttpCredentials* >(credentials));
if (!other) {
return true;
}
if (!other || (other->user() != this->user())) {
return true;

View File

@@ -1,55 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <QDebug>
#include <QNetworkRequest>
#include <QNetworkCookieJar>
#include "creds/shibboleth/shibbolethaccessmanager.h"
namespace Mirall
{
ShibbolethAccessManager::ShibbolethAccessManager(const QNetworkCookie& cookie, QObject* parent)
: MirallAccessManager (parent),
_cookie(cookie)
{}
QNetworkReply* ShibbolethAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
{
if (!_cookie.name().isEmpty()) {
QNetworkCookieJar* jar(cookieJar());
QUrl url(request.url());
QList<QNetworkCookie> cookies;
Q_FOREACH(const QNetworkCookie& cookie, jar->cookiesForUrl(url)) {
if (!cookie.name().startsWith("_shibsession_")) {
cookies << cookie;
}
}
cookies << _cookie; // this line and the line above replace all cookies with self and then add the shibboleth cookie (filtering the current shib cookie)
jar->setCookiesFromUrl(cookies, url);
}
qDebug() << "Creating a request to " << request.url().toString() << " with shibboleth cookie:" << _cookie.name();
return MirallAccessManager::createRequest (op, request, outgoingData);
}
void ShibbolethAccessManager::setCookie(const QNetworkCookie& cookie)
{
qDebug() << "Got new shibboleth cookie:" << cookie.name();
_cookie = cookie;
}
} // ns Mirall

View File

@@ -1,43 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_WIZARD_SHIBBOLETH_ACCESS_MANAGER_H
#define MIRALL_WIZARD_SHIBBOLETH_ACCESS_MANAGER_H
#include <QNetworkCookie>
#include "mirall/mirallaccessmanager.h"
namespace Mirall
{
class ShibbolethAccessManager : public MirallAccessManager
{
Q_OBJECT
public:
ShibbolethAccessManager(const QNetworkCookie& cookie, QObject* parent = 0);
public Q_SLOTS:
void setCookie(const QNetworkCookie& cookie);
protected:
QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData = 0);
private:
QNetworkCookie _cookie;
};
} // ns Mirall
#endif

View File

@@ -1,104 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <QDebug>
#include <QTextStream>
#include "creds/shibboleth/shibbolethconfigfile.h"
#include "creds/shibboleth/shibbolethcookiejar.h"
namespace Mirall
{
namespace
{
const char otherCookiesC[] = "otherCookies";
} // ns
void ShibbolethConfigFile::storeCookies(const QMap<QUrl, QList<QNetworkCookie> >& cookiesForUrl)
{
if (cookiesForUrl.isEmpty()) {
removeData(QString(), QString::fromLatin1(otherCookiesC));
} else {
QByteArray data;
QTextStream stream(&data);
Q_FOREACH (const QUrl& url, cookiesForUrl.keys()) {
const QList<QNetworkCookie>& cookies(cookiesForUrl[url]);
if (cookies.isEmpty()) {
continue;
}
stream << "URL: " << url.toString().toUtf8() << "\n";
qDebug() << "URL: " << url.toString().toUtf8();
Q_FOREACH (const QNetworkCookie& cookie, cookies) {
stream << cookie.toRawForm(QNetworkCookie::NameAndValueOnly) << "\n";
qDebug() << cookie.toRawForm(QNetworkCookie::NameAndValueOnly);
}
}
stream.flush();
const QByteArray encodedCookies(data.toBase64());
qDebug() << "Raw cookies:\n" << data;
qDebug() << "Encoded cookies: " << encodedCookies;
storeData(QString(), QString::fromLatin1(otherCookiesC), QVariant(encodedCookies));
}
}
ShibbolethCookieJar* ShibbolethConfigFile::createCookieJar() const
{
ShibbolethCookieJar* jar = new ShibbolethCookieJar();
const QVariant variant(retrieveData(QString(), QString::fromLatin1(otherCookiesC)));
if (variant.isValid()) {
QByteArray data(QByteArray::fromBase64(variant.toByteArray()));
QTextStream stream (&data);
const QString urlHeader(QString::fromLatin1("URL: "));
QUrl currentUrl;
QList<QNetworkCookie> currentCookies;
qDebug() << "Got valid cookies variant: " << data;
while (!stream.atEnd()) {
const QString line(stream.readLine());
qDebug() << line;
if (line.startsWith(urlHeader)) {
if (!currentUrl.isEmpty() && !currentCookies.isEmpty()) {
jar->setCookiesFromUrl(currentCookies, currentUrl);
currentCookies.clear();
currentUrl.clear();
}
currentUrl = QUrl(line.mid(5));
} else if (!currentUrl.isEmpty()) {
const int equalPos(line.indexOf('='));
currentCookies << QNetworkCookie(line.left(equalPos).toUtf8(), line.mid(equalPos + 1).toUtf8());
}
}
if (!currentUrl.isEmpty() && !currentCookies.isEmpty()) {
jar->setCookiesFromUrl(currentCookies, currentUrl);
}
}
return jar;
}
} // ns Mirall

View File

@@ -1,38 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_CREDS_SHIBBOLETH_CONFIG_FILE_H
#define MIRALL_CREDS_SHIBBOLETH_CONFIG_FILE_H
#include <QList>
#include <QMap>
#include <QNetworkCookie>
#include <QUrl>
#include "mirall/mirallconfigfile.h"
namespace Mirall
{
class ShibbolethCookieJar;
class ShibbolethConfigFile : public MirallConfigFile
{
public:
void storeCookies(const QMap<QUrl, QList<QNetworkCookie> >& cookies);
ShibbolethCookieJar* createCookieJar() const;
};
} // ns Mirall
#endif

View File

@@ -1,34 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "creds/shibboleth/shibbolethcookiejar.h"
namespace Mirall
{
ShibbolethCookieJar::ShibbolethCookieJar (QObject* parent)
: QNetworkCookieJar (parent)
{}
bool ShibbolethCookieJar::setCookiesFromUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url)
{
if (QNetworkCookieJar::setCookiesFromUrl (cookieList, url)) {
Q_EMIT newCookiesForUrl (cookieList, url);
return true;
}
return false;
}
} // ns Mirall

View File

@@ -1,41 +0,0 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_WIZARD_SHIBBOLETH_COOKIE_JAR_H
#define MIRALL_WIZARD_SHIBBOLETH_COOKIE_JAR_H
#include <QNetworkCookieJar>
#include <QList>
class QUrl;
class QNetworkCookie;
namespace Mirall
{
class ShibbolethCookieJar : public QNetworkCookieJar
{
Q_OBJECT
public:
ShibbolethCookieJar (QObject* parent = 0);
virtual bool setCookiesFromUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url);
Q_SIGNALS:
void newCookiesForUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url);
};
} // ns Mirall
#endif

View File

@@ -47,7 +47,7 @@ bool ShibbolethUserJob::finished()
}
QString user = json.value("ocs").toMap().value("data").toMap().value("id").toString();
qDebug() << "cloud/user: " << json << "->" << user;
//qDebug() << "cloud/user: " << json << "->" << user;
emit userFetched(user);
return true;
}

View File

@@ -14,96 +14,75 @@
#include <QApplication>
#include <QDebug>
#include <QNetworkCookie>
#include <QNetworkCookieJar>
#include <QWebFrame>
#include <QWebPage>
#include <QMessageBox>
#include <QAuthenticator>
#include <QNetworkReply>
#include "creds/shibboleth/shibbolethcookiejar.h"
#include "creds/shibboleth/shibbolethwebview.h"
#include "creds/shibboleth/authenticationdialog.h"
#include "creds/shibbolethcredentials.h"
#include "mirall/account.h"
#include "mirall/logger.h"
#include "mirall/mirallaccessmanager.h"
#include "mirall/theme.h"
namespace Mirall
{
void ShibbolethWebView::setup(Account *account, ShibbolethCookieJar* jar)
ShibbolethWebView::ShibbolethWebView(Account* account, QWidget* parent)
: QWebView(parent)
, _account(account)
, _accepted(false)
{
_account = account;
MirallAccessManager* nm = new MirallAccessManager(this);
// we need our own QNAM, but the we offload the SSL error handling to
// the account object, which already can do this
connect(nm, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
account, SLOT(slotHandleErrors(QNetworkReply*,QList<QSslError>)));
connect(nm, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
SLOT(slotHandleAuthentication(QNetworkReply*,QAuthenticator*)));
// no minimize
setWindowFlags(Qt::Dialog);
setAttribute(Qt::WA_DeleteOnClose);
QWebPage* page = new QWebPage(this);
jar->setParent(this);
connect(jar, SIGNAL (newCookiesForUrl (QList<QNetworkCookie>, QUrl)),
this, SLOT (onNewCookiesForUrl (QList<QNetworkCookie>, QUrl)));
page->setNetworkAccessManager(account->networkAccessManager());
connect(page, SIGNAL(loadStarted()),
this, SLOT(slotLoadStarted()));
connect(page, SIGNAL(loadFinished(bool)),
this, SLOT(slotLoadFinished(bool)));
nm->setCookieJar(jar);
page->setNetworkAccessManager(nm);
connect(page->networkAccessManager()->cookieJar(),
SIGNAL(newCookiesForUrl (QList<QNetworkCookie>, QUrl)),
this, SLOT(onNewCookiesForUrl (QList<QNetworkCookie>, QUrl)));
page->mainFrame()->load(account->url());
this->setPage(page);
setWindowTitle(tr("%1 - Authenticate").arg(Theme::instance()->appNameGUI()));
}
ShibbolethWebView::ShibbolethWebView(Account* account, QWidget* parent)
: QWebView(parent)
{
setup(account, new ShibbolethCookieJar(this));
// If we have a valid cookie, it's most likely expired. We can use this as
// as a criteria to tell the user why the browser window pops up
QNetworkCookie shibCookie = ShibbolethCredentials::findShibCookie(_account, ShibbolethCredentials::accountCookies(_account));
if (shibCookie != QNetworkCookie()) {
Logger::instance()->postOptionalGuiLog(tr("Reauthentication required"), tr("Your session has expired. You need to re-login to continue to use the client."));
}
}
ShibbolethWebView::~ShibbolethWebView()
{
slotLoadFinished();
}
ShibbolethWebView::ShibbolethWebView(Account* account, ShibbolethCookieJar* jar, QWidget* parent)
: QWebView(parent)
{
setup(account, jar);
}
void ShibbolethWebView::onNewCookiesForUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url)
{
QList<QNetworkCookie> otherCookies;
QNetworkCookie shibCookie;
Q_FOREACH (const QNetworkCookie& cookie, cookieList) {
if (cookie.name().startsWith ("_shibsession_")) {
if (shibCookie.name().isEmpty()) {
shibCookie = cookie;
} else {
qWarning() << "Too many Shibboleth session cookies at once!";
}
} else {
otherCookies << cookie;
if (url.host() == _account->url().host()) {
QNetworkCookie shibCookie = ShibbolethCredentials::findShibCookie(_account, cookieList);
if (shibCookie != QNetworkCookie()) {
Q_EMIT shibbolethCookieReceived(shibCookie, _account);
accept();
close();
}
}
}
if (!otherCookies.isEmpty()) {
Q_EMIT otherCookiesReceived(otherCookies, url);
}
if (!shibCookie.name().isEmpty()) {
Q_EMIT shibbolethCookieReceived(shibCookie, _account);
}
}
void ShibbolethWebView::hideEvent(QHideEvent* event)
void ShibbolethWebView::closeEvent(QCloseEvent *event)
{
Q_EMIT viewHidden();
QWebView::hideEvent(event);
if (!_accepted) {
Q_EMIT rejected();
}
QWebView::closeEvent(event);
}
void ShibbolethWebView::slotLoadStarted()
@@ -125,21 +104,9 @@ void ShibbolethWebView::slotLoadFinished(bool success)
}
}
void ShibbolethWebView::slotHandleAuthentication(QNetworkReply *reply, QAuthenticator *authenticator)
void ShibbolethWebView::accept()
{
Q_UNUSED(reply)
QUrl url = reply->url();
// show only scheme, host and port
QUrl reducedUrl;
reducedUrl.setScheme(url.scheme());
reducedUrl.setHost(url.host());
reducedUrl.setPort(url.port());
AuthenticationDialog dialog(authenticator->realm(), reducedUrl.toString(), this);
if (dialog.exec() == QDialog::Accepted) {
authenticator->setUser(dialog.user());
authenticator->setPassword(dialog.password());
}
_accepted = true;
}
} // ns Mirall

View File

@@ -37,23 +37,24 @@ public:
ShibbolethWebView(Account *account, ShibbolethCookieJar* jar, QWidget* parent = 0);
~ShibbolethWebView();
protected:
void hideEvent(QHideEvent* event);
void closeEvent(QCloseEvent *event);
Q_SIGNALS:
void shibbolethCookieReceived(const QNetworkCookie& cookie, Account* account);
void viewHidden();
void otherCookiesReceived(const QList<QNetworkCookie>& cookieList, const QUrl& url);
void shibbolethCookieReceived(const QNetworkCookie &cookie, Account *account);
void rejected();
private Q_SLOTS:
void onNewCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
void slotLoadStarted();
void slotLoadFinished(bool success = true);
void slotHandleAuthentication(QNetworkReply*,QAuthenticator*);
void slotLoadFinished(bool success);
protected:
void accept();
private:
void setup(Account *account, ShibbolethCookieJar* jar);
QPointer<Account> _account;
bool _accepted;
};
} // ns Mirall

View File

@@ -16,18 +16,21 @@
#include <QSettings>
#include <QNetworkReply>
#include <QMessageBox>
#include <qdebug.h>
#include <QAuthenticator>
#include <QDebug>
#include "creds/shibbolethcredentials.h"
#include "creds/shibboleth/shibbolethaccessmanager.h"
#include "creds/shibboleth/authenticationdialog.h"
#include "creds/shibboleth/shibbolethwebview.h"
#include "creds/shibboleth/shibbolethrefresher.h"
#include "creds/shibboleth/shibbolethconfigfile.h"
#include "creds/shibbolethcredentials.h"
#include "shibboleth/shibbolethuserjob.h"
#include "creds/credentialscommon.h"
#include "mirall/mirallaccessmanager.h"
#include "mirall/account.h"
#include "mirall/theme.h"
#include "mirall/cookiejar.h"
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
#include <qt5keychain/keychain.h>
@@ -43,7 +46,9 @@ namespace Mirall
namespace
{
const char userC[] = "user";
// Not "user" because it has a special meaning for http
const char userC[] = "shib_user";
const char shibCookieNameC[] = "_shibsession_";
int shibboleth_redirect_callback(CSYNC* csync_ctx,
const char* uri)
@@ -65,7 +70,6 @@ int shibboleth_redirect_callback(CSYNC* csync_ctx,
Account *account = AccountManager::instance()->account();
ShibbolethCredentials* creds = qobject_cast<ShibbolethCredentials*>(account->credentials());
if (!creds) {
qDebug() << "Not a Shibboleth creds instance!";
return 1;
@@ -84,18 +88,10 @@ int shibboleth_redirect_callback(CSYNC* csync_ctx,
ShibbolethCredentials::ShibbolethCredentials()
: AbstractCredentials(),
_url(),
_shibCookie(),
_ready(false),
_stillValid(false),
_browser(0),
_otherCookies()
{}
ShibbolethCredentials::ShibbolethCredentials(const QNetworkCookie& cookie, const QMap<QUrl, QList<QNetworkCookie> >& otherCookies)
: _shibCookie(cookie),
_ready(true),
_browser(0),
_otherCookies(otherCookies)
_fetchJobInProgress(false),
_browser(0)
{}
void ShibbolethCredentials::syncContextPreInit(CSYNC* ctx)
@@ -110,29 +106,11 @@ QByteArray ShibbolethCredentials::prepareCookieData() const
// have any way to get "session_key" module property from
// csync. Had we have it, then we could just append shibboleth
// cookies to the "session_key" value and set it in csync module.
QList<QNetworkCookie> cookies(AccountManager::instance()->account()->lastAuthCookies());
QMap<QString, QString> uniqueCookies;
Account *account = AccountManager::instance()->account();
QList<QNetworkCookie> cookies = accountCookies(account);
cookies << _shibCookie;
// Stuff cookies inside csync, then we can avoid the intermediate HTTP 401 reply
// when https://github.com/owncloud/core/pull/4042 is merged.
foreach(QNetworkCookie c, cookies) {
const QString cookieName(c.name());
if (cookieName.startsWith("_shibsession_")) {
continue;
}
uniqueCookies.insert(cookieName, c.value());
}
if (!_shibCookie.name().isEmpty()) {
uniqueCookies.insert(_shibCookie.name(), _shibCookie.value());
}
foreach(const QString& cookieName, uniqueCookies.keys()) {
cookiesAsString += cookieName;
cookiesAsString += '=';
cookiesAsString += uniqueCookies[cookieName];
cookiesAsString += "; ";
foreach(const QNetworkCookie &cookie, cookies) {
cookiesAsString += cookie.toRawForm(QNetworkCookie::NameAndValueOnly) + QLatin1String("; ");
}
return cookiesAsString.toLatin1();
@@ -150,9 +128,13 @@ void ShibbolethCredentials::syncContextPreStart (CSYNC* ctx)
bool ShibbolethCredentials::changed(AbstractCredentials* credentials) const
{
ShibbolethCredentials* other(dynamic_cast< ShibbolethCredentials* >(credentials));
ShibbolethCredentials* other(qobject_cast< ShibbolethCredentials* >(credentials));
if (!other || other->cookie() != this->cookie()) {
if (!other) {
return true;
}
if (_shibCookie != other->_shibCookie || _user != other->_user) {
return true;
}
@@ -169,24 +151,22 @@ QString ShibbolethCredentials::user() const
return _user;
}
QNetworkCookie ShibbolethCredentials::cookie() const
{
return _shibCookie;
}
QNetworkAccessManager* ShibbolethCredentials::getQNAM() const
{
ShibbolethAccessManager* qnam(new ShibbolethAccessManager(_shibCookie));
connect(this, SIGNAL(newCookie(QNetworkCookie)),
qnam, SLOT(setCookie(QNetworkCookie)));
QNetworkAccessManager* qnam(new MirallAccessManager);
connect(qnam, SIGNAL(finished(QNetworkReply*)),
this, SLOT(slotReplyFinished(QNetworkReply*)));
connect(qnam, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
SLOT(slotHandleAuthentication(QNetworkReply*,QAuthenticator*)));
return qnam;
}
void ShibbolethCredentials::slotReplyFinished(QNetworkReply* r)
{
if (!_browser.isNull()) {
return;
}
QVariant target = r->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (target.isValid()) {
_stillValid = false;
@@ -203,10 +183,16 @@ bool ShibbolethCredentials::ready() const
void ShibbolethCredentials::fetch(Account *account)
{
if(_fetchJobInProgress) {
return;
}
if (_user.isEmpty()) {
_user = account->credentialSetting(QLatin1String(userC)).toString();
}
if (_ready) {
_fetchJobInProgress = false;
Q_EMIT fetched();
} else {
if (account) {
@@ -219,6 +205,7 @@ void ShibbolethCredentials::fetch(Account *account)
job->setProperty("account", QVariant::fromValue(account));
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
job->start();
_fetchJobInProgress = true;
}
}
@@ -230,44 +217,29 @@ bool ShibbolethCredentials::stillValid(QNetworkReply *reply)
void ShibbolethCredentials::persist(Account* account)
{
ShibbolethConfigFile cfg;
cfg.storeCookies(_otherCookies);
storeShibCookie(_shibCookie, account);
if (!_user.isEmpty())
if (!_user.isEmpty()) {
account->setCredentialSetting(QLatin1String(userC), _user);
}
}
// only used by Application::slotLogout(). Use invalidateAndFetch for normal usage
void ShibbolethCredentials::invalidateToken(Account *account)
{
Q_UNUSED(account)
CookieJar *jar = static_cast<CookieJar*>(account->networkAccessManager()->cookieJar());
jar->deleteCookie(_shibCookie);
jar->clearSessionCookies();
removeShibCookie(account);
_shibCookie = QNetworkCookie();
storeShibCookie(_shibCookie, account); // store/erase cookie
// ### access to ctx missing, but might not be required at all
//csync_set_module_property(ctx, "session_key", "");
}
void ShibbolethCredentials::disposeBrowser()
void ShibbolethCredentials::onShibbolethCookieReceived(const QNetworkCookie& shibCookie, Account *account)
{
qDebug() << Q_FUNC_INFO;
disconnect(_browser, SIGNAL(viewHidden()),
this, SLOT(slotBrowserHidden()));
disconnect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie, Account*)),
this, SLOT(onShibbolethCookieReceived(QNetworkCookie, Account*)));
_browser->hide();
_browser->deleteLater();
_browser = 0;
}
void ShibbolethCredentials::onShibbolethCookieReceived(const QNetworkCookie& cookie, Account* account)
{
disposeBrowser();
_shibCookie = cookie;
storeShibCookie(_shibCookie, account);
Q_EMIT newCookie(_shibCookie);
storeShibCookie(shibCookie, account);
_shibCookie = shibCookie;
addToCookieJar(shibCookie);
// Now fetch the user...
// But we must first do a request to webdav so the session is enabled.
@@ -304,21 +276,22 @@ void ShibbolethCredentials::slotUserFetched(const QString &user)
_stillValid = true;
_ready = true;
_fetchJobInProgress = false;
Q_EMIT fetched();
}
void ShibbolethCredentials::slotBrowserHidden()
void ShibbolethCredentials::slotBrowserRejected()
{
disposeBrowser();
_ready = false;
_shibCookie = QNetworkCookie();
_fetchJobInProgress = false;
Q_EMIT fetched();
}
void ShibbolethCredentials::invalidateAndFetch(Account* account)
{
_ready = false;
_fetchJobInProgress = true;
// delete the credentials, then in the slot fetch them again (which will trigger browser)
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
@@ -329,12 +302,30 @@ void ShibbolethCredentials::invalidateAndFetch(Account* account)
job->start();
}
void ShibbolethCredentials::slotHandleAuthentication(QNetworkReply *reply, QAuthenticator *authenticator)
{
Q_UNUSED(reply)
QUrl url = reply->url();
// show only scheme, host and port
QUrl reducedUrl;
reducedUrl.setScheme(url.scheme());
reducedUrl.setHost(url.host());
reducedUrl.setPort(url.port());
AuthenticationDialog dialog(authenticator->realm(), reducedUrl.toString());
if (dialog.exec() == QDialog::Accepted) {
authenticator->setUser(dialog.user());
authenticator->setPassword(dialog.password());
}
}
void ShibbolethCredentials::slotInvalidateAndFetchInvalidateDone(QKeychain::Job* job)
{
Account *account = qvariant_cast<Account*>(job->property("account"));
connect (this, SIGNAL(fetched()),
this, SLOT(onFetched()));
_fetchJobInProgress = false;
// small hack to support the ShibbolethRefresher hack
// we already rand fetch() with a valid account object,
// and hence know the url on refresh
@@ -355,16 +346,17 @@ void ShibbolethCredentials::slotReadJobDone(QKeychain::Job *job)
if (job->error() == QKeychain::NoError) {
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(job);
delete readJob->settings();
qDebug() << Q_FUNC_INFO;
QList<QNetworkCookie> cookies = QNetworkCookie::parseCookies(readJob->textData().toUtf8());
if (cookies.count() > 0) {
_shibCookie = cookies.first();
addToCookieJar(_shibCookie);
}
// access
job->setSettings(account->settingsWithGroup(Theme::instance()->appName(), job));
_ready = true;
_stillValid = true;
Q_EMIT newCookie(_shibCookie);
_fetchJobInProgress = false;
Q_EMIT fetched();
} else {
showLoginWindow(account);
@@ -373,24 +365,51 @@ void ShibbolethCredentials::slotReadJobDone(QKeychain::Job *job)
void ShibbolethCredentials::showLoginWindow(Account* account)
{
if (_browser) {
if (!_browser.isNull()) {
_browser->activateWindow();
_browser->raise();
// FIXME On OS X this does not raise properly
return;
}
ShibbolethConfigFile cfg;
_browser = new ShibbolethWebView(account, cfg.createCookieJar());
CookieJar *jar = static_cast<CookieJar*>(account->networkAccessManager()->cookieJar());
// When opening a new window clear all the session cookie that might keep the user from logging in
// (or the session may already be open in the server, and there will not be redirect asking for the
// real long term cookie we want to store)
jar->clearSessionCookies();
_browser = new ShibbolethWebView(account);
connect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie, Account*)),
this, SLOT(onShibbolethCookieReceived(QNetworkCookie, Account*)));
connect(_browser, SIGNAL(viewHidden()),
this, SLOT(slotBrowserHidden()));
// FIXME If the browser was hidden (e.g. user closed it) without us logging in, the logic gets stuck
// and can only be unstuck by restarting the app or pressing "Sign in" (we should switch to offline but we don't)
this, SLOT(onShibbolethCookieReceived(QNetworkCookie, Account*)), Qt::QueuedConnection);
connect(_browser, SIGNAL(rejected()), this, SLOT(slotBrowserRejected()));
_browser->show();
}
QList<QNetworkCookie> ShibbolethCredentials::accountCookies(Account *account)
{
return account->networkAccessManager()->cookieJar()->cookiesForUrl(account->url());
}
QNetworkCookie ShibbolethCredentials::findShibCookie(Account *account, QList<QNetworkCookie> cookies)
{
if(cookies.isEmpty()) {
cookies = accountCookies(account);
}
Q_FOREACH(QNetworkCookie cookie, cookies) {
if (cookie.name().startsWith(shibCookieNameC)) {
return cookie;
}
}
return QNetworkCookie();
}
QByteArray ShibbolethCredentials::shibCookieName()
{
return QByteArray(shibCookieNameC);
}
void ShibbolethCredentials::storeShibCookie(const QNetworkCookie &cookie, Account *account)
{
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
@@ -402,5 +421,24 @@ void ShibbolethCredentials::storeShibCookie(const QNetworkCookie &cookie, Accoun
job->start();
}
void ShibbolethCredentials::removeShibCookie(Account *account)
{
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
job->setSettings(account->settingsWithGroup(Theme::instance()->appName(), job));
job->setKey(keychainKey(account->url().toString(), "shibAssertion"));
job->start();
}
void ShibbolethCredentials::addToCookieJar(const QNetworkCookie &cookie)
{
QList<QNetworkCookie> cookies;
cookies << cookie;
Account *account = AccountManager::instance()->account();
QNetworkCookieJar *jar = account->networkAccessManager()->cookieJar();
jar->blockSignals(true); // otherwise we'd call ourselves
jar->setCookiesFromUrl(cookies, account->url());
jar->blockSignals(false);
}
} // ns Mirall

View File

@@ -18,6 +18,7 @@
#include <QMap>
#include <QNetworkCookie>
#include <QUrl>
#include <QPointer>
#include "creds/abstractcredentials.h"
@@ -25,6 +26,8 @@ namespace QKeychain {
class Job;
}
class QAuthenticator;
namespace Mirall
{
@@ -36,7 +39,6 @@ Q_OBJECT
public:
ShibbolethCredentials();
ShibbolethCredentials(const QNetworkCookie& cookie, const QMap<QUrl, QList<QNetworkCookie> >& otherCookies);
void syncContextPreInit(CSYNC* ctx);
void syncContextPreStart(CSYNC* ctx);
@@ -50,16 +52,19 @@ public:
void persist(Account *account);
void invalidateToken(Account *account);
QNetworkCookie cookie() const;
void showLoginWindow(Account*);
static QList<QNetworkCookie> accountCookies(Account*);
static QNetworkCookie findShibCookie(Account*, QList<QNetworkCookie> cookies = QList<QNetworkCookie>());
static QByteArray shibCookieName();
public Q_SLOTS:
void invalidateAndFetch(Account *account);
void slotHandleAuthentication(QNetworkReply*,QAuthenticator*);
private Q_SLOTS:
void onShibbolethCookieReceived(const QNetworkCookie& cookie, Account*);
void slotBrowserHidden();
void onShibbolethCookieReceived(const QNetworkCookie&, Account*);
void slotBrowserRejected();
void onFetched();
void slotReadJobDone(QKeychain::Job*);
void slotInvalidateAndFetchInvalidateDone(QKeychain::Job*);
@@ -73,15 +78,16 @@ Q_SIGNALS:
private:
void storeShibCookie(const QNetworkCookie &cookie, Account *account);
void removeShibCookie(Account *account);
void addToCookieJar(const QNetworkCookie &cookie);
QUrl _url;
QByteArray prepareCookieData() const;
void disposeBrowser();
QNetworkCookie _shibCookie;
bool _ready;
bool _stillValid;
ShibbolethWebView* _browser;
QMap<QUrl, QList<QNetworkCookie> > _otherCookies;
bool _fetchJobInProgress;
QPointer<ShibbolethWebView> _browser;
QNetworkCookie _shibCookie;
QString _user;
};

View File

@@ -1,4 +1,5 @@
/*
*
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
*
* This program is free software; you can redistribute it and/or modify
@@ -11,8 +12,15 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <QtGlobal>
#include <signal.h>
#ifdef Q_OS_UNIX
#include <sys/time.h>
#include <sys/resource.h>
#endif
#include "mirall/application.h"
#include "mirall/theme.h"
#include "mirall/utility.h"
@@ -51,6 +59,20 @@ int main(int argc, char **argv)
return 0;
}
// check a environment variable for core dumps
#ifdef Q_OS_UNIX
if( !qgetenv("OWNCLOUD_CORE_DUMP").isEmpty() ) {
struct rlimit core_limit;
core_limit.rlim_cur = RLIM_INFINITY;
core_limit.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_CORE, &core_limit) < 0) {
fprintf(stderr, "Unable to set core dump limit\n");
} else {
qDebug() << "Core dumps enabled";
}
}
#endif
// if handleStartup returns true, main()
// needs to terminate here, e.g. because
// the updater is triggered

View File

@@ -12,9 +12,11 @@
*/
#include "mirall/account.h"
#include "mirall/cookiejar.h"
#include "mirall/theme.h"
#include "mirall/networkjobs.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/mirallaccessmanager.h"
#include "mirall/quotainfo.h"
#include "creds/abstractcredentials.h"
#include "creds/credentialsfactory.h"
@@ -75,6 +77,8 @@ Account::Account(AbstractSslErrorHandler *sslErrorHandler, QObject *parent)
Account::~Account()
{
delete _credentials;
delete _am;
}
void Account::save()
@@ -161,7 +165,11 @@ AbstractCredentials *Account::credentials() const
void Account::setCredentials(AbstractCredentials *cred)
{
// set active credential manager
QNetworkCookieJar *jar = 0;
if (_am) {
jar = _am->cookieJar();
jar->setParent(0);
_am->deleteLater();
}
@@ -170,6 +178,9 @@ void Account::setCredentials(AbstractCredentials *cred)
}
_credentials = cred;
_am = _credentials->getQNAM();
if (jar) {
_am->setCookieJar(jar);
}
connect(_am, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
SLOT(slotHandleErrors(QNetworkReply*,QList<QSslError>)));
}
@@ -186,7 +197,12 @@ QList<QNetworkCookie> Account::lastAuthCookies() const
void Account::clearCookieJar()
{
_am->setCookieJar(new QNetworkCookieJar);
_am->setCookieJar(new CookieJar);
}
QNetworkAccessManager *Account::networkAccessManager()
{
return _am;
}
QNetworkReply *Account::headRequest(const QString &relPath)

View File

@@ -34,6 +34,7 @@ namespace Mirall {
class AbstractCredentials;
class Account;
class QuotaInfo;
class MirallAccessManager;
class OWNCLOUDSYNC_EXPORT AccountManager : public QObject {
Q_OBJECT
@@ -143,6 +144,8 @@ public:
void clearCookieJar();
QNetworkAccessManager* networkAccessManager();
QuotaInfo *quotaInfo();
signals:
void stateChanged(int state);

View File

@@ -114,7 +114,6 @@ AccountSettings::AccountSettings(QWidget *parent) :
connect(FolderMan::instance(), SIGNAL(folderListLoaded(Folder::Map)),
this, SLOT(setFolderList(Folder::Map)));
setFolderList(FolderMan::instance()->map());
}
void AccountSettings::slotAccountChanged(Account *newAccount, Account *oldAccount)
@@ -140,28 +139,28 @@ void AccountSettings::slotAccountChanged(Account *newAccount, Account *oldAccoun
void AccountSettings::slotFolderActivated( const QModelIndex& indx )
{
bool state = indx.isValid();
bool isValid = indx.isValid();
bool haveFolders = ui->_folderList->model()->rowCount() > 0;
ui->_buttonRemove->setEnabled(state);
ui->_buttonRemove->setEnabled(isValid);
if( Theme::instance()->singleSyncFolder() ) {
// only one folder synced folder allowed.
ui->_buttonAdd->setVisible(!haveFolders);
} else {
ui->_buttonAdd->setVisible(true);
ui->_buttonAdd->setEnabled( true );
}
ui->_buttonEnable->setEnabled( state );
ui->_buttonAdd->setEnabled(_account && _account->state() == Account::Connected);
ui->_buttonEnable->setEnabled( isValid );
if ( state ) {
if ( isValid ) {
bool folderEnabled = _model->data( indx, FolderStatusDelegate::FolderSyncEnabled).toBool();
if ( folderEnabled ) {
ui->_buttonEnable->setText( tr( "Pause" ) );
} else {
ui->_buttonEnable->setText( tr( "Resume" ) );
}
ui->_buttonEnable->setEnabled(_account && _account->state() == Account::Connected);
ui->_buttonEnable->setEnabled( _account && _account->state() == Account::Connected);
}
}
@@ -173,8 +172,6 @@ void AccountSettings::slotAddFolder()
folderMan->setSyncEnabled(false); // do not start more syncs.
FolderWizard *folderWizard = new FolderWizard(this);
Folder::Map folderMap = folderMan->map();
folderWizard->setFolderMap( folderMap );
connect(folderWizard, SIGNAL(accepted()), SLOT(slotFolderWizardAccepted()));
connect(folderWizard, SIGNAL(rejected()), SLOT(slotFolderWizardRejected()));
@@ -269,6 +266,10 @@ void AccountSettings::folderToModelItem( QStandardItem *item, Folder *f )
// if the folder was disabled before, set the sync icon
item->setData( theme->syncStateIcon( SyncResult::SyncRunning), FolderStatusDelegate::FolderStatusIconRole );
} // we keep the previous icon for the SyncPrepare state.
} else if( status == SyncResult::Undefined ) {
// startup, the sync was never done.
qDebug() << "XXX FIRST time sync, setting icon to sync running!";
item->setData( theme->syncStateIcon( SyncResult::SyncRunning), FolderStatusDelegate::FolderStatusIconRole );
} else {
// kepp the previous icon for the prepare phase.
if( status == SyncResult::Problem) {
@@ -361,7 +362,7 @@ void AccountSettings::slotResetCurrentFolder()
if( ret == QMessageBox::Yes ) {
FolderMan *folderMan = FolderMan::instance();
Folder *f = folderMan->folder(alias);
f->slotTerminateSync(true);
f->slotTerminateSync();
f->wipe();
folderMan->slotScheduleAllFolders();
}
@@ -415,28 +416,6 @@ void AccountSettings::setFolderList( const Folder::Map &folders )
}
// move from Application
void AccountSettings::slotFolderOpenAction( const QString& alias )
{
Folder *f = FolderMan::instance()->folder(alias);
qDebug() << "opening local url " << f->path();
if( f ) {
QUrl url(f->path(), QUrl::TolerantMode);
url.setScheme( QLatin1String("file") );
#ifdef Q_OS_WIN
// work around a bug in QDesktopServices on Win32, see i-net
QString filePath = f->path();
if (filePath.startsWith(QLatin1String("\\\\")) || filePath.startsWith(QLatin1String("//")))
url.setUrl(QDir::toNativeSeparators(filePath));
else
url = QUrl::fromLocalFile(filePath);
#endif
QDesktopServices::openUrl(url);
}
}
void AccountSettings::slotEnableCurrentFolder()
{
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
@@ -453,7 +432,11 @@ void AccountSettings::slotEnableCurrentFolder()
// this sets the folder status to disabled but does not interrupt it.
Folder *f = folderMan->folder( alias );
if( f && folderEnabled ) {
if (!f) {
return;
}
if( folderEnabled ) {
// check if a sync is still running and if so, ask if we should terminate.
if( f->isBusy() ) { // its still running
#if defined(Q_OS_MAC)
@@ -478,7 +461,7 @@ void AccountSettings::slotEnableCurrentFolder()
// message box can return at any time while the thread keeps running,
// so better check again after the user has responded.
if ( f->isBusy() && terminate ) {
f->slotTerminateSync(false);
f->slotTerminateSync();
}
folderMan->slotEnableFolder( alias, !folderEnabled );
@@ -633,8 +616,9 @@ void AccountSettings::slotSetProgress(const QString& folder, const Progress::Inf
item->setData( overallSyncString, FolderStatusDelegate::SyncProgressOverallString );
int overallPercent = 0;
if( progress._totalSize > 0 ) {
overallPercent = qRound(double(completedSize)/double(progress._totalSize) * 100.0);
if( progress._totalFileCount > 0 ) {
// Add one 'byte' for each files so the percentage is moving when deleting or renaming files
overallPercent = qRound(double(completedSize + progress._completedFileCount)/double(progress._totalSize + progress._totalFileCount) * 100.0);
}
item->setData( overallPercent, FolderStatusDelegate::SyncProgressOverallPercent);
}
@@ -739,7 +723,7 @@ void AccountSettings::slotAccountStateChanged(int state)
ui->sslButton->updateAccountInfo(_account);
QUrl safeUrl(_account->url());
safeUrl.setPassword(QString()); // Remove the password from the URL to avoid showing it in the UI
ui->_buttonAdd->setEnabled(state == Account::Connected);
slotButtonsSetEnabled();
if (state == Account::Connected) {
QString user;
if (AbstractCredentials *cred = _account->credentials()) {

View File

@@ -60,7 +60,6 @@ public slots:
void slotOpenOC();
void slotUpdateFolderState( Folder* );
void slotDoubleClicked( const QModelIndex& );
void slotFolderOpenAction( const QString& );
void slotSetProgress(const QString& folder, const Progress::Info& progress);
void slotButtonsSetEnabled();

View File

@@ -45,6 +45,8 @@
#include <QMenu>
#include <QMessageBox>
class QSocket;
namespace Mirall {
namespace {
@@ -64,14 +66,12 @@ static const char optionsC[] =
QString applicationTrPath()
{
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
return QString::fromLatin1(DATADIR"/"APPLICATION_EXECUTABLE"/i18n/");
#endif
#ifdef Q_OS_MAC
return QApplication::applicationDirPath()+QLatin1String("/../Resources/Translations"); // path defaults to app dir.
#endif
#ifdef Q_OS_WIN
#if defined(Q_OS_WIN)
return QApplication::applicationDirPath();
#elif defined(Q_OS_MAC)
return QApplication::applicationDirPath()+QLatin1String("/../Resources/Translations"); // path defaults to app dir.
#elif defined(Q_OS_UNIX)
return QString::fromLatin1(DATADIR"/"APPLICATION_EXECUTABLE"/i18n/");
#endif
}
}
@@ -79,7 +79,7 @@ QString applicationTrPath()
// ----------------------------------------------------------------------------------
Application::Application(int &argc, char **argv) :
SharedTools::QtSingleApplication(argc, argv),
SharedTools::QtSingleApplication(Theme::instance()->appName() ,argc, argv),
_gui(0),
_theme(Theme::instance()),
_helpOnly(false),
@@ -99,14 +99,13 @@ Application::Application(int &argc, char **argv) :
//no need to waste time;
if ( _helpOnly ) return;
initialize();
if (isRunning())
return;
setupLogging();
setupTranslations();
connect( this, SIGNAL(messageReceived(QString)), SLOT(slotParseOptions(QString)));
connect( this, SIGNAL(messageReceived(QString, QObject*)), SLOT(slotParseOptions(QString, QObject*)));
Account *account = Account::restore();
if (account) {
@@ -159,6 +158,7 @@ Application::Application(int &argc, char **argv) :
Application::~Application()
{
delete AccountManager::instance()->account();
// qDebug() << "* Mirall shutdown";
}
@@ -245,6 +245,8 @@ void Application::slotCheckConnection()
} else {
// let gui open the setup wizard
_gui->slotOpenSettingsDialog( true );
_checkConnectionTimer.stop(); // don't popup the wizard on interval;
}
}
@@ -323,6 +325,7 @@ void Application::slotownCloudWizardDone( int res )
}
folderMan->setSyncEnabled( true );
if( res == QDialog::Accepted ) {
_checkConnectionTimer.start();
slotCheckConnection();
}
@@ -350,7 +353,7 @@ void Application::slotUseMonoIconsChanged(bool)
_gui->slotComputeOverallSyncStatus();
}
void Application::slotParseOptions(const QString &opts)
void Application::slotParseOptions(const QString &opts, QObject*)
{
QStringList options = opts.split(QLatin1Char('|'));
parseOptions(options);

View File

@@ -28,9 +28,11 @@
#include "mirall/connectionvalidator.h"
#include "mirall/progressdispatcher.h"
#include "mirall/clientproxy.h"
#include "mirall/folderman.h"
class QMessageBox;
class QSystemTrayIcon;
class QSocket;
namespace Mirall {
class Theme;
@@ -69,7 +71,7 @@ signals:
void folderStateChanged(Folder*);
protected slots:
void slotParseOptions( const QString& );
void slotParseOptions( const QString&, QObject* );
void slotCheckConnection();
void slotConnectionValidatorResult(ConnectionValidator::Status);
void slotStartUpdateDetector();
@@ -106,6 +108,8 @@ private:
QTimer _checkConnectionTimer;
FolderMan folderManager;
friend class ownCloudGui; // for _startupNetworkError
};

155
src/mirall/cookiejar.cpp Normal file
View File

@@ -0,0 +1,155 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "cookiejar.h"
#include "mirall/mirallconfigfile.h"
#include <QDebug>
#include <QFile>
#include <QDateTime>
#include <QNetworkCookie>
namespace Mirall {
namespace {
const unsigned int JAR_VERSION = 23;
}
QDataStream &operator<<(QDataStream &stream, const QList<QNetworkCookie> &list)
{
stream << JAR_VERSION;
stream << quint32(list.size());
for (int i = 0; i < list.size(); ++i)
stream << list.at(i).toRawForm();
return stream;
}
QDataStream &operator>>(QDataStream &stream, QList<QNetworkCookie> &list)
{
list.clear();
quint32 version;
stream >> version;
if (version != JAR_VERSION)
return stream;
quint32 count;
stream >> count;
for(quint32 i = 0; i < count; ++i)
{
QByteArray value;
stream >> value;
QList<QNetworkCookie> newCookies = QNetworkCookie::parseCookies(value);
if (newCookies.count() == 0 && value.length() != 0) {
qWarning() << "CookieJar: Unable to parse saved cookie:" << value;
}
for (int j = 0; j < newCookies.count(); ++j)
list.append(newCookies.at(j));
if (stream.atEnd())
break;
}
return stream;
}
CookieJar::CookieJar(QObject *parent) :
QNetworkCookieJar(parent)
{
restore();
}
CookieJar::~CookieJar()
{
save();
}
bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url)
{
if (QNetworkCookieJar::setCookiesFromUrl(cookieList, url)) {
Q_EMIT newCookiesForUrl(cookieList, url);
return true;
}
return false;
}
QList<QNetworkCookie> CookieJar::cookiesForUrl(const QUrl &url) const
{
QList<QNetworkCookie> cookies = QNetworkCookieJar::cookiesForUrl(url);
// qDebug() << url << "requests:" << cookies;
return cookies;
}
bool CookieJar::deleteCookie(const QNetworkCookie &delCookie)
{
QList<QNetworkCookie> cookies = allCookies();
bool removeSucceeded = false;
foreach(const QNetworkCookie &cookie, cookies) {
// ### cookies are not identical in attriutes, why?
if (cookie.name() == delCookie.name()) {
cookies.removeOne(cookie);
removeSucceeded = true;
}
}
setAllCookies(cookies);
return removeSucceeded;
}
void CookieJar::clearSessionCookies()
{
setAllCookies(removeExpired(allCookies()));
}
void CookieJar::save()
{
QFile file;
file.setFileName(storagePath());
qDebug() << storagePath();
file.open(QIODevice::WriteOnly);
QDataStream stream(&file);
stream << allCookies();
file.close();
}
void CookieJar::restore()
{
QFile file;
file.setFileName(storagePath());
file.open(QIODevice::ReadOnly);
QDataStream stream(&file);
QList<QNetworkCookie> list;
stream >> list;
setAllCookies(removeExpired(list));
file.close();
}
QList<QNetworkCookie> CookieJar::removeExpired(const QList<QNetworkCookie> &cookies)
{
QList<QNetworkCookie> updatedList;
foreach(const QNetworkCookie &cookie, cookies) {
if (cookie.expirationDate() > QDateTime::currentDateTime() && !cookie.isSessionCookie()) {
updatedList << cookie;
}
}
return updatedList;
}
QString CookieJar::storagePath() const
{
MirallConfigFile cfg;
return cfg.configPath() + "/cookies.db";
}
} // namespace Mirall

47
src/mirall/cookiejar.h Normal file
View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_COOKIEJAR_H
#define MIRALL_COOKIEJAR_H
#include <QNetworkCookieJar>
#include "owncloudlib.h"
namespace Mirall {
class OWNCLOUDSYNC_EXPORT CookieJar : public QNetworkCookieJar
{
Q_OBJECT
public:
explicit CookieJar(QObject *parent = 0);
~CookieJar();
bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url);
QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const;
virtual bool deleteCookie(const QNetworkCookie & cookie);
void clearSessionCookies();
signals:
void newCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
private:
void save();
void restore();
QList<QNetworkCookie> removeExpired(const QList<QNetworkCookie> &cookies);
QString storagePath() const;
};
} // namespace Mirall
#endif // MIRALL_COOKIEJAR_H

View File

@@ -91,10 +91,29 @@ Folder::Folder(const QString &alias, const QString &path, const QString& secondP
bool Folder::init()
{
QString url = Utility::toCSyncScheme(remoteUrl().toString());
Account *account = AccountManager::instance()->account();
if (!account) {
// Normaly this should not happen, but it could be that there is something
// wrong with the config and it is better not to crash.
qWarning() << "WRN: No account configured, can't sync";
return false;
}
// We need to reconstruct the url because the path need to be fully decoded, as csync will re-encode the path:
// Remember that csync will just append the filename to the path and pass it to the vio plugin.
// csync_owncloud will then re-encode everything.
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
QUrl url = remoteUrl();
QString url_string = url.scheme() + QLatin1String("://") + url.authority(QUrl::EncodeDelimiters) + url.path(QUrl::FullyDecoded);
#else
// Qt4 was broken anyway as it did not encode the '#' as it should have done (it was actually a provlem when parsing the path from QUrl::setPath
QString url_string = remoteUrl().toString();
#endif
url_string = Utility::toCSyncScheme(url_string);
QString localpath = path();
if( csync_create( &_csync_ctx, localpath.toUtf8().data(), url.toUtf8().data() ) < 0 ) {
if( csync_create( &_csync_ctx, localpath.toUtf8().data(), url_string.toUtf8().data() ) < 0 ) {
qDebug() << "Unable to create csync-context!";
slotSyncError(tr("Unable to create csync-context"));
_csync_ctx = 0;
@@ -301,8 +320,7 @@ void Folder::bubbleUpSyncResult()
SyncRunFileLog syncFileLog;
syncFileLog.start(path(), _stopWatch );
_stopWatch.reset();
syncFileLog.start(path(), _engine ? _engine->stopWatch() : Utility::StopWatch() );
QElapsedTimer timer;
timer.start();
@@ -467,7 +485,7 @@ void Folder::slotThreadTreeWalkResult(const SyncFileItemVector& items)
_syncResult.setSyncFileItemVector(items);
}
void Folder::slotTerminateSync(bool block)
void Folder::slotTerminateSync()
{
qDebug() << "folder " << alias() << " Terminating!";
@@ -477,14 +495,10 @@ void Folder::slotTerminateSync(bool block)
// Do not display an error message, user knows his own actions.
// _errors.append( tr("The CSync thread terminated.") );
// _csyncError = true;
if (!block) {
setSyncState(SyncResult::SyncAbortRequested);
return;
}
slotSyncFinished();
setSyncEnabled(false);
setSyncState(SyncResult::SyncAbortRequested);
return;
}
setSyncEnabled(false);
}
// This removes the csync File database
@@ -630,7 +644,6 @@ void Folder::slotSyncFinished()
qDebug() << "-> CSync Finished slot with error " << _csyncError << "warn count" << _syncResult.warnCount();
bubbleUpSyncResult();
_stopWatch = _engine->stopWatch();
_engine.reset(0);
// _watcher->setEventsEnabledDelayed(2000);
@@ -653,9 +666,24 @@ void Folder::slotSyncFinished()
}
emit syncStateChange();
// The syncFinished result that is to be triggered here makes the folderman
// clearing the current running sync folder marker.
// Lets wait a bit to do that because, as long as this marker is not cleared,
// file system change notifications are ignored for that folder. And it takes
// some time under certain conditions to make the file system notifications
// all come in.
QTimer::singleShot(200, this, SLOT(slotEmitFinishedDelayed() ));
}
void Folder::slotEmitFinishedDelayed()
{
emit syncFinished( _syncResult );
}
// the progress comes without a folder and the valid path set. Add that here
// and hand the result over to the progress dispatcher.
void Folder::slotTransmissionProgress(const Progress::Info &pi)
@@ -695,6 +723,9 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *
*cancel = msgBox.clickedButton() == keepBtn;
if (*cancel) {
wipe();
// speed up next sync
_lastEtag = QString();
QTimer::singleShot(50, this, SLOT(slotPollTimerTimeout()));
}
#endif
}

View File

@@ -21,7 +21,6 @@
#include "mirall/progressdispatcher.h"
#include "mirall/syncjournaldb.h"
#include "mirall/clientproxy.h"
#include "mirall/utility.h"
#include <csync.h>
@@ -149,10 +148,8 @@ public slots:
/**
* terminate the current sync run
*
* If block is true, this will block synchroniously for the sync thread to finish.
*/
void slotTerminateSync(bool block);
void slotTerminateSync();
void slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool*);
@@ -184,9 +181,12 @@ private slots:
void slotThreadTreeWalkResult(const SyncFileItemVector& );
void slotEmitFinishedDelayed();
private:
bool init();
void setIgnoredFiles();
void bubbleUpSyncResult();
@@ -200,7 +200,6 @@ private:
QString _remotePath;
QString _alias;
QString _configFile;
QFileSystemWatcher *_pathWatcher;
bool _enabled;
SyncResult _syncResult;
QScopedPointer<SyncEngine> _engine;
@@ -217,8 +216,6 @@ private:
ClientProxy _clientProxy;
Utility::StopWatch _stopWatch;
CSYNC *_csync_ctx;
};

View File

@@ -41,13 +41,6 @@ FolderMan::FolderMan(QObject *parent) :
QObject(parent),
_syncEnabled( true )
{
// if QDir::mkpath would not be so stupid, I would not need to have this
// duplication of folderConfigPath() here
MirallConfigFile cfg;
QDir storageDir(cfg.configPath());
storageDir.mkpath(QLatin1String("folders"));
_folderConfigPath = cfg.configPath() + QLatin1String("folders");
_folderChangeSignalMapper = new QSignalMapper(this);
connect(_folderChangeSignalMapper, SIGNAL(mapped(const QString &)),
this, SIGNAL(folderSyncStateChange(const QString &)));
@@ -55,15 +48,14 @@ FolderMan::FolderMan(QObject *parent) :
_folderWatcherSignalMapper = new QSignalMapper(this);
connect(_folderWatcherSignalMapper, SIGNAL(mapped(const QString&)),
this, SLOT(slotScheduleSync(const QString&)));
ne_sock_init();
Q_ASSERT(!_instance);
_instance = this;
}
FolderMan *FolderMan::instance()
{
if(!_instance) {
_instance = new FolderMan;
ne_sock_init();
}
return _instance;
}
@@ -71,6 +63,7 @@ FolderMan::~FolderMan()
{
qDeleteAll(_folderMap);
ne_sock_exit();
_instance = 0;
}
Mirall::Folder::Map FolderMan::map()
@@ -144,6 +137,11 @@ int FolderMan::setupFolders()
unloadAllFolders();
MirallConfigFile cfg;
QDir storageDir(cfg.configPath());
storageDir.mkpath(QLatin1String("folders"));
_folderConfigPath = cfg.configPath() + QLatin1String("folders");
QDir dir( _folderConfigPath );
//We need to include hidden files just in case the alias starts with '.'
dir.setFilter(QDir::Files | QDir::Hidden);
@@ -301,6 +299,7 @@ Folder* FolderMan::setupFolderFromConfigFile(const QString &file) {
qDebug() << "Adding folder to Folder Map " << folder;
_folderMap[alias] = folder;
if (paused) {
folder->setSyncEnabled(!paused);
_disabledFolders.insert(folder);
}
@@ -353,9 +352,10 @@ void FolderMan::terminateSyncProcess( const QString& alias )
if( ! folderAlias.isEmpty() && _folderMap.contains(folderAlias) ) {
Folder *f = _folderMap[folderAlias];
if( f ) {
f->slotTerminateSync(true);
if(_currentSyncFolder == folderAlias )
f->slotTerminateSync();
if(_currentSyncFolder == folderAlias ) {
_currentSyncFolder.clear();
}
}
}
}

View File

@@ -30,12 +30,13 @@ class SyncResult;
namespace Mirall {
class Application;
class OWNCLOUDSYNC_EXPORT FolderMan : public QObject
{
Q_OBJECT
public:
static FolderMan* instance();
~FolderMan();
int setupFolders();
@@ -144,10 +145,10 @@ private:
QQueue<QString> _scheduleQueue;
QMap<QString, FolderWatcher*> _folderWatchers;
explicit FolderMan(QObject *parent = 0);
static FolderMan *_instance;
explicit FolderMan(QObject *parent = 0);
~FolderMan();
friend class Mirall::Application;
};
} // namespace Mirall

View File

@@ -56,9 +56,6 @@ class FolderStatusDelegate : public QStyledItemDelegate
QSize sizeHint( const QStyleOptionViewItem&, const QModelIndex& ) const;
bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option,
const QModelIndex& index );
private:
bool _addProgressSpace;
};
} // namespace Mirall

View File

@@ -29,7 +29,7 @@
#include "mirall/folderwatcher_win.h"
#elif defined(Q_OS_MAC)
#include "mirall/folderwatcher_mac.h"
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
#elif defined(Q_OS_UNIX)
#include "mirall/folderwatcher_linux.h"
#endif
@@ -115,7 +115,7 @@ void FolderWatcher::changeDetected( const QString& path )
void FolderWatcher::changeDetected( const QStringList& paths )
{
qDebug() << Q_FUNC_INFO << paths;
// qDebug() << Q_FUNC_INFO << paths;
// TODO: this shortcut doesn't look very reliable:
// - why is the timeout only 1 second?

View File

@@ -104,7 +104,7 @@ bool FolderWizardLocalPath::isComplete() const
}
// check if the local directory isn't used yet in another ownCloud sync
Folder::Map map = _folderMap;
Folder::Map map = FolderMan::instance()->map();
if( isOk ) {
Folder::Map::const_iterator i = map.constBegin();
@@ -136,7 +136,7 @@ bool FolderWizardLocalPath::isComplete() const
QString absCleanUserFolder = QDir::cleanPath(QDir(userInput).canonicalPath())+'/';
if( isOk && QDir::cleanPath(folderDir).startsWith(absCleanUserFolder) ) {
qDebug() << "A already configured folder is child of the current selected";
warnStrings.append( tr("The selected folder is a symbolic link. An already configured"
warnStrings.append( tr("The selected folder is a symbolic link. An already configured "
"folder is contained in the folder this link is pointing to."));
isOk = false;
}
@@ -170,8 +170,8 @@ bool FolderWizardLocalPath::isComplete() const
bool goon = true;
while( goon && i != map.constEnd() ) {
Folder *f = i.value();
qDebug() << "Checking local alias: " << f->alias();
if( f ) {
qDebug() << "Checking local alias: " << f->alias();
if( f->alias() == alias ) {
warnStrings.append( tr("The alias <i>%1</i> is already in use. Please pick another alias.").arg(alias) );
isOk = false;
@@ -224,7 +224,10 @@ void FolderWizardLocalPath::slotChooseLocalFolder()
// =================================================================================
FolderWizardRemotePath::FolderWizardRemotePath()
: FormatWarningsWizardPage()
, _ownCloudDirCheck(0)
, _dirChecked(false)
,_warnWasVisible(false)
{
_ui.setupUi(this);
_ui.warnFrame->hide();
@@ -374,7 +377,7 @@ bool FolderWizardRemotePath::isComplete() const
}
wizard()->setProperty("targetPath", dir);
Folder::Map map = _folderMap;
Folder::Map map = FolderMan::instance()->map();
Folder::Map::const_iterator i = map.constBegin();
for(i = map.constBegin();i != map.constEnd(); i++ ) {
Folder *f = static_cast<Folder*>(i.value());
@@ -448,13 +451,6 @@ FolderWizard::~FolderWizard()
{
}
void FolderWizard::setFolderMap( const Folder::Map& fm)
{
_folderWizardSourcePage->setFolderMap( fm );
if (!Theme::instance()->singleSyncFolder()) {
_folderWizardTargetPage->setFolderMap( fm );
}
}
} // end namespace

View File

@@ -73,8 +73,6 @@ public:
virtual void initializePage();
virtual void cleanupPage();
void setFolderMap( const Folder::Map &fm ) { _folderMap = fm; }
protected slots:
void showWarn( const QString& = QString() ) const;
@@ -91,7 +89,7 @@ private:
ownCloudInfo *_ownCloudDirCheck;
bool _dirChecked;
bool _warnWasVisible;
Folder::Map _folderMap;
};
/**
@@ -109,7 +107,6 @@ public:
FolderWizard(QWidget *parent = 0);
~FolderWizard();
void setFolderMap( const Folder::Map &map );
private:

View File

@@ -27,6 +27,9 @@ static void mirallLogCatcher(QtMsgType type, const char *msg)
// qDebug() exports to local8Bit, which is not always UTF-8
Logger::instance()->mirallLog( QString::fromLocal8Bit(msg) );
}
static void qInstallMessageHandler(QtMsgHandler h) {
qInstallMsgHandler(h);
}
#else
static void mirallLogCatcher(QtMsgType, const QMessageLogContext &ctx, const QString &message) {
Q_UNUSED(ctx);
@@ -38,35 +41,23 @@ static void mirallLogCatcher(QtMsgType, const QMessageLogContext &ctx, const QSt
}
#endif
Logger* Logger::_instance=0;
Logger::Logger( QObject* parent)
: QObject(parent),
_showTime(true), _doLogging(false), _doFileFlush(false), _logExpire(0)
{
}
Logger *Logger::instance()
{
if( !Logger::_instance ) {
Logger::_instance = new Logger;
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
qInstallMsgHandler( mirallLogCatcher );
#else
qInstallMessageHandler(mirallLogCatcher);
#endif
}
return Logger::_instance;
static Logger log;
return &log;
}
void Logger::destroy()
Logger::Logger( QObject* parent) : QObject(parent),
_showTime(true), _doLogging(false), _doFileFlush(false), _logExpire(0)
{
if( Logger::_instance ) {
delete Logger::_instance;
Logger::_instance = 0;
}
qInstallMessageHandler(mirallLogCatcher);
}
Logger::~Logger() {
qInstallMessageHandler(0);
}
void Logger::postGuiLog(const QString &title, const QString &message)
{
emit guiLog(title, message);

View File

@@ -41,6 +41,7 @@ class OWNCLOUDSYNC_EXPORT Logger : public QObject
{
Q_OBJECT
public:
void log(Log log);
static void csyncLog( const QString& message );
@@ -49,7 +50,6 @@ public:
const QList<Log>& logs() const {return _logs;}
static Logger* instance();
static void destroy();
void postGuiLog(const QString& title, const QString& message);
void postOptionalGuiLog(const QString& title, const QString& message);
@@ -69,14 +69,12 @@ signals:
public slots:
void enterNextLogFile();
protected:
private:
Logger(QObject* parent=0);
~Logger();
QList<Log> _logs;
bool _showTime;
bool _doLogging;
static Logger* _instance;
QFile _logFile;
bool _doFileFlush;
int _logExpire;

View File

@@ -14,7 +14,9 @@
#include <QNetworkRequest>
#include <QNetworkProxy>
#include <QAuthenticator>
#include <QSslConfiguration>
#include "mirall/cookiejar.h"
#include "mirall/mirallaccessmanager.h"
#include "mirall/utility.h"
@@ -30,6 +32,7 @@ MirallAccessManager::MirallAccessManager(QObject* parent)
proxy.setHostName(" ");
setProxy(proxy);
#endif
setCookieJar(new CookieJar);
QObject::connect(this, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
this, SLOT(slotProxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
}

View File

@@ -47,6 +47,7 @@ static const char monoIconsC[] = "monoIcons";
static const char optionalDesktopNoficationsC[] = "optionalDesktopNotifications";
static const char skipUpdateCheckC[] = "skipUpdateCheck";
static const char geometryC[] = "geometry";
static const char timeoutC[] = "timeout";
static const char proxyHostC[] = "Proxy/host";
static const char proxyTypeC[] = "Proxy/type";
@@ -103,6 +104,12 @@ bool MirallConfigFile::optionalDesktopNotifications() const
return settings.value(QLatin1String(optionalDesktopNoficationsC), true).toBool();
}
int MirallConfigFile::timeout() const
{
QSettings settings(configFile(), QSettings::IniFormat);
return settings.value(QLatin1String(timeoutC), 300).toInt(); // default to 5 min
}
void MirallConfigFile::setOptionalDesktopNotifications(bool show)
{
QSettings settings(configFile(), QSettings::IniFormat);

View File

@@ -97,6 +97,8 @@ public:
bool optionalDesktopNotifications() const;
void setOptionalDesktopNotifications(bool show);
int timeout() const;
void saveGeometry(QWidget *w);
void restoreGeometry(QWidget *w);

View File

@@ -63,8 +63,6 @@ public:
void setReply(QNetworkReply *reply);
QNetworkReply* reply() const { return _reply; }
void setTimeout(qint64 msec);
void resetTimeout();
void setIgnoreCredentialFailure(bool ignore);
bool ignoreCredentialFailure() const { return _ignoreCredentialFailure; }
@@ -72,6 +70,9 @@ public:
QString responseTimestamp();
quint64 duration();
public slots:
void setTimeout(qint64 msec);
void resetTimeout();
signals:
void networkError(QNetworkReply *reply);
protected:
@@ -100,7 +101,7 @@ private slots:
private:
QNetworkReply* addTimer(QNetworkReply *reply);
bool _ignoreCredentialFailure;
QNetworkReply *_reply;
QPointer<QNetworkReply> _reply; // (QPointer because the NetworkManager may be destroyed before the jobs at exit)
Account *_account;
QString _path;
QTimer _timer;

View File

@@ -326,10 +326,9 @@ void ownCloudGui::slotShowOptionalTrayMessage(const QString &title, const QStrin
void ownCloudGui::slotFolderOpenAction( const QString& alias )
{
Folder *f = FolderMan::instance()->folder(alias);
qDebug() << "opening local url " << f->path();
if( f ) {
QUrl url(f->path(), QUrl::TolerantMode);
url.setScheme( QLatin1String("file") );
qDebug() << "opening local url " << f->path();
QUrl url = QUrl::fromLocalFile(f->path());
#ifdef Q_OS_WIN
// work around a bug in QDesktopServices on Win32, see i-net

View File

@@ -19,9 +19,16 @@
#include "propagator_qnam.h"
#include "propagatorjobs.h"
#include "propagator_legacy.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/utility.h"
#ifdef Q_OS_WIN
#include <windef.h>
#include <winbase.h>
#endif
#include <QStack>
#include <QFileInfo>
namespace Mirall {
@@ -45,11 +52,6 @@ void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorStr
if( _item._httpErrorCode == 403 ||_item._httpErrorCode == 413 || _item._httpErrorCode == 415 ) {
qDebug() << "Fatal Error condition" << _item._httpErrorCode << ", forbid retry!";
retries = -1;
#ifdef OWNCLOUD_5XX_NO_BLACKLIST
} else if (_item._httpErrorCode / 100 == 5) {
// In this configuration, never blacklist error 5xx
qDebug() << "Do not blacklist error " << _item._httpErrorCode;
#endif
} else {
static QAtomicInt defaultRetriesCount(qgetenv("OWNCLOUD_BLACKLIST_COUNT").toInt());
if (defaultRetriesCount.fetchAndAddAcquire(0) <= 0) {
@@ -61,10 +63,17 @@ void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorStr
switch( status ) {
case SyncFileItem::SoftError:
// do not blacklist in case of soft error.
break;
case SyncFileItem::FatalError:
// do not blacklist in case of soft error or fatal error.
break;
case SyncFileItem::NormalError:
#ifdef OWNCLOUD_5XX_NO_BLACKLIST
if (_item._httpErrorCode / 100 == 5) {
// In this configuration, never blacklist error 5xx
qDebug() << "Do not blacklist error " << _item._httpErrorCode;
break;
}
#endif
_propagator->_journal->updateBlacklistEntry( record );
break;
case SyncFileItem::Success:
@@ -151,6 +160,8 @@ void PropagateItemJob::slotRestoreJobCompleted(const SyncFileItem& item )
}
}
// ================================================================================
PropagateItemJob* OwncloudPropagator::createJob(const SyncFileItem& item) {
switch(item._instruction) {
case CSYNC_INSTRUCTION_REMOVE:
@@ -208,10 +219,23 @@ void OwncloudPropagator::start(const SyncFileItemVector& _syncedItems)
QVector<PropagatorJob*> directoriesToRemove;
QString removedDirectory;
foreach(const SyncFileItem &item, items) {
if (item._instruction == CSYNC_INSTRUCTION_REMOVE
&& !removedDirectory.isEmpty() && item._file.startsWith(removedDirectory)) {
//already taken care of. (by the removal of the parent directory)
continue;
if (!removedDirectory.isEmpty() && item._file.startsWith(removedDirectory)) {
// this is an item in a directory which is going to be removed.
if (item._instruction == CSYNC_INSTRUCTION_REMOVE) {
//already taken care of. (by the removal of the parent directory)
continue;
} else if (item._instruction == CSYNC_INSTRUCTION_NEW && item._isDirectory) {
// create a new directory within a deleted directory? That can happen if the directory
// etag were not fetched properly on the previous sync because the sync was aborted
// while uploading this directory (which is now removed). We can ignore it.
continue;
} else if (item._instruction == CSYNC_INSTRUCTION_IGNORE) {
continue;
}
qWarning() << "WARNING: Job within a removed directory? This should not happen!"
<< item._file << item._instruction;
}
while (!item.destination().startsWith(directories.top().first)) {
@@ -222,11 +246,21 @@ void OwncloudPropagator::start(const SyncFileItemVector& _syncedItems)
PropagateDirectory *dir = new PropagateDirectory(this, item);
dir->_firstJob.reset(createJob(item));
if (item._instruction == CSYNC_INSTRUCTION_REMOVE) {
//We do the removal of directories at the end
//We do the removal of directories at the end, because there might be moves from
// this directories that will happen later.
directoriesToRemove.append(dir);
removedDirectory = item._file + "/";
// We should not update the etag of parent directories of the removed directory
// since it would be done before the actual remove (issue #1845)
// NOTE: Currently this means that we don't update those etag at all in this sync,
// but it should not be a problem, they will be updated in the next sync.
for (int i = 0; i < directories.size(); ++i) {
directories[i].second->_item._should_update_etag = false;
}
} else {
directories.top().second->append(dir);
PropagateDirectory* currentDirJob = directories.top().second;
currentDirJob->append(dir);
}
directories.push(qMakePair(item.destination() + "/" , dir));
} else if (PropagateItemJob* current = createJob(item)) {
@@ -240,7 +274,7 @@ void OwncloudPropagator::start(const SyncFileItemVector& _syncedItems)
connect(_rootJob.data(), SIGNAL(completed(SyncFileItem)), this, SIGNAL(completed(SyncFileItem)));
connect(_rootJob.data(), SIGNAL(progress(SyncFileItem,quint64)), this, SIGNAL(progress(SyncFileItem,quint64)));
connect(_rootJob.data(), SIGNAL(finished(SyncFileItem::Status)), this, SIGNAL(finished()));
connect(_rootJob.data(), SIGNAL(finished(SyncFileItem::Status)), this, SLOT(emitFinished()));
qDebug() << (useLegacyJobs() ? "Using legacy libneon/HTTP sequential code path" : "Using QNAM/HTTP parallel code path");
@@ -279,6 +313,58 @@ bool OwncloudPropagator::useLegacyJobs()
return env=="true" || env =="1";
}
int OwncloudPropagator::httpTimeout()
{
static int timeout;
if (!timeout) {
timeout = qgetenv("OWNCLOUD_TIMEOUT").toUInt();
if (timeout == 0) {
MirallConfigFile cfg;
timeout = cfg.timeout();
}
}
return timeout;
}
bool OwncloudPropagator::localFileNameClash( const QString& relFile )
{
bool re = false;
const QString file( _localDir + relFile );
if( !file.isEmpty() && Utility::fsCasePreserving() ) {
#ifdef Q_OS_MAC
QFileInfo fileInfo(file);
if (!fileInfo.exists()) {
re = false;
} else {
re = ( ! fileInfo.canonicalFilePath().endsWith(relFile, Qt::CaseSensitive) );
}
#elif defined(Q_OS_WIN)
const QString file( _localDir + relFile );
qDebug() << "CaseClashCheck for " << file;
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
hFind = FindFirstFileW( (wchar_t*)file.utf16(), &FindFileData);
if (hFind == INVALID_HANDLE_VALUE) {
//qDebug() << "FindFirstFile failed " << GetLastError();
// returns false.
} else {
QString realFileName = QString::fromWCharArray( FindFileData.cFileName );
qDebug() << Q_FUNC_INFO << "Real file name is " << realFileName;
FindClose(hFind);
if( ! file.endsWith(realFileName, Qt::CaseSensitive) ) {
re = true;
}
}
#endif
}
return re;
}
// ================================================================================
void PropagateDirectory::start()
{
@@ -337,5 +423,4 @@ void PropagateDirectory::slotSubJobReady()
}
}
}

View File

@@ -187,6 +187,7 @@ public:
const QString _remoteFolder; // folder. (same as remoteDir but without remote.php/webdav)
SyncJournalDb * const _journal;
bool _finishedEmited; // used to ensure that finished is only emit once
public:
OwncloudPropagator(ne_session_s *session, const QString &localDir, const QString &remoteDir, const QString &remoteFolder,
@@ -197,6 +198,7 @@ public:
, _remoteDir((remoteDir.endsWith(QChar('/'))) ? remoteDir : remoteDir+'/' )
, _remoteFolder((remoteFolder.endsWith(QChar('/'))) ? remoteFolder : remoteFolder+'/' )
, _journal(progressDb)
, _finishedEmited(false)
, _activeJobs(0)
{ }
@@ -210,17 +212,28 @@ public:
/* The number of currently active jobs */
int _activeJobs;
bool isInSharedDirectory(const QString& file);
bool localFileNameClash(const QString& relfile);
void abort() {
_abortRequested.fetchAndStoreOrdered(true);
if (_rootJob)
if (_rootJob) {
_rootJob->abort();
emit finished();
}
emitFinished();
}
// timeout in seconds
static int httpTimeout();
private slots:
/** Emit the finished signal and make sure it is only emit once */
void emitFinished() {
if (!_finishedEmited)
emit finished();
_finishedEmited = true;
}
signals:
void completed(const SyncFileItem &);

View File

@@ -187,7 +187,8 @@ void OwncloudSetupWizard::slotNoOwnCloudFoundAuthTimeout(const QUrl&url)
void OwncloudSetupWizard::slotConnectToOCUrl( const QString& url )
{
qDebug() << "Connect to url: " << url;
_ocWizard->account()->setCredentials(_ocWizard->getCredentials());
AbstractCredentials *creds = _ocWizard->getCredentials();
_ocWizard->account()->setCredentials(creds);
_ocWizard->setField(QLatin1String("OCUrl"), url );
_ocWizard->appendToConfigurationLog(tr("Trying to connect to %1 at %2...")
.arg( Theme::instance()->appNameGUI() ).arg(url) );
@@ -197,7 +198,9 @@ void OwncloudSetupWizard::slotConnectToOCUrl( const QString& url )
void OwncloudSetupWizard::testOwnCloudConnect()
{
ValidateDavAuthJob *job = new ValidateDavAuthJob(_ocWizard->account(), this);
Account *account = _ocWizard->account();
ValidateDavAuthJob *job = new ValidateDavAuthJob(account, this);
job->setIgnoreCredentialFailure(true);
connect(job, SIGNAL(authResult(QNetworkReply*)), SLOT(slotConnectionCheck(QNetworkReply*)));
job->start();
@@ -483,7 +486,8 @@ ValidateDavAuthJob::ValidateDavAuthJob(Account *account, QObject *parent)
void ValidateDavAuthJob::start()
{
QNetworkReply *reply = getRequest(account()->davPath());
QString p = account()->davPath();
QNetworkReply *reply = getRequest(p);
setReply(reply);
setupConnections(reply);
AbstractNetworkJob::start();

View File

@@ -31,7 +31,8 @@
namespace Mirall {
ownCloudTheme::ownCloudTheme()
ownCloudTheme::ownCloudTheme() :
Theme()
{
// qDebug() << " ** running ownCloud theme!";
}

View File

@@ -108,7 +108,9 @@ ProgressDispatcher::~ProgressDispatcher()
void ProgressDispatcher::setProgressInfo(const QString& folder, const Progress::Info& progress)
{
if( folder.isEmpty() ) {
if( folder.isEmpty() ||
(progress._currentItems.size() == 0
&& progress._totalFileCount == 0) ) {
return;
}
emit progressInfo( folder, progress );

View File

@@ -54,10 +54,12 @@ namespace Progress
void setProgressComplete(const SyncFileItem &item) {
_currentItems.remove(item._file);
if (Progress::isSizeDependent(item._instruction)) {
_completedSize += item._size;
if (!item._isDirectory) {
_completedFileCount++;
if (Progress::isSizeDependent(item._instruction)) {
_completedSize += item._size;
}
}
_completedFileCount++;
_lastCompletedItem = item;
}
void setProgressItem(const SyncFileItem &item, quint64 size) {
@@ -69,7 +71,8 @@ namespace Progress
quint64 completedSize() const {
quint64 r = _completedSize;
foreach(const ProgressItem &i, _currentItems) {
r += i._completedSize;
if (!i._item._isDirectory)
r += i._completedSize;
}
return r;
}

View File

@@ -305,6 +305,11 @@ bool PropagateNeonJob::updateMTimeAndETag(const char* uri, time_t mtime)
void PropagateNeonJob::limitBandwidth(qint64 progress, qint64 bandwidth_limit)
{
if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) {
// Do not limit bandwidth when aborting to speed up the current transfer
return;
}
if (bandwidth_limit > 0) {
int64_t diff = _lastTime.nsecsElapsed() / 1000;
int64_t len = progress - _lastProgress;
@@ -444,6 +449,13 @@ void PropagateDownloadFileLegacy::start()
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
return;
// do a case clash check.
if( _propagator->localFileNameClash(_item._file) ) {
done( SyncFileItem::NormalError, tr("File %1 can not be downloaded because of a local file name clash!")
.arg(QDir::toNativeSeparators(_item._file)) );
return;
}
emit progress(_item, 0);
QString tmpFileName;

View File

@@ -23,7 +23,8 @@ class PropagateUploadFileLegacy: public PropagateNeonJob {
Q_OBJECT
public:
explicit PropagateUploadFileLegacy(OwncloudPropagator* propagator,const SyncFileItem& item)
: PropagateNeonJob(propagator, item), _previousFileSize(0) {}
: PropagateNeonJob(propagator, item)
, _chunked_done(0), _chunked_total_size(0), _previousFileSize(0) {}
void start();
private:
// Log callback for httpbf

View File

@@ -22,10 +22,22 @@
#include "propagatorjobs.h"
#include <QNetworkAccessManager>
#include <QFileInfo>
#include <QDir>
#include <cmath>
namespace Mirall {
static uint chunkSize() {
static uint chunkSize;
if (!chunkSize) {
chunkSize = qgetenv("OWNCLOUD_CHUNK_SIZE").toUInt();
if (chunkSize == 0) {
chunkSize = 10*1024*1024; // default to 10 MiB
}
}
return chunkSize;
}
/**
* Fiven an error from the network, map to a SyncFileItem::Status error
*/
@@ -61,19 +73,14 @@ void PUTFileJob::start() {
}
connect(reply(), SIGNAL(uploadProgress(qint64,qint64)), this, SIGNAL(uploadProgress(qint64,qint64)));
connect(reply(), SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(resetTimeout()));
AbstractNetworkJob::start();
}
static uint chunkSize() {
static uint chunkSize;
if (!chunkSize) {
chunkSize = qgetenv("OWNCLOUD_CHUNK_SIZE").toUInt();
if (chunkSize == 0) {
chunkSize = 10*1024*1024; // default to 10 MiB
}
}
return chunkSize;
void PUTFileJob::slotTimeout() {
_errorString = tr("Connection Timeout");
reply()->abort();
}
void PropagateUploadFileQNAM::start()
@@ -111,7 +118,6 @@ void PropagateUploadFileQNAM::start()
}
struct ChunkDevice : QIODevice {
Q_OBJECT
public:
QIODevice *_file;
qint64 _read;
@@ -162,7 +168,6 @@ public:
return _file->seek(pos + _start);
}
};
#include "propagator_qnam.moc"
void PropagateUploadFileQNAM::startNextChunk()
{
@@ -195,7 +200,7 @@ void PropagateUploadFileQNAM::startNextChunk()
}
QString path = _item._file;
QIODevice *device;
QIODevice *device = 0;
if (_chunkCount > 1) {
int sendingChunk = (_currentChunk + _startChunk) % _chunkCount;
// XOR with chunk size to make sure everything goes well if chunk size change between runs
@@ -213,13 +218,24 @@ void PropagateUploadFileQNAM::startNextChunk()
} else {
device = _file;
}
if (!device->isOpen())
device->open(QIODevice::ReadOnly);
_job = new PUTFileJob(AccountManager::instance()->account(), _propagator->_remoteFolder + path, device, headers);
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
connect(_job, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(slotUploadProgress(qint64,qint64)));
_job->start();
bool isOpen = true;
if (!device->isOpen()) {
isOpen = device->open(QIODevice::ReadOnly);
}
if( isOpen ) {
_job = new PUTFileJob(AccountManager::instance()->account(), _propagator->_remoteFolder + path, device, headers);
_job->setTimeout(_propagator->httpTimeout() * 1000);
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
connect(_job, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(slotUploadProgress(qint64,qint64)));
_job->start();
} else {
qDebug() << "ERR: Could not open upload file: " << device->errorString();
done( SyncFileItem::NormalError, device->errorString() );
delete device;
return;
}
}
void PropagateUploadFileQNAM::slotPutFinished()
@@ -242,7 +258,7 @@ void PropagateUploadFileQNAM::slotPutFinished()
"It is restored and your edit is in the conflict file."))) {
return;
}
QString errorString = job->reply()->errorString();
QString errorString = job->errorString();
QByteArray replyContent = job->reply()->readAll();
qDebug() << replyContent; // display the XML error in the debug
@@ -251,6 +267,12 @@ void PropagateUploadFileQNAM::slotPutFinished()
errorString += QLatin1String(" (") + rx.cap(1) + QLatin1Char(')');
}
if (_item._httpErrorCode == 412) {
// Precondition Failed: Maybe the bad etag is in the database, we need to clear the
// parent folder etag so we won't read from DB next sync.
_propagator->_journal->avoidReadFromDbOnNextSync(_item._file);
}
done(classifyError(err, _item._httpErrorCode), errorString);
return;
}
@@ -258,9 +280,14 @@ void PropagateUploadFileQNAM::slotPutFinished()
bool finished = job->reply()->hasRawHeader("ETag");
if (!finished) {
QFileInfo fi(_propagator->_localDir + _item._file);
if( !fi.exists() ) {
_propagator->_activeJobs--;
done(SyncFileItem::SoftError, tr("The local file was removed during sync."));
return;
}
if (Utility::qDateTimeToTime_t(QFileInfo(_propagator->_localDir + _item._file).lastModified())
!= _item._modtime) {
if (Utility::qDateTimeToTime_t(fi.lastModified()) != _item._modtime) {
/* Uh oh: The local file has changed during upload */
_propagator->_activeJobs--;
done(SyncFileItem::SoftError, tr("Local file changed during sync."));
@@ -273,7 +300,7 @@ void PropagateUploadFileQNAM::slotPutFinished()
_currentChunk++;
if (_currentChunk >= _chunkCount) {
_propagator->_activeJobs--;
done(SyncFileItem::NormalError, tr("The server did not aknoledge the last chunk. (No e-tag were present)"));
done(SyncFileItem::NormalError, tr("The server did not acknowledge the last chunk. (No e-tag were present)"));
return;
}
@@ -288,6 +315,8 @@ void PropagateUploadFileQNAM::slotPutFinished()
return;
}
// the following code only happens after all chunks were uploaded.
//
// the file id should only be empty for new files up- or downloaded
QByteArray fid = job->reply()->rawHeader("OC-FileID");
if( !fid.isEmpty() ) {
@@ -372,8 +401,8 @@ void GETFileJob::start() {
void GETFileJob::slotMetaDataChanged()
{
qDebug() << Q_FUNC_INFO << reply()->error() << reply()->errorString() << reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (reply()->error() != QNetworkReply::NoError ) {
if (reply()->error() != QNetworkReply::NoError
|| reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() / 100 != 2) {
// We will handle the error when the job is finished.
return;
}
@@ -420,10 +449,9 @@ void GETFileJob::slotReadyRead()
return;
}
}
resetTimeout();
}
void PropagateDownloadFileQNAM::start()
{
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
@@ -431,6 +459,13 @@ void PropagateDownloadFileQNAM::start()
qDebug() << Q_FUNC_INFO << _item._file << _propagator->_activeJobs;
// do a case clash check.
if( _propagator->localFileNameClash(_item._file) ) {
done( SyncFileItem::NormalError, tr("File %1 can not be downloaded because of a local file name clash!")
.arg(QDir::toNativeSeparators(_item._file)) );
return;
}
emit progress(_item, 0);
QString tmpFileName;
@@ -495,6 +530,7 @@ void PropagateDownloadFileQNAM::start()
_job = new GETFileJob(AccountManager::instance()->account(),
_propagator->_remoteFolder + _item._file,
&_tmpFile, headers, expectedEtagForResume);
_job->setTimeout(_propagator->httpTimeout() * 1000);
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
connect(_job, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slotDownloadProgress(qint64,qint64)));
_propagator->_activeJobs ++;
@@ -509,7 +545,9 @@ void PropagateDownloadFileQNAM::slotGetFinished()
GETFileJob *job = qobject_cast<GETFileJob *>(sender());
Q_ASSERT(job);
qDebug() << Q_FUNC_INFO << job->reply()->request().url() << "FINISHED WITH STATUS" << job->reply()->error() << job->reply()->errorString();
qDebug() << Q_FUNC_INFO << job->reply()->request().url() << "FINISHED WITH STATUS"
<< job->reply()->error()
<< (job->reply()->error() == QNetworkReply::NoError ? QLatin1String("") : job->reply()->errorString());
QNetworkReply::NetworkError err = job->reply()->error();
if (err != QNetworkReply::NoError) {
@@ -611,5 +649,13 @@ void PropagateDownloadFileQNAM::abort()
_job->reply()->abort();
}
void GETFileJob::slotTimeout()
{
_errorString = tr("Connection Timeout");
_errorStatus = SyncFileItem::FatalError;
reply()->abort();
}
}

View File

@@ -53,6 +53,7 @@ class PUTFileJob : public AbstractNetworkJob {
Q_OBJECT
QIODevice* _device;
QMap<QByteArray, QByteArray> _headers;
QString _errorString;
public:
// Takes ownership of the device
@@ -67,6 +68,13 @@ public:
return true;
}
QString errorString() {
return _errorString.isEmpty() ? reply()->errorString() : _errorString;
};
virtual void slotTimeout();
signals:
void finishedSignal();
void uploadProgress(qint64,qint64);
@@ -124,6 +132,9 @@ public:
SyncFileItem::Status errorStatus() { return _errorStatus; }
virtual void slotTimeout();
signals:
void finishedSignal();
void downloadProgress(qint64,qint64);

View File

@@ -44,11 +44,6 @@
#include <neon/ne_compress.h>
#include <neon/ne_redirect.h>
#ifdef Q_OS_WIN
#include <windef.h>
#include <winbase.h>
#endif
#include <time.h>
@@ -81,9 +76,16 @@ void PropagateLocalRemove::start()
return;
QString filename = _propagator->_localDir + _item._file;
if( _propagator->localFileNameClash(_item._file)) {
done(SyncFileItem::NormalError, tr("Could not remove %1 because of a local file name clash")
.arg(QDir::toNativeSeparators(filename)));
return;
}
if (_item._isDirectory) {
if (QDir(filename).exists() && !removeRecursively(filename)) {
done(SyncFileItem::NormalError, tr("Could not remove directory %1").arg(filename));
done(SyncFileItem::NormalError, tr("Could not remove directory %1")
.arg(QDir::toNativeSeparators(filename)));
return;
}
} else {
@@ -104,9 +106,17 @@ void PropagateLocalMkdir::start()
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
return;
QDir d;
if (!d.mkpath(_propagator->_localDir + _item._file)) {
done(SyncFileItem::NormalError, tr("could not create directory %1").arg(_propagator->_localDir + _item._file));
QDir newDir(_propagator->_localDir + _item._file);
QString newDirStr = QDir::toNativeSeparators(newDir.path());
if( Utility::fsCasePreserving() && newDir.exists() &&
_propagator->localFileNameClash(_item._file ) ) {
qDebug() << "WARN: new directory to create locally already exists!";
done( SyncFileItem::NormalError, tr("Attention, possible case sensitivity clash with %1").arg(newDirStr) );
return;
}
QDir localDir(_propagator->_localDir);
if (!localDir.mkpath(_item._file)) {
done( SyncFileItem::NormalError, tr("could not create directory %1").arg(newDirStr) );
return;
}
done(SyncFileItem::Success);
@@ -178,7 +188,19 @@ void PropagateLocalRename::start()
if (_item._file != _item._renameTarget) {
emit progress(_item, 0);
qDebug() << "MOVE " << _propagator->_localDir + _item._file << " => " << _propagator->_localDir + _item._renameTarget;
QFile::rename(_propagator->_localDir + _item._file, _propagator->_localDir + _item._renameTarget);
QFile file(_propagator->_localDir + _item._file);
if (_propagator->localFileNameClash(_item._renameTarget)) {
// Fixme: the file that is the reason for the clash could be named here,
// it would have to come out the localFileNameClash function
done(SyncFileItem::NormalError, tr( "File %1 can not be renamed to %2 because of a local file name clash")
.arg(QDir::toNativeSeparators(_item._file)).arg(QDir::toNativeSeparators(_item._renameTarget)) );
return;
}
if (!file.rename(_propagator->_localDir + _item._file, _propagator->_localDir + _item._renameTarget)) {
done(SyncFileItem::NormalError, file.errorString());
return;
}
}
_propagator->_journal->deleteFileRecord(_item._originalFile);

View File

@@ -81,6 +81,7 @@ class PropagateLocalMkdir : public PropagateItemJob {
public:
PropagateLocalMkdir (OwncloudPropagator* propagator,const SyncFileItem& item) : PropagateItemJob(propagator, item) {}
void start();
};
class PropagateRemoteRemove : public PropagateNeonJob {
Q_OBJECT

View File

@@ -23,7 +23,17 @@ namespace Mirall {
SettingsDialogMac::SettingsDialogMac(ownCloudGui *gui, QWidget *parent)
: MacPreferencesWindow(parent)
{
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
// do not show minimize button. There is no use, and retoring the
// dialog from minimize is broken in MacPreferencesWindow
setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint |
Qt::WindowCloseButtonHint | Qt::WindowMaximizeButtonHint);
// Emulate dialog behavior: Escape means close
QAction *closeWindowAction = new QAction(this);
closeWindowAction->setShortcut(QKeySequence(Qt::Key_Escape));
connect(closeWindowAction, SIGNAL(triggered()), SLOT(close()));
addAction(closeWindowAction);
setObjectName("SettingsMac"); // required as group for saveGeometry call
@@ -51,8 +61,6 @@ SettingsDialogMac::SettingsDialogMac(ownCloudGui *gui, QWidget *parent)
connect( ProgressDispatcher::instance(), SIGNAL(progressInfo(QString, Progress::Info)),
_accountSettings, SLOT(slotSetProgress(QString, Progress::Info)) );
connect( ProgressDispatcher::instance(), SIGNAL(progressSyncProblem(QString,Progress::SyncProblem)),
_accountSettings, SLOT(slotProgressProblem(QString,Progress::SyncProblem)) );
QAction *showLogWindow = new QAction(this);
showLogWindow->setShortcut(QKeySequence("F12"));

View File

@@ -83,7 +83,7 @@ QMenu* SslButton::buildCertMenu(QMenu *parent, const QSslCertificate& cert,
QLatin1String("<br/>") +
Utility::escape(Utility::formatFingerprint(sha265hash.mid(sha265hash.length()/2), false));
#endif
QString serial = QString::fromUtf8(cert.serialNumber(), true);
QString serial = QString::fromUtf8(cert.serialNumber());
QString effectiveDate = cert.effectiveDate().date().toString();
QString expiryDate = cert.expiryDate().date().toString();
QString sna = QStringList(cert.alternateSubjectNames().values()).join(" ");

View File

@@ -52,20 +52,25 @@ void csyncLogCatcher(int /*verbosity*/,
Logger::instance()->csyncLog( QString::fromUtf8(buffer) );
}
/* static variables to hold the credentials */
QMutex SyncEngine::_syncMutex;
bool SyncEngine::_syncRunning = false;
SyncEngine::SyncEngine(CSYNC *ctx, const QString& localPath, const QString& remoteURL, const QString& remotePath, Mirall::SyncJournalDb* journal)
: _csync_ctx(ctx)
, _needsUpdate(false)
, _localPath(localPath)
, _remoteUrl(remoteURL)
, _remotePath(remotePath)
, _journal(journal)
, _hasFiles(false)
, _downloadLimit(0)
, _uploadLimit(0)
{
_localPath = localPath;
_remotePath = remotePath;
_remoteUrl = remoteURL;
_csync_ctx = ctx;
_journal = journal;
qRegisterMetaType<SyncFileItem>("SyncFileItem");
qRegisterMetaType<SyncFileItem::Status>("SyncFileItem::Status");
qRegisterMetaType<Progress::Info>("Progress::Info");
_thread.setObjectName("CSync_Neon_Thread");
_thread.start();
}
@@ -265,7 +270,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
item._fileId = file->file_id;
// record the seen files to be able to clean the journal later
_seenFiles[item._file] = QString();
_seenFiles.insert(item._file);
switch(file->error_status) {
case CSYNC_STATUS_OK:
@@ -292,6 +297,8 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
item._modtime = file->modtime;
item._etag = file->etag;
item._size = file->size;
item._inode = file->inode;
item._should_update_etag = file->should_update_etag;
switch( file->type ) {
case CSYNC_FTW_TYPE_DIR:
@@ -412,18 +419,13 @@ void SyncEngine::handleSyncError(CSYNC *ctx, const char *state) {
} else {
emit csyncError(errStr);
}
csync_commit(_csync_ctx);
emit finished();
_syncMutex.unlock();
_thread.quit();
finalize();
}
void SyncEngine::startSync()
{
if (!_syncMutex.tryLock()) {
qDebug() << Q_FUNC_INFO << "WARNING: Another sync seems to be running. Not starting a new one.";
return;
}
Q_ASSERT(!_syncRunning);
_syncRunning = true;
if( ! _csync_ctx ) {
qDebug() << "XXXXXXXXXXXXXXXX FAIL: do not have csync_ctx!";
@@ -449,12 +451,7 @@ void SyncEngine::startSync()
if( fileRecordCount == -1 ) {
qDebug() << "No way to create a sync journal!";
emit csyncError(tr("Unable to initialize a sync journal."));
csync_commit(_csync_ctx);
emit finished();
_syncMutex.unlock();
_thread.quit();
finalize();
return;
// database creation error!
} else if ( fileRecordCount < 50 ) {
@@ -499,6 +496,9 @@ void SyncEngine::startSync()
// csync_set_auth_callback( _csync_ctx, getauth );
csync_set_log_callback( csyncLogCatcher );
//csync_set_log_level( 11 ); don't set the loglevel here, it shall be done by folder.cpp or owncloudcmd.cpp
int timeout = OwncloudPropagator::httpTimeout();
csync_set_module_property(_csync_ctx, "timeout", &timeout);
_stopWatch.start();
@@ -548,9 +548,7 @@ void SyncEngine::slotUpdateFinished(int updateResult)
if (!_journal->isConnected()) {
qDebug() << "Bailing out, DB failure";
emit csyncError(tr("Cannot open the sync journal"));
emit finished();
_syncMutex.unlock();
_thread.quit();
finalize();
return;
}
@@ -564,9 +562,7 @@ void SyncEngine::slotUpdateFinished(int updateResult)
emit aboutToRemoveAllFiles(_syncedItems.first()._direction, &cancel);
if (cancel) {
qDebug() << Q_FUNC_INFO << "Abort sync";
emit finished();
_syncMutex.unlock();
_thread.quit();
finalize();
return;
}
}
@@ -586,7 +582,7 @@ void SyncEngine::slotUpdateFinished(int updateResult)
connect(_propagator.data(), SIGNAL(progress(SyncFileItem,quint64)),
this, SLOT(slotProgress(SyncFileItem,quint64)));
connect(_propagator.data(), SIGNAL(adjustTotalTransmissionSize(qint64)), this, SLOT(slotAdjustTotalTransmissionSize(qint64)));
connect(_propagator.data(), SIGNAL(finished()), this, SLOT(slotFinished()));
connect(_propagator.data(), SIGNAL(finished()), this, SLOT(slotFinished()), Qt::QueuedConnection);
setNetworkLimits();
@@ -664,18 +660,24 @@ void SyncEngine::slotFinished()
if( ! _journal->postSyncCleanup( _seenFiles ) ) {
qDebug() << "Cleaning of synced ";
}
_journal->commit("All Finished.", false);
emit treeWalkResult(_syncedItems);
finalize();
}
void SyncEngine::finalize()
{
_thread.quit();
_thread.wait();
csync_commit(_csync_ctx);
qDebug() << "CSync run took " << _stopWatch.addLapTime(QLatin1String("Sync Finished"));
_stopWatch.stop();
emit finished();
_propagator.reset(0);
_syncMutex.unlock();
_thread.quit();
_syncRunning = false;
emit finished();
}
void SyncEngine::slotProgress(const SyncFileItem& item, quint64 current)

View File

@@ -21,6 +21,7 @@
#include <QMutex>
#include <QThread>
#include <QString>
#include <QSet>
#include <qelapsedtimer.h>
#include <csync.h>
@@ -101,7 +102,10 @@ private:
int treewalkFile( TREE_WALK_FILE*, bool );
bool checkBlacklisting( SyncFileItem *item );
static QMutex _syncMutex;
// cleanup and emit the finished signal
void finalize();
static bool _syncRunning; //true when one sync is running somewhere (for debugging)
SyncFileItemVector _syncedItems;
CSYNC *_csync_ctx;
@@ -112,7 +116,7 @@ private:
SyncJournalDb *_journal;
QScopedPointer <OwncloudPropagator> _propagator;
QString _lastDeleted; // if the last item was a path and it has been deleted
QHash <QString, QString> _seenFiles;
QSet<QString> _seenFiles;
QThread _thread;
Progress::Info _progressInfo;

View File

@@ -49,8 +49,9 @@ public:
FileIgnored ///< The file is in the ignored list
};
SyncFileItem() : _type(UnknownType), _direction(None), _instruction(CSYNC_INSTRUCTION_NONE),
_should_update_etag(false), _blacklistedInDb(false),
SyncFileItem() : _type(UnknownType), _direction(None), _isDirectory(false),
_instruction(CSYNC_INSTRUCTION_NONE), _modtime(0),
_size(0), _inode(0), _should_update_etag(false), _blacklistedInDb(false),
_status(NoStatus), _httpErrorCode(0), _requestDuration(0) {}
friend bool operator==(const SyncFileItem& item1, const SyncFileItem& item2) {
@@ -83,6 +84,7 @@ public:
time_t _modtime;
QByteArray _etag;
quint64 _size;
quint64 _inode;
bool _should_update_etag;
QByteArray _fileId;
bool _blacklistedInDb;

View File

@@ -491,7 +491,7 @@ SyncJournalFileRecord SyncJournalDb::getFileRecord( const QString& filename )
return rec;
}
bool SyncJournalDb::postSyncCleanup(const QHash<QString, QString> &items )
bool SyncJournalDb::postSyncCleanup(const QSet<QString> &items )
{
QMutexLocker locker(&_mutex);
@@ -770,7 +770,15 @@ void SyncJournalDb::updateBlacklistEntry( const SyncJournalBlacklistRecord& item
return;
}
query.prepare("SELECT retrycount FROM blacklist WHERE path=:path");
QString sql("SELECT retrycount FROM blacklist WHERE path=:path");
if( Utility::fsCasePreserving() ) {
// if the file system is case preserving we have to check the blacklist
// case insensitively
sql += QLatin1String(" COLLATE NOCASE");
}
query.prepare(sql);
query.bindValue(":path", item._file);
if( !query.exec() ) {
@@ -827,6 +835,28 @@ void SyncJournalDb::avoidRenamesOnNextSync(const QString& path)
}
}
void SyncJournalDb::avoidReadFromDbOnNextSync(const QString& fileName)
{
//Make sure that on the next sync, filName is not read from the DB but use the PROPFIND to
//get the info from the server
// We achieve that by clearing the etag of the parents directory recursively
QMutexLocker locker(&_mutex);
if( !checkConnect() ) {
return;
}
QSqlQuery query(_db);
// This query will match entries for whitch the path is a prefix of fileName
query.prepare("UPDATE metadata SET md5='_invalid_' WHERE ? LIKE(path||'/%') AND type == 2"); // CSYNC_FTW_TYPE_DIR == 2
query.bindValue(0, fileName);
if( !query.exec() ) {
qDebug() << "SQL error in avoidRenamesOnNextSync: "<< query.lastError().text();
} else {
qDebug() << query.executedQuery() << fileName;
}
}
void SyncJournalDb::commit(const QString& context, bool startTrans)
{

View File

@@ -57,7 +57,7 @@ public:
bool _valid;
};
struct UploadInfo {
UploadInfo() : _chunk(0), _transferid(0), _errorCount(0), _valid(false) {}
UploadInfo() : _chunk(0), _transferid(0), _size(0), _errorCount(0), _valid(false) {}
int _chunk;
int _transferid;
quint64 _size; //currently unused
@@ -73,7 +73,13 @@ public:
SyncJournalBlacklistRecord blacklistEntry( const QString& );
void avoidRenamesOnNextSync(const QString &path);
bool postSyncCleanup( const QHash<QString, QString>& items );
/**
* Make sure that on the next sync, filName is not read from the DB but use the PROPFIND to
* get the info from the server
*/
void avoidReadFromDbOnNextSync(const QString& fileName);
bool postSyncCleanup( const QSet<QString>& items );
/* Because sqlite transactions is really slow, we encapsulate everything in big transactions
* Commit will actually commit the transaction and create a new one.

View File

@@ -36,15 +36,20 @@ SyncJournalFileRecord::SyncJournalFileRecord(const SyncFileItem &item, const QSt
_type(item._type), _etag(item._etag), _fileId(item._fileId),
_uid(0), _gid(0), _mode(0)
{
// use the "old" inode coming with the item for the case where the
// filesystem stat fails. That can happen if the the file was removed
// or renamed meanwhile. For the rename case we still need the inode to
// detect the rename tough.
_inode = item._inode;
// Query the inode:
// based on code from csync_vio_local.c (csync_vio_local_stat)
#ifdef Q_OS_WIN
/* Get the Windows file id as an inode replacement. */
/* Query the inode:
based on code from csync_vio_local.c (csync_vio_local_stat)
Get the Windows file id as an inode replacement. */
HANDLE h = CreateFileW( (wchar_t*)localFileName.utf16(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL+FILE_FLAG_BACKUP_SEMANTICS, NULL );
if( h == INVALID_HANDLE_VALUE ) {
_inode = 0;
qWarning() << "Failed to query the 'inode' because CreateFileW failed for file " << localFileName;
} else {
BY_HANDLE_FILE_INFORMATION fileInfo;
@@ -60,7 +65,7 @@ SyncJournalFileRecord::SyncJournalFileRecord(const SyncFileItem &item, const QSt
_inode = FileIndex.QuadPart;
} else {
qWarning() << "Failed to query the 'inode' for file " << localFileName;
_inode = 0;
}
CloseHandle(h);
}
@@ -68,7 +73,6 @@ SyncJournalFileRecord::SyncJournalFileRecord(const SyncFileItem &item, const QSt
struct stat sb;
if( stat(QFile::encodeName(localFileName).constData(), &sb) < 0) {
qWarning() << "Failed to query the 'inode' for file " << localFileName;
_inode = 0;
} else {
_inode = sb.st_ino;
}

View File

@@ -36,6 +36,7 @@ Theme* Theme::_instance = 0;
Theme* Theme::instance() {
if (!_instance) {
_instance = new THEME_CLASS;
// some themes may not call the base ctor
_instance->_mono = false;
}
return _instance;
@@ -151,6 +152,13 @@ QIcon Theme::themeIcon( const QString& name, bool sysTray ) const
}
return icon;
}
Theme::Theme() :
QObject(0)
,_mono(false)
{
}
#endif
// if this option return true, the client only supports one folder to sync.
@@ -212,7 +220,7 @@ QString Theme::about() const
"<p>Distributed by %4 and licensed under the GNU General Public License (GPL) Version 2.0.<br>"
"%5 and the %5 logo are registered trademarks of %4 in the<br>"
"United States, other countries, or both.</p>")
.arg(MIRALL_VERSION_MAJOR).arg("http://" MIRALL_STRINGIFY(APPLICATION_DOMAIN))
.arg(MIRALL_VERSION_STRING).arg("http://" MIRALL_STRINGIFY(APPLICATION_DOMAIN))
.arg(MIRALL_STRINGIFY(APPLICATION_DOMAIN)).arg(APPLICATION_VENDOR).arg(APPLICATION_NAME);
}

View File

@@ -181,7 +181,7 @@ public:
protected:
QIcon themeIcon(const QString& name, bool sysTray = false) const;
Theme() {}
Theme();
signals:
void systrayUseMonoIconsChanged(bool);

View File

@@ -143,7 +143,7 @@ QString Utility::platform()
return QLatin1String("Linux");
#elif defined(__DragonFly__) // Q_OS_FREEBSD also defined
return QLatin1String("DragonFlyBSD");
#elif defined(Q_OS_FREEBSD)
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_FREEBSD_KERNEL)
return QLatin1String("FreeBSD");
#elif defined(Q_OS_NETBSD)
return QLatin1String("NetBSD");
@@ -167,20 +167,9 @@ QByteArray Utility::userAgentString()
void Utility::raiseDialog( QWidget *raiseWidget )
{
#ifndef TOKEN_AUTH_ONLY
// viel hilft viel ;-)
if( raiseWidget ) {
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) && \
(defined(Q_OS_WIN) || defined (Q_OS_MAC))
Qt::WindowFlags eFlags = raiseWidget->windowFlags();
if (!(eFlags & Qt::WindowStaysOnTopHint)) {
eFlags |= Qt::WindowStaysOnTopHint;
raiseWidget->setWindowFlags(eFlags);
raiseWidget->show();
eFlags &= ~Qt::WindowStaysOnTopHint;
raiseWidget->setWindowFlags(eFlags);
}
#endif
raiseWidget->show();
if( raiseWidget && raiseWidget->parentWidget() == 0) {
// Qt has a bug which causes parent-less dialogs to pop-under.
raiseWidget->showNormal();
raiseWidget->raise();
raiseWidget->activateWindow();
}
@@ -199,7 +188,7 @@ void Utility::setLaunchOnStartup(const QString &appName, const QString& guiName,
qint64 Utility::freeDiskSpace(const QString &path, bool *ok)
{
#if defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)
#if defined(Q_OS_MAC) || defined(Q_OS_FREEBSD) || defined(Q_OS_FREEBSD_KERNEL)
struct statvfs stat;
statvfs(path.toUtf8().data(), &stat);
return (qint64) stat.f_bavail * stat.f_frsize;
@@ -348,6 +337,15 @@ static bool checkDolphinCanSelect()
return p.readAll().contains("--select");
}
bool Utility::fsCasePreserving()
{
bool re = false;
if( isWindows() || isMac() ) {
re = true;
}
return re;
}
// inspired by Qt Creator's showInGraphicalShell();
void Utility::showInFileManager(const QString &localPath)
{

Some files were not shown because too many files have changed in this diff Show More