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

Compare commits

...

247 Commits

Author SHA1 Message Date
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
Olivier Goffart
d62deabf9b Fix updating mtime
Fixup commit 9193286fc1
Use the right URL for the PROPPATCH and HEAD, do not let other
jobs start when we wait for the UpdateMTimeAndETagJob
Update the etag and the fileid of the real item.
2014-04-30 10:24:17 +02:00
Jenkins for ownCloud
47c23dae30 [tx-robot] updated from transifex 2014-04-30 01:26:47 -04:00
Markus Goetz
3bf15541c6 Add set_csync_file_locked_or_open_ext
Without using function, there were problems with DLL import/export
2014-04-29 18:37:34 +02:00
Markus Goetz
876de8fd69 Networkjobs: Remove stray include 2014-04-29 17:55:26 +02:00
Olivier Goffart
983f9c5dde The job restore job need to be run with QMetaObject::invoke
Because the job might be in a different thread.
2014-04-29 16:58:24 +02:00
Olivier Goffart
9193286fc1 Support old server which do not have the x-oc-mtime support
Owncloud 4.5
Or owncloud 5 with chunking

Fixes https://github.com/owncloud/core/issues/8392
2014-04-29 16:58:24 +02:00
Olivier Goffart
1b8d11182b Add missing include
This was required so the compiler sees the declaration of
CredentialsFactory::create which should be exported
2014-04-29 16:04:24 +02:00
Olivier Goffart
dcc5c105eb fix forward declaration of CredentialsFactory::create 2014-04-29 15:50:19 +02:00
Klaas Freitag
64b42333b0 Fix typo. 2014-04-29 15:36:13 +02:00
Olivier Goffart
3ee729bc4a Add export macro to all classes that need to be exported 2014-04-29 15:31:14 +02:00
Daniel Molkentin
a268b03990 Try to not have windows stay-on-top 2014-04-29 15:31:03 +02:00
Klaas Freitag
6471a45a8a Added changelog beta1 -> beta2 2014-04-29 14:46:17 +02:00
Klaas Freitag
7c27638f36 Set release suffix to beta2 2014-04-29 14:09:43 +02:00
Olivier Goffart
0bffdfb256 Fix compiler warnings, and be less spammy in the log 2014-04-29 12:30:13 +02:00
Olivier Goffart
9f0848ba15 Merge remote-tracking branch 'origin/libowncloudsync_noqtgui' 2014-04-29 12:23:15 +02:00
Olivier Goffart
f159b028b4 Add a compile option to not blacklist error code 5xx 2014-04-29 11:39:46 +02:00
Olivier Goffart
7e702778a1 Add missing line break 2014-04-29 11:27:31 +02:00
Markus Goetz
4489a56c65 Csync: Set error at correct place 2014-04-28 17:25:18 +02:00
Markus Goetz
7f752c7e93 Csync: Plug code for csync_file_locked_or_open 2014-04-28 16:57:56 +02:00
Markus Goetz
b39359c929 Csync: Add hook for checking if a file is in use already 2014-04-28 14:18:58 +02:00
Klaas Freitag
b42d3ced15 Another fix for make install on MacOSX 2014-04-28 11:19:25 +02:00
Klaas Freitag
1c73a8d4ad Fix installation for MacOSX 2014-04-28 10:24:12 +02:00
Daniel Molkentin
2d3ea59755 Limit the mac workaround to the Mac OS X platform 2014-04-28 10:13:53 +02:00
Jenkins for ownCloud
b8b064836c [tx-robot] updated from transifex 2014-04-28 02:07:38 -04:00
Jenkins for ownCloud
3ab1330f63 [tx-robot] updated from transifex 2014-04-28 01:26:40 -04:00
Jenkins for ownCloud
ab711ddc36 [tx-robot] updated from transifex 2014-04-27 02:06:35 -04:00
Jenkins for ownCloud
2a1e67e587 [tx-robot] updated from transifex 2014-04-27 01:25:42 -04:00
Jenkins for ownCloud
1d3febe053 [tx-robot] updated from transifex 2014-04-26 01:25:42 -04:00
Olivier Goffart
165e35c750 t1.pl: change assertLocalAndRemoteDir so we actually test something 2014-04-25 14:35:20 +02:00
Olivier Goffart
9da261acd8 Do not read from the database when upgrading from 1.5
We need to make sure that the file id are updated (if the user
had upgraded from owncloud 5 to owncloud 6 while using owncloud 1.5)
2014-04-25 13:31:44 +02:00
Jenkins for ownCloud
7544f4d367 [tx-robot] updated from transifex 2014-04-25 02:06:36 -04:00
Jenkins for ownCloud
a29a56bce8 [tx-robot] updated from transifex 2014-04-25 01:25:42 -04:00
Olivier Goffart
642c16b09b Missing EXPORT 2014-04-24 23:57:42 +02:00
Olivier Goffart
5c92c190f0 Add EXPORT macro to owncloudsync library
Not all the class are exported currently, only the one that seems to be used
by the command line tools
2014-04-24 23:45:20 +02:00
Olivier Goffart
cc7826e087 Add a compile option to disable renaming when the extension changes
This is only used for a very specific server that do not support
changing the extension of files without re-uploading the file.

Since the change is small and self contained, it is guarded by a #ifdef

(Removed old BLACKLIST_ON_ERROR option that is no longer in use)
2014-04-24 11:51:48 +02:00
Jenkins for ownCloud
a154656311 [tx-robot] updated from transifex 2014-04-24 01:25:45 -04:00
hefee
9b7a3d00ee Using QFile::decodeName instead of QLatin1String 2014-04-23 18:59:40 +02:00
Sandro Knauß
1d862b77af merged 1.5 into master 2014-04-23 18:54:49 +02:00
Klaas Freitag
888843e655 Removed another file for Jenkins. 2014-04-23 13:22:06 +02:00
Klaas Freitag
28970393f6 Removed a test file as jenkins fails on it. 2014-04-23 13:18:28 +02:00
Klaas Freitag
1af7dc952c Update to latest GNUInstallDirs cmake module
This version correctly detects debians multiarch lib handling and
lets us remove the manually set CMAKE_LIB_INSTALL_DIRS from the rules
file.
2014-04-23 13:04:16 +02:00
Jenkins for ownCloud
62dcfe85e4 [tx-robot] updated from transifex 2014-04-23 01:25:49 -04:00
Markus Goetz
f6711b2842 CMake: Find libraries also on Win host compile 2014-04-22 21:02:08 +02:00
Olivier Goffart
f2519e9d87 Fix function signature: pass argument by const reference 2014-04-22 19:52:09 +02:00
Markus Goetz
94f380c1f0 Updater: Ignore files matching with CSYNC_CONFLICT_FILE_USERNAME 2014-04-22 17:05:59 +02:00
Markus Goetz
197d180cb9 Propagator: Add support for CSYNC_CONFLICT_FILE_USERNAME 2014-04-22 16:17:49 +02:00
Markus Goetz
4be20db670 Propagator: Add makeConflictFileName function 2014-04-22 16:07:18 +02:00
Olivier Goffart
46d6191bc2 Also list folder for which the alias starts with '.'
Fixes #1695
2014-04-22 14:26:08 +02:00
Olivier Goffart
ee22f377af Start the folder watcher when new folder are added
Before, we would only set up a file system watcher when we read the
config at startup.  But we also need to do it in the other case when
the user configure new folder to watch
2014-04-22 14:15:43 +02:00
Olivier Goffart
44a04227f1 Update dynamically the error message in the account settings
This let the error be shown when the conneciton is missing at startup

And also remove the red background when there is no longer an error
2014-04-22 14:08:37 +02:00
Olivier Goffart
707c6fcc5d An abort on the reply is not usually a password error.
Copy the code from HTTPCredidentials
2014-04-22 12:52:13 +02:00
Olivier Goffart
edb1f61241 Fix compilation without the BUILD_ONLY_LIBRARIES mode 2014-04-22 12:44:01 +02:00
Olivier Goffart
3fac5f91c8 In case of error, report the right error instead of missing etag
also, missing etag is not a fatal error
2014-04-22 12:43:38 +02:00
Olivier Goffart
1338c08622 Fix compilation on linux with BUILD_LIBRARIES_ONLY 2014-04-22 11:33:38 +02:00
Olivier Goffart
0cf8091705 Merge pull request #1700 from wakeup/master
Fix non-closed p tag
2014-04-22 10:08:29 +02:00
Klaas Freitag
521373f075 More specific log output. 2014-04-22 09:33:07 +02:00
Klaas Freitag
c24732f641 More debugable code. 2014-04-22 09:33:07 +02:00
Jenkins for ownCloud
655188d7b3 [tx-robot] updated from transifex 2014-04-22 01:25:41 -04:00
Markus Goetz
77ac092975 WiP: Attempt to compile without UI 2014-04-21 19:57:15 +02:00
Volkan Gezer
78e5e4ab66 Fix non-closed p tag 2014-04-21 15:29:42 +02:00
Jenkins for ownCloud
934eda128b [tx-robot] updated from transifex 2014-04-21 01:27:00 -04:00
Daniel Molkentin
ece41921ff Merge pull request #1697 from wakeup/master
Space fix
2014-04-20 15:44:03 +02:00
Volkan Gezer
9b71643c1c Space fix 2014-04-20 14:54:40 +02:00
Jenkins for ownCloud
ed48b4bbf2 [tx-robot] updated from transifex 2014-04-20 01:26:54 -04:00
Olivier Goffart
b08284e4cc Fix the background check job for the connection
We can't use the quota job for that as it needs the credidentials and therefore
may re-enter the credidential code when we are currently trying to fetch the credentials.

The quotainfo.cpp part of this patch is basically a revert of d836b80153
2014-04-19 09:49:52 +02:00
Jenkins for ownCloud
4731b506e5 [tx-robot] updated from transifex 2014-04-19 01:27:02 -04:00
Olivier Goffart
7d3b0fe0c5 Fix memory leak: Don't need to call strdup here
The other_node outlive the trav structure, so we can just use the same pointer
2014-04-18 19:16:10 +02:00
Olivier Goffart
fa38bf7029 Make sure the fileid are saved to the database when upgrading from owncloud5 to owncloud6
We fetch the id from the server, but don't save them in the database.

I Could have used INSTRUCTION_UPDATED for that, but then i would need to update the
reconcile algorithm to take in account the fact that UPDATED is possible there.

Instead, use should_update_etag  which means the db is going to be written again

Remove reference to old instruction _UPDATED and _DELETED which does not make sens with
the new propagator

Improve the test to test this case,  and that etags are properly writen to the DB
when there is a fake conflict
2014-04-18 18:27:27 +02:00
Olivier Goffart
bfdf638334 Add the files required by the tests.
Somehow they got removed with all the moving and merging.
Especially kernelcrash.txt is required for t1.pl
2014-04-18 17:20:42 +02:00
Jenkins for ownCloud
e6664c7790 [tx-robot] updated from transifex 2014-04-17 15:03:55 -04:00
Mr. Jenkins
a90779910a [tx-robot] updated from transifex 2014-04-17 01:26:53 -04:00
Mr. Jenkins
edc7a9596a [tx-robot] updated from transifex 2014-04-16 01:26:58 -04:00
Volkan Gezer
a7a19fad71 Fix note template label 2014-04-16 03:53:37 +02:00
Klaas Freitag
d143044f4a Add missing cases to avoid "unknown action" under some circumstances.
Most of the translations are not used because they translate pre
propagation states.

Fixes #1674
2014-04-15 16:54:49 +02:00
Klaas Freitag
aee7515d42 Do not dereference the _engine member variable without check.
This can cause the crash because the _engine member is deleted in the
sync finished slot. The solution is to store the stopWatch object
before the engine is destroyed.

Fixes bug #1675
2014-04-15 16:28:18 +02:00
Klaas Freitag
82ab5fdcb9 Fix condition if network limit change is logged or not. 2014-04-15 16:28:18 +02:00
Klaas Freitag
4c6e6f6302 Add initialisations for member variables.
Avoids some valgrind warnings.
2014-04-15 16:28:18 +02:00
Klaas Freitag
0a2791270a Add a reset method. 2014-04-15 16:28:18 +02:00
Klaas Freitag
c920f81562 Add braces. 2014-04-15 16:28:18 +02:00
Mr. Jenkins
9dcbafc307 [tx-robot] updated from transifex 2014-04-15 01:26:01 -04:00
Daniel Molkentin
d836b80153 Fix reconnect after server disconnect
Fixes #1679
Fixes #1568
Fixes #1659
2014-04-14 17:51:57 +02:00
Daniel Molkentin
efc4ff4d88 Fix redirects in CheckServerJob 2014-04-14 15:12:38 +02:00
Daniel Molkentin
dc043b5765 Try scheme://host/owncloud if scheme://host/ did not work
Fixes #1680
2014-04-14 15:10:08 +02:00
Daniel Molkentin
ef9a318cd9 AbstractNetworkJob Allow finished() to defer Job deletion
This allows to reuse the Job
2014-04-14 15:08:43 +02:00
Mr. Jenkins
9f4ffd44d6 [tx-robot] updated from transifex 2014-04-14 01:25:55 -04:00
Mr. Jenkins
598bfe6d1a [tx-robot] updated from transifex 2014-04-13 01:25:56 -04:00
Mr. Jenkins
5f37c7b1b8 [tx-robot] updated from transifex 2014-04-12 01:26:00 -04:00
Volkan Gezer
8250fb81b3 Fix typo. 2014-04-11 15:10:47 +02:00
Klaas Freitag
30a14b9f45 Install ocsync library to private lib directory, use rpath to find it. 2014-04-11 13:28:11 +02:00
Mr. Jenkins
b0734f2791 [tx-robot] updated from transifex 2014-04-11 01:25:58 -04:00
Mr. Jenkins
d66b0910c6 [tx-robot] updated from transifex 2014-04-10 01:26:05 -04:00
Klaas Freitag
09e05392bf Ignore all sync log files in the sync dir. 2014-04-09 22:02:28 +02:00
Daniel Molkentin
d3d202de68 Fix dataLocation on Linux/BSD
From the Qt 5 documentation:

  Note: when porting QDesktopServices::DataLocation(obsolete)
        to QStandardPaths::DataLocation, a different path will
        be returned.

        QDesktopServices::DataLocation was GenericDataLocation
        + "/data/organization/application", while
        QStandardPaths::DataLocation is GenericDataLocation
        + "/organization/application".

We'll resort to the deprecated version, since we'll need to fix
data locations to be XDG compliant sooner than later anyway
(currently scheduled for 1.8)
2014-04-09 14:59:08 +02:00
Daniel Molkentin
87010fbe1a SSL Button: Fix issues around printing Hash sums
- Use SHA 265 instead of obsolete MD5 where possible (Qt5)
- Remove <tt> formatting: that simply looked ugly
- Wrap SHA 265 hash
- Use spaces as separators

As usual, the default needs to remain ':' separation, because
it's needed to pass valid hashes to csync.
2014-04-09 14:30:51 +02:00
Jenkins for ownCloud
f302da81b1 [tx-robot] updated from transifex 2014-04-09 02:07:10 -04:00
Mr. Jenkins
3af53f5984 [tx-robot] updated from transifex 2014-04-09 01:26:26 -04:00
Klaas Freitag
08dd9796d1 HACK to avoid continuation: See task #1448
We do not know the _modtime from the server, at this point, so just set
the current one.  (rather than the one locally)
2014-04-04 10:50:40 +02:00
Sandro Knauß
47274f1075 Merge remote-tracking branch 'respect-XDG_CONFIG_HOME' into 1.5 2014-03-21 17:20:15 +01:00
Markus Goetz
f72e1cc837 Log: Don't override level for csync
The level shall be set from Folder or owncloudCmd only.
2014-03-21 13:52:35 +01:00
hefee
4e0496f74d respect XDG_CONFIG_HOME for getting user config dir.
Under linux the XDG Base Directory Specification define different
enviroment variables where to store what.
2013-12-31 02:10:44 +01: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
163 changed files with 11883 additions and 8956 deletions

View File

@@ -85,6 +85,14 @@ endif()
# this option creates only libocsync and libowncloudsync # this option creates only libocsync and libowncloudsync
option(BUILD_LIBRARIES_ONLY "BUILD_LIBRARIES_ONLY" OFF) option(BUILD_LIBRARIES_ONLY "BUILD_LIBRARIES_ONLY" OFF)
# When this option is enabled, 5xx errors are not added to the clacklist
# Normaly you don't want to enable this option because if a particular file
# trigger a bug on the server, you want the file to be blacklisted.
option(OWNCLOUD_5XX_NO_BLACKLIST "OWNCLOUD_5XX_NO_BLACKLIST" OFF)
if(OWNCLOUD_5XX_NO_BLACKLIST)
add_definitions(-DOWNCLOUD_5XX_NO_BLACKLIST=1)
endif()
#### find libs #### find libs
#find_package(Qt4 4.7.0 COMPONENTS QtCore QtGui QtXml QtNetwork QtTest QtWebkit REQUIRED ) #find_package(Qt4 4.7.0 COMPONENTS QtCore QtGui QtXml QtNetwork QtTest QtWebkit REQUIRED )
#if( UNIX AND NOT APPLE ) # Fdo notifications #if( UNIX AND NOT APPLE ) # Fdo notifications

View File

