Comparar commits

...

344 Commits

Autor SHA1 Mensagem Data
Klaas Freitag 22e31b2232 Bump version to 2.1.0 beta1 2015-11-17 15:33:22 +01:00
Klaas Freitag 5ec4fd94e0 ActivityWidget: No progress indic. for non connected accounts. 2015-11-17 15:05:54 +01:00
Klaas Freitag c9ef4d5fa0 ActivityWidget: Detect new items in the list to refetch the activities.
On refresh, remove the activity list object from the models list.
2015-11-17 14:46:25 +01:00
Klaas Freitag 1cdf0e8597 ActivityWidget: Always combine the final activity list.
In cases where the activity app is not activated on the server, the
returned list of activities is empty, so it is better this way.
2015-11-17 14:46:25 +01:00
Daniel Molkentin 7ba88cc9e3 Merge remote-tracking branch 'origin/2.0' 2015-11-17 12:57:31 +01:00
Daniel Molkentin 914df32587 Documentation: Fix PDF logo, version number 2015-11-17 12:55:41 +01:00
Olivier Goffart e0f54428d0 ShareDialog: softer line separator (#3737) 2015-11-17 12:02:20 +01:00
Markus Goetz 52a11b0835 Activities: Fix on Mac #4083 2015-11-17 11:53:49 +01:00
Markus Goetz ef17dc6482 Connectivity: Improve log output 2015-11-17 11:02:53 +01:00
Markus Goetz 9978dc3f6c QNAM: Use invalid configuration instead of default configuration
For #3969 and others.
2015-11-17 11:02:53 +01:00
Olivier Goffart f618ed3dfb gui: Fix some icons in highdpi
QIcon does not need to use Theme::hidpiFileName because QIcon takes care
of the @2x images
2015-11-17 10:48:45 +01:00
Olivier Goffart ef915fb2e5 SharedDialog: Fix the delete icon on windows and mac (#3737) 2015-11-17 10:40:45 +01:00
Olivier Goffart 6e42405113 ShareDialog: remove the search button (#3737) 2015-11-17 10:24:35 +01:00
Olivier Goffart 11ef07c74a ActivityWidget: fix compiler warnings 2015-11-17 09:54:38 +01:00
Jenkins for ownCloud 486d7690c4 [tx-robot] updated from transifex 2015-11-17 02:19:08 -05:00
Klaas Freitag 8852911f67 Merge branch 'master' of github.com:owncloud/mirall 2015-11-16 18:16:58 +01:00
Klaas Freitag e38bc6eab8 AcitivityWidget: Moved timespan-in-words method to utility.
Also added a second parameter, fixed plural translation and added
a less-than-a-minute-ago term.
2015-11-16 18:08:25 +01:00
Olivier Goffart 459e200ac0 ShareDialog: add a QScrollArea (issue #4125 ) 2015-11-16 18:01:11 +01:00
Klaas Freitag c781155b60 General Settings page: Remove the add account button.
It is now in the toolbox on the account page.
2015-11-16 17:07:05 +01:00
Klaas Freitag 87aa1de67a Merge branch 'newactivity' 2015-11-16 17:02:05 +01:00
Klaas Freitag ccb871c30b ActivityWidget: Show the subject in the Tooltip.
the original text might be elided.
2015-11-16 16:44:52 +01:00
Klaas Freitag 74ed0b4f09 Merge pull request #4139 from owncloud/account_toolbox
AccountSettings: Add a toolbox button for the account specific actions.
2015-11-16 15:53:30 +01:00
Klaas Freitag becbb7b284 AccountSettings: Address jans suggestions in #4139
- Changed sequence of menu items
- lowercased entries
- removed the "Account" from entries, its in the toolbox button already
- added a little space between toolbox button label and the rectangle.
2015-11-16 15:50:32 +01:00
Klaas Freitag ff76a842d0 Added some documentation. 2015-11-16 15:38:08 +01:00
Klaas Freitag a56926b8d9 ActivityWidget: open local file in file manager if exists. 2015-11-16 15:31:24 +01:00
Olivier Goffart 0d21503ee5 ShareDialog: fix auto completion to actualy auto complete 2015-11-16 15:23:02 +01:00
Klaas Freitag 631cb095dd ActivityWidget: Show the local path in a tooltip.
Note that the activity has also entries of files that are not synced so
that not every activity entry has to have a local pendant.

Also, one activity entry can reference multiple files, so only the first
one is shown.
2015-11-16 15:07:02 +01:00
Klaas Freitag caba719950 Folderman: Added method to find local files for a rel. server path. 2015-11-16 15:04:59 +01:00
Roeland Douma 786b602c26 Merge pull request #4133 from owncloud/sharedialog_uit_improvements
[Sharedialog] Fix UI stuff
2015-11-16 13:36:00 +01:00
Jenkins for ownCloud f4bfce153d [tx-robot] updated from transifex 2015-11-16 02:18:48 -05:00
Jenkins for ownCloud e1ab50b17c [tx-robot] updated from transifex 2015-11-14 02:19:03 -05:00
Klaas Freitag 7e4c0bd515 AccountSettings: Add a toolbox button for the account specific actions.
Also move the 'Add Account' button from the General Tab, where it
is not properly found, to the new account toolbox.
2015-11-13 14:50:07 +01:00
Klaas Freitag ddcec2971e ActivityDelegate: Gray out font if account is not connected.
This gives a visual indication of the account not being connected
and as a result maybe outdated activity data.
2015-11-13 12:48:25 +01:00
Roeland Jago Douma 72d119a05f [Sharing] Delete animation when share is removed 2015-11-13 11:03:51 +01:00
Roeland Jago Douma d423cf2c7f [Sharedialog] Fix UI stuff
Implemented suggestions form
https://github.com/owncloud/client/issues/3737#issuecomment-156036279

* Removed Shares text
* Permissions now next to username
* Simplified permissions by default
* Button to get more detailed permissions
2015-11-13 10:27:26 +01:00
Jenkins for ownCloud 3d847b50cf [tx-robot] updated from transifex 2015-11-13 02:19:01 -05:00
Klaas Freitag 731a13cfd1 ActivityWidget: Take the account state (connected or not) in account.
Display the activity entries in a different mode if the account is not
longer connected.
2015-11-12 17:52:00 +01:00
Klaas Freitag 81296fae9d AccountManager: new method to return AccountStatePtr from the name.
It uses the Account displayName to destinguish.
2015-11-12 17:50:00 +01:00
Klaas Freitag aa38f7a4f2 ActivityWidget: implement removeAccount. 2015-11-12 15:39:07 +01:00
Jenkins for ownCloud bac69f9984 [tx-robot] updated from transifex 2015-11-12 02:19:14 -05:00
Klaas Freitag c46547592c sync excludes: Add .directory files to be ignored 2015-11-11 17:27:01 +01:00
Markus Goetz fd4a5100a6 NSIS: Include Qt bearer management DLLs #3969 2015-11-11 15:19:15 +01:00
Klaas Freitag ff4a8c9202 GeneralSettings: Remove references to protocolwidget.
The ProtocolWidget is now the Activitytab Widget
2015-11-11 14:49:11 +01:00
Christian Kamm c871d721fd Tray tooltip: Use aliasGui #4096 2015-11-11 14:35:56 +01:00
Christian Kamm 05d1cc9a94 Sharing: Fix crash with share deletion #4111
The problem was that Share could be deleted *before*
the OcsShareJob itself finished. Since Share was the
parent of the network job, its object would be deleted
too early.

In general, it's unnecessary to assign parents to the OcsJobs
because they delete themselves when finished.
2015-11-11 13:28:20 +01:00
Christian Kamm 196ee05fcc Share dialog: Initialize expected expire date #4075 2015-11-11 13:01:12 +01:00
Christian Kamm e50cfa4e1b Recent Activity: Don't reset for no reason #3889 2015-11-11 12:48:15 +01:00
Daniel Molkentin 3224a959a4 Forward-declare QModelIndex. Fixes Qt4 builds. 2015-11-11 11:52:10 +01:00
Christian Kamm 2ccb3648c7 Recent Activity: Filter metadata updates #3963 2015-11-11 11:19:04 +01:00
Christian Kamm 01aa647527 FolderMan: Fix infinite wait on pause #4093
If a folder was paused while being the next item in the scheduling
queue, the whole scheduling could get stuck.

This also fixes the progress information of paused folders possibly
getting stuck.
2015-11-11 10:59:04 +01:00
Christian Kamm eb3388de68 Fix OwnSql test
3993a7f636 added asserts for failing
prepare() calls
2015-11-11 09:42:31 +01:00
Christian Kamm beb970646b Fix csync_exclude test
The exclude file was reorganized in
b6aa18bfbc
2015-11-11 09:42:31 +01:00
Christian Kamm 25c177ca3b SyncJournalFileRecord: Remove unused mode field 2015-11-11 09:42:31 +01:00
Daniel Molkentin 1d9c591c08 Fix OS X compilation: use mode_t instead of __mode_t 2015-11-11 09:36:17 +01:00
Jenkins for ownCloud f753960add [tx-robot] updated from transifex 2015-11-11 02:19:02 -05:00
Klaas Freitag 5e98894a97 ActivityView: Add a progress indicator widget to indicate action. 2015-11-10 18:10:58 +01:00
Markus Goetz 15fe3b569b Merge pull request #4100 from mnutt/credentials-from-url
Populate account setup credentials from server URL
2015-11-10 16:12:34 +01:00
Klaas Freitag 0e0b6026fc Activity: Unify the GUI, and reactivate copy to clipboard for all. 2015-11-10 15:12:35 +01:00
Christian Kamm 17dd199cba Checksums: Treat more carefully in db #4034
In particular, preserve them on local rename or remote move.
2015-11-10 15:05:00 +01:00
Christian Kamm 8f7dbe71a1 CleanupPollsJobs: Preserve more journal data 2015-11-10 14:26:25 +01:00
Christian Kamm 4b5c3d8f09 Tray: Show settings dialog on click if it's not active
Before, you often had to click twice to bring the window
to the front, because the first click would close it.
2015-11-10 12:33:36 +01:00
Christian Kamm 9955b0756a Settings: Show first account page on startup #4036 2015-11-10 12:20:08 +01:00
Christian Kamm 76d9b9c0e2 Rename env variables to include unit #2939 2015-11-10 12:07:10 +01:00
Christian Kamm 175ad6fb77 Reflect read-only permissions in filesystem #3244 2015-11-10 10:14:25 +01:00
Christian Kamm 51896902e3 Silence warning by removing extra semicolon 2015-11-10 10:06:49 +01:00
Jenkins for ownCloud b55220905e [tx-robot] updated from transifex 2015-11-10 02:19:10 -05:00
Michael Nutt bd65eb32b7 SetupWizard: populate credentials from HTTP server URL
If a user enters a server URL in the form of
https://user:pass@example.com/, pre-populate the following credentials
page with those values.
2015-11-09 18:21:33 -05:00
Olivier Goffart b29d1e94b5 ShareDialog: fix autocompletion took the wrong user 2015-11-09 17:22:17 +01:00
Olivier Goffart b74e812671 Share dialog: a few layout adjustements 2015-11-09 17:22:17 +01:00
Olivier Goffart aa27b5db14 Discovery: silent static analysis warning
We do a check one line earlier that the size is smaller than the buffer
Then we don't need to call strncpy,  strcpy is enough
2015-11-09 17:22:17 +01:00
Markus Goetz 81e3a62360 Account: Show local path in tooltip 2015-11-09 16:39:08 +01:00
Jenkins for ownCloud b0dc264369 [tx-robot] updated from transifex 2015-11-09 02:22:38 -05:00
Jenkins for ownCloud ac3f179420 [tx-robot] updated from transifex 2015-11-08 02:18:58 -05:00
Jenkins for ownCloud d9af837974 [tx-robot] updated from transifex 2015-11-07 02:19:09 -05:00
Markus Goetz 4784b327e7 Folder Status: Use same fat ... icon as web 2015-11-06 16:10:50 +01:00
Markus Goetz 1a1541ecd6 macdeployqt: Forgot comma 2015-11-06 15:18:14 +01:00
Klaas Freitag cf9fec73cf ActivityView: Add a second treeview for sync issues.
So there are three views now: One displaying the server activities, one for
the sync protocol and a third one for ignored files and issues.
2015-11-06 11:43:43 +01:00
Klaas Freitag a1551ef6ab ActivityDelegate: Make the row height public accessible.
Now it can be used to be set on the other two treeviews.
2015-11-06 11:41:32 +01:00
Markus Goetz 0163839cfb OS X: Fix toolbar oddity #3719 2015-11-06 10:18:09 +01:00
Roeland Douma 914a942e33 Merge pull request #4055 from owncloud/user_group_sharing
User group sharing
2015-11-06 09:35:42 +01:00
Jenkins for ownCloud 5e482ad4f7 [tx-robot] updated from transifex 2015-11-06 02:19:01 -05:00
Markus Goetz 6901fc9e38 macdeployqt: Also copy bearer plugins
See #3449
2015-11-05 18:15:45 +01:00
Markus Goetz 0070835330 macdeployqt: Hack to make Qt 5.5 work 2015-11-05 17:19:49 +01:00
Roeland Jago Douma 6431a2aa46 [Sharing] Build sharee list on every search 2015-11-05 15:01:29 +01:00
Roeland Jago Douma 4cf2422a83 [Sharing] Clear completer on activation 2015-11-05 13:16:52 +01:00
Roeland Jago Douma 806ec98eab [Sharing] Properly delete widget 2015-11-05 13:10:32 +01:00
Roeland Jago Douma 20fd349e17 [Sharing] Filter sharee list properly
You can't share with a user/group that you've already shared with
You can't share with yourself
2015-11-05 12:30:34 +01:00
Markus Goetz dae724b21c QtVersionAbstraction: Quick not neeed on OS X 2015-11-05 11:35:42 +01:00
Roeland Jago Douma 3e4612a1f0 [Sharing] Reorganized sharedialog code
Now we have 1 simple dialog that includes 2 widgets.
* ShareLinkWidget (for link shares)
* ShareUserGroupWidget (for user/group shares)

The ShareUserGroupWidget is only included if the server version is >=
8.2.0

For <8.2.0 the old behavior is preserved
2015-11-05 09:58:16 +01:00
Jenkins for ownCloud 6052e49bcc [tx-robot] updated from transifex 2015-11-05 02:19:06 -05:00
Roeland Jago Douma 90cbd461ab [Sharing] Allow sharing with users/groups from desktop 2015-11-04 22:00:35 +01:00
Lukas Reschke 517f2ed03d Add coverity badge 2015-11-04 21:06:48 +01:00
Daniel Molkentin 5fccc25f36 Fix Qt4 build 2015-11-04 19:28:54 +01:00
Klaas Freitag cb1571c6c5 ActivityWidget: Rather use accountState pointer directly.
Do not use it via a smart pointer class.
2015-11-04 16:40:22 +01:00
Markus Goetz 99b0d659bd Merge pull request #4073 from RealRancor/backport_4052_2.0
Backport #4052 to 2.0
2015-11-04 16:32:34 +01:00
RealRancor 854264c3d2 Backport #4052 to 2.0 2015-11-04 15:55:07 +01:00
Markus Goetz d2a6cae695 Merge pull request #4052 from RealRancor/fix_autoupdate
Make registry key a code block in autoupdate docs.
2015-11-04 15:11:45 +01:00
Markus Goetz be9ed2f6a9 Merge pull request #4058 from owncloud/client-updates
some doc fixes & updates
2015-11-04 15:11:28 +01:00
Markus Goetz 3ee8beb8a3 Exclude: Add .nfs*
From eltrai at #4017
2015-11-04 15:06:05 +01:00
Jenkins for ownCloud f816e5e2af [tx-robot] updated from transifex 2015-11-04 08:32:32 -05:00
Jenkins for ownCloud 448d8bff18 [tx-robot] updated from transifex 2015-11-04 08:30:20 -05:00
Daniel Molkentin b82ffb52c7 Merge remote-tracking branch 'origin/2.0' 2015-11-04 14:25:14 +01:00
Klaas Freitag 3bccfb8993 ActivityView: Add information about the account. 2015-11-04 13:22:03 +01:00
Roeland Jago Douma 6fb4e59120 [Sharing] First step towards proper group sharing 2015-11-04 12:56:06 +01:00
Roeland Jago Douma 309be57a12 [Sharing] Add user/group sharing dialog
Dialog can now retrive current shares for path, set the permissions on
those shares and delete the share.
2015-11-04 12:53:07 +01:00
Roeland Jago Douma 37098c96f9 [Sharing] Add setpermission to sharing code
For user/group/remote shares we were just missing the setPermissions
functionality
2015-11-04 12:53:02 +01:00
Jenkins for ownCloud 03cc67a2b1 [tx-robot] updated from transifex 2015-11-04 02:19:04 -05:00
Klaas Freitag cb4fba7658 ActivityWidget: Created a delegate for prettier display of the activities 2015-11-03 17:54:37 +01:00
Jenkins for ownCloud 89734b95c4 [tx-robot] updated from transifex 2015-11-03 02:19:04 -05:00
Carla Schroder a59c3ef278 some doc fixes & updates 2015-11-02 11:18:31 -08:00
Klaas Freitag b600ac882a ActivityListModel: Add method to refresh one Account (WIP) 2015-11-02 17:52:04 +01:00
Klaas Freitag 71849c4372 ActivityListModel: Add the page and pagesize parameter to ocs query. 2015-11-02 17:51:12 +01:00
Klaas Freitag 9545af0d43 JSONApiJob: Add method to add additional query parameter. 2015-11-02 17:37:23 +01:00
Klaas Freitag 6c6ee358d4 ActivityListModel: Check if the account is connected when fetching more. 2015-11-02 16:39:33 +01:00
Klaas Freitag 060f4f291b SettingsDialog: Add a tab with the SyncProtocol to ActivityWidget. 2015-11-02 15:46:00 +01:00
Klaas Freitag 3fb43d2322 ActivityWidget UI: Remove the preconfigured tabs from the tabwidget.
It is better to create the tabs from the code in SettingsDialog.
2015-11-02 15:45:17 +01:00
Klaas Freitag 4895683bab ActivityWidget: Do a proper asynchronous model to display the activity. 2015-11-02 15:44:13 +01:00
Klaas Freitag 43800e3d1c Merge pull request #4049 from Naereen/patch-1
Reviewing, improved style, and a initializing message
2015-11-02 10:14:07 +01:00
Klaas Freitag 3b8e1dcd89 SettingsDialog: Make ActivityWidget a member. 2015-11-01 22:30:46 +01:00
Klaas Freitag 302d6b321e ActivityWidget: Add a job to fetch activities, Activity object added 2015-11-01 22:30:37 +01:00
Jenkins for ownCloud 3f85694394 [tx-robot] updated from transifex 2015-11-01 02:18:55 -05:00
RealRancor 8c5ef2f1c3 Make registry key a code block in autoupdate docs. 2015-10-31 19:05:21 +01:00
Lilian Besson aa1a2d1247 Reviewing, improved style, and a initializing message
- Add an "Initializing owncloud-client-nautilus extension" message
2015-10-31 13:07:18 +01:00
Olivier Goffart 3993a7f636 OwnSQL: add asserts in case of error that should not happen 2015-10-30 14:05:58 +01:00
Olivier Goffart aaf16ff0e8 SyncJournalDB, clear all the queries before closing the database 2015-10-30 14:03:08 +01:00
Olivier Goffart 16c078963b owncloudcmd: add --max-sync-retries #4037
And limit by default to 3 retries
2015-10-30 13:36:31 +01:00
Klaas Freitag 9279bcdba4 Add a tabwidget to Settings dialog for activity. 2015-10-30 13:26:27 +01:00
Olivier Goffart 0c467ef5b4 Sync engine: fix signal/slot connection 2015-10-30 13:21:34 +01:00
Olivier Goffart 49cd53ee44 FolderStatusModel: attempt to detect removed undecided files #3612 2015-10-30 12:43:33 +01:00
Olivier Goffart 0e6a463564 Discovery: Don't leak DiscoveryDirectoryResult in case of error
Also remove redundent Q_FUNC_INFO
2015-10-30 12:43:33 +01:00
Roeland Douma d38b190317 Merge pull request #4033 from owncloud/share_object
Add share manager and the share objects
2015-10-30 11:01:03 +01:00
Klaas Freitag 29558cb7bb Merge pull request #4040 from owncloud/phil-davis-changelog-master
ChangeLog typos that reverted in merge from 2.0
2015-10-30 10:36:38 +01:00
Jenkins for ownCloud d2cd237e25 [tx-robot] updated from transifex 2015-10-30 02:19:00 -04:00
Roeland Jago Douma c7b814337a Use proper QFlags
Now the ShareTypes and Permissions are part of the Share class (which is
a bit better abstracted away).
2015-10-29 21:47:47 +01:00
Phil Davis ced51813c7 ChangeLog typos that reverted in merge from 2.0
Hopefully the last place I need to submit this again :)
2015-10-29 23:35:48 +05:45
Roeland Jago Douma dd8d02b8ef Act properly if OCS endpoint returned an error (OCS error)
For now pass it on to the gui. So at least they know something is wrong.
2015-10-29 16:56:23 +01:00
Olivier Goffart c3cf6aef7d SyncEngine: Don't whipe the white list if the sync was aborted
Issue #4018
2015-10-29 16:47:39 +01:00
Olivier Goffart 38a8e5ee03 Discovery: conding style: use const references for function parameters 2015-10-29 16:47:36 +01:00
Klaas Freitag 46269dac4e Merge branch '2.0'
Conflicts:
	ChangeLog
2015-10-29 16:34:15 +01:00
Roeland Jago Douma 8c0297f688 Use QLatin1Char 2015-10-29 16:03:47 +01:00
Klaas Freitag bc5890d8b5 Add version suffix git. 2015-10-29 15:46:02 +01:00
Klaas Freitag ee65315520 Merge branch '2.0.2' into 2.0
Conflicts:
	ChangeLog
2015-10-29 15:44:56 +01:00
Roeland Jago Douma 12f7cfde87 Shares do not have parents
Also some pointer cleanups
2015-10-29 15:42:25 +01:00
Roeland Jago Douma 6d80f3d756 Proper foreach 2015-10-29 15:42:25 +01:00
Roeland Jago Douma b32f752d31 Properly cleanup OCS jobs 2015-10-29 15:42:25 +01:00
Roeland Jago Douma cf8be7de91 Proper const usage 2015-10-29 15:42:25 +01:00
Roeland Jago Douma 30a3498c22 Fix typos 2015-10-29 15:42:25 +01:00
Roeland Jago Douma 239603e24c Make sure enforced passwords are properly respected
Fixes for old and new servers
2015-10-29 15:42:25 +01:00
Roeland Jago Douma 390daed3de Added getPublicUpload to LinkShare
so the gui does not have to know abou the internal permissions
2015-10-29 15:42:25 +01:00
Roeland Jago Douma 918c06aba3 Add share manager and the share objects 2015-10-29 15:42:20 +01:00
Klaas Freitag 726be08917 Revert "Config: Use monochrome icons per default on MacOSX."
This reverts commit 546cab3f62.
For OEMs this patch causes an empty tray icon set.
2015-10-29 15:37:31 +01:00
Olivier Goffart a127debc54 Quota: handle special negative value for the quota #3940
Don't show a progress bar if there is an unkown or unlimited total
2015-10-29 14:33:29 +01:00
Olivier Goffart 6aa26654f6 Merge remote-tracking branch 'origin/2.0' 2015-10-29 12:44:28 +01:00
Olivier Goffart 0fde7f0e6b Propagator: Keep a meaningfull error with old server and invalid file names
We changed the discovery code not to ignore files whose filename contains
charachter invalid on windows. (Because newer versions of the server
supports them)
Servers older than 8.1 will just say "Bad Request" as an error and it's a
regression against previous client version. So keep nice error even with
older server.

Relates to #3736
2015-10-29 12:44:08 +01:00
Christian Kamm d9f8edd259 Hidden files: Consider .* hidden everywhere #4023
This seems to be the only place where we did this only on
non-windows OSes.
2015-10-29 11:59:46 +01:00
ckamm 251679253a Merge pull request #3951 from ckamm/checksum
Checksums stored in database #3735
2015-10-29 10:40:24 +01:00
Christian Kamm 64756c5dce --version also shows Qt version
That makes it much easier for people reporting bugs.
2015-10-29 09:48:36 +01:00
Christian Kamm 9788055147 Propagator: Add blacklisting of disk space errors #2939 2015-10-29 09:36:59 +01:00
Jenkins for ownCloud 4d7fde59c2 [tx-robot] updated from transifex 2015-10-29 02:18:59 -04:00
Daniel Molkentin 4737c16996 State application name in update notification
Fixes #4020
2015-10-28 20:45:57 +01:00
Markus Goetz c97dfbf60c ChangeLog: Mention propagator removal 2015-10-28 17:03:47 +01:00
Christian Kamm 496b1e907d Checksum: Don't lose it on metadata update #3735
Also improve tests.
2015-10-28 14:49:55 +01:00
Christian Kamm 566131209d Checksum: Fixes after review 2015-10-28 14:46:20 +01:00
Christian Kamm b7823dc648 Checksum: Put checksum type into separate column #3735 2015-10-28 14:46:20 +01:00
Olivier Goffart 6d28a1b645 Fix Qt4 compilation 2015-10-28 13:26:35 +01:00
Markus Goetz b6aa18bfbc sync-exclude.lst: More likely matching files first 2015-10-28 11:25:02 +01:00
Markus Goetz d91ffc216a Exclude: Add .fuse_hidden #3999
No matter if we sync hidden files or not, those are files we should not sync
2015-10-28 11:18:44 +01:00
Markus Goetz a6c9e8c5b4 Merge branch 'kill_legacy_propagator' 2015-10-28 11:06:50 +01:00
Markus Goetz 9337927722 legacy propagator: Remove more code 2015-10-28 10:59:02 +01:00
Christian Kamm c81b02c7d9 csync tests: Remove unused function 2015-10-28 10:04:15 +01:00
Christian Kamm 5ea09d2668 Checksum: Disallow ADLER32, use Adler32 #3735 2015-10-28 09:59:33 +01:00
Christian Kamm b9fc4c5994 Checksum: Fix recomputation when forced in cfg file #3735
Don't recompute the checksum on each upload when the server does not
advertise supporting checksums.
2015-10-28 09:56:39 +01:00
Christian Kamm f1b500d3e0 Checksum: Add env variables to disable #3735 2015-10-28 09:56:39 +01:00
Christian Kamm dff37e11eb Propagate: Store computed checksums in db during upload #3735 2015-10-28 09:56:39 +01:00
Christian Kamm b1387f801b Propagate: On download store checksum header in db #3735 2015-10-28 09:56:39 +01:00
Christian Kamm 60b2312ab6 SyncJournal: Add checksumHeader column to metadata table #3735 2015-10-28 09:56:39 +01:00
Christian Kamm 0354289795 Checksums: Improvement in async computation and validation #3735 2015-10-28 09:56:39 +01:00
Christian Kamm c11c35c459 Revert "In case of empty checksum type, emit validated."
This reverts commit b05ca526a4.

The checksum type setting should not matter for downloads.
2015-10-28 09:56:39 +01:00
Christian Kamm 7c5e70ac3c PropagateUpload: Fix double-emission of finished #3844 2015-10-28 09:53:54 +01:00
Christian Kamm d2e5ba123d Fix compile after pull request merge
It conflicted with the optimization in
f18b40f7e7
2015-10-28 09:53:06 +01:00
Klaas Freitag 0c9568f6dc Merge pull request #4004 from owncloud/fix_hidden_detection
Fix hidden detection
2015-10-28 09:28:35 +01:00
Olivier Goffart f1d48a9356 Folder Model: The item needs to be selectable for the currenIndex to appear selected
And we set the current index in AccountSettings::slotLinkActivated
2015-10-27 17:37:12 +01:00
Olivier Goffart 89f2a9e6dc Account Settings: A link should make sure all the parents are expanded 2015-10-27 17:37:12 +01:00
Klaas Freitag a203da3919 FolderStatusModel: Check for null argument at start. 2015-10-27 17:37:12 +01:00
Klaas Freitag 1c1ef52cf1 AccountSettings: Display a link for undecided dirs in the sub text.
This only works in case the index is known. If not, no link is
shown, but we wait for the next update of the model.
2015-10-27 17:37:12 +01:00
Klaas Freitag 40c82c5c36 AccountSettings: Add index to undecided folder to be able to select it. 2015-10-27 17:37:12 +01:00
Klaas Freitag 81f0c6535e Enable external links in the label. 2015-10-27 17:37:12 +01:00
Klaas Freitag 46558d79a5 Add slot to handle clicks on folder names. 2015-10-27 17:37:12 +01:00
Olivier Goffart e86b4203b9 IgnoreFiles: Fix the socket API would not load the new custom ignored files #3496
We did not flush or closed the file after having modified it from the UI.
So when the socket api was reloading it, it wouldn't be able to load
the newly added rules
2015-10-27 16:07:59 +01:00
Olivier Goffart 05dd9554f9 SocketApi: Fix returning ignore for the root item all the time 2015-10-27 16:06:38 +01:00
Olivier Goffart 30a0423f81 Dolphin integration: fix error icons 2015-10-27 15:19:10 +01:00
Olivier Goffart 26e1223f9a FolderStatusModel: reset also if a folder was renamed #4011 2015-10-27 13:51:56 +01:00
Olivier Goffart 84a04de7be Settings Dialog: don't put padding on the toolbar extension
Otherwise the extension just disapear with some styles (see Issue #3795)
2015-10-27 13:42:25 +01:00
Olivier Goffart 3ff7fa0092 Merge pull request #3997 from owncloud/phil-davis-patch-1
ChangeLog 2.0.2 minor typos for 2.0 branch
2015-10-27 12:58:59 +01:00
Olivier Goffart 3f2a2cb14b FolderDelegate: put the progressbar in place of the remote or local folder #3403 #3569
So the size of the delegate does not change
2015-10-27 12:52:33 +01:00
Olivier Goffart fac00348d9 Use the term folder sync connection in more places #3757 2015-10-27 12:12:21 +01:00
Olivier Goffart 3c93fd4fb7 AccountSettings: don't disable pause when offline (#4010) 2015-10-27 10:32:33 +01:00
Klaas Freitag 6b71273380 Discovery: Fix detection of hidden files.
In the discovery phase we want to detect that dot-files are hidden
on Linux and Mac.

This fixes strange behaviour seen in issue #3980
2015-10-26 14:24:05 +01:00
Olivier Goffart dccf4e9c34 Download: Soft errors for error while resuming (#4000) 2015-10-26 12:31:07 +01:00
Olivier Goffart 39289a3164 SocketAPI: don't trim the command #3297 2015-10-26 10:15:50 +01:00
Jenkins for ownCloud 6611d878ea [tx-robot] updated from transifex 2015-10-25 02:19:01 -04:00
Jenkins for ownCloud c3fc711095 [tx-robot] updated from transifex 2015-10-24 02:18:59 -04:00
Olivier Goffart 84f1bdbc87 Folder::wipe: We need to shut the socket API down before removing the DB
Because the DB stays open and locked.

Should fix #3824
2015-10-23 17:43:01 +02:00
Phil Davis 2eb5715599 ChangeLog 2.0.2 minor typos for 2.0 branch
These changes were committed to 2.0.2-rc1 branch https://github.com/owncloud/client/pull/3957/files https://github.com/owncloud/client/commit/6da2139a1bc4069f1cd1dfb017502f089c3af26f but that branch was never merged up into 2.0 (or 2.0.2-rc2) so the changes never went anywhere.

These changes could also be applied on 2.0.2-rc2 and 2.0.2 branch for completeness - then they would be in every branch in which they have appeared.
2015-10-23 21:21:31 +05:45
Olivier Goffart c93defc82d SyncEngine: remove unused functions 2015-10-23 17:11:19 +02:00
Olivier Goffart bd39c64798 Delete all files: make the 'Keep' on by default
On windows, we need to specify at least one AcceptRole.
Otherwise the DestructiveRole might become the default

Issue #3824
2015-10-23 17:06:14 +02:00
Olivier Goffart 42a6b242c7 SettingsDialog: use QWidgetAction for the toolbar so the extension works
When the toolbar is full because there is no enough room, make the extension
of the toolbar work, by using QWidgetAction::createWidget instead of
QToolBar::insertWidget

There should not be prolem when the window is too narrow.

Relates #3832
2015-10-23 16:23:37 +02:00
Markus Goetz e5570c24f2 Merge pull request #3995 from owncloud/return-code-of-version-and-help
owncloudcmd: Make returncode 0 for --version and --help
2015-10-23 15:36:01 +02:00
Joas Schilling 6d87bd15cd Make returncode 0 for --version and --help 2015-10-23 15:17:29 +02:00
Olivier Goffart d657c00b11 FolderStatusModel: fix getting the size of the folder in the selective sync (#3986)
Regressed since d610693af1. The problem
is that the _size vector contains the pathToRemove and that it was removed
before.
Reorganize a bit the code so there is only one loop that has still all the
 information.
2015-10-23 15:13:15 +02:00
Jenkins for ownCloud 6fae06f1d0 [tx-robot] updated from transifex 2015-10-23 02:19:00 -04:00
Olivier Goffart f18b40f7e7 csync_vio: reuse the information from readdir in stat
On unix we don't safe much (otherwise csync would have been
designed differently).
On windows however, the readdir already fetch all the info, so we
can as well use it.

We still have to query for the file id but we might optimize that later
2015-10-22 18:46:41 +02:00
Olivier Goffart 6a0633083d Network Settings: Adjust the bandwidth limit option with old Qt
- Disable the whole group box
- Add a tooltip explaining why it is disabled
- Make sure it is disabled in the settings in case of upgrade
- Do a runtime check in case the running Qt is greater
2015-10-22 17:57:34 +02:00
Daniel Molkentin 899f52be4f Revert "Settings dialog: remove the close button #3713"
This reverts commit ebee6f0bc2.

Unix window managers do not have a reliable way of hinting buttons,
so we need the close button.
2015-10-22 16:20:59 +02:00
Olivier Goffart 91525a7d33 csync_exclude: Don't ignore invalid char client side (#3736)
If the server does not support it, then the server will reply with an error
2015-10-22 12:32:53 +02:00
Olivier Goffart 455c3ae57d test/CMakeLists.txt: remove comments 2015-10-22 12:32:53 +02:00
Jenkins for ownCloud b5390b5aa2 [tx-robot] updated from transifex 2015-10-22 02:19:02 -04:00
Olivier Goffart a608b4e9e0 Folder: set csync verbosity to 0 if the Logger is not there
csync_log was still accounting for 8% of the local discovery (because
of vsnprintf and asprintf)
2015-10-22 01:13:35 +02:00
Olivier Goffart f6a543ada3 Logger: speedup the sync discovery when the log is innactive
The sync throw a lot of log message, and QDateTime::fromCurrentTime is
quite expensive. So don't call it if it's not needed.
2015-10-22 00:22:25 +02:00
Daniel Molkentin c7bf09c3d4 Merge remote-tracking branch 'origin/2.0' 2015-10-21 18:49:58 +02:00
Daniel Molkentin c8ae54d9e8 Merge pull request #3982 from owncloud/20-update
update 3-dot menu
2015-10-21 18:49:38 +02:00
Carla Schroder daf6d8772f update 3-dot menu 2015-10-21 09:44:38 -07:00
Olivier Goffart c80e72da83 Sharing: change coding style of enum
From all upper case to camel case

This hopefully fix the Windows build which fails because DELETE seems
to be a macro
2015-10-21 18:40:04 +02:00
Roeland Douma ec351e00ad Merge pull request #3773 from owncloud/split_sharedialog
Split sharedialog code
2015-10-21 16:55:59 +02:00
Olivier Goffart cf242871ea SyncEngine: keep a static pointer to the codec
The QTextCodec for UTF-8 is not going to change during the application life time.
So no need to look it up for every file
2015-10-21 16:38:26 +02:00
Olivier Goffart 597d36dcf2 csync_statedb: Use the index in csync_statedb_get_below_path
Make an index from the path, and make a query that uses the index
2015-10-21 16:38:26 +02:00
Olivier Goffart 9c388787bb csync_update: Don't fetch the etag in the local discovery from the DB
We don't need it, and it's slow.
This saves a lot of DB queries

(Also replaced a strlen>0 with a faster check)
2015-10-21 16:38:26 +02:00
Markus Goetz f739d8fdd3 sqlite: Update to version 3.9.1
For OS X and Windows.
This is in line with the tests/benchmarks Olivier is doing on ArchLinux.
2015-10-21 15:55:41 +02:00
Olivier Goffart 8ff3055b47 sync-exclude.lst: Remove entries that are hardcoded anyway
The more item in the sync-exclude.lst, the slower is the sync.
Many items are already hardcoded. Some are files that no longer
exist.
2015-10-20 18:38:47 +02:00
Olivier Goffart 71827549d6 csync_exclude: Use PathMatchSpecA instead of PathMatchSpecW
So we avoid lots of memory allocation.
We can work with char* directly since both the pattern and the file
name are in UTF-8 and there is no need to understand unicode for
such pattern.

(In fact, '?' would not match anyore non-ascii characters, but I
don't think that's a problem. I don't think anyone use '?' in its
exclude list. And the two allocations per call to csync_fnmatch are
really worth getting rid of)
2015-10-20 18:38:47 +02:00
Olivier Goffart de5de7acc5 csync_exclude: Optimize
Avoid alocations as much as possible
2015-10-20 18:38:47 +02:00
Markus Goetz c8590c4468 Remove legacy propagator and neon
The code was already uneeded/unbuilt on Windows and OS X.
2015-10-20 17:57:43 +02:00
Markus Goetz 98b966d274 OS X: Use Cocoa Pasteboard instead of QClipBoard #3300 2015-10-20 15:42:43 +02:00
Olivier Goffart 674b6f2373 Account Settings: clear the focus of the "Sign In" button when clicked
So that the focus does not go to the "Remove Account" button instead
which would be wierd
2015-10-20 13:56:35 +02:00
Olivier Goffart 407ff0a99d Theme: cache the QIcon::fromTheme
We are calling that every time we draw the folder delegate.
Which is a lot when the sync is runing and the progress bar is moving
2015-10-20 13:24:11 +02:00
Olivier Goffart 0b6d21e3d5 Logger: don't call qFormatLog when unessesary
That's a lot of string operations that can be avoided if the log window
is not shown
2015-10-20 13:22:48 +02:00
Olivier Goffart 557b704069 Fix compilation warning
shibbolethcredentials.h:59:10: warning: 'askFromUser' overrides a member
function but is not marked 'override' [-Winconsistent-missing-override]
2015-10-20 11:35:25 +02:00
Olivier Goffart 4369e31a49 Folder Model: don't try to fetch data if the account is disconnected
Now that it expands automatically, it would do lots of query to the
server when the account is disconnected. (all resulting in 401)
2015-10-19 18:32:34 +02:00
Olivier Goffart 23b5a74c17 Account Settings: Don't expand while clicking on the '...' button 2015-10-19 18:23:56 +02:00
Olivier Goffart ee69ab2021 Account Settings: Don't disable double click expanding for sub folders
The root folder open on simple click,  but the sub folder don't, so keep
this behaviour which is the native behaviour
2015-10-19 18:12:49 +02:00
Olivier Goffart 374f29c4d3 Account Settings: Fix crash for acocunts withour folder
Was broken by  027a865fbc
2015-10-19 18:08:11 +02:00
Markus Goetz 67910e7d60 Discovery: Call it "Checking for changes in" in UI
For #3431
2015-10-19 15:59:16 +02:00
Markus Goetz c80b033466 VERSION.cmake: fixup 2015-10-19 15:57:13 +02:00
Olivier Goffart 671af9f8fe Merge branch 'master' 2015-10-19 15:53:58 +02:00
Olivier Goffart 6ea05ff6e3 Dolphin shell integration: use the owncloud icons 2015-10-19 15:53:40 +02:00
Markus Goetz 00485e133f VERSION.cmake: This is git not rc1 2015-10-19 15:51:33 +02:00
Olivier Goffart c520ee4eab Dolphin Shell Extension: renamove the kf5 in the name 2015-10-19 15:43:42 +02:00
Olivier Goffart 5408ec79f7 Dolphin shell extention: Remove the KDE4 based plugin 2015-10-19 15:42:41 +02:00
Olivier Goffart f8e68ae823 Merge branch 'dolphin-plugin' 2015-10-19 15:41:47 +02:00
Olivier Goffart 184412d88e Dolphin shell integration: Renames the plugins
And put the helper in a shared library so it is shared accross both plugins
2015-10-19 15:40:11 +02:00
Olivier Goffart 82d1d04774 Dolphin shell integration: share code between two plugins 2015-10-19 15:40:11 +02:00
Olivier Goffart 731d4b3d4d Dolphin shell extention: adapt to the change in KDE Frameworks 2015-10-19 15:39:51 +02:00
Markus Goetz ccec186b98 ETagJob: Depth 0 for server >= 8.1 #3730 2015-10-19 15:31:27 +02:00
Klaas Freitag c66c259447 SettingsDialog: Add new widet called ActivityWidget.
This is the new widget to display server activity.
2015-10-19 14:41:53 +02:00
Klaas Freitag 4ad165ce26 Utility: add method fileNameForGuiUse(), pimp up filename for GUI
Currently, this one only replaces colons by / on Mac platform. This makes
the function resuseable.
2015-10-19 14:36:55 +02:00
Olivier Goffart 5cac90b3eb SelectiveSyncTreeView: show the size for the root item (#3755) 2015-10-19 10:58:54 +02:00
Olivier Goffart df135a0bb2 Merge branch '2.0'
Conflicts:
	src/gui/folder.cpp
2015-10-19 10:57:37 +02:00
Roeland Jago Douma 4a04dc1a3e Typos 2015-10-16 12:51:24 +02:00
Roeland Jago Douma 0e97fbb730 Use overloaded functions 2015-10-16 12:48:48 +02:00
Roeland Jago Douma 40ab3ee751 Now only 1 constructor to ocssharejob
* Pass the share_id to the functions that need it
2015-10-16 08:28:13 +02:00
Roeland Jago Douma f95fea9866 Move permissions to OcsShareJob 2015-10-16 08:09:57 +02:00
Roeland Jago Douma 03719334ea Remove unused members 2015-10-15 22:27:55 +02:00
Roeland Jago Douma 4441053b1c Thumbnailjob fixes
* Comments
* Use the path of the abstractnetworkjob
2015-10-15 22:18:22 +02:00
Roeland Jago Douma a34b663828 Now add parameters in a less crappy way 2015-10-15 21:58:16 +02:00
Roeland Jago Douma db1f4d4016 OCSJob -> OcsJob and more docs 2015-10-15 20:54:52 +02:00
Roeland Jago Douma 3ea944d1b3 Added setPublicUpload to OcsShareJob 2015-10-15 20:34:56 +02:00
Roeland Jago Douma b293aa762c Split sharing code
There is now a generic OCSJob which must be inherited by other jobs. This is in
prepartion for the other OCS job that will come (for the Sharee API endpoint
for example).

More logic is moved from the sharedialog to the OcsShareJob. So in the GUI code
we now only say what we want (a new share, set the password etc). And the code
in libsync will make that happen. Error handling is for now still done in the
GUI part.

For now the ocsjob and ocssharejob live in gui but probabaly we should
create a libshare or libocs at some point.
2015-10-15 20:05:47 +02:00
Markus Goetz b5e75afc17 General settings: Align checkbox #3758 2015-10-15 19:15:50 +02:00
Markus Goetz 027a865fbc Account Settings: Show selective sync buttons after list load
Especially nice when having a slower network.
For #3839
2015-10-15 18:52:16 +02:00
Markus Goetz 132b5f5130 Account Settings: Expand selective sync on show #3585 2015-10-15 17:27:38 +02:00
Markus Goetz c3754e1fdd folderstatusmodel.h: Fix warning 2015-10-15 17:27:29 +02:00
Markus Goetz 963eb1f29b VERSION.cmake: master is 2.1 2015-10-15 16:51:29 +02:00
Christian Kamm c418d67920 Merge remote-tracking branch 'origin/2.0' 2015-10-15 15:54:09 +02:00
Christian Kamm 6e09e3af86 Fix test compile
I regularly fix errors in the copies of the test sources that are
made in build/. Refactoring how these tests work could be worthwhile.
2015-10-15 15:52:58 +02:00
Christian Kamm 67e9a06d30 Progress estimation: Adjust low-transfer detection #3942
Progress estimation is usually based on transfer speed. That makes no
sense when we're doing operations like deletes, that need very little
data transfer but nevertheless take a long time.

This hack attempts to detect this case better and switches to a
different estimate.

We should rewrite this to maintain and update estimates for the
transfer speed, per-file overhead and chunk-assembly overhead each
time an item finishes. Then we could provide more consistent progress
estimates without ad-hoc fixes like this one.

Also, there's an issue where resuming a partial download will lead
to exaggerated transfer speed estimates.
2015-10-15 15:04:11 +02:00
Christian Kamm abd63035c1 ETag: Allow parsing of weak tags #3946 2015-10-15 14:57:34 +02:00
Roeland Douma df2418d9c5 Merge pull request #3661 from rullzer/public_upload
Allow setting of public upload on link shares
2015-10-14 15:34:25 +02:00
Roeland Jago Douma 2fdae6d72f Allow setting op public upload on link shares 2015-10-14 15:30:28 +02:00
Roeland Jago Douma 05471d0acd Also parse capabilitie for public uploads 2015-10-14 15:30:23 +02:00
Christian Kamm 05eee16959 SelectiveSync: Show in-progress label #3524
We now show 'Fetching data...' after a second.

This also increased the timeout to 60s, making the error
condition much less likely.
2015-10-14 13:05:53 +02:00
Roeland Douma a752eadd0f Merge pull request #3923 from owncloud/check_shareapi_available
Provide information about share availablity for files
2015-10-14 12:38:03 +02:00
Roeland Jago Douma 028dc8d6c3 Add SHARE_STATUS socketAPI command
This command allows to retrieve the share status of a file. In other
words if it can be shared.
2015-10-14 12:36:32 +02:00
Roeland Jago Douma 4a7242c8f9 Extended capabilities API
* Naming of capabilities is now a bit more consistent
2015-10-14 11:45:34 +02:00
Christian Kamm efdb29d2f9 AccountSettings: Show disabled 'Add Folder' tooltip on click #3645 2015-10-14 11:34:30 +02:00
Christian Kamm 225da68832 ExcludedFiles: Add test 2015-10-13 15:01:59 +02:00
Christian Kamm 51a2e6c580 Exclusion: Fix confusion with relative and absolute paths 2015-10-13 12:53:38 +02:00
Christian Kamm 7fe03c715d SelectiveSync: Don't adjust removed path 2015-10-13 12:37:27 +02:00
Klaas Freitag 419d18c128 FileSystem: Reuse the FileInfo object that is created in the caller.
With that, a lot of stats can be avoided, ie. in SocketAPI
2015-10-09 13:02:02 +02:00
Klaas Freitag 74a7755ad9 SocketAPI: String concat optimization as learned on QtWS. 2015-10-08 18:26:30 +02:00
Klaas Freitag c1ba927b37 Propagatorjobs: Removed superflous semicolon. 2015-10-08 16:20:42 +02:00
Klaas Freitag a8eb913535 SyncLogDialog: Do not delete SyncLogDialog after close.
Keep one instance for the lifetime of the generalsettings widget.
2015-10-07 18:59:48 +02:00
Klaas Freitag cb3a301f2c Merge pull request #3899 from sebasje/sebas/cmake
fix multiarch library path for Debian/Ubuntu
2015-10-06 15:36:43 +02:00
Klaas Freitag 6d6903ef62 Merge pull request #3919 from phil-davis/libsynctypos
libsync comment and message typos for master
2015-10-06 14:49:54 +02:00
Klaas Freitag f5daf50dc4 Merge pull request #3920 from phil-davis/guitypos
GUI comment and message typos for master
2015-10-06 14:46:00 +02:00
Phil Davis b8ccbbc72a GUI comment and message typos for master 2015-10-05 10:06:19 +05:45
Phil Davis f0e17fd9c0 libtypos comment and message typos for master 2015-10-05 09:05:09 +05:45
Klaas Freitag b09f1d591c Merge pull request #3916 from RealRancor/fix_rst_syntax
Fix linkname in architecture.rst.
2015-10-04 17:59:45 +02:00
RealRancor 8fd2b8d829 Fix linkname in architecture.rst. 2015-10-03 21:42:23 +02:00
Christian Kamm d610693af1 SelectiveSync: Apply excludes #3876 2015-10-02 15:56:39 +02:00
Christian Kamm 7d1886684e FolderWatcher: Use csync exclude code #3805
Introduce a global ExcludedFiles instance to avoid loading the global
exclude lists several times.

One could still add per-folder exclude lists by checking these after
the global ones.
2015-10-02 15:56:39 +02:00
Christian Kamm 95fc792745 Tray: Change texts #3657 2015-10-02 15:48:44 +02:00
Christian Kamm efefc2d986 Merge branch '2.0'
Conflicts:
	doc/images/menu.png
	doc/images/settings_network.png
2015-10-02 15:44:50 +02:00
Christian Kamm 9f8d109a7e Network errors: Use exception name, if message is empty #2718 2015-10-02 15:25:34 +02:00
Christian Kamm cf9e5ffb0b Remove dead code
no_recursive_propfind does not exist anymore.
2015-10-02 15:17:19 +02:00
Christian Kamm 1383023b2e Fix the Qt4 build. 2015-10-02 11:05:15 +02:00
Klaas Freitag afd081f40b Settings: Move synclog widget to a seperate dialog.
This a first step to integrate the server activity view, see #3732
2015-10-01 16:57:37 +02:00
Christian Kamm 3812fd0866 Checksums: Prepare 'supported checksums' capability #3735
It currently always returns the empty list and thus has no effect.
2015-10-01 15:00:33 +02:00
Christian Kamm 24c41ed0da Propagation: Try another sync on 423 Locked #3387 2015-10-01 13:05:07 +02:00
Christian Kamm 36e8e9ebf5 Propagator: Download disk space checks #2939
* There's a critical 50 MB threshold under which syncs abort
  (OWNCLOUD_CRITICAL_FREE_SPACE)
* The sync client always keeps 250 MB free
  (OWNCLOUD_FREE_SPACE)
2015-10-01 12:59:05 +02:00
Christian Kamm 12dc372b21 Sync: An initial diskspace check #2939
* Before each sync, check that there are at least
  250 MB of space available and abort otherwise.
* Can be overridden with OWNCLOUD_MIN_FREE_SPACE
2015-10-01 10:25:35 +02:00
Christian Kamm 20ea9015ca Propagation: Make 423 Locked a soft error #3387 2015-09-30 14:00:53 +02:00
Klaas Freitag 0c148025a3 SyncLog Dialog WIP 2015-09-30 12:02:05 +02:00
Sebastian Kügler a7cf1b04ad Simplify creating the library path
Instead of checking whether the library path ends up somewhere in /usr,
set the architecture prefix, anyway. The library path mechanism is also
used in custom prefixes, without this change, the library gets installed
globally on Debian and Ubuntu, leading to non-standard behaviour and
cross-build problems, as multiple architecture builds of this library
can't be installed alongside each other.

This is the minimal change to correct this behaviour from upstream cmake.
2015-09-29 00:15:39 +02:00
Daniel Molkentin a08a90a718 Merge pull request #3892 from RealRancor/fix_faq
Fix registry key syntax in FAQ.
2015-09-27 20:38:13 +02:00
RealRancor 1cb518cb13 Fix registry key syntax in FAQ. 2015-09-27 20:19:06 +02:00
Olivier Goffart cac219aca8 Dolphin shell integration: Add a Share with owncloud action 2015-09-10 13:41:45 +02:00
Olivier Goffart a159dfc7ec Dolphin shell integration: Make it work with dolphin master 2015-09-10 13:41:45 +02:00
Daniel Molkentin b7061618b1 Merge pull request #3789 from hh-lohmann/Terminology
/doc/autoupdate.rst: "32-/64-bit" => "32-/64-bit-Windows"
2015-09-10 01:37:10 +02:00
Daniel Molkentin d823809021 Merge pull request #3781 from phil-davis/FSC
Coin the term 'folder sync connection'
2015-09-10 01:35:25 +02:00
hh.lohmann 0329a8be2e /doc/autoupdate.rst: "Migrate to the following directory" => "Edit this Registry key"
Registry keys are no directories; you would not "migrate" to keys if you are just about to switch to them; resembling formulas as "Edit these / this Registry key/s" ease fast reading, for that also ":" instead of "::" at the end (formatting what follows)
2015-09-09 12:33:25 +02:00
hh.lohmann 79f64abfc3 /doc/autoupdate.rst: "32-/64-bit" => "32-/64-bit-Windows"
Should be stated clearly that there are no alternative 32- / 64-bit-ownCloud-Clients, but just a 32-bit-ownCloud-Client that is treated differently in 32- / 64-bit-Windows
2015-09-09 12:10:10 +02:00
Markus Goetz 63636aca9b Merge pull request #3777 from owncloud/individual-it-utf8-patch
fix unicode issue #3753
2015-09-08 16:06:42 +02:00
Phil Davis fdfab07d07 Coin the term 'folder sync connection'
Proposed wording for issue
https://github.com/owncloud/client/issues/3757
2015-09-08 17:22:57 +05:45
Individual IT Services cc5f8e5122 fix unicode issue #3753
fixes the unicode issue #3753

I don't know much CPP and Qt but after some google research I found this http://wiki.qt.io/Strings_and_encodings_in_Qt
it does mention trUtf8() that has done the trick for me on Linux with Gnome 3.16.
Haven't tested it on other systems
2015-09-08 13:59:43 +05:45
Olivier Goffart 21dbf97a02 Merge remote-tracking branch 'origin/2.0' 2015-09-07 10:32:16 +02:00
Olivier Goffart 39bff056a6 Merge remote-tracking branch 'origin/2.0' 2015-09-05 18:14:30 +02:00
Jocelyn Turcotte 128d46e19a Remove *Credentials::_fetchJobInProgress
Now that fetchFromKeychain is solely called from AccountState::slotInvalidCredentials
and that this one already protects the fetch call using _waitingForNewCredentials,
we can remove that extra check.
2015-09-05 16:00:45 +02:00
Jocelyn Turcotte 6d027ebd40 Separate the credential dialog from their fetch #3350
This moves the responsibility of asking the user or not for
credentials from the Credentials classes back to the AccountState.
fetch() now only extract credentials from the keychain, reports
the result to the AccountState which then decides if askFromUser()
should be called or not. The result is once more reported to the
AccounState.

This also replaces the HttpCredentials::queryPassword virtual
which now lets HttpCredentialsGui and HttpCredentialsText do it
the way that they prefer.
2015-09-05 16:00:45 +02:00
Jocelyn Turcotte 89f69209dd Simplify the authentication code paths #3350
The AccountState is now the only class responsible for triggering credentials
fetching from the keychain or from the user.

With the ShibbolethRefresher out of the question it's possible
to remove the invalidateAndFetch virtual and manually call invalidateToken.
This also allows us to move that code from Account to AccountState.
In the end this also allows us to move the fetch() call from the
ConnectionValidator and use the same code path as for invalid credentials.
2015-09-05 16:00:45 +02:00
Jocelyn Turcotte 94a57fe8d5 Get rid of ShibbolethRefresher
This is only for neon and not necessary if we want to show a notification
instead of a login window when the network reports invalid credentials.
2015-09-05 15:45:54 +02:00
Jocelyn Turcotte dcb687929f Show a notification instead of a login window on startup #3350
The original problem is that showing a popup not originated
from the main settings window while it's focused won't be
shown in front to the user.

This try not to highjack the user's attention of the user
by showing a notification when checking the connection for
valid credentials, and require the user to sign in through
the UI. There are still issues with showing that popup from
the tray icon, but the user will most likely be looking for
the popup in that case. The new sign in button directly in
the settings account works properly.
2015-09-01 18:40:20 +02:00
Jocelyn Turcotte 628957de21 Remove the _readPwdFromDeprecatedPlace codepath
This was introduced in 1.6.2 to read the password from earlier versions.
People upgrading from 1.5 to 2.1 will sadly need to re-enter their password.
2015-09-01 18:40:20 +02:00
Jocelyn Turcotte bcfc16c0f6 Add a sign in button in the settings window
It's not obvious for users that they should sign in through
the tray icon, especially if they were automatically signed out.
2015-09-01 18:40:20 +02:00
Olivier Goffart 3ba5e27d02 Merge branch '2.0' 2015-09-01 17:57:56 +02:00
Olivier Goffart 950bc578d0 Merge branch '2.0' 2015-08-31 14:34:04 +02:00
Carla Schroder ccfcdff190 Merge pull request #3665 from owncloud/2-0updates
1st batch of updates for 2.0
2015-08-27 10:28:03 +02:00
Carla Schroder 45835f1cf9 Update navigating.rst 2015-08-27 10:25:19 +02:00
Carla Schroder cf543d1eb0 Update navigating.rst 2015-08-27 10:20:15 +02:00
Carla Schroder 9f24f10186 Update installing.rst 2015-08-27 10:07:54 +02:00
Carla Schroder bc37668e9f 1st batch of updates for 2.0 2015-08-21 13:19:15 -07:00
Daniel Molkentin 22d87218b7 Merge pull request #3601 from individual-it/master
checking if file or folder is to be shared to fix issue #3556
2015-08-18 11:45:31 +02:00
Markus Goetz 62d64acd7b Merge pull request #3589 from owncloud/sharedir
Use SHAREDIR for i18n dir
2015-08-13 16:02:11 +02:00
Individual IT Services c6ff73f3e5 checking if file or folder is to be shared to fix issue #3556 2015-08-12 21:48:04 +05:45
hefee a87602af3f use SHAREDIR for i18n
SHAREDIR is used in src/gui/application.cpp and should also use that in
CMakeLists.txt.
2015-08-11 15:14:59 +02:00
269 arquivos alterados com 70291 adições e 33525 exclusões
-7
Ver Arquivo
@@ -133,13 +133,9 @@ endif()
#endif()
set(USE_NEON TRUE)
if(HAVE_QT5)
message(STATUS "Using Qt ${Qt5Core_VERSION_MAJOR}.${Qt5Core_VERSION_MINOR}.x")
if (${Qt5Core_VERSION_MAJOR} EQUAL "5")
if (${Qt5Core_VERSION_MINOR} EQUAL "4" OR ${Qt5Core_VERSION_MINOR} GREATER 4)
message(STATUS "We do not require Neon in this setup, compile without!")
set(USE_NEON FALSE)
else()
message(STATUS "If possible compile me with Qt 5.4 or higher.")
endif()
@@ -148,9 +144,6 @@ else()
message(STATUS "If possible compile me with Qt 5.4 or higher.")
endif()
if (USE_NEON)
find_package(Neon REQUIRED)
endif(USE_NEON)
find_package(OpenSSL 1.0.0 REQUIRED)
if(NOT TOKEN_AUTH_ONLY)
+9 -3
Ver Arquivo
@@ -1,12 +1,18 @@
ChangeLog
=========
version 2.1 (release 2015-yy-zz)
* We removed the old libneon-based propagator.
It was already disabled on OS X and Windows and only used on
Linux when building with Qt < 5.4 and having bandwidth limiting enabled.
So now you need Qt 5.4 on Linux if you want bandwidth limiting.
version 2.0.2 (release 2015-10-21)
* csync_file_stat_s: Save a bit of memory
* Shibboleth: Add our base user agent to WebKit
* SelectiveSync: Increase folder list timeout to 60
* Propagation: Try another sync on 423 Locked (#3387)
* Propagation: Make 423 Locked a soft error (#3387)
* Propagation: Reset upload blacklist if a chunk suceeds
* Propagation: Reset upload blacklist if a chunk succeeds
* Application: Fix crash on early shutdown (#3898)
* Linux: Don't show settings dialog always when launched twice (#3273, #3771, #3485)
* win32 vio: Add the OPEN_REPARSE_POINTS flag to the CreateFileW call. (#3813)
@@ -36,12 +42,12 @@ version 2.0.2 (release 2015-10-21)
* PropagateLocalRemove: remove entries from the DB even if there was an error.
* Settings UI improvements (eg. #3713, #3721, #3619 and others)
* Folder: Do not create the sync folder if it does not exist (#3692)
* Shell integratioon: don't show share menu item for top level folders
* Shell integration: don't show share menu item for top level folders
* Tray: Hide while modifying menus (#3656, #3672)
* AddFolder: Improve remote path selection error handling (#3573)
* csync_update: Use excluded_traversal() to improve performance (#3638)
* csync_excluded: Add fast _traversal() function (#3638)
* csync_exclude: Speed up siginificantly (#3638)
* csync_exclude: Speed up significantly (#3638)
* AccountSettings: Adjust quota info design (#3644, #3651)
* Adjust buttons on remove folder/account questions (#3654)
+1 -1
Ver Arquivo
@@ -4,7 +4,7 @@
|-----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| client-build-matrix | [![Build Status](https://ci.owncloud.org/job/client-build-matrix-linux/badge/icon)](https://ci.owncloud.org/job/client-build-matrix-linux/) |
| client-test-matrix-linux-no-build | [![Build Status](https://ci.owncloud.org/buildStatus/icon?job=client-test-matrix-linux-no-build)](https://ci.owncloud.org/job/client-test-matrix-linux-no-build/) |
| coverity_scan | [![Build Status](https://img.shields.io/coverity/scan/2482.svg)](https://scan.coverity.com/projects/owncloud-mirall)
## Introduction
+3 -3
Ver Arquivo
@@ -1,10 +1,10 @@
set( MIRALL_VERSION_MAJOR 2 )
set( MIRALL_VERSION_MINOR 0 )
set( MIRALL_VERSION_PATCH 2 )
set( MIRALL_VERSION_MINOR 1 )
set( MIRALL_VERSION_PATCH 0 )
set( MIRALL_SOVERSION 0 )
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
set( MIRALL_VERSION_SUFFIX "") #e.g. beta1, beta2, rc1
set( MIRALL_VERSION_SUFFIX "beta1") #e.g. beta1, beta2, rc1
endif( NOT DEFINED MIRALL_VERSION_SUFFIX )
if( NOT DEFINED MIRALL_VERSION_BUILD )
+6
Ver Arquivo
@@ -38,6 +38,8 @@ QT_PLUGINS = [
'imageformats/libqgif.dylib',
'imageformats/libqico.dylib',
'imageformats/libqjpeg.dylib',
'bearer/libqcorewlanbearer.dylib',
'bearer/libqgenericbearer.dylib',
'imageformats/libqsvg.dylib',
'imageformats/libqmng.dylib',
]
@@ -144,6 +146,10 @@ def FindFramework(path):
search_pathes = FRAMEWORK_SEARCH_PATH
search_pathes.insert(0, QueryQMake('QT_INSTALL_LIBS'))
for search_path in search_pathes:
# The following two lines are needed for a custom built Qt from version 5.5 on, possibly not for the one from the Qt SDK.
# Looks like the upstream macdeployqt also had an issue there https://bugreports.qt.io/browse/QTBUG-47868
if path.find( "\@rpath/"):
path = path.replace("@rpath/", "")
abs_path = os.path.join(search_path, path)
if os.path.exists(abs_path):
return abs_path
-4
Ver Arquivo
@@ -32,7 +32,3 @@ SET(QT_MOC_EXECUTABLE ${MINGW_PREFIX}-moc)
SET(QT_RCC_EXECUTABLE ${MINGW_PREFIX}-rcc)
SET(QT_UIC_EXECUTABLE ${MINGW_PREFIX}-uic)
SET(QT_LRELEASE_EXECUTABLE ${MINGW_PREFIX}-lrelease)
# neon config
SET(NEON_CONFIG_EXECUTABLE ${CMAKE_FIND_ROOT_PATH}/bin/neon-config)
# /usr/i686-w64-mingw32/sys-root/mingw/bin/neon-config
+2
Ver Arquivo
@@ -20,5 +20,7 @@
<file>resources/lock-https.png</file>
<file>resources/lock-https@2x.png</file>
<file>resources/account.png</file>
<file>resources/more.png</file>
<file>resources/delete.png</file>
</qresource>
</RCC>
-73
Ver Arquivo
@@ -1,73 +0,0 @@
# - Try to find Neon
# Once done this will define
#
# NEON_FOUND - system has Neon
# NEON_INCLUDE_DIRS - the Neon include directory
# NEON_LIBRARIES - Link these to use Neon
# NEON_DEFINITIONS - Compiler switches required for using Neon
#
# Copyright (c) 2011-2013 Andreas Schneider <asn@cryptomilk.org>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(_NEON neon)
endif (PKG_CONFIG_FOUND)
include(GNUInstallDirs)
find_path(NEON_INCLUDE_DIRS
NAMES
neon/ne_basic.h
HINTS
${_NEON_INCLUDEDIR}
${CMAKE_INSTALL_INCLUDEDIR}
)
find_library(NEON_LIBRARIES
NAMES
neon neon-27
HINTS
${_NEON_LIBDIR}
${CMAKE_INSTALL_LIBDIR}
${CMAKE_INSTALL_PREFIX}/lib
${CMAKE_INSTALL_PREFIX}/lib64
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Neon DEFAULT_MSG NEON_LIBRARIES NEON_INCLUDE_DIRS)
# show the NEON_INCLUDE_DIRS and NEON_LIBRARIES variables only in the advanced view
mark_as_advanced(NEON_INCLUDE_DIRS NEON_LIBRARIES)
# Check if neon was compiled with LFS support, if so, the NE_LFS variable has to
# be defined in the owncloud module.
# If neon was not compiled with LFS its also ok since the underlying system
# than probably supports large files anyway.
IF( CMAKE_FIND_ROOT_PATH )
FIND_PROGRAM( NEON_CONFIG_EXECUTABLE NAMES neon-config HINTS ${CMAKE_FIND_ROOT_PATH}/bin )
ELSE( CMAKE_FIND_ROOT_PATH )
FIND_PROGRAM( NEON_CONFIG_EXECUTABLE NAMES neon-config )
ENDIF( CMAKE_FIND_ROOT_PATH )
IF ( NEON_CONFIG_EXECUTABLE )
MESSAGE(STATUS "neon-config executable: ${NEON_CONFIG_EXECUTABLE}")
# neon-config --support lfs
EXECUTE_PROCESS( COMMAND ${NEON_CONFIG_EXECUTABLE} "--support" "lfs"
RESULT_VARIABLE LFS
OUTPUT_STRIP_TRAILING_WHITESPACE )
IF (LFS EQUAL 0)
MESSAGE(STATUS "libneon has been compiled with LFS support")
SET(NEON_WITH_LFS 1)
ELSE (LFS EQUAL 0)
MESSAGE(STATUS "libneon has not been compiled with LFS support, rely on OS")
ENDIF (LFS EQUAL 0)
ELSE ( NEON_CONFIG_EXECUTABLE )
MESSAGE(STATUS, "neon-config could not be found.")
ENDIF ( NEON_CONFIG_EXECUTABLE )
+1 -7
Ver Arquivo
@@ -134,13 +134,7 @@ if(NOT DEFINED CMAKE_INSTALL_LIBDIR OR (_libdir_set
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()
set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
endif()
else() # not debian, rely on CMAKE_SIZEOF_VOID_P:
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
+5
Ver Arquivo
@@ -40,6 +40,7 @@
!define QT_DLL_PATH "${MING_BIN}"
!define ACCESSIBLE_DLL_PATH "${MING_LIB}/qt5/plugins/accessible"
!define SQLITE_DLL_PATH "${MING_LIB}/qt5/plugins/sqldrivers"
!define BEARER_DLL_PATH "${MING_LIB}/qt5/plugins/bearer"
!define IMAGEFORMATS_DLL_PATH "${MING_LIB}/qt5/plugins/imageformats"
!define PLATFORMS_DLL_PATH "${MING_LIB}/qt5/plugins/platforms"
@@ -406,6 +407,10 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
SetOutPath "$INSTDIR\sqldrivers"
File "${SQLITE_DLL_PATH}\qsqlite.dll"
SetOutPath "$INSTDIR\bearer"
File "${BEARER_DLL_PATH}\qgenericbearer.dll"
File "${BEARER_DLL_PATH}\qnativewifibearer.dll"
SetOutPath "$INSTDIR"
;License & release notes.
File "@CPACK_RESOURCE_FILE_LICENSE@"
+5 -1
Ver Arquivo
@@ -22,7 +22,9 @@ if( Qt5Core_FOUND )
find_package(Qt5WebKitWidgets REQUIRED)
find_package(Qt5WebKit REQUIRED)
find_package(Qt5PrintSupport REQUIRED)
find_package(Qt5Quick REQUIRED)
if(NOT APPLE)
find_package(Qt5Quick REQUIRED) # only needed on Windows because of OBS dependencies(?)
endif()
find_package(Qt5Widgets REQUIRED)
if(APPLE)
find_package(Qt5MacExtras REQUIRED)
@@ -31,7 +33,9 @@ if( Qt5Core_FOUND )
else( Qt5Core_FOUND )
if(WIN32 OR APPLE)
if (NOT BUILD_WITH_QT4)
message(FATAL_ERROR "Qt 5 not found, but application depends on Qt5 on Windows and Mac OS X")
endif ()
endif(WIN32 OR APPLE)
endif( Qt5Core_FOUND )
-4
Ver Arquivo
@@ -23,8 +23,4 @@
#cmakedefine SYSCONFDIR "@SYSCONFDIR@"
#cmakedefine SHAREDIR "@SHAREDIR@"
#ifndef NEON_WITH_LFS
#cmakedefine NEON_WITH_LFS "@NEON_WITH_LFS@"
#endif
#endif
-4
Ver Arquivo
@@ -24,10 +24,6 @@
#cmakedefine HAVE_ICONV 1
#cmakedefine HAVE_ICONV_CONST 1
#ifndef NEON_WITH_LFS
#cmakedefine NEON_WITH_LFS 1
#endif
#cmakedefine HAVE___MINGW_ASPRINTF 1
#cmakedefine HAVE_ASPRINTF 1
-16
Ver Arquivo
@@ -1,9 +1,6 @@
project(libcsync)
add_subdirectory(std)
if(USE_NEON)
add_subdirectory(httpbf)
endif()
# Statically include sqlite
@@ -71,19 +68,6 @@ else()
endif()
if(USE_NEON)
list(APPEND csync_SRCS
csync_owncloud.c
csync_owncloud_util.c
)
list(APPEND CSYNC_LINK_LIBRARIES
${NEON_LIBRARIES}
)
include_directories(${NEON_INCLUDE_DIRS})
add_definitions(-DUSE_NEON)
endif(USE_NEON)
configure_file(csync_version.h.in ${CMAKE_CURRENT_BINARY_DIR}/csync_version.h)
set(csync_HDRS
-47
Ver Arquivo
@@ -58,12 +58,6 @@
#include "csync_rename.h"
#include "c_jhash.h"
#ifdef USE_NEON
// Breaking the abstraction for fun and profit.
#include "csync_owncloud.h"
#endif
static int _key_cmp(const void *key, const void *data) {
uint64_t a;
csync_file_stat_t *b;
@@ -154,9 +148,6 @@ int csync_init(CSYNC *ctx) {
ctx->local.type = LOCAL_REPLICA;
#ifdef USE_NEON
owncloud_init(ctx);
#endif
ctx->remote.type = REMOTE_REPLICA;
if (c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp) < 0) {
@@ -216,14 +207,6 @@ int csync_update(CSYNC *ctx) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "No exclude file loaded or defined!");
}
#ifdef USE_NEON
/* This is not actually connecting, just setting the info for neon. The legacy propagator can use it.. */
if (dav_connect( ctx, ctx->remote.uri ) < 0) {
ctx->status_code = CSYNC_STATUS_CONNECT_ERROR;
return -1;
}
#endif
/* update detection for local replica */
csync_gettime(&start);
ctx->current = LOCAL_REPLICA;
@@ -646,10 +629,6 @@ int csync_destroy(CSYNC *ctx) {
SAFE_FREE(ctx->remote.uri);
SAFE_FREE(ctx->error_string);
#ifdef USE_NEON
owncloud_destroy(ctx);
#endif
#ifdef WITH_ICONV
c_close_iconv();
#endif
@@ -672,21 +651,6 @@ void csync_clear_exclude_list(CSYNC *ctx)
csync_exclude_clear(ctx);
}
int csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb) {
if (ctx == NULL || cb == NULL) {
return -1;
}
if (ctx->status & CSYNC_STATUS_INIT) {
ctx->status_code = CSYNC_STATUS_CSYNC_STATUS_ERROR;
fprintf(stderr, "This function must be called before initialization.");
return -1;
}
ctx->callbacks.auth_function = cb;
return 0;
}
void *csync_get_userdata(CSYNC *ctx) {
if (ctx == NULL) {
return NULL;
@@ -781,14 +745,3 @@ void csync_file_stat_free(csync_file_stat_t *st)
SAFE_FREE(st);
}
}
int csync_set_module_property(CSYNC* ctx, const char* key, void* value)
{
#ifdef USE_NEON
return owncloud_set_property(ctx, key, value);
#else
(void)ctx, (void)key, (void)value;
return 0;
#endif
}
+1 -15
Ver Arquivo
@@ -173,7 +173,7 @@ enum csync_vio_file_stat_fields_e {
CSYNC_VIO_FILE_STAT_FIELDS_TYPE = 1 << 0,
CSYNC_VIO_FILE_STAT_FIELDS_MODE = 1 << 1, // local POSIX mode
CSYNC_VIO_FILE_STAT_FIELDS_FLAGS = 1 << 2,
CSYNC_VIO_FILE_STAT_FIELDS_DEVICE = 1 << 3,
// CSYNC_VIO_FILE_STAT_FIELDS_DEVICE = 1 << 3,
CSYNC_VIO_FILE_STAT_FIELDS_INODE = 1 << 4,
// CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT = 1 << 5,
CSYNC_VIO_FILE_STAT_FIELDS_SIZE = 1 << 6,
@@ -212,7 +212,6 @@ struct csync_vio_file_stat_s {
mode_t mode;
dev_t device;
uint64_t inode;
int fields; // actually enum csync_vio_file_stat_fields_e fields;
@@ -519,19 +518,6 @@ const char *csync_get_status_string(CSYNC *ctx);
int csync_set_iconv_codec(const char *from);
#endif
/**
* @brief Set a property to module
*
* @param ctx The csync context.
*
* @param key The property key
*
* @param value An opaque pointer to the data.
*
* @return 0 on success, less than 0 if an error occured.
*/
int csync_set_module_property(CSYNC *ctx, const char *key, void *value);
/**
* @brief Aborts the current sync run as soon as possible. Can be called from another thread.
*
+59 -45
Ver Arquivo
@@ -171,7 +171,6 @@ bool csync_is_windows_reserved_word(const char* filename) {
static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const char *path, int filetype, bool check_leading_dirs) {
size_t i = 0;
const char *p = NULL;
const char *bname = NULL;
size_t blen = 0;
char *conflict = NULL;
@@ -179,22 +178,6 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED;
CSYNC_EXCLUDE_TYPE type = CSYNC_NOT_EXCLUDED;
for (p = path; *p; p++) {
switch (*p) {
case '\\':
case ':':
case '?':
case '*':
case '"':
case '>':
case '<':
case '|':
return CSYNC_FILE_EXCLUDE_INVALID_CHAR;
default:
break;
}
}
/* split up the path */
bname = strrchr(path, '/');
if (bname) {
@@ -217,7 +200,7 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
goto out;
}
#ifdef _WIN32
#ifdef _WIN32
// Windows cannot sync files ending in spaces (#2176). It also cannot
// distinguish files ending in '.' from files without an ending,
// as '.' is a separator that is not stored internally, so let's
@@ -231,7 +214,26 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
goto out;
}
#endif
// Filter out characters not allowed in a filename on windows
const char *p = NULL;
for (p = path; *p; p++) {
switch (*p) {
case '\\':
case ':':
case '?':
case '*':
case '"':
case '>':
case '<':
case '|':
match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
goto out;
default:
break;
}
}
#endif
rc = csync_fnmatch(".owncloudsync.log*", bname, 0);
if (rc == 0) {
@@ -264,40 +266,41 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
goto out;
}
/* Build a list of path components to check. */
c_strlist_t *path_components = c_strlist_new(32);
char *path_split = strdup(path);
size_t len = strlen(path_split);
for (i = len; ; --i) {
// read backwards until a path separator is found
if (i != 0 && path_split[i-1] != '/') {
continue;
}
c_strlist_t *path_components = NULL;
if (check_leading_dirs) {
/* Build a list of path components to check. */
path_components = c_strlist_new(32);
char *path_split = strdup(path);
size_t len = strlen(path_split);
for (i = len; ; --i) {
// read backwards until a path separator is found
if (i != 0 && path_split[i-1] != '/') {
continue;
}
// check 'basename', i.e. for "/foo/bar/fi" we'd check 'fi', 'bar', 'foo'
if (path_split[i] != 0) {
c_strlist_add_grow(&path_components, path_split + i);
}
// check 'basename', i.e. for "/foo/bar/fi" we'd check 'fi', 'bar', 'foo'
if (path_split[i] != 0) {
c_strlist_add_grow(&path_components, path_split + i);
}
if (i == 0 || !check_leading_dirs) {
break;
}
if (i == 0) {
break;
}
// check 'dirname', i.e. for "/foo/bar/fi" we'd check '/foo/bar', '/foo'
path_split[i-1] = '\0';
c_strlist_add_grow(&path_components, path_split);
// check 'dirname', i.e. for "/foo/bar/fi" we'd check '/foo/bar', '/foo'
path_split[i-1] = '\0';
c_strlist_add_grow(&path_components, path_split);
}
SAFE_FREE(path_split);
}
SAFE_FREE(path_split);
/* Loop over all exclude patterns and evaluate the given path */
for (i = 0; match == CSYNC_NOT_EXCLUDED && i < excludes->count; i++) {
bool match_dirs_only = false;
char *pattern_stored = c_strdup(excludes->vector[i]);
char* pattern = pattern_stored;
char *pattern = excludes->vector[i];
type = CSYNC_FILE_EXCLUDE_LIST;
if (strlen(pattern) < 1) {
SAFE_FREE(pattern_stored);
if (!pattern[0]) { /* empty pattern */
continue;
}
/* Excludes starting with ']' means it can be cleanup */
@@ -309,6 +312,9 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
}
/* Check if the pattern applies to pathes only. */
if (pattern[strlen(pattern)-1] == '/') {
if (!check_leading_dirs && filetype == CSYNC_FTW_TYPE_FILE) {
continue;
}
match_dirs_only = true;
pattern[strlen(pattern)-1] = '\0'; /* Cut off the slash */
}
@@ -326,7 +332,7 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
}
/* if still not excluded, check each component and leading directory of the path */
if (match == CSYNC_NOT_EXCLUDED) {
if (match == CSYNC_NOT_EXCLUDED && check_leading_dirs) {
size_t j = 0;
if (match_dirs_only && filetype == CSYNC_FTW_TYPE_FILE) {
j = 1; // skip the first entry, which is bname
@@ -338,8 +344,16 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
break;
}
}
} else if (match == CSYNC_NOT_EXCLUDED && !check_leading_dirs) {
rc = csync_fnmatch(pattern, bname, 0);
if (rc == 0) {
match = type;
}
}
if (match_dirs_only) {
/* restore the '/' */
pattern[strlen(pattern)] = '/';
}
SAFE_FREE(pattern_stored);
}
c_strlist_destroy(path_components);
+3 -10
Ver Arquivo
@@ -57,20 +57,13 @@ int csync_fnmatch(__const char *__pattern, __const char *__name, int __flags) {
#else /* HAVE_FNMATCH */
#include <shlwapi.h>
int csync_fnmatch(__const char *__pattern, __const char *__name, int __flags) {
wchar_t *pat = NULL;
wchar_t *name = NULL;
int csync_fnmatch(const char *pattern, const char *name, int flags) {
BOOL match;
(void) __flags;
(void) flags;
name = c_utf8_string_to_locale(__name);
pat = c_utf8_string_to_locale(__pattern);
match = PathMatchSpecA(name, pattern);
match = PathMatchSpecW(name, pat);
c_free_locale_string(pat);
c_free_locale_string(name);
if(match)
return 0;
else
-617
Ver Arquivo
@@ -1,617 +0,0 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2011 by Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2012 by Klaas Freitag <freitag@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "csync_owncloud.h"
#include "csync_owncloud_private.h"
#include <inttypes.h>
#include "csync_private.h"
#include "csync_version.h"
/*
* helper method to build up a user text for SSL problems, called from the
* verify_sslcert callback.
*/
static void addSSLWarning( char *ptr, const char *warn, int len )
{
char *concatHere = ptr;
int remainingLen = 0;
if( ! (warn && ptr )) return;
remainingLen = len - strlen(ptr);
if( remainingLen <= 0 ) return;
concatHere = ptr + strlen(ptr); /* put the write pointer to the end. */
strncpy( concatHere, warn, remainingLen );
}
/*
* Callback to verify the SSL certificate, called from libneon.
* It analyzes the SSL problem, creates a user information text and passes
* it to the csync callback to ask the user.
*/
#define LEN 4096
static int ssl_callback_by_neon(void *userdata, int failures,
const ne_ssl_certificate *certificate)
{
char problem[LEN];
char buf[MAX(NE_SSL_DIGESTLEN, NE_ABUFSIZ)];
int ret = -1;
const ne_ssl_certificate *cert = certificate;
csync_auth_callback authcb = NULL;
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
memset( problem, 0, LEN );
while( cert ) {
addSSLWarning( problem, "There are problems with the SSL certificate:\n", LEN );
if( failures & NE_SSL_NOTYETVALID ) {
addSSLWarning( problem, " * The certificate is not yet valid.\n", LEN );
}
if( failures & NE_SSL_EXPIRED ) {
addSSLWarning( problem, " * The certificate has expired.\n", LEN );
}
if( failures & NE_SSL_UNTRUSTED ) {
addSSLWarning( problem, " * The certificate is not trusted!\n", LEN );
}
if( failures & NE_SSL_IDMISMATCH ) {
addSSLWarning( problem, " * The hostname for which the certificate was "
"issued does not match the hostname of the server\n", LEN );
}
if( failures & NE_SSL_BADCHAIN ) {
addSSLWarning( problem, " * The certificate chain contained a certificate other than the server cert\n", LEN );
}
if( failures & NE_SSL_REVOKED ) {
addSSLWarning( problem, " * The server certificate has been revoked by the issuing authority.\n", LEN );
}
if (ne_ssl_cert_digest(cert, buf) == 0) {
addSSLWarning( problem, "Certificate fingerprint: ", LEN );
addSSLWarning( problem, buf, LEN );
addSSLWarning( problem, "\n", LEN );
}
cert = ne_ssl_cert_signedby( cert );
}
addSSLWarning( problem, "Do you want to accept the certificate chain anyway?\nAnswer yes to do so and take the risk: ", LEN );
if( ctx->csync_ctx ) {
authcb = csync_get_auth_callback( ctx->csync_ctx );
}
if( authcb ){
/* call the csync callback */
DEBUG_WEBDAV("Call the csync callback for SSL problems");
memset( buf, 0, NE_ABUFSIZ );
(*authcb) ( problem, buf, NE_ABUFSIZ-1, 1, 0, csync_get_userdata(ctx->csync_ctx) );
if( buf[0] == 'y' || buf[0] == 'Y') {
ret = 0;
} else {
DEBUG_WEBDAV("Authentication callback replied %s", buf );
}
}
DEBUG_WEBDAV("## VERIFY_SSL CERT: %d", ret );
return ret;
}
/*
* Authentication callback. Is set by ne_set_server_auth to be called
* from the neon lib to authenticate a request.
*/
static int authentication_callback_by_neon( void *userdata, const char *realm, int attempt,
char *username, char *password)
{
char buf[NE_ABUFSIZ];
csync_auth_callback authcb = NULL;
int re = attempt;
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
(void) realm;
/* DEBUG_WEBDAV( "Authentication required %s", realm ); */
if( username && password ) {
DEBUG_WEBDAV( "Authentication required %s", username );
if( ctx->dav_session.user ) {
/* allow user without password */
if( strlen( ctx->dav_session.user ) < NE_ABUFSIZ ) {
strcpy( username, ctx->dav_session.user );
}
if( ctx->dav_session.pwd && strlen( ctx->dav_session.pwd ) < NE_ABUFSIZ ) {
strcpy( password, ctx->dav_session.pwd );
}
} else {
authcb = csync_get_auth_callback( ctx->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, csync_get_userdata(ctx->csync_ctx) );
if( strlen(buf) < NE_ABUFSIZ ) {
strcpy( username, buf );
}
memset( buf, 0, NE_ABUFSIZ );
(*authcb) ("Enter your password: ", buf, NE_ABUFSIZ-1, 0, 0, csync_get_userdata(ctx->csync_ctx) );
if( strlen(buf) < NE_ABUFSIZ) {
strcpy( password, buf );
}
} else {
re = 1;
}
}
}
return re;
}
/*
* Authentication callback. Is set by ne_set_proxy_auth to be called
* from the neon lib to authenticate against a proxy. The data to authenticate
* against comes from mirall throught vio_module_init function.
*/
static int proxy_authentication_callback_by_neon( void *userdata, const char *realm, int attempt,
char *username, char *password)
{
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
(void) realm;
if( ctx->dav_session.proxy_user && strlen( ctx->dav_session.proxy_user ) < NE_ABUFSIZ) {
strcpy( username, ctx->dav_session.proxy_user );
if( ctx->dav_session.proxy_pwd && strlen( ctx->dav_session.proxy_pwd ) < NE_ABUFSIZ) {
strcpy( password, ctx->dav_session.proxy_pwd );
}
}
/* NTLM needs several attempts */
return (attempt < 3) ? 0 : -1;
}
/* Configure the proxy depending on the variables */
static int configureProxy( csync_owncloud_ctx_t *ctx, ne_session *session )
{
int port = 8080;
int re = -1;
if( ! session ) return -1;
if( ! ctx->dav_session.proxy_type ) return 0; /* Go by NoProxy per default */
if( ctx->dav_session.proxy_port > 0 ) {
port = ctx->dav_session.proxy_port;
}
if( c_streq(ctx->dav_session.proxy_type, "NoProxy" )) {
DEBUG_WEBDAV("No proxy configured.");
re = 0;
} else if( c_streq(ctx->dav_session.proxy_type, "DefaultProxy") ||
c_streq(ctx->dav_session.proxy_type, "HttpProxy") ||
c_streq(ctx->dav_session.proxy_type, "HttpCachingProxy") ||
c_streq(ctx->dav_session.proxy_type, "Socks5Proxy")) {
if( ctx->dav_session.proxy_host ) {
DEBUG_WEBDAV("%s at %s:%d", ctx->dav_session.proxy_type, ctx->dav_session.proxy_host, port );
if (c_streq(ctx->dav_session.proxy_type, "Socks5Proxy")) {
ne_session_socks_proxy(session, NE_SOCK_SOCKSV5, ctx->dav_session.proxy_host, port,
ctx->dav_session.proxy_user, ctx->dav_session.proxy_pwd);
} else {
ne_session_proxy(session, ctx->dav_session.proxy_host, port );
}
re = 2;
} else {
DEBUG_WEBDAV("%s requested but no proxy host defined.", ctx->dav_session.proxy_type );
/* we used to try ne_system_session_proxy here, but we should rather err out
to behave exactly like the caller. */
}
} else {
DEBUG_WEBDAV( "Unsupported Proxy: %s", ctx->dav_session.proxy_type );
}
return re;
}
/*
* This hook is called for with the response of a request. Here its checked
* if a Set-Cookie header is there for the PHPSESSID. The key is stored into
* the webdav session to be added to subsequent requests.
*/
static void post_request_hook(ne_request *req, void *userdata, const ne_status *status)
{
const char *set_cookie_header = NULL;
const char *sc = NULL;
char *key = NULL;
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
if (ctx->dav_session.session_key)
return; /* We already have a session cookie, and we should ignore other ones */
if(!(status && req)) return;
if( status->klass == 2 || status->code == 401 ) {
/* successful request */
set_cookie_header = ne_get_response_header( req, "Set-Cookie" );
if( set_cookie_header ) {
DEBUG_WEBDAV(" Set-Cookie found: %s", set_cookie_header);
/* try to find a ', ' sequence which is the separator of neon if multiple Set-Cookie
* headers are there.
* The following code parses a string like this:
* Set-Cookie: 50ace6bd8a669=p537brtt048jh8srlp2tuep7em95nh9u98mj992fbqc47d1aecp1;
*/
sc = set_cookie_header;
while(sc) {
const char *sc_val = sc;
const char *sc_end = sc_val;
int cnt = 0;
int len = strlen(sc_val); /* The length of the rest of the header string. */
while( cnt < len && *sc_end != ';' && *sc_end != ',') {
cnt++;
sc_end++;
}
if( cnt == len ) {
/* exit: We are at the end. */
sc = NULL;
} else if( *sc_end == ';' ) {
/* We are at the end of the session key. */
int keylen = sc_end-sc_val;
if( key ) {
int oldlen = strlen(key);
key = c_realloc(key, oldlen + 2 + keylen+1);
strcpy(key + oldlen, "; ");
strncpy(key + oldlen + 2, sc_val, keylen);
key[oldlen + 2 + keylen] = '\0';
} else {
key = c_malloc(keylen+1);
strncpy( key, sc_val, keylen );
key[keylen] = '\0';
}
/* now search for a ',' to find a potential other header entry */
while(cnt < len && *sc_end != ',') {
cnt++;
sc_end++;
}
if( cnt < len )
sc = sc_end+2; /* mind the space after the comma */
else
sc = NULL;
} else if( *sc_end == ',' ) {
/* A new entry is to check. */
if( *(sc_end + 1) == ' ') {
sc = sc_end+2;
} else {
/* error condition */
sc = NULL;
}
}
}
}
} else {
DEBUG_WEBDAV("Request failed, don't take session header.");
}
if( key ) {
DEBUG_WEBDAV("----> Session-key: %s", key);
SAFE_FREE(ctx->dav_session.session_key);
ctx->dav_session.session_key = key;
}
}
/*
* this hook is called just after a request has been created, before its sent.
* Here it is used to set the proxy connection header if available.
*/
static void request_created_hook(ne_request *req, void *userdata,
const char *method, const char *requri)
{
// FIXME Can possibly be merged with pre_send_hook
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
(void) method;
(void) requri;
if( !req ) return;
if(ctx->dav_session.proxy_type) {
/* required for NTLM */
ne_add_request_header(req, "Proxy-Connection", "Keep-Alive");
}
}
/*
* this hook is called just before a request has been sent.
* Here it is used to set the session cookie if available.
*/
static void pre_send_hook(ne_request *req, void *userdata,
ne_buffer *header)
{
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
if( !req ) return;
if(ctx->dav_session.session_key) {
ne_buffer_concat(header, "Cookie: ", ctx->dav_session.session_key, "\r\n", NULL);
} else {
DEBUG_WEBDAV("csync pre_send_hook We don't have a Auth Cookie (session_key), this is wrong!");
}
}
static int post_send_hook(ne_request *req, void *userdata,
const ne_status *status)
{
const char *location;
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
(void) status;
location = ne_get_response_header(req, "Location");
if( !location ) return NE_OK;
if( ctx->dav_session.redir_callback ) {
if( ctx->dav_session.redir_callback( ctx->csync_ctx, location ) ) {
return NE_REDIRECT;
} else {
return NE_RETRY;
}
}
return NE_REDIRECT;
}
/*
* Connect to a DAV server
* This function sets the flag _connected if the connection is established
* and returns if the flag is set, so calling it frequently is save.
*/
int dav_connect(CSYNC *csyncCtx, const char *base_url) {
int useSSL = 0;
int rc;
char protocol[6] = {'\0'};
char uaBuf[256];
char *path = NULL;
char *scheme = NULL;
char *host = NULL;
unsigned int port = 0;
int proxystate = -1;
csync_owncloud_ctx_t *ctx = csyncCtx->owncloud_context;
struct csync_client_certs_s* clientCerts = csyncCtx->clientCerts;
if (ctx->_connected) {
return 0;
}
rc = c_parse_uri( base_url, &scheme,
&ctx->dav_session.user,
&ctx->dav_session.pwd,
&host, &port, &path );
if( rc < 0 ) {
DEBUG_WEBDAV("Failed to parse uri %s", base_url );
goto out;
}
DEBUG_WEBDAV("* scheme %s", scheme );
DEBUG_WEBDAV("* host %s", host );
DEBUG_WEBDAV("* port %u", port );
DEBUG_WEBDAV("* path %s", path );
if( strcmp( scheme, "owncloud" ) == 0 || strcmp( scheme, "http" ) == 0 ) {
strcpy( protocol, "http");
} else if( strcmp( scheme, "ownclouds" ) == 0 || strcmp( scheme, "https") == 0 ) {
strcpy( protocol, "https");
useSSL = 1;
} else {
DEBUG_WEBDAV("Invalid scheme %s, go out here!", scheme );
rc = -1;
goto out;
}
DEBUG_WEBDAV("* user %s", ctx->dav_session.user ? ctx->dav_session.user : "");
if (port == 0) {
port = ne_uri_defaultport(protocol);
}
ctx->dav_session.ctx = ne_session_create( protocol, host, port);
if (ctx->dav_session.ctx == NULL) {
DEBUG_WEBDAV("Session create with protocol %s failed", protocol );
rc = -1;
goto out;
}
if (ctx->dav_session.read_timeout != 0) {
ne_set_read_timeout(ctx->dav_session.ctx, ctx->dav_session.read_timeout);
DEBUG_WEBDAV("Timeout set to %u seconds", ctx->dav_session.read_timeout );
}
// Should never take more than some seconds, 30 is really a max.
ne_set_connect_timeout(ctx->dav_session.ctx, 30);
snprintf( uaBuf, sizeof(uaBuf), "Mozilla/5.0 (%s) mirall/%s (csyncoC)",
CSYNC_STRINGIFY( MIRALL_VERSION ), csync_owncloud_get_platform() );
ne_set_useragent( ctx->dav_session.ctx, uaBuf);
ne_set_server_auth(ctx->dav_session.ctx, authentication_callback_by_neon, ctx);
if( useSSL ) {
if (!ne_has_support(NE_FEATURE_SSL)) {
DEBUG_WEBDAV("Error: SSL is not enabled.");
rc = -1;
goto out;
}
if(clientCerts != NULL) {
ne_ssl_client_cert *clicert;
DEBUG_WEBDAV("dav_connect: certificatePath and certificatePasswd are set, so we use it" );
DEBUG_WEBDAV(" with certificatePath: %s", clientCerts->certificatePath );
DEBUG_WEBDAV(" with certificatePasswd: %s", clientCerts->certificatePasswd );
clicert = ne_ssl_clicert_read ( clientCerts->certificatePath );
if ( clicert == NULL ) {
DEBUG_WEBDAV ( "Error read certificate : %s", ne_get_error ( ctx->dav_session.ctx ) );
} else {
if ( ne_ssl_clicert_encrypted ( clicert ) ) {
int rtn = ne_ssl_clicert_decrypt ( clicert, clientCerts->certificatePasswd );
if ( !rtn ) {
DEBUG_WEBDAV ( "Certificate was deciphered successfully." );
ne_ssl_set_clicert ( ctx->dav_session.ctx, clicert );
} else {
DEBUG_WEBDAV ( "Errors while deciphering certificate: %s", ne_get_error ( ctx->dav_session.ctx ) );
}
}
}
} else {
DEBUG_WEBDAV("dav_connect: error with csync_client_certs_s* clientCerts");
}
ne_ssl_trust_default_ca( ctx->dav_session.ctx );
ne_ssl_set_verify( ctx->dav_session.ctx, ssl_callback_by_neon, ctx);
}
/* Hook called when a request is created. It sets the proxy connection header. */
ne_hook_create_request( ctx->dav_session.ctx, request_created_hook, ctx );
/* Hook called after response headers are read. It gets the Session ID. */
ne_hook_post_headers( ctx->dav_session.ctx, post_request_hook, ctx );
/* Hook called before a request is sent. It sets the cookies. */
ne_hook_pre_send( ctx->dav_session.ctx, pre_send_hook, ctx );
/* Hook called after request is dispatched. Used for handling possible redirections. */
ne_hook_post_send( ctx->dav_session.ctx, post_send_hook, ctx );
/* Proxy support */
proxystate = configureProxy( ctx, ctx->dav_session.ctx );
if( proxystate < 0 ) {
DEBUG_WEBDAV("Error: Proxy-Configuration failed.");
} else if( proxystate > 0 ) {
ne_set_proxy_auth( ctx->dav_session.ctx, proxy_authentication_callback_by_neon, ctx );
}
ctx->_connected = 1;
rc = 0;
out:
SAFE_FREE(path);
SAFE_FREE(host);
SAFE_FREE(scheme);
return rc;
}
char *owncloud_error_string(CSYNC* ctx)
{
return ctx->owncloud_context->dav_session.error_string;
}
int owncloud_commit(CSYNC* ctx) {
if (!ctx->owncloud_context) {
return 0;
}
if( ctx->owncloud_context->dav_session.ctx ) {
ne_forget_auth(ctx->owncloud_context->dav_session.ctx);
ne_session_destroy(ctx->owncloud_context->dav_session.ctx );
ctx->owncloud_context->dav_session.ctx = 0;
}
/* DEBUG_WEBDAV( "********** vio_module_shutdown" ); */
ctx->owncloud_context->dav_session.ctx = 0;
// ne_sock_exit();
ctx->owncloud_context->_connected = 0; /* triggers dav_connect to go through the whole neon setup */
SAFE_FREE( ctx->owncloud_context->dav_session.user );
SAFE_FREE( ctx->owncloud_context->dav_session.pwd );
SAFE_FREE( ctx->owncloud_context->dav_session.session_key);
SAFE_FREE( ctx->owncloud_context->dav_session.error_string );
return 0;
}
void owncloud_destroy(CSYNC* ctx)
{
owncloud_commit(ctx);
SAFE_FREE(ctx->owncloud_context);
if (ctx->clientCerts) {
SAFE_FREE(ctx->clientCerts->certificatePasswd);
SAFE_FREE(ctx->clientCerts->certificatePath);
SAFE_FREE(ctx->clientCerts);
}
ne_sock_exit();
}
int owncloud_set_property(CSYNC* ctx, const char *key, void *data) {
#define READ_STRING_PROPERTY(P) \
if (c_streq(key, #P)) { \
SAFE_FREE(ctx->owncloud_context->dav_session.P); \
ctx->owncloud_context->dav_session.P = c_strdup((const char*)data); \
return 0; \
}
READ_STRING_PROPERTY(session_key)
READ_STRING_PROPERTY(proxy_type)
READ_STRING_PROPERTY(proxy_host)
READ_STRING_PROPERTY(proxy_user)
READ_STRING_PROPERTY(proxy_pwd)
#undef READ_STRING_PROPERTY
if (c_streq(key, "proxy_port")) {
ctx->owncloud_context->dav_session.proxy_port = *(int*)(data);
return 0;
}
if (c_streq(key, "read_timeout") || c_streq(key, "timeout")) {
ctx->owncloud_context->dav_session.read_timeout = *(int*)(data);
return 0;
}
if( c_streq(key, "get_dav_session")) {
/* Give the ne_session to the caller */
*(ne_session**)data = ctx->owncloud_context->dav_session.ctx;
return 0;
}
if( c_streq(key, "redirect_callback")) {
if (data) {
csync_owncloud_redirect_callback_t* cb_wrapper = data;
ctx->owncloud_context->dav_session.redir_callback = *cb_wrapper;
} else {
ctx->owncloud_context->dav_session.redir_callback = NULL;
}
}
if( c_streq(key, "SSLClientCerts")) {
if(ctx->clientCerts != NULL) {
SAFE_FREE(ctx->clientCerts->certificatePasswd);
SAFE_FREE(ctx->clientCerts->certificatePath);
SAFE_FREE(ctx->clientCerts);
ctx->clientCerts = NULL;
}
if (data) {
struct csync_client_certs_s* clientCerts = (struct csync_client_certs_s*) data;
struct csync_client_certs_s* newCerts = c_malloc(sizeof(struct csync_client_certs_s));
newCerts->certificatePath = c_strdup(clientCerts->certificatePath);
newCerts->certificatePasswd = c_strdup(clientCerts->certificatePasswd);
ctx->clientCerts = newCerts;
} else {
DEBUG_WEBDAV("error: in owncloud_set_property for 'SSLClientCerts'" );
}
}
return -1;
}
void owncloud_init(CSYNC* ctx) {
ne_sock_init();
ctx->owncloud_context = c_malloc( sizeof( struct csync_owncloud_ctx_s ));
ctx->owncloud_context->csync_ctx = ctx; // back reference
}
/* vim: set ts=4 sw=4 et cindent: */
-36
Ver Arquivo
@@ -1,36 +0,0 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2011 by Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2012 by Klaas Freitag <freitag@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef CSYNC_OWNCLOUD_H
#define CSYNC_OWNCLOUD_H
#include "csync.h"
#include "vio/csync_vio.h"
// Public API used by csync
int owncloud_commit(CSYNC* ctx);
void owncloud_destroy(CSYNC* ctx);
char *owncloud_error_string(CSYNC* ctx);
int owncloud_set_property(CSYNC* ctx, const char *key, void *data);
void owncloud_init(CSYNC* ctx);
int dav_connect(CSYNC* ctx, const char *base_url);
#endif /* CSYNC_OWNCLOUD_H */
-115
Ver Arquivo
@@ -1,115 +0,0 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2011 by Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2012 by Klaas Freitag <freitag@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef CSYNC_OWNCLOUD_PRIVATE_H
#define CSYNC_OWNCLOUD_PRIVATE_H
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "config_csync.h"
#ifdef NEON_WITH_LFS /* Switch on LFS in libneon. Never remove the NE_LFS! */
#define NE_LFS
#endif
#include <neon/ne_basic.h>
#include <neon/ne_socket.h>
#include <neon/ne_session.h>
#include <neon/ne_request.h>
#include <neon/ne_props.h>
#include <neon/ne_auth.h>
#include <neon/ne_dates.h>
#include <neon/ne_compress.h>
#include <neon/ne_redirect.h>
#include "c_rbtree.h"
#include "c_lib.h"
#include "csync.h"
#include "csync_misc.h"
#include "csync_macros.h"
#include "c_private.h"
#include "vio/csync_vio.h"
#include "csync_log.h"
#include "csync_owncloud.h"
#define DEBUG_WEBDAV(...) csync_log( 9, "oc_module", __VA_ARGS__);
typedef int (*csync_owncloud_redirect_callback_t)(CSYNC* ctx, const char* uri);
/* Struct with the WebDAV session */
struct dav_session_s {
ne_session *ctx;
char *user;
char *pwd;
char *proxy_type;
char *proxy_host;
int proxy_port;
char *proxy_user;
char *proxy_pwd;
char *session_key;
char *error_string;
int read_timeout;
csync_owncloud_redirect_callback_t redir_callback;
};
struct csync_owncloud_ctx_s {
CSYNC *csync_ctx;
// For the WebDAV connection
struct dav_session_s dav_session; /* The DAV Session, initialised in dav_connect */
int _connected; /* flag to indicate if a connection exists, ie.
the dav_session is valid */
};
typedef struct csync_owncloud_ctx_s csync_owncloud_ctx_t;
//typedef csync_owncloud_ctx_t* csync_owncloud_ctx_p;
void set_errno_from_http_errcode( int err );
void set_error_message( csync_owncloud_ctx_t *ctx, const char *msg );
void set_errno_from_neon_errcode(csync_owncloud_ctx_t *ctx, int neon_code );
int http_result_code_from_session(csync_owncloud_ctx_t *ctx);
void set_errno_from_session(csync_owncloud_ctx_t *ctx);
time_t oc_httpdate_parse( const char *date );
const char* csync_owncloud_get_platform(void);
char *_cleanPath( const char* uri );
#endif // CSYNC_OWNCLOUD_PRIVATE_H
-125
Ver Arquivo
@@ -1,125 +0,0 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2011 by Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2012 by Klaas Freitag <freitag@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "csync_owncloud.h"
#include "csync_owncloud_private.h"
#include "csync_misc.h"
void set_errno_from_http_errcode( int err ) {
int new_errno = 0;
switch(err) {
case 200: /* OK */
case 201: /* Created */
case 202: /* Accepted */
case 203: /* Non-Authoritative Information */
case 204: /* No Content */
case 205: /* Reset Content */
case 207: /* Multi-Status */
case 304: /* Not Modified */
new_errno = 0;
break;
case 401: /* Unauthorized */
case 402: /* Payment Required */
case 407: /* Proxy Authentication Required */
case 405:
new_errno = EPERM;
break;
case 301: /* Moved Permanently */
case 303: /* See Other */
case 404: /* Not Found */
case 410: /* Gone */
new_errno = ENOENT;
break;
case 408: /* Request Timeout */
case 504: /* Gateway Timeout */
new_errno = EAGAIN;
break;
case 423: /* Locked */
new_errno = EACCES;
break;
case 400: /* Bad Request */
case 403: /* Forbidden */
case 409: /* Conflict */
case 411: /* Length Required */
case 412: /* Precondition Failed */
case 414: /* Request-URI Too Long */
case 415: /* Unsupported Media Type */
case 424: /* Failed Dependency */
case 501: /* Not Implemented */
new_errno = EINVAL;
break;
case 507: /* Insufficient Storage */
new_errno = ENOSPC;
break;
case 206: /* Partial Content */
case 300: /* Multiple Choices */
case 302: /* Found */
case 305: /* Use Proxy */
case 306: /* (Unused) */
case 307: /* Temporary Redirect */
case 406: /* Not Acceptable */
case 416: /* Requested Range Not Satisfiable */
case 417: /* Expectation Failed */
case 422: /* Unprocessable Entity */
case 500: /* Internal Server Error */
case 502: /* Bad Gateway */
case 505: /* HTTP Version Not Supported */
new_errno = EIO;
break;
case 503: /* Service Unavailable */
new_errno = ERRNO_SERVICE_UNAVAILABLE;
break;
case 413: /* Request Entity too Large */
new_errno = EFBIG;
break;
default:
new_errno = EIO;
}
errno = new_errno;
}
// as per http://sourceforge.net/p/predef/wiki/OperatingSystems/
// extend as required
const char* csync_owncloud_get_platform() {
#if defined (_WIN32)
return "Windows";
#elif defined(__APPLE__)
return "Macintosh";
#elif defined(__gnu_linux__)
return "Linux";
#elif defined(__DragonFly__)
/* might also define __FreeBSD__ */
return "DragonFlyBSD";
#elif defined(__FreeBSD__)
return "FreeBSD";
#elif defined(__NetBSD__)
return "NetBSD";
#elif defined(__OpenBSD__)
return "OpenBSD";
#elif defined(sun) || defined(__sun)
return "Solaris";
#else
return "Unknown OS";
#endif
}
-6
Ver Arquivo
@@ -77,9 +77,6 @@ enum csync_replica_e {
typedef struct csync_file_stat_s csync_file_stat_t;
struct csync_owncloud_ctx_s; // csync_owncloud.c
/**
* @brief csync public structure
*/
@@ -169,9 +166,6 @@ struct csync_s {
bool db_is_empty;
bool ignore_hidden_files;
struct csync_owncloud_ctx_s *owncloud_context;
};
+8 -38
Ver Arquivo
@@ -416,37 +416,10 @@ csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx,
return st;
}
/* Get the etag. */
char *csync_statedb_get_etag( CSYNC *ctx, uint64_t jHash ) {
char *ret = NULL;
csync_file_stat_t *fs = NULL;
if( !ctx ) {
return NULL;
}
if( ! csync_get_statedb_exists(ctx)) return ret;
fs = csync_statedb_get_stat_by_hash(ctx, jHash );
if( fs ) {
if( fs->etag ) {
ret = c_strdup(fs->etag);
}
csync_file_stat_free(fs);
}
return ret;
}
#define BELOW_PATH_QUERY "SELECT phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize, ignoredChildrenRemote FROM metadata WHERE pathlen>? AND path LIKE(?)"
int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
int rc;
sqlite3_stmt *stmt = NULL;
int64_t cnt = 0;
char *likepath;
int asp;
int min_path_len;
if( !path ) {
return -1;
@@ -456,7 +429,12 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
return -1;
}
SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, BELOW_PATH_QUERY, -1, &stmt, NULL));
/* Select the entries for anything that starts with (path+'/')
* In other words, anything that is between path+'/' and path+'0',
* (because '0' follows '/' in ascii)
*/
const char *below_path_query = "SELECT phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize, ignoredChildrenRemote FROM metadata WHERE path > (?||'/') AND path < (?||'0')";
SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, below_path_query, -1, &stmt, NULL));
ctx->statedb.lastReturnValue = rc;
if( rc != SQLITE_OK ) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for below path query.");
@@ -467,15 +445,8 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
return -1;
}
asp = asprintf( &likepath, "%s/%%%%", path);
if (asp < 0) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!");
return -1;
}
min_path_len = strlen(path);
sqlite3_bind_int(stmt, 1, min_path_len);
sqlite3_bind_text(stmt, 2, likepath, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 1, path, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, path, -1, SQLITE_STATIC);
cnt = 0;
@@ -518,7 +489,6 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "%" PRId64 " entries read below path %s from db.", cnt, path);
}
sqlite3_finalize(stmt);
SAFE_FREE(likepath);
return 0;
}
+13 -42
Ver Arquivo
@@ -270,10 +270,6 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
((int64_t) fs->mtime), ((int64_t) tmp->modtime),
fs->etag, tmp->etag, (uint64_t) fs->inode, (uint64_t) tmp->inode,
(uint64_t) fs->size, (uint64_t) tmp->size, fs->remotePerm, tmp->remotePerm, tmp->has_ignored_files );
if( !fs->etag) {
st->instruction = CSYNC_INSTRUCTION_EVAL;
goto out;
}
if((ctx->current == REMOTE_REPLICA && !c_streq(fs->etag, tmp->etag ))
|| (ctx->current == LOCAL_REPLICA && (!_csync_mtime_equal(fs->mtime, tmp->modtime)
// zero size in statedb can happen during migration
@@ -584,7 +580,6 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
char *d_name = NULL;
csync_vio_handle_t *dh = NULL;
csync_vio_file_stat_t *dirent = NULL;
csync_vio_file_stat_t *fs = NULL;
csync_file_stat_t *previous_fs = NULL;
int read_from_db = 0;
int rc = 0;
@@ -688,8 +683,8 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
}
/* skip "." and ".." */
if (d_name[0] == '.' && (d_name[1] == '\0'
|| (d_name[1] == '.' && d_name[2] == '\0'))) {
if ( (d_name[0] == '.' && d_name[1] == '\0')
|| (d_name[0] == '.' && d_name[1] == '.' && d_name[2] == '\0')) {
csync_vio_file_stat_destroy(dirent);
dirent = NULL;
continue;
@@ -741,15 +736,21 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
/* Only for the local replica we have to stat(), for the remote one we have all data already */
if (ctx->replica == LOCAL_REPLICA) {
fs = csync_vio_file_stat_new();
res = csync_vio_stat(ctx, filename, fs);
res = csync_vio_stat(ctx, filename, dirent);
} else {
fs = dirent;
res = 0;
}
/* if the filename starts with a . we consider it a hidden file
* For windows, the hidden state is also discovered within the vio
* local stat function.
*/
if( d_name[0] == '.' ) {
dirent->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
}
if( res == 0) {
switch (fs->type) {
switch (dirent->type) {
case CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK:
flag = CSYNC_FTW_FLAG_SLINK;
break;
@@ -772,42 +773,12 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
flag = CSYNC_FTW_FLAG_NSTAT;
}
if( ctx->current == LOCAL_REPLICA ) {
char *etag = NULL;
int len = strlen( path );
uint64_t h = c_jhash64((uint8_t *) path, len, 0);
etag = csync_statedb_get_etag( ctx, h );
if(_last_db_return_error(ctx)) {
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
SAFE_FREE(etag);
goto error;
}
if( etag ) {
SAFE_FREE(fs->etag);
fs->etag = etag;
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;
if( c_streq(etag, "")) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Uniq ID from Database is EMPTY: %s", path);
} else {
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Uniq ID from Database: %s -> %s", path, fs->etag ? fs->etag : "<NULL>" );
}
}
}
previous_fs = ctx->current_fs;
/* Call walker function for each file */
rc = fn(ctx, filename, fs, flag);
rc = fn(ctx, filename, dirent, flag);
/* this function may update ctx->current and ctx->read_from_db */
/* Only for the local replica we have to destroy stat(), for the remote one it is a pointer to dirent */
if (ctx->replica == LOCAL_REPLICA) {
csync_vio_file_stat_destroy(fs);
}
if (rc < 0) {
if (CSYNC_STATUS_IS_OK(ctx->status_code)) {
ctx->status_code = CSYNC_STATUS_UPDATE_ERROR;
-57
Ver Arquivo
@@ -1,57 +0,0 @@
project(httpbflib C)
find_package(Neon)
set(HTTPBF_PUBLIC_INCLUDE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/src
${NEON_INCLUDE_DIRS}
CACHE INTERNAL "httpbflib public include directories"
)
set(HTTPBF_LIBRARY
httpbf
CACHE INTERNAL "httpbf library"
)
set(HTTPBF_LINK_LIBRARIES
${HTTPBF_LIBRARY}
)
set(httpbf_SRCS
src/httpbf.c
)
set(httpbf_HEADERS
src/httpbf.h
)
include_directories(
${HTTPBF_PUBLIC_INCLUDE_DIRS}
)
add_library(${HTTPBF_LIBRARY} STATIC ${httpbf_SRCS})
target_link_libraries(${HTTPBF_LIBRARY} ${NEON_LIBRARIES})
if(NOT WIN32)
add_definitions( -fPIC )
endif()
INSTALL(
TARGETS
${HTTPBF_LIBRARY}
LIBRARY DESTINATION
${LIB_INSTALL_DIR}
ARCHIVE DESTINATION
${LIB_INSTALL_DIR}
RUNTIME DESTINATION
${BIN_INSTALL_DIR}
)
if (NOT APPLE)
INSTALL(
FILES
${httpbf_HEADERS}
DESTINATION
${CMAKE_INSTALL_INCLUDEDIR}
)
endif (NOT APPLE)
-29
Ver Arquivo
@@ -1,29 +0,0 @@
This is a little code that does ownCloud file chunking.
Basically to put a local file to an url:
(Also see the client example code in client dir.)
/* Initialize the transfer, get a transfer struct. */
hbf_transfer_t *trans = hbf_init_transfer( url );
Hbf_State state;
if( trans ) {
int fd = open_local_file( file );
/* create a neon session to use for the transfer */
ne_session *session = create_neon_session(uri);
if( session && fd > -1 ) {
/* Prepare the list of chunks, ie. calculate chunks and write back to trans. */
state = hbf_splitlist(trans, fd);
if( state == HBF_SUCCESS ) {
/* Transfer all the chunks through the HTTP session using PUT. */
state = hbf_transfer( session, trans, "PUT" );
}
}
}
GET a large file:
Do GET Range requests.
-36
Ver Arquivo
@@ -1,36 +0,0 @@
project(client C)
set(CLIENT_EXECUTABLE httpbfclient CACHE INTERNAL "httpbf client")
set(CLIENT_LINK_LIBRARIES ${NEON_LIBRARIES} ${HBF_LIBRARY})
set(HTTPBF_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/src})
if(NOT LINUX)
list(APPEND CLIENT_LINK_LIBRARIES ${ARGP_LIBRARIES})
endif()
set(client_SRCS
httpbf_client.c
)
include_directories(
${HTTPBF_INCLUDE_DIR}
${HTTPBF_PUBLIC_INCLUDE_DIRS}
)
add_executable(${CLIENT_EXECUTABLE} ${client_SRCS})
target_link_libraries(${CLIENT_EXECUTABLE} ${CLIENT_LINK_LIBRARIES})
set_target_properties(
${CLIENT_EXECUTABLE}
PROPERTIES
OUTPUT_NAME
httpbf
)
# install( TARGETS ${CLIENT_EXECUTABLE} DESTINATION ${BIN_INSTALL_DIR} )
install(TARGETS ${CLIENT_EXECUTABLE} DESTINATION bin)
-225
Ver Arquivo
@@ -1,225 +0,0 @@
/*
* httpbf - send big files via http
*
* Copyright (c) 2012 Klaas Freitag <freitag@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <getopt.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <neon/ne_auth.h>
#include "httpbf.h"
/* Program documentation. */
static char doc[] = "Usage: httpbf [OPTION...] LOCAL REMOTEDIR\n\
httpbf - command line client to upload big files via http.\n\
\n\
Transfer a big file to a remote directory on ownCloud.\n\
\n\
-?, --help Give this help list\n\
--usage Give a short usage message\n\
-V, --version Print program version\n\
";
static char _user[NE_ABUFSIZ];
static char _pwd[NE_ABUFSIZ];
/* The options we understand. */
static const struct option long_options[] =
{
{"version", no_argument, 0, 'V' },
{"usage", no_argument, 0, 'h' },
{0, 0, 0, 0}
};
static const char* httpbf_version = "0.1";
static void print_version()
{
printf( "%s\n", httpbf_version );
exit(0);
}
static void print_help()
{
printf( "%s\n", doc );
exit(0);
}
static int ne_auth( void *userdata, const char *realm, int attempt,
char *username, char *password)
{
(void) userdata;
(void) realm;
if( username && password ) {
if( _user ) {
/* allow user without password */
if( strlen( _user ) < NE_ABUFSIZ ) {
strcpy( username, _user );
}
if( _pwd && strlen( _pwd ) < NE_ABUFSIZ ) {
strcpy( password, _pwd );
}
}
}
return attempt;
}
static int parse_args(int argc, char **argv)
{
while(optind < argc) {
int c = -1;
struct option *opt = NULL;
int result = getopt_long( argc, argv, "Vh", long_options, &c );
if( result == -1 ) {
break;
}
switch(result) {
case 'V':
print_version();
break;
case 'h':
print_help();
break;
case 0:
opt = (struct option*)&(long_options[c]);
if(strcmp(opt->name, "no-name-yet")) {
} else {
fprintf(stderr, "Argument: No idea what!\n");
}
break;
default:
break;
}
}
return optind;
}
static ne_session* create_neon_session( const char *url )
{
ne_uri uri;
ne_session *sess = NULL;
memset( _user, 0, NE_ABUFSIZ );
memset( _pwd, 0, NE_ABUFSIZ );
if( ne_uri_parse( url, &uri ) == 0 ) {
unsigned int port = ne_uri_defaultport(uri.scheme);
if( uri.userinfo ) {
char *slash = NULL;
strcpy( _user, uri.userinfo );
slash = strchr( _user, ':');
if( slash ) {
strcpy( _pwd, slash+1);
*slash = 0;
}
}
sess = ne_session_create(uri.scheme, uri.host, port);
ne_set_server_auth(sess, ne_auth, 0 );
ne_uri_free(&uri);
}
return sess;
}
static int open_local_file( const char *file )
{
int fd = -1;
if( !file ) return -1;
fd = open(file, O_RDONLY);
return fd;
}
static void transfer( const char* local, const char* uri )
{
if( !(local && uri )) return;
char *whole_url;
int len;
char *filename = basename(local);
if( ! filename ) {
return;
}
len = strlen(filename)+strlen(uri)+2;
whole_url = malloc( len );
strcpy(whole_url, uri);
strcat(whole_url, "/");
strcat(whole_url, filename);
hbf_transfer_t *trans = hbf_init_transfer( whole_url );
Hbf_State state;
if( trans ) {
ne_session *session = create_neon_session(uri);
if( session ) {
int fd = open_local_file( local );
if( fd > -1 ) {
state = hbf_splitlist(trans, fd );
if( state == HBF_SUCCESS ) {
state = hbf_transfer( session, trans, "PUT" );
}
}
ne_session_destroy(session);
}
}
if( state != HBF_SUCCESS ) {
printf("Upload failed: %s\n", hbf_error_string(state));
printf(" HTTP result %d, Server Error: %s\n",
trans->status_code, trans->error_string ? trans->error_string : "<empty>" );
}
/* Print the result of the recent transfer */
hbf_free_transfer( trans );
free(whole_url);
}
int main(int argc, char **argv) {
int rc = 0;
char errbuf[256] = {0};
parse_args(argc, argv);
/* two options must remain as source and target */
/* printf("ARGC: %d -> optind: %d\n", argc, optind ); */
if( argc - optind < 2 ) {
print_help();
}
transfer( argv[optind], argv[optind+1]);
}
/* vim: set ts=8 sw=2 et cindent: */
-38
Ver Arquivo
@@ -1,38 +0,0 @@
project(httpbf C)
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
set(HTTPBF_PUBLIC_INCLUDE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}
CACHE INTERNAL "httpbf public include directories"
)
set(HTTPBFLIB_PRIVATE_INCLUDE_DIRS
)
set(HBF_LIBRARY
httpbf
CACHE INTERNAL "httpbflib library"
)
set(HTTPBFLIB_LINK_LIBRARIES
${HBF_LIBRARY}
)
set(httpbflib_SRCS
httpbf.c
)
include_directories(
${NEON_INCLUDE_DIRS}
${GLIB2_INCLUDE_DIRS}
)
if(NOT WIN32)
add_definitions( -fPIC )
endif()
add_library(${HBF_LIBRARY} SHARED ${httpbflib_SRCS} )
target_link_libraries(${HBF_LIBRARY} ${NEON_LIBRARIES})
-688
Ver Arquivo
@@ -1,688 +0,0 @@
/*
* httpbf - send big files via http
*
* Copyright (c) 2012 Klaas Freitag <freitag@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/timeb.h>
#include <sys/time.h>
#include <inttypes.h>
#include "httpbf.h"
#include <neon/ne_session.h>
#include <neon/ne_request.h>
#include <neon/ne_basic.h>
// #ifdef NDEBUG
// #define DEBUG_HBF(...)
// #else
#define DEBUG_HBF(...) { if(transfer->log_cb) { \
char buf[1024]; \
snprintf(buf, 1024, __VA_ARGS__); \
transfer->log_cb(__func__, buf, transfer->user_data); \
} }
// #endif
#define DEFAULT_BLOCK_SIZE (10*1024*1024)
/* Platform specific defines go here. */
#ifdef _WIN32
#define _hbf_fstat _fstat64
typedef struct stat64 hbf_stat_t;
#else
#define _hbf_fstat fstat
typedef struct stat hbf_stat_t;
#endif
static int transfer_id( hbf_stat_t *sb ) {
struct timeval tp;
int res;
int r;
if( gettimeofday(&tp, 0) < 0 ) {
return 0;
}
/* build a Unique ID:
* take the current epoch and shift 8 bits up to keep the least bits.
* than add the milliseconds, again shift by 8
* and finally add the least 8 bit of the inode of the file.
*/
res = tp.tv_sec; /* epoche value in seconds */
res = res << 8;
r = (sb->st_ino & 0xFF);
res += r; /* least six bit of inode */
res = res << sizeof(tp.tv_usec);
res += tp.tv_usec; /* milliseconds */
return res;
}
hbf_transfer_t *hbf_init_transfer( const char *dest_uri ) {
hbf_transfer_t * transfer = NULL;
transfer = malloc( sizeof(hbf_transfer_t) );
memset(transfer, 0, sizeof(hbf_transfer_t));
/* store the target uri */
transfer->url = strdup(dest_uri);
transfer->status_code = 200;
transfer->error_string = NULL;
transfer->start_id = 0;
transfer->block_size = DEFAULT_BLOCK_SIZE;
transfer->threshold = transfer->block_size;
transfer->modtime_accepted = 0;
transfer->oc_header_modtime = 0;
return transfer;
}
/* Create the splitlist of a given file descriptor */
Hbf_State hbf_splitlist(hbf_transfer_t *transfer, int fd ) {
hbf_stat_t sb;
int64_t num_blocks;
int64_t blk_size;
int64_t remainder = 0;
if( ! transfer ) {
return HBF_PARAM_FAIL;
}
if( fd <= 0 ) {
DEBUG_HBF("File descriptor is invalid.");
return HBF_PARAM_FAIL;
}
if( _hbf_fstat(fd, &sb) < 0 ) {
DEBUG_HBF("Failed to stat the file descriptor: errno = %d", errno);
return HBF_FILESTAT_FAIL;
}
/* Store the file characteristics. */
transfer->fd = fd;
transfer->stat_size = sb.st_size;
transfer->modtime = sb.st_mtime;
transfer->previous_etag = NULL;
#ifndef NDEBUG
transfer->calc_size = 0;
#endif
DEBUG_HBF("block_size: %" PRId64 " threshold: %" PRId64 " st_size: %" PRId64, transfer->block_size, transfer->threshold, sb.st_size );
/* calc the number of blocks to split in */
blk_size = transfer->block_size;
if (sb.st_size < transfer->threshold) {
blk_size = transfer->threshold;
}
num_blocks = sb.st_size / blk_size;
/* there migth be a remainder. */
remainder = sb.st_size - num_blocks * blk_size;
/* if there is a remainder, add one block */
if( remainder > 0 ) {
num_blocks++;
}
/* The file has size 0. There still needs to be at least one block. */
if( sb.st_size == 0 ) {
num_blocks = 1;
blk_size = 0;
}
DEBUG_HBF("num_blocks: %" PRId64 " rmainder: %" PRId64 " blk_size: %" PRId64, num_blocks, remainder, blk_size );
if( num_blocks ) {
int cnt;
int64_t overall = 0;
/* create a datastructure for the transfer data */
transfer->block_arr = calloc(num_blocks, sizeof(hbf_block_t*));
transfer->block_cnt = num_blocks;
transfer->transfer_id = transfer_id(&sb);
transfer->start_id = 0;
for( cnt=0; cnt < num_blocks; cnt++ ) {
/* allocate a block struct and fill */
hbf_block_t *block = malloc( sizeof(hbf_block_t) );
memset(block, 0, sizeof(hbf_block_t));
block->seq_number = cnt;
if( cnt > 0 ) {
block->start = cnt * blk_size;
}
block->size = blk_size;
block->state = HBF_NOT_TRANSFERED;
/* consider the remainder if we're already at the end */
if( cnt == num_blocks-1 && remainder > 0 ) {
block->size = remainder;
}
overall += block->size;
/* store the block data into the result array in the transfer */
*((transfer->block_arr)+cnt) = block;
DEBUG_HBF("created block %d (start: %" PRId64 " size: %" PRId64 ")", cnt, block->start, block->size );
}
#ifndef NDEBUG
transfer->calc_size = overall;
#endif
}
return HBF_SUCCESS;
}
void hbf_free_transfer( hbf_transfer_t *transfer ) {
int cnt;
if( !transfer ) return;
for( cnt = 0; cnt < transfer->block_cnt; cnt++ ) {
hbf_block_t *block = transfer->block_arr[cnt];
if( !block ) continue;
if( block->http_error_msg ) free( block->http_error_msg );
if( block->etag ) free( block->etag );
}
free( transfer->block_arr );
free( transfer->url );
free( transfer->file_id );
if( transfer->error_string) free( (void*) transfer->error_string );
free( transfer );
}
static char* get_transfer_url( hbf_transfer_t *transfer, int indx ) {
char *res = NULL;
hbf_block_t *block = NULL;
if( ! transfer ) return NULL;
if( indx >= transfer->block_cnt ) return NULL;
block = transfer->block_arr[indx];
if( ! block ) return NULL;
if( transfer->block_cnt == 1 ) {
/* Just one chunk. We send as an ordinary request without chunking. */
res = strdup( transfer->url );
} else {
char trans_id_str[32];
char trans_block_str[32];
char indx_str[32];
int len = 1; /* trailing zero. */
int tlen = 0;
tlen = sprintf( trans_id_str, "%u", transfer->transfer_id );
if( tlen < 0 ) {
return NULL;
}
len += tlen;
tlen = sprintf( trans_block_str, "%u", transfer->block_cnt );
if( tlen < 0 ) {
return NULL;
}
len += tlen;
tlen = sprintf( indx_str, "%u", indx );
if( tlen < 0 ) {
return NULL;
}
len += tlen;
len += strlen(transfer->url);
len += strlen("-chunking---");
res = malloc(len);
/* Note: must be %u for unsigned because one does not want '--' */
if( sprintf(res, "%s-chunking-%u-%u-%u", transfer->url, transfer->transfer_id,
transfer->block_cnt, indx ) < 0 ) {
return NULL;
}
}
return res;
}
/*
* perform one transfer of one block.
* returns HBF_TRANSFER_SUCCESS if the transfer of this block was a success
* returns HBF_SUCCESS if the server aknoweldge that he received all the blocks
*/
static int _hbf_dav_request(hbf_transfer_t *transfer, ne_request *req, int fd, hbf_block_t *blk ) {
Hbf_State state = HBF_TRANSFER_SUCCESS;
int res;
const ne_status *req_status = NULL;
const char *etag = NULL;
(void) transfer;
if( ! (blk && req) ) return HBF_PARAM_FAIL;
ne_set_request_body_fd(req, fd, blk->start, blk->size);
DEBUG_HBF("Block: %d , Start: %" PRId64 " and Size: %" PRId64 "", blk->seq_number, blk->start, blk->size );
res = ne_request_dispatch(req);
req_status = ne_get_status( req );
switch(res) {
case NE_OK:
blk->state = HBF_TRANSFER_FAILED;
state = HBF_FAIL;
etag = 0;
if( req_status->klass == 2 ) {
state = HBF_TRANSFER_SUCCESS;
blk->state = HBF_TRANSFER_SUCCESS;
etag = ne_get_response_header(req, "ETag");
if (etag && etag[0]) {
/* When there is an etag, it means the transfer was complete */
state = HBF_SUCCESS;
if( etag[0] == '"' && etag[ strlen(etag)-1] == '"') {
int len = strlen( etag )-2;
blk->etag = malloc( len+1 );
strncpy( blk->etag, etag+1, len );
blk->etag[len] = '\0';
} else {
blk->etag = strdup( etag );
}
} else {
/* DEBUG_HBF("OOOOOOOO No etag returned!"); */
}
/* check if the server was able to set the mtime already. */
etag = ne_get_response_header(req, "X-OC-MTime");
if( etag && strcmp(etag, "accepted") == 0 ) {
/* the server acknowledged that the mtime was set. */
transfer->modtime_accepted = 1;
}
etag = ne_get_response_header(req, "OC-FileID");
if( etag ) {
transfer->file_id = strdup( etag );
}
}
break;
case NE_AUTH:
state = HBF_AUTH_FAIL;
blk->state = HBF_TRANSFER_FAILED;
break;
case NE_PROXYAUTH:
state = HBF_PROXY_AUTH_FAIL;
blk->state = HBF_TRANSFER_FAILED;
break;
case NE_CONNECT:
state = HBF_CONNECT_FAIL;
blk->state = HBF_TRANSFER_FAILED;
break;
case NE_TIMEOUT:
state = HBF_TIMEOUT_FAIL;
blk->state = HBF_TRANSFER_FAILED;
break;
case NE_ERROR:
state = HBF_FAIL;
blk->state = HBF_TRANSFER_FAILED;
break;
}
blk->http_result_code = req_status->code;
if( req_status->reason_phrase ) {
blk->http_error_msg = strdup(req_status->reason_phrase);
}
return state;
}
Hbf_State hbf_validate_source_file( hbf_transfer_t *transfer ) {
Hbf_State state = HBF_SUCCESS;
hbf_stat_t sb;
if( transfer == NULL ) {
state = HBF_PARAM_FAIL;
}
if( state == HBF_SUCCESS ) {
if( transfer->fd <= 0 ) {
state = HBF_PARAM_FAIL;
}
}
if( state == HBF_SUCCESS ) {
int rc = _hbf_fstat( transfer->fd, &sb );
if( rc != 0 ) {
state = HBF_STAT_FAIL;
}
}
if( state == HBF_SUCCESS ) {
if( sb.st_mtime != transfer->modtime || sb.st_size != transfer->stat_size ) {
state = HBF_SOURCE_FILE_CHANGE;
}
}
return state;
}
/* Get the HTTP error code for the last request */
static int _hbf_http_error_code(ne_session *session) {
const char *msg = ne_get_error( session );
char *msg2;
int err;
err = strtol(msg, &msg2, 10);
if (msg == msg2) {
err = 0;
}
return err;
}
static Hbf_State _hbf_transfer_no_chunk(ne_session *session, hbf_transfer_t *transfer, const char *verb) {
int res;
const ne_status* req_status;
ne_request *req = ne_request_create(session, verb ? verb : "PUT", transfer->url);
if (!req)
return HBF_MEMORY_FAIL;
ne_add_request_header( req, "Content-Type", "application/octet-stream");
ne_set_request_body_fd(req, transfer->fd, 0, transfer->stat_size);
DEBUG_HBF("HBF: chunking not supported for %s", transfer->url);
res = ne_request_dispatch(req);
req_status = ne_get_status( req );
if (res == NE_OK && req_status->klass == 2) {
ne_request_destroy(req);
return HBF_SUCCESS;
}
if( transfer->error_string ) free( transfer->error_string );
transfer->error_string = strdup( ne_get_error(session) );
transfer->status_code = req_status->code;
ne_request_destroy(req);
return HBF_FAIL;
}
Hbf_State hbf_transfer( ne_session *session, hbf_transfer_t *transfer, const char *verb ) {
Hbf_State state = HBF_TRANSFER_SUCCESS;
int cnt;
if( ! session ) {
state = HBF_SESSION_FAIL;
}
if( ! transfer ) {
state = HBF_SPLITLIST_FAIL;
}
if( ! verb ) {
state = HBF_PARAM_FAIL;
}
if(state == HBF_TRANSFER_SUCCESS) {
DEBUG_HBF("%s request to %s", verb, transfer->url);
}
for( cnt=0; state == HBF_TRANSFER_SUCCESS && cnt < transfer->block_cnt; cnt++ ) {
/* cnt goes from O to block_cnt, but block_id starts at start_id and wrap around
* That way if we have not finished uploaded when we reach block_cnt, we re-upload
* the beginning of the file that the server did not have in cache anymore.
*/
int block_id = (cnt + transfer->start_id) % transfer->block_cnt;
hbf_block_t *block = transfer->block_arr[block_id];
char *transfer_url = NULL;
if( ! block ) state = HBF_PARAM_FAIL;
if( transfer->abort_cb ) {
int do_abort = (transfer->abort_cb)(transfer->user_data);
if( do_abort ) {
state = HBF_USER_ABORTED;
transfer->start_id = block_id % transfer->block_cnt;
}
}
if( state == HBF_TRANSFER_SUCCESS ) {
transfer_url = get_transfer_url( transfer, block_id );
if( ! transfer_url ) {
state = HBF_PARAM_FAIL;
}
}
if( state == HBF_TRANSFER_SUCCESS ) {
if( transfer->block_cnt > 1 && cnt > 0 ) {
/* The block count is > 1, check size and mtime before transmitting. */
state = hbf_validate_source_file(transfer);
if( state == HBF_SOURCE_FILE_CHANGE ) {
/* The source file has changed meanwhile */
}
}
}
if( state == HBF_TRANSFER_SUCCESS || state == HBF_SUCCESS ) {
ne_request *req = ne_request_create(session, verb, transfer_url);
if( req ) {
char buf[21];
snprintf(buf, sizeof(buf), "%"PRId64, transfer->stat_size);
ne_add_request_header(req, "OC-Total-Length", buf);
if( transfer->oc_header_modtime > 0 ) {
snprintf(buf, sizeof(buf), "%"PRId64, transfer->oc_header_modtime);
ne_add_request_header(req, "X-OC-Mtime", buf);
}
if( transfer->previous_etag ) {
ne_add_request_header(req, "If-Match", transfer->previous_etag);
}
if( transfer->block_cnt > 1 ) {
ne_add_request_header(req, "OC-Chunked", "1");
snprintf(buf, sizeof(buf), "%"PRId64, transfer->threshold);
ne_add_request_header(req, "OC-Chunk-Size", buf);
}
ne_add_request_header( req, "Content-Type", "application/octet-stream");
state = _hbf_dav_request(transfer, req, transfer->fd, block );
if( state != HBF_TRANSFER_SUCCESS && state != HBF_SUCCESS) {
if( transfer->error_string ) free( transfer->error_string );
transfer->error_string = strdup( ne_get_error(session) );
transfer->start_id = block_id % transfer->block_cnt;
/* Set the code of the last transmission. */
state = HBF_FAIL;
transfer->status_code = transfer->block_arr[block_id]->http_result_code;
}
ne_request_destroy(req);
if (transfer->block_cnt > 1 && state == HBF_SUCCESS && cnt == 0) {
/* Success on the first chunk is suspicious.
It could happen that the server did not support chunking */
int rc = ne_delete(session, transfer_url);
if (rc == NE_OK && _hbf_http_error_code(session) == 204) {
/* If delete suceeded, it means some proxy strips the OC_CHUNKING header
start again without chunking: */
free( transfer_url );
return _hbf_transfer_no_chunk(session, transfer, verb);
}
}
if (state == HBF_TRANSFER_SUCCESS && transfer->chunk_finished_cb) {
transfer->chunk_finished_cb(transfer, block_id, transfer->user_data);
}
} else {
state = HBF_MEMORY_FAIL;
}
}
free( transfer_url );
}
/* do the source file validation finally (again). */
if( state == HBF_TRANSFER_SUCCESS ) {
/* This means that no etag was returned on one of the chunks to indicate
* that the upload was finished. */
state = HBF_TRANSFER_NOT_ACKED;
}
return state;
}
int hbf_fail_http_code( hbf_transfer_t *transfer )
{
int cnt;
if( ! transfer ) return 0;
for( cnt = 0; cnt < transfer->block_cnt; cnt++ ) {
int block_id = (cnt + transfer->start_id) % transfer->block_cnt;
hbf_block_t *block = transfer->block_arr[block_id];
if( block->state != HBF_NOT_TRANSFERED && block->state != HBF_TRANSFER_SUCCESS ) {
return block->http_result_code;
}
}
return 200;
}
const char *hbf_transfer_etag( hbf_transfer_t *transfer )
{
int cnt;
const char *etag = NULL;
if( ! transfer ) return 0;
/* Loop over all parts and do a assertion that there is only one etag. */
for( cnt = 0; cnt < transfer->block_cnt; cnt++ ) {
int block_id = (cnt + transfer->start_id) % transfer->block_cnt;
hbf_block_t *block = transfer->block_arr[block_id];
if( block->etag ) {
if( etag && strcmp(etag, block->etag) != 0 ) {
/* multiple etags in the transfer, not equal. */
DEBUG_HBF( "WARN: etags are not equal in blocks of one single transfer." );
}
etag = block->etag;
}
}
return etag;
}
const char *hbf_transfer_file_id( hbf_transfer_t *transfer )
{
const char *re = NULL;
if(transfer) {
re = transfer->file_id;
}
return re;
}
const char *hbf_error_string(hbf_transfer_t *transfer, Hbf_State state)
{
const char *re;
int cnt;
switch( state ) {
case HBF_SUCCESS:
re = "Ok.";
break;
case HBF_NOT_TRANSFERED: /* never tried to transfer */
re = "Block was not yet tried to transfer.";
break;
case HBF_TRANSFER: /* transfer currently running */
re = "Block is currently transferred.";
break;
case HBF_TRANSFER_FAILED: /* transfer tried but failed */
re = "Block transfer failed.";
break;
case HBF_TRANSFER_SUCCESS: /* transfer succeeded. */
re = "Block transfer successful.";
break;
case HBF_SPLITLIST_FAIL: /* the file could not be split */
re = "Splitlist could not be computed.";
break;
case HBF_SESSION_FAIL:
re = "No valid session in transfer.";
break;
case HBF_FILESTAT_FAIL:
re = "Source file could not be stat'ed.";
break;
case HBF_PARAM_FAIL:
re = "Parameter fail.";
break;
case HBF_AUTH_FAIL:
re = "Authentication fail.";
break;
case HBF_PROXY_AUTH_FAIL:
re = "Proxy Authentication fail.";
break;
case HBF_CONNECT_FAIL:
re = "Connection could not be established.";
break;
case HBF_TIMEOUT_FAIL:
re = "Network timeout.";
break;
case HBF_MEMORY_FAIL:
re = "Out of memory.";
break;
case HBF_STAT_FAIL:
re = "Filesystem stat on file failed.";
break;
case HBF_SOURCE_FILE_CHANGE:
re = "Source file changed too often during upload.";
break;
case HBF_USER_ABORTED:
re = "Transmission aborted by user.";
break;
case HBF_TRANSFER_NOT_ACKED:
re = "The server did not provide an Etag.";
break;
case HBF_FAIL:
default:
for( cnt = 0; cnt < transfer->block_cnt; cnt++ ) {
int block_id = (cnt + transfer->start_id) % transfer->block_cnt;
hbf_block_t *block = transfer->block_arr[block_id];
if( block->state != HBF_NOT_TRANSFERED && block->state != HBF_TRANSFER_SUCCESS
&& block->http_error_msg != NULL) {
return block->http_error_msg;
}
}
re = "Unknown error.";
}
return re;
}
void hbf_set_abort_callback( hbf_transfer_t *transfer, hbf_abort_callback cb)
{
if( transfer ) {
transfer->abort_cb = cb;
}
}
void hbf_set_log_callback(hbf_transfer_t* transfer, hbf_log_callback cb)
{
if( transfer ) {
transfer->log_cb = cb;
}
}
-142
Ver Arquivo
@@ -1,142 +0,0 @@
/**
* http big file functions
*
* Copyright (c) 2012 by Klaas Freitag <freitag@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _HBF_SEND_H
#define _HBF_SEND_H
#include "config_csync.h"
#ifdef NEON_WITH_LFS /* Switch on LFS in libneon. Never remove the NE_LFS! */
#define NE_LFS
#endif
#include <neon/ne_session.h>
#ifdef __cplusplus
extern "C" {
#endif
enum hbf_state_e {
HBF_SUCCESS,
HBF_NOT_TRANSFERED, /* never tried to transfer */
HBF_TRANSFER, /* transfer currently running */
HBF_TRANSFER_FAILED, /* transfer tried but failed */
HBF_TRANSFER_SUCCESS, /* block transfer succeeded. */
HBF_SPLITLIST_FAIL, /* the file could not be split */
HBF_SESSION_FAIL,
HBF_FILESTAT_FAIL,
HBF_PARAM_FAIL,
HBF_AUTH_FAIL,
HBF_PROXY_AUTH_FAIL,
HBF_CONNECT_FAIL,
HBF_TIMEOUT_FAIL,
HBF_MEMORY_FAIL,
HBF_STAT_FAIL,
HBF_SOURCE_FILE_CHANGE,
HBF_USER_ABORTED,
HBF_TRANSFER_NOT_ACKED,
HBF_FAIL
};
typedef enum hbf_state_e Hbf_State;
typedef struct hbf_block_s hbf_block_t;
struct hbf_block_s {
int seq_number;
int64_t start;
int64_t size;
Hbf_State state;
int http_result_code;
char *http_error_msg;
char *etag;
int tries;
};
typedef struct hbf_transfer_s hbf_transfer_t;
/* Callback for to check on abort */
typedef int (*hbf_abort_callback) (void *);
typedef void (*hbf_log_callback) (const char *, const char *, void*);
typedef void (*hbf_chunk_finished_callback) (hbf_transfer_t*,int, void*);
struct hbf_transfer_s {
hbf_block_t **block_arr;
int block_cnt;
int fd;
int transfer_id;
char *url;
int start_id;
int status_code;
char *error_string;
int64_t stat_size;
time_t modtime;
time_t oc_header_modtime;
int64_t block_size;
int64_t threshold;
void *user_data;
hbf_abort_callback abort_cb;
hbf_log_callback log_cb;
hbf_chunk_finished_callback chunk_finished_cb;
int modtime_accepted;
const char *previous_etag; /* etag send as the If-Match http header */
char *file_id;
#ifndef NDEBUG
int64_t calc_size;
#endif
};
hbf_transfer_t *hbf_init_transfer( const char *dest_uri );
Hbf_State hbf_transfer( ne_session *session, hbf_transfer_t *transfer, const char *verb );
Hbf_State hbf_splitlist( hbf_transfer_t *transfer, int fd );
void hbf_free_transfer( hbf_transfer_t *transfer );
const char *hbf_error_string(hbf_transfer_t* transfer, Hbf_State state);
const char *hbf_transfer_etag( hbf_transfer_t *transfer );
const char *hbf_transfer_file_id( hbf_transfer_t *transfer );
void hbf_set_abort_callback( hbf_transfer_t *transfer, hbf_abort_callback cb);
void hbf_set_log_callback( hbf_transfer_t *transfer, hbf_log_callback cb);
/* returns an http (error) code of the transmission. If the transmission
* succeeded, the code is 200. If it failed, its the error code of the
* first part transmission that failed.
*/
int hbf_fail_http_code( hbf_transfer_t *transfer );
Hbf_State hbf_validate_source_file( hbf_transfer_t *transfer );
#ifdef __cplusplus
}
#endif
#endif
-18
Ver Arquivo
@@ -1,18 +0,0 @@
project(hbf_test C )
add_definitions(-DUNIT_TESTING=1)
find_package(CMocka REQUIRED)
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${CMOCKA_INCLUDE_DIRS}
${NEON_INCLUDE_DIRS}
${HTTPBF_PUBLIC_INCLUDE_DIRS}
)
add_executable(send_test hbf_send_test.c)
target_link_libraries(send_test ${CMOCKA_LIBRARIES} ${NEON_LIBRARIES} ${HBF_LIBRARY} )
Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 1.2 MiB

-162
Ver Arquivo
@@ -1,162 +0,0 @@
/*
* httpbf - send big files via http
*
* Copyright (c) 2012 Klaas Freitag <freitag@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <string.h>
#include <cmocka.h>
#include "config_csync.h"
#include <httpbf.h>
// A test case that does nothing and succeeds.
static void null_test_success(void **state) {
(void) state;
}
static char* test_file( const char* name ) {
if( ! name ) return 0;
char path[260];
strcpy( path, TESTFILEDIR);
if(path[strlen(TESTFILEDIR)-1] != '/')
strcat( path, "/");
strcat( path, name );
return strdup(path);
}
static void test_get_transfer_url( void **state ) {
const char *url = "http://example.org/owncloud";
const char *turl = NULL;
char res[256];
int i;
Hbf_State hbf_state;
hbf_transfer_t *list = NULL;
list = hbf_init_transfer( url );
assert_non_null( list );
/* open a file */
int fd = open( test_file("church.jpg"), O_RDONLY );
assert_true(fd >= 0);
hbf_state = hbf_splitlist(list, fd);
assert_true( hbf_state == HBF_SUCCESS);
for( i=0; i < list->block_cnt; i++ ) {
turl = get_transfer_url( list, i );
sprintf(res, "%s-chunking-%d-%d-%d", url, list->transfer_id,
list->block_cnt, i );
printf( "XX: %s\n", res );
assert_string_equal( turl, res );
}
}
static void test_hbf_init_transfer( void **state ) {
hbf_transfer_t *list = NULL;
const char *url = "http://example.org/owncloud";
list = hbf_init_transfer( url );
assert_non_null( list );
assert_string_equal( url, list->url );
}
/* test with a file size that is not a multiply of the slize size. */
static void test_hbf_splitlist_odd( void **state ){
hbf_transfer_t *list = NULL;
const char *dest_url = "http://localhost/ocm/remote.php/webdav/big/church.jpg";
/* open a file */
int fd = open(test_file("church.jpg"), O_RDONLY);
assert_true(fd >= 0);
int prev_id = 0;
int i;
Hbf_State hbf_state;
/* do a smoke test for uniqueness */
for( i=0; i < 10000; i++) {
list = hbf_init_transfer(dest_url);
assert_non_null(list);
usleep(1);
hbf_state = hbf_splitlist(list, fd);
assert_int_not_equal(list->transfer_id, prev_id);
prev_id = list->transfer_id;
hbf_free_transfer(list);
}
list = hbf_init_transfer(dest_url);
assert_non_null(list);
hbf_state = hbf_splitlist(list, fd);
assert_non_null(list);
assert_int_equal(list->calc_size, list->stat_size);
assert_int_not_equal(list->block_cnt, 0);
assert_true( hbf_state == HBF_SUCCESS);
/* checks on the block list */
int seen_zero_seq = 0;
int prev_seq = -1;
int64_t prev_block_end = -1;
for( i=0; i < list->block_cnt; i++) {
hbf_block_t *blk = list->block_arr[i];
assert_non_null(blk);
if( blk->seq_number == 0 ) seen_zero_seq++;
assert_int_equal(prev_seq, blk->seq_number -1 );
prev_seq = blk->seq_number;
assert_true((prev_block_end+1) == (blk->start));
prev_block_end = blk->start + blk->size;
}
/* Make sure we exactly saw blk->seq_number == 0 exactly one times */
assert_int_equal( seen_zero_seq, 1 );
hbf_free_transfer( list );
}
int main(void) {
const UnitTest tests[] = {
unit_test(null_test_success),
unit_test(test_hbf_splitlist_odd),
unit_test(test_hbf_init_transfer),
unit_test(test_get_transfer_url)
};
return run_tests(tests);
}
-6
Ver Arquivo
@@ -36,9 +36,6 @@
#define CSYNC_LOG_CATEGORY_NAME "csync.vio.main"
#include "csync_log.h"
#if USE_NEON
#include "csync_owncloud.h"
#endif
csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name) {
switch(ctx->replica) {
@@ -132,8 +129,5 @@ char *csync_vio_get_status_string(CSYNC *ctx) {
if(ctx->error_string) {
return ctx->error_string;
}
#ifdef USE_NEON
return owncloud_error_string(ctx);
#endif
return 0;
}
-10
Ver Arquivo
@@ -157,13 +157,6 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
return -1;
}
buf->name = c_basename(uri);
if (buf->name == NULL) {
csync_vio_file_stat_destroy(buf);
c_free_locale_string(wuri);
return -1;
}
buf->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE;
switch(sb.st_mode & S_IFMT) {
@@ -210,9 +203,6 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
#endif
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS;
buf->device = sb.st_dev;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DEVICE;
buf->inode = sb.st_ino;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE;
+64 -88
Ver Arquivo
@@ -116,10 +116,31 @@ int csync_vio_local_closedir(csync_vio_handle_t *dhandle) {
return rc;
}
static time_t FileTimeToUnixTime(FILETIME *filetime, DWORD *remainder)
{
long long int t = filetime->dwHighDateTime;
t <<= 32;
t += (UINT32)filetime->dwLowDateTime;
t -= 116444736000000000LL;
if (t < 0)
{
if (remainder) *remainder = 9999999 - (-t - 1) % 10000000;
return -1 - ((-t - 1) / 10000000);
}
else
{
if (remainder) *remainder = t % 10000000;
return t / 10000000;
}
}
csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) {
dhandle_t *handle = NULL;
csync_vio_file_stat_t *file_stat = NULL;
ULARGE_INTEGER FileIndex;
DWORD rem;
handle = (dhandle_t *) dhandle;
@@ -148,13 +169,43 @@ csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) {
file_stat->name = c_utf8_from_locale(handle->ffd.cFileName);
file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
file_stat->type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
} else {
file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR;
}
if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT
&& handle->ffd.dwReserved0 & IO_REPARSE_TAG_SYMLINK) {
file_stat->flags = CSYNC_VIO_FILE_FLAGS_SYMLINK;
file_stat->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
} else if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE
|| handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE
|| handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) {
file_stat->type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
} else if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
file_stat->type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
} else {
file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR;
}
return file_stat;
file_stat->flags = CSYNC_VIO_FILE_FLAGS_NONE;
/* Check for the hidden flag */
if( handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) {
file_stat->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
}
file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS;
file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
file_stat->size = (handle->ffd.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + handle->ffd.nFileSizeLow;
file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
file_stat->atime = FileTimeToUnixTime(&handle->ffd.ftLastAccessTime, &rem);
file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME;
file_stat->mtime = FileTimeToUnixTime(&handle->ffd.ftLastWriteTime, &rem);
/* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Local File MTime: %llu", (unsigned long long) buf->mtime ); */
file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
file_stat->ctime = FileTimeToUnixTime(&handle->ffd.ftCreationTime, &rem);
file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME;
return file_stat;
err:
SAFE_FREE(file_stat);
@@ -162,29 +213,16 @@ err:
return NULL;
}
static time_t FileTimeToUnixTime(FILETIME *filetime, DWORD *remainder)
{
long long int t = filetime->dwHighDateTime;
t <<= 32;
t += (UINT32)filetime->dwLowDateTime;
t -= 116444736000000000LL;
if (t < 0)
{
if (remainder) *remainder = 9999999 - (-t - 1) % 10000000;
return -1 - ((-t - 1) / 10000000);
}
else
{
if (remainder) *remainder = t % 10000000;
return t / 10000000;
}
}
int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
HANDLE h, hFind;
FILETIME ftCreate, ftAccess, ftWrite;
/* Almost nothing to do since csync_vio_local_readdir already filled up most of the information
But we still need to fetch the file ID.
Possible optimisation: only fetch the file id when we need it (for new files)
*/
HANDLE h;
BY_HANDLE_FILE_INFORMATION fileInfo;
WIN32_FIND_DATAW FindFileData;
ULARGE_INTEGER FileIndex;
mbchar_t *wuri = c_utf8_path_to_locale( uri );
@@ -205,47 +243,6 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
return -1;
}
buf->flags = CSYNC_VIO_FILE_FLAGS_NONE;
do {
// Check first if it is a symlink (code from c_islink)
if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
hFind = FindFirstFileW(wuri, &FindFileData );
if (hFind != INVALID_HANDLE_VALUE) {
if( (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
(FindFileData.dwReserved0 & IO_REPARSE_TAG_SYMLINK) ) {
buf->flags = CSYNC_VIO_FILE_FLAGS_SYMLINK;
buf->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
break;
}
}
FindClose(hFind);
}
if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DEVICE
|| fileInfo.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE
|| fileInfo.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) {
buf->type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
break;
}
if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
buf->type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
break;
}
// fallthrough:
buf->type = CSYNC_VIO_FILE_TYPE_REGULAR;
break;
} while (0);
/* Check for the hidden flag */
if( fileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) {
buf->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
}
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE;
buf->device = fileInfo.dwVolumeSerialNumber;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DEVICE;
/* Get the Windows file id as an inode replacement. */
FileIndex.HighPart = fileInfo.nFileIndexHigh;
FileIndex.LowPart = fileInfo.nFileIndexLow;
@@ -253,28 +250,7 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
/* printf("Index: %I64i\n", FileIndex.QuadPart); */
buf->inode = FileIndex.QuadPart;
buf->size = (fileInfo.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + fileInfo.nFileSizeLow;
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
/* Get the file time with a win32 call rather than through stat. See
* http://www.codeproject.com/Articles/1144/Beating-the-Daylight-Savings-Time-bug-and-getting
* for deeper explanation.
*/
if( GetFileTime(h, &ftCreate, &ftAccess, &ftWrite) ) {
DWORD rem;
buf->atime = FileTimeToUnixTime(&ftAccess, &rem);
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME;
buf->mtime = FileTimeToUnixTime(&ftWrite, &rem);
/* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Local File MTime: %llu", (unsigned long long) buf->mtime ); */
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME;
buf->ctime = FileTimeToUnixTime(&ftCreate, &rem);
buf->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME;
}
c_free_locale_string(wuri);
CloseHandle(h);
return 0;
}
-5
Ver Arquivo
@@ -7,7 +7,6 @@ include_directories(
${CSTDLIB_PUBLIC_INCLUDE_DIRS}
${CMAKE_BINARY_DIR}
${CMOCKA_INCLUDE_DIR}
${HTTPBF_PUBLIC_INCLUDE_DIRS}
)
include_directories(${CHECK_INCLUDE_DIRS})
@@ -54,10 +53,6 @@ add_cmocka_test(check_csync_update csync_tests/check_csync_update.c ${TEST_TARGE
# encoding
add_cmocka_test(check_encoding_functions encoding_tests/check_encoding.c ${TEST_TARGET_LIBRARIES})
# httpbf
set(TEST_HTTPBF_LIBRARIES ${TEST_TARGET_LIBRARIES} ${NEON_LIBRARIES})
add_cmocka_test(check_httpbf httpbf_tests/hbf_send_test.c ${TEST_HTTPBF_LIBRARIES} )
if(UNIT_TESTING)
INSTALL( FILES "${CMOCKA_LIBRARIES}" DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif(UNIT_TESTING)
+17 -1
Ver Arquivo
@@ -48,6 +48,12 @@ static void setup_init(void **state) {
rc = csync_exclude_load(EXCLUDE_LIST_FILE, &(csync->excludes));
assert_int_equal(rc, 0);
/* and add some unicode stuff */
rc = _csync_exclude_add(&(csync->excludes), "*.💩");
assert_int_equal(rc, 0);
rc = _csync_exclude_add(&(csync->excludes), "пятницы.*");
assert_int_equal(rc, 0);
*state = csync;
}
@@ -81,7 +87,7 @@ static void check_csync_exclude_load(void **state)
rc = csync_exclude_load(EXCLUDE_LIST_FILE, &(csync->excludes) );
assert_int_equal(rc, 0);
assert_string_equal(csync->excludes->vector[0], "*.filepart");
assert_string_equal(csync->excludes->vector[0], "*~");
assert_int_not_equal(csync->excludes->count, 0);
}
@@ -145,6 +151,16 @@ static void check_csync_excluded(void **state)
rc = csync_excluded(csync, ".netscape/cache", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
/* Not excluded */
rc = csync_excluded(csync, "unicode/中文.hé", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
/* excluded */
rc = csync_excluded(csync, "unicode/пятницы.txt", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
rc = csync_excluded(csync, "unicode/中文.💩", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
}
static void check_csync_excluded_traversal(void **state)
@@ -201,7 +201,6 @@ static csync_vio_file_stat_t* create_fstat(const char *name,
}
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE;
fs->device = 0;
fs->size = 157459;
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE;
-241
Ver Arquivo
@@ -1,241 +0,0 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2013 by Klaas Freitag <freitag@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <string.h>
#include <unistd.h>
#include <cmocka.h>
#include "config_test.h"
#if USE_NEON
#include "httpbf.c"
#endif
// A test case that does nothing and succeeds.
static void null_test_success(void **state) {
(void) state;
}
#if USE_NEON
static char* test_file( const char* name ) {
char path[260];
if( ! name ) return 0;
strcpy( path, TESTFILES_DIR);
if(path[strlen(TESTFILES_DIR)-1] != '/')
strcat( path, "/");
strcat( path, name );
return strdup(path);
}
static void test_get_transfer_url( void **state ) {
const char *url = "http://example.org/owncloud";
const char *turl = NULL;
int fd;
Hbf_State hbf_state;
hbf_transfer_t *list = NULL;
(void) state;
list = hbf_init_transfer( url );
assert_non_null( list );
/* open a file */
fd = open( test_file("church.jpg"), O_RDONLY );
assert_true(fd >= 0);
hbf_state = hbf_splitlist(list, fd);
assert_true( hbf_state == HBF_SUCCESS);
assert_true( list->block_cnt == 1);
turl = get_transfer_url( list, 0 );
assert_non_null( turl );
assert_string_equal( url, turl );
hbf_free_transfer( list );
}
static void test_get_transfer_url_bigfile( void **state ) {
const char *url = "http://example.org/big_file";
const char *turl = NULL;
char res[256];
int i, fd;
Hbf_State hbf_state;
hbf_transfer_t *list = NULL;
(void) state;
list = hbf_init_transfer( url );
assert_non_null( list );
list->threshold = list->block_size = (1024*1024); /* block size 1 MB */
/* open a file */
fd = open( test_file("church.jpg"), O_RDONLY );
assert_true(fd >= 0);
hbf_state = hbf_splitlist(list, fd);
assert_true( hbf_state == HBF_SUCCESS);
assert_true( list->block_cnt == 2 );
for( i=0; i < list->block_cnt; i++ ) {
turl = get_transfer_url( list, i );
assert_non_null(turl);
sprintf(res, "%s-chunking-%u-%u-%u", url, list->transfer_id,
list->block_cnt, i );
/* printf( "XX: %s\n", res ); */
assert_string_equal( turl, res );
}
hbf_free_transfer(list);
}
static void test_hbf_init_transfer( void **state ) {
hbf_transfer_t *list = NULL;
const char *url = "http://example.org/owncloud";
(void) state;
list = hbf_init_transfer( url );
assert_non_null( list );
assert_string_equal( url, list->url );
}
/* test with a file size that is not a multiply of the slize size. */
static void test_hbf_splitlist_odd( void **state ){
hbf_transfer_t *list = NULL;
const char *dest_url = "http://localhost/ocm/remote.php/webdav/big/church.jpg";
int prev_id = 0;
int i, fd;
Hbf_State hbf_state;
(void) state;
/* open a file */
fd = open(test_file("church.jpg"), O_RDONLY);
assert_true(fd >= 0);
/* do a smoke test for uniqueness */
for( i=0; i < 10000; i++) {
list = hbf_init_transfer(dest_url);
assert_non_null(list);
usleep(1);
hbf_state = hbf_splitlist(list, fd);
assert_int_not_equal(list->transfer_id, prev_id);
prev_id = list->transfer_id;
hbf_free_transfer(list);
}
list = hbf_init_transfer(dest_url);
assert_non_null(list);
hbf_state = hbf_splitlist(list, fd);
assert_non_null(list);
#ifndef NDEBUG
assert_int_equal(list->calc_size, list->stat_size);
#endif
assert_int_not_equal(list->block_cnt, 0);
assert_true( hbf_state == HBF_SUCCESS);
/* checks on the block list */
if( 1 ) {
int seen_zero_seq = 0;
int prev_seq = -1;
int64_t prev_block_end = -1;
for( i=0; i < list->block_cnt; i++) {
hbf_block_t *blk = list->block_arr[i];
assert_non_null(blk);
if( blk->seq_number == 0 ) seen_zero_seq++;
assert_int_equal(prev_seq, blk->seq_number -1 );
prev_seq = blk->seq_number;
assert_true((prev_block_end+1) == (blk->start));
prev_block_end = blk->start + blk->size;
}
/* Make sure we exactly saw blk->seq_number == 0 exactly one times */
assert_int_equal( seen_zero_seq, 1 );
}
hbf_free_transfer( list );
}
/* test with a file size that is not a multiply of the slize size. */
static void test_hbf_splitlist_zero( void **state ){
hbf_transfer_t *list = NULL;
const char *dest_url = "http://localhost/ocm/remote.php/webdav/big/zerofile.txt";
int fd;
Hbf_State hbf_state;
(void) state;
/* open a file */
fd = open(test_file("zerofile.txt"), O_RDONLY);
assert_true(fd >= 0);
list = hbf_init_transfer(dest_url);
assert_non_null(list);
hbf_state = hbf_splitlist(list, fd);
assert_non_null(list);
assert_int_equal(list->stat_size, 0);
#ifndef NDEBUG
assert_int_equal(list->calc_size, list->stat_size);
#endif
assert_int_equal(list->block_cnt, 1);
assert_true( hbf_state == HBF_SUCCESS);
hbf_free_transfer( list );
}
#endif
int main(void) {
const UnitTest tests[] = {
unit_test(null_test_success),
#if USE_NEON
unit_test(test_hbf_splitlist_odd),
unit_test(test_hbf_splitlist_zero),
unit_test(test_hbf_init_transfer),
unit_test(test_get_transfer_url),
unit_test(test_get_transfer_url_bigfile)
#endif
};
return run_tests(tests);
}
-52
Ver Arquivo
@@ -73,15 +73,6 @@ static void setup_dir(void **state) {
assert_int_equal(rc, 0);
}
static void setup_file(void **state) {
int rc;
setup_dir(state);
rc = system("echo \"This is a test\" > /tmp/csync_test/file.txt");
assert_int_equal(rc, 0);
}
static void teardown(void **state) {
CSYNC *csync = *state;
int rc;
@@ -164,46 +155,6 @@ static void check_csync_vio_readdir(void **state)
}
/*
* Test for general functions (stat, chmod, chown, ...)
*/
static void check_csync_vio_stat_dir(void **state)
{
CSYNC *csync = *state;
csync_vio_file_stat_t *fs;
int rc;
fs = csync_vio_file_stat_new();
assert_non_null(fs);
rc = csync_vio_stat(csync, CSYNC_TEST_DIR, fs);
assert_int_equal(rc, 0);
assert_string_equal(fs->name, "csync_test");
assert_int_equal(fs->type, CSYNC_VIO_FILE_TYPE_DIRECTORY);
csync_vio_file_stat_destroy(fs);
}
static void check_csync_vio_stat_file(void **state)
{
CSYNC *csync = *state;
csync_vio_file_stat_t *fs;
int rc;
fs = csync_vio_file_stat_new();
assert_non_null(fs);
rc = csync_vio_stat(csync, CSYNC_TEST_FILE, fs);
assert_int_equal(rc, 0);
assert_string_equal(fs->name, "file.txt");
assert_int_equal(fs->type, CSYNC_VIO_FILE_TYPE_REGULAR);
csync_vio_file_stat_destroy(fs);
}
int torture_run_tests(void)
{
const UnitTest tests[] = {
@@ -211,9 +162,6 @@ int torture_run_tests(void)
unit_test_setup_teardown(check_csync_vio_opendir_perm, setup, teardown),
unit_test(check_csync_vio_closedir_null),
unit_test_setup_teardown(check_csync_vio_readdir, setup_dir, teardown),
unit_test_setup_teardown(check_csync_vio_stat_dir, setup_dir, teardown),
unit_test_setup_teardown(check_csync_vio_stat_file, setup_file, teardown),
};
return run_tests(tests);
+5 -5
Ver Arquivo
@@ -11,8 +11,8 @@ the Updater will check for updates and notify you when a new version is
available.
.. note:: Because of various technical issues, desktop sync clients older than
1.7 will not be allowed to connect and sync with the ownCloud 8.1 server. It is
highly recommended to keep your client updated.
1.7 will not be allowed to connect and sync with the ownCloud 8.1+ server. It
is highly recommended to keep your client updated.
Basic Workflow
--------------
@@ -73,8 +73,8 @@ To prevent automatic updates, but allow manual overrides:
1. Edit these Registry keys:
a. (32-bit) ``HKEY_LOCAL_MACHINE\Software\ownCloud\ownCloud``
b. (64-bit) ``HKEY_LOCAL_MACHINE\Software\Wow6432Node\ownCloud\ownCloud``
a. (32-bit-Windows) ``HKEY_LOCAL_MACHINE\Software\ownCloud\ownCloud``
b. (64-bit-Windows) ``HKEY_LOCAL_MACHINE\Software\Wow6432Node\ownCloud\ownCloud``
2. Add the key ``skipUpdateCheck`` (of type DWORD).
@@ -89,7 +89,7 @@ To prevent automatic updates and disallow manual overrides:
1. Edit this Registry key:
HKEY_LOCAL_MACHINE\Software\Policies\ownCloud\ownCloud
``HKEY_LOCAL_MACHINE\Software\Policies\ownCloud\ownCloud``
2. Add the key ``skipUpdateCheck`` (of type DWORD).
+3 -3
Ver Arquivo
@@ -48,9 +48,9 @@ copyright = u'2013, The ownCloud developers'
# built documents.
#
# The short X.Y version.
version = '@VERSION_MAJOR@.@VERSION_MINOR@'
version = '@MIRALL_VERSION_MAJOR@.@MIRALL_VERSION_MINOR@'
# The full version, including alpha/beta/rc tags.
release = '@VERSION@'
release = '@MIRALL_VERSION@'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -189,7 +189,7 @@ latex_documents = [
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
latex_logo = '@LATEX_LOGO@'
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 5.7 KiB

Depois

Largura:  |  Altura:  |  Tamanho: 5.5 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 39 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 41 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 44 KiB

Arquivo binário não exibido.

Antes

Largura:  |  Altura:  |  Tamanho: 59 KiB

+5 -1
Ver Arquivo
@@ -3,7 +3,8 @@ Installing the Desktop Synchronization Client
=============================================
You can download the latest version of the ownCloud Desktop Synchronization
Client from the `ownCloud Website <https://owncloud.org/install/#desktop>`_.
Client from the `ownCloud download page
<https://owncloud.org/install/#desktop>`_.
There are clients for Linux, Mac OS X, and Microsoft Windows.
Installation on Mac OS X and Windows is the same as for any software
@@ -21,6 +22,9 @@ will display a notification when an update is available.
Linux users must also have a password manager enabled, such as GNOME Keyring or
KWallet, so that the sync client can login automatically.
You will also find links to source code archives and older versions on the
download page.
Installation Wizard
-------------------
+4 -3
Ver Arquivo
@@ -13,14 +13,15 @@ Your files are always automatically synchronized between your ownCloud server
and local PC.
.. note:: Because of various technical issues, desktop sync clients older than
1.7 will not allowed to connect and sync with the ownCloud 8.1 server. It is
highly recommended to keep your client updated.
1.7 will not allowed to connect and sync with the ownCloud 8.1+ server. It
is highly recommended to keep your client updated.
Improvements and New Features
-----------------------------
The 2.0 release of the ownCloud desktop sync client has many new features and
improvements.
improvements. (See the `complete changelog
<https://owncloud.org/changelog/desktop/>`_.)
* Multi-account support
* Many UI improvements
Arquivo binário não exibido.
+26 -13
Ver Arquivo
@@ -92,18 +92,27 @@ have the following features:
removed synchronization on an account (see **Remove Sync** below).
The little button with three dots that sits to the right of the sync status bar
offers three additional options:
offers four additional options:
* Open Folder
* Pause Sync
* Choose What to Sync
* Pause Sync / Resume Sync
* Remove Sync
**Pause Sync** pauses sync operations without making any changes to your account.
**Open Folder** opens a file explorer window displaying the client-side folder
that is being synced.
**Remove Sync** suspends synchronization without removing the account, and it
removes your folder sync selection. When you're ready to resume synchronization
click the **Add Folder Sync Connection** button, and re-select the folders you
want to sync.
**Choose What to Sync** opens the folder sync tree view. From there you can
choose to sync all or only some of the folders in the folder tree.
**Pause Sync** pauses sync operations for just this folder sync connection
without making any changes to your account.
**Resume Sync** resumes sync operations for this folder sync connection.
**Remove Sync** removes this folder sync connection without removing the
account. If you want to synchronize the folder tree again then click the
**Add Folder Sync Connection** button, and re-select the folder tree that
you want to sync.
.. image:: images/client-7.png
:alt: Extra options for sync operations
@@ -122,12 +131,15 @@ Multi-Account Support
You may now configure multiple ownCloud accounts in your desktop sync client.
Simply click the **Add an Account** button on the General tab, and follow the
account creation wizard. The new account will appear as a new tab in the settings dialog, where you can adjust its settings at any time.
account creation wizard. The new account will appear as a new tab in the
settings dialog, where you can adjust its settings at any time.
Editing Ignored Files
---------------------
The Ignored Files Editor can be opened by clicking on the button in the General tab of the settings dialog. The settings apply to all configured accounts. The :guilabel:`Ignored Files Editor` provides a list of files that are ignored
The Ignored Files Editor can be opened by clicking on the button in the General
tab of the settings dialog. The settings apply to all configured accounts. The
:guilabel:`Ignored Files Editor` provides a list of files that are ignored
(that is, not synchronized) by the client and server during synchronizations.
You may add additional files or directories that you want to exclude from the
synchronization process. In addition to using standard characters, the Ignored
@@ -184,7 +196,8 @@ components of the path being checked.
.. note:: Custom entries are currently not validated for syntactical
correctness by the editor, so you will not see any warnings for bad
syntax. If your synchronization does not work as you expected, check your syntax.
syntax. If your synchronization does not work as you expected, check your
syntax.
Each pattern string in the list is preceded by a checkbox. When the check box
contains a check mark, in addition to ignoring the file or directory component
@@ -197,8 +210,8 @@ this list:
- The ownCloud Client always excludes files containing characters that cannot
be synchronized to other file systems.
- Files are removed that cause individual errors three times during a synchronization.
However, the client provides the option of retrying a synchronization three additional
times on files that produce errors.
- Files are removed that cause individual errors three times during a
synchronization. However, the client provides the option of retrying a
synchronization three additional times on files that produce errors.
For more detailed information see :ref:`ignored-files-label`.
+6 -6
Ver Arquivo
@@ -51,8 +51,8 @@ Where:
* ``Connected to <ownCloud instance> as <user>``: Indicates the ownCloud server
which the client is syncing with and the user account on that server.
* ``Add Folder...``: Provides the ability to add another folder to the sync
(see ``Adding a folder``).
* ``Add Folder Sync Connection...``: Provides the ability to add another folder to the sync
(see ``Adding a folder sync connection``).
* ``Pause/Resume``: Will pause the current sync or prevent the client from
starting a new sync. Resume will resume the sync process.
* ``Remove``: Will remove the selected folder from being synced. This is used,
@@ -74,11 +74,11 @@ Where:
.. image:: images/settings_account.png
:scale: 50 %
Adding a Folder
^^^^^^^^^^^^^^^
Adding a Folder Sync Connection
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Adding a new sync is initiated by clicking ``Add Folder...`` in the ``Account``
settings.
Adding a new sync is initiated by clicking ``Add Folder Sync Connection`` in
the ``Account`` settings.
..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
Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 243 B

Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 122 B

@@ -1,256 +0,0 @@
From 3a26dc77f8e988ea99b23c4d5a2c831ecc31c920 Mon Sep 17 00:00:00 2001
From: Olivier Goffart <ogoffart@woboq.com>
Date: Thu, 17 Jul 2014 13:26:56 +0200
Subject: [PATCH] WIP: add KOverlayIconPlugin
---
.../src/kitemviews/kfileitemmodelrolesupdater.cpp | 35 ++++++++++++-
.../src/kitemviews/kfileitemmodelrolesupdater.h | 9 ++++
lib/konq/CMakeLists.txt | 4 +-
lib/konq/koverlayiconplugin.cpp | 30 ++++++++++++
lib/konq/koverlayiconplugin.desktop | 4 ++
lib/konq/koverlayiconplugin.h | 57 ++++++++++++++++++++++
6 files changed, 137 insertions(+), 2 deletions(-)
create mode 100644 lib/konq/koverlayiconplugin.cpp
create mode 100644 lib/konq/koverlayiconplugin.desktop
create mode 100644 lib/konq/koverlayiconplugin.h
diff --git a/dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp b/dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp
index 0865d40..840a65d 100644
--- a/dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp
+++ b/dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp
@@ -28,9 +28,11 @@
#include <KGlobal>
#include <KIO/JobUiDelegate>
#include <KIO/PreviewJob>
+#include <KServiceTypeTrader>
#include "private/kpixmapmodifier.h"
#include "private/kdirectorycontentscounter.h"
+#include <koverlayiconplugin.h>
#include <QApplication>
#include <QPainter>
@@ -129,6 +131,17 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO
m_directoryContentsCounter = new KDirectoryContentsCounter(m_model, this);
connect(m_directoryContentsCounter, SIGNAL(result(QString,int)),
this, SLOT(slotDirectoryContentsCountReceived(QString,int)));
+
+
+ const KService::List pluginServices = KServiceTypeTrader::self()->query("KOverlayIconPlugin");
+
+ for (KService::List::ConstIterator it = pluginServices.constBegin(); it != pluginServices.constEnd(); ++it) {
+ KOverlayIconPlugin* plugin = (*it)->createInstance<KOverlayIconPlugin>(this);
+ if (plugin) {
+ m_overlayIconsPlugin.append(plugin);
+ connect(plugin, SIGNAL(overlaysChanged(KUrl,QStringList)), this, SLOT(slotOverlaysChanged(KUrl,QStringList)));
+ }
+ }
}
KFileItemModelRolesUpdater::~KFileItemModelRolesUpdater()
@@ -1075,7 +1088,11 @@ QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileIte
data.insert("type", item.mimeComment());
}
- data.insert("iconOverlays", item.overlays());
+ QStringList overlays = item.overlays();
+ foreach(KOverlayIconPlugin *it, m_overlayIconsPlugin) {
+ overlays.append(it->getOverlays(item));
+ }
+ data.insert("iconOverlays", overlays);
#ifdef HAVE_BALOO
if (m_balooFileMonitor) {
@@ -1086,6 +1103,22 @@ QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileIte
return data;
}
+void KFileItemModelRolesUpdater::slotOverlaysChanged(const KUrl& url, const QStringList &)
+{
+ KFileItem item = m_model->fileItem(url);
+ if (item.isNull())
+ return;
+ int index = m_model->index(item);
+ QHash <QByteArray, QVariant> data = m_model->data(index);
+ QStringList overlays = item.overlays();
+ foreach(KOverlayIconPlugin *it, m_overlayIconsPlugin) {
+ overlays.append(it->getOverlays(item));
+ }
+ data.insert("iconOverlays", overlays);
+ m_model->setData(index, data);
+}
+
+
void KFileItemModelRolesUpdater::updateAllPreviews()
{
if (m_state == Paused) {
diff --git a/dolphin/src/kitemviews/kfileitemmodelrolesupdater.h b/dolphin/src/kitemviews/kfileitemmodelrolesupdater.h
index a9e979a..6d3add0 100644
--- a/dolphin/src/kitemviews/kfileitemmodelrolesupdater.h
+++ b/dolphin/src/kitemviews/kfileitemmodelrolesupdater.h
@@ -32,6 +32,7 @@
#include <QSize>
#include <QStringList>
+class KOverlayIconPlugin;
class KDirectoryContentsCounter;
class KFileItemModel;
class KJob;
@@ -180,6 +181,12 @@ private slots:
void slotPreviewJobFinished();
/**
+ * Is invoked when one of the KOverlayIconPlugin emit the signal that an overlay has changed
+ */
+ void slotOverlaysChanged(const KUrl&, const QStringList&);
+
+
+ /**
* Resolves the sort role of the next item in m_pendingSortRole, applies it
* to the model, and invokes itself if there are any pending items left. If
* that is not the case, \a startUpdating() is called.
@@ -331,6 +338,8 @@ private:
KDirectoryContentsCounter* m_directoryContentsCounter;
+ QList<KOverlayIconPlugin*> m_overlayIconsPlugin;
+
#ifdef HAVE_BALOO
Baloo::FileMonitor* m_balooFileMonitor;
#endif
diff --git a/lib/konq/CMakeLists.txt b/lib/konq/CMakeLists.txt
index 8ecbfa9..7381caf 100644
--- a/lib/konq/CMakeLists.txt
+++ b/lib/konq/CMakeLists.txt
@@ -22,6 +22,7 @@ set(konq_LIB_SRCS
konq_historyprovider.cpp
kversioncontrolplugin.cpp # used by dolphin and its version control plugins (deprecated)
kversioncontrolplugin2.cpp # used by dolphin and its version control plugins
+ koverlayiconplugin.cpp
konq_nameandurlinputdialog.cpp # deprecated (functionality has moved to kdelibs)
knewmenu.cpp # deprecated (functionality has moved to kdelibs)
@@ -67,8 +68,9 @@ install( FILES
konq_fileitemcapabilities.h
kversioncontrolplugin.h
kversioncontrolplugin2.h
+ koverlayiconplugin.h
konq_historyprovider.h
konq_historyentry.h
DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel
)
-install( FILES konqpopupmenuplugin.desktop konqdndpopupmenuplugin.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR} )
+install( FILES konqpopupmenuplugin.desktop konqdndpopupmenuplugin.desktop koverlayiconplugin.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR} )
diff --git a/lib/konq/koverlayiconplugin.cpp b/lib/konq/koverlayiconplugin.cpp
new file mode 100644
index 0000000..6125040
--- /dev/null
+++ b/lib/konq/koverlayiconplugin.cpp
@@ -0,0 +1,30 @@
+/*****************************************************************************
+ * Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.com> *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License version 2 as published by the Free Software Foundation. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public License *
+ * along with this library; see the file COPYING.LIB. If not, write to *
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301, USA. *
+ *****************************************************************************/
+
+#include "koverlayiconplugin.h"
+#include <KFileItem>
+
+KOverlayIconPlugin::KOverlayIconPlugin(QObject* parent) : QObject(parent)
+{
+}
+
+KOverlayIconPlugin::~KOverlayIconPlugin()
+{
+}
+
+#include "koverlayiconplugin.moc"
diff --git a/lib/konq/koverlayiconplugin.desktop b/lib/konq/koverlayiconplugin.desktop
new file mode 100644
index 0000000..65a1170
--- /dev/null
+++ b/lib/konq/koverlayiconplugin.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KOverlayIconPlugin
+Comment=Plugin to add overlay icons in Dolphin
diff --git a/lib/konq/koverlayiconplugin.h b/lib/konq/koverlayiconplugin.h
new file mode 100644
index 0000000..bcdf31b
--- /dev/null
+++ b/lib/konq/koverlayiconplugin.h
@@ -0,0 +1,57 @@
+/*****************************************************************************
+ * Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.com> *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License version 2 as published by the Free Software Foundation. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public License *
+ * along with this library; see the file COPYING.LIB. If not, write to *
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301, USA. *
+ *****************************************************************************/
+
+
+#ifndef OverlayIconPlugin_H
+#define OverlayIconPlugin_H
+
+#include <QtCore/QObject>
+#include <libkonq_export.h>
+
+class KUrl;
+class KFileItem;
+
+/**
+ * @brief Base class for overlay icon plugins.
+ *
+ * Enables the file manager to show custom overlay icons on files.
+ *
+ * To write a custom plugin you need to create a .desktop file for your plugin with
+ * KDE-ServiceTypes=KOverlayIconPlugin
+ */
+class LIBKONQ_EXPORT KOverlayIconPlugin : public QObject {
+ Q_OBJECT
+ void *d;
+public:
+ explicit KOverlayIconPlugin(QObject *parent = 0);
+ ~KOverlayIconPlugin();
+
+ /**
+ * Returns a list of overlay pixmap to add to a file
+ * This can be a path to an icon, or the icon name
+ */
+ virtual QStringList getOverlays(const KFileItem &item) = 0;
+signals:
+
+ /**
+ * Emit this signal when the list of overlay icon changed for a given URL
+ */
+ void overlaysChanged(const KUrl &url, const QStringList &overlays);
+};
+
+#endif
--
2.1.3
+41 -12
Ver Arquivo
@@ -1,17 +1,46 @@
cmake_minimum_required(VERSION 2.6)
project(dolphin-owncloud)
find_package(KDE4 REQUIRED)
include(KDE4Defaults)
include(MacroLibrary)
find_package(LibKonq REQUIRED)
add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS})
cmake_minimum_required(VERSION 2.8.12)
include(FeatureSummary)
set(QT_MIN_VERSION "5.3.0")
set(KF5_MIN_VERSION "5.16.0")
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Core Network)
find_package(ECM 1.2.0 REQUIRED CONFIG)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS CoreAddons KIO)
set_package_properties(DolphinVcs PROPERTIES
DESCRIPTION "the Dolphin plugin library"
URL "http://dolphin.kde.org/"
TYPE REQUIRED
PURPOSE "Provides plugin interfaces for Dolphin."
)
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings)
include(ECMMarkNonGuiExecutable)
include(GenerateExportHeader)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS)
include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES} )
include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${LIBKONQ_INCLUDE_DIR} )
kde4_add_plugin(ownclouddolphinplugin ownclouddolphinplugin.cpp)
#---HELPER---
add_library(ownclouddolphinpluginhelper SHARED ownclouddolphinpluginhelper.cpp)
target_link_libraries(ownclouddolphinpluginhelper Qt5::Network)
generate_export_header(ownclouddolphinpluginhelper)
install(TARGETS ownclouddolphinpluginhelper LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
target_link_libraries(ownclouddolphinplugin ${KDE4_KIO_LIBS} ${LIBKONQ_LIBRARY})
install(FILES ownclouddolphinplugin.desktop DESTINATION ${SERVICES_INSTALL_DIR})
install(TARGETS ownclouddolphinplugin DESTINATION ${PLUGIN_INSTALL_DIR})
#---OVERLAY PLUGIN---
kcoreaddons_add_plugin(ownclouddolphinoverlayplugin INSTALL_NAMESPACE "kf5/overlayicon"
JSON ownclouddolphinoverlayplugin.json SOURCES ownclouddolphinoverlayplugin.cpp)
target_link_libraries(ownclouddolphinoverlayplugin KF5::CoreAddons KF5::KIOCore KF5::KIOWidgets ownclouddolphinpluginhelper)
#---ACTION PLUGIN---
add_library(ownclouddolphinactionplugin MODULE ownclouddolphinactionplugin.cpp)
target_link_libraries(ownclouddolphinactionplugin KF5::CoreAddons KF5::KIOCore KF5::KIOWidgets ownclouddolphinpluginhelper)
install(FILES ownclouddolphinactionplugin.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR})
install(TARGETS ownclouddolphinactionplugin DESTINATION ${KDE_INSTALL_PLUGINDIR})
+4 -11
Ver Arquivo
@@ -1,18 +1,11 @@
- The patch 0001-KOverlayIconPlugin.patch should be applied to kde-baseapps git repository
(It should apply to both KDE/4.14 or Applications/14.12 branches)
- Recompile and install dolphin
- Recompile and install recent enough version of dolphin and kio (git from oct 2015)
- Build and install the plugin
- After installing, run
kdeinit4 --noincremental
- Make sure to set XDG_DATA_DIRS=$PREFIX/share, QT_PLUGIN_PATH=$PREFIX/lib64/plugins/
- To test that the plugin is well installed
ktraderclient --servicetype KOverlayIconPlugin
It should show the Owncloud plugin
- After installing, run
kdeinit5 --noincremental
- restart dolphin (make sure to kill all instances)
@@ -0,0 +1,67 @@
/******************************************************************************
* Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
******************************************************************************/
#include <KPluginFactory>
#include <KPluginLoader>
#include <KIOWidgets/kabstractfileitemactionplugin.h>
#include <QtNetwork/QLocalSocket>
#include <KIOCore/kfileitem.h>
#include <KIOCore/KFileItemListProperties>
#include <QtWidgets/QAction>
#include <QtCore/QTimer>
#include "ownclouddolphinpluginhelper.h"
class OwncloudDolphinPluginAction : public KAbstractFileItemActionPlugin
{
public:
explicit OwncloudDolphinPluginAction(QObject* parent, const QList<QVariant>&)
: KAbstractFileItemActionPlugin(parent) { }
QList<QAction*> actions(const KFileItemListProperties& fileItemInfos, QWidget* parentWidget) Q_DECL_OVERRIDE
{
auto helper = OwncloudDolphinPluginHelper::instance();
QList<QUrl> urls = fileItemInfos.urlList();
if (urls.count() != 1 || !helper->isConnected())
return {};
auto url = urls.first();
if (!url.isLocalFile())
return {};
auto localFile = url.toLocalFile();
const auto paths = helper->paths();
if (!std::any_of(paths.begin(), paths.end(), [&](const QString &s) {
return localFile.startsWith(s);
} ))
return {};
auto act = new QAction(parentWidget);
act->setText(helper->shareActionString());
connect(act, &QAction::triggered, this, [localFile, helper] {
helper->sendCommand("SHARE:"+localFile.toUtf8()+"\n");
} );
return { act };
}
};
K_PLUGIN_FACTORY(OwncloudDolphinPluginActionFactory, registerPlugin<OwncloudDolphinPluginAction>();)
K_EXPORT_PLUGIN(OwncloudDolphinPluginActionFactory("ownclouddolhpinpluginaction"))
#include "ownclouddolphinactionplugin.moc"
@@ -0,0 +1,6 @@
[Desktop Entry]
Type=Service
Name=OwncloudAction
ServiceTypes=KFileItemAction/Plugin
MimeType=application/octet-stream;inode/directory;
X-KDE-Library=ownclouddolphinactionplugin
@@ -0,0 +1,101 @@
/******************************************************************************
* Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
******************************************************************************/
#include <KOverlayIconPlugin>
#include <KPluginFactory>
#include <QtNetwork/QLocalSocket>
#include <KIOCore/kfileitem.h>
#include <QTimer>
#include "ownclouddolphinpluginhelper.h"
class OwncloudDolphinPlugin : public KOverlayIconPlugin
{
Q_PLUGIN_METADATA(IID "com.owncloud.ovarlayiconplugin" FILE "ownclouddolphinoverlayplugin.json");
Q_OBJECT
typedef QHash<QByteArray, QByteArray> StatusMap;
StatusMap m_status;
public:
OwncloudDolphinPlugin() {
auto helper = OwncloudDolphinPluginHelper::instance();
QObject::connect(helper, &OwncloudDolphinPluginHelper::commandRecieved,
this, &OwncloudDolphinPlugin::slotCommandRecieved);
}
QStringList getOverlays(const QUrl& url) override {
auto helper = OwncloudDolphinPluginHelper::instance();
if (!helper->isConnected())
return QStringList();
if (!url.isLocalFile())
return QStringList();
const QByteArray localFile = url.toLocalFile().toUtf8();
helper->sendCommand("RETRIEVE_FILE_STATUS:" + localFile + "\n");
StatusMap::iterator it = m_status.find(localFile);
if (it != m_status.constEnd()) {
return overlaysForString(*it);
}
return QStringList();
}
private:
QStringList overlaysForString(const QByteArray &status) {
QStringList r;
if (status.startsWith("NOP"))
return r;
if (status.startsWith("OK"))
r << "ownCloud_ok";
if (status.startsWith("SYNC") || status.startsWith("NEW"))
r << "ownCloud_sync";
if (status.startsWith("IGNORE") || status.startsWith("WARN"))
r << "ownCloud_warn";
if (status.startsWith("ERROR"))
r << "ownCloud_error";
if (status.contains("+SWM"))
r << "document-share";
return r;
}
void slotCommandRecieved(const QByteArray &line) {
QList<QByteArray> tokens = line.split(':');
if (tokens.count() != 3)
return;
if (tokens[0] != "STATUS" && tokens[0] != "BROADCAST")
return;
if (tokens[2].isEmpty())
return;
const QByteArray name = tokens[2];
QByteArray &status = m_status[name]; // reference to the item in the hash
if (status == tokens[1])
return;
status = tokens[1];
emit overlaysChanged(QUrl::fromLocalFile(QString::fromUtf8(name)), overlaysForString(status));
}
};
#include "ownclouddolphinoverlayplugin.moc"
@@ -0,0 +1,8 @@
{
"KPlugin": {
"Description": "Overlay icon for owncloud",
"ServiceTypes": [
"KOverlayIconPlugin"
]
}
}
@@ -1,131 +0,0 @@
/******************************************************************************
* Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
******************************************************************************/
#include <koverlayiconplugin.h>
#include <KPluginFactory>
#include <KPluginLoader>
#include <kdebug.h>
#include <kfileitem.h>
#include <QtNetwork/QLocalSocket>
class OwncloudDolphinPlugin : public KOverlayIconPlugin
{
Q_OBJECT
QLocalSocket m_socket;
typedef QHash<QByteArray, QByteArray> StatusMap;
StatusMap m_status;
QByteArray m_line;
public:
explicit OwncloudDolphinPlugin(QObject* parent, const QList<QVariant>&) : KOverlayIconPlugin(parent) {
connect(&m_socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
tryConnect();
}
virtual QStringList getOverlays(const KFileItem& item) {
KUrl url = item.url();
if (!url.isLocalFile())
return QStringList();
const QByteArray localFile = url.toLocalFile().toUtf8();
kDebug() << localFile;
tryConnect();
if (m_socket.state() == QLocalSocket::ConnectingState) {
if (!m_socket.waitForConnected(100)) {
kWarning() << "not connected" << m_socket.errorString();
}
}
if (m_socket.state() == QLocalSocket::ConnectedState) {
m_socket.write("RETRIEVE_FILE_STATUS:");
m_socket.write(localFile);
m_socket.write("\n");
}
StatusMap::iterator it = m_status.find(localFile);
if (it != m_status.constEnd()) {
return overlaysForString(*it);
}
return QStringList();
}
private:
void tryConnect() {
if (m_socket.state() != QLocalSocket::UnconnectedState)
return;
QString runtimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
QString socketPath = runtimeDir + "/" + "ownCloud" + "/socket";
m_socket.connectToServer(socketPath);
}
QStringList overlaysForString(const QByteArray status) {
QStringList r;
if (status.startsWith("NOP"))
return r;
if (status.startsWith("OK"))
r << "dialog-ok";
if (status.startsWith("SYNC") || status.startsWith("NEW"))
r << "view-refresh";
if (status.contains("+SWM"))
r << "document-share";
kDebug() << status << r;
return r;
}
private slots:
void readyRead() {
while (m_socket.bytesAvailable()) {
m_line += m_socket.readLine();
if (!m_line.endsWith("\n"))
continue;
QByteArray line;
qSwap(line, m_line);
line.chop(1);
kDebug() << "got line " << line;
if (line.isEmpty())
continue;
QList<QByteArray> tokens = line.split(':');
if (tokens.count() != 3)
continue;
if (tokens[0] != "STATUS" && tokens[0] != "BROADCAST")
continue;
if (tokens[2].isEmpty())
continue;
const QByteArray name = tokens[2];
QByteArray &status = m_status[name]; // reference to the item in the hash
if (status == tokens[1])
continue;
status = tokens[1];
emit this->overlaysChanged(KUrl::fromLocalFile(QString::fromUtf8(name)), overlaysForString(status));
}
}
};
K_PLUGIN_FACTORY(OwncloudDolphinPluginFactory, registerPlugin<OwncloudDolphinPlugin>();)
K_EXPORT_PLUGIN(OwncloudDolphinPluginFactory("ownclouddolhpinplugin"))
#include "ownclouddolphinplugin.moc"
@@ -1,6 +0,0 @@
[Desktop Entry]
Type=Service
Name=Owncloud
X-KDE-ServiceTypes=KOverlayIconPlugin
MimeType=text/plain;
X-KDE-Library=ownclouddolphinplugin
@@ -0,0 +1,98 @@
/******************************************************************************
* Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
******************************************************************************/
#include <QtNetwork/QLocalSocket>
#include <qcoreevent.h>
#include <QFile>
#include "ownclouddolphinpluginhelper.h"
OwncloudDolphinPluginHelper* OwncloudDolphinPluginHelper::instance()
{
static OwncloudDolphinPluginHelper self;
return &self;
}
OwncloudDolphinPluginHelper::OwncloudDolphinPluginHelper()
{
connect(&_socket, &QLocalSocket::connected, this, &OwncloudDolphinPluginHelper::slotConnected);
connect(&_socket, &QLocalSocket::readyRead, this, &OwncloudDolphinPluginHelper::slotReadyRead);
_connectTimer.start(45 * 1000, Qt::VeryCoarseTimer, this);
tryConnect();
}
void OwncloudDolphinPluginHelper::timerEvent(QTimerEvent *e)
{
if (e->timerId() == _connectTimer.timerId()) {
tryConnect();
return;
}
QObject::timerEvent(e);
}
bool OwncloudDolphinPluginHelper::isConnected() const
{
return _socket.state() == QLocalSocket::ConnectedState;
}
void OwncloudDolphinPluginHelper::sendCommand(const char* data)
{
_socket.write(data);
_socket.flush();
}
void OwncloudDolphinPluginHelper::slotConnected()
{
sendCommand("SHARE_MENU_TITLE:\n");
}
void OwncloudDolphinPluginHelper::tryConnect()
{
if (_socket.state() != QLocalSocket::UnconnectedState) {
return;
}
QString runtimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
QString socketPath = runtimeDir + QLatin1String("/ownCloud/socket");
_socket.connectToServer(socketPath);
}
void OwncloudDolphinPluginHelper::slotReadyRead()
{
while (_socket.bytesAvailable()) {
_line += _socket.readLine();
if (!_line.endsWith("\n"))
continue;
QByteArray line;
qSwap(line, _line);
line.chop(1);
if (line.isEmpty())
continue;
if (line.startsWith("REGISTER_PATH:")) {
auto col = line.indexOf(':');
QString file = QString::fromUtf8(line.constData() + col + 1, line.size() - col - 1);
_paths.append(file);
continue;
} else if (line.startsWith("SHARE_MENU_TITLE:")) {
auto col = line.indexOf(':');
_shareActionString = QString::fromUtf8(line.constData() + col + 1, line.size() - col - 1);
continue;
}
emit commandRecieved(line);
}
}
@@ -0,0 +1,52 @@
/******************************************************************************
* Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
******************************************************************************/
#pragma once
#include <QObject>
#include <QBasicTimer>
#include <QLocalSocket>
#include "ownclouddolphinpluginhelper_export.h"
class OWNCLOUDDOLPHINPLUGINHELPER_EXPORT OwncloudDolphinPluginHelper : public QObject {
Q_OBJECT
public:
static OwncloudDolphinPluginHelper *instance();
QString shareActionString() const { return _shareActionString; }
bool isConnected() const;
void sendCommand(const char *data);
QVector<QString> paths() const { return _paths; }
signals:
void commandRecieved(const QByteArray &cmd);
protected:
void timerEvent(QTimerEvent*) override;
private:
OwncloudDolphinPluginHelper();
void slotConnected();
void slotReadyRead();
void tryConnect();
QLocalSocket _socket;
QByteArray _line;
QVector<QString> _paths;
QString _shareActionString;
QBasicTimer _connectTimer;
};
@@ -1,267 +0,0 @@
From d452ed613a9e02ed81eec2f3226f28babff240c8 Mon Sep 17 00:00:00 2001
From: Olivier Goffart <ogoffart@woboq.com>
Date: Thu, 17 Jul 2014 13:26:56 +0200
Subject: [PATCH] WIP: add KOverlayIconPlugin
Conflicts:
dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp
lib/konq/CMakeLists.txt
---
.../src/kitemviews/kfileitemmodelrolesupdater.cpp | 38 ++++++++++++++-
.../src/kitemviews/kfileitemmodelrolesupdater.h | 9 ++++
lib/konq/src/CMakeLists.txt | 4 +-
lib/konq/src/koverlayiconplugin.cpp | 30 ++++++++++++
lib/konq/src/koverlayiconplugin.desktop | 4 ++
lib/konq/src/koverlayiconplugin.h | 57 ++++++++++++++++++++++
6 files changed, 140 insertions(+), 2 deletions(-)
create mode 100644 lib/konq/src/koverlayiconplugin.cpp
create mode 100644 lib/konq/src/koverlayiconplugin.desktop
create mode 100644 lib/konq/src/koverlayiconplugin.h
diff --git a/dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp b/dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp
index df521e2..4d94836 100644
--- a/dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp
+++ b/dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp
@@ -29,9 +29,11 @@
#include <KJobWidgets>
#include <KIO/JobUiDelegate>
#include <KIO/PreviewJob>
+#include <KServiceTypeTrader>
#include "private/kpixmapmodifier.h"
#include "private/kdirectorycontentscounter.h"
+#include <koverlayiconplugin.h>
#include <QApplication>
#include <QPainter>
@@ -129,6 +131,20 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO
m_directoryContentsCounter = new KDirectoryContentsCounter(m_model, this);
connect(m_directoryContentsCounter, &KDirectoryContentsCounter::result,
this, &KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived);
+
+
+ const KService::List pluginServices = KServiceTypeTrader::self()->query("KOverlayIconPlugin");
+
+ for (KService::List::ConstIterator it = pluginServices.constBegin(); it != pluginServices.constEnd(); ++it) {
+ QString error;
+ KOverlayIconPlugin* plugin = (*it)->createInstance<KOverlayIconPlugin>(this, QVariantList(), &error);
+ if (plugin) {
+ m_overlayIconsPlugin.append(plugin);
+ connect(plugin, &KOverlayIconPlugin::overlaysChanged, this, &KFileItemModelRolesUpdater::slotOverlaysChanged);
+ } else {
+ qWarning() << "Could not load plugin " << (*it)->name() << ":" << error;
+ }
+ }
}
KFileItemModelRolesUpdater::~KFileItemModelRolesUpdater()
@@ -1065,7 +1081,11 @@ QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileIte
data.insert("type", item.mimeComment());
}
- data.insert("iconOverlays", item.overlays());
+ QStringList overlays = item.overlays();
+ foreach(KOverlayIconPlugin *it, m_overlayIconsPlugin) {
+ overlays.append(it->getOverlays(item));
+ }
+ data.insert("iconOverlays", overlays);
#ifdef HAVE_BALOO
if (m_balooFileMonitor) {
@@ -1076,6 +1096,22 @@ QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileIte
return data;
}
+void KFileItemModelRolesUpdater::slotOverlaysChanged(const QUrl& url, const QStringList &)
+{
+ KFileItem item = m_model->fileItem(url);
+ if (item.isNull())
+ return;
+ int index = m_model->index(item);
+ QHash <QByteArray, QVariant> data = m_model->data(index);
+ QStringList overlays = item.overlays();
+ foreach(KOverlayIconPlugin *it, m_overlayIconsPlugin) {
+ overlays.append(it->getOverlays(item));
+ }
+ data.insert("iconOverlays", overlays);
+ m_model->setData(index, data);
+}
+
+
void KFileItemModelRolesUpdater::updateAllPreviews()
{
if (m_state == Paused) {
diff --git a/dolphin/src/kitemviews/kfileitemmodelrolesupdater.h b/dolphin/src/kitemviews/kfileitemmodelrolesupdater.h
index 6c82dbe..1e5b98e 100644
--- a/dolphin/src/kitemviews/kfileitemmodelrolesupdater.h
+++ b/dolphin/src/kitemviews/kfileitemmodelrolesupdater.h
@@ -32,6 +32,7 @@
#include <QSize>
#include <QStringList>
+class KOverlayIconPlugin;
class KDirectoryContentsCounter;
class KFileItemModel;
class QPixmap;
@@ -183,6 +184,12 @@ private slots:
void slotPreviewJobFinished();
/**
+ * Is invoked when one of the KOverlayIconPlugin emit the signal that an overlay has changed
+ */
+ void slotOverlaysChanged(const QUrl& url, const QStringList&);
+
+
+ /**
* Resolves the sort role of the next item in m_pendingSortRole, applies it
* to the model, and invokes itself if there are any pending items left. If
* that is not the case, \a startUpdating() is called.
@@ -333,6 +340,8 @@ private:
KDirectoryContentsCounter* m_directoryContentsCounter;
+ QList<KOverlayIconPlugin*> m_overlayIconsPlugin;
+
#ifdef HAVE_BALOO
Baloo::FileMonitor* m_balooFileMonitor;
#endif
diff --git a/lib/konq/src/CMakeLists.txt b/lib/konq/src/CMakeLists.txt
index 9c05b9f..0ac0526 100644
--- a/lib/konq/src/CMakeLists.txt
+++ b/lib/konq/src/CMakeLists.txt
@@ -15,6 +15,7 @@ set(konq_LIB_SRCS
konq_historyprovider.cpp # konqueror and konqueror/sidebar
kversioncontrolplugin.cpp # used by dolphin and its version control plugins (deprecated)
kversioncontrolplugin2.cpp # used by dolphin and its version control plugins
+ koverlayiconplugin.cpp
)
add_library(KF5Konq ${konq_LIB_SRCS})
@@ -64,13 +65,14 @@ install(FILES
konq_popupmenuplugin.h
kversioncontrolplugin.h
kversioncontrolplugin2.h
+ koverlayiconplugin.h
${LibKonq_BINARY_DIR}/src/libkonq_export.h
DESTINATION ${KF5_INCLUDE_INSTALL_DIR}
COMPONENT Devel
)
-install(FILES konqpopupmenuplugin.desktop konqdndpopupmenuplugin.desktop
+install(FILES konqpopupmenuplugin.desktop konqdndpopupmenuplugin.desktop koverlayiconplugin.desktop
DESTINATION ${SERVICETYPES_INSTALL_DIR}
)
diff --git a/lib/konq/src/koverlayiconplugin.cpp b/lib/konq/src/koverlayiconplugin.cpp
new file mode 100644
index 0000000..6125040
--- /dev/null
+++ b/lib/konq/src/koverlayiconplugin.cpp
@@ -0,0 +1,30 @@
+/*****************************************************************************
+ * Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.com> *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License version 2 as published by the Free Software Foundation. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public License *
+ * along with this library; see the file COPYING.LIB. If not, write to *
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301, USA. *
+ *****************************************************************************/
+
+#include "koverlayiconplugin.h"
+#include <KFileItem>
+
+KOverlayIconPlugin::KOverlayIconPlugin(QObject* parent) : QObject(parent)
+{
+}
+
+KOverlayIconPlugin::~KOverlayIconPlugin()
+{
+}
+
+#include "koverlayiconplugin.moc"
diff --git a/lib/konq/src/koverlayiconplugin.desktop b/lib/konq/src/koverlayiconplugin.desktop
new file mode 100644
index 0000000..65a1170
--- /dev/null
+++ b/lib/konq/src/koverlayiconplugin.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KOverlayIconPlugin
+Comment=Plugin to add overlay icons in Dolphin
diff --git a/lib/konq/src/koverlayiconplugin.h b/lib/konq/src/koverlayiconplugin.h
new file mode 100644
index 0000000..bfdaa2f
--- /dev/null
+++ b/lib/konq/src/koverlayiconplugin.h
@@ -0,0 +1,57 @@
+/*****************************************************************************
+ * Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.com> *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License version 2 as published by the Free Software Foundation. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public License *
+ * along with this library; see the file COPYING.LIB. If not, write to *
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301, USA. *
+ *****************************************************************************/
+
+
+#ifndef OverlayIconPlugin_H
+#define OverlayIconPlugin_H
+
+#include <QtCore/QObject>
+#include <libkonq_export.h>
+
+class KUrl;
+class KFileItem;
+
+/**
+ * @brief Base class for overlay icon plugins.
+ *
+ * Enables the file manager to show custom overlay icons on files.
+ *
+ * To write a custom plugin you need to create a .desktop file for your plugin with
+ * KDE-ServiceTypes=KOverlayIconPlugin
+ */
+class LIBKONQ_EXPORT KOverlayIconPlugin : public QObject {
+ Q_OBJECT
+ void *d;
+public:
+ explicit KOverlayIconPlugin(QObject *parent = 0);
+ ~KOverlayIconPlugin();
+
+ /**
+ * Returns a list of overlay pixmap to add to a file
+ * This can be a path to an icon, or the icon name
+ */
+ virtual QStringList getOverlays(const KFileItem &item) = 0;
+signals:
+
+ /**
+ * Emit this signal when the list of overlay icon changed for a given URL
+ */
+ void overlaysChanged(const QUrl &url, const QStringList &overlays);
+};
+
+#endif
--
2.2.1
-30
Ver Arquivo
@@ -1,30 +0,0 @@
project(dolphin-owncloud)
cmake_minimum_required(VERSION 2.8)
set(QT_MIN_VERSION "5.3.0")
find_package(ECM 1.2.0 REQUIRED CONFIG)
include(FeatureSummary)
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH})
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings)
include(ECMInstallIcons)
include(ECMSetupVersion)
find_package(Qt5 CONFIG REQUIRED Core DBus Test Widgets)
find_package(KF5 REQUIRED Archive Bookmarks CoreAddons Config ConfigWidgets DBusAddons KIO KDELibs4Support Parts Activities)
find_package(KF5Konq REQUIRED)
add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS)
add_library(ownclouddolphinplugin MODULE ownclouddolphinplugin.cpp)
target_link_libraries(ownclouddolphinplugin KF5::Konq)
install(FILES ownclouddolphinplugin.desktop DESTINATION ${SERVICES_INSTALL_DIR})
install(TARGETS ownclouddolphinplugin DESTINATION ${PLUGIN_INSTALL_DIR})
-16
Ver Arquivo
@@ -1,16 +0,0 @@
- The patch 0001-KOverlayIconPlugin.patch should be applied to kde-baseapps git repository
(It should apply to frameworks branch)
- Recompile and install dolphin (frameworks branch)
- Build and install the plugin
- Make sure to set XDG_DATA_DIRS=$PREFIX/share, QT_PLUGIN_PATH=$PREFIX/lib64/plugins/
- After installing, run
kdeinit5 --noincremental
- restart dolphin (make sure to kill all instances)
@@ -1,131 +0,0 @@
/******************************************************************************
* Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
******************************************************************************/
#include <koverlayiconplugin.h>
#include <KPluginFactory>
#include <KPluginLoader>
#include <kdebug.h>
#include <kfileitem.h>
#include <QtNetwork/QLocalSocket>
class OwncloudDolphinPlugin : public KOverlayIconPlugin
{
Q_OBJECT
QLocalSocket m_socket;
typedef QHash<QByteArray, QByteArray> StatusMap;
StatusMap m_status;
QByteArray m_line;
public:
explicit OwncloudDolphinPlugin(QObject* parent, const QList<QVariant>&) : KOverlayIconPlugin(parent) {
connect(&m_socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
tryConnect();
}
virtual QStringList getOverlays(const KFileItem& item) {
auto url = item.url();
if (!url.isLocalFile())
return QStringList();
const QByteArray localFile = url.toLocalFile().toUtf8();
kDebug() << localFile;
tryConnect();
if (m_socket.state() == QLocalSocket::ConnectingState) {
if (!m_socket.waitForConnected(100)) {
kWarning() << "not connected" << m_socket.errorString();
}
}
if (m_socket.state() == QLocalSocket::ConnectedState) {
m_socket.write("RETRIEVE_FILE_STATUS:");
m_socket.write(localFile);
m_socket.write("\n");
}
StatusMap::iterator it = m_status.find(localFile);
if (it != m_status.constEnd()) {
return overlaysForString(*it);
}
return QStringList();
}
private:
void tryConnect() {
if (m_socket.state() != QLocalSocket::UnconnectedState)
return;
QString runtimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
QString socketPath = runtimeDir + "/" + "ownCloud" + "/socket";
m_socket.connectToServer(socketPath);
}
QStringList overlaysForString(const QByteArray status) {
QStringList r;
if (status.startsWith("NOP"))
return r;
if (status.startsWith("OK"))
r << "dialog-ok";
if (status.startsWith("SYNC") || status.startsWith("NEW"))
r << "view-refresh";
if (status.contains("+SWM"))
r << "document-share";
kDebug() << status << r;
return r;
}
private slots:
void readyRead() {
while (m_socket.bytesAvailable()) {
m_line += m_socket.readLine();
if (!m_line.endsWith("\n"))
continue;
QByteArray line;
qSwap(line, m_line);
line.chop(1);
kDebug() << "got line " << line;
if (line.isEmpty())
continue;
QList<QByteArray> tokens = line.split(':');
if (tokens.count() != 3)
continue;
if (tokens[0] != "STATUS" && tokens[0] != "BROADCAST")
continue;
if (tokens[2].isEmpty())
continue;
const QByteArray name = tokens[2];
QByteArray &status = m_status[name]; // reference to the item in the hash
if (status == tokens[1])
continue;
status = tokens[1];
emit this->overlaysChanged(QUrl::fromLocalFile(QString::fromUtf8(name)), overlaysForString(status));
}
}
};
K_PLUGIN_FACTORY(OwncloudDolphinPluginFactory, registerPlugin<OwncloudDolphinPlugin>();)
K_EXPORT_PLUGIN(OwncloudDolphinPluginFactory("ownclouddolhpinplugin"))
#include "ownclouddolphinplugin.moc"
@@ -1,6 +0,0 @@
[Desktop Entry]
Type=Service
Name=Owncloud
X-KDE-ServiceTypes=KOverlayIconPlugin
MimeType=text/plain;
X-KDE-Library=ownclouddolphinplugin
+48 -42
Ver Arquivo
@@ -2,6 +2,10 @@
#
# Copyright (C) by Klaas Freitag <freitag@owncloud.com>
#
# This program is the core of OwnCloud integration to Nautilus
# It will be installed on /usr/share/nautilus-python/extensions/ with the paquet owncloud-client-nautilus
# (https://github.com/owncloud/client/edit/master/shell_integration/nautilus/syncstate.py)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
@@ -18,7 +22,9 @@ import socket
from gi.repository import GObject, Nautilus
# do not touch the following line.
print("Initializing owncloud-client-nautilus extension")
# Do not touch the following line.
appname = 'ownCloud'
def get_local_path(url):
@@ -38,7 +44,6 @@ def get_runtime_dir():
return fallback
class SocketConnect(GObject.GObject):
def __init__(self):
GObject.GObject.__init__(self)
@@ -48,8 +53,8 @@ class SocketConnect(GObject.GObject):
self._sock = None
self._listeners = [self._update_registered_paths]
self._remainder = ''
self.nautilusVFSFile_table = {} # not needed in this object actually but shared
# all over the other objects.
self.nautilusVFSFile_table = {} # not needed in this object actually but shared
# all over the other objects.
# returns true when one should try again!
if self._connectToSocketServer():
@@ -77,38 +82,38 @@ class SocketConnect(GObject.GObject):
def _connectToSocketServer(self):
try:
self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
postfix = "/"+appname+"/socket"
sock_file = get_runtime_dir()+postfix
postfix = "/" + appname + "/socket" # Should use os.path.join instead
sock_file = get_runtime_dir() + postfix
print ("Socket: " + sock_file + " <=> " + postfix)
if sock_file != postfix:
try:
print("Socket File: "+sock_file)
print("Socket File: " + sock_file)
self._sock.connect(sock_file)
self.connected = True
print("Setting connected to %r" % self.connected )
print("Setting connected to %r." % self.connected )
self._watch_id = GObject.io_add_watch(self._sock, GObject.IO_IN, self._handle_notify)
print("Socket watch id: "+str(self._watch_id))
return False # don't run again
print("Socket watch id: " + str(self._watch_id))
return False # Don't run again
except Exception as e:
print("Could not connect to unix socket." + str(e))
print("Could not connect to unix socket. " + str(e))
else:
print("Sock-File not valid: "+sock_file)
except Exception as e:
print("Connect could not be established, try again later ")
print("Sock-File not valid: " + sock_file)
except Exception as e: # Bad habbit
print("Connect could not be established, try again later.")
self._sock.close()
return True # run again, if enabled via timeout_add()
return True # Run again, if enabled via timeout_add()
# notify is the raw answer from the socket
# Notify is the raw answer from the socket
def _handle_notify(self, source, condition):
data = source.recv(1024)
# prepend the remaining data from last call
# Prepend the remaining data from last call
if len(self._remainder) > 0:
data = self._remainder+data
data = self._remainder + data
self._remainder = ''
if len(data) > 0:
# remember the remainder for next round
# Remember the remainder for next round
lastNL = data.rfind('\n');
if lastNL > -1 and lastNL < len(data):
self._remainder = data[lastNL+1:]
@@ -119,10 +124,10 @@ class SocketConnect(GObject.GObject):
else:
return False
return True # run again
return True # Run again
def _handle_server_response(self, line):
print("Server response: "+line)
print("Server response: " + line)
parts = line.split(':')
action = parts[0]
args = parts[1:]
@@ -151,32 +156,33 @@ class MenuExtension(GObject.GObject, Nautilus.MenuProvider):
def get_file_items(self, window, files):
if len(files) != 1:
return
file=files[0]
items=[]
file = files[0]
items = []
# internal or external file?!
# Internal or external file?!
syncedFile = False
for reg_path in socketConnect.registered_paths:
topLevelFolder=False
topLevelFolder = False
filename = get_local_path(file.get_uri())
#check if its a folder (ends with an /), if yes add a "/" otherwise it will not find the entry in the table
if os.path.isdir(filename+"/"):
filename=filename+"/"
#check if toplevel folder, we need to ignore those as they cannot be shared
# Check if its a folder (ends with an /), if yes add a "/"
# otherwise it will not find the entry in the table
if os.path.isdir(filename + "/"):
filename += "/"
# Check if toplevel folder, we need to ignore those as they cannot be shared
if filename.count("/") < (reg_path.count("/")+2):
topLevelFolder=True
# only show the menu extension if the file is synced and the sync
# Only show the menu extension if the file is synced and the sync
# status is ok. Not for ignored files etc.
# ignore top level folders
if filename.startswith(reg_path) and topLevelFolder == False and socketConnect.nautilusVFSFile_table[filename]['state'] == 'OK':
syncedFile = True
# if it is neither in a synced folder or is a directory
if (not syncedFile):
# If it is neither in a synced folder or is a directory
if not syncedFile:
return items
# create an menu item
labelStr = "Share with "+appname+"..."
# Create an menu item
labelStr = "Share with " + appname + "..."
item = Nautilus.MenuItem(name='NautilusPython::ShareItem', label=labelStr,
tip='Share file %s through ownCloud' % file.get_name())
item.connect("activate", self.menu_share, file)
@@ -187,8 +193,8 @@ class MenuExtension(GObject.GObject, Nautilus.MenuProvider):
def menu_share(self, menu, file):
filename = get_local_path(file.get_uri())
print("Share file "+filename)
socketConnect.sendCommand("SHARE:"+filename+"\n")
print("Share file " + filename)
socketConnect.sendCommand("SHARE:" + filename + "\n")
class SyncStateExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.InfoProvider):
@@ -205,7 +211,7 @@ class SyncStateExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.Info
return None
def askForOverlay(self, file):
# print("Asking for overlay for "+file)
# print("Asking for overlay for "+file) # For debug only
if os.path.isdir(file):
folderStatus = socketConnect.sendCommand("RETRIEVE_FOLDER_STATUS:"+file+"\n");
@@ -240,8 +246,8 @@ class SyncStateExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.Info
'NOP' : appname +'_error'
}
# file = args[0]
# print "Action for " + file + ": "+args[0]
# file = args[0] # For debug only
# print("Action for " + file + ": " + args[0]) # For debug only
if action == 'STATUS':
newState = args[0]
emblem = Emblems[newState]
@@ -253,7 +259,7 @@ class SyncStateExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.Info
if( not itemStore['state'] or newState != itemStore['state'] ):
item = itemStore['item']
item.add_emblem(emblem)
# print "Setting emblem on " + args[1]+ "<>"+emblem+"<>"
# print("Setting emblem on " + args[1] + "<>" + emblem + "<>") # For debug only
socketConnect.nautilusVFSFile_table[args[1]] = {'item': item, 'state':newState}
elif action == 'UPDATE_VIEW':
@@ -278,9 +284,9 @@ class SyncStateExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.Info
if filename.startswith(reg_path):
socketConnect.nautilusVFSFile_table[filename] = {'item': item, 'state':''}
# item.add_string_attribute('share_state', "share state")
# item.add_string_attribute('share_state', "share state") # ?
self.askForOverlay(filename)
break
else:
# print("Not in scope:"+filename)
# print("Not in scope:" + filename) # For debug only
pass
+40028 -9160
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+1049 -321
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+20 -25
Ver Arquivo
@@ -58,6 +58,7 @@ struct CmdOptions {
bool ignoreHiddenFiles;
QString exclude;
QString unsyncedfolders;
int restartTimes;
};
// we can't use csync_set_userdata because the SyncEngine sets it already.
@@ -114,11 +115,11 @@ public:
_sslTrusted(false)
{}
QString queryPassword(bool *ok, const QString&) Q_DECL_OVERRIDE {
if (ok) {
*ok = true;
}
return ::queryPassword(user());
void askFromUser() Q_DECL_OVERRIDE {
_password = ::queryPassword(user());
_ready = true;
persist();
emit asked();
}
void setSSLTrusted( bool isTrusted ) {
@@ -155,17 +156,18 @@ void help()
std::cout << " --password, -p [pass] Use [pass] as password" << std::endl;
std::cout << " -n Use netrc (5) for login" << std::endl;
std::cout << " --non-interactive Do not block execution with interaction" << std::endl;
std::cout << " --max-sync-retries [n] Retries maximum n times (default to 3)" << std::endl;
std::cout << " -h Sync hidden files,do not ignore them" << std::endl;
std::cout << " --version, -v Display version and exit" << std::endl;
std::cout << "" << std::endl;
exit(1);
exit(0);
}
void showVersion() {
const char *binaryName = APPLICATION_EXECUTABLE "cmd";
std::cout << binaryName << " version " << qPrintable(Theme::instance()->version()) << std::endl;
exit(1);
exit(0);
}
void parseOptions( const QStringList& app_args, CmdOptions *options )
@@ -222,6 +224,8 @@ void parseOptions( const QStringList& app_args, CmdOptions *options )
options->exclude = it.next();
} else if( option == "--unsyncedfolders" && !it.peekNext().startsWith("-") ) {
options->unsyncedfolders = it.next();
} else if( option == "--max-sync-retries" && !it.peekNext().startsWith("-") ) {
options->restartTimes = it.next().toInt();
} else {
help();
}
@@ -268,6 +272,7 @@ int main(int argc, char **argv) {
options.useNetrc = false;
options.interactive = true;
options.ignoreHiddenFiles = true;
options.restartTimes = 3;
ClientProxy clientProxy;
parseOptions( app.arguments(), &options );
@@ -356,6 +361,7 @@ int main(int argc, char **argv) {
account->setCredentials(cred);
account->setSslErrorHandler(sslErrorHandler);
int restartCount = 0;
restart_sync:
CSYNC *_csync_ctx;
@@ -369,7 +375,6 @@ restart_sync:
csync_set_log_level(options.silent ? 1 : 11);
opts = &options;
cred->syncContextPreInit(_csync_ctx);
if( csync_init( _csync_ctx ) < 0 ) {
qFatal("Could not initialize csync!");
@@ -379,15 +384,11 @@ restart_sync:
// ignore hidden files or not
_csync_ctx->ignore_hidden_files = options.ignoreHiddenFiles;
csync_set_module_property(_csync_ctx, "csync_context", _csync_ctx);
if( !options.proxy.isNull() ) {
QString host;
int port = 0;
bool ok;
// Set as default and let overwrite later
csync_set_module_property(_csync_ctx, "proxy_type", (void*) "NoProxy");
QStringList pList = options.proxy.split(':');
if(pList.count() == 3) {
// http: //192.168.178.23 : 8080
@@ -397,13 +398,6 @@ restart_sync:
port = pList.at(2).toInt(&ok);
if( !host.isNull() ) {
csync_set_module_property(_csync_ctx, "proxy_type", (void*) "HttpProxy");
csync_set_module_property(_csync_ctx, "proxy_host", host.toUtf8().data());
if( ok && port ) {
csync_set_module_property(_csync_ctx, "proxy_port", (void*) &port);
}
}
QNetworkProxyFactory::setUseSystemConfiguration(false);
QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::HttpProxy, host, port));
}
@@ -414,7 +408,6 @@ restart_sync:
url.remove(0, 8);
url = QString("http%1").arg(url);
}
clientProxy.setCSyncProxy(QUrl(url), _csync_ctx);
}
// Exclude lists
@@ -453,8 +446,6 @@ restart_sync:
return EXIT_FAILURE;
}
cred->syncContextPreStart(_csync_ctx);
Cmd cmd;
SyncJournalDb db(options.source_dir);
if (!selectiveSyncList.empty()) {
@@ -462,7 +453,7 @@ restart_sync:
}
SyncEngine engine(account, _csync_ctx, options.source_dir, QUrl(options.target_url).path(), folder, &db);
QObject::connect(&engine, SIGNAL(finished()), &app, SLOT(quit()));
QObject::connect(&engine, SIGNAL(finished(bool)), &app, SLOT(quit()));
QObject::connect(&engine, SIGNAL(transmissionProgress(ProgressInfo)), &cmd, SLOT(transmissionProgressSlot()));
// Have to be done async, else, an error before exec() does not terminate the event loop.
@@ -473,8 +464,12 @@ restart_sync:
csync_destroy(_csync_ctx);
if (engine.isAnotherSyncNeeded()) {
qDebug() << "Restarting Sync, because another sync is needed";
goto restart_sync;
if (restartCount < options.restartTimes) {
restartCount++;
qDebug() << "Restarting Sync, because another sync is needed" << restartCount;
goto restart_sync;
}
qWarning() << "Another sync is needed, but not done because restart count is exceeded" << restartCount;
}
return 0;
+19 -3
Ver Arquivo
@@ -21,8 +21,13 @@ set(client_UI
ignorelisteditor.ui
networksettings.ui
protocolwidget.ui
activitywidget.ui
synclogdialog.ui
settingsdialog.ui
sharedialog.ui
sharelinkwidget.ui
shareusergroupwidget.ui
sharewidget.ui
sslerrordialog.ui
owncloudsetuppage.ui
addcertificatedialog.ui
@@ -50,29 +55,39 @@ set(client_SRCS
ignorelisteditor.cpp
logbrowser.cpp
networksettings.cpp
ocsjob.cpp
ocssharejob.cpp
ocsshareejob.cpp
openfilemanager.cpp
owncloudgui.cpp
owncloudsetupwizard.cpp
protocolwidget.cpp
activitywidget.cpp
activityitemdelegate.cpp
selectivesyncdialog.cpp
settingsdialog.cpp
share.cpp
sharedialog.cpp
sharelinkwidget.cpp
shareusergroupwidget.cpp
sharee.cpp
socketapi.cpp
sslbutton.cpp
sslerrordialog.cpp
syncrunfilelog.cpp
systray.cpp
thumbnailjob.cpp
quotainfo.cpp
accountstate.cpp
addcertificatedialog.cpp
authenticationdialog.cpp
proxyauthhandler.cpp
proxyauthdialog.cpp
synclogdialog.cpp
creds/credentialsfactory.cpp
creds/httpcredentialsgui.cpp
creds/shibbolethcredentials.cpp
creds/shibboleth/shibbolethwebview.cpp
creds/shibboleth/shibbolethrefresher.cpp
creds/shibboleth/shibbolethuserjob.cpp
wizard/abstractcredswizardpage.cpp
wizard/owncloudadvancedsetuppage.cpp
@@ -98,6 +113,7 @@ IF( APPLE )
list(APPEND client_SRCS settingsdialogmac.cpp)
list(APPEND client_SRCS socketapisocket_mac.mm)
list(APPEND client_SRCS systray.mm)
list(APPEND client_SRCS clipboard.mm)
if(SPARKLE_FOUND)
# Define this, we need to check in updater.cpp
@@ -221,7 +237,7 @@ if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
endforeach( _file )
endif(NOT WIN32)
install(FILES ${client_I18N} DESTINATION ${DATADIR}/${APPLICATION_EXECUTABLE}/i18n)
install(FILES ${client_I18N} DESTINATION ${SHAREDIR}/${APPLICATION_EXECUTABLE}/i18n)
# we may not add MACOSX_BUNDLE here, if not building one
@@ -292,7 +308,7 @@ install(TARGETS ${APPLICATION_EXECUTABLE}
if(BUILD_OWNCLOUD_OSX_BUNDLE AND NOT BUILD_LIBRARIES_ONLY)
get_target_property (QT_QMAKE_EXECUTABLE Qt5::qmake IMPORTED_LOCATION)
install(CODE "
message(STATUS \"Deploying (Qt) dependencies and fixing library pathes...\")
message(STATUS \"Deploying (Qt) dependencies and fixing library paths...\")
execute_process(COMMAND \"${CMAKE_SOURCE_DIR}/admin/osx/macdeployqt.py\" ${CMAKE_INSTALL_PREFIX}/${OWNCLOUD_OSX_BUNDLE} ${QT_QMAKE_EXECUTABLE})
" COMPONENT RUNTIME)
endif()
+10
Ver Arquivo
@@ -215,6 +215,16 @@ AccountPtr AccountManager::load(QSettings& settings)
return acc;
}
AccountStatePtr AccountManager::account(const QString& name)
{
foreach (const auto& acc, _accounts) {
if (acc->account()->displayName() == name) {
return acc;
}
}
return AccountStatePtr();
}
AccountState *AccountManager::addAccount(const AccountPtr& newAccount)
{
auto id = newAccount->id();
+8 -3
Ver Arquivo
@@ -36,13 +36,13 @@ public:
void save(bool saveCredentials = true);
/**
* Creates account objects from from a given settings file.
* Creates account objects from a given settings file.
* return true if the account was restored
*/
bool restore();
/**
* Add this account in the list of saved account.
* Add this account in the list of saved accounts.
* Typically called from the wizard
*/
AccountState *addAccount(const AccountPtr &newAccount);
@@ -54,10 +54,15 @@ public:
/**
* Return a list of all accounts.
* (this is a list of QSharedPointer for internal reason, one should normaly not keep a copy of them)
* (this is a list of QSharedPointer for internal reasons, one should normally not keep a copy of them)
*/
QList<AccountStatePtr> accounts() { return _accounts; }
/**
* Return the account state pointer for an account identified by its display name
*/
AccountStatePtr account(const QString& name);
/**
* Delete the AccountState
*/
+159 -29
Ver Arquivo
@@ -42,6 +42,7 @@
#include <QKeySequence>
#include <QIcon>
#include <QVariant>
#include <QToolTip>
#include <qstringlistmodel.h>
#include <qpropertyanimation.h>
@@ -82,14 +83,21 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) :
#else
ui->_folderList->setMinimumWidth( 300 );
#endif
createAccountToolbox();
connect(AccountManager::instance(), SIGNAL(accountAdded(AccountState*)),
SLOT(slotAccountAdded(AccountState*)));
connect(ui->_folderList, SIGNAL(customContextMenuRequested(QPoint)),
this, SLOT(slotCustomContextMenuRequested(QPoint)));
connect(ui->_folderList, SIGNAL(expanded(QModelIndex)) , this, SLOT(refreshSelectiveSyncStatus()));
connect(ui->_folderList, SIGNAL(collapsed(QModelIndex)) , this, SLOT(refreshSelectiveSyncStatus()));
connect(ui->selectiveSyncNotification, SIGNAL(linkActivated(QString)),
this, SLOT(slotLinkActivated(QString)));
connect(_model, SIGNAL(suggestExpand(QModelIndex)), ui->_folderList, SLOT(expand(QModelIndex)));
connect(_model, SIGNAL(dirtyChanged()), this, SLOT(refreshSelectiveSyncStatus()));
refreshSelectiveSyncStatus();
connect(_model, SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(refreshSelectiveSyncStatus()));
QAction *resetFolderAction = new QAction(this);
resetFolderAction->setShortcut(QKeySequence(Qt::Key_F5));
@@ -101,7 +109,8 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) :
connect(syncNowAction, SIGNAL(triggered()), SLOT(slotSyncCurrentFolderNow()));
addAction(syncNowAction);
connect(ui->_folderList, SIGNAL(clicked(QModelIndex)), SLOT(slotFolderActivated(QModelIndex)));
connect(ui->_folderList, SIGNAL(clicked(const QModelIndex &)),
this, SLOT(slotFolderListClicked(const QModelIndex&)));
connect(ui->selectiveSyncApply, SIGNAL(clicked()), _model, SLOT(slotApplySelectiveSync()));
connect(ui->selectiveSyncCancel, SIGNAL(clicked()), _model, SLOT(resetFolders()));
@@ -120,7 +129,27 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) :
connect( &_quotaInfo, SIGNAL(quotaUpdated(qint64,qint64)),
this, SLOT(slotUpdateQuota(qint64,qint64)));
connect(ui->deleteButton, SIGNAL(clicked()) , this, SLOT(slotDeleteAccount()));
}
void AccountSettings::createAccountToolbox()
{
QMenu *menu = new QMenu();
_addAccountAction = new QAction(tr("Add new"), this);
menu->addAction(_addAccountAction);
connect(_addAccountAction, SIGNAL(triggered(bool)), SLOT(slotOpenAccountWizard()));
_toggleSignInOutAction = new QAction(tr("Sign out"), this);
connect(_toggleSignInOutAction, SIGNAL(triggered(bool)), SLOT(slotToggleSignInState()));
menu->addAction(_toggleSignInOutAction);
QAction *action = new QAction(tr("Remove"), this);
menu->addAction(action);
connect( action, SIGNAL(triggered(bool)), SLOT(slotDeleteAccount()));
ui->_accountToolbox->setText(tr("Account") + QLatin1Char(' '));
ui->_accountToolbox->setMenu(menu);
ui->_accountToolbox->setPopupMode(QToolButton::InstantPopup);
// Expand already on single click
ui->_folderList->setExpandsOnDoubleClick(false);
@@ -128,20 +157,25 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) :
this, SLOT(slotFolderListClicked(const QModelIndex&)));
}
void AccountSettings::slotOpenAccountWizard()
{
if (QSystemTrayIcon::isSystemTrayAvailable()) {
topLevelWidget()->close();
}
OwncloudSetupWizard::runWizard(qApp, SLOT(slotownCloudWizardDone(int)), 0);
}
void AccountSettings::slotToggleSignInState()
{
bool signedInState = _accountState->isSignedOut();
_accountState->setSignedOut( !signedInState );
}
void AccountSettings::doExpand()
{
ui->_folderList->expandToDepth(0);
}
void AccountSettings::slotFolderListClicked( const QModelIndex& indx )
{
if( _model->classify(indx) == FolderStatusModel::RootFolder &&
_accountState && _accountState->state() == AccountState::Connected ) {
bool expanded = ! (ui->_folderList->isExpanded(indx));
ui->_folderList->setExpanded(indx, expanded);
}
}
void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
{
QTreeView *tv = ui->_folderList;
@@ -165,24 +199,29 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
QAction *ac = menu->addAction(tr("Open folder"));
connect(ac, SIGNAL(triggered(bool)), this, SLOT(slotOpenCurrentFolder()));
ac = menu->addAction(tr("Choose What to Sync"));
ac = menu->addAction(tr("Choose what to sync"));
ac->setEnabled(folderConnected);
connect(ac, SIGNAL(triggered(bool)), this, SLOT(doExpand()));
ac = menu->addAction(folderPaused ? tr("Resume sync") : tr("Pause sync"));
ac->setEnabled(folderConnected);
connect(ac, SIGNAL(triggered(bool)), this, SLOT(slotEnableCurrentFolder()));
ac = menu->addAction(tr("Remove sync"));
ac = menu->addAction(tr("Remove folder sync connection"));
connect(ac, SIGNAL(triggered(bool)), this, SLOT(slotRemoveCurrentFolder()));
menu->exec(tv->mapToGlobal(pos));
}
void AccountSettings::slotFolderActivated( const QModelIndex& indx )
void AccountSettings::slotFolderListClicked(const QModelIndex& indx)
{
if (indx.data(FolderStatusDelegate::AddButton).toBool()
&& indx.flags() & Qt::ItemIsEnabled) {
slotAddFolder();
if (indx.data(FolderStatusDelegate::AddButton).toBool()) {
if (indx.flags() & Qt::ItemIsEnabled) {
slotAddFolder();
} else {
QToolTip::showText(
QCursor::pos(),
_model->data(indx, Qt::ToolTipRole).toString(),
this);
}
return;
}
if (_model->classify(indx) == FolderStatusModel::RootFolder) {
@@ -191,6 +230,13 @@ void AccountSettings::slotFolderActivated( const QModelIndex& indx )
auto pos = tv->mapFromGlobal(QCursor::pos());
if (FolderStatusDelegate::optionsButtonRect(tv->visualRect(indx)).contains(pos)) {
slotCustomContextMenuRequested(pos);
return;
}
// Expand root items on single click
if(_accountState && _accountState->state() == AccountState::Connected ) {
bool expanded = ! (ui->_folderList->isExpanded(indx));
ui->_folderList->setExpanded(indx, expanded);
}
}
}
@@ -274,13 +320,13 @@ void AccountSettings::slotRemoveCurrentFolder()
qDebug() << "Remove Folder alias " << alias;
if( !alias.isEmpty() ) {
QMessageBox messageBox(QMessageBox::Question,
tr("Confirm Sync Removal"),
tr("Confirm Folder Sync Connection Removal"),
tr("<p>Do you really want to stop syncing the folder <i>%1</i>?</p>"
"<p><b>Note:</b> This will <b>not</b> delete any files.</p>").arg(alias),
QMessageBox::NoButton,
this);
QPushButton* yesButton =
messageBox.addButton(tr("Stop syncing"), QMessageBox::YesRole);
messageBox.addButton(tr("Remove Folder Sync Connection"), QMessageBox::YesRole);
messageBox.addButton(tr("Cancel"), QMessageBox::NoRole);
messageBox.exec();
@@ -450,7 +496,15 @@ void AccountSettings::slotUpdateQuota(qint64 total, qint64 used)
ui->quotaProgressBar->setToolTip(toolTip);
} else {
ui->quotaProgressBar->setVisible(false);
ui->quotaInfoLabel->setText(tr("Currently there is no storage usage information available."));
ui->quotaInfoLabel->setToolTip(QString());
/* -1 means not computed; -2 means unknown; -3 means unlimited (#3940)*/
if (total == 0 || total == -1) {
ui->quotaInfoLabel->setText(tr("Currently there is no storage usage information available."));
} else {
QString usedStr = Utility::octetsToString(used);
ui->quotaInfoLabel->setText(tr("%1 in use").arg(usedStr));
}
}
}
@@ -499,6 +553,49 @@ void AccountSettings::slotAccountStateChanged(int state)
ui->_folderList->setExpanded(_model->index(i), false);
}
}
/* set the correct label for the Account toolbox button */
if( _accountState ) {
bool isConnected = _accountState->isConnected();
if( isConnected ) {
_toggleSignInOutAction->setText(tr("Sign out"));
} else {
_toggleSignInOutAction->setText(tr("Sign in"));
}
}
}
void AccountSettings::slotLinkActivated(const QString& link)
{
// Parse folder alias and filename from the link, calculate the index
// and select it if it exists.
const QStringList li = link.split(QLatin1String("?folder="));
if( li.count() > 1) {
QString myFolder = li[0];
const QString alias = li[1];
if(myFolder.endsWith(QLatin1Char('/'))) myFolder.chop(1);
// Make sure the folder itself is expanded
Folder *f = FolderMan::instance()->folder(alias);
QModelIndex folderIndx = _model->indexForPath(f, QString());
if( !ui->_folderList->isExpanded(folderIndx)) {
ui->_folderList->setExpanded(folderIndx, true);
}
QModelIndex indx = _model->indexForPath(f, myFolder);
if( indx.isValid() ) {
// make sure all the parents are expanded
for (auto i = indx.parent(); i.isValid(); i = i.parent()) {
if( !ui->_folderList->isExpanded(i)) {
ui->_folderList->setExpanded(i, true);
}
}
ui->_folderList->setSelectionMode(QAbstractItemView::SingleSelection);
ui->_folderList->setCurrentIndex(indx);
ui->_folderList->scrollTo(indx);
} else {
qDebug() << "Unable to find a valid index for " << myFolder;
}
}
}
AccountSettings::~AccountSettings()
@@ -509,35 +606,52 @@ AccountSettings::~AccountSettings()
void AccountSettings::refreshSelectiveSyncStatus()
{
bool shouldBeVisible = _model->isDirty();
QStringList undecidedFolder;
for (int i = 0; !shouldBeVisible && i < _model->rowCount(); ++i) {
if (ui->_folderList->isExpanded(_model->index(i)))
auto index = _model->index(i);
if (ui->_folderList->isExpanded(index) && _model->rowCount(index) > 0) {
shouldBeVisible = true;
}
}
QString msg;
int cnt = 0;
foreach (Folder *folder, FolderMan::instance()->map().values()) {
if (folder->accountState() != _accountState) {
continue;
}
auto undecidedList = folder->journalDb()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncUndecidedList);
QString p;
foreach(const auto &it, undecidedList) {
undecidedFolder.append(it);
// FIXME: add the folder alias in a hoover hint.
// folder->alias() + QLatin1String("/")
if( cnt++ ) {
msg += QLatin1String(", ");
}
QString myFolder = (it);
if( myFolder.endsWith('/')) {
myFolder.chop(1);
}
QModelIndex theIndx = _model->indexForPath(folder, myFolder);
if(theIndx.isValid()) {
msg += QString::fromLatin1("<a href=\"%1?folder=%2\">%1</a>").arg(myFolder).arg(folder->alias());
} else {
msg += myFolder; // no link because we do not know the index yet.
}
}
}
if (undecidedFolder.isEmpty()) {
if (msg.isEmpty()) {
ui->selectiveSyncNotification->setVisible(false);
ui->selectiveSyncNotification->setText(QString());
} else {
ui->selectiveSyncNotification->setVisible(true);
ui->selectiveSyncNotification->setText(
tr("There are new folders that were not synchronized because they are too big: %1")
.arg(undecidedFolder.join(tr(", "))));
QString wholeMsg = tr("There are new folders that were not synchronized because they are too big: ") + msg;
ui->selectiveSyncNotification->setText(wholeMsg);
shouldBeVisible = true;
}
ui->selectiveSyncApply->setEnabled(_model->isDirty() || !undecidedFolder.isEmpty());
ui->selectiveSyncApply->setEnabled(_model->isDirty() || !msg.isEmpty());
bool wasVisible = !ui->selectiveSyncStatus->isHidden();
if (wasVisible != shouldBeVisible) {
QSize hint = ui->selectiveSyncStatus->sizeHint();
@@ -554,6 +668,16 @@ void AccountSettings::refreshSelectiveSyncStatus()
}
}
void AccountSettings::slotAccountAdded(AccountState*)
{
// if the theme is limited to single account, the button must hide if
// there is already one account.
if( AccountManager::instance()->accounts().size() > 1 &&
!Theme::instance()->multiAccount() ) {
_addAccountAction->setVisible(false);
}
}
void AccountSettings::slotDeleteAccount()
{
// Deleting the account potentially deletes 'this', so
@@ -582,6 +706,9 @@ void AccountSettings::slotDeleteAccount()
// if there is no more account, show the wizard.
if( manager->accounts().isEmpty() ) {
// allow to add a new account if there is non any more. Always think
// about single account theming!
_addAccountAction->setVisible(true);
OwncloudSetupWizard::runWizard(qApp, SLOT(slotownCloudWizardDone(int)));
}
@@ -592,6 +719,9 @@ bool AccountSettings::event(QEvent* e)
if (e->type() == QEvent::Hide || e->type() == QEvent::Show) {
_quotaInfo.setActive(isVisible());
}
if (e->type() == QEvent::Show) {
ui->_folderList->setExpanded(_model->index(0, 0), true);
}
return QWidget::event(e);
}
+7 -1
Ver Arquivo
@@ -61,7 +61,6 @@ signals:
void openFolderAlias( const QString& );
public slots:
void slotFolderActivated( const QModelIndex& );
void slotOpenOC();
void slotUpdateQuota( qint64,qint64 );
void slotAccountStateChanged(int state);
@@ -78,15 +77,20 @@ protected slots:
void slotFolderWizardAccepted();
void slotFolderWizardRejected();
void slotDeleteAccount();
void slotToggleSignInState();
void slotOpenAccountWizard();
void slotAccountAdded(AccountState *);
void refreshSelectiveSyncStatus();
void slotCustomContextMenuRequested(const QPoint&);
void slotFolderListClicked( const QModelIndex& indx );
void doExpand();
void slotLinkActivated(const QString &link);
private:
void showConnectionLabel(const QString& message,
QStringList errors = QStringList());
bool event(QEvent*) Q_DECL_OVERRIDE;
void createAccountToolbox();
Ui::AccountSettings *ui;
@@ -95,6 +99,8 @@ private:
bool _wasDisabledBefore;
AccountState *_accountState;
QuotaInfo _quotaInfo;
QAction *_toggleSignInOutAction;
QAction *_addAccountAction;
};
} // namespace OCC
+16 -34
Ver Arquivo
@@ -6,30 +6,18 @@
<rect>
<x>0</x>
<y>0</y>
<width>469</width>
<height>652</height>
<width>575</width>
<height>557</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QWidget" name="accountStatus" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="SslButton" name="sslButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
@@ -42,7 +30,7 @@
</property>
</widget>
</item>
<item>
<item row="0" column="1">
<widget class="QLabel" name="connectLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
@@ -61,26 +49,17 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Remove the account configuration from the client</string>
</property>
<item row="0" column="2">
<widget class="QToolButton" name="_accountToolbox">
<property name="text">
<string>Remove Account</string>
<string>...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="storageGroupBox">
<item>
<widget class="QLabel" name="quotaInfoLabel">
@@ -131,7 +110,7 @@
</item>
</layout>
</item>
<item>
<item row="2" column="0">
<widget class="QTreeView" name="_folderList">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
@@ -150,7 +129,7 @@
</property>
</widget>
</item>
<item>
<item row="3" column="0">
<widget class="QWidget" name="selectiveSyncStatus" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
@@ -169,6 +148,9 @@
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
+40 -11
Ver Arquivo
@@ -15,6 +15,7 @@
#include "accountmanager.h"
#include "account.h"
#include "creds/abstractcredentials.h"
#include "logger.h"
#include <QDebug>
#include <QSettings>
@@ -28,6 +29,7 @@ AccountState::AccountState(AccountPtr account)
, _state(AccountState::Disconnected)
, _connectionStatus(ConnectionValidator::Undefined)
, _waitingForNewCredentials(false)
, _credentialsFetchMode(Interactive)
{
qRegisterMetaType<AccountState*>("AccountState*");
@@ -35,6 +37,8 @@ AccountState::AccountState(AccountPtr account)
SLOT(slotInvalidCredentials()));
connect(account.data(), SIGNAL(credentialsFetched(AbstractCredentials*)),
SLOT(slotCredentialsFetched(AbstractCredentials*)));
connect(account.data(), SIGNAL(credentialsAsked(AbstractCredentials*)),
SLOT(slotCredentialsAsked(AbstractCredentials*)));
}
AccountState::~AccountState()
@@ -79,7 +83,7 @@ void AccountState::setState(State state)
_connectionStatus = ConnectionValidator::Undefined;
_connectionErrors.clear();
} else if (oldState == SignedOut && _state == Disconnected) {
checkConnectivity();
checkConnectivity(Interactive);
}
}
@@ -131,16 +135,17 @@ bool AccountState::isConnectedOrTemporarilyUnavailable() const
return isConnected() || _state == ServiceUnavailable;
}
void AccountState::checkConnectivity()
void AccountState::checkConnectivity(CredentialFetchMode credentialsFetchMode)
{
if (isSignedOut() || _waitingForNewCredentials) {
return;
}
if (_connectionValidator) {
qDebug() << "ConnectionValidator already running, ignoring";
qDebug() << "ConnectionValidator already running, ignoring" << account()->displayName();
return;
}
_credentialsFetchMode = credentialsFetchMode;
ConnectionValidator * conValidator = new ConnectionValidator(account());
_connectionValidator = conValidator;
connect(conValidator, SIGNAL(connectionResult(ConnectionValidator::Status,QStringList)),
@@ -202,8 +207,8 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
// much more likely, so keep trying to connect.
setState(NetworkError);
break;
case ConnectionValidator::CredentialsWrong:
account()->handleInvalidCredentials();
case ConnectionValidator::CredentialsMissingOrWrong:
slotInvalidCredentials();
break;
case ConnectionValidator::UserCanceledCredentials:
setState(SignedOut);
@@ -219,15 +224,41 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
void AccountState::slotInvalidCredentials()
{
if (isSignedOut()) {
if (isSignedOut() || _waitingForNewCredentials)
return;
}
if (account()->credentials()->ready())
account()->credentials()->invalidateToken();
account()->credentials()->fetchFromKeychain();
setState(ConfigurationError);
_waitingForNewCredentials = true;
}
void AccountState::slotCredentialsFetched(AbstractCredentials* credentials)
{
if (!credentials->ready()) {
// No exiting credentials found in the keychain
if (_credentialsFetchMode == Interactive)
credentials->askFromUser();
else {
Logger::instance()->postOptionalGuiLog(tr("Reauthentication required"), tr("You need to re-login to continue using the account %1.").arg(_account->displayName()));
setState(SignedOut);
_waitingForNewCredentials = false;
}
return;
}
_waitingForNewCredentials = false;
// When new credentials become available we always want to restart the
// connection validation, even if it's currently running.
delete _connectionValidator;
checkConnectivity(_credentialsFetchMode);
}
void AccountState::slotCredentialsAsked(AbstractCredentials* credentials)
{
_waitingForNewCredentials = false;
@@ -239,11 +270,9 @@ void AccountState::slotCredentialsFetched(AbstractCredentials* credentials)
// When new credentials become available we always want to restart the
// connection validation, even if it's currently running.
if (_connectionValidator) {
delete _connectionValidator;
}
delete _connectionValidator;
checkConnectivity();
checkConnectivity(_credentialsFetchMode);
}
std::unique_ptr<QSettings> AccountState::settings()
+5 -2
Ver Arquivo
@@ -19,6 +19,7 @@
#include <QPointer>
#include "utility.h"
#include "connectionvalidator.h"
#include "creds/abstractcredentials.h"
#include <memory>
class QSettings;
@@ -27,7 +28,6 @@ namespace OCC {
class AccountState;
class Account;
class AbstractCredentials;
/**
* @brief Extra info about an ownCloud server account.
@@ -59,6 +59,7 @@ public:
/// An error like invalid credentials where retrying won't help.
ConfigurationError
};
enum CredentialFetchMode { Interactive, NonInteractive };
/// The actual current connectivity status.
typedef ConnectionValidator::Status ConnectionStatus;
@@ -84,7 +85,7 @@ public:
/// Triggers a ping to the server to update state and
/// connection status and errors.
void checkConnectivity();
void checkConnectivity(CredentialFetchMode credentialsFetchMode);
/** Returns a new settings object for this account, already in the right groups. */
std::unique_ptr<QSettings> settings();
@@ -104,6 +105,7 @@ protected Q_SLOTS:
void slotConnectionValidatorResult(ConnectionValidator::Status status, const QStringList& errors);
void slotInvalidCredentials();
void slotCredentialsFetched(AbstractCredentials* creds);
void slotCredentialsAsked(AbstractCredentials* creds);
private:
AccountPtr _account;
@@ -111,6 +113,7 @@ private:
ConnectionStatus _connectionStatus;
QStringList _connectionErrors;
bool _waitingForNewCredentials;
CredentialFetchMode _credentialsFetchMode;
QPointer<ConnectionValidator> _connectionValidator;
};
+153
Ver Arquivo
@@ -0,0 +1,153 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
* Copyright (C) by Olivier Goffart <ogoffart@woboq.com>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "activityitemdelegate.h"
#include "folderstatusmodel.h"
#include "folderman.h"
#include "accountstate.h"
#include "utility.h"
#include <theme.h>
#include <account.h>
#include <QFileIconProvider>
#include <QPainter>
#include <QApplication>
namespace OCC {
int ActivityItemDelegate::_iconHeight = 0;
int ActivityItemDelegate::_margin = 0;
int ActivityItemDelegate::iconHeight()
{
if( _iconHeight == 0 ) {
QStyleOptionViewItem option;
QFont font = option.font;
QFontMetrics fm(font);
_iconHeight = qRound(fm.height() / 5.0 * 8.0);
}
return _iconHeight;
}
int ActivityItemDelegate::rowHeight()
{
if( _margin == 0 ) {
QStyleOptionViewItem opt;
QFont f = opt.font;
QFontMetrics fm(f);
_margin = fm.height()/4;
}
return iconHeight() + 2 * _margin;
}
QSize ActivityItemDelegate::sizeHint(const QStyleOptionViewItem & option ,
const QModelIndex & /* index */) const
{
QFont font = option.font;
return QSize( 0, rowHeight() );
}
void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QStyledItemDelegate::paint(painter,option,index);
QFont font = option.font;
QFontMetrics fm( font );
int margin = fm.height()/4;
painter->save();
QIcon actionIcon = qvariant_cast<QIcon>(index.data(ActionIconRole));
QIcon userIcon = qvariant_cast<QIcon>(index.data(UserIconRole));
QString actionText = qvariant_cast<QString>(index.data(ActionTextRole));
QString pathText = qvariant_cast<QString>(index.data(PathRole));
QString remoteLink = qvariant_cast<QString>(index.data(LinkRole));
QString timeText = qvariant_cast<QString>(index.data(PointInTimeRole));
QString accountRole = qvariant_cast<QString>(index.data(AccountRole));
bool accountOnline = qvariant_cast<bool> (index.data(AccountConnectedRole));
QRect actionIconRect = option.rect;
QRect userIconRect = option.rect;
int iconHeight = qRound(fm.height() / 5.0 * 8.0);
int iconWidth = iconHeight;
actionIconRect.setLeft( option.rect.left() + margin );
actionIconRect.setWidth( iconWidth );
actionIconRect.setHeight( iconHeight );
actionIconRect.setTop( actionIconRect.top() + margin );
userIconRect.setLeft( actionIconRect.right() + margin );
userIconRect.setWidth( iconWidth );
userIconRect.setHeight( iconHeight );
userIconRect.setTop( actionIconRect.top() );
int textTopOffset = qRound( (iconHeight - fm.height())/ 2.0 );
// time rect
QRect timeBox;
int timeBoxWidth = fm.boundingRect(QLatin1String("4 hour(s) ago on longlongdomain.org")).width(); // FIXME.
timeBox.setTop( actionIconRect.top()+textTopOffset);
timeBox.setLeft( option.rect.right() - timeBoxWidth- margin );
timeBox.setWidth( timeBoxWidth);
timeBox.setHeight( fm.height() );
QRect actionTextBox = timeBox;
actionTextBox.setLeft( userIconRect.right()+margin );
actionTextBox.setRight( timeBox.left()-margin );
/* === start drawing === */
QPixmap pm = actionIcon.pixmap(iconWidth, iconHeight, QIcon::Normal);
painter->drawPixmap(QPoint(actionIconRect.left(), actionIconRect.top()), pm);
pm = userIcon.pixmap(iconWidth, iconHeight, QIcon::Normal);
painter->drawPixmap(QPoint(userIconRect.left(), userIconRect.top()), pm);
const QString elidedAction = fm.elidedText(actionText, Qt::ElideRight, actionTextBox.width());
painter->drawText(actionTextBox, elidedAction);
int atPos = accountRole.indexOf(QLatin1Char('@'));
if( atPos > -1 ) {
accountRole.remove(0, atPos+1);
}
QString timeStr = tr("%1 on %2").arg(timeText).arg(accountRole);
if( !accountOnline ) {
QPalette p = option.palette;
painter->setPen(p.color(QPalette::Disabled, QPalette::Text));
timeStr.append(" ");
timeStr.append(tr("(disconnected)"));
}
const QString elidedTime = fm.elidedText(timeStr, Qt::ElideRight, timeBox.width());
painter->drawText(timeBox, elidedTime);
painter->restore();
}
bool ActivityItemDelegate::editorEvent ( QEvent * event, QAbstractItemModel * model,
const QStyleOptionViewItem & option, const QModelIndex & index )
{
return QStyledItemDelegate::editorEvent(event, model, option, index);
}
} // namespace OCC
+53
Ver Arquivo
@@ -0,0 +1,53 @@
/*
* Copyright (C) by Klaas Freitag <freitag@kde.org>
* Copyright (C) by Olivier Goffart <ogoffart@woboq.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#pragma once
#include <QStyledItemDelegate>
namespace OCC {
/**
* @brief The ActivityItemDelegate class
* @ingroup gui
*/
class ActivityItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
enum datarole { ActionIconRole = Qt::UserRole + 1,
UserIconRole,
AccountRole,
ActionTextRole,
PathRole,
LinkRole,
PointInTimeRole,
AccountConnectedRole };
void paint( QPainter*, const QStyleOptionViewItem&, const QModelIndex& ) const Q_DECL_OVERRIDE;
QSize sizeHint( const QStyleOptionViewItem&, const QModelIndex& ) const Q_DECL_OVERRIDE;
bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option,
const QModelIndex& index ) Q_DECL_OVERRIDE;
static int rowHeight();
static int iconHeight();
private:
static int _margin;
static int _iconHeight;
};
} // namespace OCC
+433
Ver Arquivo
@@ -0,0 +1,433 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; 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 <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
#include <QtWidgets>
#endif
#include "activitywidget.h"
#include "configfile.h"
#include "syncresult.h"
#include "logger.h"
#include "utility.h"
#include "theme.h"
#include "folderman.h"
#include "syncfileitem.h"
#include "folder.h"
#include "openfilemanager.h"
#include "owncloudpropagator.h"
#include "account.h"
#include "accountstate.h"
#include "accountmanager.h"
#include "activityitemdelegate.h"
#include "protocolwidget.h"
#include "QProgressIndicator.h"
#include "ui_activitywidget.h"
#include <climits>
namespace OCC {
void ActivityList::setAccountName( const QString& name )
{
_accountName = name;
}
QString ActivityList::accountName() const
{
return _accountName;
}
/* ==================================================================== */
ActivityListModel::ActivityListModel(QWidget *parent)
:QAbstractListModel(parent)
{
}
QVariant ActivityListModel::data(const QModelIndex &index, int role) const
{
Activity a;
if (!index.isValid())
return QVariant();
a = _finalList.at(index.row());
AccountStatePtr ast = AccountManager::instance()->account(a._accName);
QStringList list;
if (role == Qt::EditRole)
return QVariant();
switch (role) {
case ActivityItemDelegate::PathRole:
list = FolderMan::instance()->findFileInLocalFolders(a._file);
if( list.count() > 0 ) {
return QVariant(list.at(0));
}
return QVariant();
break;
case ActivityItemDelegate::ActionIconRole:
return QVariant(); // FIXME once the action can be quantified, display on Icon
break;
case ActivityItemDelegate::UserIconRole:
return QIcon(QLatin1String(":/client/resources/account.png"));
break;
case Qt::ToolTipRole:
case ActivityItemDelegate::ActionTextRole:
return a._subject;
break;
case ActivityItemDelegate::LinkRole:
return a._link;
break;
case ActivityItemDelegate::AccountRole:
return a._accName;
break;
case ActivityItemDelegate::PointInTimeRole:
return Utility::timeAgoInWords(a._dateTime);
break;
case ActivityItemDelegate::AccountConnectedRole:
return (ast && ast->isConnected());
break;
default:
return QVariant();
}
return QVariant();
}
int ActivityListModel::rowCount(const QModelIndex&) const
{
return _finalList.count();
}
// current strategy: Fetch 100 items per Account
bool ActivityListModel::canFetchMore(const QModelIndex& ) const
{
if( _activityLists.count() == 0 ) return true;
QMap<AccountState*, ActivityList>::const_iterator i = _activityLists.begin();
while (i != _activityLists.end()) {
AccountState *ast = i.key();
if( !ast->isConnected() ) {
return false;
}
ActivityList activities = i.value();
if( activities.count() == 0 &&
! _currentlyFetching.contains(ast) ) {
return true;
}
++i;
}
return false;
}
void ActivityListModel::startFetchJob(AccountState* s)
{
if( !s->isConnected() ) {
return;
}
JsonApiJob *job = new JsonApiJob(s->account(), QLatin1String("ocs/v1.php/cloud/activity"), this);
QObject::connect(job, SIGNAL(jsonRecieved(QVariantMap)), this, SLOT(slotActivitiesReceived(QVariantMap)));
job->setProperty("AccountStatePtr", QVariant::fromValue<AccountState*>(s));
QList< QPair<QString,QString> > params;
params.append(qMakePair(QLatin1String("page"), QLatin1String("0")));
params.append(qMakePair(QLatin1String("pagesize"), QLatin1String("100")));
job->addQueryParams(params);
_currentlyFetching.insert(s);
qDebug() << "Start fetching activities for " << s->account()->displayName();
job->start();
}
void ActivityListModel::slotActivitiesReceived(const QVariantMap& json)
{
auto activities = json.value("ocs").toMap().value("data").toList();
qDebug() << "*** activities" << activities;
ActivityList list;
AccountState* ai = qvariant_cast<AccountState*>(sender()->property("AccountStatePtr"));
_currentlyFetching.remove(ai);
list.setAccountName( ai->account()->displayName());
foreach( auto activ, activities ) {
auto json = activ.toMap();
Activity a;
a._accName = ai->account()->displayName();
a._id = json.value("id").toLongLong();
a._subject = json.value("subject").toString();
a._message = json.value("message").toString();
a._file = json.value("file").toString();
a._link = json.value("link").toUrl();
a._dateTime = json.value("date").toDateTime();
list.append(a);
}
_activityLists[ai] = list;
combineActivityLists();
}
void ActivityListModel::combineActivityLists()
{
ActivityList resultList;
foreach( ActivityList list, _activityLists.values() ) {
resultList.append(list);
}
std::sort( resultList.begin(), resultList.end() );
beginInsertRows(QModelIndex(), 0, resultList.count()-1);
_finalList = resultList;
endInsertRows();
}
void ActivityListModel::fetchMore(const QModelIndex &)
{
QList<AccountStatePtr> accounts = AccountManager::instance()->accounts();
foreach (AccountStatePtr asp, accounts) {
bool newItem = false;
// if the account is not yet managed, add an empty list.
if( !_activityLists.contains(asp.data()) ) {
_activityLists[asp.data()] = ActivityList();
newItem = true;
}
ActivityList activities = _activityLists[asp.data()];
if( newItem ) {
startFetchJob(asp.data());
}
}
}
void ActivityListModel::slotRefreshActivity(AccountState *ast)
{
if(ast && _activityLists.contains(ast)) {
qDebug() << "**** Refreshing Activity list for" << ast->account()->displayName();
_activityLists.remove(ast);
}
startFetchJob(ast);
}
void ActivityListModel::slotRemoveAccount(AccountState *ast )
{
if( _activityLists.contains(ast) ) {
int i = 0;
const QString accountToRemove = ast->account()->displayName();
QMutableListIterator<Activity> it(_finalList);
while (it.hasNext()) {
Activity activity = it.next();
if( activity._accName == accountToRemove ) {
beginRemoveRows(QModelIndex(), i, i+1);
it.remove();
endRemoveRows();
}
}
_activityLists.remove(ast);
_currentlyFetching.remove(ast);
}
}
/* ==================================================================== */
ActivityWidget::ActivityWidget(QWidget *parent) :
QWidget(parent),
_ui(new Ui::ActivityWidget)
{
_ui->setupUi(this);
// Adjust copyToClipboard() when making changes here!
#if defined(Q_OS_MAC)
_ui->_activityList->setMinimumWidth(400);
#endif
_model = new ActivityListModel(this);
ActivityItemDelegate *delegate = new ActivityItemDelegate;
delegate->setParent(this);
_ui->_activityList->setItemDelegate(delegate);
_ui->_activityList->setAlternatingRowColors(true);
_ui->_activityList->setModel(_model);
_ui->_headerLabel->setText(tr("Server Activities"));
_copyBtn = _ui->_dialogButtonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
_copyBtn->setToolTip( tr("Copy the activity list to the clipboard."));
connect(_copyBtn, SIGNAL(clicked()), SIGNAL(copyToClipboard()));
connect(_model, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(rowsInserted()));
connect( _ui->_activityList, SIGNAL(activated(QModelIndex)), this,
SLOT(slotOpenFile(QModelIndex)));
}
ActivityWidget::~ActivityWidget()
{
delete _ui;
}
void ActivityWidget::slotRefresh(AccountState *ptr)
{
_model->slotRefreshActivity(ptr);
}
void ActivityWidget::slotRemoveAccount( AccountState *ptr )
{
_model->slotRemoveAccount(ptr);
}
// FIXME: Reused from protocol widget. Move over to utilities.
QString ActivityWidget::timeString(QDateTime dt, QLocale::FormatType format) const
{
const QLocale loc = QLocale::system();
QString dtFormat = loc.dateTimeFormat(format);
static const QRegExp re("(HH|H|hh|h):mm(?!:s)");
dtFormat.replace(re, "\\1:mm:ss");
return loc.toString(dt, dtFormat);
}
void ActivityWidget::storeActivityList( QTextStream& ts )
{
ActivityList activities = _model->activityList();
foreach( Activity activity, activities ) {
ts << left
// account name
<< qSetFieldWidth(30)
<< activity._accName
// date and time
<< qSetFieldWidth(34)
<< activity._dateTime.toString()
// subject
<< qSetFieldWidth(10)
<< activity._subject
// file
<< qSetFieldWidth(30)
<< activity._file
// message (mostly empty)
<< qSetFieldWidth(55)
<< activity._message
//
<< qSetFieldWidth(0)
<< endl;
}
}
void ActivityWidget::slotOpenFile(QModelIndex indx)
{
if( indx.isValid() ) {
QString fullPath = indx.data(ActivityItemDelegate::PathRole).toString();
if (QFile::exists(fullPath)) {
showInFileManager(fullPath);
}
}
}
/* ==================================================================== */
ActivitySettings::ActivitySettings(QWidget *parent)
:QWidget(parent)
{
QHBoxLayout *hbox = new QHBoxLayout(this);
setLayout(hbox);
// create a tab widget for the three activity views
_tab = new QTabWidget(this);
hbox->addWidget(_tab);
_activityWidget = new ActivityWidget(this);
_tab->addTab(_activityWidget, Theme::instance()->applicationIcon(), tr("Server Activity"));
connect(_activityWidget, SIGNAL(copyToClipboard()), this, SLOT(slotCopyToClipboard()));
_protocolWidget = new ProtocolWidget(this);
_tab->addTab(_protocolWidget, Theme::instance()->syncStateIcon(SyncResult::Success), tr("Sync Protocol"));
connect(_protocolWidget, SIGNAL(copyToClipboard()), this, SLOT(slotCopyToClipboard()));
// Add the not-synced list into the tab
QWidget *w = new QWidget;
QVBoxLayout *vbox2 = new QVBoxLayout(this);
vbox2->addWidget(new QLabel(tr("List of ignored or errornous files"), this));
vbox2->addWidget(_protocolWidget->issueWidget());
QDialogButtonBox *dlgButtonBox = new QDialogButtonBox(this);
vbox2->addWidget(dlgButtonBox);
QPushButton *_copyBtn = dlgButtonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
_copyBtn->setToolTip( tr("Copy the activity list to the clipboard."));
_copyBtn->setEnabled(true);
connect(_copyBtn, SIGNAL(clicked()), this, SLOT(slotCopyToClipboard()));
w->setLayout(vbox2);
_tab->addTab(w, Theme::instance()->syncStateIcon(SyncResult::Problem), tr("Not Synced"));
// Add a progress indicator to spin if the acitivity list is updated.
_progressIndicator = new QProgressIndicator(this);
_tab->setCornerWidget(_progressIndicator);
// connect a model signal to stop the animation.
connect(_activityWidget, SIGNAL(rowsInserted()), _progressIndicator, SLOT(stopAnimation()));
}
void ActivitySettings::slotCopyToClipboard()
{
QString text;
QTextStream ts(&text);
int idx = _tab->currentIndex();
QString theSubject;
if( idx == 0 ) {
// the activity widget
_activityWidget->storeActivityList(ts);
theSubject = tr("server activity list");
} else if(idx == 1 ) {
// the protocol widget
_protocolWidget->storeSyncActivity(ts);
theSubject = tr("sync activity list");
} else if(idx == 2 ) {
// issues Widget
theSubject = tr("not syned items list");
_protocolWidget->storeSyncIssues(ts);
}
QApplication::clipboard()->setText(text);
emit guiLog(tr("Copied to clipboard"), tr("The %1 has been copied to the clipboard.").arg(theSubject));
}
void ActivitySettings::slotRemoveAccount( AccountState *ptr )
{
_activityWidget->slotRemoveAccount(ptr);
}
void ActivitySettings::slotRefresh( AccountState* ptr )
{
if( ptr && ptr->isConnected() ) {
_progressIndicator->startAnimation();
_activityWidget->slotRefresh(ptr);
}
}
ActivitySettings::~ActivitySettings()
{
}
}
+193
Ver Arquivo
@@ -0,0 +1,193 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; 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 ACTIVITYWIDGET_H
#define ACTIVITYWIDGET_H
#include <QDialog>
#include <QDateTime>
#include <QLocale>
#include <QAbstractListModel>
#include "progressdispatcher.h"
#include "owncloudgui.h"
#include "account.h"
#include "ui_activitywidget.h"
class QPushButton;
class QProgressIndicator;
namespace OCC {
class Account;
class AccountStatusPtr;
class ProtocolWidget;
namespace Ui {
class ActivityWidget;
}
class Application;
/**
* @brief Activity Structure
* @ingroup gui
*
* contains all the information describing a single activity.
*/
class Activity
{
public:
qlonglong _id;
QString _subject;
QString _message;
QString _file;
QUrl _link;
QDateTime _dateTime;
QString _accName;
/**
* @brief Sort operator to sort the list youngest first.
* @param val
* @return
*/
bool operator<( const Activity& val ) const {
return _dateTime.toMSecsSinceEpoch() > val._dateTime.toMSecsSinceEpoch();
}
};
/**
* @brief The ActivityList
* @ingroup gui
*
* A QList based list of Activities
*/
class ActivityList:public QList<Activity>
{
public:
void setAccountName( const QString& name );
QString accountName() const;
private:
QString _accountName;
};
/**
* @brief The ActivityListModel
* @ingroup gui
*
* Simple list model to provide the list view with data.
*/
class ActivityListModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit ActivityListModel(QWidget *parent=0);
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
int rowCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE;
bool canFetchMore(const QModelIndex& ) const Q_DECL_OVERRIDE;
void fetchMore(const QModelIndex&) Q_DECL_OVERRIDE;
ActivityList activityList() { return _finalList; }
public slots:
void slotRefreshActivity(AccountState* ast);
void slotRemoveAccount( AccountState *ast );
private slots:
void slotActivitiesReceived(const QVariantMap& json);
private:
void startFetchJob(AccountState* s);
void combineActivityLists();
QMap<AccountState*, ActivityList> _activityLists;
ActivityList _finalList;
QSet<AccountState*> _currentlyFetching;
};
/**
* @brief The ActivityWidget class
* @ingroup gui
*
* The list widget to display the activities, contained in the
* subsequent ActivitySettings widget.
*/
class ActivityWidget : public QWidget
{
Q_OBJECT
public:
explicit ActivityWidget(QWidget *parent = 0);
~ActivityWidget();
QSize sizeHint() const { return ownCloudGui::settingsDialogSize(); }
void storeActivityList(QTextStream &ts);
public slots:
void slotOpenFile(QModelIndex indx);
void slotRefresh(AccountState* ptr);
void slotRemoveAccount( AccountState *ptr );
signals:
void guiLog(const QString&, const QString&);
void copyToClipboard();
void rowsInserted();
private:
QString timeString(QDateTime dt, QLocale::FormatType format) const;
Ui::ActivityWidget *_ui;
QPushButton *_copyBtn;
ActivityListModel *_model;
};
/**
* @brief The ActivitySettings class
* @ingroup gui
*
* Implements a tab for the settings dialog, displaying the three activity
* lists.
*/
class ActivitySettings : public QWidget
{
Q_OBJECT
public:
explicit ActivitySettings(QWidget *parent = 0);
~ActivitySettings();
QSize sizeHint() const { return ownCloudGui::settingsDialogSize(); }
public slots:
void slotRefresh( AccountState* ptr );
void slotRemoveAccount( AccountState *ptr );
void slotCopyToClipboard();
signals:
void guiLog(const QString&, const QString&);
private:
QTabWidget *_tab;
ActivityWidget *_activityWidget;
ProtocolWidget *_protocolWidget;
QProgressIndicator *_progressIndicator;
};
}
#endif // ActivityWIDGET_H
+38
Ver Arquivo
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OCC::ActivityWidget</class>
<widget class="QWidget" name="OCC::ActivityWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>693</width>
<height>556</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="_headerLabel">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QListView" name="_activityList"/>
</item>
<item row="2" column="0">
<widget class="QDialogButtonBox" name="_dialogButtonBox"/>
</item>
</layout>
</widget>
<tabstops>
<tabstop>_activityList</tabstop>
<tabstop>_dialogButtonBox</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
+14 -6
Ver Arquivo
@@ -35,6 +35,7 @@
#include "accountmanager.h"
#include "creds/abstractcredentials.h"
#include "updater/ocupdater.h"
#include "excludedfiles.h"
#include "config.h"
@@ -103,7 +104,7 @@ Application::Application(int &argc, char **argv) :
{
_startedAt.start();
// TODO: Can't set this without breaking current config pathes
// TODO: Can't set this without breaking current config paths
// setOrganizationName(QLatin1String(APPLICATION_VENDOR));
setOrganizationDomain(QLatin1String(APPLICATION_REV_DOMAIN));
setApplicationName( _theme->appNameGUI() );
@@ -135,6 +136,13 @@ Application::Application(int &argc, char **argv) :
setupLogging();
setupTranslations();
// Setup global excludes
ConfigFile cfg;
ExcludedFiles& excludes = ExcludedFiles::instance();
excludes.addExcludeFilePath( cfg.excludeFile(ConfigFile::SystemScope) );
excludes.addExcludeFilePath( cfg.excludeFile(ConfigFile::UserScope) );
excludes.reloadExcludes();
_folderManager.reset(new FolderMan);
connect(this, SIGNAL(messageReceived(QString, QObject*)), SLOT(slotParseMessage(QString, QObject*)));
@@ -145,7 +153,6 @@ Application::Application(int &argc, char **argv) :
setQuitOnLastWindowClosed(false);
ConfigFile cfg;
_theme->setSystrayUseMonoIcons(cfg.monoIcons());
connect (_theme, SIGNAL(systrayUseMonoIconsChanged(bool)), SLOT(slotUseMonoIconsChanged(bool)));
@@ -172,7 +179,7 @@ Application::Application(int &argc, char **argv) :
connect(&_checkConnectionTimer, SIGNAL(timeout()), this, SLOT(slotCheckConnection()));
_checkConnectionTimer.setInterval(32 * 1000); // check for connection every 32 seconds.
_checkConnectionTimer.start();
// Also check immediatly
// Also check immediately
QTimer::singleShot( 0, this, SLOT( slotCheckConnection() ));
// Update checks
@@ -237,7 +244,7 @@ void Application::slotCheckConnection()
// when the error is permanent.
if (state != AccountState::SignedOut
&& state != AccountState::ConfigurationError) {
accountState->checkConnectivity();
accountState->checkConnectivity(AccountState::NonInteractive);
}
}
@@ -420,6 +427,7 @@ void Application::showVersion()
stream << _theme->appName().toLatin1().constData()
<< QLatin1String(" version ")
<< _theme->version().toLatin1().constData() << endl;
stream << "Using Qt " << qVersion() << endl;
displayHelpText(helpText);
}
@@ -444,7 +452,7 @@ void Application::setHelp()
QString substLang(const QString &lang)
{
// Map the more apropriate script codes
// Map the more appropriate script codes
// to country codes as used by Qt and
// transifex translation conventions.
@@ -486,7 +494,7 @@ void Application::setupTranslations()
// Permissive approach: Qt and keychain translations
// may be missing, but Qt translations must be there in order
// for us to accept the language. Otherwise, we try with the next.
// "en" is an exeption as it is the default language and may not
// "en" is an exception as it is the default language and may not
// have a translation file provided.
qDebug() << Q_FUNC_INFO << "Using" << lang << "translation";
setProperty("ui_lang", lang);
+16
Ver Arquivo
@@ -0,0 +1,16 @@
#include <QString>
#include <QDebug>
#import <Cocoa/Cocoa.h>
namespace OCC {
// https://github.com/owncloud/client/issues/3300
void copyToPasteboard(const QString &string)
{
qDebug() << Q_FUNC_INFO << string;
[[NSPasteboard generalPasteboard] clearContents];
[[NSPasteboard generalPasteboard] setString:[NSString stringWithUTF8String:string.toUtf8().data()]
forType:NSStringPboardType];
}
}
+18 -8
Ver Arquivo
@@ -23,24 +23,34 @@ using namespace QKeychain;
namespace OCC
{
QString HttpCredentialsGui::queryPassword(bool *ok, const QString& hint)
void HttpCredentialsGui::askFromUser()
{
if (!ok) {
return QString();
}
// The rest of the code assumes that this will be done asynchronously
QMetaObject::invokeMethod(this, "askFromUserAsync", Qt::QueuedConnection);
}
void HttpCredentialsGui::askFromUserAsync()
{
QString msg = tr("Please enter %1 password:\n"
"\n"
"User: %2\n"
"Account: %3\n")
.arg(Theme::instance()->appNameGUI(), _user, _account->displayName());
if (!hint.isEmpty()) {
msg += QLatin1String("\n") + hint + QLatin1String("\n");
if (!_fetchErrorString.isEmpty()) {
msg += QLatin1String("\n") + tr("Reading from keychain failed with error: '%1'").arg(
_fetchErrorString) + QLatin1String("\n");
}
return QInputDialog::getText(0, tr("Enter Password"), msg,
bool ok = false;
QString pwd = QInputDialog::getText(0, tr("Enter Password"), msg,
QLineEdit::Password, _previousPassword,
ok);
&ok);
if (ok) {
_password = pwd;
_ready = true;
persist();
}
emit asked();
}
} // namespace OCC
+2 -1
Ver Arquivo
@@ -28,7 +28,8 @@ class HttpCredentialsGui : public HttpCredentials {
public:
explicit HttpCredentialsGui() : HttpCredentials() {}
HttpCredentialsGui(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd) : HttpCredentials(user, password, certificatePath, certificatePasswd) {}
QString queryPassword(bool *ok, const QString& hint) Q_DECL_OVERRIDE;
void askFromUser() Q_DECL_OVERRIDE;
Q_INVOKABLE void askFromUserAsync();
};
} // namespace OCC
@@ -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 <QEventLoop>
#include "account.h"
#include "creds/shibboleth/shibbolethrefresher.h"
#include "creds/shibbolethcredentials.h"
namespace OCC
{
ShibbolethRefresher::ShibbolethRefresher(AccountPtr account, ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent)
: QObject(parent),
_account(account),
_creds(creds),
_csync_ctx(csync_ctx)
{}
void ShibbolethRefresher::refresh()
{
QEventLoop loop;
connect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
this, SLOT(onInvalidatedAndFetched(QByteArray)));
connect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
&loop, SLOT(quit()));
QMetaObject::invokeMethod(_creds, "invalidateAndFetch",Qt::QueuedConnection,
Q_ARG(AccountPtr, _account));
loop.exec();
disconnect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
&loop, SLOT(quit()));
}
void ShibbolethRefresher::onInvalidatedAndFetched(const QByteArray& cookies)
{
// "cookies" is const and its data() return const void*. We want just void*.
QByteArray myCookies(cookies);
disconnect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
this, SLOT(onInvalidatedAndFetched(QByteArray)));
csync_set_module_property(_csync_ctx, "session_key", myCookies.data());
}
} // namespace OCC
@@ -1,53 +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_REFRESHER_H
#define MIRALL_CREDS_SHIBBOLETH_REFRESHER_H
#include <QObject>
#include <csync.h>
class QByteArray;
namespace OCC
{
class Account;
class ShibbolethCredentials;
/**
* @brief The ShibbolethRefresher class
* @ingroup gui
*/
class ShibbolethRefresher : public QObject
{
Q_OBJECT
public:
ShibbolethRefresher(AccountPtr account, ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent = 0);
void refresh();
private Q_SLOTS:
void onInvalidatedAndFetched(const QByteArray& cookieData);
private:
AccountPtr _account;
ShibbolethCredentials* _creds;
CSYNC* _csync_ctx;
};
} // namespace OCC
#endif
+13 -114
Ver Arquivo
@@ -12,7 +12,6 @@
* for more details.
*/
#include <QMutex>
#include <QSettings>
#include <QNetworkReply>
#include <QMessageBox>
@@ -21,7 +20,6 @@
#include "creds/shibbolethcredentials.h"
#include "creds/shibboleth/shibbolethwebview.h"
#include "creds/shibboleth/shibbolethrefresher.h"
#include "creds/shibbolethcredentials.h"
#include "shibboleth/shibbolethuserjob.h"
#include "creds/credentialscommon.h"
@@ -46,39 +44,6 @@ namespace
const char userC[] = "shib_user";
const char shibCookieNameC[] = "_shibsession_";
int shibboleth_redirect_callback(CSYNC* csync_ctx,
const char* uri)
{
if (!csync_ctx || !uri) {
return 1;
}
const QString qurl(QString::fromLatin1(uri));
QRegExp shibbolethyWords ("SAML|wayf");
shibbolethyWords.setCaseSensitivity (Qt::CaseInsensitive);
if (!qurl.contains(shibbolethyWords)) {
return 1;
}
SyncEngine* engine = reinterpret_cast<SyncEngine*>(csync_get_userdata(csync_ctx));
AccountPtr account = engine->account();
ShibbolethCredentials* creds = qobject_cast<ShibbolethCredentials*>(account->credentials());
if (!creds) {
qDebug() << "Not a Shibboleth creds instance!";
return 1;
}
QMutex mutex;
QMutexLocker locker(&mutex);
ShibbolethRefresher refresher(account, creds, csync_ctx);
// blocks
refresher.refresh();
return creds->ready() ? 0 : 1;
}
} // ns
ShibbolethCredentials::ShibbolethCredentials()
@@ -86,14 +51,12 @@ ShibbolethCredentials::ShibbolethCredentials()
_url(),
_ready(false),
_stillValid(false),
_fetchJobInProgress(false),
_browser(0)
{}
ShibbolethCredentials::ShibbolethCredentials(const QNetworkCookie& cookie)
: _ready(true),
_stillValid(true),
_fetchJobInProgress(false),
_browser(0),
_shibCookie(cookie)
{
@@ -110,34 +73,6 @@ void ShibbolethCredentials::setAccount(Account* account)
}
}
void ShibbolethCredentials::syncContextPreInit(CSYNC* ctx)
{
csync_set_auth_callback (ctx, handleNeonSSLProblems);
}
QByteArray ShibbolethCredentials::prepareCookieData() const
{
QString cookiesAsString;
QList<QNetworkCookie> cookies = accountCookies(_account);
foreach(const QNetworkCookie &cookie, cookies) {
cookiesAsString += cookie.toRawForm(QNetworkCookie::NameAndValueOnly) + QLatin1String("; ");
}
return cookiesAsString.toLatin1();
}
void ShibbolethCredentials::syncContextPreStart (CSYNC* ctx)
{
typedef int (*csync_owncloud_redirect_callback_t)(CSYNC* ctx, const char* uri);
csync_owncloud_redirect_callback_t cb = shibboleth_redirect_callback;
csync_set_module_property(ctx, "session_key", prepareCookieData().data());
csync_set_module_property(ctx, "redirect_callback", &cb);
}
bool ShibbolethCredentials::changed(AbstractCredentials* credentials) const
{
ShibbolethCredentials* other(qobject_cast< ShibbolethCredentials* >(credentials));
@@ -191,17 +126,12 @@ bool ShibbolethCredentials::ready() const
return _ready;
}
void ShibbolethCredentials::fetch()
void ShibbolethCredentials::fetchFromKeychain()
{
if(_fetchJobInProgress) {
return;
}
if (_user.isEmpty()) {
_user = _account->credentialSetting(QLatin1String(userC)).toString();
}
if (_ready) {
_fetchJobInProgress = false;
Q_EMIT fetched();
} else {
_url = _account->url();
@@ -211,10 +141,14 @@ void ShibbolethCredentials::fetch()
job->setKey(keychainKey(_account->url().toString(), "shibAssertion"));
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
job->start();
_fetchJobInProgress = true;
}
}
void ShibbolethCredentials::askFromUser()
{
showLoginWindow();
}
bool ShibbolethCredentials::stillValid(QNetworkReply *reply)
{
Q_UNUSED(reply)
@@ -229,9 +163,10 @@ void ShibbolethCredentials::persist()
}
}
// only used by Application::slotLogout(). Use invalidateAndFetch for normal usage
void ShibbolethCredentials::invalidateToken()
{
_ready = false;
CookieJar *jar = static_cast<CookieJar*>(_account->networkAccessManager()->cookieJar());
// Remove the _shibCookie
@@ -249,8 +184,6 @@ void ShibbolethCredentials::invalidateToken()
jar->clearSessionCookies();
removeShibCookie();
_shibCookie = QNetworkCookie();
// ### access to ctx missing, but might not be required at all
//csync_set_module_property(ctx, "session_key", "");
}
void ShibbolethCredentials::onShibbolethCookieReceived(const QNetworkCookie& shibCookie)
@@ -265,7 +198,7 @@ void ShibbolethCredentials::onShibbolethCookieReceived(const QNetworkCookie& shi
void ShibbolethCredentials::slotFetchUser()
{
// We must first do a request to webdav so the session is enabled.
// (because for some reason we wan't access the API without that.. a bug in the server maybe?)
// (because for some reason we can't access the API without that.. a bug in the server maybe?)
EntityExistsJob* job = new EntityExistsJob(_account->sharedFromThis(), _account->davPath(), this);
connect(job, SIGNAL(exists(QNetworkReply*)), this, SLOT(slotFetchUserHelper()));
job->setIgnoreCredentialFailure(true);
@@ -296,48 +229,14 @@ void ShibbolethCredentials::slotUserFetched(const QString &user)
_stillValid = true;
_ready = true;
_fetchJobInProgress = false;
Q_EMIT fetched();
Q_EMIT asked();
}
void ShibbolethCredentials::slotBrowserRejected()
{
_ready = false;
_fetchJobInProgress = false;
Q_EMIT fetched();
}
void ShibbolethCredentials::invalidateAndFetch()
{
_ready = false;
_fetchJobInProgress = true;
// delete the credentials, then in the slot fetch them again (which will trigger browser)
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
job->setSettings(_account->settingsWithGroup(Theme::instance()->appName(), job).release());
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotInvalidateAndFetchInvalidateDone(QKeychain::Job*)));
job->setKey(keychainKey(_account->url().toString(), "shibAssertion"));
job->start();
}
void ShibbolethCredentials::slotInvalidateAndFetchInvalidateDone(QKeychain::Job*)
{
connect (this, SIGNAL(fetched()),
this, SLOT(onFetched()));
_fetchJobInProgress = false;
// small hack to support the ShibbolethRefresher hack
// we already rand fetch() with a valid account object,
// and hence know the url on refresh
fetch();
}
void ShibbolethCredentials::onFetched()
{
disconnect (this, SIGNAL(fetched()),
this, SLOT(onFetched()));
Q_EMIT invalidatedAndFetched(prepareCookieData());
Q_EMIT asked();
}
void ShibbolethCredentials::slotReadJobDone(QKeychain::Job *job)
@@ -355,10 +254,10 @@ void ShibbolethCredentials::slotReadJobDone(QKeychain::Job *job)
_ready = true;
_stillValid = true;
_fetchJobInProgress = false;
Q_EMIT fetched();
} else {
showLoginWindow();
_ready = false;
Q_EMIT fetched();
}
}
+3 -11
Ver Arquivo
@@ -44,18 +44,17 @@ Q_OBJECT
public:
ShibbolethCredentials();
/* create a credentials for an already connected account */
/* create credentials for an already connected account */
ShibbolethCredentials(const QNetworkCookie &cookie);
void setAccount(Account* account) Q_DECL_OVERRIDE;
void syncContextPreInit(CSYNC* ctx) Q_DECL_OVERRIDE;
void syncContextPreStart(CSYNC* ctx) Q_DECL_OVERRIDE;
bool changed(AbstractCredentials* credentials) const Q_DECL_OVERRIDE;
QString authType() const Q_DECL_OVERRIDE;
QString user() const Q_DECL_OVERRIDE;
QNetworkAccessManager* getQNAM() const Q_DECL_OVERRIDE;
bool ready() const Q_DECL_OVERRIDE;
void fetch() Q_DECL_OVERRIDE;
void fetchFromKeychain() Q_DECL_OVERRIDE;
void askFromUser() Q_DECL_OVERRIDE;
bool stillValid(QNetworkReply *reply) Q_DECL_OVERRIDE;
void persist() Q_DECL_OVERRIDE;
void invalidateToken() Q_DECL_OVERRIDE;
@@ -66,15 +65,10 @@ public:
static QNetworkCookie findShibCookie(Account *, QList<QNetworkCookie> cookies = QList<QNetworkCookie>());
static QByteArray shibCookieName();
public Q_SLOTS:
void invalidateAndFetch() Q_DECL_OVERRIDE;
private Q_SLOTS:
void onShibbolethCookieReceived(const QNetworkCookie&);
void slotBrowserRejected();
void onFetched();
void slotReadJobDone(QKeychain::Job*);
void slotInvalidateAndFetchInvalidateDone(QKeychain::Job*);
void slotReplyFinished(QNetworkReply*);
void slotUserFetched(const QString& user);
void slotFetchUser();
@@ -82,7 +76,6 @@ private Q_SLOTS:
Q_SIGNALS:
void newCookie(const QNetworkCookie& cookie);
void invalidatedAndFetched(const QByteArray& cookieData);
private:
void storeShibCookie(const QNetworkCookie &cookie);
@@ -93,7 +86,6 @@ private:
bool _ready;
bool _stillValid;
bool _fetchJobInProgress;
QPointer<ShibbolethWebView> _browser;
QNetworkCookie _shibCookie;
QString _user;
+39 -14
Ver Arquivo
@@ -28,9 +28,10 @@
#include "clientproxy.h"
#include "syncengine.h"
#include "syncrunfilelog.h"
#include "socketapi.h"
#include "theme.h"
#include "filesystem.h"
#include "excludedfiles.h"
#include "creds/abstractcredentials.h"
@@ -88,14 +89,14 @@ Folder::Folder(const FolderDefinition& definition,
bool Folder::init()
{
// We need to reconstruct the url because the path need to be fully decoded, as csync will re-encode the path:
// We need to reconstruct the url because the path needs to be fully decoded, as csync will re-encode the path:
// Remember that csync will just append the filename to the path and pass it to the vio plugin.
// csync_owncloud will then re-encode everything.
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
QUrl url = remoteUrl();
QString url_string = url.scheme() + QLatin1String("://") + url.authority(QUrl::EncodeDelimiters) + url.path(QUrl::FullyDecoded);
#else
// Qt4 was broken anyway as it did not encode the '#' as it should have done (it was actually a provlem when parsing the path from QUrl::setPath
// Qt4 was broken anyway as it did not encode the '#' as it should have done (it was actually a problem when parsing the path from QUrl::setPath
QString url_string = remoteUrl().toString();
#endif
url_string = Utility::toCSyncScheme(url_string);
@@ -108,10 +109,9 @@ bool Folder::init()
_csync_ctx = 0;
} else {
csync_set_log_callback( csyncLogCatcher );
csync_set_log_level( 11 );
csync_set_log_level( Logger::instance()->isNoop() ? 0 : 11 );
Q_ASSERT( _accountState );
_accountState->account()->credentials()->syncContextPreInit(_csync_ctx);
if( csync_init( _csync_ctx ) < 0 ) {
qDebug() << "Could not initialize csync!" << csync_get_status(_csync_ctx) << csync_get_status_string(_csync_ctx);
@@ -157,7 +157,7 @@ void Folder::checkLocalPath()
qDebug() << "Checked local path ok";
} else {
// Check directory again
if( !FileSystem::fileExists(_definition.localPath) ) {
if( !FileSystem::fileExists(_definition.localPath, fi) ) {
_syncResult.setErrorString(tr("Local folder %1 does not exist.").arg(_definition.localPath));
_syncResult.setStatus( SyncResult::SetupError );
} else if( !fi.isDir() ) {
@@ -700,6 +700,28 @@ void Folder::removeFromSettings() const
settings->remove(_definition.alias);
}
bool Folder::isFileExcludedAbsolute(const QString& fullPath) const
{
if (!fullPath.startsWith(path())) {
// Mark paths we're not responsible for as excluded...
return true;
}
QString myFullPath = fullPath;
if (myFullPath.endsWith(QLatin1Char('/'))) {
myFullPath.chop(1);
}
QString relativePath = myFullPath.mid(path().size());
auto excl = ExcludedFiles::instance().isExcluded(myFullPath, relativePath, _definition.ignoreHiddenFiles);
return excl != CSYNC_NOT_EXCLUDED;
}
bool Folder::isFileExcludedRelative(const QString& relativePath) const
{
return isFileExcludedAbsolute(path() + relativePath);
}
void Folder::watcherSlot(QString fn)
{
// FIXME: On OS X we could not do this "if" since on OS X the file watcher ignores events for ourselves
@@ -749,6 +771,8 @@ void Folder::wipe()
// Delete files that have been partially downloaded.
slotDiscardDownloadProgress();
//Unregister the socket API so it does not keep the .sync_journal file open
FolderMan::instance()->socketApi()->slotUnregisterPath(alias());
_journal.close(); // close the sync journal
QFile file(stateDbFile);
@@ -767,6 +791,8 @@ void Folder::wipe()
QFile::remove( stateDbFile + "-shm" );
QFile::remove( stateDbFile + "-wal" );
QFile::remove( stateDbFile + "-journal" );
FolderMan::instance()->socketApi()->slotRegisterPath(alias());
}
bool Folder::setIgnoredFiles()
@@ -817,11 +843,10 @@ void Folder::startSync(const QStringList &pathList)
QMetaObject::invokeMethod(this, "slotSyncFinished", Qt::QueuedConnection);
return;
}
_clientProxy.setCSyncProxy(_accountState->account()->url(), _csync_ctx);
} else if (proxyDirty()) {
_clientProxy.setCSyncProxy(_accountState->account()->url(), _csync_ctx);
setProxyDirty(false);
}
csync_set_log_level( Logger::instance()->isNoop() ? 0 : 11 );
if (isBusy()) {
qCritical() << "* ERROR csync is still running and new sync requested.";
@@ -862,7 +887,7 @@ void Folder::startSync(const QStringList &pathList)
this, SLOT(slotAboutToPropagate(SyncFileItemVector&)));
connect(_engine.data(), SIGNAL(started()), SLOT(slotSyncStarted()), Qt::QueuedConnection);
connect(_engine.data(), SIGNAL(finished()), SLOT(slotSyncFinished()), Qt::QueuedConnection);
connect(_engine.data(), SIGNAL(finished(bool)), SLOT(slotSyncFinished(bool)), Qt::QueuedConnection);
connect(_engine.data(), SIGNAL(csyncError(QString)), SLOT(slotSyncError(QString)), Qt::QueuedConnection);
connect(_engine.data(), SIGNAL(csyncUnavailable()), SLOT(slotCsyncUnavailable()), Qt::QueuedConnection);
@@ -934,7 +959,7 @@ void Folder::slotCsyncUnavailable()
_csyncUnavail = true;
}
void Folder::slotSyncFinished()
void Folder::slotSyncFinished(bool success)
{
qDebug() << " - client version" << qPrintable(Theme::instance()->version())
<< " Qt" << qVersion()
@@ -992,15 +1017,15 @@ void Folder::slotSyncFinished()
qDebug() << "the last" << _consecutiveFailingSyncs << "syncs failed";
}
if (_syncResult.status() == SyncResult::Success) {
// Clear the white list as all the folder that should be on that list are sync-ed
if (_syncResult.status() == SyncResult::Success && success) {
// Clear the white list as all the folders that should be on that list are sync-ed
journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncWhiteList, QStringList());
}
emit syncStateChange();
// The syncFinished result that is to be triggered here makes the folderman
// clearing the current running sync folder marker.
// clear 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
@@ -1119,7 +1144,7 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool *cancel)
QMessageBox msgBox(QMessageBox::Warning, tr("Remove All Files?"),
msg.arg(alias()));
msgBox.addButton(tr("Remove all files"), QMessageBox::DestructiveRole);
QPushButton* keepBtn = msgBox.addButton(tr("Keep files"), QMessageBox::ActionRole);
QPushButton* keepBtn = msgBox.addButton(tr("Keep files"), QMessageBox::AcceptRole);
if (msgBox.exec() == -1) {
*cancel = true;
return;

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