@@ -1,6 +1,22 @@
ChangeLog 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 "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 * Job-based change propagation, enables faster parallel up/downloads
(right now only if no bandwidth limit is set and no proxy is used) (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 * Significantly reduced CPU load when checking for local and remote changes
@@ -18,6 +34,7 @@ version 1.6.0 (release 2014-04- )
* Mac OS X: Fix UI inconsistencies on Mavericks * Mac OS X: Fix UI inconsistencies on Mavericks
* Shibboleth: Warn if authenticating with a different user * Shibboleth: Warn if authenticating with a different user
* Remove vio abstraction in csync * 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 ) version 1.5.3 (release 2014-03-10 )
* Fix usage of proxies after first sync run (#1502, #1524, #1459, #1521) * Fix usage of proxies after first sync run (#1502, #1524, #1459, #1521)

View File

@@ -4,7 +4,7 @@ set( MIRALL_VERSION_PATCH 0 )
set( MIRALL_SOVERSION 0 ) set( MIRALL_SOVERSION 0 )
if ( NOT DEFINED MIRALL_VERSION_SUFFIX ) if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
set( MIRALL_VERSION_SUFFIX "beta1" ) #e.g. beta1, beta2, rc1 set( MIRALL_VERSION_SUFFIX "") #e.g. beta1, beta2, rc1
endif( NOT DEFINED MIRALL_VERSION_SUFFIX ) endif( NOT DEFINED MIRALL_VERSION_SUFFIX )
if( NOT DEFINED MIRALL_VERSION_BUILD ) 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_MESSAGEBOX_TEXT "Βρέθηκε η(οι) διεργασία(ες) ${APPLICATION_EXECUTABLE} η(οι) οποία(ες) θα πρέπει να τερματιστεί(ούν).$\nΘα θέλατε να την(τις) τερματίσει ο βοηθός εγκατάστασης για εσάς;"
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Τερματισμός διεργασιών ${APPLICATION_EXECUTABLE}." StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Τερματισμός διεργασιών ${APPLICATION_EXECUTABLE}."
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Δεν βρέθηκε διεργασία για βίαιο τερματισμό!" StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Δεν βρέθηκε διεργασία για βίαιο τερματισμό!"
StrCpy $PageReinstall_NEW_Field_1 "Μια παλαιότερη έκδοση της ${APPLICATION_NAME} είναι εγκατεστημένη στο σύστημά σας. Είναι προτεινόμενο να απεγκαταστήσετε την τρέχουσα έκδοση πριν την εγκατάσταση. Επιλέξτε τη διαδικασία που επιθυμείτε να πραγματοποιείσετε και πατήστε Επόμενο για να συνεχίσετε." StrCpy $PageReinstall_NEW_Field_1 "Μια παλαιότερη έκδοση της ${APPLICATION_NAME} είναι εγκατεστημένη στο σύστημά σας. Είναι προτεινόμενο να απεγκαταστήσετε την τρέχουσα έκδοση πριν την εγκατάσταση. Επιλέξτε τη διαδικασία που επιθυμείτε να εκτελέσετε και πατήστε Επόμενο για να συνεχίσετε."
StrCpy $PageReinstall_NEW_Field_2 "Απεγκατάσταση πριν την εγκατάσταση" StrCpy $PageReinstall_NEW_Field_2 "Απεγκατάσταση πριν την εγκατάσταση"
StrCpy $PageReinstall_NEW_Field_3 "Να μην απεγκατασταθεί" StrCpy $PageReinstall_NEW_Field_3 "Να μην απεγκατασταθεί"
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Ήδη εγκατεστημένο" StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Ήδη εγκατεστημένη"
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Επιλέξτε πώς θέλετε να εγκαταστήσετε την ${APPLICATION_NAME}." StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Επιλέξτε πώς θέλετε να εγκαταστήσετε την ${APPLICATION_NAME}."
StrCpy $PageReinstall_OLD_Field_1 "Μια νεώτερη έκδοση της ${APPLICATION_NAME} είναι ήδη εγκατεστημένη! Δεν συνίσταται να εγκαταστείσετε μια παλαιότερη έκδοση. Εάν θέλετε πραγματικά να εγκαταστήσετε αυτή την παλαιότερη έκδοση, είναι καλύτερο να απεγκαταστήσετε την τρέχουσα έκδοση πρώτα. Επιλέξτε τη διαδικασία που επιθυμείτε να πραγματοποιείσετε και επιλέξτε Επόμενο για να συνεχίσετε." StrCpy $PageReinstall_OLD_Field_1 "Μια νεώτερη έκδοση της ${APPLICATION_NAME} είναι ήδη εγκατεστημένη! Δεν συνίσταται να εγκαταστείσετε μια παλαιότερη έκδοση. Εάν θέλετε πραγματικά να εγκαταστήσετε αυτήν την παλαιότερη έκδοση, είναι καλύτερο να απεγκαταστήσετε την τρέχουσα έκδοση πρώτα. Επιλέξτε τη διαδικασία που επιθυμείτε να εκτελέσετε και επιλέξτε Επόμενο για να συνεχίσετε."
StrCpy $PageReinstall_SAME_Field_1 "Η ${APPLICATION_NAME} ${VERSION} είναι ήδη εγκατεστημένη.\n\nΕπιλέξτε τη διαδικασία που επιθυμείτε να πραγματοποιείσετε και επιλέξτε Επόμενο για να συνεχίσετε." StrCpy $PageReinstall_SAME_Field_1 "Η ${APPLICATION_NAME} ${VERSION} είναι ήδη εγκατεστημένη.\n\nΕπιλέξτε τη διαδικασία που επιθυμείτε να εκτελέσετε και επιλέξτε Επόμενο για να συνεχίσετε."
StrCpy $PageReinstall_SAME_Field_2 "Προσθήκη/ Επανεγκατάσταση συνιστωσών" StrCpy $PageReinstall_SAME_Field_2 "Προσθήκη/ Επανεγκατάσταση συνιστωσών"
StrCpy $PageReinstall_SAME_Field_3 "Απεγκατάσταση ${APPLICATION_NAME}" StrCpy $PageReinstall_SAME_Field_3 "Απεγκατάσταση ${APPLICATION_NAME}"
StrCpy $UNINSTALLER_APPDATA_TITLE "Απεγκατάσταση ${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_QUICK_LAUNCH_DetailPrint "Δημιουργία Συντόμευσης Ταχείας Εκκίνησης"
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "Βάση ${APPLICATION_NAME}." StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "Βάση ${APPLICATION_NAME}."
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "Συντόμευση ${APPLICATION_NAME}." StrCpy $OPTION_SECTION_SC_START_MENU_Desc "Συντόμευση ${APPLICATION_NAME}."
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Συντόμευση στην επιφάνεια εργασίας της " StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Συντόμευση επιφάνειας εργασίας της ${APPLICATION_NAME}."
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Συντόμευση Ταχείας Εκκίνησης της " StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Συντόμευση Ταχείας Εκκίνησης της ${APPLICATION_NAME}."
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Αφαίρεση του φακέλου δεδομένων της ${APPLICATION_NAME} από τον υπολογιστή σας" StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Αφαίρεση του φακέλου δεδομένων της ${APPLICATION_NAME} από τον υπολογιστή σας."
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "Θέλετε να αφαιρέσετε τον φάκελο δεδομένων της ${APPLICATION_NAME};" StrCpy $UNINSTALLER_APPDATA_LABEL_1 "Θέλετε να αφαιρέσετε τον φάκελο δεδομένων της ${APPLICATION_NAME};"
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Αφήστε κενό για να διατηρήσετε τον φάκελο δεδομένων για μελλοντική χρήση ή επιλέξτε για να διγράψετε το φάκελο δεδομένων." StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Αφήστε κενό για να διατηρήσετε τον φάκελο δεδομένων για μελλοντική χρήση ή επιλέξτε για να διγράψετε το φάκελο δεδομένων."
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "Να διαγραφεί ο φάκελος δεδομένων." StrCpy $UNINSTALLER_APPDATA_CHECKBOX "Ναι, διαγραφή αυτού του φακέλου δεδομένων."
StrCpy $UNINSTALLER_FILE_Detail "Εγγραφή Εφαρμογής Απεγκατάστασης" StrCpy $UNINSTALLER_FILE_Detail "Εγγραφή Εφαρμογής Απεγκατάστασης"
StrCpy $UNINSTALLER_REGISTRY_Detail "Εγγραφή Κλειδιών μητρώου (Registry) της Εφαρμογής Εγκατάστασης" StrCpy $UNINSTALLER_REGISTRY_Detail "Εγγραφή Κλειδιών μητρώου (Registry) της Εφαρμογής Εγκατάστασης"
StrCpy $UNINSTALLER_FINISHED_Detail "Ολοκλήρωση" StrCpy $UNINSTALLER_FINISHED_Detail "Ολοκληρώθηκε"
StrCpy $UNINSTALL_MESSAGEBOX "Φαίνεται πως η ${APPLICATION_NAME} είναι εγκατεστημένη στον κατάλογο '$INSTDIR'.$\n$\nΣυνέχιση παρ' όλα αυτά (δεν συνίσταται);" StrCpy $UNINSTALL_MESSAGEBOX "Δεν φαίνεται να είναι εγκατεστημένηη η ${APPLICATION_NAME} στον κατάλογο '$INSTDIR'.$\n$\nΣυνέχιση παρ' όλα αυτά (δεν συνίσταται);"
StrCpy $UNINSTALL_ABORT "Η απεγκατάσταση ματαιώθηκε από το χρήστη" StrCpy $UNINSTALL_ABORT "Η απεγκατάσταση ματαιώθηκε από το χρήστη"
StrCpy $INIT_NO_QUICK_LAUNCH "Συντόμευση Ταχείας Εκκίνησης (Μ/Δ)" StrCpy $INIT_NO_QUICK_LAUNCH "Συντόμευση Ταχείας Εκκίνησης (Μ/Δ)"
StrCpy $INIT_NO_DESKTOP "Συντόμευση Επιφάνειας Εργασίας (αντικαθιστά υπάρχουσα)" StrCpy $INIT_NO_DESKTOP "Συντόμευση Επιφάνειας Εργασίας (αντικαθιστά υπάρχουσα)"

View File

@@ -1,17 +1,18 @@
# Auto-generated - do not modify # Auto-generated - do not modify
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Kiadási jegyzetek megtekintése"
StrCpy $PageReinstall_NEW_Field_2 "Eltávolítás telepítés előtt"
StrCpy $PageReinstall_NEW_Field_3 "Ne távolítsa el"
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Már telepítve" StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Már telepítve"
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Válaszd ki, hogy szeretnéd telepíteni a következő alkalmazást ${APPLICATION_NAME}." StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Válaszd ki, hogy szeretnéd telepíteni a következő alkalmazást ${APPLICATION_NAME}."
StrCpy $PageReinstall_SAME_Field_2 "Komponens hozzáadása/újratelepítése" StrCpy $PageReinstall_SAME_Field_2 "Komponens hozzáadása/újratelepítése"
StrCpy $PageReinstall_SAME_Field_3 "Eltávolitani ${APPLICATION_NAME}" StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} eltávolítása"
StrCpy $UNINSTALLER_APPDATA_TITLE "Eltávolitani ${APPLICATION_NAME}" StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} eltávolítása"
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "Igen, törölje ezt az adatkönyvtárat."
StrCpy $UNINSTALLER_FINISHED_Detail "Befejezve" StrCpy $UNINSTALLER_FINISHED_Detail "Befejezve"
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Show release notes"
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Found ${APPLICATION_EXECUTABLE} process(s) which need to be stopped.$\nDo you want the installer to stop these for you?" StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Found ${APPLICATION_EXECUTABLE} process(s) which need to be stopped.$\nDo you want the installer to stop these for you?"
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Killing ${APPLICATION_EXECUTABLE} processes." StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Killing ${APPLICATION_EXECUTABLE} processes."
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Process to kill not found!" StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Process to kill not found!"
StrCpy $PageReinstall_NEW_Field_1 "An older version of ${APPLICATION_NAME} is installed on your system. It is recommended that you uninstall the current version before installing. Select the operation you want to perform and click Next to continue." StrCpy $PageReinstall_NEW_Field_1 "An older version of ${APPLICATION_NAME} is installed on your system. It is recommended that you uninstall the current version before installing. Select the operation you want to perform and click Next to continue."
StrCpy $PageReinstall_NEW_Field_2 "Uninstall before installing"
StrCpy $PageReinstall_NEW_Field_3 "Do not uninstall"
StrCpy $PageReinstall_OLD_Field_1 "A newer version of ${APPLICATION_NAME} is already installed! It is not recommended that you install an older version. If you really want to install this older version, it is better to uninstall the current version first. Select the operation you want to perform and click Next to continue." StrCpy $PageReinstall_OLD_Field_1 "A newer version of ${APPLICATION_NAME} is already installed! It is not recommended that you install an older version. If you really want to install this older version, it is better to uninstall the current version first. Select the operation you want to perform and click Next to continue."
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.\r\nSelect the operation you want to perform and click Next to continue." StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.\r\nSelect the operation you want to perform and click Next to continue."
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Choose the maintenance option to perform." StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Choose the maintenance option to perform."
@@ -29,7 +30,6 @@ StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Quick Launch shortcut for ${APPLICA
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Remove ${APPLICATION_NAME}'s data folder from your computer." StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Remove ${APPLICATION_NAME}'s data folder from your computer."
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "Do you want to delete ${APPLICATION_NAME}'s data folder?" StrCpy $UNINSTALLER_APPDATA_LABEL_1 "Do you want to delete ${APPLICATION_NAME}'s data folder?"
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Leave unchecked to keep the data folder for later use or check to delete the data folder." StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Leave unchecked to keep the data folder for later use or check to delete the data folder."
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "Yes, delete this data folder."
StrCpy $UNINSTALLER_FILE_Detail "Writing Uninstaller" StrCpy $UNINSTALLER_FILE_Detail "Writing Uninstaller"
StrCpy $UNINSTALLER_REGISTRY_Detail "Writing Installer Registry Keys" StrCpy $UNINSTALLER_REGISTRY_Detail "Writing Installer Registry Keys"
StrCpy $UNINSTALL_MESSAGEBOX "It does not appear that ${APPLICATION_NAME} is installed in the directory '$INSTDIR'.$\r$\nContinue anyway (not recommended)?" StrCpy $UNINSTALL_MESSAGEBOX "It does not appear that ${APPLICATION_NAME} is installed in the directory '$INSTDIR'.$\r$\nContinue anyway (not recommended)?"

View File

@@ -1,6 +1,6 @@
# Auto-generated - do not modify # Auto-generated - do not modify
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Mostra le note di rilascio" StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Mostra le note di rilascio"
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Trovati ${APPLICATION_EXECUTABLE} processi che dovrebbero essere fermati.$\nVuoi che il programma di installazione li fermi per te?" StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Trovati ${APPLICATION_EXECUTABLE} processi che dovrebbero essere fermati.$\nVuoi che il programma di installazione li fermi al posto tuo?"
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Sto terminando ${APPLICATION_EXECUTABLE} processi." StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Sto terminando ${APPLICATION_EXECUTABLE} processi."
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Il processo da terminare non è stato trovato!" StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Il processo da terminare non è stato trovato!"
StrCpy $PageReinstall_NEW_Field_1 "Una versione più datata di ${APPLICATION_NAME} è installata sul tuo sistema. Si consiglia di disinstallare la versione attuale prima di installare. Seleziona l'operazione da eseguire e fai clic su Avanti per continuare." StrCpy $PageReinstall_NEW_Field_1 "Una versione più datata di ${APPLICATION_NAME} è installata sul tuo sistema. Si consiglia di disinstallare la versione attuale prima di installare. Seleziona l'operazione da eseguire e fai clic su Avanti per continuare."

View File

@@ -0,0 +1,44 @@
# Auto-generated - do not modify
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Mostrar notas de la versión"
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Parando el proceso ${APPLICATION_EXECUTABLE}."
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Proceso a detener no encontrado!"
StrCpy $PageReinstall_NEW_Field_1 "Una versión anterior de ${APPLICATION_NAME} esta instalada en el sistema. Es recomendado que quite esta versión antes de instalar. Elija la operación a realizar y seleccione Siguiente para continuar."
StrCpy $PageReinstall_NEW_Field_2 "Des-instale antes de Instalar."
StrCpy $PageReinstall_NEW_Field_3 "No des-instalar."
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Actualmente Instalado."
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Elija como desea instalar ${APPLICATION_NAME}."
StrCpy $PageReinstall_OLD_Field_1 "Una versión mas reciente de ${APPLICATION_NAME} esta actualmente instalada! No es recomendado que instale una versión antigua. Si realmente desea instalar esta versión obsoleta, es mejor que des-instale la versión actual primero. Seleccione la operación que desea realizar y presione en Siguiente para continuar. "
StrCpy $PageReinstall_SAME_Field_2 "Agregar/Re-Instalar componentes"
StrCpy $PageReinstall_SAME_Field_3 "Des-instalar ${APPLICATION_NAME}"
StrCpy $UNINSTALLER_APPDATA_TITLE "Des-instalar ${APPLICATION_NAME}"
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Elija la opción de mantenimiento a realizar."
StrCpy $SEC_APPLICATION_DETAILS "Instalar esenciales ${APPLICATION_NAME}."
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Acceso Directo en Menú de Programas"
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Agregando el Acceso Directo al Menú de Inicio para ${APPLICATION_NAME}."
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Acceso directo en Escritorio"
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "Creando Accesos Directos en Escritorio"
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "Acceso directo de ${APPLICATION_NAME}"
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Acceso Directo al Escritorio para ${APPLICATION_NAME}."
StrCpy $UNINSTALLER_APPDATA_SUBTITLE "Quitar la carpeta de datos ${APPLICATION_NAME} de la computadora."
StrCpy $UNINSTALLER_APPDATA_LABEL_1 "Desea borrar la carpeta de datos de ${APPLICATION_NAME}?"
StrCpy $UNINSTALLER_APPDATA_LABEL_2 "Dejar des-tildado para mantener la carpeta de datos para posterior uso o tildar para borrar la carpeta de datos."
StrCpy $UNINSTALLER_APPDATA_CHECKBOX "Si, eliminar esta carpeta de datos."
StrCpy $UNINSTALLER_FILE_Detail "Escribiendo Des-Instalador."
StrCpy $UNINSTALLER_REGISTRY_Detail "Escribiendo claves de Registro del Instalador"
StrCpy $UNINSTALLER_FINISHED_Detail "Terminado"
StrCpy $UNINSTALL_ABORT "Des-instalación abortada por el usuario"
StrCpy $INIT_NO_DESKTOP "Acceso Directo en Escritorio (Sobrescribe existentes)"
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Este instalador requiere acceso Administrador, intente de nuevo. "
StrCpy $INIT_INSTALLER_RUNNING "El instalador ya esta corriendo."
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Este des-instalador requiere acceso administrador, intente de nuevo"
StrCpy $INIT_UNINSTALLER_RUNNING "El des-instalador ya esta corriendo"
StrCpy $SectionGroup_Shortcuts "Accesos Directos"
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Found ${APPLICATION_EXECUTABLE} process(s) which need to be stopped.$\nDo you want the installer to stop these for you?"
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.\r\nSelect the operation you want to perform and click Next to continue."
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Quick Launch Shortcut"
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Creating Quick Launch Shortcut"
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} essentials."
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Quick Launch shortcut for ${APPLICATION_NAME}."
StrCpy $UNINSTALL_MESSAGEBOX "It does not appear that ${APPLICATION_NAME} is installed in the directory '$INSTDIR'.$\r$\nContinue anyway (not recommended)?"
StrCpy $INIT_NO_QUICK_LAUNCH "Quick Launch Shortcut (N/A)"
StrCpy $UAC_ERROR_ELEVATE "Unable to elevate, error:"

View File

@@ -36,9 +36,9 @@ StrCpy $UNINSTALL_MESSAGEBOX "Det verkar inte som ${APPLICATION_NAME} är instal
StrCpy $UNINSTALL_ABORT "Avinstallering avbröts av användare" StrCpy $UNINSTALL_ABORT "Avinstallering avbröts av användare"
StrCpy $INIT_NO_QUICK_LAUNCH "Snabbstartsgenväg (N/A)" StrCpy $INIT_NO_QUICK_LAUNCH "Snabbstartsgenväg (N/A)"
StrCpy $INIT_NO_DESKTOP "Skrivbordsgenväg (skriver över nuvarande)" StrCpy $INIT_NO_DESKTOP "Skrivbordsgenväg (skriver över nuvarande)"
StrCpy $UAC_ERROR_ELEVATE "Kunde inte få förhöjda rättigheter, fel:"
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Detta installationsprogram kräver adminstratörs rättigheter, försök igen" StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Detta installationsprogram kräver adminstratörs rättigheter, försök igen"
StrCpy $INIT_INSTALLER_RUNNING "Installationsprogrammet körs redan." StrCpy $INIT_INSTALLER_RUNNING "Installationsprogrammet körs redan."
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Detta avinstallationsprogram kräver administratörs rättigheter, försök igen" StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Detta avinstallationsprogram kräver administratörs rättigheter, försök igen"
StrCpy $INIT_UNINSTALLER_RUNNING "Avinstallationsprogrammet körs redan." StrCpy $INIT_UNINSTALLER_RUNNING "Avinstallationsprogrammet körs redan."
StrCpy $SectionGroup_Shortcuts "Genvägar" StrCpy $SectionGroup_Shortcuts "Genvägar"
StrCpy $UAC_ERROR_ELEVATE "Unable to elevate, error:"

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_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_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_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_2 "Bileşenleri ekle/yeniden yükle"
StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} uygulamasını kaldır" StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} uygulamasını kaldır"
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} uygulamasını kaldır" StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} uygulamasını kaldır"

View File

@@ -3,6 +3,7 @@
!insertmacro MUI_LANGUAGE "Estonian" !insertmacro MUI_LANGUAGE "Estonian"
!insertmacro MUI_LANGUAGE "Turkish" !insertmacro MUI_LANGUAGE "Turkish"
!insertmacro MUI_LANGUAGE "Slovenian" !insertmacro MUI_LANGUAGE "Slovenian"
!insertmacro MUI_LANGUAGE "SpanishInternational"
!insertmacro MUI_LANGUAGE "Dutch" !insertmacro MUI_LANGUAGE "Dutch"
!insertmacro MUI_LANGUAGE "Hungarian" !insertmacro MUI_LANGUAGE "Hungarian"
!insertmacro MUI_LANGUAGE "French" !insertmacro MUI_LANGUAGE "French"

View File

@@ -31,7 +31,7 @@ HINTS
find_library(NEON_LIBRARIES find_library(NEON_LIBRARIES
NAMES NAMES
neon neon neon-27
HINTS HINTS
${_NEON_LIBDIR} ${_NEON_LIBDIR}
${CMAKE_INSTALL_LIBDIR} ${CMAKE_INSTALL_LIBDIR}

View File

@@ -30,7 +30,7 @@ find_path(SQLITE3_INCLUDE_DIR
find_library(SQLITE3_LIBRARY find_library(SQLITE3_LIBRARY
NAMES NAMES
sqlite3 sqlite3 sqlite3-0
PATHS PATHS
${_SQLITE3_LIBDIR} ${_SQLITE3_LIBDIR}
) )

View File

@@ -1,32 +1,49 @@
# - Define GNU standard installation directories #.rst:
# GNUInstallDirs
# --------------
#
# Define GNU standard installation directories
#
# Provides install directory variables as defined for GNU software: # Provides install directory variables as defined for GNU software:
# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html #
# ::
#
# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
#
# Inclusion of this module defines the following variables: # Inclusion of this module defines the following variables:
# CMAKE_INSTALL_<dir> - destination for files of a given type #
# CMAKE_INSTALL_FULL_<dir> - corresponding absolute path # ::
#
# CMAKE_INSTALL_<dir> - destination for files of a given type
# CMAKE_INSTALL_FULL_<dir> - corresponding absolute path
#
# where <dir> is one of: # where <dir> is one of:
# BINDIR - user executables (bin) #
# SBINDIR - system admin executables (sbin) # ::
# LIBEXECDIR - program executables (libexec) #
# SYSCONFDIR - read-only single-machine data (etc) # BINDIR - user executables (bin)
# SHAREDSTATEDIR - modifiable architecture-independent data (com) # SBINDIR - system admin executables (sbin)
# LOCALSTATEDIR - modifiable single-machine data (var) # LIBEXECDIR - program executables (libexec)
# LIBDIR - object code libraries (lib or lib64) # SYSCONFDIR - read-only single-machine data (etc)
# INCLUDEDIR - C header files (include) # SHAREDSTATEDIR - modifiable architecture-independent data (com)
# OLDINCLUDEDIR - C header files for non-gcc (/usr/include) # LOCALSTATEDIR - modifiable single-machine data (var)
# DATAROOTDIR - read-only architecture-independent data root (share) # LIBDIR - object code libraries (lib or lib64 or lib/<multiarch-tuple> on Debian)
# DATADIR - read-only architecture-independent data (DATAROOTDIR) # INCLUDEDIR - C header files (include)
# INFODIR - info documentation (DATAROOTDIR/info) # OLDINCLUDEDIR - C header files for non-gcc (/usr/include)
# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale) # DATAROOTDIR - read-only architecture-independent data root (share)
# MANDIR - man documentation (DATAROOTDIR/man) # DATADIR - read-only architecture-independent data (DATAROOTDIR)
# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME) # INFODIR - info documentation (DATAROOTDIR/info)
# Each CMAKE_INSTALL_<dir> value may be passed to the DESTINATION options of # LOCALEDIR - locale-dependent data (DATAROOTDIR/locale)
# install() commands for the corresponding file type. If the includer does # MANDIR - man documentation (DATAROOTDIR/man)
# not define a value the above-shown default will be used and the value will # DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME)
# appear in the cache for editing by the user. #
# Each CMAKE_INSTALL_FULL_<dir> value contains an absolute path constructed # Each CMAKE_INSTALL_<dir> value may be passed to the DESTINATION
# from the corresponding destination by prepending (if necessary) the value # options of install() commands for the corresponding file type. If the
# of CMAKE_INSTALL_PREFIX. # includer does not define a value the above-shown default will be used
# and the value will appear in the cache for editing by the user. Each
# CMAKE_INSTALL_FULL_<dir> value contains an absolute path constructed
# from the corresponding destination by prepending (if necessary) the
# value of CMAKE_INSTALL_PREFIX.
#============================================================================= #=============================================================================
# Copyright 2011 Nikita Krupen'ko <krnekit@gmail.com> # Copyright 2011 Nikita Krupen'ko <krnekit@gmail.com>
@@ -68,30 +85,90 @@ if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR)
set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)") set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)")
endif() endif()
if(NOT DEFINED CMAKE_INSTALL_LIBDIR) # We check if the variable was manually set and not cached, in order to
# allow projects to set the values as normal variables before including
# GNUInstallDirs to avoid having the entries cached or user-editable. It
# replaces the "if(NOT DEFINED CMAKE_INSTALL_XXX)" checks in all the
# other cases.
# If CMAKE_INSTALL_LIBDIR is defined, if _libdir_set is false, then the
# variable is a normal one, otherwise it is a cache one.
get_property(_libdir_set CACHE CMAKE_INSTALL_LIBDIR PROPERTY TYPE SET)
if(NOT DEFINED CMAKE_INSTALL_LIBDIR OR (_libdir_set
AND DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX
AND NOT "${_GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX}" STREQUAL "${CMAKE_INSTALL_PREFIX}"))
# If CMAKE_INSTALL_LIBDIR is not defined, it is always executed.
# Otherwise:
# * if _libdir_set is false it is not executed (meaning that it is
# not a cache variable)
# * if _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX is not defined it is
# not executed
# * if _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX and
# CMAKE_INSTALL_PREFIX are the same string it is not executed.
# _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX is updated after the
# execution, of this part of code, therefore at the next inclusion
# of the file, CMAKE_INSTALL_LIBDIR is defined, and the 2 strings
# are equal, meaning that the if is not executed the code the
# second time.
set(_LIBDIR_DEFAULT "lib") set(_LIBDIR_DEFAULT "lib")
# Override this default 'lib' with 'lib64' iff: # Override this default 'lib' with 'lib64' iff:
# - we are on Linux system but NOT cross-compiling # - we are on Linux system but NOT cross-compiling
# - we are NOT on debian # - we are NOT on debian
# - we are on a 64 bits system # - we are on a 64 bits system
# reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf # reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf
# Note that the future of multi-arch handling may be even # For Debian with multiarch, use 'lib/${CMAKE_LIBRARY_ARCHITECTURE}' if
# more complicated than that: http://wiki.debian.org/Multiarch # CMAKE_LIBRARY_ARCHITECTURE is set (which contains e.g. "i386-linux-gnu"
if(CMAKE_SYSTEM_NAME MATCHES "Linux" # and CMAKE_INSTALL_PREFIX is "/usr"
AND NOT CMAKE_CROSSCOMPILING # See http://wiki.debian.org/Multiarch
AND NOT EXISTS "/etc/debian_version") if(DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX)
if(NOT DEFINED CMAKE_SIZEOF_VOID_P) set(__LAST_LIBDIR_DEFAULT "lib")
message(AUTHOR_WARNING # __LAST_LIBDIR_DEFAULT is the default value that we compute from
"Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. " # _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX, not a cache entry for
"Please enable at least one language before including GNUInstallDirs.") # the value that was last used as the default.
else() # This value is used to figure out whether the user changed the
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") # CMAKE_INSTALL_LIBDIR value manually, or if the value was the
set(_LIBDIR_DEFAULT "lib64") # default one. When CMAKE_INSTALL_PREFIX changes, the value is
# updated to the new default, unless the user explicitly changed it.
endif()
if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$"
AND NOT CMAKE_CROSSCOMPILING)
if (EXISTS "/etc/debian_version") # is this a debian system ?
if(CMAKE_LIBRARY_ARCHITECTURE)
if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/?$")
set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
endif()
if(DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX
AND "${_GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/?$")
set(__LAST_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
endif()
endif()
else() # not debian, rely on CMAKE_SIZEOF_VOID_P:
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
message(AUTHOR_WARNING
"Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
"Please enable at least one language before including GNUInstallDirs.")
else()
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(_LIBDIR_DEFAULT "lib64")
if(DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX)
set(__LAST_LIBDIR_DEFAULT "lib64")
endif()
endif()
endif() endif()
endif() endif()
endif() endif()
set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})") if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})")
elseif(DEFINED __LAST_LIBDIR_DEFAULT
AND "${__LAST_LIBDIR_DEFAULT}" STREQUAL "${CMAKE_INSTALL_LIBDIR}")
set_property(CACHE CMAKE_INSTALL_LIBDIR PROPERTY VALUE "${_LIBDIR_DEFAULT}")
endif()
endif() endif()
# Save for next run
set(_GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE INTERNAL "CMAKE_INSTALL_PREFIX during last run")
unset(_libdir_set)
unset(__LAST_LIBDIR_DEFAULT)
if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR) if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)") set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)")

View File

@@ -11,13 +11,15 @@ endif( BUILD_WITH_QT4 )
if( Qt5Core_FOUND ) if( Qt5Core_FOUND )
message(STATUS "Found Qt5 core, checking for further dependencies...") message(STATUS "Found Qt5 core, checking for further dependencies...")
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Quick REQUIRED)
find_package(Qt5PrintSupport REQUIRED)
find_package(Qt5WebKit REQUIRED)
find_package(Qt5Network REQUIRED) find_package(Qt5Network REQUIRED)
find_package(Qt5Xml REQUIRED) find_package(Qt5Xml REQUIRED)
find_package(Qt5WebKitWidgets REQUIRED) if(NOT TOKEN_AUTH_ONLY)
find_package(Qt5WebKitWidgets REQUIRED)
find_package(Qt5WebKit REQUIRED)
find_package(Qt5PrintSupport REQUIRED)
find_package(Qt5Quick REQUIRED)
find_package(Qt5Widgets REQUIRED)
endif()
if(APPLE) if(APPLE)
find_package(Qt5MacExtras REQUIRED) find_package(Qt5MacExtras REQUIRED)
endif(APPLE) endif(APPLE)
@@ -37,23 +39,27 @@ if( Qt5Core_FOUND )
include_directories(${Qt5DBus_INCLUDES}) include_directories(${Qt5DBus_INCLUDES})
add_definitions(${Qt5DBus_DEFINITIONS}) add_definitions(${Qt5DBus_DEFINITIONS})
endif (WITH_DBUS) endif (WITH_DBUS)
include_directories(${Qt5Core_INCLUDES})
include_directories(${Qt5Widgets_INCLUDES}) add_definitions(${Qt5Core_DEFINITIONS})
add_definitions(${Qt5Widgets_DEFINITIONS})
if (NOT WIN32) #implied on Win32 if (NOT WIN32) #implied on Win32
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
endif(NOT WIN32) endif(NOT WIN32)
# set(CMAKE_CXX_FLAGS "${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") # set(CMAKE_CXX_FLAGS "${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
if(APPLE) if(APPLE AND NOT TOKEN_AUTH_ONLY)
include_directories(${Qt5MacExtras_INCLUDE_DIRS}) include_directories(${Qt5MacExtras_INCLUDE_DIRS})
add_definitions(${Qt5MacExtras_DEFINITIONS}) add_definitions(${Qt5MacExtras_DEFINITIONS})
set (QT_LIBRARIES ${QT_LIBRARIES} ${Qt5MacExtras_LIBRARIES}) set (QT_LIBRARIES ${QT_LIBRARIES} ${Qt5MacExtras_LIBRARIES})
endif(APPLE) endif()
if(NOT BUILD_LIBRARIES_ONLY)
macro(qt_wrap_ui) macro(qt_wrap_ui)
qt5_wrap_ui(${ARGN}) qt5_wrap_ui(${ARGN})
endmacro() endmacro()
else()
# hack
SET(QT_UIC_EXECUTABLE "")
endif()
macro(qt_add_resources) macro(qt_add_resources)
qt5_add_resources(${ARGN}) qt5_add_resources(${ARGN})

View File

@@ -44,11 +44,10 @@ if(HAVE_ICONV AND WITH_ICONV)
list(APPEND CSYNC_LINK_LIBRARIES ${ICONV_LIBRARIES}) list(APPEND CSYNC_LINK_LIBRARIES ${ICONV_LIBRARIES})
endif() endif()
set(BLACKLIST_ON_ERROR 0 CACHE BOOL # Specific option for builds tied to servers that do not support renaming extensions
"If an errors occurs three times on the same file, do not attempt to process that file any further.") set(NO_RENAME_EXTENSION 0 CACHE BOOL "Do not issue rename if the extension changes")
if(NO_RENAME_EXTENSION)
if(BLACKLIST_ON_ERROR) add_definitions(-DNO_RENAME_EXTENSION)
add_definitions(-DBLACKLIST_ON_ERROR)
endif() endif()
set(csync_SRCS set(csync_SRCS
@@ -110,17 +109,29 @@ set_target_properties(
SOVERSION SOVERSION
${LIBRARY_SOVERSION} ${LIBRARY_SOVERSION}
) )
if(BUILD_OWNCLOUD_OSX_BUNDLE)
INSTALL( INSTALL(
TARGETS
${CSYNC_LIBRARY}
LIBRARY DESTINATION
${LIB_INSTALL_DIR}
ARCHIVE DESTINATION
${LIB_INSTALL_DIR}
RUNTIME DESTINATION
${BIN_INSTALL_DIR}
)
else()
INSTALL(
TARGETS TARGETS
${CSYNC_LIBRARY} ${CSYNC_LIBRARY}
LIBRARY DESTINATION LIBRARY DESTINATION
${LIB_INSTALL_DIR} ${LIB_INSTALL_DIR}/${APPLICATION_EXECUTABLE}
ARCHIVE DESTINATION ARCHIVE DESTINATION
${LIB_INSTALL_DIR} ${LIB_INSTALL_DIR}/${APPLICATION_EXECUTABLE}
RUNTIME DESTINATION RUNTIME DESTINATION
${BIN_INSTALL_DIR} ${BIN_INSTALL_DIR}/${APPLICATION_EXECUTABLE}
) )
endif()
# INSTALL( # INSTALL(
# FILES # FILES

View File

@@ -191,15 +191,12 @@ int csync_init(CSYNC *ctx) {
ctx->local.type = LOCAL_REPLICA; ctx->local.type = LOCAL_REPLICA;
if ( !ctx->options.local_only_mode) { 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; ctx->remote.type = REMOTE_REPLICA;
} else { } else {
ctx->remote.type = LOCAL_REPLICA; 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) { if (c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp) < 0) {
ctx->status_code = CSYNC_STATUS_TREE_ERROR; ctx->status_code = CSYNC_STATUS_TREE_ERROR;
rc = -1; rc = -1;
@@ -447,14 +444,15 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
trav.rename_path = cur->destpath; trav.rename_path = cur->destpath;
trav.etag = cur->etag; trav.etag = cur->etag;
trav.file_id = cur->file_id; trav.file_id = cur->file_id;
trav.inode = cur->inode;
trav.error_status = cur->error_status; trav.error_status = cur->error_status;
trav.should_update_etag = cur->should_update_etag; trav.should_update_etag = cur->should_update_etag;
if( other_node ) { if( other_node ) {
csync_file_stat_t *other_stat = (csync_file_stat_t*)other_node->data; csync_file_stat_t *other_stat = (csync_file_stat_t*)other_node->data;
trav.other.etag = other_stat->etag ? c_strdup(other_stat->etag) : NULL; trav.other.etag = other_stat->etag;
trav.other.file_id = c_strdup(other_stat->file_id); trav.other.file_id = other_stat->file_id;
trav.other.instruction = other_stat->instruction; trav.other.instruction = other_stat->instruction;
trav.other.modtime = other_stat->modtime; trav.other.modtime = other_stat->modtime;
trav.other.size = other_stat->size; trav.other.size = other_stat->size;
@@ -629,6 +627,8 @@ int csync_commit(CSYNC *ctx) {
_csync_clean_ctx(ctx); _csync_clean_ctx(ctx);
ctx->remote.read_from_db = 0; ctx->remote.read_from_db = 0;
ctx->read_from_db_disabled = 0;
/* Create new trees */ /* Create new trees */
rc = c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp); rc = c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp);
@@ -923,3 +923,10 @@ int csync_set_module_property(CSYNC* ctx, const char* key, void* value)
return csync_vio_set_property(ctx, key, value); return csync_vio_set_property(ctx, key, value);
} }
int csync_set_read_from_db(CSYNC* ctx, int enabled)
{
ctx->read_from_db_disabled = !enabled;
return 0;
}

View File

@@ -102,7 +102,8 @@ enum csync_status_codes_e {
/* Codes for file individual status: */ /* Codes for file individual status: */
CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK, CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK,
CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST, CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST,
CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS,
CYSNC_STATUS_FILE_LOCKED_OR_OPEN
}; };
typedef enum csync_status_codes_e CSYNC_STATUS; typedef enum csync_status_codes_e CSYNC_STATUS;
@@ -130,10 +131,7 @@ enum csync_instructions_e {
CSYNC_INSTRUCTION_IGNORE = 0x00000020, /* The file is ignored (UPDATE|RECONCILE) */ CSYNC_INSTRUCTION_IGNORE = 0x00000020, /* The file is ignored (UPDATE|RECONCILE) */
CSYNC_INSTRUCTION_SYNC = 0x00000040, /* The file need to be pushed to the other remote (RECONCILE) */ CSYNC_INSTRUCTION_SYNC = 0x00000040, /* The file need to be pushed to the other remote (RECONCILE) */
CSYNC_INSTRUCTION_STAT_ERROR = 0x00000080, CSYNC_INSTRUCTION_STAT_ERROR = 0x00000080,
CSYNC_INSTRUCTION_ERROR = 0x00000100, CSYNC_INSTRUCTION_ERROR = 0x00000100
/* instructions for the propagator */
CSYNC_INSTRUCTION_DELETED = 0x00000200,
CSYNC_INSTRUCTION_UPDATED = 0x00000400
}; };
enum csync_ftw_type_e { enum csync_ftw_type_e {
@@ -172,6 +170,7 @@ enum csync_notify_type_e {
struct csync_tree_walk_file_s { struct csync_tree_walk_file_s {
const char *path; const char *path;
int64_t size; int64_t size;
int64_t inode;
time_t modtime; time_t modtime;
#ifdef _WIN32 #ifdef _WIN32
uint32_t uid; uint32_t uid;
@@ -591,6 +590,11 @@ void csync_resume(CSYNC *ctx);
*/ */
int csync_abort_requested(CSYNC *ctx); int csync_abort_requested(CSYNC *ctx);
/**
* Specify if it is allowed to read the remote tree from the DB (default to enabled)
*/
int csync_set_read_from_db(CSYNC* ctx, int enabled);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -144,6 +144,7 @@ CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype) {
char *bname = NULL; char *bname = NULL;
char *dname = NULL; char *dname = NULL;
char *prev_dname = NULL; char *prev_dname = NULL;
char *conflict = NULL;
int rc = -1; int rc = -1;
CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED; CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED;
CSYNC_EXCLUDE_TYPE type = CSYNC_NOT_EXCLUDED; CSYNC_EXCLUDE_TYPE type = CSYNC_NOT_EXCLUDED;
@@ -200,6 +201,19 @@ CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype) {
goto out; goto out;
} }
if (getenv("CSYNC_CONFLICT_FILE_USERNAME")) {
asprintf(&conflict, "*_conflict_%s-*", getenv("CSYNC_CONFLICT_FILE_USERNAME"));
rc = csync_fnmatch(conflict, path, 0);
if (rc == 0) {
match = CSYNC_FILE_SILENTLY_EXCLUDED;
SAFE_FREE(conflict);
SAFE_FREE(bname);
SAFE_FREE(dname);
goto out;
}
SAFE_FREE(conflict);
}
SAFE_FREE(bname); SAFE_FREE(bname);
SAFE_FREE(dname); SAFE_FREE(dname);

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. int _connected = 0; /* flag to indicate if a connection exists, ie.
the dav_session is valid */ the dav_session is valid */
csync_auth_callback _authcb;
void *_userdata; void *_userdata;
long long chunked_total_size = 0; long long chunked_total_size = 0;
long long chunked_done = 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)]; char buf[MAX(NE_SSL_DIGESTLEN, NE_ABUFSIZ)];
int ret = -1; int ret = -1;
const ne_ssl_certificate *cert = certificate; const ne_ssl_certificate *cert = certificate;
csync_auth_callback authcb = NULL;
(void) userdata; (void) userdata;
memset( problem, 0, LEN ); 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 ); 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 */ /* call the csync callback */
DEBUG_WEBDAV("Call the csync callback for SSL problems"); DEBUG_WEBDAV("Call the csync callback for SSL problems");
memset( buf, 0, NE_ABUFSIZ ); 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') { if( buf[0] == 'y' || buf[0] == 'Y') {
ret = 0; ret = 0;
} else { } else {
@@ -184,6 +188,8 @@ static int ne_auth( void *userdata, const char *realm, int attempt,
char *username, char *password) char *username, char *password)
{ {
char buf[NE_ABUFSIZ]; char buf[NE_ABUFSIZ];
csync_auth_callback authcb = NULL;
int re = attempt;
(void) userdata; (void) userdata;
(void) realm; (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 ) { if( dav_session.pwd && strlen( dav_session.pwd ) < NE_ABUFSIZ ) {
strcpy( password, dav_session.pwd ); 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 { } 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; goto out;
} }
if (dav_session.read_timeout == 0) 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);
DEBUG_WEBDAV("Timeout set to %u seconds", dav_session.read_timeout );
ne_set_read_timeout(dav_session.ctx, dav_session.read_timeout); }
snprintf( uaBuf, sizeof(uaBuf), "Mozilla/5.0 (%s) csyncoC/%s", snprintf( uaBuf, sizeof(uaBuf), "Mozilla/5.0 (%s) csyncoC/%s",
get_platform(), CSYNC_STRINGIFY( LIBCSYNC_VERSION )); get_platform(), CSYNC_STRINGIFY( LIBCSYNC_VERSION ));
@@ -982,8 +993,10 @@ int owncloud_commit(void) {
clean_caches(); clean_caches();
if( dav_session.ctx ) if( dav_session.ctx ) {
ne_session_destroy( dav_session.ctx ); ne_forget_auth(dav_session.ctx);
ne_session_destroy( dav_session.ctx );
}
/* DEBUG_WEBDAV( "********** vio_module_shutdown" ); */ /* DEBUG_WEBDAV( "********** vio_module_shutdown" ); */
dav_session.ctx = 0; dav_session.ctx = 0;
@@ -1047,10 +1060,9 @@ int owncloud_set_property(const char *key, void *data) {
return -1; return -1;
} }
void owncloud_init(csync_auth_callback cb, void *userdata) { void owncloud_init(void *userdata) {
_userdata = userdata; _userdata = userdata;
_authcb = cb;
_connected = 0; /* triggers dav_connect to go through the whole neon setup */ _connected = 0; /* triggers dav_connect to go through the whole neon setup */
memset(&dav_session, 0, sizeof(dav_session)); 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_stat(const char *uri, csync_vio_file_stat_t *buf);
int owncloud_commit(void); int owncloud_commit(void);
char *owncloud_error_string(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); int owncloud_set_property(const char *key, void *data);
#endif /* CSYNC_OWNCLOUD_H */ #endif /* CSYNC_OWNCLOUD_H */

View File

@@ -161,6 +161,7 @@ struct csync_s {
int status; int status;
volatile int abort; volatile int abort;
void *rename_info; void *rename_info;
int read_from_db_disabled;
}; };

View File

@@ -183,6 +183,7 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
if( !c_streq(cur->file_id, "") ) { if( !c_streq(cur->file_id, "") ) {
csync_vio_set_file_id( other->file_id, cur->file_id ); csync_vio_set_file_id( other->file_id, cur->file_id );
} }
other->inode = cur->inode;
cur->instruction = CSYNC_INSTRUCTION_NONE; cur->instruction = CSYNC_INSTRUCTION_NONE;
} else if (other->instruction == CSYNC_INSTRUCTION_REMOVE) { } else if (other->instruction == CSYNC_INSTRUCTION_REMOVE) {
other->instruction = CSYNC_INSTRUCTION_RENAME; 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, "") ) { if( !c_streq(cur->file_id, "") ) {
csync_vio_set_file_id( other->file_id, cur->file_id ); csync_vio_set_file_id( other->file_id, cur->file_id );
} }
other->inode = cur->inode;
cur->instruction = CSYNC_INSTRUCTION_NONE; cur->instruction = CSYNC_INSTRUCTION_NONE;
} else if (other->instruction == CSYNC_INSTRUCTION_NEW) { } else if (other->instruction == CSYNC_INSTRUCTION_NEW) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "OOOO=> NEW detected in other tree!"); CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "OOOO=> NEW detected in other tree!");
@@ -223,6 +224,16 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
/* file on current replica is changed or new */ /* file on current replica is changed or new */
case CSYNC_INSTRUCTION_EVAL: case CSYNC_INSTRUCTION_EVAL:
case CSYNC_INSTRUCTION_NEW: case CSYNC_INSTRUCTION_NEW:
// This operation is usually a no-op and will by default return false
if (csync_file_locked_or_open(ctx->local.uri, cur->path)) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "[Reconciler] IGNORING file %s/%s since it is locked / open", ctx->local.uri, cur->path);
cur->instruction = CSYNC_INSTRUCTION_ERROR;
if (cur->error_status == CSYNC_STATUS_OK) // don't overwrite error
cur->error_status = CYSNC_STATUS_FILE_LOCKED_OR_OPEN;
break;
} else {
//CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "[Reconciler] not ignoring file %s/%s", ctx->local.uri, cur->path);
}
switch (other->instruction) { switch (other->instruction) {
/* file on other replica is changed or new */ /* file on other replica is changed or new */
case CSYNC_INSTRUCTION_NEW: case CSYNC_INSTRUCTION_NEW:
@@ -235,10 +246,11 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
} }
if (is_equal_files) { if (is_equal_files) {
/* The files are considered equal. */ /* The files are considered equal. */
cur->instruction = CSYNC_INSTRUCTION_UPDATED; /* update the DB */ cur->instruction = CSYNC_INSTRUCTION_NONE;
other->instruction = CSYNC_INSTRUCTION_NONE; other->instruction = CSYNC_INSTRUCTION_NONE;
if( !cur->etag && other->etag ) cur->etag = c_strdup(other->etag); if( !cur->etag && other->etag ) cur->etag = c_strdup(other->etag);
cur->should_update_etag = true; /* update DB */
} else if(ctx->current == REMOTE_REPLICA) { } else if(ctx->current == REMOTE_REPLICA) {
cur->instruction = CSYNC_INSTRUCTION_CONFLICT; cur->instruction = CSYNC_INSTRUCTION_CONFLICT;
other->instruction = CSYNC_INSTRUCTION_NONE; other->instruction = CSYNC_INSTRUCTION_NONE;

View File

@@ -79,6 +79,26 @@ static uint64_t _hash_of_file(CSYNC *ctx, const char *file) {
return h; return h;
} }
#ifdef NO_RENAME_EXTENSION
/* Return true if the two path have the same extension. false otherwise. */
static bool _csync_sameextension(const char *p1, const char *p2) {
/* Find pointer to the extensions */
const char *e1 = strrchr(p1, '.');
const char *e2 = strrchr(p2, '.');
/* If the found extension contains a '/', it is because the . was in the folder name
* => no extensions */
if (e1 && strchr(e1, '/')) e1 = NULL;
if (e2 && strchr(e2, '/')) e2 = NULL;
/* If none have extension, it is the same extension */
if (!e1 && !e2)
return true;
/* c_streq takes care of the rest */
return c_streq(e1, e2);
}
#endif
static int _csync_detect_update(CSYNC *ctx, const char *file, static int _csync_detect_update(CSYNC *ctx, const char *file,
const csync_vio_file_stat_t *fs, const int type) { const csync_vio_file_stat_t *fs, const int type) {
@@ -235,18 +255,29 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
goto out; goto out;
} }
if (type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA if (type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA
&& c_streq(fs->file_id, tmp->file_id)) { && c_streq(fs->file_id, tmp->file_id) && !ctx->read_from_db_disabled) {
/* If both etag and file id are equal for a directory, read all contents from /* If both etag and file id are equal for a directory, read all contents from
* the database. */ * the database.
* The comparison of file id ensure that we fetch all the file id when upgrading from
* owncloud 5 to owncloud 6.
*/
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Reading from database: %s", path); CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Reading from database: %s", path);
ctx->remote.read_from_db = true; ctx->remote.read_from_db = true;
} }
if (!c_streq(fs->file_id, tmp->file_id) && ctx->current == REMOTE_REPLICA) {
/* file id has changed. Which means we need to update the DB.
* (upgrade from owncloud 5 to owncloud 6 for instence) */
st->should_update_etag = true;
}
st->instruction = CSYNC_INSTRUCTION_NONE; st->instruction = CSYNC_INSTRUCTION_NONE;
} else { } else {
enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN; enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
/* check if it's a file and has been renamed */ /* check if it's a file and has been renamed */
if (ctx->current == LOCAL_REPLICA) { 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); tmp = csync_statedb_get_stat_by_inode(ctx, fs->inode);
/* translate the file type between the two stat types csync has. */ /* translate the file type between the two stat types csync has. */
@@ -259,8 +290,12 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
} }
if (tmp && tmp->inode == fs->inode && tmp_vio_type == fs->type if (tmp && tmp->inode == fs->inode && tmp_vio_type == fs->type
&& (tmp->modtime == fs->mtime || fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY)) { && (tmp->modtime == fs->mtime || fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY)
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "inodes: %" PRId64 " <-> %" PRId64, (uint64_t) tmp->inode, (uint64_t) fs->inode); #ifdef NO_RENAME_EXTENSION
&& _csync_sameextension(tmp->path, path)
#endif
) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "pot rename detected based on inode # %" PRId64 "", (uint64_t) fs->inode);
/* inode found so the file has been renamed */ /* inode found so the file has been renamed */
st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME; st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) { if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
@@ -443,7 +478,6 @@ static bool fill_tree_from_db(CSYNC *ctx, const char *uri)
/* File tree walker */ /* File tree walker */
int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
unsigned int depth) { unsigned int depth) {
char errbuf[256] = {0};
char *filename = NULL; char *filename = NULL;
char *d_name = NULL; char *d_name = NULL;
csync_vio_handle_t *dh = NULL; csync_vio_handle_t *dh = NULL;
@@ -487,10 +521,7 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!"); CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!");
} }
} else { } else {
C_STRERROR(errno, errbuf, sizeof(errbuf)); CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "opendir failed for %s - errno %d", uri, errno);
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR,
"opendir failed for %s - %s (errno %d)",
uri, errbuf, errno);
} }
goto error; goto error;
} }
@@ -638,7 +669,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_NEW ||
ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL_RENAME)) { ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL_RENAME)) {
ctx->current_fs->should_update_etag = true; ctx->current_fs->should_update_etag = true;

View File

@@ -55,8 +55,6 @@ static const _instr_code_struct _instr[] =
{ "INSTRUCTION_SYNC", CSYNC_INSTRUCTION_SYNC }, { "INSTRUCTION_SYNC", CSYNC_INSTRUCTION_SYNC },
{ "INSTRUCTION_STAT_ERR", CSYNC_INSTRUCTION_STAT_ERROR }, { "INSTRUCTION_STAT_ERR", CSYNC_INSTRUCTION_STAT_ERROR },
{ "INSTRUCTION_ERROR", CSYNC_INSTRUCTION_ERROR }, { "INSTRUCTION_ERROR", CSYNC_INSTRUCTION_ERROR },
{ "INSTRUCTION_DELETED", CSYNC_INSTRUCTION_DELETED },
{ "INSTRUCTION_UPDATED", CSYNC_INSTRUCTION_UPDATED },
{ NULL, CSYNC_INSTRUCTION_ERROR } { NULL, CSYNC_INSTRUCTION_ERROR }
}; };
@@ -182,3 +180,22 @@ csync_vio_file_stat_t *csync_vio_convert_file_stat(csync_file_stat_t *st) {
return vfs; return vfs;
} }
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;
}
bool csync_file_locked_or_open( const char *dir, const char *fname) {
char *tmp_uri = NULL;
bool ret;
if (!csync_file_locked_or_open_ext) {
return false;
}
asprintf(&tmp_uri, "%s/%s", dir, fname);
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "csync_file_locked_or_open %s", tmp_uri);
ret = csync_file_locked_or_open_ext(tmp_uri);
SAFE_FREE(tmp_uri);
return ret;
}

View File

@@ -35,4 +35,5 @@ void csync_win32_set_file_hidden( const char *file, bool hidden );
/* Convert a csync_file_stat_t to csync_vio_file_stat_t */ /* Convert a csync_file_stat_t to csync_vio_file_stat_t */
csync_vio_file_stat_t *csync_vio_convert_file_stat(csync_file_stat_t *st); csync_vio_file_stat_t *csync_vio_convert_file_stat(csync_file_stat_t *st);
bool csync_file_locked_or_open( const char *dir, const char *fname);
#endif /* _CSYNC_UTIL_H */ #endif /* _CSYNC_UTIL_H */

View File

@@ -55,9 +55,6 @@
/** Get the size of an array */ /** Get the size of an array */
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) #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 * 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 * get the "discarding const" warning by the compiler. That doesn't actually

View File

@@ -113,11 +113,6 @@ int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) {
if (rc < 0) { if (rc < 0) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Local stat failed, errno %d", errno); 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; break;
default: default:
break; 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); */ /* printf("Index: %I64i\n", FileIndex.QuadPart); */
buf->inode = 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 /* 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 * http://www.codeproject.com/Articles/1144/Beating-the-Daylight-Savings-Time-bug-and-getting
* for deeper explanation. * for deeper explanation.

View File

@@ -243,19 +243,6 @@ static void check_csync_statedb_get_stat_by_hash_not_found(void **state)
free(tmp); 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) 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_query_statement, setup, teardown),
unit_test_setup_teardown(check_csync_statedb_create_error, 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_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_drop_tables, setup, teardown),
unit_test_setup_teardown(check_csync_statedb_insert_metadata, 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_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_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), unit_test_setup_teardown(check_csync_statedb_get_stat_by_inode_not_found, setup_db, teardown),
}; };

View File

@@ -233,8 +233,6 @@ static void check_csync_detect_update_db_none(void **state)
st = c_rbtree_node_data(csync->local.tree->root); st = c_rbtree_node_data(csync->local.tree->root);
assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW); assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
/* set the instruction to UPDATED that it gets written to the statedb */
st->instruction = CSYNC_INSTRUCTION_UPDATED;
/* create a statedb */ /* create a statedb */
csync_set_status(csync, 0xFFFF); csync_set_status(csync, 0xFFFF);
@@ -262,9 +260,6 @@ static void check_csync_detect_update_db_eval(void **state)
st = c_rbtree_node_data(csync->local.tree->root); st = c_rbtree_node_data(csync->local.tree->root);
assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW); assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
/* set the instruction to UPDATED that it gets written to the statedb */
st->instruction = CSYNC_INSTRUCTION_UPDATED;
/* create a statedb */ /* create a statedb */
csync_set_status(csync, 0xFFFF); csync_set_status(csync, 0xFFFF);
@@ -344,8 +339,6 @@ static void check_csync_detect_update_db_new(void **state)
st = c_rbtree_node_data(csync->local.tree->root); st = c_rbtree_node_data(csync->local.tree->root);
assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW); assert_int_equal(st->instruction, CSYNC_INSTRUCTION_NEW);
/* set the instruction to UPDATED that it gets written to the statedb */
st->instruction = CSYNC_INSTRUCTION_UPDATED;
/* create a statedb */ /* create a statedb */
csync_set_status(csync, 0xFFFF); csync_set_status(csync, 0xFFFF);

View File

@@ -56,13 +56,13 @@ assertLocalDirs( 'toremote1', localDir().'remoteToLocal1' );
# Check if the synced files from ownCloud have the same timestamp as the local ones. # Check if the synced files from ownCloud have the same timestamp as the local ones.
print "\nNow assert remote 'toremote1' with local " . localDir() . " :\n"; print "\nNow assert remote 'toremote1' with local " . localDir() . " :\n";
assertLocalAndRemoteDir( 'remoteToLocal1', 0); assertLocalAndRemoteDir( '', 0);
# remove a local file. # remove a local file.
printInfo( "\nRemove a local file\n" ); printInfo( "\nRemove a local file\n" );
unlink( localDir() . 'remoteToLocal1/kernelcrash.txt' ); unlink( localDir() . 'remoteToLocal1/rtl4/quitte.pdf' );
csync(); csync();
assertLocalAndRemoteDir( 'remoteToLocal1', 0); assertLocalAndRemoteDir( '', 0);
# add local files to a new dir1 # add local files to a new dir1
printInfo( "Add some more files to local:"); printInfo( "Add some more files to local:");
@@ -76,34 +76,46 @@ foreach my $file ( <./tolocal1/*> ) {
} }
csync( ); csync( );
print "\nAssert local and remote dirs.\n"; print "\nAssert local and remote dirs.\n";
assertLocalAndRemoteDir( 'fromLocal1', 0); assertLocalAndRemoteDir( '', 0);
# move a local file # move a local file
printInfo( "Move a file locally." ); printInfo( "Move a file locally." );
move( "$locDir/kramer.jpg", "$locDir/oldtimer.jpg" ); move( "$locDir/kramer.jpg", "$locDir/oldtimer.jpg" );
csync( ); csync( );
assertLocalAndRemoteDir( 'fromLocal1', 0); assertLocalAndRemoteDir( '', 0);
# move a local directory. # move a local directory.
printInfo( "Move a local directory." ); printInfo( "Move a local directory." );
move( localDir() . 'remoteToLocal1/rtl1', localDir(). 'remoteToLocal1/rtlX'); move( localDir() . 'remoteToLocal1/rtl1', localDir(). 'remoteToLocal1/rtlX');
csync(); csync();
assertLocalAndRemoteDir( 'fromLocal1', 0); assertLocalAndRemoteDir( '', 0);
# remove a local dir # remove a local dir
printInfo( "Remove a local directory."); printInfo( "Remove a local directory.");
localCleanup( 'remoteToLocal1/rtlX' ); localCleanup( 'remoteToLocal1/rtlX' );
csync(); csync();
assertLocalAndRemoteDir( 'fromLocal1', 0); assertLocalAndRemoteDir( '', 0);
assert( ! -e localDir().'remoteToLocal1/rtlX' ); assert( ! -e localDir().'remoteToLocal1/rtlX' );
# create a false conflict, only the mtimes are changed, by content are equal. # create twos false conflict, only the mtimes are changed, by content are equal.
printInfo( "Create a false conflict."); printInfo( "Create two false conflict.");
my $srcFile = 'toremote1/kernelcrash.txt'; put_to_dir( 'toremote1/kernelcrash.txt', 'remoteToLocal1' );
put_to_dir( $srcFile, 'remoteToLocal1' ); put_to_dir( 'toremote1/kraft_logo.gif', 'remoteToLocal1' );
# don't wait so mtime are likely the same on the client and the server.
system( "touch " . localDir() . "remoteToLocal1/kraft_logo.gif" );
# wait two second so the mtime are different
system( "sleep 2 && touch " . localDir() . "remoteToLocal1/kernelcrash.txt" ); system( "sleep 2 && touch " . localDir() . "remoteToLocal1/kernelcrash.txt" );
csync( ); csync( );
assertLocalAndRemoteDir( 'fromLocal1', 0); assertLocalAndRemoteDir( '', 0);
# The previous sync should have updated the etags, and this should NOT be a conflict
printInfo( "Update the file again");
system("echo more data >> " . localDir() . "remoteToLocal1/kernelcrash.txt");
system("echo corruption >> " . localDir() . "remoteToLocal1/kraft_logo.gif");
csync( );
assertLocalAndRemoteDir( '', 0);
# create a true conflict. # create a true conflict.
printInfo( "Create a conflict." ); printInfo( "Create a conflict." );
@@ -111,13 +123,14 @@ system( "echo \"This is more stuff\" >> /tmp/kernelcrash.txt" );
put_to_dir( '/tmp/kernelcrash.txt', 'remoteToLocal1' ); put_to_dir( '/tmp/kernelcrash.txt', 'remoteToLocal1' );
system( "sleep 2 && touch " . localDir() . "remoteToLocal1/kernelcrash.txt" ); system( "sleep 2 && touch " . localDir() . "remoteToLocal1/kernelcrash.txt" );
csync(); csync();
assertLocalAndRemoteDir( 'remoteToLocal1', 1); assertLocalAndRemoteDir( '', 1);
my $localMD5 = md5OfFile( localDir().'remoteToLocal1/kernelcrash.txt' ); my $localMD5 = md5OfFile( localDir().'remoteToLocal1/kernelcrash.txt' );
my $realMD5 = md5OfFile( '/tmp/kernelcrash.txt' ); my $realMD5 = md5OfFile( '/tmp/kernelcrash.txt' );
print "MD5 compare $localMD5 <-> $realMD5\n"; print "MD5 compare $localMD5 <-> $realMD5\n";
assert( $localMD5 eq $realMD5 ); assert( $localMD5 eq $realMD5 );
assert( glob(localDir().'remoteToLocal1/kernelcrash_conflict-*.txt' ) ); assert( glob(localDir().'remoteToLocal1/kernelcrash_conflict-*.txt' ) );
system("rm " . localDir().'remoteToLocal1/kernelcrash_conflict-*.txt' );
# prepare test for issue 1329, rtlX need to be modified # prepare test for issue 1329, rtlX need to be modified
@@ -125,13 +138,13 @@ assert( glob(localDir().'remoteToLocal1/kernelcrash_conflict-*.txt' ) );
printInfo( "Add a local directory"); printInfo( "Add a local directory");
system("cp -r 'toremote1/rtl1/' '" . localDir(). "remoteToLocal1/rtlX'"); system("cp -r 'toremote1/rtl1/' '" . localDir(). "remoteToLocal1/rtlX'");
csync(); csync();
assertLocalAndRemoteDir( 'fromLocal1', 0); assertLocalAndRemoteDir( '', 0);
# remove a local dir (still for issue 1329) # remove a local dir (still for issue 1329)
printInfo( "Remove that directory."); printInfo( "Remove that directory.");
localCleanup( 'remoteToLocal1/rtlX' ); localCleanup( 'remoteToLocal1/rtlX' );
csync(); csync();
assertLocalAndRemoteDir( 'fromLocal1', 0); assertLocalAndRemoteDir( '', 0);
assert( ! -e localDir().'remoteToLocal1/rtlX' ); assert( ! -e localDir().'remoteToLocal1/rtlX' );
@@ -141,7 +154,7 @@ system("cp -r 'toremote1/rtl1/' '" . localDir(). "remoteToLocal1/rtlX'");
assert( -e localDir().'remoteToLocal1/rtlX' ); assert( -e localDir().'remoteToLocal1/rtlX' );
assert( -e localDir().'remoteToLocal1/rtlX/rtl11/file.txt' ); assert( -e localDir().'remoteToLocal1/rtlX/rtl11/file.txt' );
csync(); csync();
assertLocalAndRemoteDir( 'fromLocal1', 0); assertLocalAndRemoteDir( '', 0);
assert( -e localDir().'remoteToLocal1/rtlX' ); assert( -e localDir().'remoteToLocal1/rtlX' );
assert( -e localDir().'remoteToLocal1/rtlX/rtl11/file.txt' ); assert( -e localDir().'remoteToLocal1/rtlX/rtl11/file.txt' );

View File

@@ -80,7 +80,6 @@ assert( $inode == $inode2, "Inode has changed!");
printInfo("Move a file into a sub directory."); printInfo("Move a file into a sub directory.");
# now move the file into a sub directory # now move the file into a sub directory
$inode = getInode('remoteToLocal1/kernel.txt');
moveRemoteFile( 'remoteToLocal1/kernel.txt', 'remoteToLocal1/rtl1/'); moveRemoteFile( 'remoteToLocal1/kernel.txt', 'remoteToLocal1/rtl1/');
csync(); csync();
@@ -175,6 +174,24 @@ createLocalFile( localDir(). 'remoteToLocal1/rtl2/newRemoteDir/donat.txt', 8021
csync(); csync();
assertLocalAndRemoteDir( 'remoteToLocal1', 1); assertLocalAndRemoteDir( 'remoteToLocal1', 1);
printInfo("simulate a owncloud 5 update by removing all the fileid");
## simulate a owncloud 5 update by removing all the fileid
system( "sqlite3 " . localDir() . ".csync_journal.db \"UPDATE metadata SET fileid='';\"");
#refresh the ids
csync();
assertLocalAndRemoteDir( 'remoteToLocal1', 1);
printInfo("Move a file from the server");
$inode = getInode('remoteToLocal1/rtl2/kb1_local_gone.jpg');
moveRemoteFile( 'remoteToLocal1/rtl2/kb1_local_gone.jpg', 'remoteToLocal1/rtl2/kb1_local_gone2.jpg');
csync();
assertLocalAndRemoteDir( 'remoteToLocal1', 1);
$inode2 = getInode('remoteToLocal1/rtl2/kb1_local_gone2.jpg');
assert( $inode == $inode2, "Inode has changed 3!");
cleanup(); cleanup();
# -- # --

View File

@@ -0,0 +1 @@
A nice document.

View File

@@ -0,0 +1,16 @@
freitag@zora:~>
Message from syslogd@zora at Sep 20 21:35:41 ...
kernel:[ 6702.458047] general protection fault: 0000 [#1] PREEMPT SMP
Message from syslogd@zora at Sep 20 21:35:41 ...
kernel:[ 6702.458060] last sysfs file: /sys/devices/LNXSYSTM:00/device:00/PNP0A08:00/device:03/ATK0110:00/hwmon/hwmon0/temp1_label
Message from syslogd@zora at Sep 20 21:35:41 ...
kernel:[ 6702.458232] Stack:
Message from syslogd@zora at Sep 20 21:35:41 ...
kernel:[ 6702.458262] Call Trace:
Message from syslogd@zora at Sep 20 21:35:41 ...
kernel:[ 6702.458375] Code: 00 00 80 00 00 00 48 b9 00 00 00 00 80 ff ff ff 4e 8d 34 30 49 21 ce 48 8b 4c 24 38 49 8d 56 ff 48 3b 54 24 48 4c 0f 43 74 24 40 <48> 8b 11 48 85 d2 0f 84 d4 01 00 00 48 b9 fb 0f 00 00 00 c0 ff

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@@ -1 +0,0 @@
some content.

View File

@@ -12,12 +12,15 @@ if(SPHINX_FOUND)
# assets # assets
set(LATEX_LOGO "${CMAKE_CURRENT_SOURCE_DIR}/logo-blue.pdf") 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) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in" conf.py @ONLY)
if(WITH_DOC) if(WITH_DOC)
add_custom_target(doc ALL DEPENDS doc-html doc-man COMMENT "Building documentation...") 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) else(WITH_DOC)
add_custom_target(doc DEPENDS doc-html doc-man COMMENT "Building documentation...") add_custom_target(doc DEPENDS doc-html doc-man COMMENT "Building documentation...")
endif(WITH_DOC) endif(WITH_DOC)
@@ -39,9 +42,6 @@ if(SPHINX_FOUND)
add_custom_target(doc-pdf $(MAKE) -C ${SPHINX_PDF_DIR} all-pdf add_custom_target(doc-pdf $(MAKE) -C ${SPHINX_PDF_DIR} all-pdf
DEPENDS doc-latex ) DEPENDS doc-latex )
add_dependencies(doc doc-pdf) add_dependencies(doc doc-pdf)
if (WITH_DOC)
install(DIRECTORY ${SPHINX_PDF_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR})
endif (WITH_DOC)
endif(PDFLATEX_FOUND) endif(PDFLATEX_FOUND)
if (EXISTS ${QT_QCOLLECTIONGENERATOR_EXECUTABLE}) if (EXISTS ${QT_QCOLLECTIONGENERATOR_EXECUTABLE})
add_custom_target( doc-qch-sphinx ${SPHINX_EXECUTABLE} add_custom_target( doc-qch-sphinx ${SPHINX_EXECUTABLE}
@@ -53,9 +53,6 @@ if(SPHINX_FOUND)
${SPHINX_QCH_DIR}/*.qhcp ${SPHINX_QCH_DIR}/*.qhcp
DEPENDS doc-qch-sphinx ) DEPENDS doc-qch-sphinx )
add_dependencies(doc doc-qch) add_dependencies(doc doc-qch)
if (WITH_DOC)
install(DIRECTORY ${SPHINX_QCH_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR})
endif (WITH_DOC)
endif() endif()
add_custom_target( doc-html ${SPHINX_EXECUTABLE} add_custom_target( doc-html ${SPHINX_EXECUTABLE}
-q -c . -b html -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 More information about the apache logging can be found at
``http://httpd.apache.org/docs/current/logs.html``. ``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

@@ -80,7 +80,7 @@ Adding a Folder
Adding a new sync is initiated by clicking ``Add Folder...`` in the ``Account`` Adding a new sync is initiated by clicking ``Add Folder...`` in the ``Account``
settings. settings.
..note: To add a folder, you must not already sync a folder that contains this ..note:: To add a folder, you must not already sync a folder that contains this
folder. By default, the wizard sets up the root folder of the ownCloud folder. By default, the wizard sets up the root folder of the ownCloud
server to sync all of your ownCloud account. In consequence, you will server to sync all of your ownCloud account. In consequence, you will
first need to remove this folder prior to specifying new syncs. first need to remove this folder prior to specifying new syncs.

View File

@@ -1,5 +1,5 @@
This is the src directory of the QtLockedFile 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. 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). ** This file is part of Qt Creator.
**
** Contact: http://www.qt-project.org/
** **
** 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 ** 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 ** In addition, as a special exception, Digia gives you certain additional
** License version 2.1 as published by the Free Software Foundation and ** rights. These rights are described in the Digia Qt LGPL Exception
** 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
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** 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"

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). ** This file is part of Qt Creator.
**
** Contact: http://www.qt-project.org/
** **
** 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 ** 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 ** In addition, as a special exception, Digia gives you certain additional
** License version 2.1 as published by the Free Software Foundation and ** rights. These rights are described in the Digia Qt LGPL Exception
** 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
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** 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 #ifndef QTLOCKEDFILE_H
#define 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). ** This file is part of Qt Creator.
**
** Contact: http://www.qt-project.org/
** **
** 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 ** 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 ** In addition, as a special exception, Digia gives you certain additional
** License version 2.1 as published by the Free Software Foundation and ** rights. These rights are described in the Digia Qt LGPL Exception
** 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
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** 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"
@@ -96,6 +95,7 @@ bool QtLockedFile::unlock()
} }
m_lock_mode = NoLock; m_lock_mode = NoLock;
remove();
return true; 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). ** This file is part of Qt Creator.
**
** Contact: http://www.qt-project.org/
** **
** 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 ** 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 ** In addition, as a special exception, Digia gives you certain additional
** License version 2.1 as published by the Free Software Foundation and ** rights. These rights are described in the Digia Qt LGPL Exception
** 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
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** 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"
@@ -50,7 +49,7 @@ static QString errorCodeToString(DWORD errorCode)
if (data != 0) if (data != 0)
LocalFree(data); LocalFree(data);
if (result.endsWith('\n')) if (result.endsWith(QLatin1Char('\n')))
result.truncate(result.length() - 1); result.truncate(result.length() - 1);
return result; return result;
@@ -168,6 +167,7 @@ bool QtLockedFile::unlock()
} }
m_lock_mode = QtLockedFile::NoLock; m_lock_mode = QtLockedFile::NoLock;
remove();
return true; return true;
} }

View File

@@ -1,5 +1,5 @@
This is the src directory of the QtSingleApplication solution 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. 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). ** This file is part of Qt Creator.
**
** Contact: http://www.qt-project.org/
** **
** 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 ** 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 ** In addition, as a special exception, Digia gives you certain additional
** License version 2.1 as published by the Free Software Foundation and ** rights. These rights are described in the Digia Qt LGPL Exception
** 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
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** 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" #include "qtlocalpeer.h"
@@ -47,7 +46,31 @@ static PProcessIdToSessionId pProcessIdToSessionId = 0;
namespace SharedTools { 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) QtLocalPeer::QtLocalPeer(QObject *parent, const QString &appId)
: QObject(parent), id(appId) : QObject(parent), id(appId)
@@ -55,26 +78,7 @@ QtLocalPeer::QtLocalPeer(QObject *parent, const QString &appId)
if (id.isEmpty()) if (id.isEmpty())
id = QCoreApplication::applicationFilePath(); //### On win, check if this returns .../argv[0] without casefolding; .\MYAPP == .\myapp on Win id = QCoreApplication::applicationFilePath(); //### On win, check if this returns .../argv[0] without casefolding; .\MYAPP == .\myapp on Win
QByteArray idc = id.toUtf8(); socketName = appSessionId(id);
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
server = new QLocalServer(this); server = new QLocalServer(this);
QString lockName = QDir(QDir::tempPath()).absolutePath() QString lockName = QDir(QDir::tempPath()).absolutePath()
+ QLatin1Char('/') + socketName + QLatin1Char('/') + socketName
@@ -100,7 +104,7 @@ bool QtLocalPeer::isClient()
return false; return false;
} }
bool QtLocalPeer::sendMessage(const QString &message, int timeout) bool QtLocalPeer::sendMessage(const QString &message, int timeout, bool block)
{ {
if (!isClient()) if (!isClient())
return false; return false;
@@ -130,6 +134,8 @@ bool QtLocalPeer::sendMessage(const QString &message, int timeout)
bool res = socket.waitForBytesWritten(timeout); bool res = socket.waitForBytesWritten(timeout);
res &= socket.waitForReadyRead(timeout); // wait for ack res &= socket.waitForReadyRead(timeout); // wait for ack
res &= (socket.read(qstrlen(ack)) == ack); res &= (socket.read(qstrlen(ack)) == ack);
if (block) // block until peer disconnects
socket.waitForDisconnected(-1);
return res; return res;
} }
@@ -140,8 +146,11 @@ void QtLocalPeer::receiveConnection()
return; return;
// Why doesn't Qt have a blocking stream that takes care of this shait??? // Why doesn't Qt have a blocking stream that takes care of this shait???
while (socket->bytesAvailable() < static_cast<int>(sizeof(quint32))) while (socket->bytesAvailable() < static_cast<int>(sizeof(quint32))) {
socket->waitForReadyRead(); if (!socket->isValid()) // stale request
return;
socket->waitForReadyRead(1000);
}
QDataStream ds(socket); QDataStream ds(socket);
QByteArray uMsg; QByteArray uMsg;
quint32 remaining; quint32 remaining;
@@ -166,8 +175,7 @@ void QtLocalPeer::receiveConnection()
QString message = QString::fromUtf8(uMsg.constData(), uMsg.size()); QString message = QString::fromUtf8(uMsg.constData(), uMsg.size());
socket->write(ack, qstrlen(ack)); socket->write(ack, qstrlen(ack));
socket->waitForBytesWritten(1000); socket->waitForBytesWritten(1000);
delete socket; emit messageReceived(message, socket); // ##(might take a long time to return)
emit messageReceived(message); // ##(might take a long time to return)
} }
} // namespace SharedTools } // 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). ** This file is part of Qt Creator.
**
** Contact: http://www.qt-project.org/
** **
** 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 ** 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 ** In addition, as a special exception, Digia gives you certain additional
** License version 2.1 as published by the Free Software Foundation and ** rights. These rights are described in the Digia Qt LGPL Exception
** 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
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** 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 <QLocalServer>
#include <QLocalSocket> #include <QLocalSocket>
@@ -43,12 +42,13 @@ class QtLocalPeer : public QObject
public: public:
explicit QtLocalPeer(QObject *parent = 0, const QString &appId = QString()); explicit QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
bool isClient(); bool isClient();
bool sendMessage(const QString &message, int timeout); bool sendMessage(const QString &message, int timeout, bool block);
QString applicationId() const QString applicationId() const
{ return id; } { return id; }
static QString appSessionId(const QString &appId);
Q_SIGNALS: Q_SIGNALS:
void messageReceived(const QString &message); void messageReceived(const QString &message, QObject *socket);
protected Q_SLOTS: protected Q_SLOTS:
void receiveConnection(); void receiveConnection();
@@ -58,9 +58,6 @@ protected:
QString socketName; QString socketName;
QLocalServer* server; QLocalServer* server;
QtLockedFile lockFile; QtLockedFile lockFile;
private:
static const char* ack;
}; };
} // namespace SharedTools } // 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). ** This file is part of Qt Creator.
**
** Contact: http://www.qt-project.org/
** **
** 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 ** 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 ** In addition, as a special exception, Digia gives you certain additional
** License version 2.1 as published by the Free Software Foundation and ** rights. These rights are described in the Digia Qt LGPL Exception
** 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
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** 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 "qtsingleapplication.h"
#include "qtlocalpeer.h" #include "qtlocalpeer.h"
#include <QWidget> #include <qtlockedfile.h>
#include <QDir>
#include <QFileOpenEvent> #include <QFileOpenEvent>
#include <QSharedMemory>
#include <QWidget>
namespace SharedTools { namespace SharedTools {
void QtSingleApplication::sysInit(const QString &appId) static const int instancesSize = 1024;
static QString instancesLockFilename(const QString &appSessionId)
{ {
actWin = 0; const QChar slash(QLatin1Char('/'));
firstPeer = new QtLocalPeer(this, appId); QString res = QDir::tempPath();
connect(firstPeer, SIGNAL(messageReceived(QString)), SIGNAL(messageReceived(QString))); if (!res.endsWith(slash))
pidPeer = new QtLocalPeer(this, appId + QLatin1Char('-') + QString::number(QCoreApplication::applicationPid(), 10)); res += slash;
connect(pidPeer, SIGNAL(messageReceived(QString)), SIGNAL(messageReceived(QString))); 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) QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv)
: QApplication(argc, argv) : QApplication(argc, argv),
firstPeer(-1),
pidPeer(0)
{ {
this->appId = appId; 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();
} }
QtSingleApplication::~QtSingleApplication()
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type)
: QApplication(argc, argv, type)
{ {
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) bool QtSingleApplication::event(QEvent *event)
{ {
@@ -104,31 +131,26 @@ bool QtSingleApplication::event(QEvent *event)
bool QtSingleApplication::isRunning(qint64 pid) bool QtSingleApplication::isRunning(qint64 pid)
{ {
if (pid == -1) if (pid == -1) {
return firstPeer->isClient(); pid = firstPeer;
if (pid == -1)
return false;
}
QtLocalPeer peer(this, appId + QLatin1Char('-') + QString::number(pid, 10)); QtLocalPeer peer(this, appId + QLatin1Char('-') + QString::number(pid, 10));
return peer.isClient(); return peer.isClient();
} }
void QtSingleApplication::initialize(bool)
{
firstPeer->isClient();
pidPeer->isClient();
}
bool QtSingleApplication::sendMessage(const QString &message, int timeout, qint64 pid) bool QtSingleApplication::sendMessage(const QString &message, int timeout, qint64 pid)
{ {
if (pid == -1) if (pid == -1) {
return firstPeer->sendMessage(message, timeout); pid = firstPeer;
if (pid == -1)
return false;
}
QtLocalPeer peer(this, appId + QLatin1Char('-') + QString::number(pid, 10)); QtLocalPeer peer(this, appId + QLatin1Char('-') + QString::number(pid, 10));
return peer.sendMessage(message, timeout); return peer.sendMessage(message, timeout, block);
}
QString QtSingleApplication::id() const
{
return firstPeer->applicationId();
} }
QString QtSingleApplication::applicationId() const QString QtSingleApplication::applicationId() const
@@ -136,16 +158,20 @@ QString QtSingleApplication::applicationId() const
return appId; return appId;
} }
void QtSingleApplication::setBlock(bool value)
{
block = value;
}
void QtSingleApplication::setActivationWindow(QWidget *aw, bool activateOnMessage) void QtSingleApplication::setActivationWindow(QWidget *aw, bool activateOnMessage)
{ {
actWin = aw; actWin = aw;
if (activateOnMessage) { if (!pidPeer)
connect(firstPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow())); return;
connect(pidPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow())); if (activateOnMessage)
} else { connect(pidPeer, SIGNAL(messageReceived(QString,QObject*)), this, SLOT(activateWindow()));
disconnect(firstPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow())); else
disconnect(pidPeer, SIGNAL(messageReceived(QString)), this, SLOT(activateWindow())); 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). ** This file is part of Qt Creator.
**
** Contact: http://www.qt-project.org/
** **
** 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 ** 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 ** In addition, as a special exception, Digia gives you certain additional
** License version 2.1 as published by the Free Software Foundation and ** rights. These rights are described in the Digia Qt LGPL Exception
** 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
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** 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 #ifndef QTSINGLEAPPLICATION_H
#define _SHAREDTOOLS_SINGLEAPPLICATION #define QTSINGLEAPPLICATION_H
#include <QApplication> #include <QApplication>
QT_FORWARD_DECLARE_CLASS(QSharedMemory)
namespace SharedTools { namespace SharedTools {
class QtLocalPeer; class QtLocalPeer;
@@ -42,50 +43,37 @@ class QtSingleApplication : public QApplication
Q_OBJECT Q_OBJECT
public: public:
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
QtSingleApplication(const QString &id, int &argc, char **argv); QtSingleApplication(const QString &id, int &argc, char **argv);
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) ~QtSingleApplication();
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
bool isRunning(qint64 pid = -1); bool isRunning(qint64 pid = -1);
QString id() const;
void setActivationWindow(QWidget* aw, bool activateOnMessage = true); void setActivationWindow(QWidget* aw, bool activateOnMessage = true);
QWidget* activationWindow() const; QWidget* activationWindow() const;
bool event(QEvent *event); bool event(QEvent *event);
QString applicationId() const; QString applicationId() const;
void setBlock(bool value);
public Q_SLOTS: public Q_SLOTS:
bool sendMessage(const QString &message, int timeout = 5000, qint64 pid = -1); bool sendMessage(const QString &message, int timeout = 5000, qint64 pid = -1);
void activateWindow(); 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: Q_SIGNALS:
void messageReceived(const QString &message); void messageReceived(const QString &message, QObject *socket);
void fileOpenRequest(const QString &file); void fileOpenRequest(const QString &file);
private: private:
void sysInit(const QString &appId = QString()); QString instancesFileName(const QString &appId);
QtLocalPeer *firstPeer;
qint64 firstPeer;
QSharedMemory *instances;
QtLocalPeer *pidPeer; QtLocalPeer *pidPeer;
QWidget *actWin; QWidget *actWin;
QString appId; QString appId;
bool block;
}; };
} // namespace SharedTools } // 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). ** This file is part of Qt Creator.
**
** Contact: http://www.qt-project.org/
** **
** 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 ** 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 ** In addition, as a special exception, Digia gives you certain additional
** License version 2.1 as published by the Free Software Foundation and ** rights. These rights are described in the Digia Qt LGPL Exception
** 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
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** 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 "qtsinglecoreapplication.h"
#include "qtlocalpeer.h" #include "qtlocalpeer.h"
@@ -37,6 +36,7 @@ QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
: QCoreApplication(argc, argv) : QCoreApplication(argc, argv)
{ {
peer = new QtLocalPeer(this); peer = new QtLocalPeer(this);
block = false;
connect(peer, SIGNAL(messageReceived(QString)), SIGNAL(messageReceived(QString))); connect(peer, SIGNAL(messageReceived(QString)), SIGNAL(messageReceived(QString)));
} }
@@ -57,7 +57,7 @@ bool QtSingleCoreApplication::isRunning()
bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout) 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(); return peer->applicationId();
} }
void QtSingleCoreApplication::setBlock(bool value)
{
block = value;
}
} // namespace SharedTools } // 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). ** This file is part of Qt Creator.
**
** Contact: http://www.qt-project.org/
** **
** 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 ** 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 ** In addition, as a special exception, Digia gives you certain additional
** License version 2.1 as published by the Free Software Foundation and ** rights. These rights are described in the Digia Qt LGPL Exception
** 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
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** 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> #include <QCoreApplication>
@@ -44,6 +43,7 @@ public:
bool isRunning(); bool isRunning();
QString id() const; QString id() const;
void setBlock(bool value);
public Q_SLOTS: public Q_SLOTS:
bool sendMessage(const QString &message, int timeout = 5000); bool sendMessage(const QString &message, int timeout = 5000);
@@ -55,6 +55,7 @@ Q_SIGNALS:
private: private:
QtLocalPeer* peer; QtLocalPeer* peer;
bool block;
}; };
} // namespace SharedTools } // 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) set(CMAKE_AUTOMOC TRUE)
include(GenerateExportHeader)
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
@@ -27,9 +28,9 @@ IF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
) )
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
if(SPARKLE_FOUND) if(SPARKLE_FOUND AND NOT BUILD_LIBRARIES_ONLY)
list (APPEND OS_SPECIFIC_LINK_LIBRARIES ${SPARKLE_LIBRARY}) list (APPEND OS_SPECIFIC_LINK_LIBRARIES ${SPARKLE_LIBRARY})
endif(SPARKLE_FOUND) endif()
set(3rdparty_SRC set(3rdparty_SRC
3rdparty/qtsingleapplication/qtsingleapplication.cpp 3rdparty/qtsingleapplication/qtsingleapplication.cpp
@@ -103,6 +104,7 @@ set(libsync_SRCS
mirall/quotainfo.cpp mirall/quotainfo.cpp
mirall/clientproxy.cpp mirall/clientproxy.cpp
mirall/syncrunfilelog.cpp mirall/syncrunfilelog.cpp
mirall/cookiejar.cpp
creds/dummycredentials.cpp creds/dummycredentials.cpp
creds/abstractcredentials.cpp creds/abstractcredentials.cpp
creds/credentialsfactory.cpp creds/credentialsfactory.cpp
@@ -115,19 +117,16 @@ if(TOKEN_AUTH_ONLY)
${libsync_SRCS} ${libsync_SRCS}
creds/tokencredentials.cpp creds/tokencredentials.cpp
) )
else() else()
set (libsync_SRCS set (libsync_SRCS
${libsync_SRCS} ${libsync_SRCS}
creds/httpcredentials.cpp creds/httpcredentials.cpp
creds/shibbolethcredentials.cpp creds/shibbolethcredentials.cpp
creds/shibboleth/shibbolethaccessmanager.cpp creds/shibboleth/shibbolethwebview.cpp
creds/shibboleth/shibbolethcookiejar.cpp creds/shibboleth/shibbolethrefresher.cpp
creds/shibboleth/shibbolethwebview.cpp creds/shibboleth/authenticationdialog.cpp
creds/shibboleth/shibbolethrefresher.cpp creds/shibboleth/shibbolethuserjob.cpp
creds/shibboleth/shibbolethconfigfile.cpp )
creds/shibboleth/authenticationdialog.cpp
creds/shibboleth/shibbolethuserjob.cpp
)
endif() endif()
IF( NOT WIN32 AND NOT APPLE ) IF( NOT WIN32 AND NOT APPLE )
@@ -195,25 +194,39 @@ if(NEON_FOUND)
endif() endif()
add_library(${synclib_NAME} SHARED ${libsync_SRCS} ${syncMoc}) add_library(${synclib_NAME} SHARED ${libsync_SRCS} ${syncMoc})
qt5_use_modules(${synclib_NAME} Widgets Network Xml WebKitWidgets Sql) 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()
qt5_use_modules(${synclib_NAME} Widgets Network Xml WebKitWidgets Sql)
endif()
set_target_properties( ${synclib_NAME} PROPERTIES set_target_properties( ${synclib_NAME} PROPERTIES
VERSION ${MIRALL_VERSION} VERSION ${MIRALL_VERSION}
SOVERSION ${MIRALL_SOVERSION} SOVERSION ${MIRALL_SOVERSION}
) )
set_target_properties( ${synclib_NAME} PROPERTIES
INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}/${APPLICATION_EXECUTABLE}" )
target_link_libraries(${synclib_NAME} ${libsync_LINK_TARGETS} ) target_link_libraries(${synclib_NAME} ${libsync_LINK_TARGETS} )
if(BUILD_LIBRARIES_ONLY) if(BUILD_LIBRARIES_ONLY)
add_library(${synclib_NAME}_static STATIC ${libsync_SRCS} ${syncMoc}) #add_library(${synclib_NAME}_static STATIC ${libsync_SRCS} ${syncMoc})
qt5_use_modules(${synclib_NAME}_static Widgets Network Xml WebKitWidgets Sql) #qt5_use_modules(${synclib_NAME}_static Widgets Network Xml Sql)
set_target_properties( ${synclib_NAME}_static PROPERTIES #set_target_properties( ${synclib_NAME}_static PROPERTIES
VERSION ${MIRALL_VERSION} # VERSION ${MIRALL_VERSION}
SOVERSION ${MIRALL_SOVERSION} # SOVERSION ${MIRALL_SOVERSION}
) #)
target_link_libraries(${synclib_NAME}_static ${libsync_LINK_TARGETS} ) #target_link_libraries(${synclib_NAME}_static ${libsync_LINK_TARGETS} )
endif() endif()
@@ -376,17 +389,17 @@ if (WITH_DBUS)
set(ADDITIONAL_APP_MODULES DBus) set(ADDITIONAL_APP_MODULES DBus)
endif(WITH_DBUS) endif(WITH_DBUS)
if(NOT BUILD_OWNCLOUD_OSX_BUNDLE) if(NOT BUILD_OWNCLOUD_OSX_BUNDLE AND NOT BUILD_LIBRARIES_ONLY)
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
if(NOT WIN32 AND NOT BUILD_LIBRARIES_ONLY) if(NOT WIN32)
file( GLOB _icons "${theme_dir}/colored/${ICON_APP_NAME}-icon-*.png" ) file( GLOB _icons "${theme_dir}/colored/${ICON_APP_NAME}-icon-*.png" )
foreach( _file ${_icons} ) foreach( _file ${_icons} )
string( REPLACE "${theme_dir}/colored/${ICON_APP_NAME}-icon-" "" _res ${_file} ) string( REPLACE "${theme_dir}/colored/${ICON_APP_NAME}-icon-" "" _res ${_file} )
string( REPLACE ".png" "" _res ${_res} ) string( REPLACE ".png" "" _res ${_res} )
install( FILES ${_file} RENAME ${ICON_APP_NAME}.png DESTINATION ${DATADIR}/icons/hicolor/${_res}x${_res}/apps ) install( FILES ${_file} RENAME ${ICON_APP_NAME}.png DESTINATION ${DATADIR}/icons/hicolor/${_res}x${_res}/apps )
endforeach( _file ) endforeach( _file )
endif(NOT WIN32 AND NOT BUILD_LIBRARIES_ONLY) endif(NOT WIN32)
install(FILES ${mirall_I18N} DESTINATION share/${APPLICATION_EXECUTABLE}/i18n) install(FILES ${mirall_I18N} DESTINATION share/${APPLICATION_EXECUTABLE}/i18n)
@@ -418,14 +431,17 @@ elseif(NOT BUILD_LIBRARIES_ONLY)
install(FILES ${qtkeychain_I18N} DESTINATION ${QM_DIR}) install(FILES ${qtkeychain_I18N} DESTINATION ${QM_DIR})
endif() endif()
add_library(updater STATIC ${updater_SRCS} ${updaterMoc})
target_link_libraries(updater ${synclib_NAME})
qt5_use_modules(updater Widgets Network Xml)
if(NOT BUILD_LIBRARIES_ONLY) if(NOT BUILD_LIBRARIES_ONLY)
add_library(updater STATIC ${updater_SRCS} ${updaterMoc})
target_link_libraries(updater ${synclib_NAME})
qt5_use_modules(updater Widgets Network Xml)
set_target_properties( ${APPLICATION_EXECUTABLE} PROPERTIES set_target_properties( ${APPLICATION_EXECUTABLE} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIRECTORY} RUNTIME_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIRECTORY}
) )
set_target_properties( ${APPLICATION_EXECUTABLE} PROPERTIES
INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}/${APPLICATION_EXECUTABLE}" )
target_link_libraries( ${APPLICATION_EXECUTABLE} ${QT_LIBRARIES} ) target_link_libraries( ${APPLICATION_EXECUTABLE} ${QT_LIBRARIES} )
target_link_libraries( ${APPLICATION_EXECUTABLE} ${synclib_NAME} ) target_link_libraries( ${APPLICATION_EXECUTABLE} ${synclib_NAME} )
target_link_libraries( ${APPLICATION_EXECUTABLE} updater ) target_link_libraries( ${APPLICATION_EXECUTABLE} updater )
@@ -464,10 +480,14 @@ endif()
set(owncloudcmd_NAME ${APPLICATION_EXECUTABLE}cmd) set(owncloudcmd_NAME ${APPLICATION_EXECUTABLE}cmd)
set(OWNCLOUDCMD_SRC owncloudcmd/simplesslerrorhandler.cpp owncloudcmd/owncloudcmd.cpp) set(OWNCLOUDCMD_SRC owncloudcmd/simplesslerrorhandler.cpp owncloudcmd/owncloudcmd.cpp)
if(NOT BUILD_LIBRARIES_ONLY) if(NOT BUILD_LIBRARIES_ONLY)
add_executable(${owncloudcmd_NAME} ${OWNCLOUDCMD_SRC}) add_executable(${owncloudcmd_NAME} ${OWNCLOUDCMD_SRC})
qt5_use_modules(${owncloudcmd_NAME} Network Sql) qt5_use_modules(${owncloudcmd_NAME} Network Sql)
set_target_properties(${owncloudcmd_NAME} PROPERTIES set_target_properties(${owncloudcmd_NAME} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIRECTORY} ) RUNTIME_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIRECTORY} )
set_target_properties(${owncloudcmd_NAME} PROPERTIES
INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}/${APPLICATION_EXECUTABLE}" )
target_link_libraries(${owncloudcmd_NAME} ${synclib_NAME}) target_link_libraries(${owncloudcmd_NAME} ${synclib_NAME})
endif() endif()

View File

@@ -17,6 +17,8 @@
#include <QObject> #include <QObject>
#include <csync.h> #include <csync.h>
#include "owncloudlib.h"
class QNetworkAccessManager; class QNetworkAccessManager;
class QNetworkReply; class QNetworkReply;
@@ -24,7 +26,7 @@ namespace Mirall
{ {
class Account; class Account;
class AbstractCredentials : public QObject class OWNCLOUDSYNC_EXPORT AbstractCredentials : public QObject
{ {
Q_OBJECT Q_OBJECT

View File

@@ -13,6 +13,7 @@
#include <QString> #include <QString>
#include "creds/credentialsfactory.h"
#ifdef TOKEN_AUTH_ONLY #ifdef TOKEN_AUTH_ONLY
#include "creds/tokencredentials.h" #include "creds/tokencredentials.h"
#else #else

View File

@@ -14,16 +14,18 @@
#ifndef MIRALL_CREDS_CREDENTIALS_FACTORY_H #ifndef MIRALL_CREDS_CREDENTIALS_FACTORY_H
#define MIRALL_CREDS_CREDENTIALS_FACTORY_H #define MIRALL_CREDS_CREDENTIALS_FACTORY_H
class AbstractCredentials; #include "owncloudlib.h"
class QString; class QString;
namespace Mirall namespace Mirall
{ {
class AbstractCredentials;
namespace CredentialsFactory namespace CredentialsFactory
{ {
AbstractCredentials* create(const QString& type); OWNCLOUDSYNC_EXPORT AbstractCredentials* create(const QString& type);
} // ns CredentialsFactory } // ns CredentialsFactory

View File

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

View File

@@ -30,7 +30,7 @@ class Job;
namespace Mirall namespace Mirall
{ {
class HttpCredentials : public AbstractCredentials class OWNCLOUDSYNC_EXPORT HttpCredentials : public AbstractCredentials
{ {
Q_OBJECT Q_OBJECT

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

@@ -35,7 +35,7 @@ void ShibbolethUserJob::start()
AbstractNetworkJob::start(); AbstractNetworkJob::start();
} }
void ShibbolethUserJob::finished() bool ShibbolethUserJob::finished()
{ {
bool success = false; bool success = false;
QVariantMap json = QtJson::parse(QString::fromUtf8(reply()->readAll()), success).toMap(); QVariantMap json = QtJson::parse(QString::fromUtf8(reply()->readAll()), success).toMap();
@@ -43,12 +43,13 @@ void ShibbolethUserJob::finished()
if (!success || json.isEmpty()) { if (!success || json.isEmpty()) {
qDebug() << "cloud/user: invalid JSON!"; qDebug() << "cloud/user: invalid JSON!";
emit userFetched(QString()); emit userFetched(QString());
return; return true;
} }
QString user = json.value("ocs").toMap().value("data").toMap().value("id").toString(); 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); emit userFetched(user);
return true;
} }

View File

@@ -36,7 +36,7 @@ signals:
void tryAgain(); void tryAgain();
private slots: private slots:
virtual void finished(); virtual bool finished();
}; };

View File

@@ -14,54 +14,53 @@
#include <QApplication> #include <QApplication>
#include <QDebug> #include <QDebug>
#include <QNetworkCookie> #include <QNetworkCookie>
#include <QNetworkCookieJar>
#include <QWebFrame> #include <QWebFrame>
#include <QWebPage> #include <QWebPage>
#include <QMessageBox> #include <QMessageBox>
#include <QAuthenticator> #include <QAuthenticator>
#include <QNetworkReply> #include <QNetworkReply>
#include "creds/shibboleth/shibbolethcookiejar.h"
#include "creds/shibboleth/shibbolethwebview.h"
#include "creds/shibboleth/authenticationdialog.h" #include "creds/shibboleth/authenticationdialog.h"
#include "creds/shibboleth/shibbolethwebview.h"
#include "creds/shibbolethcredentials.h"
#include "mirall/account.h" #include "mirall/account.h"
#include "mirall/logger.h"
#include "mirall/mirallaccessmanager.h" #include "mirall/mirallaccessmanager.h"
#include "mirall/theme.h" #include "mirall/theme.h"
namespace Mirall namespace Mirall
{ {
void ShibbolethWebView::setup(Account *account, ShibbolethCookieJar* jar) ShibbolethWebView::ShibbolethWebView(Account* account, QWidget* parent)
: QWebView(parent)
, _account(account)
, _accepted(false)
{ {
_account = account; // no minimize
MirallAccessManager* nm = new MirallAccessManager(this); setWindowFlags(Qt::Dialog);
// we need our own QNAM, but the we offload the SSL error handling to setAttribute(Qt::WA_DeleteOnClose);
// 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*)));
QWebPage* page = new QWebPage(this); QWebPage* page = new QWebPage(this);
page->setNetworkAccessManager(account->networkAccessManager());
jar->setParent(this);
connect(jar, SIGNAL (newCookiesForUrl (QList<QNetworkCookie>, QUrl)),
this, SLOT (onNewCookiesForUrl (QList<QNetworkCookie>, QUrl)));
connect(page, SIGNAL(loadStarted()), connect(page, SIGNAL(loadStarted()),
this, SLOT(slotLoadStarted())); this, SLOT(slotLoadStarted()));
connect(page, SIGNAL(loadFinished(bool)), connect(page, SIGNAL(loadFinished(bool)),
this, SLOT(slotLoadFinished(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()); page->mainFrame()->load(account->url());
this->setPage(page); this->setPage(page);
setWindowTitle(tr("%1 - Authenticate").arg(Theme::instance()->appNameGUI())); setWindowTitle(tr("%1 - Authenticate").arg(Theme::instance()->appNameGUI()));
}
ShibbolethWebView::ShibbolethWebView(Account* account, QWidget* parent) // If we have a valid cookie, it's most likely expired. We can use this as
: QWebView(parent) // as a criteria to tell the user why the browser window pops up
{ QNetworkCookie shibCookie = ShibbolethCredentials::findShibCookie(_account, ShibbolethCredentials::accountCookies(_account));
setup(account, new ShibbolethCookieJar(this)); 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() ShibbolethWebView::~ShibbolethWebView()
@@ -69,41 +68,24 @@ ShibbolethWebView::~ShibbolethWebView()
slotLoadFinished(); slotLoadFinished();
} }
ShibbolethWebView::ShibbolethWebView(Account* account, ShibbolethCookieJar* jar, QWidget* parent)
: QWebView(parent)
{
setup(account, jar);
}
void ShibbolethWebView::onNewCookiesForUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url) void ShibbolethWebView::onNewCookiesForUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url)
{ {
QList<QNetworkCookie> otherCookies; if (url.host() == _account->url().host()) {
QNetworkCookie shibCookie; QNetworkCookie shibCookie = ShibbolethCredentials::findShibCookie(_account, cookieList);
if (shibCookie != QNetworkCookie()) {
Q_FOREACH (const QNetworkCookie& cookie, cookieList) { Q_EMIT shibbolethCookieReceived(shibCookie, _account);
if (cookie.name().startsWith ("_shibsession_")) { accept();
if (shibCookie.name().isEmpty()) { close();
shibCookie = cookie; }
} else {
qWarning() << "Too many Shibboleth session cookies at once!";
}
} else {
otherCookies << cookie;
} }
}
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(); if (!_accepted) {
QWebView::hideEvent(event); Q_EMIT rejected();
}
QWebView::closeEvent(event);
} }
void ShibbolethWebView::slotLoadStarted() void ShibbolethWebView::slotLoadStarted()
@@ -142,4 +124,9 @@ void ShibbolethWebView::slotHandleAuthentication(QNetworkReply *reply, QAuthenti
} }
} }
void ShibbolethWebView::accept()
{
_accepted = true;
}
} // ns Mirall } // ns Mirall

View File

@@ -14,6 +14,7 @@
#ifndef MIRALL_WIZARD_SHIBBOLETH_WEB_VIEW_H #ifndef MIRALL_WIZARD_SHIBBOLETH_WEB_VIEW_H
#define MIRALL_WIZARD_SHIBBOLETH_WEB_VIEW_H #define MIRALL_WIZARD_SHIBBOLETH_WEB_VIEW_H
#include "owncloudlib.h"
#include <QList> #include <QList>
#include <QPointer> #include <QPointer>
#include <QWebView> #include <QWebView>
@@ -27,7 +28,7 @@ namespace Mirall
class ShibbolethCookieJar; class ShibbolethCookieJar;
class Account; class Account;
class ShibbolethWebView : public QWebView class OWNCLOUDSYNC_EXPORT ShibbolethWebView : public QWebView
{ {
Q_OBJECT Q_OBJECT
@@ -36,13 +37,11 @@ public:
ShibbolethWebView(Account *account, ShibbolethCookieJar* jar, QWidget* parent = 0); ShibbolethWebView(Account *account, ShibbolethCookieJar* jar, QWidget* parent = 0);
~ShibbolethWebView(); ~ShibbolethWebView();
protected: void closeEvent(QCloseEvent *event);
void hideEvent(QHideEvent* event);
Q_SIGNALS: Q_SIGNALS:
void shibbolethCookieReceived(const QNetworkCookie& cookie, Account* account); void shibbolethCookieReceived(const QNetworkCookie &cookie, Account *account);
void viewHidden(); void rejected();
void otherCookiesReceived(const QList<QNetworkCookie>& cookieList, const QUrl& url);
private Q_SLOTS: private Q_SLOTS:
void onNewCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url); void onNewCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
@@ -50,9 +49,13 @@ private Q_SLOTS:
void slotLoadFinished(bool success = true); void slotLoadFinished(bool success = true);
void slotHandleAuthentication(QNetworkReply*,QAuthenticator*); void slotHandleAuthentication(QNetworkReply*,QAuthenticator*);
protected:
void accept();
private: private:
void setup(Account *account, ShibbolethCookieJar* jar); void setup(Account *account, ShibbolethCookieJar* jar);
QPointer<Account> _account; QPointer<Account> _account;
bool _accepted;
}; };
} // ns Mirall } // ns Mirall

View File

@@ -16,18 +16,19 @@
#include <QSettings> #include <QSettings>
#include <QNetworkReply> #include <QNetworkReply>
#include <QMessageBox> #include <QMessageBox>
#include <qdebug.h> #include <QDebug>
#include "creds/shibbolethcredentials.h" #include "creds/shibbolethcredentials.h"
#include "creds/shibboleth/shibbolethaccessmanager.h"
#include "creds/shibboleth/shibbolethwebview.h" #include "creds/shibboleth/shibbolethwebview.h"
#include "creds/shibboleth/shibbolethrefresher.h" #include "creds/shibboleth/shibbolethrefresher.h"
#include "creds/shibboleth/shibbolethconfigfile.h" #include "creds/shibbolethcredentials.h"
#include "shibboleth/shibbolethuserjob.h" #include "shibboleth/shibbolethuserjob.h"
#include "creds/credentialscommon.h" #include "creds/credentialscommon.h"
#include "mirall/mirallaccessmanager.h"
#include "mirall/account.h" #include "mirall/account.h"
#include "mirall/theme.h" #include "mirall/theme.h"
#include "mirall/cookiejar.h"
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
#include <qt5keychain/keychain.h> #include <qt5keychain/keychain.h>
@@ -43,7 +44,9 @@ namespace Mirall
namespace 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, int shibboleth_redirect_callback(CSYNC* csync_ctx,
const char* uri) const char* uri)
@@ -65,7 +68,6 @@ int shibboleth_redirect_callback(CSYNC* csync_ctx,
Account *account = AccountManager::instance()->account(); Account *account = AccountManager::instance()->account();
ShibbolethCredentials* creds = qobject_cast<ShibbolethCredentials*>(account->credentials()); ShibbolethCredentials* creds = qobject_cast<ShibbolethCredentials*>(account->credentials());
if (!creds) { if (!creds) {
qDebug() << "Not a Shibboleth creds instance!"; qDebug() << "Not a Shibboleth creds instance!";
return 1; return 1;
@@ -84,18 +86,10 @@ int shibboleth_redirect_callback(CSYNC* csync_ctx,
ShibbolethCredentials::ShibbolethCredentials() ShibbolethCredentials::ShibbolethCredentials()
: AbstractCredentials(), : AbstractCredentials(),
_url(), _url(),
_shibCookie(),
_ready(false), _ready(false),
_stillValid(false), _stillValid(false),
_browser(0), _fetchJobInProgress(false),
_otherCookies() _browser(0)
{}
ShibbolethCredentials::ShibbolethCredentials(const QNetworkCookie& cookie, const QMap<QUrl, QList<QNetworkCookie> >& otherCookies)
: _shibCookie(cookie),
_ready(true),
_browser(0),
_otherCookies(otherCookies)
{} {}
void ShibbolethCredentials::syncContextPreInit(CSYNC* ctx) void ShibbolethCredentials::syncContextPreInit(CSYNC* ctx)
@@ -110,29 +104,11 @@ QByteArray ShibbolethCredentials::prepareCookieData() const
// have any way to get "session_key" module property from // have any way to get "session_key" module property from
// csync. Had we have it, then we could just append shibboleth // csync. Had we have it, then we could just append shibboleth
// cookies to the "session_key" value and set it in csync module. // cookies to the "session_key" value and set it in csync module.
QList<QNetworkCookie> cookies(AccountManager::instance()->account()->lastAuthCookies()); Account *account = AccountManager::instance()->account();
QMap<QString, QString> uniqueCookies; QList<QNetworkCookie> cookies = accountCookies(account);
cookies << _shibCookie; foreach(const QNetworkCookie &cookie, cookies) {
// Stuff cookies inside csync, then we can avoid the intermediate HTTP 401 reply cookiesAsString += cookie.toRawForm(QNetworkCookie::NameAndValueOnly) + QLatin1String("; ");
// 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 += "; ";
} }
return cookiesAsString.toLatin1(); return cookiesAsString.toLatin1();
@@ -150,9 +126,13 @@ void ShibbolethCredentials::syncContextPreStart (CSYNC* ctx)
bool ShibbolethCredentials::changed(AbstractCredentials* credentials) const 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; return true;
} }
@@ -169,17 +149,9 @@ QString ShibbolethCredentials::user() const
return _user; return _user;
} }
QNetworkCookie ShibbolethCredentials::cookie() const
{
return _shibCookie;
}
QNetworkAccessManager* ShibbolethCredentials::getQNAM() const QNetworkAccessManager* ShibbolethCredentials::getQNAM() const
{ {
ShibbolethAccessManager* qnam(new ShibbolethAccessManager(_shibCookie)); QNetworkAccessManager* qnam(new MirallAccessManager);
connect(this, SIGNAL(newCookie(QNetworkCookie)),
qnam, SLOT(setCookie(QNetworkCookie)));
connect(qnam, SIGNAL(finished(QNetworkReply*)), connect(qnam, SIGNAL(finished(QNetworkReply*)),
this, SLOT(slotReplyFinished(QNetworkReply*))); this, SLOT(slotReplyFinished(QNetworkReply*)));
return qnam; return qnam;
@@ -187,6 +159,10 @@ QNetworkAccessManager* ShibbolethCredentials::getQNAM() const
void ShibbolethCredentials::slotReplyFinished(QNetworkReply* r) void ShibbolethCredentials::slotReplyFinished(QNetworkReply* r)
{ {
if (!_browser.isNull()) {
return;
}
QVariant target = r->attribute(QNetworkRequest::RedirectionTargetAttribute); QVariant target = r->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (target.isValid()) { if (target.isValid()) {
_stillValid = false; _stillValid = false;
@@ -203,10 +179,16 @@ bool ShibbolethCredentials::ready() const
void ShibbolethCredentials::fetch(Account *account) void ShibbolethCredentials::fetch(Account *account)
{ {
if(_fetchJobInProgress) {
return;
}
if (_user.isEmpty()) { if (_user.isEmpty()) {
_user = account->credentialSetting(QLatin1String(userC)).toString(); _user = account->credentialSetting(QLatin1String(userC)).toString();
} }
if (_ready) { if (_ready) {
_fetchJobInProgress = false;
Q_EMIT fetched(); Q_EMIT fetched();
} else { } else {
if (account) { if (account) {
@@ -219,6 +201,7 @@ void ShibbolethCredentials::fetch(Account *account)
job->setProperty("account", QVariant::fromValue(account)); job->setProperty("account", QVariant::fromValue(account));
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*))); connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
job->start(); job->start();
_fetchJobInProgress = true;
} }
} }
@@ -230,44 +213,29 @@ bool ShibbolethCredentials::stillValid(QNetworkReply *reply)
void ShibbolethCredentials::persist(Account* account) void ShibbolethCredentials::persist(Account* account)
{ {
ShibbolethConfigFile cfg;
cfg.storeCookies(_otherCookies);
storeShibCookie(_shibCookie, account); storeShibCookie(_shibCookie, account);
if (!_user.isEmpty()) if (!_user.isEmpty()) {
account->setCredentialSetting(QLatin1String(userC), _user); account->setCredentialSetting(QLatin1String(userC), _user);
}
} }
// only used by Application::slotLogout(). Use invalidateAndFetch for normal usage // only used by Application::slotLogout(). Use invalidateAndFetch for normal usage
void ShibbolethCredentials::invalidateToken(Account *account) 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(); _shibCookie = QNetworkCookie();
storeShibCookie(_shibCookie, account); // store/erase cookie
// ### access to ctx missing, but might not be required at all // ### access to ctx missing, but might not be required at all
//csync_set_module_property(ctx, "session_key", ""); //csync_set_module_property(ctx, "session_key", "");
} }
void ShibbolethCredentials::disposeBrowser() void ShibbolethCredentials::onShibbolethCookieReceived(const QNetworkCookie& shibCookie, Account *account)
{ {
qDebug() << Q_FUNC_INFO; storeShibCookie(shibCookie, account);
disconnect(_browser, SIGNAL(viewHidden()), _shibCookie = shibCookie;
this, SLOT(slotBrowserHidden())); addToCookieJar(shibCookie);
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);
// Now fetch the user... // Now fetch the user...
// But we must first do a request to webdav so the session is enabled. // But we must first do a request to webdav so the session is enabled.
@@ -304,21 +272,22 @@ void ShibbolethCredentials::slotUserFetched(const QString &user)
_stillValid = true; _stillValid = true;
_ready = true; _ready = true;
_fetchJobInProgress = false;
Q_EMIT fetched(); Q_EMIT fetched();
} }
void ShibbolethCredentials::slotBrowserHidden() void ShibbolethCredentials::slotBrowserRejected()
{ {
disposeBrowser();
_ready = false; _ready = false;
_shibCookie = QNetworkCookie(); _fetchJobInProgress = false;
Q_EMIT fetched(); Q_EMIT fetched();
} }
void ShibbolethCredentials::invalidateAndFetch(Account* account) void ShibbolethCredentials::invalidateAndFetch(Account* account)
{ {
_ready = false; _ready = false;
_fetchJobInProgress = true;
// delete the credentials, then in the slot fetch them again (which will trigger browser) // delete the credentials, then in the slot fetch them again (which will trigger browser)
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName()); DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
@@ -335,6 +304,7 @@ void ShibbolethCredentials::slotInvalidateAndFetchInvalidateDone(QKeychain::Job*
connect (this, SIGNAL(fetched()), connect (this, SIGNAL(fetched()),
this, SLOT(onFetched())); this, SLOT(onFetched()));
_fetchJobInProgress = false;
// small hack to support the ShibbolethRefresher hack // small hack to support the ShibbolethRefresher hack
// we already rand fetch() with a valid account object, // we already rand fetch() with a valid account object,
// and hence know the url on refresh // and hence know the url on refresh
@@ -355,16 +325,17 @@ void ShibbolethCredentials::slotReadJobDone(QKeychain::Job *job)
if (job->error() == QKeychain::NoError) { if (job->error() == QKeychain::NoError) {
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(job); ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(job);
delete readJob->settings(); delete readJob->settings();
qDebug() << Q_FUNC_INFO;
QList<QNetworkCookie> cookies = QNetworkCookie::parseCookies(readJob->textData().toUtf8()); QList<QNetworkCookie> cookies = QNetworkCookie::parseCookies(readJob->textData().toUtf8());
if (cookies.count() > 0) { if (cookies.count() > 0) {
_shibCookie = cookies.first(); _shibCookie = cookies.first();
addToCookieJar(_shibCookie);
} }
// access
job->setSettings(account->settingsWithGroup(Theme::instance()->appName(), job)); job->setSettings(account->settingsWithGroup(Theme::instance()->appName(), job));
_ready = true; _ready = true;
_stillValid = true; _stillValid = true;
Q_EMIT newCookie(_shibCookie); _fetchJobInProgress = false;
Q_EMIT fetched(); Q_EMIT fetched();
} else { } else {
showLoginWindow(account); showLoginWindow(account);
@@ -373,24 +344,44 @@ void ShibbolethCredentials::slotReadJobDone(QKeychain::Job *job)
void ShibbolethCredentials::showLoginWindow(Account* account) void ShibbolethCredentials::showLoginWindow(Account* account)
{ {
if (_browser) { if (!_browser.isNull()) {
_browser->activateWindow(); _browser->activateWindow();
_browser->raise(); _browser->raise();
// FIXME On OS X this does not raise properly // FIXME On OS X this does not raise properly
return; return;
} }
ShibbolethConfigFile cfg; _browser = new ShibbolethWebView(account);
_browser = new ShibbolethWebView(account, cfg.createCookieJar());
connect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie, Account*)), connect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie, Account*)),
this, SLOT(onShibbolethCookieReceived(QNetworkCookie, Account*))); this, SLOT(onShibbolethCookieReceived(QNetworkCookie, Account*)));
connect(_browser, SIGNAL(viewHidden()), connect(_browser, SIGNAL(rejected()), this, SLOT(slotBrowserRejected()));
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)
_browser->show(); _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) void ShibbolethCredentials::storeShibCookie(const QNetworkCookie &cookie, Account *account)
{ {
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName()); WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
@@ -402,5 +393,24 @@ void ShibbolethCredentials::storeShibCookie(const QNetworkCookie &cookie, Accoun
job->start(); 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 } // ns Mirall

View File

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

View File

@@ -17,8 +17,6 @@
#include <QDebug> #include <QDebug>
#include <QNetworkReply> #include <QNetworkReply>
#include <QSettings> #include <QSettings>
#include <QInputDialog>
#include "mirall/account.h" #include "mirall/account.h"
#include "mirall/mirallaccessmanager.h" #include "mirall/mirallaccessmanager.h"
@@ -70,6 +68,7 @@ int getauth(const char *prompt,
} }
const char userC[] = "user"; const char userC[] = "user";
const char authenticationFailedC[] = "owncloud-authentication-failed";
} // ns } // ns
@@ -174,22 +173,13 @@ bool TokenCredentials::stillValid(QNetworkReply *reply)
{ {
return ((reply->error() != QNetworkReply::AuthenticationRequiredError) return ((reply->error() != QNetworkReply::AuthenticationRequiredError)
// returned if user or password is incorrect // returned if user or password is incorrect
&& (reply->error() != QNetworkReply::OperationCanceledError)); && (reply->error() != QNetworkReply::OperationCanceledError
|| !reply->property(authenticationFailedC).toBool()));
} }
QString TokenCredentials::queryPassword(bool *ok) QString TokenCredentials::queryPassword(bool *ok)
{ {
qDebug() << AccountManager::instance()->account()->state(); return QString();
if (ok) {
QString str = QInputDialog::getText(0, tr("Enter Password"),
tr("Please enter %1 password for user '%2':")
.arg(Theme::instance()->appNameGUI(), _user),
QLineEdit::Password, QString(), ok);
qDebug() << AccountManager::instance()->account()->state();
return str;
} else {
return QString();
}
} }
void TokenCredentials::invalidateToken(Account *account) void TokenCredentials::invalidateToken(Account *account)
@@ -221,6 +211,7 @@ void TokenCredentials::slotAuthentication(QNetworkReply* reply, QAuthenticator*
// instead of utf8 encoding. Instead, we send it manually. Thus, if we reach this signal, // instead of utf8 encoding. Instead, we send it manually. Thus, if we reach this signal,
// those credentials were invalid and we terminate. // those credentials were invalid and we terminate.
qDebug() << "Stop request: Authentication failed for " << reply->url().toString(); qDebug() << "Stop request: Authentication failed for " << reply->url().toString();
reply->setProperty(authenticationFailedC, true);
reply->close(); reply->close();
} }

View File

@@ -31,7 +31,7 @@ namespace Mirall
{ {
class TokenCredentialsAccessManager; class TokenCredentialsAccessManager;
class TokenCredentials : public AbstractCredentials class OWNCLOUDSYNC_EXPORT TokenCredentials : public AbstractCredentials
{ {
Q_OBJECT Q_OBJECT

View File

@@ -1,4 +1,5 @@
/* /*
*
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
* *
* This program is free software; you can redistribute it and/or modify * 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 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details. * for more details.
*/ */
#include <QtGlobal>
#include <signal.h> #include <signal.h>
#ifdef Q_OS_UNIX
#include <sys/time.h>
#include <sys/resource.h>
#endif
#include "mirall/application.h" #include "mirall/application.h"
#include "mirall/theme.h" #include "mirall/theme.h"
#include "mirall/utility.h" #include "mirall/utility.h"
@@ -51,6 +59,20 @@ int main(int argc, char **argv)
return 0; 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() // if handleStartup returns true, main()
// needs to terminate here, e.g. because // needs to terminate here, e.g. because
// the updater is triggered // the updater is triggered

View File

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

View File

@@ -22,6 +22,7 @@
#include <QSslCertificate> #include <QSslCertificate>
#include <QSslConfiguration> #include <QSslConfiguration>
#include <QSslError> #include <QSslError>
#include "utility.h"
class QSettings; class QSettings;
class QNetworkReply; class QNetworkReply;
@@ -33,8 +34,9 @@ namespace Mirall {
class AbstractCredentials; class AbstractCredentials;
class Account; class Account;
class QuotaInfo; class QuotaInfo;
class MirallAccessManager;
class AccountManager : public QObject { class OWNCLOUDSYNC_EXPORT AccountManager : public QObject {
Q_OBJECT Q_OBJECT
public: public:
static AccountManager *instance(); static AccountManager *instance();
@@ -63,7 +65,7 @@ public:
/** /**
* @brief This class represents an account on an ownCloud Server * @brief This class represents an account on an ownCloud Server
*/ */
class Account : public QObject { class OWNCLOUDSYNC_EXPORT Account : public QObject {
Q_OBJECT Q_OBJECT
public: public:
enum State { Disconnected = 0, /// no network connection enum State { Disconnected = 0, /// no network connection
@@ -142,6 +144,8 @@ public:
void clearCookieJar(); void clearCookieJar();
QNetworkAccessManager* networkAccessManager();
QuotaInfo *quotaInfo(); QuotaInfo *quotaInfo();
signals: signals:
void stateChanged(int state); void stateChanged(int state);

View File

@@ -114,7 +114,6 @@ AccountSettings::AccountSettings(QWidget *parent) :
connect(FolderMan::instance(), SIGNAL(folderListLoaded(Folder::Map)), connect(FolderMan::instance(), SIGNAL(folderListLoaded(Folder::Map)),
this, SLOT(setFolderList(Folder::Map))); this, SLOT(setFolderList(Folder::Map)));
setFolderList(FolderMan::instance()->map()); setFolderList(FolderMan::instance()->map());
} }
void AccountSettings::slotAccountChanged(Account *newAccount, Account *oldAccount) void AccountSettings::slotAccountChanged(Account *newAccount, Account *oldAccount)
@@ -140,28 +139,28 @@ void AccountSettings::slotAccountChanged(Account *newAccount, Account *oldAccoun
void AccountSettings::slotFolderActivated( const QModelIndex& indx ) void AccountSettings::slotFolderActivated( const QModelIndex& indx )
{ {
bool state = indx.isValid(); bool isValid = indx.isValid();
bool haveFolders = ui->_folderList->model()->rowCount() > 0; bool haveFolders = ui->_folderList->model()->rowCount() > 0;
ui->_buttonRemove->setEnabled(state); ui->_buttonRemove->setEnabled(isValid);
if( Theme::instance()->singleSyncFolder() ) { if( Theme::instance()->singleSyncFolder() ) {
// only one folder synced folder allowed. // only one folder synced folder allowed.
ui->_buttonAdd->setVisible(!haveFolders); ui->_buttonAdd->setVisible(!haveFolders);
} else { } else {
ui->_buttonAdd->setVisible(true); 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(); bool folderEnabled = _model->data( indx, FolderStatusDelegate::FolderSyncEnabled).toBool();
if ( folderEnabled ) { if ( folderEnabled ) {
ui->_buttonEnable->setText( tr( "Pause" ) ); ui->_buttonEnable->setText( tr( "Pause" ) );
} else { } else {
ui->_buttonEnable->setText( tr( "Resume" ) ); ui->_buttonEnable->setText( tr( "Resume" ) );
} }
ui->_buttonEnable->setEnabled(_account && _account->state() == Account::Connected); ui->_buttonEnable->setEnabled( _account && _account->state() == Account::Connected);
} }
} }
@@ -241,6 +240,10 @@ void AccountSettings::slotButtonsSetEnabled()
void AccountSettings::setGeneralErrors( const QStringList& errors ) void AccountSettings::setGeneralErrors( const QStringList& errors )
{ {
_generalErrors = errors; _generalErrors = errors;
if (_account) {
// this will update the message
slotAccountStateChanged(_account->state());
}
} }
void AccountSettings::folderToModelItem( QStandardItem *item, Folder *f ) void AccountSettings::folderToModelItem( QStandardItem *item, Folder *f )
@@ -265,6 +268,10 @@ void AccountSettings::folderToModelItem( QStandardItem *item, Folder *f )
// if the folder was disabled before, set the sync icon // if the folder was disabled before, set the sync icon
item->setData( theme->syncStateIcon( SyncResult::SyncRunning), FolderStatusDelegate::FolderStatusIconRole ); item->setData( theme->syncStateIcon( SyncResult::SyncRunning), FolderStatusDelegate::FolderStatusIconRole );
} // we keep the previous icon for the SyncPrepare state. } // 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 { } else {
// kepp the previous icon for the prepare phase. // kepp the previous icon for the prepare phase.
if( status == SyncResult::Problem) { if( status == SyncResult::Problem) {
@@ -357,7 +364,7 @@ void AccountSettings::slotResetCurrentFolder()
if( ret == QMessageBox::Yes ) { if( ret == QMessageBox::Yes ) {
FolderMan *folderMan = FolderMan::instance(); FolderMan *folderMan = FolderMan::instance();
Folder *f = folderMan->folder(alias); Folder *f = folderMan->folder(alias);
f->slotTerminateSync(true); f->slotTerminateSync();
f->wipe(); f->wipe();
folderMan->slotScheduleAllFolders(); folderMan->slotScheduleAllFolders();
} }
@@ -380,6 +387,7 @@ void AccountSettings::showConnectionLabel( const QString& message, const QString
if( _generalErrors.isEmpty() ) { if( _generalErrors.isEmpty() ) {
ui->connectLabel->setText( message ); ui->connectLabel->setText( message );
ui->connectLabel->setToolTip(tooltip); ui->connectLabel->setToolTip(tooltip);
ui->connectLabel->setStyleSheet(QString());
} else { } else {
const QString msg = _generalErrors.join(QLatin1String("\n")); const QString msg = _generalErrors.join(QLatin1String("\n"));
ui->connectLabel->setText( msg ); ui->connectLabel->setText( msg );
@@ -473,7 +481,7 @@ void AccountSettings::slotEnableCurrentFolder()
// message box can return at any time while the thread keeps running, // message box can return at any time while the thread keeps running,
// so better check again after the user has responded. // so better check again after the user has responded.
if ( f->isBusy() && terminate ) { if ( f->isBusy() && terminate ) {
f->slotTerminateSync(false); f->slotTerminateSync();
} }
folderMan->slotEnableFolder( alias, !folderEnabled ); folderMan->slotEnableFolder( alias, !folderEnabled );
@@ -628,8 +636,9 @@ void AccountSettings::slotSetProgress(const QString& folder, const Progress::Inf
item->setData( overallSyncString, FolderStatusDelegate::SyncProgressOverallString ); item->setData( overallSyncString, FolderStatusDelegate::SyncProgressOverallString );
int overallPercent = 0; int overallPercent = 0;
if( progress._totalSize > 0 ) { if( progress._totalFileCount > 0 ) {
overallPercent = qRound(double(completedSize)/double(progress._totalSize) * 100.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); item->setData( overallPercent, FolderStatusDelegate::SyncProgressOverallPercent);
} }
@@ -734,7 +743,7 @@ void AccountSettings::slotAccountStateChanged(int state)
ui->sslButton->updateAccountInfo(_account); ui->sslButton->updateAccountInfo(_account);
QUrl safeUrl(_account->url()); QUrl safeUrl(_account->url());
safeUrl.setPassword(QString()); // Remove the password from the URL to avoid showing it in the UI 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) { if (state == Account::Connected) {
QString user; QString user;
if (AbstractCredentials *cred = _account->credentials()) { if (AbstractCredentials *cred = _account->credentials()) {

View File

@@ -45,6 +45,8 @@
#include <QMenu> #include <QMenu>
#include <QMessageBox> #include <QMessageBox>
class QSocket;
namespace Mirall { namespace Mirall {
namespace { namespace {
@@ -64,14 +66,12 @@ static const char optionsC[] =
QString applicationTrPath() QString applicationTrPath()
{ {
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) #if defined(Q_OS_WIN)
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
return QApplication::applicationDirPath(); 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 #endif
} }
} }
@@ -79,7 +79,7 @@ QString applicationTrPath()
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
Application::Application(int &argc, char **argv) : Application::Application(int &argc, char **argv) :
SharedTools::QtSingleApplication(argc, argv), SharedTools::QtSingleApplication(Theme::instance()->appName() ,argc, argv),
_gui(0), _gui(0),
_theme(Theme::instance()), _theme(Theme::instance()),
_helpOnly(false), _helpOnly(false),
@@ -99,14 +99,13 @@ Application::Application(int &argc, char **argv) :
//no need to waste time; //no need to waste time;
if ( _helpOnly ) return; if ( _helpOnly ) return;
initialize();
if (isRunning()) if (isRunning())
return; return;
setupLogging(); setupLogging();
setupTranslations(); setupTranslations();
connect( this, SIGNAL(messageReceived(QString)), SLOT(slotParseOptions(QString))); connect( this, SIGNAL(messageReceived(QString, QObject*)), SLOT(slotParseOptions(QString, QObject*)));
Account *account = Account::restore(); Account *account = Account::restore();
if (account) { if (account) {
@@ -139,6 +138,10 @@ Application::Application(int &argc, char **argv) :
this, SLOT(slotAccountChanged(Account*,Account*))); this, SLOT(slotAccountChanged(Account*,Account*)));
// startup procedure. // startup procedure.
connect(&_checkConnectionTimer, SIGNAL(timeout()), this, SLOT(slotCheckConnection()));
_checkConnectionTimer.setInterval(32 * 1000); // check for connection every 32 seconds.
_checkConnectionTimer.start();
// Also check immediatly
QTimer::singleShot( 0, this, SLOT( slotCheckConnection() )); QTimer::singleShot( 0, this, SLOT( slotCheckConnection() ));
if( cfg.skipUpdateCheck() ) { if( cfg.skipUpdateCheck() ) {
@@ -155,6 +158,7 @@ Application::Application(int &argc, char **argv) :
Application::~Application() Application::~Application()
{ {
delete AccountManager::instance()->account();
// qDebug() << "* Mirall shutdown"; // qDebug() << "* Mirall shutdown";
} }
@@ -226,8 +230,9 @@ void Application::slotCheckConnection()
if (account->state() == Account::InvalidCredidential if (account->state() == Account::InvalidCredidential
|| account->state() == Account::SignedOut) { || account->state() == Account::SignedOut) {
//Do not try to connect if we are logged out //Do not try to connect if we are logged out
if (!_userTriggeredConnect) if (!_userTriggeredConnect) {
return; return;
}
} }
if (_conValidator) if (_conValidator)
@@ -240,6 +245,8 @@ void Application::slotCheckConnection()
} else { } else {
// let gui open the setup wizard // let gui open the setup wizard
_gui->slotOpenSettingsDialog( true ); _gui->slotOpenSettingsDialog( true );
_checkConnectionTimer.stop(); // don't popup the wizard on interval;
} }
} }
@@ -269,6 +276,8 @@ void Application::slotToggleFolderman(int state)
folderMan->slotScheduleAllFolders(); folderMan->slotScheduleAllFolders();
break; break;
case Account::Disconnected: case Account::Disconnected:
_checkConnectionTimer.start();
// fall through
case Account::SignedOut: case Account::SignedOut:
case Account::InvalidCredidential: case Account::InvalidCredidential:
folderMan->setSyncEnabled(false); folderMan->setSyncEnabled(false);
@@ -289,6 +298,7 @@ void Application::slotConnectionValidatorResult(ConnectionValidator::Status stat
folderMan->setSyncEnabled(true); folderMan->setSyncEnabled(true);
// queue up the sync for all folders. // queue up the sync for all folders.
folderMan->slotScheduleAllFolders(); folderMan->slotScheduleAllFolders();
_checkConnectionTimer.stop();
} else { } else {
// if we have problems here, it's unlikely that syncing will work. // if we have problems here, it's unlikely that syncing will work.
FolderMan::instance()->setSyncEnabled(false); FolderMan::instance()->setSyncEnabled(false);
@@ -298,7 +308,6 @@ void Application::slotConnectionValidatorResult(ConnectionValidator::Status stat
if (_userTriggeredConnect) { if (_userTriggeredConnect) {
_userTriggeredConnect = false; _userTriggeredConnect = false;
} }
QTimer::singleShot(30*1000, this, SLOT(slotCheckConnection()));
} }
_gui->startupConnected( (status == ConnectionValidator::Connected), startupFails); _gui->startupConnected( (status == ConnectionValidator::Connected), startupFails);
@@ -316,6 +325,7 @@ void Application::slotownCloudWizardDone( int res )
} }
folderMan->setSyncEnabled( true ); folderMan->setSyncEnabled( true );
if( res == QDialog::Accepted ) { if( res == QDialog::Accepted ) {
_checkConnectionTimer.start();
slotCheckConnection(); slotCheckConnection();
} }
@@ -343,7 +353,7 @@ void Application::slotUseMonoIconsChanged(bool)
_gui->slotComputeOverallSyncStatus(); _gui->slotComputeOverallSyncStatus();
} }
void Application::slotParseOptions(const QString &opts) void Application::slotParseOptions(const QString &opts, QObject*)
{ {
QStringList options = opts.split(QLatin1Char('|')); QStringList options = opts.split(QLatin1Char('|'));
parseOptions(options); parseOptions(options);

View File

@@ -18,6 +18,7 @@
#include <QApplication> #include <QApplication>
#include <QPointer> #include <QPointer>
#include <QQueue> #include <QQueue>
#include <QTimer>
#include "qtsingleapplication.h" #include "qtsingleapplication.h"
@@ -27,9 +28,11 @@
#include "mirall/connectionvalidator.h" #include "mirall/connectionvalidator.h"
#include "mirall/progressdispatcher.h" #include "mirall/progressdispatcher.h"
#include "mirall/clientproxy.h" #include "mirall/clientproxy.h"
#include "mirall/folderman.h"
class QMessageBox; class QMessageBox;
class QSystemTrayIcon; class QSystemTrayIcon;
class QSocket;
namespace Mirall { namespace Mirall {
class Theme; class Theme;
@@ -68,7 +71,7 @@ signals:
void folderStateChanged(Folder*); void folderStateChanged(Folder*);
protected slots: protected slots:
void slotParseOptions( const QString& ); void slotParseOptions( const QString&, QObject* );
void slotCheckConnection(); void slotCheckConnection();
void slotConnectionValidatorResult(ConnectionValidator::Status); void slotConnectionValidatorResult(ConnectionValidator::Status);
void slotStartUpdateDetector(); void slotStartUpdateDetector();
@@ -103,6 +106,10 @@ private:
ClientProxy _proxy; ClientProxy _proxy;
QTimer _checkConnectionTimer;
FolderMan folderManager;
friend class ownCloudGui; // for _startupNetworkError friend class ownCloudGui; // for _startupNetworkError
}; };

View File

@@ -18,12 +18,13 @@
#include <QNetworkProxy> #include <QNetworkProxy>
#include <csync.h> #include <csync.h>
#include "utility.h"
namespace Mirall { namespace Mirall {
class MirallConfigFile; class MirallConfigFile;
class ClientProxy : public QObject class OWNCLOUDSYNC_EXPORT ClientProxy : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:

View File

@@ -14,6 +14,7 @@
#ifndef CONNECTIONVALIDATOR_H #ifndef CONNECTIONVALIDATOR_H
#define CONNECTIONVALIDATOR_H #define CONNECTIONVALIDATOR_H
#include "owncloudlib.h"
#include <QObject> #include <QObject>
#include <QStringList> #include <QStringList>
#include <QVariantMap> #include <QVariantMap>
@@ -23,7 +24,7 @@ namespace Mirall {
class Account; class Account;
class ConnectionValidator : public QObject class OWNCLOUDSYNC_EXPORT ConnectionValidator : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:

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

@@ -49,8 +49,11 @@ CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype);
#include <QTimer> #include <QTimer>
#include <QUrl> #include <QUrl>
#include <QDir> #include <QDir>
#ifndef TOKEN_AUTH_ONLY
#include <QMessageBox> #include <QMessageBox>
#include <QPushButton> #include <QPushButton>
#endif
namespace Mirall { namespace Mirall {
@@ -88,6 +91,14 @@ Folder::Folder(const QString &alias, const QString &path, const QString& secondP
bool Folder::init() bool Folder::init()
{ {
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;
}
QString url = Utility::toCSyncScheme(remoteUrl().toString()); QString url = Utility::toCSyncScheme(remoteUrl().toString());
QString localpath = path(); QString localpath = path();
@@ -298,7 +309,7 @@ void Folder::bubbleUpSyncResult()
SyncRunFileLog syncFileLog; SyncRunFileLog syncFileLog;
syncFileLog.start(path(), _engine->stopWatch() ); syncFileLog.start(path(), _engine ? _engine->stopWatch() : Utility::StopWatch() );
QElapsedTimer timer; QElapsedTimer timer;
timer.start(); timer.start();
@@ -463,7 +474,7 @@ void Folder::slotThreadTreeWalkResult(const SyncFileItemVector& items)
_syncResult.setSyncFileItemVector(items); _syncResult.setSyncFileItemVector(items);
} }
void Folder::slotTerminateSync(bool block) void Folder::slotTerminateSync()
{ {
qDebug() << "folder " << alias() << " Terminating!"; qDebug() << "folder " << alias() << " Terminating!";
@@ -473,14 +484,10 @@ void Folder::slotTerminateSync(bool block)
// Do not display an error message, user knows his own actions. // Do not display an error message, user knows his own actions.
// _errors.append( tr("The CSync thread terminated.") ); // _errors.append( tr("The CSync thread terminated.") );
// _csyncError = true; // _csyncError = true;
if (!block) { setSyncEnabled(false);
setSyncState(SyncResult::SyncAbortRequested); setSyncState(SyncResult::SyncAbortRequested);
return; return;
}
slotSyncFinished();
} }
setSyncEnabled(false);
} }
// This removes the csync File database // This removes the csync File database
@@ -648,9 +655,24 @@ void Folder::slotSyncFinished()
} }
emit syncStateChange(); 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 ); emit syncFinished( _syncResult );
} }
// the progress comes without a folder and the valid path set. Add that here // the progress comes without a folder and the valid path set. Add that here
// and hand the result over to the progress dispatcher. // and hand the result over to the progress dispatcher.
void Folder::slotTransmissionProgress(const Progress::Info &pi) void Folder::slotTransmissionProgress(const Progress::Info &pi)
@@ -670,6 +692,7 @@ void Folder::slotTransmissionProgress(const Progress::Info &pi)
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel) void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel)
{ {
#ifndef TOKEN_AUTH_ONLY
QString msg = direction == SyncFileItem::Down ? QString msg = direction == SyncFileItem::Down ?
tr("This sync would remove all the files in the local sync folder '%1'.\n" tr("This sync would remove all the files in the local sync folder '%1'.\n"
"If you or your administrator have reset your account on the server, choose " "If you or your administrator have reset your account on the server, choose "
@@ -689,7 +712,11 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *
*cancel = msgBox.clickedButton() == keepBtn; *cancel = msgBox.clickedButton() == keepBtn;
if (*cancel) { if (*cancel) {
wipe(); wipe();
// speed up next sync
_lastEtag = QString();
QTimer::singleShot(50, this, SLOT(slotPollTimerTimeout()));
} }
#endif
} }
SyncFileStatus Folder::fileStatus( const QString& fileName ) SyncFileStatus Folder::fileStatus( const QString& fileName )

View File

@@ -59,7 +59,7 @@ typedef enum SyncFileStatus_s {
} SyncFileStatus; } SyncFileStatus;
class Folder : public QObject class OWNCLOUDSYNC_EXPORT Folder : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -148,10 +148,8 @@ public slots:
/** /**
* terminate the current sync run * 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*); void slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool*);
@@ -183,6 +181,8 @@ private slots:
void slotThreadTreeWalkResult(const SyncFileItemVector& ); void slotThreadTreeWalkResult(const SyncFileItemVector& );
void slotEmitFinishedDelayed();
private: private:
bool init(); bool init();

View File

@@ -27,8 +27,10 @@
#include <shlobj.h> #include <shlobj.h>
#endif #endif
#include <QDesktopServices> #ifndef TOKEN_AUTH_ONLY
#include <QMessageBox> #include <QMessageBox>
#endif
#include <QtCore> #include <QtCore>
namespace Mirall { namespace Mirall {
@@ -39,13 +41,6 @@ FolderMan::FolderMan(QObject *parent) :
QObject(parent), QObject(parent),
_syncEnabled( true ) _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); _folderChangeSignalMapper = new QSignalMapper(this);
connect(_folderChangeSignalMapper, SIGNAL(mapped(const QString &)), connect(_folderChangeSignalMapper, SIGNAL(mapped(const QString &)),
this, SIGNAL(folderSyncStateChange(const QString &))); this, SIGNAL(folderSyncStateChange(const QString &)));
@@ -53,15 +48,14 @@ FolderMan::FolderMan(QObject *parent) :
_folderWatcherSignalMapper = new QSignalMapper(this); _folderWatcherSignalMapper = new QSignalMapper(this);
connect(_folderWatcherSignalMapper, SIGNAL(mapped(const QString&)), connect(_folderWatcherSignalMapper, SIGNAL(mapped(const QString&)),
this, SLOT(slotScheduleSync(const QString&))); this, SLOT(slotScheduleSync(const QString&)));
ne_sock_init();
Q_ASSERT(!_instance);
_instance = this;
} }
FolderMan *FolderMan::instance() FolderMan *FolderMan::instance()
{ {
if(!_instance) {
_instance = new FolderMan;
ne_sock_init();
}
return _instance; return _instance;
} }
@@ -69,6 +63,7 @@ FolderMan::~FolderMan()
{ {
qDeleteAll(_folderMap); qDeleteAll(_folderMap);
ne_sock_exit(); ne_sock_exit();
_instance = 0;
} }
Mirall::Folder::Map FolderMan::map() Mirall::Folder::Map FolderMan::map()
@@ -142,14 +137,19 @@ int FolderMan::setupFolders()
unloadAllFolders(); unloadAllFolders();
MirallConfigFile cfg;
QDir storageDir(cfg.configPath());
storageDir.mkpath(QLatin1String("folders"));
_folderConfigPath = cfg.configPath() + QLatin1String("folders");
QDir dir( _folderConfigPath ); QDir dir( _folderConfigPath );
dir.setFilter(QDir::Files); //We need to include hidden files just in case the alias starts with '.'
dir.setFilter(QDir::Files | QDir::Hidden);
QStringList list = dir.entryList(); QStringList list = dir.entryList();
foreach ( const QString& alias, list ) { foreach ( const QString& alias, list ) {
Folder *f = setupFolderFromConfigFile( alias ); Folder *f = setupFolderFromConfigFile( alias );
if( f ) { if( f ) {
registerFolderMonitor(f);
slotScheduleSync(alias); slotScheduleSync(alias);
emit( folderSyncStateChange( f->alias() ) ); emit( folderSyncStateChange( f->alias() ) );
} }
@@ -163,7 +163,8 @@ int FolderMan::setupFolders()
bool FolderMan::ensureJournalGone(const QString &localPath) bool FolderMan::ensureJournalGone(const QString &localPath)
{ {
// FIXME move this to UI, not libowncloudsync
#ifndef TOKEN_AUTH_ONLY
// remove old .csync_journal file // remove old .csync_journal file
QString stateDbFile = localPath+QLatin1String("/.csync_journal.db"); QString stateDbFile = localPath+QLatin1String("/.csync_journal.db");
while (QFile::exists(stateDbFile) && !QFile::remove(stateDbFile)) { while (QFile::exists(stateDbFile) && !QFile::remove(stateDbFile)) {
@@ -177,6 +178,7 @@ bool FolderMan::ensureJournalGone(const QString &localPath)
return false; return false;
} }
} }
#endif
return true; return true;
} }
@@ -297,6 +299,7 @@ Folder* FolderMan::setupFolderFromConfigFile(const QString &file) {
qDebug() << "Adding folder to Folder Map " << folder; qDebug() << "Adding folder to Folder Map " << folder;
_folderMap[alias] = folder; _folderMap[alias] = folder;
if (paused) { if (paused) {
folder->setSyncEnabled(!paused);
_disabledFolders.insert(folder); _disabledFolders.insert(folder);
} }
@@ -307,6 +310,8 @@ Folder* FolderMan::setupFolderFromConfigFile(const QString &file) {
connect(folder, SIGNAL(syncFinished(SyncResult)), SLOT(slotFolderSyncFinished(SyncResult))); connect(folder, SIGNAL(syncFinished(SyncResult)), SLOT(slotFolderSyncFinished(SyncResult)));
_folderChangeSignalMapper->setMapping( folder, folder->alias() ); _folderChangeSignalMapper->setMapping( folder, folder->alias() );
registerFolderMonitor(folder);
return folder; return folder;
} }
@@ -347,9 +352,10 @@ void FolderMan::terminateSyncProcess( const QString& alias )
if( ! folderAlias.isEmpty() && _folderMap.contains(folderAlias) ) { if( ! folderAlias.isEmpty() && _folderMap.contains(folderAlias) ) {
Folder *f = _folderMap[folderAlias]; Folder *f = _folderMap[folderAlias];
if( f ) { if( f ) {
f->slotTerminateSync(true); f->slotTerminateSync();
if(_currentSyncFolder == folderAlias ) if(_currentSyncFolder == folderAlias ) {
_currentSyncFolder.clear(); _currentSyncFolder.clear();
}
} }
} }
} }

View File

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

View File

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

View File

@@ -172,7 +172,7 @@ void FolderWatcherPrivate::slotReceivedNotification(int fd)
if (event->len > 0 && event->wd > -1) { if (event->len > 0 && event->wd > -1) {
// qDebug() << Q_FUNC_INFO << event->name; // qDebug() << Q_FUNC_INFO << event->name;
if (QByteArray(event->name).startsWith(".csync") || if (QByteArray(event->name).startsWith(".csync") ||
QByteArray(event->name) == ".owncloudsync.log") { QByteArray(event->name).startsWith(".owncloudsync.log")) {
// qDebug() << "ignore journal"; // qDebug() << "ignore journal";
} else { } else {
const QString p = _watches[event->wd]; const QString p = _watches[event->wd];

View File

@@ -136,7 +136,7 @@ bool FolderWizardLocalPath::isComplete() const
QString absCleanUserFolder = QDir::cleanPath(QDir(userInput).canonicalPath())+'/'; QString absCleanUserFolder = QDir::cleanPath(QDir(userInput).canonicalPath())+'/';
if( isOk && QDir::cleanPath(folderDir).startsWith(absCleanUserFolder) ) { if( isOk && QDir::cleanPath(folderDir).startsWith(absCleanUserFolder) ) {
qDebug() << "A already configured folder is child of the current selected"; 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.")); "folder is contained in the folder this link is pointing to."));
isOk = false; isOk = false;
} }

View File

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

View File

@@ -22,6 +22,8 @@
#include <QTextStream> #include <QTextStream>
#include <qmutex.h> #include <qmutex.h>
#include "utility.h"
namespace Mirall { namespace Mirall {
struct Log{ struct Log{
@@ -35,10 +37,11 @@ struct Log{
QString message; QString message;
}; };
class Logger : public QObject class OWNCLOUDSYNC_EXPORT Logger : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
void log(Log log); void log(Log log);
static void csyncLog( const QString& message ); static void csyncLog( const QString& message );
@@ -47,7 +50,6 @@ public:
const QList<Log>& logs() const {return _logs;} const QList<Log>& logs() const {return _logs;}
static Logger* instance(); static Logger* instance();
static void destroy();
void postGuiLog(const QString& title, const QString& message); void postGuiLog(const QString& title, const QString& message);
void postOptionalGuiLog(const QString& title, const QString& message); void postOptionalGuiLog(const QString& title, const QString& message);
@@ -67,14 +69,12 @@ signals:
public slots: public slots:
void enterNextLogFile(); void enterNextLogFile();
protected: private:
Logger(QObject* parent=0); Logger(QObject* parent=0);
~Logger();
QList<Log> _logs; QList<Log> _logs;
bool _showTime; bool _showTime;
bool _doLogging; bool _doLogging;
static Logger* _instance;
QFile _logFile; QFile _logFile;
bool _doFileFlush; bool _doFileFlush;
int _logExpire; int _logExpire;

View File

@@ -14,7 +14,9 @@
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QNetworkProxy> #include <QNetworkProxy>
#include <QAuthenticator> #include <QAuthenticator>
#include <QSslConfiguration>
#include "mirall/cookiejar.h"
#include "mirall/mirallaccessmanager.h" #include "mirall/mirallaccessmanager.h"
#include "mirall/utility.h" #include "mirall/utility.h"
@@ -24,12 +26,13 @@ namespace Mirall
MirallAccessManager::MirallAccessManager(QObject* parent) MirallAccessManager::MirallAccessManager(QObject* parent)
: QNetworkAccessManager (parent) : QNetworkAccessManager (parent)
{ {
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) && defined(Q_OS_MAC)
// FIXME Workaround http://stackoverflow.com/a/15707366/2941 https://bugreports.qt-project.org/browse/QTBUG-30434 // FIXME Workaround http://stackoverflow.com/a/15707366/2941 https://bugreports.qt-project.org/browse/QTBUG-30434
QNetworkProxy proxy = this->proxy(); QNetworkProxy proxy = this->proxy();
proxy.setHostName(" "); proxy.setHostName(" ");
setProxy(proxy); setProxy(proxy);
#endif #endif
setCookieJar(new CookieJar);
QObject::connect(this, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), QObject::connect(this, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
this, SLOT(slotProxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); this, SLOT(slotProxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
} }

View File

@@ -14,12 +14,13 @@
#ifndef MIRALL_ACCESS_MANAGER_H #ifndef MIRALL_ACCESS_MANAGER_H
#define MIRALL_ACCESS_MANAGER_H #define MIRALL_ACCESS_MANAGER_H
#include "owncloudlib.h"
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
namespace Mirall namespace Mirall
{ {
class MirallAccessManager : public QNetworkAccessManager class OWNCLOUDSYNC_EXPORT MirallAccessManager : public QNetworkAccessManager
{ {
Q_OBJECT Q_OBJECT

View File

@@ -22,7 +22,11 @@
#include "creds/abstractcredentials.h" #include "creds/abstractcredentials.h"
#include "creds/credentialsfactory.h" #include "creds/credentialsfactory.h"
#ifndef TOKEN_AUTH_ONLY
#include <QWidget> #include <QWidget>
#include <QHeaderView>
#endif
#include <QCoreApplication> #include <QCoreApplication>
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
@@ -30,7 +34,6 @@
#include <QSettings> #include <QSettings>
#include <QDebug> #include <QDebug>
#include <QNetworkProxy> #include <QNetworkProxy>
#include <QHeaderView>
#define DEFAULT_REMOTE_POLL_INTERVAL 30000 // default remote poll time in milliseconds #define DEFAULT_REMOTE_POLL_INTERVAL 30000 // default remote poll time in milliseconds
#define DEFAULT_MAX_LOG_LINES 20000 #define DEFAULT_MAX_LOG_LINES 20000
@@ -44,6 +47,7 @@ static const char monoIconsC[] = "monoIcons";
static const char optionalDesktopNoficationsC[] = "optionalDesktopNotifications"; static const char optionalDesktopNoficationsC[] = "optionalDesktopNotifications";
static const char skipUpdateCheckC[] = "skipUpdateCheck"; static const char skipUpdateCheckC[] = "skipUpdateCheck";
static const char geometryC[] = "geometry"; static const char geometryC[] = "geometry";
static const char timeoutC[] = "timeout";
static const char proxyHostC[] = "Proxy/host"; static const char proxyHostC[] = "Proxy/host";
static const char proxyTypeC[] = "Proxy/type"; static const char proxyTypeC[] = "Proxy/type";
@@ -100,6 +104,12 @@ bool MirallConfigFile::optionalDesktopNotifications() const
return settings.value(QLatin1String(optionalDesktopNoficationsC), true).toBool(); 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) void MirallConfigFile::setOptionalDesktopNotifications(bool show)
{ {
QSettings settings(configFile(), QSettings::IniFormat); QSettings settings(configFile(), QSettings::IniFormat);
@@ -109,20 +119,25 @@ void MirallConfigFile::setOptionalDesktopNotifications(bool show)
void MirallConfigFile::saveGeometry(QWidget *w) void MirallConfigFile::saveGeometry(QWidget *w)
{ {
#ifndef TOKEN_AUTH_ONLY
Q_ASSERT(!w->objectName().isNull()); Q_ASSERT(!w->objectName().isNull());
QSettings settings(configFile(), QSettings::IniFormat); QSettings settings(configFile(), QSettings::IniFormat);
settings.beginGroup(w->objectName()); settings.beginGroup(w->objectName());
settings.setValue(QLatin1String(geometryC), w->saveGeometry()); settings.setValue(QLatin1String(geometryC), w->saveGeometry());
settings.sync(); settings.sync();
#endif
} }
void MirallConfigFile::restoreGeometry(QWidget *w) void MirallConfigFile::restoreGeometry(QWidget *w)
{ {
#ifndef TOKEN_AUTH_ONLY
w->restoreGeometry(getValue(geometryC, w->objectName()).toByteArray()); w->restoreGeometry(getValue(geometryC, w->objectName()).toByteArray());
#endif
} }
void MirallConfigFile::saveGeometryHeader(QHeaderView *header) void MirallConfigFile::saveGeometryHeader(QHeaderView *header)
{ {
#ifndef TOKEN_AUTH_ONLY
if(!header) return; if(!header) return;
Q_ASSERT(!header->objectName().isNull()); Q_ASSERT(!header->objectName().isNull());
@@ -130,16 +145,19 @@ void MirallConfigFile::saveGeometryHeader(QHeaderView *header)
settings.beginGroup(header->objectName()); settings.beginGroup(header->objectName());
settings.setValue(QLatin1String(geometryC), header->saveState()); settings.setValue(QLatin1String(geometryC), header->saveState());
settings.sync(); settings.sync();
#endif
} }
void MirallConfigFile::restoreGeometryHeader(QHeaderView *header) void MirallConfigFile::restoreGeometryHeader(QHeaderView *header)
{ {
#ifndef TOKEN_AUTH_ONLY
if(!header) return; if(!header) return;
Q_ASSERT(!header->objectName().isNull()); Q_ASSERT(!header->objectName().isNull());
QSettings settings(configFile(), QSettings::IniFormat); QSettings settings(configFile(), QSettings::IniFormat);
settings.beginGroup(header->objectName()); settings.beginGroup(header->objectName());
header->restoreState(getValue(geometryC, header->objectName()).toByteArray()); header->restoreState(getValue(geometryC, header->objectName()).toByteArray());
#endif
} }
QVariant MirallConfigFile::getPolicySetting(const QString &setting, const QVariant& defaultValue) const QVariant MirallConfigFile::getPolicySetting(const QString &setting, const QVariant& defaultValue) const

View File

@@ -15,6 +15,7 @@
#ifndef MIRALLCONFIGFILE_H #ifndef MIRALLCONFIGFILE_H
#define MIRALLCONFIGFILE_H #define MIRALLCONFIGFILE_H
#include "owncloudlib.h"
#include <QSharedPointer> #include <QSharedPointer>
#include <QString> #include <QString>
#include <QVariant> #include <QVariant>
@@ -26,7 +27,7 @@ namespace Mirall {
class AbstractCredentials; class AbstractCredentials;
class MirallConfigFile class OWNCLOUDSYNC_EXPORT MirallConfigFile
{ {
public: public:
MirallConfigFile(); MirallConfigFile();
@@ -96,6 +97,8 @@ public:
bool optionalDesktopNotifications() const; bool optionalDesktopNotifications() const;
void setOptionalDesktopNotifications(bool show); void setOptionalDesktopNotifications(bool show);
int timeout() const;
void saveGeometry(QWidget *w); void saveGeometry(QWidget *w);
void restoreGeometry(QWidget *w); void restoreGeometry(QWidget *w);

View File

@@ -34,7 +34,6 @@
#include "creds/credentialsfactory.h" #include "creds/credentialsfactory.h"
#include "creds/abstractcredentials.h" #include "creds/abstractcredentials.h"
#include "creds/shibbolethcredentials.h"
Q_DECLARE_METATYPE(QTimer*) Q_DECLARE_METATYPE(QTimer*)
@@ -148,7 +147,7 @@ void AbstractNetworkJob::slotFinished()
_responseTimestamp = QString::fromAscii(_reply->rawHeader("Date")); _responseTimestamp = QString::fromAscii(_reply->rawHeader("Date"));
_duration = _durationTimer.elapsed(); _duration = _durationTimer.elapsed();
finished(); bool discard = finished();
AbstractCredentials *creds = _account->credentials(); AbstractCredentials *creds = _account->credentials();
if (!creds->stillValid(_reply) &&! _ignoreCredentialFailure if (!creds->stillValid(_reply) &&! _ignoreCredentialFailure
&& _account->state() != Account::InvalidCredidential) { && _account->state() != Account::InvalidCredidential) {
@@ -164,7 +163,9 @@ void AbstractNetworkJob::slotFinished()
creds->fetch(_account); creds->fetch(_account);
} }
} }
deleteLater(); if (discard) {
deleteLater();
}
} }
quint64 AbstractNetworkJob::duration() quint64 AbstractNetworkJob::duration()
@@ -228,7 +229,7 @@ void RequestEtagJob::start()
AbstractNetworkJob::start(); AbstractNetworkJob::start();
} }
void RequestEtagJob::finished() bool RequestEtagJob::finished()
{ {
if (reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) { if (reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) {
// Parse DAV response // Parse DAV response
@@ -247,6 +248,7 @@ void RequestEtagJob::finished()
} }
emit etagRetreived(etag); emit etagRetreived(etag);
} }
return true;
} }
/*********************************************************************************************/ /*********************************************************************************************/
@@ -265,9 +267,10 @@ void MkColJob::start()
AbstractNetworkJob::start(); AbstractNetworkJob::start();
} }
void MkColJob::finished() bool MkColJob::finished()
{ {
emit finished(reply()->error()); emit finished(reply()->error());
return true;
} }
/*********************************************************************************************/ /*********************************************************************************************/
@@ -297,7 +300,7 @@ void LsColJob::start()
AbstractNetworkJob::start(); AbstractNetworkJob::start();
} }
void LsColJob::finished() bool LsColJob::finished()
{ {
if (reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) { if (reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) {
// Parse DAV response // Parse DAV response
@@ -323,13 +326,20 @@ void LsColJob::finished()
} }
emit directoryListing(folders); emit directoryListing(folders);
} }
return true;
} }
/*********************************************************************************************/ /*********************************************************************************************/
namespace {
const char statusphpC[] = "status.php";
const char owncloudDirC[] = "owncloud/";
}
CheckServerJob::CheckServerJob(Account *account, bool followRedirect, QObject *parent) CheckServerJob::CheckServerJob(Account *account, bool followRedirect, QObject *parent)
: AbstractNetworkJob(account, QLatin1String("status.php") , parent) : AbstractNetworkJob(account, QLatin1String(statusphpC) , parent)
, _followRedirects(followRedirect) , _followRedirects(followRedirect)
, _subdirFallback(false)
, _redirectCount(0) , _redirectCount(0)
{ {
setIgnoreCredentialFailure(true); setIgnoreCredentialFailure(true);
@@ -364,7 +374,7 @@ bool CheckServerJob::installed(const QVariantMap &info)
return info.value(QLatin1String("installed")).toBool(); return info.value(QLatin1String("installed")).toBool();
} }
void CheckServerJob::finished() bool CheckServerJob::finished()
{ {
account()->setSslConfiguration(reply()->sslConfiguration()); account()->setSslConfiguration(reply()->sslConfiguration());
@@ -383,10 +393,20 @@ void CheckServerJob::finished()
resetTimeout(); resetTimeout();
setReply(getRequest(redirectUrl)); setReply(getRequest(redirectUrl));
setupConnections(reply()); setupConnections(reply());
return; return false;
} }
} }
// The serverInstalls to /owncloud. Let's try that if the file wasn't found
// at the original location
if ((reply()->error() == QNetworkReply::ContentNotFoundError) && (!_subdirFallback)) {
_subdirFallback = true;
setPath(QLatin1String(owncloudDirC)+QLatin1String(statusphpC));
start();
qDebug() << "Retrying with" << reply()->url();
return false;
}
bool success = false; bool success = false;
QVariantMap status = QtJson::parse(QString::fromUtf8(reply()->readAll()), success).toMap(); QVariantMap status = QtJson::parse(QString::fromUtf8(reply()->readAll()), success).toMap();
// empty or invalid response // empty or invalid response
@@ -401,7 +421,9 @@ void CheckServerJob::finished()
emit instanceFound(reply()->url(), status); emit instanceFound(reply()->url(), status);
} else { } else {
qDebug() << "No proper answer on " << requestedUrl; qDebug() << "No proper answer on " << requestedUrl;
emit instanceNotFound(reply());
} }
return true;
} }
/*********************************************************************************************/ /*********************************************************************************************/
@@ -451,7 +473,7 @@ QList<QByteArray> PropfindJob::properties() const
return _properties; return _properties;
} }
void PropfindJob::finished() bool PropfindJob::finished()
{ {
int http_result_code = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); int http_result_code = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
@@ -486,6 +508,7 @@ void PropfindJob::finished()
qDebug() << "Quota request *not* successful, http result code is" << http_result_code qDebug() << "Quota request *not* successful, http result code is" << http_result_code
<< (http_result_code == 302 ? reply()->header(QNetworkRequest::LocationHeader).toString() : QLatin1String("")); << (http_result_code == 302 ? reply()->header(QNetworkRequest::LocationHeader).toString() : QLatin1String(""));
} }
return true;
} }
/*********************************************************************************************/ /*********************************************************************************************/
@@ -502,9 +525,10 @@ void EntityExistsJob::start()
AbstractNetworkJob::start(); AbstractNetworkJob::start();
} }
void EntityExistsJob::finished() bool EntityExistsJob::finished()
{ {
emit exists(reply()); emit exists(reply());
return true;
} }
/*********************************************************************************************/ /*********************************************************************************************/
@@ -535,7 +559,7 @@ void CheckQuotaJob::start()
AbstractNetworkJob::start(); AbstractNetworkJob::start();
} }
void CheckQuotaJob::finished() bool CheckQuotaJob::finished()
{ {
if (reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) { if (reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) {
// Parse DAV response // Parse DAV response
@@ -560,6 +584,7 @@ void CheckQuotaJob::finished()
qint64 total = quotaUsedBytes + quotaAvailableBytes; qint64 total = quotaUsedBytes + quotaAvailableBytes;
emit quotaRetrieved(total, quotaUsedBytes); emit quotaRetrieved(total, quotaUsedBytes);
} }
return true;
} }
NetworkJobTimeoutPauser::NetworkJobTimeoutPauser(QNetworkReply *reply) NetworkJobTimeoutPauser::NetworkJobTimeoutPauser(QNetworkReply *reply)

View File

@@ -16,6 +16,7 @@
#ifndef NETWORKJOBS_H #ifndef NETWORKJOBS_H
#define NETWORKJOBS_H #define NETWORKJOBS_H
#include "owncloudlib.h"
#include <QObject> #include <QObject>
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QNetworkReply> #include <QNetworkReply>
@@ -46,7 +47,7 @@ private:
/** /**
* @brief The AbstractNetworkJob class * @brief The AbstractNetworkJob class
*/ */
class AbstractNetworkJob : public QObject { class OWNCLOUDSYNC_EXPORT AbstractNetworkJob : public QObject {
Q_OBJECT Q_OBJECT
public: public:
explicit AbstractNetworkJob(Account *account, const QString &path, QObject* parent = 0); explicit AbstractNetworkJob(Account *account, const QString &path, QObject* parent = 0);
@@ -62,8 +63,6 @@ public:
void setReply(QNetworkReply *reply); void setReply(QNetworkReply *reply);
QNetworkReply* reply() const { return _reply; } QNetworkReply* reply() const { return _reply; }
void setTimeout(qint64 msec);
void resetTimeout();
void setIgnoreCredentialFailure(bool ignore); void setIgnoreCredentialFailure(bool ignore);
bool ignoreCredentialFailure() const { return _ignoreCredentialFailure; } bool ignoreCredentialFailure() const { return _ignoreCredentialFailure; }
@@ -71,6 +70,9 @@ public:
QString responseTimestamp(); QString responseTimestamp();
quint64 duration(); quint64 duration();
public slots:
void setTimeout(qint64 msec);
void resetTimeout();
signals: signals:
void networkError(QNetworkReply *reply); void networkError(QNetworkReply *reply);
protected: protected:
@@ -87,7 +89,7 @@ protected:
QNetworkReply* headRequest(const QUrl &url); QNetworkReply* headRequest(const QUrl &url);
int maxRedirects() const { return 10; } int maxRedirects() const { return 10; }
virtual void finished() = 0; virtual bool finished() = 0;
QString _responseTimestamp; QString _responseTimestamp;
QElapsedTimer _durationTimer; QElapsedTimer _durationTimer;
quint64 _duration; quint64 _duration;
@@ -99,7 +101,7 @@ private slots:
private: private:
QNetworkReply* addTimer(QNetworkReply *reply); QNetworkReply* addTimer(QNetworkReply *reply);
bool _ignoreCredentialFailure; bool _ignoreCredentialFailure;
QNetworkReply *_reply; QPointer<QNetworkReply> _reply; // (QPointer because the NetworkManager may be destroyed before the jobs at exit)
Account *_account; Account *_account;
QString _path; QString _path;
QTimer _timer; QTimer _timer;
@@ -108,7 +110,7 @@ private:
/** /**
* @brief The EntityExistsJob class * @brief The EntityExistsJob class
*/ */
class EntityExistsJob : public AbstractNetworkJob { class OWNCLOUDSYNC_EXPORT EntityExistsJob : public AbstractNetworkJob {
Q_OBJECT Q_OBJECT
public: public:
explicit EntityExistsJob(Account *account, const QString &path, QObject* parent = 0); explicit EntityExistsJob(Account *account, const QString &path, QObject* parent = 0);
@@ -118,13 +120,13 @@ signals:
void exists(QNetworkReply*); void exists(QNetworkReply*);
private slots: private slots:
virtual void finished(); virtual bool finished();
}; };
/** /**
* @brief The LsColJob class * @brief The LsColJob class
*/ */
class LsColJob : public AbstractNetworkJob { class OWNCLOUDSYNC_EXPORT LsColJob : public AbstractNetworkJob {
Q_OBJECT Q_OBJECT
public: public:
explicit LsColJob(Account *account, const QString &path, QObject *parent = 0); explicit LsColJob(Account *account, const QString &path, QObject *parent = 0);
@@ -134,7 +136,7 @@ signals:
void directoryListing(const QStringList &items); void directoryListing(const QStringList &items);
private slots: private slots:
virtual void finished(); virtual bool finished();
}; };
/** /**
@@ -152,7 +154,7 @@ signals:
void result(const QVariantMap &values); void result(const QVariantMap &values);
private slots: private slots:
virtual void finished(); virtual bool finished();
private: private:
QList<QByteArray> _properties; QList<QByteArray> _properties;
@@ -161,7 +163,7 @@ private:
/** /**
* @brief The MkColJob class * @brief The MkColJob class
*/ */
class MkColJob : public AbstractNetworkJob { class OWNCLOUDSYNC_EXPORT MkColJob : public AbstractNetworkJob {
Q_OBJECT Q_OBJECT
public: public:
explicit MkColJob(Account *account, const QString &path, QObject *parent = 0); explicit MkColJob(Account *account, const QString &path, QObject *parent = 0);
@@ -171,13 +173,13 @@ signals:
void finished(QNetworkReply::NetworkError); void finished(QNetworkReply::NetworkError);
private slots: private slots:
virtual void finished(); virtual bool finished();
}; };
/** /**
* @brief The CheckServerJob class * @brief The CheckServerJob class
*/ */
class CheckServerJob : public AbstractNetworkJob { class OWNCLOUDSYNC_EXPORT CheckServerJob : public AbstractNetworkJob {
Q_OBJECT Q_OBJECT
public: public:
explicit CheckServerJob(Account *account, bool followRedirect = false, QObject *parent = 0); explicit CheckServerJob(Account *account, bool followRedirect = false, QObject *parent = 0);
@@ -189,14 +191,16 @@ public:
signals: signals:
void instanceFound(const QUrl&url, const QVariantMap &info); void instanceFound(const QUrl&url, const QVariantMap &info);
void instanceNotFound(QNetworkReply *reply);
void timeout(const QUrl&url); void timeout(const QUrl&url);
private slots: private slots:
virtual void finished(); virtual bool finished();
virtual void slotTimeout(); virtual void slotTimeout();
private: private:
bool _followRedirects; bool _followRedirects;
bool _subdirFallback;
int _redirectCount; int _redirectCount;
}; };
@@ -214,7 +218,7 @@ signals:
void etagRetreived(const QString &etag); void etagRetreived(const QString &etag);
private slots: private slots:
virtual void finished(); virtual bool finished();
}; };
/** /**
@@ -230,7 +234,8 @@ signals:
void quotaRetrieved(qint64 totalBytes, qint64 availableBytes); void quotaRetrieved(qint64 totalBytes, qint64 availableBytes);
private slots: private slots:
virtual void finished(); /** Return true if you want the job to be deleted after this slot has finished running. */
virtual bool finished();
}; };
} // namespace Mirall } // namespace Mirall

View File

@@ -146,6 +146,7 @@ void ownCloudGui::slotOpenPath(const QString &path)
void ownCloudGui::slotAccountStateChanged() void ownCloudGui::slotAccountStateChanged()
{ {
setupContextMenu(); setupContextMenu();
slotComputeOverallSyncStatus();
} }
void ownCloudGui::startupConnected( bool connected, const QStringList& fails ) void ownCloudGui::startupConnected( bool connected, const QStringList& fails )
@@ -160,6 +161,8 @@ void ownCloudGui::startupConnected( bool connected, const QStringList& fails )
} }
_startupFails = fails; // store that for the settings dialog once it appears. _startupFails = fails; // store that for the settings dialog once it appears.
if( !_settingsDialog.isNull() )
_settingsDialog->setGeneralErrors( _startupFails );
} }
@@ -171,6 +174,11 @@ void ownCloudGui::slotComputeOverallSyncStatus()
_tray->setToolTip(tr("Please sign in")); _tray->setToolTip(tr("Please sign in"));
return; return;
} }
if (a->state() == Account::Disconnected) {
_tray->setIcon(Theme::instance()->syncStateIcon( SyncResult::Unavailable, true));
_tray->setToolTip(tr("Disconnected from server"));
return;
}
} }
// display the info of the least successful sync (eg. not just display the result of the latest sync // display the info of the least successful sync (eg. not just display the result of the latest sync
QString trayMessage; QString trayMessage;

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