1
0
mirror of https://github.com/chylex/Nextcloud-Desktop.git synced 2026-04-03 09:11:33 +02:00

Compare commits

...

263 Commits

Author SHA1 Message Date
Michael Schuster
b45f5fd1a9 Bump version to 2.6.4
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-03-03 20:32:31 +01:00
Nextcloud bot
a4317ca50d [tx-robot] updated from transifex 2020-03-03 19:24:11 +00:00
Michael Schuster
6c6eeab479 Merge pull request #1830 from nextcloud/backport/1829/stable-2.6
[stable-2.6] Fix Explorer pinning: Add fallbacks for Shell commands (fixes #1599)
2020-03-03 20:15:57 +01:00
Christian Kamm
7fdbc72991 Windows: Fix context menu handling only own verbs #7004
Previously it'd handle all verbs as if they were our own.

Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-03-03 19:13:31 +00:00
Michael Schuster
2187c6f4fc Fix Explorer pinning: Add fallbacks for Shell commands (fixes #1599)
See: #1599

Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-03-03 19:13:31 +00:00
Michael Schuster
f3b825f333 Merge pull request #1828 from nextcloud/backport/1827/stable-2.6
[stable-2.6] WebFlowCredentials: Make username comparison case-insensitive (fix #1741)
2020-03-03 06:27:18 +01:00
Michael Schuster
676d4e1308 WebFlowCredentials: Make username comparison case-insensitive (fix #1741)
Fixes issue #1741

Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-03-03 05:26:20 +00:00
Nextcloud bot
e03309a05e [tx-robot] updated from transifex 2020-03-03 03:27:09 +00:00
Bruno Perel
de15f20006 Fix git merge hiccup
(cherry picked from commit 7378ae6a7f)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-03-03 01:39:04 +01:00
Nextcloud bot
7ed1062314 [tx-robot] updated from transifex 2020-03-02 03:25:11 +00:00
Michael Schuster
80138b1cbf Merge pull request #1825 from nextcloud/backport/1823/stable-2.6
[stable-2.6] Disable HTTP/2 for now due to Qt bug, allow enabling it via env var
2020-03-02 03:29:03 +01:00
Michael Schuster
93547ced6d Fix build with older Qt: Disable http2 for now due to Qt bug, add env var (upstream)
Disable http2 for now due to Qt bug but allow enabling it via env var, see: https://github.com/owncloud/client/pull/7620
  and: https://github.com/nextcloud/desktop/pull/1806
Issue: https://github.com/nextcloud/desktop/issues/1503

Co-authored-by: XNG <Milokita@users.noreply.github.com>
Co-authored-by: Hannah von Reth <hannah.vonreth@owncloud.com>

Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-03-02 02:27:55 +00:00
XNG
0aefa58644 Disable http2 for now due to Qt bug
So that user may continue to use http2 on their webpage

Signed-off-by: XNG <Milokita@users.noreply.github.com>
(cherry picked from commit dad95d4e4617211360bf2b4391e29c341e939844)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-03-02 02:27:55 +00:00
Michael Schuster
992bcf56f5 Merge pull request #1824 from nextcloud/activity-date-time-tooltip
ActivityListModel: Show full date and time as a Tooltip only
2020-03-02 02:56:49 +01:00
Michael Schuster
35de69f7bc ActivityListModel: Show full date and time as a Tooltip only
- Fixes issue #1780
- Limits the visual overhead

Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-03-02 02:47:57 +01:00
Michael Schuster
1c44909254 Merge pull request #1821 from nextcloud/backport/1820/stable-2.6
[stable-2.6] Fix Explorer integration re-save and hide option on non-Windows
2020-03-01 05:45:51 +01:00
Michael Schuster
c3ccb72f2b Fix Explorer integration: Hide option on non-Windows
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-03-01 04:44:35 +00:00
Michael Schuster
890bd09ce9 Fix Explorer integration re-save (fixes issue #1807)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-03-01 04:44:35 +00:00
Nextcloud bot
b5309c47fc [tx-robot] updated from transifex 2020-03-01 03:27:09 +00:00
Nextcloud bot
d24a09e47f [tx-robot] updated from transifex 2020-02-29 03:26:28 +00:00
Nextcloud bot
bdae4a9be7 [tx-robot] updated from transifex 2020-02-28 03:26:27 +00:00
Nextcloud bot
d9ce9814da [tx-robot] updated from transifex 2020-02-27 03:27:46 +00:00
Nextcloud bot
f6d019af21 [tx-robot] updated from transifex 2020-02-26 03:27:49 +00:00
Nextcloud bot
423ee61817 [tx-robot] updated from transifex 2020-02-25 03:32:56 +00:00
Michael Schuster
4871776a4b Merge pull request #1813 from nextcloud/backport/1810/stable-2.6
[stable-2.6] l10n: Changes to improve source strings
2020-02-24 21:09:18 +01:00
rakekniven
f4e83891e1 l10n: Change spelling of "webdav"
Signed-off-by: rakekniven <mark.ziegler@rakekniven.de>
2020-02-24 20:08:10 +00:00
rakekniven
d589b524e0 l10n: Removed colon from translation
Signed-off-by: rakekniven <mark.ziegler@rakekniven.de>
2020-02-24 20:08:10 +00:00
rakekniven
de0158e2bb l10n: Removed blank before colon
Signed-off-by: rakekniven <mark.ziegler@rakekniven.de>
2020-02-24 20:08:10 +00:00
rakekniven
62856f9001 l10n: Change case of one word
Signed-off-by: rakekniven <mark.ziegler@rakekniven.de>
2020-02-24 20:08:10 +00:00
Nextcloud bot
1313bc573f [tx-robot] updated from transifex 2020-02-24 03:29:29 +00:00
Nextcloud bot
c2838fb8a8 [tx-robot] updated from transifex 2020-02-23 03:29:39 +00:00
Nextcloud bot
ba71bf13f4 [tx-robot] updated from transifex 2020-02-22 03:28:55 +00:00
Michael Schuster
7e36c7ba59 Merge pull request #1803 from nextcloud/backport/1802/stable-2.6
[stable-2.6] Updater: Add query-parameter 'updatesegment' to the update check
2020-02-21 23:42:15 +01:00
Michael Schuster
e9641a3b94 Updater: Add query-parameter 'updatesegment' to the update check
Used to throttle down desktop release rollout in order to keep the update servers alive at peak times.

See: https://github.com/nextcloud/client_updater_server/pull/36

Targeted issues: #1795, #1800

Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-02-21 22:40:41 +00:00
Nextcloud bot
7ff1911492 [tx-robot] updated from transifex 2020-02-21 12:43:03 +00:00
Nextcloud bot
57f8b866a5 [tx-robot] updated from transifex 2020-02-21 12:16:08 +00:00
Nextcloud bot
883df2f4fa [tx-robot] updated from transifex 2020-02-21 12:13:24 +00:00
Michael Schuster
5880c4954e Bump version to 2.6.3
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-02-17 01:59:48 +01:00
Michael Schuster
b02bd066a9 Update translations
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-02-17 01:55:38 +01:00
Michael Schuster
6abec7cea9 Merge pull request #1789 from nextcloud/backport/1782/stable-2.6
[stable-2.6] Add UserInfo class and fetch quota via API instead of PropfindJob
2020-02-17 01:48:11 +01:00
Michael Schuster
cc4e6b236a Fix Tests linkage (missed UserInfo.cpp in CMakeLists.txt)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-02-17 00:31:37 +00:00
Michael Schuster
821946ad94 Code cleanup
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-02-17 00:31:37 +00:00
Michael Schuster
94c3e19ede Add UserInfo class and fetch quota via API instead of PropfindJob
The PropfindJob quota includes the size of shares and thus leads to confusion
in regard of the real space available, as shown in the UI.
This commit aims to streamline the behaviour with the Android and iOS apps,
which also utilize the API.

Details:
- Refactor the QuotaInfo class into UserInfo
- Use JsonApiJob (ocs/v1.php/cloud/user) instead of PropfindJob
- Let ConnectionValidator use the new UserInfo class to fetch
  the user and the avatar image (to avoid code duplication)
- Allow updating the avatar image upon AccountSettings visibility,
  using UserInfo's quota fetching

Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-02-17 00:31:37 +00:00
rakekniven
feba6910ce Changed product name to Nextcloud
Reported at Transifex.

Signed-off-by: rakekniven <mark.ziegler@rakekniven.de>
(cherry picked from commit dfdb872e7b)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-02-16 19:01:39 +01:00
Michael Schuster
4f37249750 Merge pull request #1787 from nextcloud/backport/1770/stable-2.6
[stable-2.6] l10n: Changed grammar and triple dots to ellipsis
2020-02-16 18:56:55 +01:00
rakekniven
fda8c406f6 l10n: Changed grammar
Signed-off-by: rakekniven <mark.ziegler@rakekniven.de>
2020-02-16 17:56:03 +00:00
rakekniven
a804c4650a l10n: Triple dot to ellipsis
Signed-off-by: rakekniven <mark.ziegler@rakekniven.de>
2020-02-16 17:56:02 +00:00
rakekniven
e1f4963973 l10n: Triple dot to ellipsis
Signed-off-by: rakekniven <mark.ziegler@rakekniven.de>
2020-02-16 17:56:02 +00:00
rakekniven
6ae761c43c Triple dot to ellipsis
Signed-off-by: rakekniven <mark.ziegler@rakekniven.de>
2020-02-16 17:56:02 +00:00
rakekniven
504bb34d26 l10n: Triple dot to ellipsis
Signed-off-by: rakekniven <mark.ziegler@rakekniven.de>
2020-02-16 17:56:02 +00:00
rakekniven
1136cee383 l10n: Changed spelling of "user name" to "username"
Using "username" like on > 200 strings over the whole Nextcloud project.

Signed-off-by: rakekniven mark.ziegler@rakekniven.de
(cherry picked from commit 32c2c062c0)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-02-16 18:51:34 +01:00
Michael Schuster
591d4c812b Merge pull request #1786 from nextcloud/backport/1765/stable-2.6
[stable-2.6] Start the client in background if activated by D-Bus
2020-02-16 18:46:49 +01:00
Corentin Noël
a105e3f758 Start the client in background if activated by D-Bus
The nextcloud client can be started by any other application consuming libcloudproviers.
Make sure that the client won't pop-up if we open the file manager.

Signed-off-by: Corentin Noël <corentin.noel@collabora.com>
2020-02-16 17:46:20 +00:00
Michael Schuster
a88687bfe3 Merge pull request #1785 from nextcloud/backport/1764/stable-2.6
[stable-2.6] Do not install files related to cloud providers under Xenial
2020-02-16 18:43:46 +01:00
István Váradi
879ed544e1 Do not install files related to cloud providers under Xenial
Signed-off-by: István Váradi <Istvan.Varadi@ericsson.com>
2020-02-16 17:42:22 +00:00
Michael Schuster
13aaffc46b Merge pull request #1784 from nextcloud/backport/1760/stable-2.6
[stable-2.6] Update autoupdate.rst
2020-02-16 18:38:00 +01:00
Andre-Schuiki
62fc12fe40 Update autoupdate.rst
Hi, you have the wrong registry path in the documentation? (tested client version: 2.6.0 x64 build: 20190927)
The Nextcloud Client checks the path "HKEY_LOCAL_MACHINE\Software\Policies\Nextcloud GmbH\Nextcloud" not "HKEY_LOCAL_MACHINE\Software\Policies\Nextcloud\Nextcloud" under HKLM.
2020-02-16 17:36:59 +00:00
Michael Schuster
f4543e0c79 Merge pull request #1783 from nextcloud/backport/1729/stable-2.6
[stable-2.6] Install libcloudproviders files by default on debian
2020-02-16 18:19:15 +01:00
Corentin Noël
d35f466773 Install libcloudproviders files by default on debian
Signed-off-by: Corentin Noël <corentin@elementary.io>
2020-02-16 17:18:39 +00:00
XNG
e3cb3b28ff apply http2 qt resend patch from owncloud
Signed-off-by: XNG <Milokita@users.noreply.github.com>
(cherry picked from commit 768cf7e1ae)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-02-14 17:45:33 +01:00
XNG
36049afbc4 apply http2 qt resend patch from owncloud
Signed-off-by: XNG <Milokita@users.noreply.github.com>
(cherry picked from commit d87a88e39f)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-02-14 17:45:33 +01:00
XNG
59c165aa1d apply http2 qt resend patch from owncloud
Signed-off-by: XNG <Milokita@users.noreply.github.com>
(cherry picked from commit 314c00a8b7)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-02-14 17:45:30 +01:00
Dominique Fuchs
071b4abeeb Merge pull request #1774 from nextcloud/backport/1763/stable-2.6
[stable-2.6] Make sure that the libcloudprovider integration is using a valid D-Bus path
2020-02-06 07:24:51 +01:00
Corentin Noël
93e04fc72b Make sure that the libcloudprovider integration is using a valid D-Bus path
Set a simple unique identifier per folder to ensure that it is always unique.

Fixes https://github.com/nextcloud/desktop/issues/1704

Signed-off-by: Corentin Noël <corentin@elementary.io>
2020-02-06 06:22:35 +00:00
Michael Schuster
a9915c4b46 Merge pull request #1752 from nextcloud/backport/1745/stable-2.6
[stable-2.6] Use system proxy by default if no config file is present
2020-01-23 18:13:10 +01:00
Julius Härtl
a265ff52e7 Use system proxy by default if no config file is present
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2020-01-23 17:12:33 +00:00
Michael Schuster
85b4965d7f Linux AppImage build script: Use QtKeyChain master
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit a35aa58943)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-01-18 16:33:26 +01:00
Roeland Jago Douma
963beec760 Windows 7 is out of support
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
(cherry picked from commit a3aab00ca9)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-01-18 16:10:20 +01:00
Brandon
2f812063ac Correct wrong variable
Signed-off-by: Brandon <brandon.yeow@websparks.sg>
(cherry picked from commit d10bc1bb14)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-01-18 16:10:20 +01:00
Brandon
a485120a34 Correct wrong variable
Signed-off-by: Brandon <me@branbit.com>
Signed-off-by: Brandon <brandon.yeow@websparks.sg>
(cherry picked from commit 18a88fcecf)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-01-18 16:10:19 +01:00
ritsute
6337116de7 Handle broken shared file error gracefully
Signed-off-by: Brandon <me@branbit.com>
Signed-off-by: Brandon <brandon.yeow@websparks.sg>
(cherry picked from commit c92f520423)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-01-18 16:10:19 +01:00
JanDragon
a56eb2e95e Welcome to 2020
(cherry picked from commit 7565c547ae)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-01-18 16:09:25 +01:00
Michael Schuster
ac3246f9f2 Fix Explorer integration on Windows and the crash on other systems
- Ensure that the folder integration stays persistent in Explorer,
  the uninstaller removes the folder upon updating the client.
  Recreate all entries upon start. This has the benefit of removing
  old remains of non-working, outdated entries.

- Don't crash on the other systems when the user clicks the option
  button "Show sync folders in Explorer's Navigation Pane".
  Even though the option currently doesn't work on the other platforms,
  crashing is never good...

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 8f9101773c)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-01-18 16:09:11 +01:00
Roeland Jago Douma
aa9849c112 Ask for password on password protected link shares
Fixes #1485

This was missed when creating the new share dialog.
Now it pops up with a nice share password dialog to enter for your link
share.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
(cherry picked from commit 05083e32c9)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-01-18 16:08:56 +01:00
JanDragon
a89e49ef84 Updated year in legalnotice.cpp
(cherry picked from commit 4a64e8da83)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2020-01-18 16:08:37 +01:00
Michael Schuster
1d745535f7 KeychainChunk: Fix error handling in ReadJob::slotReadJobDone
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 12:13:26 +01:00
Michael Schuster
3184aeed43 Add temporary Flow2 translation (german)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 11:06:17 +01:00
Michael Schuster
3faf010b55 Update translations
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:18:57 +01:00
Michael Schuster
163c80e203 Fix date in ActivityWidget and remove unnecessary string conversion
The local date and time value was converted into a string, just to be converted
into another string, to be converted to a value once again, returning zero as
the result. This caused the widget to always display "now".

Looks like this was a simply copy and paste mistake from this line in
ActivityListModel::slotActivitiesReceived:

a._dateTime = QDateTime::fromString(json.value("date").toString(), Qt::ISODate);

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit e07859fb3c)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:52 +01:00
Michael Schuster
73462e97aa Heavy refactoring: Windows workaround for >= 4k (4096 bit) client-cert SSL keys and large certs
With QtKeychain on Windows, storing larger keys or certs in one keychain entry causes the
following error due to limits in the Windows APIs:
    Error: "Credential size exceeds maximum size of 2560"

This fix implements the new wrapper class KeychainChunk with wrapper jobs ReadJob and WriteJob
to encapsulate the QKeychain handling of ReadPasswordJob and WritePasswordJob with binaryData
but split every supplied keychain entry's data into 2048 byte chunks, on Windows only.

The wrapper is used for all keychain operations in WebFlowCredentials, except for the server password.

All finished keychain jobs now get deleted properly, to avoid memory leaks.

For reference also see previous fixes:
- https://github.com/nextcloud/desktop/pull/1389
- https://github.com/nextcloud/desktop/pull/1394

This should finally fix the re-opened issue:
- https://github.com/nextcloud/desktop/issues/863

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 9b034a2eb0)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:52 +01:00
Michael Schuster
6f4144a464 Flow2AuthWidget: Minor fixes and improvements
- Improve status messages

- Add a counter to make sure that "Link copied to clipboard." is visible for
  three seconds and to not enable the buttons too early

- Add more space between buttons and status

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit bd9652b24c)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:51 +01:00
Michael Schuster
9820464545 Flow2: Refactor UI into Flow2AuthWidget only and improve Flow2Auth
- Flow2AuthCredsPage:
  - Remove .ui file and embed Flow2AuthWidget into layout

- Flow2AuthWidget:
  - Make use generic for Flow2AuthCredsPage and WebFlowCredentialsDialog
  - Fix _errorLabel to render HTML tags instead of dumping them as plain text

- Flow2Auth:
  - Explicitly start auth with startAuth(account) instead of using constructor
  - Take control of copying the auth link to clipboard
  - Request a new auth link on copying, to avoid expiry invalidation
  - Use signals statusChanged() and result() to be more verbose (status, errors)
  - Change timer invocation and add safety bool's to avoid weird behaviour when
    the user triggers multiple link-copy calls (fetchNewToken)

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 8b5f09305c)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:51 +01:00
Michael Schuster
3ecd7823f9 Add new HeaderBanner class for WebFlowCredentialsDialog
New widget on top of the layout, based on Qt's own modern wizard header banner.

This should improve the user's perception of the dialog.

Encapsulate the existing layout into a container layout to allow the banner taking
the full width of the dialog.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 6d033f2964)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:51 +01:00
Michael Schuster
9b504eaddd Make WebFlowCredentialsDialog cancellation- and deletion-safe
- Add new signal to let WebFlowCredentials know and emit asked() to also
  tell AccountState that the user won't authenticate, and triggering
  log-out state in the settings window.

- Use deleteLater() to safely delete WebFlowCredentialsDialog, so
  that Qt can free it at the right time and without crashes.
  Do the same with it's _webView and _flow2AuthWidget on closeEvent().

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 0bcac1882a)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:51 +01:00
Michael Schuster
838ca6cba0 WebFlowCredentialsDialog: Bring re-auth dialog to top (raise) on error
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit b6b04aeff8)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:51 +01:00
Michael Schuster
7e5e40d5c4 Flow2: Make ProgressIndicator's background-aware (Dark-/Light-Mode switching)
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit a69aed80e6)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:50 +01:00
Michael Schuster
abd8d1fda1 Flow2: Add poll status text, ProgressIndicator and countdown timer
Also enable / disable buttons during polling.

This aims to make the authentication status more transparent and should avoid the
impression that the client is perhaps doing nothing.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit e81f972270)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:50 +01:00
Michael Schuster
0a3491f332 Small fixes and code cleanup
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 542590db7c)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:50 +01:00
Michael Schuster
15d9ca2b00 Flow2: Poll for re-auth result upon WebFlowCredentialsDialog window activation
Since the default remote poll interval has been re-raised recently to 30 seconds,
the delay between clicking "Grant access" in the browser and fetch and showing success
in the dialog may seem erroneous to the users and tempt them to click "Re-open browser"
again, causing the whole login process to restart.

This commit implements an event handler to pass the dialog's window activation
event down to the Login Flow v2 widget, in order to allow it to poll earlier.

See previous commits for dependent implementation details.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit e04aae94bc)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:50 +01:00
Michael Schuster
7682749415 WebFlowCredentialsDialog: Bring re-auth dialog to top (raise) upon showing SettingsDialog
Purpose: The floating re-auth windows of the WebFlowCredentialsDialog often get hidden behind
the SettingsDialog, and the users have to minimize a lot of other windows to find them again.

See previous commit for dependent implementation details.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit aa18667905)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:50 +01:00
Michael Schuster
a18fc5b5c9 Add helper slots and signals to catch SettingsDialog's window activation events
Signal the SettingsDialog's window activation event down to ownCloudGui and Application,
so that other classes can hook in to get notified when the SettingsDialog is being shown
again.

This approach has been chosen because we otherwise would have to deal with new instance
pointers of the current SettingsWindow - but Application is already there ;-)

Purpose: The floating re-auth windows of the WebFlowCredentialsDialog often get hidden
behind the SettingsDialog, and the users have to minimize a lot of other windows to find
them again. This commit implements the preparation for the upcoming fix commit.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit addb27a085)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:50 +01:00
Michael Schuster
96783a9b80 Flow2: Use ownCloudGui::raiseDialog to bring account setup wizard to top (raise) on auth result
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit be10d5200f)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:49 +01:00
Michael Schuster
258c2cee2e Flow2: Poll for auth result upon account setup wizard window activation
Since the default remote poll interval has been re-raised recently to 30 seconds,
the delay between clicking "Grant access" in the browser and fetch and showing success
in the wizard may seem erroneous to the users and tempt them to click "Re-open browser"
again, causing the whole login process to restart.

This commit implements an event handler to pass the wizard's window activation
event down to the Login Flow v2 page, in order to allow it to poll earlier.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit e8348612b4)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:49 +01:00
Michael Schuster
65ff3c0de1 Flow2: Bring account setup wizard to top (raise) on auth result
Show and raise the wizard on success / error in the Login Flow v2 auth.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 3a160a4dce)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:49 +01:00
Michael Schuster
6879c9f1c9 Fix issue #1237: White text on almost-white background
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit ccd20f0172)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:49 +01:00
Michael Schuster
fade8465e4 Fix folder opening in ActivityListModel
After fixing the crash in the previous commit, double-clicking on Activity list rows still didn't work.

This fix partly reverts commit 8546d53b05 in ActivityItemDelegate::PathRole
of ActivityListModel::data, but adds a new check for relPath's existence in line 74.

I'm assuming the previous change there has been done to shorten the code and avoid opening the user's home
folder upon clicking entries which file value is "App Password". The new path-check takes care of that too now.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit c03bc8540c)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:49 +01:00
Michael Schuster
76b5c6b6d4 Fix crash in ActivityListModel (fixes #1693)
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 003acb7254)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:49 +01:00
Michael Schuster
bdd0cc4dc3 Show date and time in activity log (fixes issue #1683)
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit b961b683d6)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:16:48 +01:00
Michael Schuster
876b1e239e Fix build (missing refactoring)
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit a7dade979c)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:15:53 +01:00
Michael Schuster
da2007c7f6 Mac and high-dpi displays: Add workaround in ActivityItemDelegate to show full uncropped activity's actionText and timeText
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 3a2caf61e5)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:15:53 +01:00
Michael Schuster
7a33cb97cd Make all ProgressIndicator's background-aware (Dark-/Light-Mode switching)
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit b5ed16088a)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:15:53 +01:00
Michael Schuster
7a18a58fae Make OwncloudWizard and its pages background-aware (Dark-/Light-Mode switching)
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit e4a20b9e72)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:15:53 +01:00
Michael Schuster
fcc9d02bcc Remove unnecessary string translation and copy in ActivityItemDelegate
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 37e5fe786f)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:15:52 +01:00
Michael Schuster
98238669fe Remove unnecessary breaks in ActivityListModel
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 643995528b)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:15:52 +01:00
Michael Schuster
a80de38517 Make ActivityItemDelegate background- and selection-aware (Dark-/Light-Mode switching)
Also implement cached member icons in ActivityListModel and return their enums to
ActivityItemDelegate instead of always recreating them for each call to paint().

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit ecd17f2ea2)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:15:52 +01:00
Michael Schuster
4cb75d91f9 Refactor ActivitySettings: Rename member variable ui to _ui
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit bf0bf2c1b6)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:15:52 +01:00
Michael Schuster
55e4dceeb7 Make AccountSettings and ActivitySettings background-aware (Dark-/Light-Mode switching)
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit acedf362b6)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:15:52 +01:00
Michael Schuster
0006b35abf Change error link colour in AccountSettings::showConnectionLabel
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 3b580eeca7)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:15:51 +01:00
Michael Schuster
b153391cbf Add new Theme helper method to custom-colourize links
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 6adfff1f13)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:15:51 +01:00
Michael Schuster
c0659a3124 Change Dark Mode link colour
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 7d542d7989)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-24 09:15:49 +01:00
Michael Schuster
de8a7aa680 Fix Activity List: Add check to avoid first empty entry
Add checks to ActivityListModel::combineActivityLists in order to avoid adding
empty Activity entries to the _finalList.

The previous implementation always added an empty entry to the top of the list because
_notificationIgnoredFiles was appended without checking (_listOfIgnoredFiles.size() > 0).

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit cc21d175f1)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-18 03:31:32 +01:00
Michael Schuster
03b11693a3 Fix build for stable-2.6 (changes from PR #1651)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-09 22:45:47 +01:00
Camila San
23f2d79f70 Bump version to 2.6.2 2019-12-09 21:51:13 +01:00
Michael Schuster
f6db365391 Update translations
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-09 21:48:20 +01:00
Michael Schuster
95f74ceb1f macOS: Rename 'Explorer' appropriately on non-Windows
- Rename it to 'Finder' on macOS.
- This way we also avoid having the whole string re-translated on Transifex.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit b754eacd74)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-09 21:46:48 +01:00
Michael Schuster
91be4961d7 Make the ShareDialog background-aware (Dark-/Light-Mode switching)
Use customizeStyle() to change link colours, icons and pixmaps in the ShareDialog and notify
it's widgets via slots.

TODO - known issue (macOS):
- The background and font colours in the ShareUserLine widget still stay the same.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 7ce8a6a201)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-09 21:46:48 +01:00
Michael Schuster
b3eb16bfd3 Make SettingsDialog background-aware (Dark-/Light-Mode switching)
Use customizeStyle() to change link colours in the SettingsDialog and notify it's widgets via slots.

Also modify the background colour of the errors messages in AccountSettings::showConnectionLabel
to always use an appropiate colour for it's custom-defined background.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 789a2a7ae3)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-09 21:46:47 +01:00
Michael Schuster
52d91ce198 Implement and move some colour-aware helper methods into the Theme class
This introduces a new method to change the colours in the links in QLabel's.
Utilizes a custom crafted RegEx function to replace already-coloured links.

Moved code is based on stuff from the SettingsDialog class.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit be4fc6b887)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-09 21:46:47 +01:00
Michael Schuster
c49efcc137 Pick from upstream: Fix too low contrast when tab is selected
The low contrast is also a problem with the Dark Mode on macOS.

For reference please see:
- Commit: 413ef5e96d
- Issue: https://github.com/owncloud/client/issues/7512

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 2dae31486a)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-09 21:46:47 +01:00
Michael Schuster
c14556153f Fix SSL-button's info background color for Dark Mode
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 71f66c6229)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-09 21:46:47 +01:00
Michael Schuster
5e1a2a423f Remove submodule qtmacgoodies and the MacSettingsDialog class
Reverts back to the SettingsDialog class because of bugs and glitches with
more recent Qt versions (Qt 5.12) and with the macOS Dark Mode.

See upstream: https://github.com/owncloud/client/pull/7492

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit b4f926ded7)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-09 21:46:44 +01:00
Michael Schuster
3ac1ba079a Fix deleteKeychainEntries: Stay consistent with job->setInsecureFallback(false)
We never fall back to the insecure variant in the whole codebase, so don't do it here.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 5869b93acb)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-08 03:10:30 +01:00
Michael Schuster
b7a9cd1d45 Fix Windows key-chunk deletion (too paranoid)
Clear the key chunk buffer, but don't set _clientSslKeyChunkCount to zero because we need it later for deleteKeychainEntries

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit b15eb27aa9)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-08 03:10:29 +01:00
Michael Schuster
c7b0ce036d Fix member variable name from last refactoring (Windows code)
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 336b64a569)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-08 03:10:29 +01:00
Michael Schuster
f5afa07b0a Fix Remote Wipe keychain storage
In certain cases don't write the app password in Account::writeAppPasswordOnce:
- id() is empty: This always happend once the Account Wizard showed the folder selection
- appPassword is empty: Caused by Logout -> Relaunch, preventing remote wipe on relaunch

Implement some logging to ease debugging in the future.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 6a49e787bb)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-08 03:10:29 +01:00
Michael Schuster
1b550b976f Remote Wipe: Implement hack to allow deleting all keychain entries (SSL certs & keys)
Client SSL certificates and keys cannot be deleted at this time because there is
no UI for selecting them on re-login.

We introduce this dirty hack here, to allow deleting them upon Remote Wipe.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 0c5f4a1525)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-08 03:10:29 +01:00
Michael Schuster
68f0b9e0aa Refactoring: Windows workaround for >= 4k (4096 bit) client-cert SSL keys
WebFlowCredentials:
- Remove _clientSslCaKeyWriteQueue and simply use _clientSslKeyChunkBufferPEM
- Store key's sub-chunks in slots with "." (dot) suffix
- Implement deletion of the key chunks in WebFlowCredentials::deleteKeychainEntries
- Remove spaces in log messages
- Improve code readability

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 6ef9f3cc26)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-08 03:10:29 +01:00
Michael Schuster
8945ef2652 Windows: Workaround for storing >= 4k (4096 bit) client-cert SSL keys
With QtKeychain on Windows, storing larger keys in one keychain entry causes the
following error due to limits in the Windows APIs:
  Error: "Credential size exceeds maximum size of 2560"

To avoid overhead on the other platforms and balance code duplication, this
approach puts some read- and write-parts into Windows-only defines.

For reference also see previous fixes:
- https://github.com/nextcloud/desktop/pull/1389
- https://github.com/nextcloud/desktop/pull/1394

This (again) fixes the re-opened issue:
- https://github.com/nextcloud/desktop/issues/863

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 72be80cbd9)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-08 03:10:26 +01:00
Felix Eckhofer
0cc74d21a2 Use user-provided username in displayName()
This replaces `davUser()`, which is replaced by a numeric ID when using
LDAP, by the username that was actually used for logging in.

Fixes #836

Signed-off-by: Felix Eckhofer <felix@eckhofer.com>
(cherry picked from commit ace142bb23)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-06 22:28:53 +01:00
Felix Eckhofer
f4c79c8f68 Fix typo
Signed-off-by: Felix Eckhofer <felix@eckhofer.com>
(cherry picked from commit 28da954aad)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-06 22:24:20 +01:00
Joas Schilling
b6ef8edb12 Use … instead of 3 dots
Signed-off-by: Joas Schilling <coding@schilljs.com>
(cherry picked from commit a4fa8b05e5065da62bb7f6d3cc8c371a2a68ed06)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-06 21:26:23 +01:00
Joas Schilling
06ffd3e841 Fix some translations
Signed-off-by: Joas Schilling <coding@schilljs.com>
(cherry picked from commit 862342872d9685c8be89406182d471d246c2f9a7)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-06 21:26:15 +01:00
Joas Schilling
a3596b80e9 Improve the translation of "Share via …"
Signed-off-by: Joas Schilling <coding@schilljs.com>
(cherry picked from commit 98b7d2ebc00ceda1ff74e2adad3b340193e7eb17)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-06 21:25:43 +01:00
Michael Schuster
8ac1d92161 Fall back to old login flow on GS as this is not yet ready (#2: re-auth)
This commit ensures that the check also occurs on re-authorization in case
the user gets logged out.

See: https://github.com/nextcloud/desktop/pull/1644

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 877fd7abb9)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-06 21:10:13 +01:00
Roeland Jago Douma
d55f1d5c06 Fall back to old login flow on GS as this is not yet ready
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
(cherry picked from commit 363e62f8fa)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-06 21:10:02 +01:00
David Kahles
854c637c73 Compare QDateTime objects more efficient
There is no need to call toMSecsSinceEpoch() as QDateTime implements an
comparison operator itself. This is more efficient, because the
QDateTime comparison operator doesn't call localtime() in all cases. Thus, we
don't read /etc/localtime for every comparison. This improves
performance in some cases.

Signed-off-by: David Kahles <david.kahles96@gmail.com>
(cherry picked from commit 9a3aa55b29)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-06 16:20:27 +01:00
István Váradi
92ad0c4a43 Add libdbus-1-dev to the build dependencies
Signed-off-by: István Váradi <ivaradi@varadiistvan.hu>
(cherry picked from commit 805b85a4d7)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-05 20:27:44 +01:00
Corentin Noël
fb8facb787 Build with libcloudproviders on debian and in the AppImage
Signed-off-by: Corentin Noël <corentin.noel@collabora.com>
(cherry picked from commit 04dd02c295)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-05 20:27:02 +01:00
Michael Schuster
30832cc427 MSVC Fix for PR #1526: Fix clang's variadic macro warnings
The recently merged #1526 caused the MSVC Builds on Windows to fail.

This patch sets the new CMake flag only if the compiler it not MSVC.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit a12164ad53)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-05 20:21:13 +01:00
Johannes Lorenz
ab7f29c0b2 Fix clang's variadic macro warnings
Using variadic macros like `qCWarning()` without any parameter for "..."
is a GNU extension, which causes a lot of `clang` warnings:

```
desktop/src/common/ownsql.cpp:74:24: warning: must specify at least one
 argument for '...' parameter of variadic macro
 [-Wgnu-zero-variadic-macro-arguments]
        qCWarning(lcSql) << "Error:" << _error << "for" << filename;
                       ^
/usr/include/qt/QtCore/qloggingcategory.h:140:11: note: macro 'qCWarning'
 defined here
          ^
```

This patch tells `clang` to be silent.

Signed-off-by: Johannes Lorenz <j.git@lorenz-ho.me>
(cherry picked from commit 8c334a1f43)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-05 20:20:56 +01:00
Camila San
6500442217 Merge the list of ignored files/symlinks into one Activity notification.
Signed-off-by: Camila San <hello@camila.codes>
(cherry picked from commit 8546d53b05)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-05 20:12:11 +01:00
Dominique Fuchs
0e6a9fd0c1 Don't need a second if for non-Windows, using Qt macro for platform check
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 7750d2198d)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-05 20:05:06 +01:00
Dominique Fuchs
ed7c489722 Fixed typo preventing successful path rename on Win and modified ASSERT for Window path styles
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit f993e7c555)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-12-05 20:04:25 +01:00
Michael Schuster
d4b9b5129a Fix copyright year in MacOSXBundleInfo.plist.in for 2019
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 407864c40e)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-29 17:27:15 +01:00
Michael Schuster
4a79e24db2 Use ReadPasswordJob::finished for ReadPasswordJob
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 76c7ab499f)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-29 15:59:33 +01:00
Michael Schuster
215d185fbe Fix remote wipe keychain storage (issue #1592)
The app password for the remote wipe was constantly being written in
WebFlowCredentials::slotFinished to the keychain, leading to unnecessary
write and log overhead on the system.

This fix introduces a check to only store the app password once in
a lifetime of the Account class. Also the method used to store the
password will be renamed from setAppPassword to writeAppPasswordOnce
to be more expressive.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit dcc84d3508)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-29 15:59:30 +01:00
Andreas Wunderlich
6f273bf7dd Revert default remote poll interval back from 5 seconds to 30 seconds
Signed-off-by: Andreas Wunderlich <code@andwun.me>
(cherry picked from commit f293dbfeeb)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-28 18:08:22 +01:00
Michael Schuster
f2bc25c9ca macOS build: Avoid the Get-Task-Allow Entitlement (Notarization)
Setting CODE_SIGN_INJECT_BASE_ENTITLEMENTS to NO is required for macOS
Notarization.

See: https://developer.apple.com/documentation/xcode/notarizing_macos_software_before_distribution/resolving_common_notarization_issues

And upstream: 97f4af32ae

Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-27 15:19:41 +01:00
István Váradi
ca6de6128f Build for Debian stable and oldstable
Signed-off-by: István Váradi <ivaradi@varadiistvan.hu>
(cherry picked from commit 2fc76c2b24)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-27 15:09:50 +01:00
Christoph Wurst
a1e5e6ca40 Fix legal notice year
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
(cherry picked from commit 923abd8d0b)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-27 15:09:38 +01:00
Michael Schuster
cf8bb1c5bc Merge pull request #1622 from nextcloud/backport/1621/stable-2.6
[stable-2.6] Add timestamp to Mac installer code signing
2019-11-17 20:35:16 +01:00
Michael Schuster
ebe1cef357 Add timestamp to Mac installer code signing
Use the --timestamp option for 'productsign' to add a secure timestamp.

See: https://developer.apple.com/documentation/xcode/notarizing_macos_software_before_distribution/resolving_common_notarization_issues

Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-17 19:33:56 +00:00
Michael Schuster
922d14f016 Fix: add /usr/local/lib to LD_LIBRARY_PATH for OpenSSL 1.1.1
Drone pipeline qt-5.12 failed because the unit tests didn't find OpenSSL.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit fce0a50e37)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-17 03:23:45 +01:00
Michael Schuster
7a0c6a2f8f Fix: escape env vars
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit c047232c3b)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-17 03:23:42 +01:00
Michael Schuster
f35a2c0b2c Bump Qt 5.12.5 image
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit a846f0276d)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-17 03:23:37 +01:00
Michael Schuster
c6b22089e3 Fix dir in upload script
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 801098f546)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-17 02:17:02 +01:00
Michael Schuster
cf0082f92f Make AppImage upload optional and add timeout
Moves the upload into a separate Drone command and adds a timeout for curl
to fail after 15 minutes.

Returns zero to keep Drone from failing.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 4fc8936553)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-17 02:17:00 +01:00
Michael Schuster
f4e129d4e2 Move .desktop file path to new env var to avoid duplicates
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit dd0135ce2e)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-17 02:16:55 +01:00
Michael Schuster
ec6eaf2121 Upgrade for Qt 5.12.5 in docker-ci
- Use the new image: nextcloudci/client-5.12:client-5.12-5
- Use it's new QT_BASE_DIR: /opt/qt5.12.5

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit d830a1c5f7)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-17 02:13:03 +01:00
Michael Schuster
1dc1f91620 Fix: Apply http2 patch from owncloud #1573 - only with Qt >= 5.8
Drone builds failed with Qt 5.7 and we introduce a new ifdef here
to avoid patching specifically for Ubuntu Xenial only.

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 5131463644)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-14 03:33:49 +01:00
Adrian Brzezinski
5adbc01ef1 * fix for issue no. 1351 2019-11-04 22:48:42 +01:00
Sergey Zolotarev
c4a04bfd05 Don't run connection wizard when quitting the application
Signed-off-by: Sergey Zolotarev <sryze@protonmail.com>
2019-11-04 22:40:18 +01:00
Sergey Zolotarev
03711429f4 Replace isQuitting flag with disconnect()
Signed-off-by: Sergey Zolotarev <sryze@protonmail.com>
2019-11-04 22:40:07 +01:00
Michael Schuster
e3cb040c3c Update submodules for Qt 5.12.5 (qtmacgoodies)
Fetch the new submodule commits to get these fixes:
- Merge upstream: Retrieve the associated NSView more reliably: https://github.com/camilasan/qtmacgoodies/pull/1
- Bugfix for Qt 5.12.5 - Redraw the ToolBar: https://github.com/camilasan/qtmacgoodies/pull/2

Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-04 22:38:21 +01:00
Camila San
83a21179fa Update translation files.
Signed-off-by: Camila San <hello@camila.codes>
2019-11-04 20:54:47 +01:00
XNG
829da85aa5 Apply http2 patch from owncloud
Signed-off-by: XNG <Milokita@users.noreply.github.com>
2019-11-04 20:22:31 +01:00
Camila San
3b1ac89312 Fix remote wipe when a proxy is configured.
Signed-off-by: Camila San <hello@camila.codes>
2019-11-04 20:20:00 +01:00
Michael Schuster
57df29e7c9 Merge pull request #1582 from nextcloud/backport/1580/stable-2.6
[stable-2.6] Fix updater message: Download link instead of "use the system's updat…
2019-11-04 19:58:08 +01:00
Michael Schuster
d774067004 Fix updater message: Download link instead of "use the system's update tool"
Provide a download link to the new version instead of the confusing message that
users should use their "system's update tool to install it".

Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-11-04 18:56:20 +00:00
Camila San
728154386c Once client gets 401/403 from the server, check if remote wipe was requested.
- When the the users logs because of 401 or 403 errors, it checks if the
server requested the remote wipe. If yes, locally deletes account and folders
connected to the account and notify the server. If no, proceeds to ask the
user to login again.
- The app password is restored in the keychain.
- WIP: The change also includes a test class for RemoteWipe.

Signed-off-by: Camila San <hello@camila.codes>
2019-11-04 19:31:17 +01:00
tuxmaster5000
bc31182c63 Rename owncloud tests to nextcloud 2019-11-04 19:31:07 +01:00
Michael Schuster
a6bb84080a Merge pull request #1555 from nextcloud/backport/1554/stable-2.6
[stable-2.6] Fix duplicate items in Apps menu (a bug introduced in #1477)
2019-10-23 23:49:01 +02:00
Sergey Zolotarev
576ba7c011 Fix duplicate items in Apps menu (a bug introduced in #1477)
Signed-off-by: Sergey Zolotarev <sryze@protonmail.com>
2019-10-23 21:46:35 +00:00
Camila San
b6893aad16 Bump version to 2.6.1.
Signed-off-by: Camila San <hello@camila.codes>
2019-10-17 22:35:28 +02:00
kilian.pfeiffer
59d1624ce5 changed max GUI bandwith limits 2019-10-17 21:48:21 +02:00
Ivan Čukić
a0faf1f54d Race condition in the remote size loading logic
The quota retrieval process might not be finished by the time
the used space on the server (`_rSize`) is compared against
the locally available disk space which might end up in
a "There isn't enough free space in the local folder!" message
even if there is enough free space.

This patch updates the status after the quota has been retrieved.

It also initializes `_rSize` to `-1` so that errors like this
are easier to catch in the future.
2019-10-17 21:44:58 +02:00
Michael Schuster
caa7c845c2 fix comment typo
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 21:38:18 +02:00
Michael Schuster
e43a80d0be Fix double slashes in WebDAV URLs (account setup wizard)
Sanitize URL paths to elaminate double-slashes in the URL path string,
used for the first connection by the account setup wizard.

Example: https://cloud.example.com/remote.php/webdav//

Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 21:37:41 +02:00
Michael Schuster
f060a92563 Fix outdated link to server admin docs
Sets the target version from "15" to "latest" and removes
"index.html" because this could get obsolete in the future too.

Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 21:34:05 +02:00
Dominique Fuchs
483696261d Fixed some missing 'translatable' exclusions, added missing window titles in flow dialogs
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
2019-10-17 21:33:34 +02:00
Dominique Fuchs
610e35ec64 Fixed unused var
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
2019-10-17 21:22:48 +02:00
Dominique Fuchs
5fa5526ea2 Added slight svg transparency as requested in ref issue, fixed bg detection logic
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
2019-10-17 21:22:40 +02:00
Dominique Fuchs
42d9d99a92 (Maybe) finished implementation of themed wizard buttons and accessibility refinements and thus implementation of helper fct. to retrieve themed QIcons.
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
2019-10-17 21:22:30 +02:00
Dominique Fuchs
c3ff9ca917 [WIP] themed button implementation
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
2019-10-17 21:22:21 +02:00
Dominique Fuchs
875f123d5b [WIP] Resource file and include changes as well as new control icons for wizard slide buttons
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
2019-10-17 21:21:58 +02:00
Dominique Fuchs
a5f053afe4 Layout optimizations and tab access for self-hosting link
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
2019-10-17 21:18:03 +02:00
Dominique Fuchs
63a6992f97 fix naming for slide navigation, adapted everywhere to be consistent
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
2019-10-17 21:17:34 +02:00
Dominique Fuchs
54740378f0 Restructured layout, as the initial change were too broken (after additions through the last months)
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
2019-10-17 21:16:51 +02:00
Dominique Fuchs
1dc443bc06 Fixed wrong resource paths
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
2019-10-17 21:15:57 +02:00
Dominique Fuchs
e541109d7c Added newly created next/prev svg's and fixed reduntant layout parts in wizard
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
2019-10-17 21:13:47 +02:00
Izabela Bakollari
993f124120 Add files via upload 2019-10-17 21:12:05 +02:00
Camila San
0a373ea708 Checks if exclude file is empty before creating the regular expressions.
The default file created by the application it is not empty.

Signed-off-by: Camila San <hello@camila.codes>
2019-10-17 21:03:42 +02:00
Daniel Kesselberg
0fae01495e Add server info to menu
Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
2019-10-17 21:03:23 +02:00
rakekniven
97867384b1 Fixed grammar
Reported at Transifex.
See https://www.transifex.com/nextcloud/nextcloud/translate/#nl/client/182396083

Signed-off-by: rakekniven <mark.ziegler@rakekniven.de>
2019-10-17 21:03:05 +02:00
Sergey Zolotarev
c54f6e83ed Prevent jumping of tray menu
Instead of adding the "Apps" menu after the apps are fetched, add it
from the start (together with other actions) but in a disabled state,
and enable it after the apps data is ready.

Signed-off-by: Sergey Zolotarev <sryze@protonmail.com>
2019-10-17 21:02:47 +02:00
Sergey Zolotarev
a9a731dfc0 Don't run connection wizard when quitting the application
Signed-off-by: Sergey Zolotarev <sryze@protonmail.com>
2019-10-17 21:02:28 +02:00
Sergey Zolotarev
d0f469bd90 Replace isQuitting flag with disconnect()
Signed-off-by: Sergey Zolotarev <sryze@protonmail.com>
2019-10-17 21:02:09 +02:00
asapelkin
374375ce3f little loops optimization
Signed-off-by: asapelkin <asapelkin0x01@ya.ru>
2019-10-17 20:55:56 +02:00
Michael Schuster
89ef03412e Pick from upstream: Update qtmacgoodies for an OSX crash fix #6930
With Qt 5.12.5 this OC crash also applies to the Nextcloud Desktop Client on macOS.

For reference please see:
- https://github.com/owncloud/client/issues/6930
- 0dc7bc3328

For the required changes in the qtmacgoodies submodule see:
https://github.com/camilasan/qtmacgoodies/pull/1

Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 20:52:42 +02:00
Nextcloud bot
07d3fe3a79 [tx-robot] updated from transifex
(cherry picked from commit 04f2bd4baa)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 20:37:56 +02:00
Nextcloud bot
24107040cc [tx-robot] updated from transifex
(cherry picked from commit 4f7d7e3601)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 20:37:49 +02:00
Nextcloud bot
9d9fc6d0bf [tx-robot] updated from transifex
(cherry picked from commit 13b2b5253e)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 20:37:41 +02:00
Nextcloud bot
51f5991f1e [tx-robot] updated from transifex
(cherry picked from commit 2121e7116e)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 20:37:32 +02:00
Javier Llorente
a8b93516cc Add sync date next to "Synchronized with local folder"
(cherry picked from commit cbc19e86fb)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 20:37:21 +02:00
Sebastian Grund
a85c228e59 issue1216: added sync-exclude entry for emacs recovery files
Signed-off-by: Sebastian Grund <grund92@gmx.de>
(cherry picked from commit a9bea53c89)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 20:37:11 +02:00
Michael Schuster
04a75eaca2 Add warning for failed chown in libsync/propagatedownload.cpp
In addition to PR 1409 generate warnings if chown fails.

See: https://github.com/nextcloud/desktop/pull/1409

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 207de071f4)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 20:36:41 +02:00
Michael Schuster
2f46601396 Replace old NSI Windows setup wizard graphics
New UI resources based on current https://github.com/nextcloud/promo

New:
- Icon based on https://github.com/nextcloud/desktop/pull/1401
- Wizard image & header image (dotted background replaces old cloud background)

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 819a006a17)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 20:33:28 +02:00
Dominique Fuchs
18fc6a9e0e fixed wrongly assigned pointer, didn't recognize class
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit c662ff1902)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:38:55 +02:00
Dominique Fuchs
34675e03a8 Use -Wno-gnu-zero-variadic-macro-arguments only for Clang
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit a3825080db)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:38:55 +02:00
Dominique Fuchs
4b5cf94a29 Q_UNUSED for atm unused parameters
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit a237493def)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:38:55 +02:00
Dominique Fuchs
1729e1a94c Declared Q_UNUSED for as-of-now unused parameters.
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 3a0cd45782)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:38:55 +02:00
Dominique Fuchs
60859714ae Prevented warning regarding operator precedence - enhanced clarity by adding parentheses
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit f08cc08eb2)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:38:55 +02:00
Dominique Fuchs
b5fcfd918b removed reduntant /* within a comment
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit e3685b951c)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:38:54 +02:00
Dominique Fuchs
44176be964 Remove unnecessary argument
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 6b04e2f77b)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:38:54 +02:00
Dominique Fuchs
3935866052 Prevent use of uninitialized folder pointer.
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 2e8b7771b0)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:38:54 +02:00
Dominique Fuchs
1e9c45222c Added forgotten case when parsing log through gui. LockedFiles were not communicated.
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 26e98d35e6)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:38:54 +02:00
Dominique Fuchs
adc3b1a25c initialize _modtime to prevent undefined usage
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit ab3d0141ec)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:38:54 +02:00
Dominique Fuchs
9ae0417cad Use return type to prevent warning and determine chown success. Added TODO
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 39df36c247)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:38:54 +02:00
Dominique Fuchs
03453d6800 Removed disabling of msvc warning to prevent generating a unknown option for other compilers in turn. Now detect specifically GCC in ifdef
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 7473cdf184)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:38:53 +02:00
Dominique Fuchs
1ac9c4ea8d Moved macro definition due to timing issues while compiling when relying on header inheritance
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit c585e81530)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:19 +02:00
Dominique Fuchs
986bb49a88 Conditional (based on Qt version) use of 'horizontalAdvance' to provide better UI experience. See https://doc.qt.io/qt-5/qfontmetrics-obsolete.html#width
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit c779098772)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:19 +02:00
Dominique Fuchs
8f39c4140e commit 222b2d did the trick. now streamlined use of https://doc.qt.io/qt-5/qtglobal.html#QT_VERSION_CHECK
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit cc07ed1ee8)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:18 +02:00
Dominique Fuchs
9c7903868f Further testing of cond. include of Qt library > 5.9. Utilized different macro.
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 222b2d8645)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:18 +02:00
Dominique Fuchs
8ee1adf058 Fixed another logic error -> logical to bitwise OR for QTLEGACY
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit f41eeaf6ec)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:18 +02:00
Dominique Fuchs
27fb1fcd53 Fixed logic error in QTLEGACY macro and added forgottin #if clause for header file
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 48097801e8)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:18 +02:00
Dominique Fuchs
29cc5c1e7f Added macro definition and compile-time condition to support Qt < 5.9
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit dca83aad45)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:18 +02:00
Dominique Fuchs
29bb76019f Indeed, DWORD is a special snowflake - only when on _WIN32
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit be7a524557)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:18 +02:00
Dominique Fuchs
bf6d57f327 Fixed wrongly formatted args for win32 linker flags resulting in 'unrecognized option' for all of them. Remark: /WL is for VS only, useless (and not necessary for msvc cmd)
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 0827ff0995)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:17 +02:00
Dominique Fuchs
eb5ec05ef8 Fixed missing braces
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 503b9de2a0)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:17 +02:00
Dominique Fuchs
c723028eae Qt: Fixed numerous deprecated calls by adapting newer ones
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit a2d47cdec4)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:17 +02:00
Dominique Fuchs
5d024fdf33 Added cmake preprocessor definitions when using msvc regarding the 'safe' versions of CRT functions
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit ba74c24d8f)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:17 +02:00
Dominique Fuchs
ed99cb297b Use existing fct for RegKeyQuery instead of redundant subroutine
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit d60a216982)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:17 +02:00
Dominique Fuchs
a0e794a7f1 Numoerous safe conversions implemented. Added additional Utility::convertSizeToDWORD for windows builds.
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit d6af025a46)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:16 +02:00
Dominique Fuchs
0761342840 Corrected namespace when calling convertSizetoUint
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 82fa10c227)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:16 +02:00
Dominique Fuchs
4da9123b67 Renamed conversion function to make intention more clear. Also defaulted to 'controlled truncation' to not stupidly crash. TBD/TODO: Better handling for such things.
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 46e0a05078)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:16 +02:00
Dominique Fuchs
c7158e2c7c Selectively and temporary disabled warning about unknown preprocessor declarative for msvc when using specific GCC instruction.
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 8329de4cee)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:16 +02:00
Dominique Fuchs
4adc45483a Implemented Utility::convert function to convert size_t -> uint safely and on the fly. Often necessary for Qt and WIN32 functions. Using this will not generate compiler warnings of possible truncation. First call implemented in ownsql.cpp
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit b4dee67bf5)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:16 +02:00
Dominique Fuchs
ae0ff6b3e3 Fixed broken overloading mechanism of variadic templates. See code comment for further information.
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 5ae3435fe6)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:16 +02:00
Dominique Fuchs
dc6d2e6a6d usage of UINT as iterator here because comparing with UINT retval from DragQueryFile
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 9a256fcbfe)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:15 +02:00
Dominique Fuchs
5127f50d1e Removed redundant (and wrong in terms of it's value) definitions for WINVER/_WIN32_WINNT
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 112d2bfe11)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:15 +02:00
Dominique Fuchs
a26f2a7359 Removed redundant (and wrong in terms of it's value) definitions for WINVER/_WIN32_WINNT
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 69a11a7ec1)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:15 +02:00
Dominique Fuchs
42f1f445a9 Removed redundant (and wrong in terms of it's value) definitions for WINVER/_WIN32_WINNT
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 3960ffea3f)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:15 +02:00
Dominique Fuchs
51304485c3 Updated WINVER/_WIN32_WINNT from 0x0600 to 0x0601 (e.g. Server 2008/Vista to 7) as 7 is reasonable and noted everywhere as requirement
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit 78543deee4)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 19:34:12 +02:00
Björn Bidar
63cc6edddd fix qt warning about registering a URL sheme first.
Qt recommends to register a URL scheme before installing it.
I don't know the impact of the not registering before instaling but I
think the change is pretty harmles.

See:
https://doc.qt.io/qt-5/qwebengineurlscheme.html#registerScheme
Signed-off-by: Björn Bidar <theodorstormgrade@gmail.com>
(cherry picked from commit cea0d519a4)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 18:08:39 +02:00
Dominique Fuchs
58abebe9ac Fixed e2e key transmission issue after generation (forgotten content type on sendrequest())
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
(cherry picked from commit a35b346e62)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-17 17:33:41 +02:00
Michael Schuster
1182ae9e26 Merge pull request #1515 from nextcloud/qt5-mac-5.12-prepare
Add new "styles" plugin to macOS deployment script for Qt 5.12.5
2019-10-15 23:58:26 +02:00
Michael Schuster
3407174c2f Add new "styles" plugin to macOS deployment script for Qt 5.12.5
Qt 5.12 needs this library to use the correct style for Light / Dark Mode:

  styles/libqmacstyle.dylib

The interface looks like from the 1990's without this library ;-)

Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-14 02:01:56 +02:00
Michael Schuster
913894eaa5 Merge pull request #1496 from nextcloud/backport/1495/stable-2.6
[stable-2.6] Add a 'Content-Length: 0' header to initial POST requests
2019-10-10 08:11:43 +02:00
Michael Schuster
db91552578 Add a 'Content-Length: 0' header to initial POST requests
The webserver lighttpd rejected POST requests without a Content-length
header with "411 Length Required".

See: https://github.com/nextcloud/desktop/issues/1473

Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-10 06:09:59 +00:00
Camila San
286e45bafe Bump version to 2.6.0
Signed-off-by: Camila San <hello@camila.codes>
(cherry picked from commit e0b32c19e4)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-05 15:13:59 +02:00
Michael Schuster
aa1bb470e6 fix comment typo
Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 905c1532fe)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-05 14:56:48 +02:00
Michael Schuster
3be9adde4b Fix double slashes in WebDAV URLs (account setup wizard)
Sanitize URL paths to elaminate double-slashes in the URL path string,
used for the first connection by the account setup wizard.

Example: https://cloud.example.com/remote.php/webdav//

Signed-off-by: Michael Schuster <michael@schuster.ms>
(cherry picked from commit 67107a4f5d)
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-10-05 14:56:15 +02:00
István Váradi
41d97abd08 Merge pull request #1475 from ivaradi/stable-2.6
Remove kdelibs5-dev from the build dependencies for Eoan
2019-10-05 09:33:00 +02:00
István Váradi
6bc232c9b4 Remove kdelibs5-dev from the build dependencies for Eoan
Signed-off-by: István Váradi <ivaradi@varadiistvan.hu>
2019-10-05 09:31:55 +02:00
István Váradi
d4a0be92ae Merge pull request #1466 from ivaradi/stable-2.6.0
Trigger builds for tagging on the 2.6.0 branch
2019-10-04 20:19:38 +02:00
István Váradi
75bf41fba1 Trigger builds for tagging on the 2.6.0 branch
Signed-off-by: István Váradi <ivaradi@varadiistvan.hu>
2019-10-02 19:18:13 +02:00
Camila San
a2bfd5039c Revert "Fix White Window issue on Windows after Qt 5.12.4 upgrade"
This reverts commit aeba2e4de6.
2019-09-27 15:04:14 +02:00
Camila San
a9ee7472b9 Improve wording of the context menu in the file manager extension.
'Share...' -> 'Share options'
'private link' -> 'internal link'
Removes 'to clipboard' from 'copy link' options.

Signed-off-by: Camila San <hello@camila.codes>
2019-09-26 13:24:10 +02:00
Michael Schuster
211d6cb162 UI improvement: Message box: Delete / Keep all files
Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-09-26 12:05:34 +02:00
Mariusz Wasak
501c353291 Fix for #1382 "linux client crashes for no discernable reason"
There in no "return" in
PropagateUploadFileCommon::slotStartUpload in if (prevModtime != _item-
>_modtime) {... }

There is possibility that
PropagateItemJob::done(status, errorString)
maybe called two times from PropagateUploadFileCommon::slotStartUpload
1. in if (prevModtime != _item->_modtime) {... }
2. in if (fileIsStillChanging(*_item)) {..}
if changes in files are frequent the second call is possible.

This two calls has effect in PropagatorCompositeJob::slotSubJobFinished
and job is removed two times in _runningJobs.remove(i);
(the second time with argumetnt -1 (because first call removed job).

This return was removed in commit
efc039863b - by accident I think.

Good simulation is to synchronize firefox profile with frequent page
refresh.

Signed-off-by: Mariusz Wasak <mawasak@gmail.com>
2019-09-26 12:03:20 +02:00
Michael Schuster
aeba2e4de6 Fix White Window issue on Windows after Qt 5.12.4 upgrade
Qt 5.12.4 seems to introduce a new bug on Windows, causing the settings window
to not be redrawn when re-opening it, for example by clicking at the tray icon.

As a workaround this fix starts a 100 ms timer to be fired once upon
QDialog::showEvent is called.

Signed-off-by: Michael Schuster <michael@schuster.ms>
2019-09-26 11:29:49 +02:00
Camila Ayres
2f9f84c1f2 Merge pull request #1447 from nextcloud/backport/1438/stable-2.6
[stable-2.6] Changes wording in the share context menu.
2019-09-26 11:16:17 +02:00
Camila San
33646b1775 Changes wording in the share context menu.
Instead of only Nextcloud it says "Share via Nextcloud".

Signed-off-by: Camila San <hello@camila.codes>
2019-09-26 09:12:28 +00:00
249 changed files with 77588 additions and 58550 deletions

View File

@@ -237,13 +237,17 @@ name: qt-5.12
steps:
- name: build and test
image: nextcloudci/client-5.12:client-5.12-2
image: nextcloudci/client-5.12:client-5.12-5
commands:
# Install QtKeyChain
- /bin/bash -c "
export CC=gcc-7 &&
export CXX=g++-7 &&
source /opt/qt512/bin/qt512-env.sh &&
export QT_BASE_DIR=/opt/qt5.12.5 &&
export QTDIR=\$QT_BASE_DIR &&
export PATH=\$QT_BASE_DIR/bin:\$PATH &&
export LD_LIBRARY_PATH=\$QT_BASE_DIR/lib/x86_64-linux-gnu:\$QT_BASE_DIR/lib:/usr/local/lib:\$LD_LIBRARY_PATH &&
export PKG_CONFIG_PATH=\$QT_BASE_DIR/lib/pkgconfig:\$PKG_CONFIG_PATH &&
cd /tmp &&
git clone https://github.com/frankosterfeld/qtkeychain.git &&
cd qtkeychain &&
@@ -257,7 +261,11 @@ steps:
- /bin/bash -c "
export CC=gcc-7 &&
export CXX=g++-7 &&
source /opt/qt512/bin/qt512-env.sh &&
export QT_BASE_DIR=/opt/qt5.12.5 &&
export QTDIR=\$QT_BASE_DIR &&
export PATH=\$QT_BASE_DIR/bin:\$PATH &&
export LD_LIBRARY_PATH=\$QT_BASE_DIR/lib/x86_64-linux-gnu:\$QT_BASE_DIR/lib:/usr/local/lib:\$LD_LIBRARY_PATH &&
export PKG_CONFIG_PATH=\$QT_BASE_DIR/lib/pkgconfig:\$PKG_CONFIG_PATH &&
mkdir build &&
cd build &&
cmake -D NO_SHIBBOLETH=1 -DCMAKE_BUILD_TYPE=Debug -DUNIT_TESTING=1 ../ &&
@@ -278,13 +286,17 @@ name: qt-5.12-clang
steps:
- name: build and test
image: nextcloudci/client-5.12:client-5.12-2
image: nextcloudci/client-5.12:client-5.12-5
commands:
# Install QtKeyChain
- /bin/bash -c "
export CC=clang-6.0 &&
export CXX=clang++-6.0 &&
source /opt/qt512/bin/qt512-env.sh &&
export QT_BASE_DIR=/opt/qt5.12.5 &&
export QTDIR=\$QT_BASE_DIR &&
export PATH=\$QT_BASE_DIR/bin:\$PATH &&
export LD_LIBRARY_PATH=\$QT_BASE_DIR/lib/x86_64-linux-gnu:\$QT_BASE_DIR/lib:/usr/local/lib:\$LD_LIBRARY_PATH &&
export PKG_CONFIG_PATH=\$QT_BASE_DIR/lib/pkgconfig:\$PKG_CONFIG_PATH &&
cd /tmp &&
git clone https://github.com/frankosterfeld/qtkeychain.git &&
cd qtkeychain &&
@@ -298,7 +310,11 @@ steps:
- /bin/bash -c "
export CC=clang-6.0 &&
export CXX=clang++-6.0 &&
source /opt/qt512/bin/qt512-env.sh &&
export QT_BASE_DIR=/opt/qt5.12.5 &&
export QTDIR=\$QT_BASE_DIR &&
export PATH=\$QT_BASE_DIR/bin:\$PATH &&
export LD_LIBRARY_PATH=\$QT_BASE_DIR/lib/x86_64-linux-gnu:\$QT_BASE_DIR/lib:/usr/local/lib:\$LD_LIBRARY_PATH &&
export PKG_CONFIG_PATH=\$QT_BASE_DIR/lib/pkgconfig:\$PKG_CONFIG_PATH &&
mkdir build &&
cd build &&
cmake -D NO_SHIBBOLETH=1 -DCMAKE_BUILD_TYPE=Debug -DUNIT_TESTING=1 ../ &&
@@ -319,9 +335,10 @@ name: AppImage
steps:
- name: build
image: nextcloudci/client-5.12:client-5.12-2
image: nextcloudci/client-5.12:client-5.12-5
commands:
- /bin/bash -c "./admin/linux/build-appimage.sh"
- /bin/bash -c "./admin/linux/upload-appimage.sh"
trigger:
branch:
- master
@@ -344,10 +361,9 @@ steps:
from_secret: DEBIAN_SECRET_IV
trigger:
branch:
- master
- stable-2.6
event:
- pull_request
- push
- tag
---
kind: pipeline
name: Documentation

3
.gitmodules vendored
View File

@@ -1,6 +1,3 @@
[submodule "src/3rdparty/qtmacgoodies"]
path = src/3rdparty/qtmacgoodies
url = https://github.com/camilasan/qtmacgoodies.git
[submodule "binary"]
path = binary
url = git://github.com/owncloud/owncloud-client-binary.git

View File

@@ -198,7 +198,7 @@ X-GNOME-Autostart-Delay=3
# Translations
Icon[cs_CZ]=@NAZEV_IKONY_APLIKACE@
Icon[cs_CZ]=@APPLICATION_ICON_NAME@
Name[cs_CZ]=@APPLICATION_NAME@ synchronizační klient pro desktop
Comment[cs_CZ]=@APPLICATION_NAME@ synchronizační klient pro desktop
GenericName[cs_CZ]=Synchronizace složek

View File

@@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_ICON_NAME@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Icon[cy_GB]=@APPLICATION_ICON_NAME@
Name[cy_GB]=@APPLICATION_NAME@ cleient cydweddu bwrdd gwaith
Comment[cy_GB]=@APPLICATION_NAME@ cleient cydweddu bwrdd gwaith
GenericName[cy_GB]=Cydweddu Ffolder

View File

@@ -198,7 +198,7 @@ X-GNOME-Autostart-Delay=3
# Translations
Icon[de]=@APPLICATION_ICON_NAME@
Name[de]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
Comment[de]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
GenericName[de]=Synchronisationsordner
Icon[de_DE]=@APPLICATION_ICON_NAME@
Name[de_DE]=@APPLICATION_NAME@ Client zur Desktop-Synchronisierung
Comment[de_DE]=@APPLICATION_NAME@ Client zur Desktop-Synchronisierung
GenericName[de_DE]=Synchronisierungsordner

View File

@@ -198,4 +198,7 @@ X-GNOME-Autostart-Delay=3
# Translations
Icon[el]=@APPLICATION_ICON_NAME@
Name[el]=@APPLICATION_NAME@ πρόγραμμα συγχρονισμού
Comment[el]=@APPLICATION_NAME@ πρόγραμμα συγχρονισμού
GenericName[el]=Συγχρονισμός φακέλου

View File

@@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_ICON_NAME@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Icon[es_AR]=@APPLICATION_ICON_NAME@
Name[es_AR]=@APPLICATION_NAME@ cliente de sincronización de escritorio
Comment[es_AR]=@APPLICATION_NAME@ cliente de sincronización de escritorio
GenericName[es_AR]=Sincronización de carpetas

View File

@@ -0,0 +1,201 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_ICON_NAME@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Comment[fa]=@ APPLICATION_NAME @ مشتری هماهنگ سازی دسکتاپ

View File

@@ -201,4 +201,4 @@ X-GNOME-Autostart-Delay=3
Icon[ro]=@APPLICATION_ICON_NAME@
Name[ro]=@APPLICATION_NAME@ client de sincronizare pentru desktop
Comment[ro]=@APPLICATION_NAME@ client de sincronizare pentru desktop
GenericName[ro]=Sincronizare dosare
GenericName[ro]=Sincronizare director

View File

@@ -201,4 +201,4 @@ X-GNOME-Autostart-Delay=3
Icon[sk_SK]=@APPLICATION_ICON_NAME@
Name[sk_SK]=@APPLICATION_NAME@ synchronizačný klient pre PC
Comment[sk_SK]=@APPLICATION_NAME@ synchronizačný klient pre PC
GenericName[sk_SK]=Synchnonizácia priečinkov
GenericName[sk_SK]=Synchronizácia priečinkov

View File

@@ -199,6 +199,6 @@ X-GNOME-Autostart-Delay=3
# Translations
Icon[sl]=@APPLICATION_ICON_NAME@
Name[sl]=@APPLICATION_NAME@ odjemalec za usklajevanje
Comment[sl]=@APPLICATION_NAME@ odjemalec za usklajevanje
Name[sl]=@APPLICATION_NAME@ program za usklajevanje
Comment[sl]=@APPLICATION_NAME@ program za usklajevanje
GenericName[sl]=Usklajevanje map

View File

@@ -199,4 +199,6 @@ X-GNOME-Autostart-Delay=3
# Translations
Icon[sv]=@APPLICATION_ICON_NAME@
Name[sv]=@APPLICATION_NAME@ desktopssynkklient
Comment[sv]=@APPLICATION_NAME@ desktopssynkroniseringsklient
GenericName[sv]=Mappsynkronisering

View File

@@ -0,0 +1,204 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ desktop sync client
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_ICON_NAME@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
# Translations
Icon[sw]=@APPLICATION_ICON_NAME@
Name[sw]=Teja ya @APPLICATION_NAME@ ya kufanana faili kwa seva na faili ziko hapa
Comment[sw]=Teja ya @APPLICATION_NAME@ ya kufanana faili kwa seva na faili ziko hapa
GenericName[sw]=Fanana Kabrasha

View File

@@ -198,6 +198,7 @@ X-GNOME-Autostart-Delay=3
# Translations
Icon[zh_TW]=@APPLICATION_ICON_NAME@
Name[zh_TW]=@APPLICATION_NAME@ 桌面同步客戶端
Comment[zh_TW]=@APPLICATION_NAME@ 桌面同步客戶端
GenericName[zh_TW]=資料夾同步

View File

@@ -203,8 +203,16 @@ if( WIN32 )
add_definitions( -D__USE_MINGW_ANSI_STDIO=1 )
add_definitions( -DNOMINMAX )
# Get APIs from from Vista onwards.
add_definitions( -D_WIN32_WINNT=0x0600)
add_definitions( -DWINVER=0x0600)
add_definitions( -D_WIN32_WINNT=0x0601 )
add_definitions( -DWINVER=0x0601 )
if( MSVC )
# Use automatic overload for suitable CRT safe-functions
# See https://docs.microsoft.com/de-de/cpp/c-runtime-library/security-features-in-the-crt?view=vs-2019
add_definitions( -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1 )
# Also: Disable compiler warnings because we don't use Windows CRT safe-functions explicitly and don't intend to
# as this is a pure cross-platform source the only alternative would be a ton of ifdefs with calls to the _s version
add_definitions( -D_CRT_SECURE_NO_WARNINGS )
endif( MSVC )
endif( WIN32 )
if (APPLE)

View File

@@ -1,7 +1,7 @@
set( MIRALL_VERSION_MAJOR 2 )
set( MIRALL_VERSION_MINOR 5 )
set( MIRALL_VERSION_PATCH 3 )
set( MIRALL_VERSION_YEAR 2019 )
set( MIRALL_VERSION_MINOR 6 )
set( MIRALL_VERSION_PATCH 4 )
set( MIRALL_VERSION_YEAR 2020 )
set( MIRALL_SOVERSION 0 )
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )

View File

@@ -14,6 +14,7 @@ RUN apt-get update -q && DEBIAN_FRONTEND=noninteractive apt-get install -q -y --
libsqlite3-dev \
libssl-dev \
libcmocka-dev \
libcloudproviders-dev \
qt5-default \
qttools5-dev-tools \
libqt5webkit5-dev \

View File

@@ -6,7 +6,7 @@ mkdir /app
mkdir /build
#Set Qt-5.12
export QT_BASE_DIR=/opt/qt512
export QT_BASE_DIR=/opt/qt5.12.5
export QTDIR=$QT_BASE_DIR
export PATH=$QT_BASE_DIR/bin:$PATH
export LD_LIBRARY_PATH=$QT_BASE_DIR/lib/x86_64-linux-gnu:$QT_BASE_DIR/lib:$LD_LIBRARY_PATH
@@ -18,11 +18,11 @@ if [ $SUFFIX != "master" ]; then
SUFFIX="PR-$SUFFIX"
fi
#QtKeyChain 0.9.1
#QtKeyChain master
cd /build
git clone https://github.com/frankosterfeld/qtkeychain.git
cd qtkeychain
git checkout v0.9.1
git checkout master
mkdir build
cd build
cmake -D CMAKE_INSTALL_PREFIX=/usr ../
@@ -66,7 +66,8 @@ rm -rf ./usr/share/nemo-python/
mv ./etc/Nextcloud/sync-exclude.lst ./usr/bin/
rm -rf ./etc
sed -i -e 's|Icon=nextcloud|Icon=Nextcloud|g' usr/share/applications/nextcloud.desktop # Bug in desktop file?
DESKTOP_FILE=/app/usr/share/applications/${LINUX_APPLICATION_ID}.desktop
sed -i -e 's|Icon=nextcloud|Icon=Nextcloud|g' ${DESKTOP_FILE} # Bug in desktop file?
cp ./usr/share/icons/hicolor/512x512/apps/Nextcloud.png . # Workaround for linuxeployqt bug, FIXME
@@ -87,17 +88,12 @@ chmod a+x linuxdeployqt*.AppImage
rm ./linuxdeployqt-continuous-x86_64.AppImage
unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/app/usr/lib/
./squashfs-root/AppRun /app/usr/share/applications/nextcloud.desktop -bundle-non-qt-libs
./squashfs-root/AppRun ${DESKTOP_FILE} -bundle-non-qt-libs
# Set origin
./squashfs-root/usr/bin/patchelf --set-rpath '$ORIGIN/' /app/usr/lib/libnextcloudsync.so.0
# Build AppImage
./squashfs-root/AppRun /app/usr/share/applications/nextcloud.desktop -appimage
./squashfs-root/AppRun ${DESKTOP_FILE} -appimage
mv Nextcloud*.AppImage Nextcloud-${SUFFIX}-${DRONE_COMMIT}-x86_64.AppImage
curl --upload-file $(readlink -f ./Nextcloud*.AppImage) https://transfer.sh/Nextcloud-${SUFFIX}-${DRONE_COMMIT}-x86_64.AppImage
echo
echo "Get the AppImage at the link above!"

View File

@@ -7,9 +7,10 @@ Build-Depends: cmake,
cdbs,
dh-python,
extra-cmake-modules (>= 5.16),
kdelibs5-dev,
libkf5kio-dev,
libcmocka-dev,
libcloudproviders-dev,
libdbus-1-dev,
libhttp-dav-perl,
libinotify-dev [kfreebsd-any],
libqt5svg5-dev,

View File

@@ -0,0 +1,48 @@
nextcloud-client (2.3.3-1.0~oldstable1) oldstable; urgency=medium
* Debian build support for the forked client.
-- István Váradi <ivaradi@varadiistvan.hu> Mon, 6 Nov 2017 20:20:04 +0100
nextcloud-client (2.3.1-1.0) oldstable; urgency=medium
* New upstream version
-- István Váradi <ivaradi@varadiistvan.hu> Thu, 23 Mar 2017 19:07:36 +0100
nextcloud-client (2.3.0-1.0) oldstable; urgency=medium
* New upstream version
-- István Váradi <ivaradi@varadiistvan.hu> Tue, 21 Mar 2017 19:34:13 +0100
nextcloud-client (2.2.4-1.4) oldstable; urgency=medium
* The locale-specific icon names are correct too
-- István Váradi <ivaradi@varadiistvan.hu> Tue, 7 Feb 2017 19:55:40 +0100
nextcloud-client (2.2.4-1.3) oldstable; urgency=medium
* Caja syncstate plugin is built.
* The syncstate plugin has application-specific name
-- István Váradi <ivaradi@varadiistvan.hu> Fri, 27 Jan 2017 19:34:18 +0100
nextcloud-client (2.2.4-1.2) oldstable; urgency=medium
* Fixed appname in the Nemo syncstate extension.
-- István Váradi <ivaradi@varadiistvan.hu> Thu, 19 Jan 2017 16:46:50 +0100
nextcloud-client (2.2.4-1.1) oldstable; urgency=medium
* Added Nautilus and Nemo syncstate extensions.
-- István Váradi <ivaradi@varadiistvan.hu> Tue, 17 Jan 2017 19:55:32 +0100
nextcloud-client (2.2.4-1.0) oldstable; urgency=medium
* Initial release.
-- István Váradi <ivaradi@varadiistvan.hu> Wed, 14 Dec 2016 20:07:46 +0100

View File

@@ -0,0 +1,84 @@
Source: nextcloud-client
Section: contrib/devel
Priority: optional
Maintainer: István Váradi <ivaradi@varadiistvan.hu>
Build-Depends: cmake,
debhelper,
cdbs,
dh-python,
extra-cmake-modules (>= 5.16),
kdelibs5-dev,
kio-dev,
libcmocka-dev,
libdbus-1-dev,
libhttp-dav-perl,
libinotify-dev [kfreebsd-any],
libqt5webkit5-dev,
libqt5svg5-dev,
libsqlite3-dev,
libssl-dev (>= 1.1.0),
zlib1g-dev,
optipng,
pkg-kde-tools,
python-sphinx | python3-sphinx,
python3-all,
qt5keychain-dev,
qtwebengine5-dev,
qtdeclarative5-dev,
qttools5-dev,
qttools5-dev-tools,
xvfb
Standards-Version: 3.9.8
Homepage: https://github.com/nextcloud/client_theming
#Vcs-Git: git://anonscm.debian.org/collab-maint/nextcloud-client.git
#Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/nextcloud-client.git
Package: nextcloud-client
Architecture: any
Depends: libnextcloudsync0 (=${binary:Version}), ${shlibs:Depends}, ${misc:Depends}, nextcloud-client-l10n
Recommends: libgnome-keyring0
Description: Nextcloud desktop sync client
Use the desktop client to keep your files synchronized
between your Nextcloud server and your desktop. Select
one or more directories on your local machine and always
have access to your latest files wherever you are.
Package: libnextcloudsync0
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Nextcloud sync library
Used by the Nextcloud desktop client as the synchronization engine.
Package: libnextcloudsync-dev
Architecture: any
Section: contrib/libdevel
Depends: libnextcloudsync0 (=${binary:Version}), ${misc:Depends}
Description: Nextcloud sync library development files
The headers and development library for the Nextcloud sync library.
Package: nextcloud-client-l10n
Architecture: all
Depends: ${misc:Depends}
Description: Nextcloud client internatialization files
The translation files.
Package: nextcloud-client-nautilus
Architecture: all
Depends: nextcloud-client (>=${binary:Version}), libnextcloudsync0, python-nautilus, nautilus, ${misc:Depends}
Description: Nautilus plugin for Nextcloud
This package contains a Nautilus plugin to display
synchronization status icons for Nextcloud files.
Package: nextcloud-client-nemo
Architecture: all
Depends: nextcloud-client (>=${binary:Version}), libnextcloudsync0, python-nemo, nemo, ${misc:Depends}
Description: Nemo plugin for Nextcloud
This package contains a Nemo plugin to display
synchronization status icons for Nextcloud files.
Package: nextcloud-client-caja
Architecture: all
Depends: nextcloud-client (>=${binary:Version}), libnextcloudsync0, python-caja, caja, ${misc:Depends}
Description: Caja plugin for Nextcloud
This package contains a Caja plugin to display
synchronization status icons for Nextcloud files.

View File

@@ -9,7 +9,10 @@ Build-Depends: cmake,
extra-cmake-modules (>= 5.16),
kdelibs5-dev,
kio-dev,
libavcodec58,
libcmocka-dev,
libcloudproviders-dev,
libdbus-1-dev,
libhttp-dav-perl,
libinotify-dev [kfreebsd-any],
libqt5webkit5-dev,

View File

@@ -0,0 +1,4 @@
usr/bin
usr/share/applications
usr/share/icons
debian/101-sync-inotify.conf etc/sysctl.d

View File

@@ -10,6 +10,8 @@ Build-Depends: cmake,
kdelibs5-dev,
libkf5kio-dev,
libcmocka-dev,
libcloudproviders-dev,
libdbus-1-dev,
libhttp-dav-perl,
libinotify-dev [kfreebsd-any],
libqt5svg5-dev,

View File

@@ -1,4 +1,6 @@
usr/bin
usr/share/applications
usr/share/cloud-providers/
usr/share/dbus-1/services/
usr/share/icons
debian/101-sync-inotify.conf etc/sysctl.d

View File

@@ -51,7 +51,7 @@ if ! wget http://ppa.launchpad.net/${repo}/ubuntu/pool/main/n/nextcloud-client/n
origsourceopt="-sa"
fi
for distribution in xenial bionic disco eoan stable; do
for distribution in xenial bionic disco eoan stable oldstable; do
rm -rf nextcloud-client_${basever}
cp -a ${DRONE_WORKSPACE} nextcloud-client_${basever}
@@ -98,26 +98,46 @@ if test "${pull_request}" = "master"; then
PPA=$PPA_BETA
OBS_PROJECT=$OBS_PROJECT_BETA
fi
OBS_SUBDIR="${OBS_PROJECT}/${OBS_PACKAGE}"
if test -f ~/.has_ppa_keys; then
for changes in nextcloud-client_*~+([a-z])1_source.changes; do
dput $PPA $changes > /dev/null
case "${changes}" in
*oldstable1*)
;;
*)
dput $PPA $changes > /dev/null
;;
esac
done
mkdir osc
cd osc
osc co ${OBS_PROJECT} ${OBS_PACKAGE}
if test "$(ls ${OBS_SUBDIR})"; then
osc delete ${OBS_SUBDIR}/*
fi
cp ../nextcloud-client*.orig.tar.* ${OBS_SUBDIR}/
cp ../nextcloud-client_*[0-9.][0-9].dsc ${OBS_SUBDIR}/
cp ../nextcloud-client_*[0-9.][0-9].debian.tar* ${OBS_SUBDIR}/
cp ../nextcloud-client_*[0-9.][0-9]_source.changes ${OBS_SUBDIR}/
osc add ${OBS_SUBDIR}/*
for distribution in stable oldstable; do
if test "${distribution}" = "oldstable"; then
pkgsuffix=".${distribution}"
pkgvertag="~${distribution}1"
else
pkgsuffix=""
pkgvertag=""
fi
cd ${OBS_SUBDIR}
osc commit -m "Travis update"
package="${OBS_PACKAGE}${pkgsuffix}"
OBS_SUBDIR="${OBS_PROJECT}/${package}"
mkdir -p osc
pushd osc
osc co ${OBS_PROJECT} ${package}
if test "$(ls ${OBS_SUBDIR})"; then
osc delete ${OBS_SUBDIR}/*
fi
cp ../nextcloud-client*.orig.tar.* ${OBS_SUBDIR}/
cp ../nextcloud-client_*[0-9.][0-9]${pkgvertag}.dsc ${OBS_SUBDIR}/
cp ../nextcloud-client_*[0-9.][0-9]${pkgvertag}.debian.tar* ${OBS_SUBDIR}/
cp ../nextcloud-client_*[0-9.][0-9]${pkgvertag}_source.changes ${OBS_SUBDIR}/
osc add ${OBS_SUBDIR}/*
cd ${OBS_SUBDIR}
osc commit -m "Travis update"
popd
done
fi
fi

21
admin/linux/upload-appimage.sh Executable file
View File

@@ -0,0 +1,21 @@
#! /bin/bash
set -xe
cd /build
# Upload AppImage
APPIMAGE=$(readlink -f ./Nextcloud*.AppImage)
BASENAME=$(basename ${APPIMAGE})
if curl --max-time 900 --upload-file ${APPIMAGE} https://transfer.sh/${BASENAME}
then
echo
echo "Get the AppImage at the link above!"
else
echo
echo "Upload failed, however this is an optional step."
fi
# Don't let the Drone build fail
exit 0

View File

@@ -49,7 +49,7 @@ fi
if [ ! -z "$identity" ]; then
echo "Will try to sign the installer"
pushd $install_path
productsign --sign "$identity" "$installer_file" "$installer_file.new"
productsign --timestamp --sign "$identity" "$installer_file" "$installer_file.new"
mv "$installer_file".new "$installer_file"
popd
else

View File

@@ -32,11 +32,12 @@ FRAMEWORK_SEARCH_PATH=[
os.path.join(os.environ['HOME'], 'Library/Frameworks')
]
LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/Qt-5.6.2/lib', '.']
LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/Qt-5.12.5/lib', '.']
QT_PLUGINS = [
'sqldrivers/libqsqlite.dylib',
'platforms/libqcocoa.dylib',
'styles/libqmacstyle.dylib',
'imageformats/libqgif.dylib',
'imageformats/libqico.dylib',
'imageformats/libqjpeg.dylib',
@@ -46,7 +47,7 @@ QT_PLUGINS = [
QT_PLUGINS_SEARCH_PATH=[
# os.path.join(os.environ['QTDIR'], 'plugins'),
# '/usr/local/Cellar/qt/5.2.1/plugins',
'/usr/local/Qt-5.6.2/plugins',
'/usr/local/Qt-5.12.5/plugins',
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

After

Width:  |  Height:  |  Size: 151 KiB

2
binary

Submodule binary updated: 3425fab2c6...09f12de312

View File

@@ -27,7 +27,7 @@
<key>CFBundleShortVersionString</key>
<string>@MIRALL_VERSION_STRING@</string>
<key>NSHumanReadableCopyright</key>
<string>(C) 2014-2018 @APPLICATION_VENDOR@</string>
<string>(C) 2014-2020 @APPLICATION_VENDOR@</string>
<key>NSSupportsAutomaticGraphicsSwitching</key>
<true/>
<key>SUShowReleaseNotes</key>

View File

@@ -3,7 +3,11 @@
# For details see the accompanying COPYING* file.
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long -Wno-gnu-zero-variadic-macro-arguments")
# Use this only for Clang
if (CMAKE_CXX_COMPILER MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long -Wno-gnu-zero-variadic-macro-arguments")
endif()
# Fix sqlite compilation on macOS
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-incompatible-pointer-types-discards-qualifiers")

View File

@@ -87,7 +87,7 @@ To prevent automatic updates and disallow manual overrides:
1. Edit this Registry key:
``HKEY_LOCAL_MACHINE\Software\Policies\Nextcloud\Nextcloud``
``HKEY_LOCAL_MACHINE\Software\Policies\Nextcloud GmbH\Nextcloud``
2. Add the key ``skipUpdateCheck`` (of type DWORD).

View File

@@ -27,7 +27,7 @@ download page.
System Requirements
----------------------------------
- Windows 7+
- Windows 8.1+
- macOS 10.7+ (**64-bit only**)
- CentOS 6 & 7 (64-bit only)
- Debian 8.0 & 9.0
@@ -36,8 +36,7 @@ System Requirements
- openSUSE Leap 42.2 & 42.3
.. note::
For Linux distributions, we support, if technically feasible, the latest 2 versions per platform and the previous `LTS`_.
>>>>>>> b2da03441... update supported linux platforms
For Linux distributions, we support, if technically feasible, the latest 2 versions per platform and the previous LTS.
Installation Wizard
-------------------

View File

@@ -467,6 +467,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = FinderSyncExt/FinderSyncExt.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";

View File

@@ -35,11 +35,11 @@ public:
QString contextMenuTitle() const
{
return _strings.value("CONTEXT_MENU_TITLE", "ownCloud");
return _strings.value("CONTEXT_MENU_TITLE", "Nextcloud");
}
QString shareActionTitle() const
{
return _strings.value("SHARE_MENU_TITLE", "Share...");
return _strings.value("SHARE_MENU_TITLE", "Share");
}
QString copyPrivateLinkTitle() const { return _strings["COPY_PRIVATE_LINK_MENU_TITLE"]; }

View File

@@ -1,4 +1,4 @@
[D-BUS Service]
Name=@LIBCLOUDPROVIDERS_DBUS_BUS_NAME@
Exec=@APPLICATION_EXECUTABLE@
Exec=@APPLICATION_EXECUTABLE@ --background

View File

@@ -89,7 +89,7 @@ IFACEMETHODIMP OCContextMenu::Initialize(
HDROP hDrop = static_cast<HDROP>(GlobalLock(stm.hGlobal));
if (hDrop) {
UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
for (int i = 0; i < nFiles; ++i) {
for (UINT i = 0; i < nFiles; ++i) {
// Get the path of the file.
wchar_t buffer[MAX_PATH];
@@ -182,20 +182,38 @@ IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
{
std::wstring command;
CMINVOKECOMMANDINFOEX *piciEx = nullptr;
if (pici->cbSize == sizeof(CMINVOKECOMMANDINFOEX))
piciEx = (CMINVOKECOMMANDINFOEX*)pici;
// For the Unicode case, if the high-order word is not zero, the
// command's verb string is in lpcmi->lpVerbW.
if (HIWORD(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW))
{
command = ((CMINVOKECOMMANDINFOEX *)pici)->lpVerbW;
} else {
if (piciEx
&& (piciEx->fMask & CMIC_MASK_UNICODE)
&& HIWORD(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW)) {
command = piciEx->lpVerbW;
// Verify that we handle the verb
bool handled = false;
for (auto &item : m_info.menuItems) {
if (item.command == command) {
handled = true;
break;
}
}
if (!handled)
return E_FAIL;
} else if (IS_INTRESOURCE(pici->lpVerb)) {
// If the command cannot be identified through the verb string, then
// check the identifier offset.
auto offset = LOWORD(pici->lpVerb);
if (offset >= m_info.menuItems.size())
return E_FAIL;
command = m_info.menuItems[offset].command;
} else {
return E_FAIL;
}
OCClientInterface::SendRequest(command.data(), m_selectedFiles);

View File

@@ -5,6 +5,8 @@
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#define WINVER 0x0501
#define _WIN32_WINNT 0x0501
// Note: Here was a #define for windows target version
// e.g. WINVER / _WIN32_WINNT, see https://devblogs.microsoft.com/oldnewthing/20070411-00/?p=27283
// Unnecessary because we define both in desktop/CMakeLists.txt
#include <SDKDDKVer.h>

View File

@@ -13,8 +13,10 @@
*/
#define WIN32_LEAN_AND_MEAN
#define WINVER 0x0501
#define _WIN32_WINNT 0x0501
// Note: Here was a #define for windows target version
// e.g. WINVER / _WIN32_WINNT, see https://devblogs.microsoft.com/oldnewthing/20070411-00/?p=27283
// Unnecessary because we define both in desktop/CMakeLists.txt
#include "CommunicationSocket.h"
#include "RegistryUtil.h"

View File

@@ -1,7 +1,9 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#define WINVER 0x0501
#define _WIN32_WINNT 0x0501
// Note: Here was a #define for windows target version
// e.g. WINVER / _WIN32_WINNT, see https://devblogs.microsoft.com/oldnewthing/20070411-00/?p=27283
// Unnecessary because we define both in desktop/CMakeLists.txt
#include <windows.h>

View File

@@ -29,12 +29,17 @@ if(NOT MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_FORTIFY_SOURCE=2")
endif()
# Calling Qt's qCWarning(category, ...) with no params for "..." is a GNU
# extension (C++11 §16.3/4 forbids them). Silence clang's warnings.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-gnu-zero-variadic-macro-arguments")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-gnu-zero-variadic-macro-arguments")
endif()
if(WIN32)
# Enable DEP & ASLR
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--nxcompat -Wl,--dynamicbase")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--nxcompat -Wl,--dynamicbase")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /nxcompat /dynamicbase")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /nxcompat /dynamicbase")
elseif(UNIX AND NOT APPLE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now")

View File

@@ -11,43 +11,50 @@
// For overloading macros by argument count
// See stackoverflow.com/questions/16683146/can-macros-be-overloaded-by-number-of-arguments
#define OC_ASSERT_CAT(A, B) A##B
#define OC_ASSERT_SELECT(NAME, NUM) OC_ASSERT_CAT(NAME##_, NUM)
#define OC_ASSERT_GET_COUNT(_1, _2, _3, COUNT, ...) COUNT
#define OC_ASSERT_VA_SIZE(...) OC_ASSERT_GET_COUNT(__VA_ARGS__, 3, 2, 1, 0)
// Bugfix 08/09/2019: Broken arg expansion led to always collapsing to 1 arg (XXXX_1 overload result)
// See also: https://stackoverflow.com/questions/9183993/msvc-variadic-macro-expansion
#define OC_ASSERT_GLUE(x, y) x y
#define OC_ASSERT_OVERLOAD(NAME, ...) OC_ASSERT_SELECT(NAME, OC_ASSERT_VA_SIZE(__VA_ARGS__)) \
(__VA_ARGS__)
#define OC_ASSERT_GET_COUNT(_1, _2, _3, COUNT, ...) COUNT
#define OC_ASSERT_EXPAND_ARGS(args) OC_ASSERT_GET_COUNT args
#define OC_ASSERT_VA_SIZE(...) OC_ASSERT_EXPAND_ARGS((__VA_ARGS__, 3, 2, 1, 0))
#define OC_ASSERT_SELECT2(NAME, COUNT) NAME##COUNT
#define OC_ASSERT_SELECT1(NAME, COUNT) OC_ASSERT_SELECT2(NAME, COUNT)
#define OC_ASSERT_SELECT(NAME, COUNT) OC_ASSERT_SELECT1(NAME, COUNT)
#define OC_ASSERT_OVERLOAD(NAME, ...) OC_ASSERT_GLUE(OC_ASSERT_SELECT(NAME, OC_ASSERT_VA_SIZE(__VA_ARGS__)), \
(__VA_ARGS__))
// Default assert: If the condition is false in debug builds, terminate.
//
// Prints a message on failure, even in release builds.
#define ASSERT(...) OC_ASSERT_OVERLOAD(ASSERT, __VA_ARGS__)
#define ASSERT_1(cond) \
#define ASSERT1(cond) \
if (!(cond)) { \
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
} else { \
}
#define ASSERT_2(cond, message) \
#define ASSERT2(cond, message) \
if (!(cond)) { \
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
} else { \
}
#define ASSERT(...) OC_ASSERT_OVERLOAD(ASSERT, __VA_ARGS__)
// Enforce condition to be true, even in release builds.
//
// Prints 'message' and aborts execution if 'cond' is false.
#define ENFORCE(...) OC_ASSERT_OVERLOAD(ENFORCE, __VA_ARGS__)
#define ENFORCE_1(cond) \
#define ENFORCE1(cond) \
if (!(cond)) { \
qFatal("ENFORCE: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
} else { \
}
#define ENFORCE_2(cond, message) \
#define ENFORCE2(cond, message) \
if (!(cond)) { \
qFatal("ENFORCE: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
} else { \
}
#define ENFORCE(...) OC_ASSERT_OVERLOAD(ENFORCE, __VA_ARGS__)
// An assert that is only present in debug builds: typically used for
// asserts that are too expensive for release mode.

View File

@@ -207,7 +207,10 @@ static inline uint64_t c_jhash64(const uint8_t *k, uint64_t length, uint64_t int
/* handle the last 23 bytes */
c += length;
switch(len) {
// pragma only for GCC (and clang continues to pretend to be it by defining __GNUC__)
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif
case 23: c+=((uint64_t)k[22]<<56);
case 22: c+=((uint64_t)k[21]<<48);
case 21: c+=((uint64_t)k[20]<<40);

View File

@@ -281,8 +281,8 @@ int SqlQuery::prepare(const QByteArray &sql, bool allow_failure)
*/
static bool startsWithInsensitive(const QByteArray &a, const char *b)
{
int len = strlen(b);
return a.size() >= len && qstrnicmp(a.constData(), b, len) == 0;
size_t len = strlen(b);
return a.size() >= len && qstrnicmp(a.constData(), b, Utility::convertSizeToUint(len)) == 0;
}
bool SqlQuery::isSelect()

View File

@@ -103,6 +103,7 @@ public:
: _chunk(0)
, _transferid(0)
, _size(0)
, _modtime(0)
, _errorCount(0)
, _valid(false)
{

View File

@@ -396,6 +396,26 @@ void Utility::crash()
*a = 1;
}
// Use this functions to retrieve uint/int (often required by Qt and WIN32) from size_t
// without compiler warnings about possible truncation
uint Utility::convertSizeToUint(size_t &convertVar)
{
if( convertVar > UINT_MAX ) {
//throw std::bad_cast();
convertVar = UINT_MAX; // intentionally default to wrong value here to not crash: exception handling TBD
}
return static_cast<uint>(convertVar);
}
uint Utility::convertSizeToInt(size_t &convertVar)
{
if( convertVar > INT_MAX ) {
//throw std::bad_cast();
convertVar = INT_MAX; // intentionally default to wrong value here to not crash: exception handling TBD
}
return static_cast<int>(convertVar);
}
// read the output of the owncloud --version command from the owncloud
// version that is on disk. This works for most versions of the client,
// because clients that do not yet know the --version flag return the

View File

@@ -55,6 +55,12 @@ namespace Utility {
OCSYNC_EXPORT QByteArray userAgentString();
OCSYNC_EXPORT bool hasLaunchOnStartup(const QString &appName);
OCSYNC_EXPORT void setLaunchOnStartup(const QString &appName, const QString &guiName, bool launch);
OCSYNC_EXPORT uint convertSizeToUint(size_t &convertVar);
OCSYNC_EXPORT uint convertSizeToInt(size_t &convertVar);
#ifdef Q_OS_WIN
OCSYNC_EXPORT DWORD convertSizeToDWORD(size_t &convertVar);
#endif
/**
* Return the amount of free space available.

View File

@@ -90,32 +90,13 @@ void setLaunchOnStartup_private(const QString &appName, const QString &guiName,
// TODO: Right now only detection on toggle/startup, not when windows theme is switched while nextcloud is running
static inline bool hasDarkSystray_private()
{
bool hasDarkSystray = true;
// Open registry key first, continue only on success (may be legitimately absent in earlier windows versions)
HKEY hKey;
LONG lRes = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_READ, &hKey);
// classical windows function - preserve buff size for DWORD, call ExW version, store regkey value in nResult
if (lRes == ERROR_SUCCESS) {
DWORD dwBufferSize(sizeof(DWORD));
DWORD nResult(0);
// https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexw
LONG nError = ::RegQueryValueExW(hKey,
L"SystemUsesLightTheme",
NULL,
NULL,
reinterpret_cast<LPBYTE>(&nResult),
&dwBufferSize);
// if RegQuery returned no error and light theme was found, change systray return value
if (nError == ERROR_SUCCESS && nResult == 1)
hasDarkSystray = false;
return hasDarkSystray;
} else {
// fallback to true if regkey could not be determined
return hasDarkSystray;
if(Utility::registryGetKeyValue( HKEY_CURRENT_USER,
"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
"SystemUsesLightTheme" ) == 1) {
return false;
}
else {
return true;
}
}
@@ -283,4 +264,13 @@ bool Utility::registryWalkSubKeys(HKEY hRootKey, const QString &subKey, const st
return retCode != ERROR_NO_MORE_ITEMS;
}
DWORD Utility::convertSizeToDWORD(size_t &convertVar)
{
if( convertVar > UINT_MAX ) {
//throw std::bad_cast();
convertVar = UINT_MAX; // intentionally default to wrong value here to not crash: exception handling TBD
}
return static_cast<DWORD>(convertVar);
}
} // namespace OCC

View File

@@ -73,7 +73,7 @@ static void csync_exclude_expand_escapes(QByteArray &input)
line[o++] = line[i];
}
}
input.resize(o);
input.resize(OCC::Utility::convertSizeToUint(o));
}
// See http://support.microsoft.com/kb/74496 and
@@ -288,7 +288,11 @@ void ExcludedFiles::addManualExclude(const QByteArray &expr)
void ExcludedFiles::addManualExclude(const QByteArray &expr, const QByteArray &basePath)
{
#if defined(Q_OS_WIN)
Q_ASSERT(basePath.size() >= 2 && basePath.at(1) == ':');
#else
Q_ASSERT(basePath.startsWith('/'));
#endif
Q_ASSERT(basePath.endsWith('/'));
auto key = basePath;
@@ -322,7 +326,11 @@ bool ExcludedFiles::loadExcludeFile(const QByteArray & basePath, const QString &
csync_exclude_expand_escapes(line);
_allExcludes[basePath].append(line);
}
prepare(basePath);
// nothing to prepare if the user decided to not exclude anything
if(_allExcludes.size())
prepare(basePath);
return true;
}
@@ -338,8 +346,8 @@ bool ExcludedFiles::reloadExcludeFiles()
_fullRegexDir.clear();
bool success = true;
for (auto basePath : _excludeFiles.keys()) {
for (auto file : _excludeFiles.value(basePath)) {
for (const auto& basePath : _excludeFiles.keys()) {
for (const auto& file : _excludeFiles.value(basePath)) {
success = loadExcludeFile(basePath, file);
}
}

View File

@@ -724,7 +724,8 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
if (ctx->current == LOCAL_REPLICA) {
ASSERT(dirent->path.startsWith(ctx->local.uri)); // path is relative to uri
// "len + 1" to include the slash in-between.
dirent->path = dirent->path.mid(strlen(ctx->local.uri) + 1);
size_t uriLength = strlen(ctx->local.uri);
dirent->path = dirent->path.mid(OCC::Utility::convertSizeToInt(uriLength) + 1);
}
previous_fs = ctx->current_fs;

View File

@@ -38,6 +38,7 @@
#include "c_alloc.h"
#include "c_string.h"
#include "common/filesystembase.h"
#include "common/utility.h"
/* Convert a locale String to UTF8 */
QByteArray c_utf8_from_locale(const mbchar_t *wstr)
@@ -52,10 +53,10 @@ QByteArray c_utf8_from_locale(const mbchar_t *wstr)
size_t len;
len = wcslen(wstr);
/* Call once to get the required size. */
size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, len, NULL, 0, NULL, NULL);
size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, OCC::Utility::convertSizeToInt(len), NULL, 0, NULL, NULL);
if (size_needed > 0) {
dst.resize(size_needed);
WideCharToMultiByte(CP_UTF8, 0, wstr, len, dst.data(), size_needed, NULL, NULL);
WideCharToMultiByte(CP_UTF8, 0, wstr, OCC::Utility::convertSizeToInt(len), dst.data(), size_needed, NULL, NULL);
}
return dst;
#else
@@ -95,7 +96,7 @@ mbchar_t* c_utf8_string_to_locale(const char *str)
int size_needed;
len = strlen(str);
size_needed = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
size_needed = MultiByteToWideChar(CP_UTF8, 0, str, OCC::Utility::convertSizeToInt(len), NULL, 0);
if (size_needed > 0) {
int size_char = (size_needed + 1) * sizeof(mbchar_t);
dst = (mbchar_t*)c_malloc(size_char);
@@ -114,7 +115,8 @@ mbchar_t* c_utf8_string_to_locale(const char *str)
return NULL;
} else {
#ifdef _WIN32
QByteArray unc_str = OCC::FileSystem::pathtoUNC(QByteArray::fromRawData(str, strlen(str)));
size_t strLength = strlen(str);
QByteArray unc_str = OCC::FileSystem::pathtoUNC(QByteArray::fromRawData(str, OCC::Utility::convertSizeToInt(strLength)));
mbchar_t *dst = c_utf8_string_to_locale(unc_str);
return dst;
#else

View File

@@ -57,7 +57,7 @@ csync_vio_handle_t *csync_vio_local_opendir(const char *name) {
handle = (dhandle_t*)c_malloc(sizeof(dhandle_t));
// the file wildcard has to be attached
int len_name = strlen(name);
size_t len_name = strlen(name);
if( len_name ) {
char *h = NULL;

View File

@@ -35,12 +35,11 @@ set(client_UI_SRCS
addcertificatedialog.ui
proxyauthdialog.ui
mnemonicdialog.ui
wizard/flow2authwidget.ui
wizard/owncloudadvancedsetuppage.ui
wizard/owncloudconnectionmethoddialog.ui
wizard/owncloudhttpcredspage.ui
wizard/owncloudoauthcredspage.ui
wizard/flow2authcredspage.ui
wizard/flow2authwidget.ui
wizard/owncloudsetupnocredspage.ui
wizard/owncloudwizardresultpage.ui
wizard/webview.ui
@@ -91,7 +90,7 @@ set(client_SRCS
syncrunfilelog.cpp
systray.cpp
thumbnailjob.cpp
quotainfo.cpp
userinfo.cpp
accountstate.cpp
addcertificatedialog.cpp
authenticationdialog.cpp
@@ -103,11 +102,14 @@ set(client_SRCS
servernotificationhandler.cpp
guiutility.cpp
elidedlabel.cpp
headerbanner.cpp
iconjob.cpp
remotewipe.cpp
creds/credentialsfactory.cpp
creds/httpcredentialsgui.cpp
creds/oauth.cpp
creds/flow2auth.cpp
creds/keychainchunk.cpp
creds/webflowcredentials.cpp
creds/webflowcredentialsdialog.cpp
wizard/postfixlineedit.cpp
@@ -144,8 +146,6 @@ set(updater_SRCS
IF( APPLE )
list(APPEND client_SRCS cocoainitializer_mac.mm)
list(APPEND client_SRCS settingsdialogmac.cpp)
list(REMOVE_ITEM client_SRCS settingsdialog.cpp)
list(APPEND client_SRCS socketapisocket_mac.mm)
list(APPEND client_SRCS systray.mm)
@@ -175,14 +175,6 @@ set(3rdparty_SRC
../3rdparty/kmessagewidget/kmessagewidget.cpp
)
if (APPLE)
list(APPEND 3rdparty_SRC
../3rdparty/qtmacgoodies/src/macpreferenceswindow.mm
../3rdparty/qtmacgoodies/src/macstandardicon.mm
../3rdparty/qtmacgoodies/src/macwindow.mm
)
endif()
if(NOT WIN32)
list(APPEND 3rdparty_SRC ../3rdparty/qtlockedfile/qtlockedfile_unix.cpp)
else()
@@ -338,7 +330,6 @@ ENDIF()
target_include_directories(${APPLICATION_EXECUTABLE} PRIVATE
${CMAKE_SOURCE_DIR}/src/3rdparty/QProgressIndicator
${CMAKE_SOURCE_DIR}/src/3rdparty/qtlockedfile
${CMAKE_SOURCE_DIR}/src/3rdparty/qtmacgoodies/src
${CMAKE_SOURCE_DIR}/src/3rdparty/qtsingleapplication
${CMAKE_SOURCE_DIR}/src/3rdparty/kmessagewidget
${CMAKE_CURRENT_BINARY_DIR}

View File

@@ -368,6 +368,7 @@ void AccountManager::shutdown()
_accounts.clear();
foreach (const auto &acc, accountsCopy) {
emit accountRemoved(acc.data());
emit removeAccountFolders(acc.data());
}
}

View File

@@ -70,7 +70,6 @@ public:
*/
void deleteAccount(AccountState *account);
/**
* Creates an account and sets up some basic handlers.
* Does *not* add the account to the account manager just yet.
@@ -104,6 +103,7 @@ public slots:
Q_SIGNALS:
void accountAdded(AccountState *account);
void accountRemoved(AccountState *account);
void removeAccountFolders(AccountState *account);
private:
AccountManager() {}

View File

@@ -26,7 +26,7 @@
#include "configfile.h"
#include "account.h"
#include "accountstate.h"
#include "quotainfo.h"
#include "userinfo.h"
#include "accountmanager.h"
#include "owncloudsetupwizard.h"
#include "creds/abstractcredentials.h"
@@ -57,10 +57,6 @@
#include "account.h"
#ifdef Q_OS_MAC
#include "settingsdialogmac.h"
#endif
namespace OCC {
Q_LOGGING_CATEGORY(lcAccountSettings, "nextcloud.gui.account.settings", QtInfoMsg)
@@ -113,13 +109,13 @@ protected:
AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
: QWidget(parent)
, ui(new Ui::AccountSettings)
, _ui(new Ui::AccountSettings)
, _wasDisabledBefore(false)
, _accountState(accountState)
, _quotaInfo(accountState)
, _userInfo(accountState, false, true)
, _menuShown(false)
{
ui->setupUi(this);
_ui->setupUi(this);
_model = new FolderStatusModel;
_model->setAccountState(_accountState);
@@ -127,35 +123,40 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
FolderStatusDelegate *delegate = new FolderStatusDelegate;
delegate->setParent(this);
ui->_folderList->header()->hide();
ui->_folderList->setItemDelegate(delegate);
ui->_folderList->setModel(_model);
// Connect styleChanged events to our widgets, so they can adapt (Dark-/Light-Mode switching)
connect(this, &AccountSettings::styleChanged, delegate, &FolderStatusDelegate::slotStyleChanged);
_ui->_folderList->header()->hide();
_ui->_folderList->setItemDelegate(delegate);
_ui->_folderList->setModel(_model);
#if defined(Q_OS_MAC)
ui->_folderList->setMinimumWidth(400);
_ui->_folderList->setMinimumWidth(400);
#else
ui->_folderList->setMinimumWidth(300);
_ui->_folderList->setMinimumWidth(300);
#endif
new ToolTipUpdater(ui->_folderList);
new ToolTipUpdater(_ui->_folderList);
auto mouseCursorChanger = new MouseCursorChanger(this);
mouseCursorChanger->folderList = ui->_folderList;
mouseCursorChanger->folderList = _ui->_folderList;
mouseCursorChanger->model = _model;
ui->_folderList->setMouseTracking(true);
ui->_folderList->setAttribute(Qt::WA_Hover, true);
ui->_folderList->installEventFilter(mouseCursorChanger);
_ui->_folderList->setMouseTracking(true);
_ui->_folderList->setAttribute(Qt::WA_Hover, true);
_ui->_folderList->installEventFilter(mouseCursorChanger);
createAccountToolbox();
connect(AccountManager::instance(), &AccountManager::accountAdded,
this, &AccountSettings::slotAccountAdded);
connect(ui->_folderList, &QWidget::customContextMenuRequested,
connect(this, &AccountSettings::removeAccountFolders,
AccountManager::instance(), &AccountManager::removeAccountFolders);
connect(_ui->_folderList, &QWidget::customContextMenuRequested,
this, &AccountSettings::slotCustomContextMenuRequested);
connect(ui->_folderList, &QAbstractItemView::clicked,
connect(_ui->_folderList, &QAbstractItemView::clicked,
this, &AccountSettings::slotFolderListClicked);
connect(ui->_folderList, &QTreeView::expanded, this, &AccountSettings::refreshSelectiveSyncStatus);
connect(ui->_folderList, &QTreeView::collapsed, this, &AccountSettings::refreshSelectiveSyncStatus);
connect(ui->selectiveSyncNotification, &QLabel::linkActivated,
connect(_ui->_folderList, &QTreeView::expanded, this, &AccountSettings::refreshSelectiveSyncStatus);
connect(_ui->_folderList, &QTreeView::collapsed, this, &AccountSettings::refreshSelectiveSyncStatus);
connect(_ui->selectiveSyncNotification, &QLabel::linkActivated,
this, &AccountSettings::slotLinkActivated);
connect(_model, &FolderStatusModel::suggestExpand, ui->_folderList, &QTreeView::expand);
connect(_model, &FolderStatusModel::suggestExpand, _ui->_folderList, &QTreeView::expand);
connect(_model, &FolderStatusModel::dirtyChanged, this, &AccountSettings::refreshSelectiveSyncStatus);
refreshSelectiveSyncStatus();
connect(_model, &QAbstractItemModel::rowsInserted,
@@ -172,25 +173,26 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
addAction(syncNowWithRemoteDiscovery);
connect(ui->selectiveSyncApply, &QAbstractButton::clicked, _model, &FolderStatusModel::slotApplySelectiveSync);
connect(ui->selectiveSyncCancel, &QAbstractButton::clicked, _model, &FolderStatusModel::resetFolders);
connect(ui->bigFolderApply, &QAbstractButton::clicked, _model, &FolderStatusModel::slotApplySelectiveSync);
connect(ui->bigFolderSyncAll, &QAbstractButton::clicked, _model, &FolderStatusModel::slotSyncAllPendingBigFolders);
connect(ui->bigFolderSyncNone, &QAbstractButton::clicked, _model, &FolderStatusModel::slotSyncNoPendingBigFolders);
connect(_ui->selectiveSyncApply, &QAbstractButton::clicked, _model, &FolderStatusModel::slotApplySelectiveSync);
connect(_ui->selectiveSyncCancel, &QAbstractButton::clicked, _model, &FolderStatusModel::resetFolders);
connect(_ui->bigFolderApply, &QAbstractButton::clicked, _model, &FolderStatusModel::slotApplySelectiveSync);
connect(_ui->bigFolderSyncAll, &QAbstractButton::clicked, _model, &FolderStatusModel::slotSyncAllPendingBigFolders);
connect(_ui->bigFolderSyncNone, &QAbstractButton::clicked, _model, &FolderStatusModel::slotSyncNoPendingBigFolders);
connect(FolderMan::instance(), &FolderMan::folderListChanged, _model, &FolderStatusModel::resetFolders);
connect(this, &AccountSettings::folderChanged, _model, &FolderStatusModel::resetFolders);
QColor color = palette().highlight().color();
ui->quotaProgressBar->setStyleSheet(QString::fromLatin1(progressBarStyleC).arg(color.name()));
// quotaProgressBar style now set in customizeStyle()
/*QColor color = palette().highlight().color();
_ui->quotaProgressBar->setStyleSheet(QString::fromLatin1(progressBarStyleC).arg(color.name()));*/
ui->connectLabel->setText(tr("No account configured."));
_ui->connectLabel->setText(tr("No account configured."));
connect(_accountState, &AccountState::stateChanged, this, &AccountSettings::slotAccountStateChanged);
slotAccountStateChanged();
connect(&_quotaInfo, &QuotaInfo::quotaUpdated,
connect(&_userInfo, &UserInfo::quotaUpdated,
this, &AccountSettings::slotUpdateQuota);
// Connect E2E stuff
@@ -202,8 +204,10 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
{
slotNewMnemonicGenerated();
} else {
ui->encryptionMessage->hide();
_ui->encryptionMessage->hide();
}
customizeStyle();
}
@@ -225,9 +229,9 @@ void AccountSettings::createAccountToolbox()
menu->addAction(action);
connect(action, &QAction::triggered, this, &AccountSettings::slotDeleteAccount);
ui->_accountToolbox->setText(tr("Account") + QLatin1Char(' '));
ui->_accountToolbox->setMenu(menu);
ui->_accountToolbox->setPopupMode(QToolButton::InstantPopup);
_ui->_accountToolbox->setText(tr("Account") + QLatin1Char(' '));
_ui->_accountToolbox->setMenu(menu);
_ui->_accountToolbox->setPopupMode(QToolButton::InstantPopup);
slotAccountAdded(_accountState);
}
@@ -235,14 +239,14 @@ void AccountSettings::createAccountToolbox()
void AccountSettings::slotNewMnemonicGenerated()
{
ui->encryptionMessage->setText(tr("This account supports end-to-end encryption"));
_ui->encryptionMessage->setText(tr("This account supports end-to-end encryption"));
QAction *mnemonic = new QAction(tr("Enable encryption"), this);
connect(mnemonic, &QAction::triggered, this, &AccountSettings::requesetMnemonic);
connect(mnemonic, &QAction::triggered, ui->encryptionMessage, &KMessageWidget::hide);
connect(mnemonic, &QAction::triggered, _ui->encryptionMessage, &KMessageWidget::hide);
ui->encryptionMessage->addAction(mnemonic);
ui->encryptionMessage->show();
_ui->encryptionMessage->addAction(mnemonic);
_ui->encryptionMessage->show();
}
void AccountSettings::slotMenuBeforeShow() {
@@ -250,7 +254,7 @@ void AccountSettings::slotMenuBeforeShow() {
return;
}
auto menu = ui->_accountToolbox->menu();
auto menu = _ui->_accountToolbox->menu();
// We can't check this during the initial creation as there is no account yet then
if (_accountState->account()->capabilities().clientSideEncryptionAvaliable()) {
@@ -265,7 +269,7 @@ void AccountSettings::slotMenuBeforeShow() {
QString AccountSettings::selectedFolderAlias() const
{
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
QModelIndex selected = _ui->_folderList->selectionModel()->currentIndex();
if (!selected.isValid())
return "";
return _model->data(selected, FolderStatusDelegate::FolderAliasRole).toString();
@@ -278,16 +282,7 @@ void AccountSettings::slotOpenAccountWizard()
if (qgetenv("QT_QPA_PLATFORMTHEME") == "appmenu-qt5" || QSystemTrayIcon::isSystemTrayAvailable()) {
topLevelWidget()->close();
}
#ifdef Q_OS_MAC
qCDebug(lcAccountSettings) << parent() << topLevelWidget();
SettingsDialogMac *sd = qobject_cast<SettingsDialogMac *>(topLevelWidget());
if (sd) {
sd->showActivityPage();
} else {
qFatal("nope");
}
#endif
OwncloudSetupWizard::runWizard(qApp, SLOT(slotownCloudWizardDone(int)), nullptr);
}
@@ -303,7 +298,7 @@ void AccountSettings::slotToggleSignInState()
void AccountSettings::doExpand()
{
ui->_folderList->expandToDepth(0);
_ui->_folderList->expandToDepth(0);
}
void AccountSettings::slotShowMnemonic(const QString &mnemonic) {
@@ -334,9 +329,9 @@ void AccountSettings::slotEncryptionFlagError(const QByteArray& fileId, int http
void AccountSettings::slotLockForEncryptionSuccess(const QByteArray& fileId, const QByteArray &token)
{
accountsState()->account()->e2e()->setTokenForFolder(fileId, token);
accountsState()->account()->e2e()->setTokenForFolder(fileId, token);
FolderMetadata emptyMetadata(accountsState()->account());
FolderMetadata emptyMetadata(accountsState()->account());
auto encryptedMetadata = emptyMetadata.encryptedMetadata();
if (encryptedMetadata.isEmpty()) {
//TODO: Mark the folder as unencrypted as the metadata generation failed.
@@ -348,36 +343,36 @@ void AccountSettings::slotLockForEncryptionSuccess(const QByteArray& fileId, con
return;
}
auto storeMetadataJob = new StoreMetaDataApiJob(accountsState()->account(), fileId, emptyMetadata.encryptedMetadata());
connect(storeMetadataJob, &StoreMetaDataApiJob::success,
this, &AccountSettings::slotUploadMetadataSuccess);
connect(storeMetadataJob, &StoreMetaDataApiJob::error,
this, &AccountSettings::slotUpdateMetadataError);
connect(storeMetadataJob, &StoreMetaDataApiJob::success,
this, &AccountSettings::slotUploadMetadataSuccess);
connect(storeMetadataJob, &StoreMetaDataApiJob::error,
this, &AccountSettings::slotUpdateMetadataError);
storeMetadataJob->start();
storeMetadataJob->start();
}
void AccountSettings::slotUploadMetadataSuccess(const QByteArray& folderId)
{
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
this, &AccountSettings::slotUnlockFolderSuccess);
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
this, &AccountSettings::slotUnlockFolderError);
unlockJob->start();
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
this, &AccountSettings::slotUnlockFolderSuccess);
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
this, &AccountSettings::slotUnlockFolderError);
unlockJob->start();
}
void AccountSettings::slotUpdateMetadataError(const QByteArray& folderId, int httpReturnCode)
{
Q_UNUSED(httpReturnCode);
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
this, &AccountSettings::slotUnlockFolderSuccess);
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
this, &AccountSettings::slotUnlockFolderError);
unlockJob->start();
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
this, &AccountSettings::slotUnlockFolderSuccess);
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
this, &AccountSettings::slotUnlockFolderError);
unlockJob->start();
}
void AccountSettings::slotLockForEncryptionError(const QByteArray& fileId, int httpErrorCode)
@@ -551,7 +546,7 @@ void AccountSettings::slotEditCurrentIgnoredFiles()
void AccountSettings::slotEditCurrentLocalIgnoredFiles()
{
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
QModelIndex selected = _ui->_folderList->selectionModel()->currentIndex();
if (!selected.isValid() || _model->classify(selected) != FolderStatusModel::SubFolder)
return;
QString fileName = _model->data(selected, FolderStatusDelegate::FolderPathRole).toString();
@@ -623,7 +618,7 @@ void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index
void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
{
QTreeView *tv = ui->_folderList;
QTreeView *tv = _ui->_folderList;
QModelIndex index = tv->indexAt(pos);
if (!index.isValid()) {
return;
@@ -654,7 +649,7 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
ac = menu->addAction(tr("Edit Ignored Files"));
connect(ac, &QAction::triggered, this, &AccountSettings::slotEditCurrentIgnoredFiles);
if (!ui->_folderList->isExpanded(index)) {
if (!_ui->_folderList->isExpanded(index)) {
ac = menu->addAction(tr("Choose what to sync"));
ac->setEnabled(folderConnected);
connect(ac, &QAction::triggered, this, &AccountSettings::doExpand);
@@ -693,7 +688,7 @@ void AccountSettings::slotFolderListClicked(const QModelIndex &indx)
}
if (_model->classify(indx) == FolderStatusModel::RootFolder) {
// tries to find if we clicked on the '...' button.
QTreeView *tv = ui->_folderList;
QTreeView *tv = _ui->_folderList;
auto pos = tv->mapFromGlobal(QCursor::pos());
if (FolderStatusDelegate::optionsButtonRect(tv->visualRect(indx), layoutDirection()).contains(pos)) {
slotCustomContextMenuRequested(pos);
@@ -706,8 +701,8 @@ void AccountSettings::slotFolderListClicked(const QModelIndex &indx)
// Expand root items on single click
if (_accountState && _accountState->state() == AccountState::Connected) {
bool expanded = !(ui->_folderList->isExpanded(indx));
ui->_folderList->setExpanded(indx, expanded);
bool expanded = !(_ui->_folderList->isExpanded(indx));
_ui->_folderList->setExpanded(indx, expanded);
}
}
}
@@ -744,7 +739,7 @@ void AccountSettings::slotFolderWizardAccepted()
qCInfo(lcAccountSettings) << "Creating folder" << definition.localPath;
if (!dir.mkpath(".")) {
QMessageBox::warning(this, tr("Folder creation failed"),
tr("<p>Could not create local folder <i>%1</i>.")
tr("<p>Could not create local folder <i>%1</i>.</p>")
.arg(QDir::toNativeSeparators(definition.localPath)));
return;
}
@@ -789,7 +784,7 @@ void AccountSettings::slotRemoveCurrentFolder()
{
FolderMan *folderMan = FolderMan::instance();
auto folder = folderMan->folder(selectedFolderAlias());
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
QModelIndex selected = _ui->_folderList->selectionModel()->currentIndex();
if (selected.isValid() && folder) {
int row = selected.row();
@@ -831,7 +826,7 @@ void AccountSettings::slotOpenCurrentFolder()
void AccountSettings::slotOpenCurrentLocalSubFolder()
{
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
QModelIndex selected = _ui->_folderList->selectionModel()->currentIndex();
if (!selected.isValid() || _model->classify(selected) != FolderStatusModel::SubFolder)
return;
QString fileName = _model->data(selected, FolderStatusDelegate::FolderPathRole).toString();
@@ -845,18 +840,21 @@ void AccountSettings::showConnectionLabel(const QString &message, QStringList er
"border-width: 1px; border-style: solid; border-color: #aaaaaa;"
"border-radius:5px;");
if (errors.isEmpty()) {
ui->connectLabel->setText(message);
ui->connectLabel->setToolTip(QString());
ui->connectLabel->setStyleSheet(QString());
QString msg = message;
Theme::replaceLinkColorStringBackgroundAware(msg);
_ui->connectLabel->setText(msg);
_ui->connectLabel->setToolTip(QString());
_ui->connectLabel->setStyleSheet(QString());
} else {
errors.prepend(message);
const QString msg = errors.join(QLatin1String("\n"));
QString msg = errors.join(QLatin1String("\n"));
qCDebug(lcAccountSettings) << msg;
ui->connectLabel->setText(msg);
ui->connectLabel->setToolTip(QString());
ui->connectLabel->setStyleSheet(errStyle);
Theme::replaceLinkColorString(msg, QColor("#c1c8e6"));
_ui->connectLabel->setText(msg);
_ui->connectLabel->setToolTip(QString());
_ui->connectLabel->setStyleSheet(errStyle);
}
ui->accountStatus->setVisible(!message.isEmpty());
_ui->accountStatus->setVisible(!message.isEmpty());
}
void AccountSettings::slotEnableCurrentFolder()
@@ -954,29 +952,29 @@ void AccountSettings::slotOpenOC()
void AccountSettings::slotUpdateQuota(qint64 total, qint64 used)
{
if (total > 0) {
ui->quotaProgressBar->setVisible(true);
ui->quotaProgressBar->setEnabled(true);
_ui->quotaProgressBar->setVisible(true);
_ui->quotaProgressBar->setEnabled(true);
// workaround the label only accepting ints (which may be only 32 bit wide)
const double percent = used / (double)total * 100;
const int percentInt = qMin(qRound(percent), 100);
ui->quotaProgressBar->setValue(percentInt);
_ui->quotaProgressBar->setValue(percentInt);
QString usedStr = Utility::octetsToString(used);
QString totalStr = Utility::octetsToString(total);
QString percentStr = Utility::compactFormatDouble(percent, 1);
QString toolTip = tr("%1 (%3%) of %2 in use. Some folders, including network mounted or shared folders, might have different limits.").arg(usedStr, totalStr, percentStr);
ui->quotaInfoLabel->setText(tr("%1 of %2 in use").arg(usedStr, totalStr));
ui->quotaInfoLabel->setToolTip(toolTip);
ui->quotaProgressBar->setToolTip(toolTip);
_ui->quotaInfoLabel->setText(tr("%1 of %2 in use").arg(usedStr, totalStr));
_ui->quotaInfoLabel->setToolTip(toolTip);
_ui->quotaProgressBar->setToolTip(toolTip);
} else {
ui->quotaProgressBar->setVisible(false);
ui->quotaInfoLabel->setToolTip(QString());
_ui->quotaProgressBar->setVisible(false);
_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."));
_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));
_ui->quotaInfoLabel->setText(tr("%1 in use").arg(usedStr));
}
}
}
@@ -985,7 +983,7 @@ void AccountSettings::slotAccountStateChanged()
{
int state = _accountState ? _accountState->state() : AccountState::Disconnected;
if (_accountState) {
ui->sslButton->updateAccountState(_accountState);
_ui->sslButton->updateAccountState(_accountState);
AccountPtr account = _accountState->account();
QUrl safeUrl(account->url());
safeUrl.setPassword(QString()); // Remove the password from the URL to avoid showing it in the UI
@@ -1030,7 +1028,7 @@ void AccountSettings::slotAccountStateChanged()
"<a href='%1'>Click here</a> to re-open the browser.")
.arg(url.toString(QUrl::FullyEncoded)));
} else {
showConnectionLabel(tr("Connecting to %1...").arg(serverWithUser));
showConnectionLabel(tr("Connecting to %1").arg(serverWithUser));
}
} else {
showConnectionLabel(tr("No connection to %1 at %2.")
@@ -1044,14 +1042,14 @@ void AccountSettings::slotAccountStateChanged()
}
/* Allow to expand the item if the account is connected. */
ui->_folderList->setItemsExpandable(state == AccountState::Connected);
_ui->_folderList->setItemsExpandable(state == AccountState::Connected);
if (state != AccountState::Connected) {
/* check if there are expanded root items, if so, close them */
int i;
for (i = 0; i < _model->rowCount(); ++i) {
if (ui->_folderList->isExpanded(_model->index(i)))
ui->_folderList->setExpanded(_model->index(i), false);
if (_ui->_folderList->isExpanded(_model->index(i)))
_ui->_folderList->setExpanded(_model->index(i), false);
}
} else if (_model->isDirty()) {
// If we connect and have pending changes, show the list.
@@ -1095,21 +1093,21 @@ void AccountSettings::slotLinkActivated(const QString &link)
// 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);
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);
if (!_ui->_folderList->isExpanded(i)) {
_ui->_folderList->setExpanded(i, true);
}
}
ui->_folderList->setSelectionMode(QAbstractItemView::SingleSelection);
ui->_folderList->setCurrentIndex(indx);
ui->_folderList->scrollTo(indx);
_ui->_folderList->setSelectionMode(QAbstractItemView::SingleSelection);
_ui->_folderList->setCurrentIndex(indx);
_ui->_folderList->scrollTo(indx);
} else {
qCWarning(lcAccountSettings) << "Unable to find a valid index for " << myFolder;
}
@@ -1118,7 +1116,7 @@ void AccountSettings::slotLinkActivated(const QString &link)
AccountSettings::~AccountSettings()
{
delete ui;
delete _ui;
}
void AccountSettings::refreshSelectiveSyncStatus()
@@ -1156,8 +1154,8 @@ void AccountSettings::refreshSelectiveSyncStatus()
}
if (msg.isEmpty()) {
ui->selectiveSyncButtons->setVisible(true);
ui->bigFolderUi->setVisible(false);
_ui->selectiveSyncButtons->setVisible(true);
_ui->bigFolderUi->setVisible(false);
} else {
ConfigFile cfg;
QString info = !cfg.confirmExternalStorage()
@@ -1166,27 +1164,27 @@ void AccountSettings::refreshSelectiveSyncStatus()
? tr("There are folders that were not synchronized because they are external storages: ")
: tr("There are folders that were not synchronized because they are too big or external storages: ");
ui->selectiveSyncNotification->setText(info + msg);
ui->selectiveSyncButtons->setVisible(false);
ui->bigFolderUi->setVisible(true);
_ui->selectiveSyncNotification->setText(info + msg);
_ui->selectiveSyncButtons->setVisible(false);
_ui->bigFolderUi->setVisible(true);
shouldBeVisible = true;
}
ui->selectiveSyncApply->setEnabled(_model->isDirty() || !msg.isEmpty());
bool wasVisible = !ui->selectiveSyncStatus->isHidden();
_ui->selectiveSyncApply->setEnabled(_model->isDirty() || !msg.isEmpty());
bool wasVisible = !_ui->selectiveSyncStatus->isHidden();
if (wasVisible != shouldBeVisible) {
QSize hint = ui->selectiveSyncStatus->sizeHint();
QSize hint = _ui->selectiveSyncStatus->sizeHint();
if (shouldBeVisible) {
ui->selectiveSyncStatus->setMaximumHeight(0);
ui->selectiveSyncStatus->setVisible(true);
_ui->selectiveSyncStatus->setMaximumHeight(0);
_ui->selectiveSyncStatus->setVisible(true);
}
auto anim = new QPropertyAnimation(ui->selectiveSyncStatus, "maximumHeight", ui->selectiveSyncStatus);
auto anim = new QPropertyAnimation(_ui->selectiveSyncStatus, "maximumHeight", _ui->selectiveSyncStatus);
anim->setEndValue(shouldBeVisible ? hint.height() : 0);
anim->start(QAbstractAnimation::DeleteWhenStopped);
connect(anim, &QPropertyAnimation::finished, [this, shouldBeVisible]() {
ui->selectiveSyncStatus->setMaximumHeight(QWIDGETSIZE_MAX);
_ui->selectiveSyncStatus->setMaximumHeight(QWIDGETSIZE_MAX);
if (!shouldBeVisible) {
ui->selectiveSyncStatus->hide();
_ui->selectiveSyncStatus->hide();
}
});
}
@@ -1240,18 +1238,36 @@ void AccountSettings::slotDeleteAccount()
bool AccountSettings::event(QEvent *e)
{
if (e->type() == QEvent::Hide || e->type() == QEvent::Show) {
_quotaInfo.setActive(isVisible());
_userInfo.setActive(isVisible());
}
if (e->type() == QEvent::Show) {
// Expand the folder automatically only if there's only one, see #4283
// The 2 is 1 folder + 1 'add folder' button
if (_model->rowCount() <= 2) {
ui->_folderList->setExpanded(_model->index(0, 0), true);
_ui->_folderList->setExpanded(_model->index(0, 0), true);
}
}
return QWidget::event(e);
}
void AccountSettings::slotStyleChanged()
{
customizeStyle();
// Notify the other widgets (Dark-/Light-Mode switching)
emit styleChanged();
}
void AccountSettings::customizeStyle()
{
QString msg = _ui->connectLabel->text();
Theme::replaceLinkColorStringBackgroundAware(msg);
_ui->connectLabel->setText(msg);
QColor color = palette().highlight().color();
_ui->quotaProgressBar->setStyleSheet(QString::fromLatin1(progressBarStyleC).arg(color.name()));
}
} // namespace OCC
#include "accountsettings.moc"

View File

@@ -22,7 +22,7 @@
#include <QTimer>
#include "folder.h"
#include "quotainfo.h"
#include "userinfo.h"
#include "progressdispatcher.h"
#include "owncloudgui.h"
#include "folderstatusmodel.h"
@@ -63,11 +63,14 @@ signals:
void openFolderAlias(const QString &);
void showIssuesList(AccountState *account);
void requesetMnemonic();
void removeAccountFolders(AccountState *account);
void styleChanged();
public slots:
void slotOpenOC();
void slotUpdateQuota(qint64, qint64);
void slotAccountStateChanged();
void slotStyleChanged();
AccountState *accountsState() { return _accountState; }
@@ -128,17 +131,18 @@ private:
bool event(QEvent *) override;
void createAccountToolbox();
void openIgnoredFilesDialog(const QString & absFolderPath);
void customizeStyle();
/// Returns the alias of the selected folder, empty string if none
QString selectedFolderAlias() const;
Ui::AccountSettings *ui;
Ui::AccountSettings *_ui;
FolderStatusModel *_model;
QUrl _OCUrl;
bool _wasDisabledBefore;
AccountState *_accountState;
QuotaInfo _quotaInfo;
UserInfo _userInfo;
QAction *_toggleSignInOutAction;
QAction *_addAccountAction;

View File

@@ -187,7 +187,7 @@
<item row="0" column="2">
<widget class="QToolButton" name="_accountToolbox">
<property name="text">
<string>...</string>
<string notr="true">...</string>
</property>
</widget>
</item>
@@ -208,7 +208,7 @@
<string/>
</property>
<property name="text">
<string>Storage space: ...</string>
<string>Storage space: </string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>

View File

@@ -14,6 +14,7 @@
#include "accountstate.h"
#include "accountmanager.h"
#include "remotewipe.h"
#include "account.h"
#include "creds/abstractcredentials.h"
#include "creds/httpcredentials.h"
@@ -24,6 +25,11 @@
#include <QTimer>
#include <qfontmetrics.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkRequest>
#include <QBuffer>
namespace OCC {
Q_LOGGING_CATEGORY(lcAccountState, "nextcloud.gui.account.state", QtInfoMsg)
@@ -36,11 +42,12 @@ AccountState::AccountState(AccountPtr account)
, _waitingForNewCredentials(false)
, _notificationsEtagResponseHeader("*")
, _maintenanceToConnectedDelay(60000 + (qrand() % (4 * 60000))) // 1-5min delay
, _remoteWipe(new RemoteWipe(_account))
{
qRegisterMetaType<AccountState *>("AccountState*");
connect(account.data(), &Account::invalidCredentials,
this, &AccountState::slotInvalidCredentials);
this, &AccountState::slotHandleRemoteWipeCheck);
connect(account.data(), &Account::credentialsFetched,
this, &AccountState::slotCredentialsFetched);
connect(account.data(), &Account::credentialsAsked,
@@ -222,7 +229,7 @@ void AccountState::checkConnectivity()
return;
}
ConnectionValidator *conValidator = new ConnectionValidator(account());
ConnectionValidator *conValidator = new ConnectionValidator(AccountStatePtr(this));
_connectionValidator = conValidator;
connect(conValidator, &ConnectionValidator::connectionResult,
this, &AccountState::slotConnectionValidatorResult);
@@ -303,7 +310,7 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
break;
case ConnectionValidator::CredentialsWrong:
case ConnectionValidator::CredentialsNotReady:
slotInvalidCredentials();
handleInvalidCredentials();
break;
case ConnectionValidator::SslError:
setState(SignedOut);
@@ -322,7 +329,20 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
}
}
void AccountState::slotInvalidCredentials()
void AccountState::slotHandleRemoteWipeCheck()
{
// make sure it changes account state and icons
signOutByUi();
qCInfo(lcAccountState) << "Invalid credentials for" << _account->url().toString()
<< "checking for remote wipe request";
_waitingForNewCredentials = false;
setState(SignedOut);
}
void AccountState::handleInvalidCredentials()
{
if (isSignedOut() || _waitingForNewCredentials)
return;
@@ -343,6 +363,7 @@ void AccountState::slotInvalidCredentials()
account()->credentials()->askFromUser();
}
void AccountState::slotCredentialsFetched(AbstractCredentials *)
{
// Make a connection attempt, no matter whether the credentials are

View File

@@ -29,6 +29,7 @@ namespace OCC {
class AccountState;
class Account;
class RemoteWipe;
typedef QExplicitlySharedDataPointer<AccountState> AccountStatePtr;
@@ -150,6 +151,9 @@ public:
*/
void setNavigationAppsEtagResponseHeader(const QByteArray &value);
///Asks for user credentials
void handleInvalidCredentials();
public slots:
/// Triggers a ping to the server to update state and
/// connection status and errors.
@@ -164,7 +168,11 @@ signals:
protected Q_SLOTS:
void slotConnectionValidatorResult(ConnectionValidator::Status status, const QStringList &errors);
void slotInvalidCredentials();
/// When client gets a 401 or 403 checks if server requested remote wipe
/// before asking for user credentials again
void slotHandleRemoteWipeCheck();
void slotCredentialsFetched(AbstractCredentials *creds);
void slotCredentialsAsked(AbstractCredentials *creds);
@@ -190,6 +198,13 @@ private:
* Milliseconds for which to delay reconnection after 503/maintenance.
*/
int _maintenanceToConnectedDelay;
/**
* Connects remote wipe check with the account
* the log out triggers the check (loads app password -> create request)
*/
RemoteWipe *_remoteWipe;
};
}

View File

@@ -21,7 +21,7 @@ namespace OCC {
bool operator<(const Activity &rhs, const Activity &lhs)
{
return rhs._dateTime.toMSecsSinceEpoch() > lhs._dateTime.toMSecsSinceEpoch();
return rhs._dateTime > lhs._dateTime;
}
bool operator==(const Activity &rhs, const Activity &lhs)

View File

@@ -15,6 +15,7 @@
*/
#include "activityitemdelegate.h"
#include "activitylistmodel.h"
#include "folderstatusmodel.h"
#include "folderman.h"
#include "accountstate.h"
@@ -26,6 +27,14 @@
#include <QPainter>
#include <QApplication>
#define FIXME_USE_HIGH_DPI_RATIO
#ifdef FIXME_USE_HIGH_DPI_RATIO
// FIXME: Find a better way to calculate the text width on high-dpi displays (Retina).
#include <QDesktopWidget>
#endif
#define HASQT5_11 (QT_VERSION >= QT_VERSION_CHECK(5,11,0))
namespace OCC {
int ActivityItemDelegate::_iconHeight = 0;
@@ -38,6 +47,12 @@ int ActivityItemDelegate::_buttonHeight = 0;
const QString ActivityItemDelegate::_remote_share("remote_share");
const QString ActivityItemDelegate::_call("call");
ActivityItemDelegate::ActivityItemDelegate()
: QStyledItemDelegate()
{
customizeStyle();
}
int ActivityItemDelegate::iconHeight()
{
if (_iconHeight == 0) {
@@ -87,10 +102,26 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
int iconSize = 16;
int iconOffset = qRound(fm.height() / 4.0 * 7.0);
int offset = 4;
const bool isSelected = (option.state & QStyle::State_Selected);
#ifdef FIXME_USE_HIGH_DPI_RATIO
// FIXME: Find a better way to calculate the text width on high-dpi displays (Retina).
const int device_pixel_ration = QApplication::desktop()->devicePixelRatio();
int pixel_ratio = (device_pixel_ration > 1 ? device_pixel_ration : 1);
#endif
// get the data
Activity::Type activityType = qvariant_cast<Activity::Type>(index.data(ActionRole));
QIcon actionIcon = qvariant_cast<QIcon>(index.data(ActionIconRole));
QIcon actionIcon;
const ActivityListModel::ActionIcon icn = qvariant_cast<ActivityListModel::ActionIcon>(index.data(ActionIconRole));
switch(icn.iconType) {
case ActivityListModel::ActivityIconType::iconUseCached: actionIcon = icn.cachedIcon; break;
case ActivityListModel::ActivityIconType::iconActivity: actionIcon = (isSelected ? _iconActivity_sel : _iconActivity); break;
case ActivityListModel::ActivityIconType::iconBell: actionIcon = (isSelected ? _iconBell_sel : _iconBell); break;
case ActivityListModel::ActivityIconType::iconStateError: actionIcon = _iconStateError; break;
case ActivityListModel::ActivityIconType::iconStateWarning: actionIcon = _iconStateWarning; break;
case ActivityListModel::ActivityIconType::iconStateInfo: actionIcon = _iconStateInfo; break;
case ActivityListModel::ActivityIconType::iconStateSync: actionIcon = _iconStateSync; break;
}
QString objectType = qvariant_cast<QString>(index.data(ObjectTypeRole));
QString actionText = qvariant_cast<QString>(index.data(ActionTextRole));
QString messageText = qvariant_cast<QString>(index.data(MessageRole));
@@ -106,15 +137,27 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
// subject text rect
QRect actionTextBox = actionIconRect;
#if (HASQT5_11)
int actionTextBoxWidth = fm.horizontalAdvance(actionText);
#else
int actionTextBoxWidth = fm.width(actionText);
#endif
actionTextBox.setTop(option.rect.top() + margin + offset/2);
actionTextBox.setHeight(fm.height());
actionTextBox.setLeft(actionIconRect.right() + margin);
#ifdef FIXME_USE_HIGH_DPI_RATIO
// FIXME: Find a better way to calculate the text width on high-dpi displays (Retina).
actionTextBoxWidth *= pixel_ratio;
#endif
actionTextBox.setRight(actionTextBox.left() + actionTextBoxWidth + margin);
// message text rect
QRect messageTextBox = actionTextBox;
#if (HASQT5_11)
int messageTextWidth = fm.horizontalAdvance(messageText);
#else
int messageTextWidth = fm.width(messageText);
#endif
int messageTextTop = option.rect.top() + fm.height() + margin;
if(actionText.isEmpty()) messageTextTop = option.rect.top() + margin + offset/2;
messageTextBox.setTop(messageTextTop);
@@ -128,14 +171,21 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
// time box rect
QRect timeBox = messageTextBox;
QString timeStr = tr("%1").arg(timeText);
int timeTextWidth = fm.width(timeStr);
#if (HASQT5_11)
int timeTextWidth = fm.horizontalAdvance(timeText);
#else
int timeTextWidth = fm.width(timeText);
#endif
int timeTop = option.rect.top() + fm.height() + fm.height() + margin + offset/2;
if(messageText.isEmpty() || actionText.isEmpty())
timeTop = option.rect.top() + fm.height() + margin;
timeBox.setTop(timeTop);
timeBox.setHeight(fm.height());
timeBox.setBottom(timeBox.top() + fm.height());
#ifdef FIXME_USE_HIGH_DPI_RATIO
// FIXME: Find a better way to calculate the text width on high-dpi displays (Retina).
timeTextWidth *= pixel_ratio;
#endif
timeBox.setRight(timeBox.left() + timeTextWidth + margin);
// buttons - default values
@@ -170,9 +220,9 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
if(activityType == Activity::Type::NotificationType){
// Secondary will be 'Dismiss' or '...' multiple options button
secondaryButton.icon = QIcon(QLatin1String(":/client/resources/close.svg"));
secondaryButton.icon = (isSelected ? _iconClose_sel : _iconClose);
if(customList.size() > 1)
secondaryButton.icon = QIcon(QLatin1String(":/client/resources/more.svg"));
secondaryButton.icon = (isSelected ? _iconMore_sel : _iconMore);
secondaryButton.iconSize = QSize(iconSize, iconSize);
// Primary button will be 'More Information' or 'Accept'
@@ -180,7 +230,11 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
if(objectType == _remote_share) primaryButton.text = tr("Accept");
if(objectType == _call) primaryButton.text = tr("Join");
#if (HASQT5_11)
primaryButton.rect.setLeft(left - margin * 2 - fm.horizontalAdvance(primaryButton.text));
#else
primaryButton.rect.setLeft(left - margin * 2 - fm.width(primaryButton.text));
#endif
// save info to be able to filter mouse clicks
_buttonHeight = buttonSize;
@@ -191,12 +245,17 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
} else if(activityType == Activity::SyncResultType){
// Secondary will be 'open file manager' with the folder icon
secondaryButton.icon = QIcon(QLatin1String(":/client/resources/folder.svg"));
secondaryButton.icon = _iconFolder;
secondaryButton.iconSize = QSize(iconSize, iconSize);
// Primary button will be 'open browser'
primaryButton.text = tr("Open Browser");
#if (HASQT5_11)
primaryButton.rect.setLeft(left - margin * 2 - fm.horizontalAdvance(primaryButton.text));
#else
primaryButton.rect.setLeft(left - margin * 2 - fm.width(primaryButton.text));
#endif
// save info to be able to filter mouse clicks
_buttonHeight = buttonSize;
@@ -207,7 +266,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
} else if(activityType == Activity::SyncFileItemType){
// Secondary will be 'open file manager' with the folder icon
secondaryButton.icon = QIcon(QLatin1String(":/client/resources/folder.svg"));
secondaryButton.icon = _iconFolder;
secondaryButton.iconSize = QSize(iconSize, iconSize);
// No primary button on this case
@@ -232,7 +291,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
p.setCurrentColorGroup(QPalette::Disabled);
// change pen color if the line is selected
if (option.state & QStyle::State_Selected)
if (isSelected)
painter->setPen(p.color(QPalette::HighlightedText));
else
painter->setPen(p.color(QPalette::Text));
@@ -246,8 +305,15 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
painter->drawText(actionTextBox, elidedAction);
// draw the buttons
if(activityType == Activity::Type::NotificationType || activityType == Activity::Type::SyncResultType)
if(activityType == Activity::Type::NotificationType || activityType == Activity::Type::SyncResultType) {
primaryButton.palette = p;
if (isSelected)
primaryButton.palette.setColor(QPalette::ButtonText, p.color(QPalette::HighlightedText));
else
primaryButton.palette.setColor(QPalette::ButtonText, p.color(QPalette::Text));
QApplication::style()->drawControl(QStyle::CE_PushButton, &primaryButton, painter);
}
// Since they are errors on local syncing, there is nothing to do in the server
if(activityType != Activity::Type::ActivityType)
@@ -261,13 +327,13 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
}
// change pen color for the time
if (option.state & QStyle::State_Selected)
if (isSelected)
painter->setPen(p.color(QPalette::Disabled, QPalette::HighlightedText));
else
painter->setPen(p.color(QPalette::Disabled, QPalette::Text));
// draw the time
const QString elidedTime = fm.elidedText(timeStr, Qt::ElideRight, spaceLeftForText);
const QString elidedTime = fm.elidedText(timeText, Qt::ElideRight, spaceLeftForText);
painter->drawText(timeBox, elidedTime);
painter->restore();
@@ -310,4 +376,32 @@ bool ActivityItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
return QStyledItemDelegate::editorEvent(event, model, option, index);
}
void ActivityItemDelegate::slotStyleChanged()
{
customizeStyle();
}
void ActivityItemDelegate::customizeStyle()
{
QPalette pal;
pal.setColor(QPalette::Base, QColor(0,0,0)); // use dark background colour to invert icons
_iconClose = Theme::createColorAwareIcon(QLatin1String(":/client/resources/close.svg"));
_iconClose_sel = Theme::createColorAwareIcon(QLatin1String(":/client/resources/close.svg"), pal);
_iconMore = Theme::createColorAwareIcon(QLatin1String(":/client/resources/more.svg"));
_iconMore_sel = Theme::createColorAwareIcon(QLatin1String(":/client/resources/more.svg"), pal);
_iconFolder = QIcon(QLatin1String(":/client/resources/folder.svg"));
_iconActivity = Theme::createColorAwareIcon(QLatin1String(":/client/resources/activity.png"));
_iconActivity_sel = Theme::createColorAwareIcon(QLatin1String(":/client/resources/activity.png"), pal);
_iconBell = Theme::createColorAwareIcon(QLatin1String(":/client/resources/bell.svg"));
_iconBell_sel = Theme::createColorAwareIcon(QLatin1String(":/client/resources/bell.svg"), pal);
_iconStateError = QIcon(QLatin1String(":/client/resources/state-error.svg"));
_iconStateWarning = QIcon(QLatin1String(":/client/resources/state-warning.svg"));
_iconStateInfo = QIcon(QLatin1String(":/client/resources/state-info.svg"));
_iconStateSync = QIcon(QLatin1String(":/client/resources/state-sync.svg"));
}
} // namespace OCC

View File

@@ -43,6 +43,8 @@ public:
AccountConnectedRole,
SyncFileStatusRole };
ActivityItemDelegate();
void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override;
QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const override;
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
@@ -51,11 +53,16 @@ public:
static int rowHeight();
static int iconHeight();
public slots:
void slotStyleChanged();
signals:
void primaryButtonClickedOnItemView(const QModelIndex &index);
void secondaryButtonClickedOnItemView(const QModelIndex &index);
private:
void customizeStyle();
static int _margin;
static int _iconHeight;
static int _primaryButtonWidth;
@@ -65,6 +72,23 @@ private:
static int _buttonHeight;
static const QString _remote_share;
static const QString _call;
QIcon _iconClose;
QIcon _iconClose_sel;
QIcon _iconMore;
QIcon _iconMore_sel;
QIcon _iconFolder;
QIcon _iconActivity;
QIcon _iconActivity_sel;
QIcon _iconBell;
QIcon _iconBell_sel;
QIcon _iconStateError;
QIcon _iconStateWarning;
QIcon _iconStateInfo;
QIcon _iconStateSync;
};
} // namespace OCC

View File

@@ -71,13 +71,14 @@ QVariant ActivityListModel::data(const QModelIndex &index, int role) const
return QVariant(list.at(0));
}
// File does not exist anymore? Let's try to open its path
list = FolderMan::instance()->findFileInLocalFolders(QFileInfo(relPath).path(), ast->account());
if (list.count() > 0) {
return QVariant(list.at(0));
if(QFileInfo(relPath).exists()) {
list = FolderMan::instance()->findFileInLocalFolders(QFileInfo(relPath).path(), ast->account());
if (list.count() > 0) {
return QVariant(list.at(0));
}
}
}
return QVariant();
break;
case ActivityItemDelegate::ActionsLinksRole:{
QList<QVariant> customList;
foreach (ActivityLink customItem, a._links) {
@@ -86,61 +87,63 @@ QVariant ActivityListModel::data(const QModelIndex &index, int role) const
customList << customVariant;
}
return customList;
break;
}
case ActivityItemDelegate::ActionIconRole:
case ActivityItemDelegate::ActionIconRole:{
ActionIcon actionIcon;
if(a._type == Activity::NotificationType){
QIcon cachedIcon = ServerNotificationHandler::iconCache.value(a._id);
if(!cachedIcon.isNull())
return cachedIcon;
else return QIcon(QLatin1String(":/client/resources/bell.svg"));
if(!cachedIcon.isNull()) {
actionIcon.iconType = ActivityIconType::iconUseCached;
actionIcon.cachedIcon = cachedIcon;
} else {
actionIcon.iconType = ActivityIconType::iconBell;
}
} else if(a._type == Activity::SyncResultType){
return QIcon(QLatin1String(":/client/resources/state-error.svg"));
actionIcon.iconType = ActivityIconType::iconStateError;
} else if(a._type == Activity::SyncFileItemType){
if(a._status == SyncFileItem::NormalError
|| a._status == SyncFileItem::FatalError
|| a._status == SyncFileItem::DetailError
|| a._status == SyncFileItem::BlacklistedError) {
return QIcon(QLatin1String(":/client/resources/state-error.svg"));
actionIcon.iconType = ActivityIconType::iconStateError;
} else if(a._status == SyncFileItem::SoftError
|| a._status == SyncFileItem::Conflict
|| a._status == SyncFileItem::Restoration
|| a._status == SyncFileItem::FileLocked){
return QIcon(QLatin1String(":/client/resources/state-warning.svg"));
actionIcon.iconType = ActivityIconType::iconStateWarning;
} else if(a._status == SyncFileItem::FileIgnored){
return QIcon(QLatin1String(":/client/resources/state-info.svg"));
actionIcon.iconType = ActivityIconType::iconStateInfo;
} else {
actionIcon.iconType = ActivityIconType::iconStateSync;
}
return QIcon(QLatin1String(":/client/resources/state-sync.svg"));
} else {
actionIcon.iconType = ActivityIconType::iconActivity;
}
return QIcon(QLatin1String(":/client/resources/activity.png"));
break;
QVariant icn;
icn.setValue(actionIcon);
return icn;
}
case ActivityItemDelegate::ObjectTypeRole:
return a._objectType;
break;
case ActivityItemDelegate::ActionRole:{
QVariant type;
type.setValue(a._type);
return type;
break;
}
case ActivityItemDelegate::ActionTextRole:
return a._subject;
break;
case ActivityItemDelegate::MessageRole:
return a._message;
break;
case ActivityItemDelegate::LinkRole:
return a._link;
break;
case ActivityItemDelegate::AccountRole:
return a._accName;
break;
case ActivityItemDelegate::PointInTimeRole:
return Utility::timeAgoInWords(a._dateTime);
break;
return Utility::timeAgoInWords(a._dateTime.toLocalTime());
case Qt::ToolTipRole:
return a._dateTime.toLocalTime().toString(Qt::DefaultLocaleShortDate);
case ActivityItemDelegate::AccountConnectedRole:
return (ast && ast->isConnected());
break;
default:
return QVariant();
}
@@ -229,6 +232,29 @@ void ActivityListModel::addErrorToActivityList(Activity activity) {
combineActivityLists();
}
void ActivityListModel::addIgnoredFileToList(Activity newActivity) {
qCInfo(lcActivity) << "First checking for duplicates then add file to the notification list of ignored files: " << newActivity._file;
bool duplicate = false;
if(_listOfIgnoredFiles.size() == 0){
_notificationIgnoredFiles = newActivity;
_notificationIgnoredFiles._subject = tr("Files from the ignore list as well as symbolic links are not synced. This includes:");
_listOfIgnoredFiles.append(newActivity);
return;
}
foreach(Activity activity, _listOfIgnoredFiles){
if(activity._file == newActivity._file){
duplicate = true;
break;
}
}
if(!duplicate){
_notificationIgnoredFiles._message.append(", " + newActivity._file);
}
}
void ActivityListModel::addNotificationToActivityList(Activity activity) {
qCInfo(lcActivity) << "Notification successfully added to the notification list: " << activity._subject;
_notificationLists.prepend(activity);
@@ -242,7 +268,7 @@ void ActivityListModel::clearNotifications() {
}
void ActivityListModel::removeActivityFromActivityList(int row) {
Activity activity = _finalList.at(row);
Activity activity = _finalList.at(row);
removeActivityFromActivityList(activity);
combineActivityLists();
}
@@ -276,22 +302,31 @@ void ActivityListModel::removeActivityFromActivityList(Activity activity) {
}
}
void ActivityListModel::combineActivityLists()
{
ActivityList resultList;
std::sort(_notificationErrorsLists.begin(), _notificationErrorsLists.end());
resultList.append(_notificationErrorsLists);
if(_notificationErrorsLists.count() > 0) {
std::sort(_notificationErrorsLists.begin(), _notificationErrorsLists.end());
resultList.append(_notificationErrorsLists);
}
if(_listOfIgnoredFiles.size() > 0)
resultList.append(_notificationIgnoredFiles);
std::sort(_notificationLists.begin(), _notificationLists.end());
resultList.append(_notificationLists);
if(_notificationLists.count() > 0) {
std::sort(_notificationLists.begin(), _notificationLists.end());
resultList.append(_notificationLists);
}
std::sort(_syncFileItemLists.begin(), _syncFileItemLists.end());
resultList.append(_syncFileItemLists);
if(_syncFileItemLists.count() > 0) {
std::sort(_syncFileItemLists.begin(), _syncFileItemLists.end());
resultList.append(_syncFileItemLists);
}
std::sort(_activityLists.begin(), _activityLists.end());
resultList.append(_activityLists);
if(_activityLists.count() > 0) {
std::sort(_activityLists.begin(), _activityLists.end());
resultList.append(_activityLists);
}
beginResetModel();
_finalList.clear();

View File

@@ -38,6 +38,20 @@ class ActivityListModel : public QAbstractListModel
{
Q_OBJECT
public:
enum ActivityIconType {
iconUseCached = 0,
iconActivity,
iconBell,
iconStateError,
iconStateWarning,
iconStateInfo,
iconStateSync
};
struct ActionIcon {
ActivityIconType iconType;
QIcon cachedIcon;
};
explicit ActivityListModel(AccountState *accountState, QWidget *parent = nullptr);
QVariant data(const QModelIndex &index, int role) const override;
@@ -51,6 +65,7 @@ public:
void addNotificationToActivityList(Activity activity);
void clearNotifications();
void addErrorToActivityList(Activity activity);
void addIgnoredFileToList(Activity newActivity);
void addSyncFileItemToActivityList(Activity activity);
void removeActivityFromActivityList(int row);
void removeActivityFromActivityList(Activity activity);
@@ -73,6 +88,8 @@ private:
ActivityList _activityLists;
ActivityList _syncFileItemLists;
ActivityList _notificationLists;
ActivityList _listOfIgnoredFiles;
Activity _notificationIgnoredFiles;
ActivityList _notificationErrorsLists;
ActivityList _finalList;
AccountState *_accountState;
@@ -81,4 +98,7 @@ private:
int _currentItem = 0;
};
}
Q_DECLARE_METATYPE(OCC::ActivityListModel::ActionIcon)
#endif // ACTIVITYLISTMODEL_H

View File

@@ -89,6 +89,9 @@ ActivityWidget::ActivityWidget(AccountState *accountState, QWidget *parent)
this, &ActivityWidget::addError);
_removeTimer.setInterval(1000);
// Connect styleChanged events to our widgets, so they can adapt (Dark-/Light-Mode switching)
connect(this, &ActivityWidget::styleChanged, delegate, &ActivityItemDelegate::slotStyleChanged);
}
ActivityWidget::~ActivityWidget()
@@ -127,11 +130,12 @@ void ActivityWidget::slotProgressInfo(const QString &folder, const ProgressInfo
}
if(activity._status == SyncFileItem::FileIgnored && !QFileInfo(f->path() + activity._file).exists()){
if(activity._status == SyncFileItem::FileIgnored && !QFileInfo(f->path() + activity._file).exists()) {
_model->removeActivityFromActivityList(activity);
continue;
}
if(!QFileInfo(f->path() + activity._file).exists()){
_model->removeActivityFromActivityList(activity);
continue;
@@ -175,7 +179,7 @@ void ActivityWidget::slotItemCompleted(const QString &folder, const SyncFileItem
Activity activity;
activity._type = Activity::SyncFileItemType; //client activity
activity._status = item->_status;
activity._dateTime = QDateTime::fromString(QDateTime::currentDateTime().toString(), Qt::ISODate);
activity._dateTime = QDateTime::currentDateTime();
activity._message = item->_originalFile;
activity._link = folderInstance->accountState()->account()->url();
activity._accName = folderInstance->accountState()->account()->displayName();
@@ -191,8 +195,12 @@ void ActivityWidget::slotItemCompleted(const QString &folder, const SyncFileItem
qCWarning(lcActivity) << "Item " << item->_file << " retrieved resulted in error " << item->_errorString;
activity._subject = item->_errorString;
// add 'protocol error' to activity list
_model->addErrorToActivityList(activity);
if(item->_status == SyncFileItem::Status::FileIgnored) {
_model->addIgnoredFileToList(activity);
} else {
// add 'protocol error' to activity list
_model->addErrorToActivityList(activity);
}
}
}
}
@@ -543,6 +551,12 @@ void ActivityWidget::slotNotifyServerFinished(const QString &reply, int replyCod
qCInfo(lcActivity) << "Server Notification reply code" << replyCode << reply;
}
void ActivityWidget::slotStyleChanged()
{
// Notify the other widgets (Dark-/Light-Mode switching)
emit styleChanged();
}
/* ==================================================================== */
ActivitySettings::ActivitySettings(AccountState *accountState, QWidget *parent)
@@ -565,6 +579,9 @@ ActivitySettings::ActivitySettings(AccountState *accountState, QWidget *parent)
// connect a model signal to stop the animation
connect(_activityWidget, &ActivityWidget::rowsInserted, _progressIndicator, &QProgressIndicator::stopAnimation);
connect(_activityWidget, &ActivityWidget::rowsInserted, this, &ActivitySettings::slotDisplayActivities);
// Connect styleChanged events to our widgets, so they can adapt (Dark-/Light-Mode switching)
connect(this, &ActivitySettings::styleChanged, _activityWidget, &ActivityWidget::slotStyleChanged);
}
void ActivitySettings::slotDisplayActivities(){
@@ -623,4 +640,14 @@ bool ActivitySettings::event(QEvent *e)
ActivitySettings::~ActivitySettings()
{
}
void ActivitySettings::slotStyleChanged()
{
if(_progressIndicator)
_progressIndicator->setColor(QGuiApplication::palette().color(QPalette::Text));
// Notify the other widgets (Dark-/Light-Mode switching)
emit styleChanged();
}
}

View File

@@ -78,12 +78,14 @@ public slots:
void addError(const QString &folderAlias, const QString &message, ErrorCategory category);
void slotProgressInfo(const QString &folder, const ProgressInfo &progress);
void slotItemCompleted(const QString &folder, const SyncFileItemPtr &item);
void slotStyleChanged();
signals:
void guiLog(const QString &, const QString &);
void rowsInserted();
void hideActivityTab(bool);
void sendNotificationRequest(const QString &accountName, const QString &link, const QByteArray &verb, int row);
void styleChanged();
private slots:
void slotBuildNotificationDisplay(const ActivityList &list);
@@ -96,6 +98,7 @@ private slots:
void slotSecondaryButtonClickedOnListView(const QModelIndex &index);
private:
void customizeStyle();
void showLabels();
QString timeString(QDateTime dt, QLocale::FormatType format) const;
Ui::ActivityWidget *_ui;
@@ -137,6 +140,7 @@ public slots:
void slotRefresh();
void slotRemoveAccount();
void setNotificationRefreshInterval(std::chrono::milliseconds interval);
void slotStyleChanged();
private slots:
void slotRegularNotificationCheck();
@@ -144,6 +148,7 @@ private slots:
signals:
void guiLog(const QString &, const QString &);
void styleChanged();
private:
bool event(QEvent *e) override;

View File

@@ -48,7 +48,7 @@
<item>
<widget class="QPushButton" name="pushButtonBrowseCertificate">
<property name="text">
<string>Browse...</string>
<string>Browse</string>
</property>
</widget>
</item>
@@ -57,7 +57,7 @@
<item row="1" column="0">
<widget class="QLabel" name="labelPWDCertificate">
<property name="text">
<string>Certificate password :</string>
<string>Certificate password:</string>
</property>
</widget>
</item>

View File

@@ -108,6 +108,7 @@ Application::Application(int &argc, char **argv)
, _userTriggeredConnect(false)
, _debugMode(false)
, _backgroundMode(false)
, _isQuitting(false)
{
_startedAt.start();
@@ -253,6 +254,9 @@ Application::Application(int &argc, char **argv)
// Cleanup at Quit.
connect(this, &QCoreApplication::aboutToQuit, this, &Application::slotCleanup);
// Allow other classes to hook into isShowingSettingsDialog() signals (re-auth widgets, for example)
connect(_gui.data(), &ownCloudGui::isShowingSettingsDialog, this, &Application::slotGuiIsShowingSettings);
}
Application::~Application()
@@ -264,6 +268,8 @@ Application::~Application()
}
// Remove the account from the account manager so it can be deleted.
disconnect(AccountManager::instance(), &AccountManager::accountRemoved,
this, &Application::slotAccountStateRemoved);
AccountManager::instance()->shutdown();
}
@@ -283,7 +289,7 @@ void Application::slotAccountStateRemoved(AccountState *accountState)
}
// if there is no more account, show the wizard.
if (AccountManager::instance()->accounts().isEmpty()) {
if (!_isQuitting && AccountManager::instance()->accounts().isEmpty()) {
// allow to add a new account if there is non any more. Always think
// about single account theming!
OwncloudSetupWizard::runWizard(this, SLOT(slotownCloudWizardDone(int)));
@@ -306,6 +312,8 @@ void Application::slotAccountStateAdded(AccountState *accountState)
void Application::slotCleanup()
{
_isQuitting = true;
AccountManager::instance()->save();
FolderMan::instance()->unloadAndDeleteAllFolders();
@@ -643,5 +651,9 @@ void Application::showSettingsDialog()
_gui->slotShowSettings();
}
void Application::slotGuiIsShowingSettings()
{
emit isShowingSettingsDialog();
}
} // namespace OCC

View File

@@ -82,6 +82,7 @@ protected:
signals:
void folderRemoved();
void folderStateChanged(Folder *);
void isShowingSettingsDialog();
protected slots:
void slotParseMessage(const QString &, QObject *);
@@ -91,6 +92,7 @@ protected slots:
void slotAccountStateAdded(AccountState *accountState);
void slotAccountStateRemoved(AccountState *accountState);
void slotSystemOnlineConfigurationChanged(QNetworkConfiguration);
void slotGuiIsShowingSettings();
private:
void setHelp();
@@ -114,6 +116,7 @@ private:
bool _userTriggeredConnect;
bool _debugMode;
bool _backgroundMode;
bool _isQuitting;
ClientProxy _proxy;

View File

@@ -53,7 +53,7 @@ bool ClientProxy::isUsingSystemDefault()
return cfg.proxyType() == QNetworkProxy::DefaultProxy;
}
return false;
return true;
}
QString printQNetworkProxy(const QNetworkProxy &proxy)

View File

@@ -52,8 +52,8 @@ void CloudProviderManager::registerSignals()
CloudProviderManager::CloudProviderManager(QObject *parent) : QObject(parent)
{
_map = new QMap<QString, CloudProviderWrapper*>();
QString busName = QString(LIBCLOUDPROVIDERS_DBUS_BUS_NAME);
g_bus_own_name (G_BUS_TYPE_SESSION, busName.toAscii().data(), G_BUS_NAME_OWNER_FLAGS_NONE, nullptr, on_name_acquired, nullptr, this, nullptr);
_folder_index = 0;
g_bus_own_name (G_BUS_TYPE_SESSION, LIBCLOUDPROVIDERS_DBUS_BUS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE, nullptr, on_name_acquired, nullptr, this, nullptr);
}
void CloudProviderManager::slotFolderListChanged(const Folder::Map &folderMap)
@@ -72,7 +72,7 @@ void CloudProviderManager::slotFolderListChanged(const Folder::Map &folderMap)
while (j.hasNext()) {
j.next();
if (!_map->contains(j.key())) {
auto *cpo = new CloudProviderWrapper(this, j.value(), _providerExporter);
auto *cpo = new CloudProviderWrapper(this, j.value(), _folder_index++, _providerExporter);
_map->insert(j.key(), cpo);
}
}

View File

@@ -36,6 +36,7 @@ public slots:
private:
QMap<QString, CloudProviderWrapper*> *_map;
unsigned int _folder_index;
};
#endif // CLOUDPROVIDERMANAGER_H

View File

@@ -33,13 +33,13 @@ using namespace OCC;
GSimpleActionGroup *actionGroup = nullptr;
CloudProviderWrapper::CloudProviderWrapper(QObject *parent, Folder *folder, CloudProvidersProviderExporter* cloudprovider) : QObject(parent)
CloudProviderWrapper::CloudProviderWrapper(QObject *parent, Folder *folder, int folderId, CloudProvidersProviderExporter* cloudprovider) : QObject(parent)
, _folder(folder)
{
GMenuModel *model;
GActionGroup *action_group;
_recentlyChanged = new QList<QPair<QString, QString>>();
QString accountName = QString("Account%1Folder%2").arg(folder->alias(), folder->accountState()->account()->id());
QString accountName = QString("Folder/%1").arg(folderId);
_cloudProvider = CLOUD_PROVIDERS_PROVIDER_EXPORTER(cloudprovider);
_cloudProviderAccount = cloud_providers_account_exporter_new(_cloudProvider, accountName.toUtf8().data());

View File

@@ -38,7 +38,7 @@ class CloudProviderWrapper : public QObject
{
Q_OBJECT
public:
explicit CloudProviderWrapper(QObject *parent = nullptr, Folder *folder = nullptr, CloudProvidersProviderExporter* cloudprovider = nullptr);
explicit CloudProviderWrapper(QObject *parent = nullptr, Folder *folder = nullptr, int folderId = 0, CloudProvidersProviderExporter* cloudprovider = nullptr);
~CloudProviderWrapper();
CloudProvidersAccountExporter* accountExporter();
Folder* folder();

View File

@@ -22,6 +22,8 @@
#include "connectionvalidator.h"
#include "account.h"
#include "accountstate.h"
#include "userinfo.h"
#include "networkjobs.h"
#include "clientproxy.h"
#include <creds/abstractcredentials.h>
@@ -34,9 +36,10 @@ Q_LOGGING_CATEGORY(lcConnectionValidator, "nextcloud.sync.connectionvalidator",
// This makes sure we get tried often enough without "ConnectionValidator already running"
static qint64 timeoutToUseMsec = qMax(1000, ConnectionValidator::DefaultCallingIntervalMsec - 5 * 1000);
ConnectionValidator::ConnectionValidator(AccountPtr account, QObject *parent)
ConnectionValidator::ConnectionValidator(AccountStatePtr accountState, QObject *parent)
: QObject(parent)
, _account(account)
, _accountState(accountState)
, _account(accountState->account())
, _isCheckingServerAndAuth(false)
{
}
@@ -44,7 +47,7 @@ ConnectionValidator::ConnectionValidator(AccountPtr account, QObject *parent)
void ConnectionValidator::checkServerAndAuth()
{
if (!_account) {
_errors << tr("No ownCloud account configured");
_errors << tr("No Nextcloud account configured");
reportResult(NotConfigured);
return;
}
@@ -265,10 +268,9 @@ void ConnectionValidator::ocsConfigReceived(const QJsonDocument &json, AccountPt
void ConnectionValidator::fetchUser()
{
JsonApiJob *job = new JsonApiJob(_account, QLatin1String("ocs/v1.php/cloud/user"), this);
job->setTimeout(timeoutToUseMsec);
QObject::connect(job, &JsonApiJob::jsonReceived, this, &ConnectionValidator::slotUserFetched);
job->start();
UserInfo *userInfo = new UserInfo(_accountState.data(), true, true, this);
QObject::connect(userInfo, &UserInfo::fetchedLastInfo, this, &ConnectionValidator::slotUserFetched);
userInfo->setActive(true);
}
bool ConnectionValidator::setAndCheckServerVersion(const QString &version)
@@ -300,34 +302,22 @@ bool ConnectionValidator::setAndCheckServerVersion(const QString &version)
return true;
}
void ConnectionValidator::slotUserFetched(const QJsonDocument &json)
void ConnectionValidator::slotUserFetched(UserInfo *userInfo)
{
QString user = json.object().value("ocs").toObject().value("data").toObject().value("id").toString();
if (!user.isEmpty()) {
_account->setDavUser(user);
}
QString displayName = json.object().value("ocs").toObject().value("data").toObject().value("display-name").toString();
if (!displayName.isEmpty()) {
_account->setDavDisplayName(displayName);
if(userInfo) {
userInfo->setActive(false);
userInfo->deleteLater();
}
#ifndef TOKEN_AUTH_ONLY
AvatarJob *job = new AvatarJob(_account, _account->davUser(), 128, this);
job->setTimeout(20 * 1000);
QObject::connect(job, &AvatarJob::avatarPixmap, this, &ConnectionValidator::slotAvatarImage);
job->start();
connect(_account->e2e(), &ClientSideEncryption::initializationFinished, this, &ConnectionValidator::reportConnected);
_account->e2e()->initialize();
#else
reportResult(Connected);
#endif
}
#ifndef TOKEN_AUTH_ONLY
void ConnectionValidator::slotAvatarImage(const QImage &img)
{
_account->setAvatar(img);
connect(_account->e2e(), &ClientSideEncryption::initializationFinished, this, &ConnectionValidator::reportConnected);
_account->e2e()->initialize();
}
void ConnectionValidator::reportConnected() {
reportResult(Connected);
}

View File

@@ -67,23 +67,20 @@ namespace OCC {
+---------------------------------+
|
fetchUser
PropfindJob
|
+-> slotUserFetched
AvatarJob
|
+-> slotAvatarImage -->
Utilizes the UserInfo class to fetch the user and avatar image
+-----------------------------------+
|
+-> Client Side Encryption Checks --+ --reportResult()
\endcode
*/
class UserInfo;
class ConnectionValidator : public QObject
{
Q_OBJECT
public:
explicit ConnectionValidator(AccountPtr account, QObject *parent = nullptr);
explicit ConnectionValidator(AccountStatePtr accountState, QObject *parent = nullptr);
enum Status {
Undefined,
@@ -125,13 +122,12 @@ protected slots:
void slotAuthSuccess();
void slotCapabilitiesRecieved(const QJsonDocument &);
void slotUserFetched(const QJsonDocument &);
#ifndef TOKEN_AUTH_ONLY
void slotAvatarImage(const QImage &img);
#endif
void slotUserFetched(UserInfo *userInfo);
private:
#ifndef TOKEN_AUTH_ONLY
void reportConnected();
#endif
void reportResult(Status status);
void checkServerCapabilities();
void fetchUser();
@@ -144,6 +140,7 @@ private:
bool setAndCheckServerVersion(const QString &version);
QStringList _errors;
AccountStatePtr _accountState;
AccountPtr _account;
bool _isCheckingServerAndAuth;
};

View File

@@ -14,10 +14,12 @@
*/
#include <QDesktopServices>
#include <QApplication>
#include <QClipboard>
#include <QTimer>
#include <QBuffer>
#include "account.h"
#include "creds/flow2auth.h"
#include "flow2auth.h"
#include <QJsonObject>
#include <QJsonDocument>
#include "theme.h"
@@ -28,6 +30,17 @@ namespace OCC {
Q_LOGGING_CATEGORY(lcFlow2auth, "nextcloud.sync.credentials.flow2auth", QtInfoMsg)
Flow2Auth::Flow2Auth(Account *account, QObject *parent)
: QObject(parent)
, _account(account)
, _isBusy(false)
, _hasToken(false)
{
_pollTimer.setInterval(1000);
QObject::connect(&_pollTimer, &QTimer::timeout, this, &Flow2Auth::slotPollTimerTimeout);
}
Flow2Auth::~Flow2Auth()
{
}
@@ -47,22 +60,46 @@ QUrl Flow2Auth::authorisationLink() const
void Flow2Auth::openBrowser()
{
_pollTimer.stop();
fetchNewToken(TokenAction::actionOpenBrowser);
}
void Flow2Auth::copyLinkToClipboard()
{
fetchNewToken(TokenAction::actionCopyLinkToClipboard);
}
void Flow2Auth::fetchNewToken(const TokenAction action)
{
if(_isBusy)
return;
_isBusy = true;
_hasToken = false;
emit statusChanged(PollStatus::statusFetchToken, 0);
// Step 1: Initiate a login, do an anonymous POST request
QUrl url = Utility::concatUrlPath(_account->url().toString(), QLatin1String("/index.php/login/v2"));
auto job = _account->sendRequest("POST", url);
// add 'Content-Length: 0' header (see https://github.com/nextcloud/desktop/issues/1473)
QNetworkRequest req;
req.setHeader(QNetworkRequest::ContentLengthHeader, "0");
auto job = _account->sendRequest("POST", url, req);
job->setTimeout(qMin(30 * 1000ll, job->timeoutMsec()));
QObject::connect(job, &SimpleNetworkJob::finishedSignal, this, [this](QNetworkReply *reply) {
QObject::connect(job, &SimpleNetworkJob::finishedSignal, this, [this, action](QNetworkReply *reply) {
auto jsonData = reply->readAll();
QJsonParseError jsonParseError;
QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object();
QString pollToken, pollEndpoint, loginUrl;
QString pollToken = json.value("poll").toObject().value("token").toString();
QString pollEndpoint = json.value("poll").toObject().value("endpoint").toString();
QUrl loginUrl = json["login"].toString();
if (reply->error() == QNetworkReply::NoError && jsonParseError.error == QJsonParseError::NoError
&& !json.isEmpty()) {
pollToken = json.value("poll").toObject().value("token").toString();
pollEndpoint = json.value("poll").toObject().value("endpoint").toString();
loginUrl = json["login"].toString();
}
if (reply->error() != QNetworkReply::NoError || jsonParseError.error != QJsonParseError::NoError
|| json.isEmpty() || pollToken.isEmpty() || pollEndpoint.isEmpty() || loginUrl.isEmpty()) {
@@ -81,7 +118,9 @@ void Flow2Auth::openBrowser()
errorReason = tr("The reply from the server did not contain all expected fields");
}
qCWarning(lcFlow2auth) << "Error when getting the loginUrl" << json << errorReason;
emit result(Error);
emit result(Error, errorReason);
_pollTimer.stop();
_isBusy = false;
return;
}
@@ -95,23 +134,50 @@ void Flow2Auth::openBrowser()
ConfigFile cfg;
std::chrono::milliseconds polltime = cfg.remotePollInterval();
qCInfo(lcFlow2auth) << "setting remote poll timer interval to" << polltime.count() << "msec";
_pollTimer.setInterval(polltime.count());
QObject::connect(&_pollTimer, &QTimer::timeout, this, &Flow2Auth::slotPollTimerTimeout);
_pollTimer.start();
_secondsInterval = (polltime.count() / 1000);
_secondsLeft = _secondsInterval;
emit statusChanged(PollStatus::statusPollCountdown, _secondsLeft);
// Try to open Browser
if (!QDesktopServices::openUrl(authorisationLink())) {
// We cannot open the browser, then we claim we don't support Flow2Auth.
// Our UI callee should ask the user to copy and open the link.
emit result(NotSupported, QString());
if(!_pollTimer.isActive()) {
_pollTimer.start();
}
switch(action)
{
case actionOpenBrowser:
// Try to open Browser
if (!QDesktopServices::openUrl(authorisationLink())) {
// We cannot open the browser, then we claim we don't support Flow2Auth.
// Our UI callee will ask the user to copy and open the link.
emit result(NotSupported);
}
break;
case actionCopyLinkToClipboard:
QApplication::clipboard()->setText(authorisationLink().toString(QUrl::FullyEncoded));
emit statusChanged(PollStatus::statusCopyLinkToClipboard, 0);
break;
}
_isBusy = false;
_hasToken = true;
});
}
void Flow2Auth::slotPollTimerTimeout()
{
_pollTimer.stop();
if(_isBusy || !_hasToken)
return;
_isBusy = true;
_secondsLeft--;
if(_secondsLeft > 0) {
emit statusChanged(PollStatus::statusPollCountdown, _secondsLeft);
_isBusy = false;
return;
}
emit statusChanged(PollStatus::statusPollNow, 0);
// Step 2: Poll
QNetworkRequest req;
@@ -128,10 +194,15 @@ void Flow2Auth::slotPollTimerTimeout()
auto jsonData = reply->readAll();
QJsonParseError jsonParseError;
QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object();
QUrl serverUrl;
QString loginName, appPassword;
QUrl serverUrl = json["server"].toString();
QString loginName = json["loginName"].toString();
QString appPassword = json["appPassword"].toString();
if (reply->error() == QNetworkReply::NoError && jsonParseError.error == QJsonParseError::NoError
&& !json.isEmpty()) {
serverUrl = json["server"].toString();
loginName = json["loginName"].toString();
appPassword = json["appPassword"].toString();
}
if (reply->error() != QNetworkReply::NoError || jsonParseError.error != QJsonParseError::NoError
|| json.isEmpty() || serverUrl.isEmpty() || loginName.isEmpty() || appPassword.isEmpty()) {
@@ -151,26 +222,50 @@ void Flow2Auth::slotPollTimerTimeout()
}
qCDebug(lcFlow2auth) << "Error when polling for the appPassword" << json << errorReason;
// We get a 404 until authentication is done, so don't show this error in the GUI.
if(reply->error() != QNetworkReply::ContentNotFoundError)
emit result(Error, errorReason);
// Forget sensitive data
appPassword.clear();
loginName.clear();
// Failed: poll again
_pollTimer.start();
_secondsLeft = _secondsInterval;
_isBusy = false;
return;
}
_pollTimer.stop();
// Success
qCInfo(lcFlow2auth) << "Success getting the appPassword for user: " << loginName << ", server: " << serverUrl.toString();
_account->setUrl(serverUrl);
emit result(LoggedIn, loginName, appPassword);
emit result(LoggedIn, QString(), loginName, appPassword);
// Forget sensitive data
appPassword.clear();
loginName.clear();
_loginUrl.clear();
_pollToken.clear();
_pollEndpoint.clear();
_isBusy = false;
_hasToken = false;
});
}
void Flow2Auth::slotPollNow()
{
// poll now if we're not already doing so
if(_isBusy || !_hasToken)
return;
_secondsLeft = 1;
slotPollTimerTimeout();
}
} // namespace OCC

View File

@@ -25,17 +25,23 @@ namespace OCC {
* Job that does the authorization, grants and fetches the access token via Login Flow v2
*
* See: https://docs.nextcloud.com/server/latest/developer_manual/client_apis/LoginFlow/index.html#login-flow-v2
*
*/
class Flow2Auth : public QObject
{
Q_OBJECT
public:
Flow2Auth(Account *account, QObject *parent)
: QObject(parent)
, _account(account)
{
}
enum TokenAction {
actionOpenBrowser = 1,
actionCopyLinkToClipboard
};
enum PollStatus {
statusPollCountdown = 1,
statusPollNow,
statusFetchToken,
statusCopyLinkToClipboard
};
Flow2Auth(Account *account, QObject *parent);
~Flow2Auth();
enum Result { NotSupported,
@@ -44,6 +50,7 @@ public:
Q_ENUM(Result);
void start();
void openBrowser();
void copyLinkToClipboard();
QUrl authorisationLink() const;
signals:
@@ -51,18 +58,29 @@ signals:
* The state has changed.
* when logged in, appPassword has the value of the app password.
*/
void result(Flow2Auth::Result result, const QString &user = QString(), const QString &appPassword = QString());
void result(Flow2Auth::Result result, const QString &errorString = QString(),
const QString &user = QString(), const QString &appPassword = QString());
void statusChanged(const PollStatus status, int secondsLeft);
public slots:
void slotPollNow();
private slots:
void slotPollTimerTimeout();
private:
void fetchNewToken(const TokenAction action);
Account *_account;
QUrl _loginUrl;
QString _pollToken;
QString _pollEndpoint;
QTimer _pollTimer;
int _secondsLeft;
int _secondsInterval;
bool _isBusy;
bool _hasToken;
};
} // namespace OCC

View File

@@ -0,0 +1,221 @@
/*
* Copyright (C) by Michael Schuster <michael@nextcloud.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 "account.h"
#include "keychainchunk.h"
#include "theme.h"
#include "networkjobs.h"
#include "configfile.h"
#include "creds/abstractcredentials.h"
using namespace QKeychain;
namespace OCC {
Q_LOGGING_CATEGORY(lcKeychainChunk, "nextcloud.sync.credentials.keychainchunk", QtInfoMsg)
namespace KeychainChunk {
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
static void addSettingsToJob(Account *account, QKeychain::Job *job)
{
Q_UNUSED(account)
auto settings = ConfigFile::settingsWithGroup(Theme::instance()->appName());
settings->setParent(job); // make the job parent to make setting deleted properly
job->setSettings(settings.release());
}
#endif
/*
* Job
*/
Job::Job(QObject *parent)
: QObject(parent)
{
_serviceName = Theme::instance()->appName();
}
/*
* WriteJob
*/
WriteJob::WriteJob(Account *account, const QString &key, const QByteArray &data, QObject *parent)
: Job(parent)
{
_account = account;
_key = key;
// Windows workaround: Split the private key into chunks of 2048 bytes,
// to allow 4k (4096 bit) keys to be saved (obey Windows's limits)
_chunkBuffer = data;
_chunkCount = 0;
}
void WriteJob::start()
{
slotWriteJobDone(nullptr);
}
void WriteJob::slotWriteJobDone(QKeychain::Job *incomingJob)
{
QKeychain::WritePasswordJob *writeJob = static_cast<QKeychain::WritePasswordJob *>(incomingJob);
// errors?
if (writeJob) {
_error = writeJob->error();
_errorString = writeJob->errorString();
if (writeJob->error() != NoError) {
qCWarning(lcKeychainChunk) << "Error while writing" << writeJob->key() << "chunk" << writeJob->errorString();
_chunkBuffer.clear();
}
}
// write a chunk if there is any in the buffer
if (!_chunkBuffer.isEmpty()) {
#if defined(Q_OS_WIN)
// Windows workaround: Split the data into chunks of 2048 bytes,
// to allow 4k (4096 bit) keys to be saved (obey Windows's limits)
auto chunk = _chunkBuffer.left(KeychainChunk::ChunkSize);
_chunkBuffer = _chunkBuffer.right(_chunkBuffer.size() - chunk.size());
#else
// write full data in one chunk on non-Windows, as usual
auto chunk = _chunkBuffer;
_chunkBuffer.clear();
#endif
auto index = (_chunkCount++);
// keep the limit
if (_chunkCount > KeychainChunk::MaxChunks) {
qCWarning(lcKeychainChunk) << "Maximum chunk count exceeded while writing" << writeJob->key() << "chunk" << QString::number(index) << "cutting off after" << QString::number(KeychainChunk::MaxChunks) << "chunks";
writeJob->deleteLater();
_chunkBuffer.clear();
emit finished(this);
return;
}
const QString kck = AbstractCredentials::keychainKey(
_account->url().toString(),
_key + (index > 0 ? (QString(".") + QString::number(index)) : QString()),
_account->id());
QKeychain::WritePasswordJob *job = new QKeychain::WritePasswordJob(_serviceName);
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
addSettingsToJob(_account, job);
#endif
job->setInsecureFallback(_insecureFallback);
connect(job, &QKeychain::Job::finished, this, &KeychainChunk::WriteJob::slotWriteJobDone);
// only add the key's (sub)"index" after the first element, to stay compatible with older versions and non-Windows
job->setKey(kck);
job->setBinaryData(chunk);
job->start();
chunk.clear();
} else {
emit finished(this);
}
writeJob->deleteLater();
}
/*
* ReadJob
*/
ReadJob::ReadJob(Account *account, const QString &key, const bool &keychainMigration, QObject *parent)
: Job(parent)
{
_account = account;
_key = key;
_keychainMigration = keychainMigration;
_chunkCount = 0;
_chunkBuffer.clear();
}
void ReadJob::start()
{
_chunkCount = 0;
_chunkBuffer.clear();
const QString kck = AbstractCredentials::keychainKey(
_account->url().toString(),
_key,
_keychainMigration ? QString() : _account->id());
QKeychain::ReadPasswordJob *job = new QKeychain::ReadPasswordJob(_serviceName);
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
addSettingsToJob(_account, job);
#endif
job->setInsecureFallback(_insecureFallback);
job->setKey(kck);
connect(job, &QKeychain::Job::finished, this, &KeychainChunk::ReadJob::slotReadJobDone);
job->start();
}
void ReadJob::slotReadJobDone(QKeychain::Job *incomingJob)
{
// Errors or next chunk?
QKeychain::ReadPasswordJob *readJob = static_cast<QKeychain::ReadPasswordJob *>(incomingJob);
if (readJob) {
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
_chunkBuffer.append(readJob->binaryData());
_chunkCount++;
#if defined(Q_OS_WIN)
// try to fetch next chunk
if (_chunkCount < KeychainChunk::MaxChunks) {
const QString kck = AbstractCredentials::keychainKey(
_account->url().toString(),
_key + QString(".") + QString::number(_chunkCount),
_keychainMigration ? QString() : _account->id());
QKeychain::ReadPasswordJob *job = new QKeychain::ReadPasswordJob(_serviceName);
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
addSettingsToJob(_account, job);
#endif
job->setInsecureFallback(_insecureFallback);
job->setKey(kck);
connect(job, &QKeychain::Job::finished, this, &KeychainChunk::ReadJob::slotReadJobDone);
job->start();
readJob->deleteLater();
return;
} else {
qCWarning(lcKeychainChunk) << "Maximum chunk count for" << readJob->key() << "reached, ignoring after" << KeychainChunk::MaxChunks;
}
#endif
} else {
if (readJob->error() != QKeychain::Error::EntryNotFound ||
((readJob->error() == QKeychain::Error::EntryNotFound) && _chunkCount == 0)) {
_error = readJob->error();
_errorString = readJob->errorString();
qCWarning(lcKeychainChunk) << "Unable to read" << readJob->key() << "chunk" << QString::number(_chunkCount) << readJob->errorString();
}
}
readJob->deleteLater();
}
emit finished(this);
}
} // namespace KeychainChunk
} // namespace OCC

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) by Michael Schuster <michael@nextcloud.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
#ifndef KEYCHAINCHUNK_H
#define KEYCHAINCHUNK_H
#include <QObject>
#include <keychain.h>
#include "accountfwd.h"
// We don't support insecure fallback
// #define KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK
namespace OCC {
namespace KeychainChunk {
/*
* Workaround for Windows:
*
* Split the keychain entry's data into chunks of 2048 bytes,
* to allow 4k (4096 bit) keys / large certs to be saved (see limits in webflowcredentials.h)
*/
static constexpr int ChunkSize = 2048;
static constexpr int MaxChunks = 10;
/*
* @brief: Abstract base class for KeychainChunk jobs.
*/
class Job : public QObject {
Q_OBJECT
public:
Job(QObject *parent = nullptr);
const QKeychain::Error error() const {
return _error;
}
const QString errorString() const {
return _errorString;
}
QByteArray binaryData() const {
return _chunkBuffer;
}
const bool insecureFallback() const {
return _insecureFallback;
}
// If we use it but don't support insecure fallback, give us nice compilation errors ;p
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
void setInsecureFallback(const bool &insecureFallback)
{
_insecureFallback = insecureFallback;
}
#endif
protected:
QString _serviceName;
Account *_account;
QString _key;
bool _insecureFallback = false;
bool _keychainMigration = false;
QKeychain::Error _error = QKeychain::NoError;
QString _errorString;
int _chunkCount = 0;
QByteArray _chunkBuffer;
}; // class Job
/*
* @brief: Simple wrapper class for QKeychain::WritePasswordJob, splits too large keychain entry's data into chunks on Windows
*/
class WriteJob : public KeychainChunk::Job {
Q_OBJECT
public:
WriteJob(Account *account, const QString &key, const QByteArray &data, QObject *parent = nullptr);
void start();
signals:
void finished(KeychainChunk::WriteJob *incomingJob);
private slots:
void slotWriteJobDone(QKeychain::Job *incomingJob);
}; // class WriteJob
/*
* @brief: Simple wrapper class for QKeychain::ReadPasswordJob, splits too large keychain entry's data into chunks on Windows
*/
class ReadJob : public KeychainChunk::Job {
Q_OBJECT
public:
ReadJob(Account *account, const QString &key, const bool &keychainMigration, QObject *parent = nullptr);
void start();
signals:
void finished(KeychainChunk::ReadJob *incomingJob);
private slots:
void slotReadJobDone(QKeychain::Job *incomingJob);
}; // class ReadJob
} // namespace KeychainChunk
} // namespace OCC
#endif // KEYCHAINCHUNK_H

View File

@@ -18,6 +18,7 @@
#include "theme.h"
#include "wizard/webview.h"
#include "webflowcredentialsdialog.h"
#include "keychainchunk.h"
using namespace QKeychain;
@@ -75,6 +76,7 @@ private:
QPointer<const WebFlowCredentials> _cred;
};
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
static void addSettingsToJob(Account *account, QKeychain::Job *job)
{
Q_UNUSED(account)
@@ -82,6 +84,7 @@ static void addSettingsToJob(Account *account, QKeychain::Job *job)
settings->setParent(job); // make the job parent to make setting deleted properly
job->setSettings(settings.release());
}
#endif
WebFlowCredentials::WebFlowCredentials()
: _ready(false)
@@ -147,25 +150,32 @@ void WebFlowCredentials::fetchFromKeychain() {
}
void WebFlowCredentials::askFromUser() {
// LoginFlowV2 > WebViewFlow > OAuth > Shib > Basic
bool useFlow2 = (_account->serverVersionInt() >= Account::makeServerVersion(16, 0, 0));
// Determine if the old flow has to be used (GS for now)
// Do a DetermineAuthTypeJob to make sure that the server is still using Flow2
DetermineAuthTypeJob *job = new DetermineAuthTypeJob(_account->sharedFromThis(), this);
connect(job, &DetermineAuthTypeJob::authType, [this](DetermineAuthTypeJob::AuthType type) {
// LoginFlowV2 > WebViewFlow > OAuth > Shib > Basic
bool useFlow2 = (type != DetermineAuthTypeJob::WebViewFlow);
_askDialog = new WebFlowCredentialsDialog(_account, useFlow2);
_askDialog = new WebFlowCredentialsDialog(_account, useFlow2);
if (!useFlow2) {
QUrl url = _account->url();
QString path = url.path() + "/index.php/login/flow";
url.setPath(path);
_askDialog->setUrl(url);
}
if (!useFlow2) {
QUrl url = _account->url();
QString path = url.path() + "/index.php/login/flow";
url.setPath(path);
_askDialog->setUrl(url);
}
QString msg = tr("You have been logged out of %1 as user %2. Please login again")
.arg(_account->displayName(), _user);
_askDialog->setInfo(msg);
QString msg = tr("You have been logged out of %1 as user %2. Please login again")
.arg(_account->displayName(), _user);
_askDialog->setInfo(msg);
_askDialog->show();
_askDialog->show();
connect(_askDialog, &WebFlowCredentialsDialog::urlCatched, this, &WebFlowCredentials::slotAskFromUserCredentialsProvided);
connect(_askDialog, &WebFlowCredentialsDialog::urlCatched, this, &WebFlowCredentials::slotAskFromUserCredentialsProvided);
connect(_askDialog, &WebFlowCredentialsDialog::onClose, this, &WebFlowCredentials::slotAskFromUserCancelled);
});
job->start();
qCDebug(lcWebFlowCredentials()) << "User needs to reauth!";
}
@@ -173,7 +183,11 @@ void WebFlowCredentials::askFromUser() {
void WebFlowCredentials::slotAskFromUserCredentialsProvided(const QString &user, const QString &pass, const QString &host) {
Q_UNUSED(host)
if (_user != user) {
// Compare the re-entered username case-insensitive and save the new value (avoid breaking the account)
// See issue: https://github.com/nextcloud/desktop/issues/1741
if (QString::compare(_user, user, Qt::CaseInsensitive) == 0) {
_user = user;
} else {
qCInfo(lcWebFlowCredentials()) << "Authed with the wrong user!";
QString msg = tr("Please login with the user: %1")
@@ -199,10 +213,18 @@ void WebFlowCredentials::slotAskFromUserCredentialsProvided(const QString &user,
emit asked();
_askDialog->close();
delete _askDialog;
_askDialog->deleteLater();
_askDialog = nullptr;
}
void WebFlowCredentials::slotAskFromUserCancelled() {
qCDebug(lcWebFlowCredentials()) << "User cancelled reauth!";
emit asked();
_askDialog->deleteLater();
_askDialog = nullptr;
}
bool WebFlowCredentials::stillValid(QNetworkReply *reply) {
if (reply->error() != QNetworkReply::NoError) {
@@ -223,33 +245,32 @@ void WebFlowCredentials::persist() {
// write cert if there is one
if (!_clientSslCertificate.isNull()) {
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
connect(job, &Job::finished, this, &WebFlowCredentials::slotWriteClientCertPEMJobDone);
job->setKey(keychainKey(_account->url().toString(), _user + clientCertificatePEMC, _account->id()));
job->setBinaryData(_clientSslCertificate.toPem());
auto *job = new KeychainChunk::WriteJob(_account,
_user + clientCertificatePEMC,
_clientSslCertificate.toPem());
connect(job, &KeychainChunk::WriteJob::finished, this, &WebFlowCredentials::slotWriteClientCertPEMJobDone);
job->start();
} else {
// no cert, just write credentials
slotWriteClientCertPEMJobDone();
slotWriteClientCertPEMJobDone(nullptr);
}
}
void WebFlowCredentials::slotWriteClientCertPEMJobDone()
void WebFlowCredentials::slotWriteClientCertPEMJobDone(KeychainChunk::WriteJob *writeJob)
{
if(writeJob)
writeJob->deleteLater();
// write ssl key if there is one
if (!_clientSslKey.isNull()) {
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
connect(job, &Job::finished, this, &WebFlowCredentials::slotWriteClientKeyPEMJobDone);
job->setKey(keychainKey(_account->url().toString(), _user + clientKeyPEMC, _account->id()));
job->setBinaryData(_clientSslKey.toPem());
auto *job = new KeychainChunk::WriteJob(_account,
_user + clientKeyPEMC,
_clientSslKey.toPem());
connect(job, &KeychainChunk::WriteJob::finished, this, &WebFlowCredentials::slotWriteClientKeyPEMJobDone);
job->start();
} else {
// no key, just write credentials
slotWriteClientKeyPEMJobDone();
slotWriteClientKeyPEMJobDone(nullptr);
}
}
@@ -264,7 +285,7 @@ void WebFlowCredentials::writeSingleClientCaCertPEM()
// keep the limit
if (index > (_clientSslCaCertificatesMaxCount - 1)) {
qCWarning(lcWebFlowCredentials) << "Maximum client CA cert count exceeded while writing slot" << QString::number(index) << "), cutting off after " << QString::number(_clientSslCaCertificatesMaxCount) << "certs";
qCWarning(lcWebFlowCredentials) << "Maximum client CA cert count exceeded while writing slot" << QString::number(index) << "cutting off after" << QString::number(_clientSslCaCertificatesMaxCount) << "certs";
_clientSslCaCertificatesWriteQueue.clear();
@@ -272,20 +293,21 @@ void WebFlowCredentials::writeSingleClientCaCertPEM()
return;
}
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
connect(job, &Job::finished, this, &WebFlowCredentials::slotWriteClientCaCertsPEMJobDone);
job->setKey(keychainKey(_account->url().toString(), _user + clientCaCertificatePEMC + QString::number(index), _account->id()));
job->setBinaryData(cert.toPem());
auto *job = new KeychainChunk::WriteJob(_account,
_user + clientCaCertificatePEMC + QString::number(index),
cert.toPem());
connect(job, &KeychainChunk::WriteJob::finished, this, &WebFlowCredentials::slotWriteClientCaCertsPEMJobDone);
job->start();
} else {
slotWriteClientCaCertsPEMJobDone(nullptr);
}
}
void WebFlowCredentials::slotWriteClientKeyPEMJobDone()
void WebFlowCredentials::slotWriteClientKeyPEMJobDone(KeychainChunk::WriteJob *writeJob)
{
if(writeJob)
writeJob->deleteLater();
_clientSslCaCertificatesWriteQueue.clear();
// write ca certs if there are any
@@ -300,16 +322,16 @@ void WebFlowCredentials::slotWriteClientKeyPEMJobDone()
}
}
void WebFlowCredentials::slotWriteClientCaCertsPEMJobDone(QKeychain::Job *incomingJob)
void WebFlowCredentials::slotWriteClientCaCertsPEMJobDone(KeychainChunk::WriteJob *writeJob)
{
// errors / next ca cert?
if (incomingJob && !_clientSslCaCertificates.isEmpty()) {
WritePasswordJob *writeJob = static_cast<WritePasswordJob *>(incomingJob);
if (writeJob && !_clientSslCaCertificates.isEmpty()) {
if (writeJob->error() != NoError) {
qCWarning(lcWebFlowCredentials) << "Error while writing client CA cert" << writeJob->errorString();
}
writeJob->deleteLater();
if (!_clientSslCaCertificatesWriteQueue.isEmpty()) {
// next ca cert
writeSingleClientCaCertPEM();
@@ -319,7 +341,9 @@ void WebFlowCredentials::slotWriteClientCaCertsPEMJobDone(QKeychain::Job *incomi
// done storing ca certs, time for the password
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
addSettingsToJob(_account, job);
#endif
job->setInsecureFallback(false);
connect(job, &Job::finished, this, &WebFlowCredentials::slotWriteJobDone);
job->setKey(keychainKey(_account->url().toString(), _user, _account->id()));
@@ -358,6 +382,8 @@ void WebFlowCredentials::forgetSensitiveData() {
fetchUser();
_account->deleteAppPassword();
const QString kck = keychainKey(_account->url().toString(), _user, _account->id());
if (kck.isEmpty()) {
qCDebug(lcWebFlowCredentials()) << "InvalidateToken: User is empty, bailing out!";
@@ -367,18 +393,15 @@ void WebFlowCredentials::forgetSensitiveData() {
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
job->setInsecureFallback(false);
job->setKey(kck);
connect(job, &Job::finished, this, [](QKeychain::Job *job) {
DeletePasswordJob *djob = qobject_cast<DeletePasswordJob *>(job);
djob->deleteLater();
});
job->start();
invalidateToken();
/* IMPORTANT
/* TODO: For "Log out" & "Remove account": Remove client CA certs and KEY!
*
* Disabled as long as selecting another cert is not supported by the UI.
*
* Being able to specify a new certificate is important anyway: expiry etc.
*/
//deleteKeychainEntries();
deleteKeychainEntries();
}
void WebFlowCredentials::setAccount(Account *account) {
@@ -416,34 +439,31 @@ void WebFlowCredentials::slotFinished(QNetworkReply *reply) {
if (reply->error() == QNetworkReply::NoError) {
_credentialsValid = true;
/// Used later for remote wipe
_account->writeAppPasswordOnce(_password);
}
}
void WebFlowCredentials::fetchFromKeychainHelper() {
// Read client cert from keychain
const QString kck = keychainKey(
_account->url().toString(),
_user + clientCertificatePEMC,
_keychainMigration ? QString() : _account->id());
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
job->setKey(kck);
connect(job, &Job::finished, this, &WebFlowCredentials::slotReadClientCertPEMJobDone);
auto *job = new KeychainChunk::ReadJob(_account,
_user + clientCertificatePEMC,
_keychainMigration);
connect(job, &KeychainChunk::ReadJob::finished, this, &WebFlowCredentials::slotReadClientCertPEMJobDone);
job->start();
}
void WebFlowCredentials::slotReadClientCertPEMJobDone(QKeychain::Job *incomingJob)
void WebFlowCredentials::slotReadClientCertPEMJobDone(KeychainChunk::ReadJob *readJob)
{
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
Q_ASSERT(!incomingJob->insecureFallback()); // If insecureFallback is set, the next test would be pointless
if (_retryOnKeyChainError && (incomingJob->error() == QKeychain::NoBackendAvailable
|| incomingJob->error() == QKeychain::OtherError)) {
Q_ASSERT(!readJob->insecureFallback()); // If insecureFallback is set, the next test would be pointless
if (_retryOnKeyChainError && (readJob->error() == QKeychain::NoBackendAvailable
|| readJob->error() == QKeychain::OtherError)) {
// Could be that the backend was not yet available. Wait some extra seconds.
// (Issues #4274 and #6522)
// (For kwallet, the error is OtherError instead of NoBackendAvailable, maybe a bug in QtKeychain)
qCInfo(lcWebFlowCredentials) << "Backend unavailable (yet?) Retrying in a few seconds." << incomingJob->errorString();
qCInfo(lcWebFlowCredentials) << "Backend unavailable (yet?) Retrying in a few seconds." << readJob->errorString();
QTimer::singleShot(10000, this, &WebFlowCredentials::fetchFromKeychainHelper);
_retryOnKeyChainError = false;
return;
@@ -452,7 +472,6 @@ void WebFlowCredentials::slotReadClientCertPEMJobDone(QKeychain::Job *incomingJo
#endif
// Store PEM in memory
ReadPasswordJob *readJob = static_cast<ReadPasswordJob *>(incomingJob);
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(readJob->binaryData(), QSsl::Pem);
if (sslCertificateList.length() >= 1) {
@@ -460,25 +479,19 @@ void WebFlowCredentials::slotReadClientCertPEMJobDone(QKeychain::Job *incomingJo
}
}
// Load key too
const QString kck = keychainKey(
_account->url().toString(),
_user + clientKeyPEMC,
_keychainMigration ? QString() : _account->id());
readJob->deleteLater();
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
job->setKey(kck);
connect(job, &Job::finished, this, &WebFlowCredentials::slotReadClientKeyPEMJobDone);
// Load key too
auto *job = new KeychainChunk::ReadJob(_account,
_user + clientKeyPEMC,
_keychainMigration);
connect(job, &KeychainChunk::ReadJob::finished, this, &WebFlowCredentials::slotReadClientKeyPEMJobDone);
job->start();
}
void WebFlowCredentials::slotReadClientKeyPEMJobDone(QKeychain::Job *incomingJob)
void WebFlowCredentials::slotReadClientKeyPEMJobDone(KeychainChunk::ReadJob *readJob)
{
// Store key in memory
ReadPasswordJob *readJob = static_cast<ReadPasswordJob *>(incomingJob);
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
QByteArray clientKeyPEM = readJob->binaryData();
// FIXME Unfortunately Qt has a bug and we can't just use QSsl::Opaque to let it
@@ -493,8 +506,13 @@ void WebFlowCredentials::slotReadClientKeyPEMJobDone(QKeychain::Job *incomingJob
if (_clientSslKey.isNull()) {
qCWarning(lcWebFlowCredentials) << "Could not load SSL key into Qt!";
}
clientKeyPEM.clear();
} else {
qCWarning(lcWebFlowCredentials) << "Unable to read client key" << readJob->errorString();
}
readJob->deleteLater();
// Start fetching client CA certs
_clientSslCaCertificates.clear();
@@ -505,28 +523,20 @@ void WebFlowCredentials::readSingleClientCaCertPEM()
{
// try to fetch a client ca cert
if (_clientSslCaCertificates.count() < _clientSslCaCertificatesMaxCount) {
const QString kck = keychainKey(
_account->url().toString(),
_user + clientCaCertificatePEMC + QString::number(_clientSslCaCertificates.count()),
_keychainMigration ? QString() : _account->id());
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
addSettingsToJob(_account, job);
job->setInsecureFallback(false);
job->setKey(kck);
connect(job, &Job::finished, this, &WebFlowCredentials::slotReadClientCaCertsPEMJobDone);
auto *job = new KeychainChunk::ReadJob(_account,
_user + clientCaCertificatePEMC + QString::number(_clientSslCaCertificates.count()),
_keychainMigration);
connect(job, &KeychainChunk::ReadJob::finished, this, &WebFlowCredentials::slotReadClientCaCertsPEMJobDone);
job->start();
} else {
qCWarning(lcWebFlowCredentials) << "Maximum client CA cert count exceeded while reading, ignoring after " << _clientSslCaCertificatesMaxCount;
qCWarning(lcWebFlowCredentials) << "Maximum client CA cert count exceeded while reading, ignoring after" << _clientSslCaCertificatesMaxCount;
slotReadClientCaCertsPEMJobDone(nullptr);
}
}
void WebFlowCredentials::slotReadClientCaCertsPEMJobDone(QKeychain::Job *incomingJob) {
// Store key in memory
ReadPasswordJob *readJob = static_cast<ReadPasswordJob *>(incomingJob);
void WebFlowCredentials::slotReadClientCaCertsPEMJobDone(KeychainChunk::ReadJob *readJob) {
// Store cert in memory
if (readJob) {
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(readJob->binaryData(), QSsl::Pem);
@@ -534,15 +544,19 @@ void WebFlowCredentials::slotReadClientCaCertsPEMJobDone(QKeychain::Job *incomin
_clientSslCaCertificates.append(sslCertificateList.at(0));
}
readJob->deleteLater();
// try next cert
readSingleClientCaCertPEM();
return;
} else {
if (readJob->error() != QKeychain::Error::EntryNotFound ||
(readJob->error() == QKeychain::Error::EntryNotFound) && _clientSslCaCertificates.count() == 0) {
qCWarning(lcWebFlowCredentials) << "Unable to read client CA cert slot " << QString::number(_clientSslCaCertificates.count()) << readJob->errorString();
((readJob->error() == QKeychain::Error::EntryNotFound) && _clientSslCaCertificates.count() == 0)) {
qCWarning(lcWebFlowCredentials) << "Unable to read client CA cert slot" << QString::number(_clientSslCaCertificates.count()) << readJob->errorString();
}
}
readJob->deleteLater();
}
// Now fetch the actual server password
@@ -552,7 +566,9 @@ void WebFlowCredentials::slotReadClientCaCertsPEMJobDone(QKeychain::Job *incomin
_keychainMigration ? QString() : _account->id());
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
addSettingsToJob(_account, job);
#endif
job->setInsecureFallback(false);
job->setKey(kck);
connect(job, &Job::finished, this, &WebFlowCredentials::slotReadPasswordJobDone);
@@ -560,7 +576,7 @@ void WebFlowCredentials::slotReadClientCaCertsPEMJobDone(QKeychain::Job *incomin
}
void WebFlowCredentials::slotReadPasswordJobDone(Job *incomingJob) {
QKeychain::ReadPasswordJob *job = static_cast<ReadPasswordJob *>(incomingJob);
QKeychain::ReadPasswordJob *job = qobject_cast<ReadPasswordJob *>(incomingJob);
QKeychain::Error error = job->error();
// If we could not find the entry try the old entries
@@ -583,6 +599,8 @@ void WebFlowCredentials::slotReadPasswordJobDone(Job *incomingJob) {
}
emit fetched();
job->deleteLater();
// If keychain data was read from legacy location, wipe these entries and store new ones
if (_keychainMigration && _ready) {
_keychainMigration = false;
@@ -593,23 +611,60 @@ void WebFlowCredentials::slotReadPasswordJobDone(Job *incomingJob) {
}
void WebFlowCredentials::deleteKeychainEntries(bool oldKeychainEntries) {
auto startDeleteJob = [this, oldKeychainEntries](QString user) {
auto startDeleteJob = [this, oldKeychainEntries](QString key) {
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
addSettingsToJob(_account, job);
job->setInsecureFallback(true);
#endif
job->setInsecureFallback(false);
job->setKey(keychainKey(_account->url().toString(),
user,
key,
oldKeychainEntries ? QString() : _account->id()));
connect(job, &Job::finished, this, [](QKeychain::Job *job) {
DeletePasswordJob *djob = qobject_cast<DeletePasswordJob *>(job);
djob->deleteLater();
});
job->start();
};
startDeleteJob(_user);
startDeleteJob(_user + clientKeyPEMC);
startDeleteJob(_user + clientCertificatePEMC);
for (auto i = 0; i < _clientSslCaCertificates.count(); i++) {
startDeleteJob(_user + clientCaCertificatePEMC + QString::number(i));
/* IMPORTANT - remove later - FIXME MS@2019-12-07 -->
* TODO: For "Log out" & "Remove account": Remove client CA certs and KEY!
*
* Disabled as long as selecting another cert is not supported by the UI.
*
* Being able to specify a new certificate is important anyway: expiry etc.
*
* We introduce this dirty hack here, to allow deleting them upon Remote Wipe.
*/
if(_account->isRemoteWipeRequested_HACK()) {
// <-- FIXME MS@2019-12-07
startDeleteJob(_user + clientKeyPEMC);
startDeleteJob(_user + clientCertificatePEMC);
for (auto i = 0; i < _clientSslCaCertificates.count(); i++) {
startDeleteJob(_user + clientCaCertificatePEMC + QString::number(i));
}
#if defined(Q_OS_WIN)
// Also delete key / cert sub-chunks (Windows workaround)
// The first chunk (0) has no suffix, to stay compatible with older versions and non-Windows
for (auto chunk = 1; chunk < KeychainChunk::MaxChunks; chunk++) {
const QString strChunkSuffix = QString(".") + QString::number(chunk);
startDeleteJob(_user + clientKeyPEMC + strChunkSuffix);
startDeleteJob(_user + clientCertificatePEMC + strChunkSuffix);
for (auto i = 0; i < _clientSslCaCertificates.count(); i++) {
startDeleteJob(_user + clientCaCertificatePEMC + QString::number(i));
}
}
#endif
// FIXME MS@2019-12-07 -->
}
// <-- FIXME MS@2019-12-07
}
}
} // namespace OCC

View File

@@ -19,6 +19,11 @@ namespace QKeychain {
namespace OCC {
namespace KeychainChunk {
class ReadJob;
class WriteJob;
}
class WebFlowCredentialsDialog;
class WebFlowCredentials : public AbstractCredentials
@@ -61,15 +66,16 @@ private slots:
void slotFinished(QNetworkReply *reply);
void slotAskFromUserCredentialsProvided(const QString &user, const QString &pass, const QString &host);
void slotAskFromUserCancelled();
void slotReadClientCertPEMJobDone(QKeychain::Job *incomingJob);
void slotReadClientKeyPEMJobDone(QKeychain::Job *incomingJob);
void slotReadClientCaCertsPEMJobDone(QKeychain::Job *incommingJob);
void slotReadClientCertPEMJobDone(KeychainChunk::ReadJob *readJob);
void slotReadClientKeyPEMJobDone(KeychainChunk::ReadJob *readJob);
void slotReadClientCaCertsPEMJobDone(KeychainChunk::ReadJob *readJob);
void slotReadPasswordJobDone(QKeychain::Job *incomingJob);
void slotWriteClientCertPEMJobDone();
void slotWriteClientKeyPEMJobDone();
void slotWriteClientCaCertsPEMJobDone(QKeychain::Job *incomingJob);
void slotWriteClientCertPEMJobDone(KeychainChunk::WriteJob *writeJob);
void slotWriteClientKeyPEMJobDone(KeychainChunk::WriteJob *writeJob);
void slotWriteClientCaCertsPEMJobDone(KeychainChunk::WriteJob *writeJob);
void slotWriteJobDone(QKeychain::Job *);
private:
@@ -83,7 +89,7 @@ private:
void writeSingleClientCaCertPEM();
/*
* Since we're limited by Windows limits we just create our own
* Since we're limited by Windows limits, we just create our own
* limit to avoid evil things happening by endless recursion
*
* Better than storing the count and relying on maybe-hacked values
@@ -121,6 +127,6 @@ protected:
WebFlowCredentialsDialog *_askDialog;
};
}
} // namespace OCC
#endif // WEBFLOWCREDENTIALS_H

View File

@@ -4,6 +4,9 @@
#include <QLabel>
#include "theme.h"
#include "application.h"
#include "owncloudgui.h"
#include "headerbanner.h"
#include "wizard/owncloudwizardcommon.h"
#include "wizard/webview.h"
#include "wizard/flow2authwidget.h"
@@ -19,31 +22,59 @@ WebFlowCredentialsDialog::WebFlowCredentialsDialog(Account *account, bool useFlo
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
_layout = new QVBoxLayout(this);
int spacing = _layout->spacing();
int margin = _layout->margin();
_layout->setSpacing(0);
_layout->setMargin(0);
if(_useFlow2) {
_headerBanner = new HeaderBanner(this);
_layout->addWidget(_headerBanner);
Theme *theme = Theme::instance();
_headerBanner->setup(tr("Log in"), theme->wizardHeaderLogo(), theme->wizardHeaderBanner(),
Qt::AutoText, QString::fromLatin1("color:#fff;"));
}
_containerLayout = new QVBoxLayout(this);
_containerLayout->setSpacing(spacing);
_containerLayout->setMargin(margin);
//QString msg = tr("You have been logged out of %1 as user %2, please login again")
// .arg(_account->displayName(), _user);
_infoLabel = new QLabel();
_layout->addWidget(_infoLabel);
_containerLayout->addWidget(_infoLabel);
if (_useFlow2) {
_flow2AuthWidget = new Flow2AuthWidget(account);
_layout->addWidget(_flow2AuthWidget);
_flow2AuthWidget = new Flow2AuthWidget();
_containerLayout->addWidget(_flow2AuthWidget);
connect(_flow2AuthWidget, &Flow2AuthWidget::urlCatched, this, &WebFlowCredentialsDialog::urlCatched);
connect(_flow2AuthWidget, &Flow2AuthWidget::authResult, this, &WebFlowCredentialsDialog::slotFlow2AuthResult);
// Connect styleChanged events to our widgets, so they can adapt (Dark-/Light-Mode switching)
connect(this, &WebFlowCredentialsDialog::styleChanged, _flow2AuthWidget, &Flow2AuthWidget::slotStyleChanged);
// allow Flow2 page to poll on window activation
connect(this, &WebFlowCredentialsDialog::onActivate, _flow2AuthWidget, &Flow2AuthWidget::slotPollNow);
_flow2AuthWidget->startAuth(account);
} else {
_webView = new WebView();
_layout->addWidget(_webView);
_containerLayout->addWidget(_webView);
connect(_webView, &WebView::urlCatched, this, &WebFlowCredentialsDialog::urlCatched);
}
auto app = static_cast<Application *>(qApp);
connect(app, &Application::isShowingSettingsDialog, this, &WebFlowCredentialsDialog::slotShowSettingsDialog);
_errorLabel = new QLabel();
_errorLabel->hide();
_layout->addWidget(_errorLabel);
_containerLayout->addWidget(_errorLabel);
WizardCommon::initErrorLabel(_errorLabel);
_layout->addLayout(_containerLayout);
setLayout(_layout);
customizeStyle();
}
void WebFlowCredentialsDialog::closeEvent(QCloseEvent* e) {
@@ -52,11 +83,17 @@ void WebFlowCredentialsDialog::closeEvent(QCloseEvent* e) {
if (_webView) {
// Force calling WebView::~WebView() earlier so that _profile and _page are
// deleted in the correct order.
delete _webView;
_webView->deleteLater();
_webView = nullptr;
}
if (_flow2AuthWidget)
delete _flow2AuthWidget;
if (_flow2AuthWidget) {
_flow2AuthWidget->resetAuth();
_flow2AuthWidget->deleteLater();
_flow2AuthWidget = nullptr;
}
emit onClose();
}
void WebFlowCredentialsDialog::setUrl(const QUrl &url) {
@@ -69,6 +106,9 @@ void WebFlowCredentialsDialog::setInfo(const QString &msg) {
}
void WebFlowCredentialsDialog::setError(const QString &error) {
// bring window to top
slotShowSettingsDialog();
if (_useFlow2 && _flow2AuthWidget) {
_flow2AuthWidget->setError(error);
return;
@@ -82,4 +122,49 @@ void WebFlowCredentialsDialog::setError(const QString &error) {
}
}
void WebFlowCredentialsDialog::changeEvent(QEvent *e)
{
switch (e->type()) {
case QEvent::StyleChange:
case QEvent::PaletteChange:
case QEvent::ThemeChange:
customizeStyle();
// Notify the other widgets (Dark-/Light-Mode switching)
emit styleChanged();
break;
case QEvent::ActivationChange:
if(isActiveWindow())
emit onActivate();
break;
default:
break;
}
QDialog::changeEvent(e);
}
void WebFlowCredentialsDialog::customizeStyle()
{
// HINT: Customize dialog's own style here, if necessary in the future (Dark-/Light-Mode switching)
}
void WebFlowCredentialsDialog::slotShowSettingsDialog()
{
// bring window to top but slightly delay, to avoid being hidden behind the SettingsDialog
QTimer::singleShot(100, this, [this] {
ownCloudGui::raiseDialog(this);
});
}
void WebFlowCredentialsDialog::slotFlow2AuthResult(Flow2Auth::Result r, const QString &errorString, const QString &user, const QString &appPassword)
{
if(r == Flow2Auth::LoggedIn) {
emit urlCatched(user, appPassword, QString());
} else {
// bring window to top
slotShowSettingsDialog();
}
}
} // namespace OCC

View File

@@ -5,12 +5,14 @@
#include <QUrl>
#include "accountfwd.h"
#include "creds/flow2auth.h"
class QLabel;
class QVBoxLayout;
namespace OCC {
class HeaderBanner;
class WebView;
class Flow2AuthWidget;
@@ -30,11 +32,21 @@ public:
protected:
void closeEvent(QCloseEvent * e) override;
void changeEvent(QEvent *) override;
public slots:
void slotFlow2AuthResult(Flow2Auth::Result, const QString &errorString, const QString &user, const QString &appPassword);
void slotShowSettingsDialog();
signals:
void urlCatched(const QString user, const QString pass, const QString host);
void styleChanged();
void onActivate();
void onClose();
private:
void customizeStyle();
bool _useFlow2;
Flow2AuthWidget *_flow2AuthWidget;
@@ -43,8 +55,10 @@ private:
QLabel *_errorLabel;
QLabel *_infoLabel;
QVBoxLayout *_layout;
QVBoxLayout *_containerLayout;
HeaderBanner *_headerBanner;
};
}
} // namespace OCC
#endif // WEBFLOWCREDENTIALSDIALOG_H

View File

@@ -417,6 +417,13 @@ void Folder::createGuiLog(const QString &filename, LogStatus status, int count,
text = tr("%1 could not be synced due to an error. See the log for details.").arg(file);
}
break;
case LogStatusFileLocked:
if (count > 1) {
text = tr("%1 and %n other file(s) are currently locked.", "", count -1).arg(file);
} else {
text = tr("%1 is currently locked.").arg(file);
}
break;
}
if (!text.isEmpty()) {
@@ -895,13 +902,19 @@ void Folder::slotItemCompleted(const SyncFileItemPtr &item)
}
// add new directories or remove gone away dirs to the watcher
if (item->isDirectory() && item->_instruction == CSYNC_INSTRUCTION_NEW) {
if (_folderWatcher)
_folderWatcher->addPath(path() + item->_file);
}
if (item->isDirectory() && item->_instruction == CSYNC_INSTRUCTION_REMOVE) {
if (_folderWatcher)
_folderWatcher->removePath(path() + item->_file);
if (_folderWatcher && item->isDirectory()) {
switch (item->_instruction) {
case CSYNC_INSTRUCTION_NEW:
_folderWatcher->addPath(path() + item->_file);
break;
case CSYNC_INSTRUCTION_REMOVE:
_folderWatcher->removePath(path() + item->_file);
break;
case CSYNC_INSTRUCTION_RENAME:
_folderWatcher->removePath(path() + item->_file);
_folderWatcher->addPath(path() + item->destination());
break;
}
}
// Success and failure of sync items adjust what the next sync is
@@ -1072,20 +1085,20 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction dir, bool *cancel
if (!cfgFile.promptDeleteFiles())
return;
QString msg = dir == SyncFileItem::Down ? tr("All files in the sync folder '%1' folder were deleted on the server.\n"
QString msg = dir == SyncFileItem::Down ? tr("All files in the sync folder '%1' were deleted on the server.\n"
"These deletes will be synchronized to your local sync folder, making such files "
"unavailable unless you have a right to restore. \n"
"If you decide to keep the files, they will be re-synced with the server if you have rights to do so.\n"
"If you decide to restore the files, they will be re-synced with the server if you have rights to do so.\n"
"If you decide to delete the files, they will be unavailable to you, unless you are the owner.")
: tr("All the files in your local sync folder '%1' were deleted. These deletes will be "
"synchronized with your server, making such files unavailable unless restored.\n"
"Are you sure you want to sync those actions with the server?\n"
"If this was an accident and you decide to keep your files, they will be re-synced from the server.");
QMessageBox msgBox(QMessageBox::Warning, tr("Download new files?"),
: tr("All files got deleted from your local sync folder '%1'.\n"
"These files will be deleted from the server and will not be available on your other devices if they "
"will not be restored.\n"
"If this action was unintended you can restore the lost data now.");
QMessageBox msgBox(QMessageBox::Warning, tr("Delete all files?"),
msg.arg(shortGuiLocalPath()));
msgBox.setWindowFlags(msgBox.windowFlags() | Qt::WindowStaysOnTopHint);
msgBox.addButton(tr("Download new files"), QMessageBox::DestructiveRole);
QPushButton *keepBtn = msgBox.addButton(tr("Keep local files"), QMessageBox::AcceptRole);
msgBox.addButton(tr("Delete all files"), QMessageBox::DestructiveRole);
QPushButton *keepBtn = msgBox.addButton(tr("Restore deleted files"), QMessageBox::AcceptRole);
if (msgBox.exec() == -1) {
*cancel = true;
return;

View File

@@ -75,7 +75,7 @@ FolderMan::FolderMan(QObject *parent)
this, &FolderMan::slotScheduleFolderByTime);
_timeScheduler.start();
connect(AccountManager::instance(), &AccountManager::accountRemoved,
connect(AccountManager::instance(), &AccountManager::removeAccountFolders,
this, &FolderMan::slotRemoveFoldersForAccount);
connect(_lockWatcher.data(), &LockWatcher::fileUnlocked,
@@ -443,7 +443,7 @@ void FolderMan::slotFolderSyncPaused(Folder *f, bool paused)
void FolderMan::slotFolderCanSyncChanged()
{
Folder *f = qobject_cast<Folder *>(sender());
ASSERT(f);
ASSERT(f);
if (f->canSync()) {
_socketApi->slotRegisterPath(f->alias());
} else {
@@ -562,7 +562,7 @@ void FolderMan::slotEtagJobDestroyed(QObject * /*o*/)
void FolderMan::slotRunOneEtagJob()
{
if (_currentEtagJob.isNull()) {
Folder *folder;
Folder *folder = nullptr;
foreach (Folder *f, _folderMap) {
if (f->etagJob()) {
// Caveat: always grabs the first folder with a job, but we think this is Ok for now and avoids us having a seperate queue.
@@ -1084,6 +1084,73 @@ bool FolderMan::startFromScratch(const QString &localFolder)
return true;
}
void FolderMan::slotWipeFolderForAccount(AccountState *accountState)
{
QVarLengthArray<Folder *, 16> foldersToRemove;
Folder::MapIterator i(_folderMap);
while (i.hasNext()) {
i.next();
Folder *folder = i.value();
if (folder->accountState() == accountState) {
foldersToRemove.append(folder);
}
}
bool success = false;
foreach (const auto &f, foldersToRemove) {
if (!f) {
qCCritical(lcFolderMan) << "Can not remove null folder";
return;
}
qCInfo(lcFolderMan) << "Removing " << f->alias();
const bool currentlyRunning = (_currentSyncFolder == f);
if (currentlyRunning) {
// abort the sync now
terminateSyncProcess();
}
if (_scheduledFolders.removeAll(f) > 0) {
emit scheduleQueueChanged();
}
// wipe database
f->wipe();
// wipe data
QDir userFolder(f->path());
if (userFolder.exists()) {
success = userFolder.removeRecursively();
if (!success) {
qCWarning(lcFolderMan) << "Failed to remove existing folder " << f->path();
} else {
qCInfo(lcFolderMan) << "wipe: Removed file " << f->path();
}
} else {
success = true;
qCWarning(lcFolderMan) << "folder does not exist, can not remove.";
}
f->setSyncPaused(true);
// remove the folder configuration
f->removeFromSettings();
unloadFolder(f);
if (currentlyRunning) {
delete f;
}
_navigationPaneHelper.scheduleUpdateCloudStorageRegistry();
}
emit folderListChanged(_folderMap);
emit wipeDone(accountState, success);
}
void FolderMan::setDirtyProxy()
{
foreach (Folder *f, _folderMap.values()) {

View File

@@ -207,6 +207,11 @@ signals:
*/
void folderListChanged(const Folder::Map &);
/**
* Emitted once slotRemoveFoldersForAccount is done wiping
*/
void wipeDone(AccountState *account, bool success);
public slots:
/**
@@ -231,6 +236,9 @@ public slots:
// slot to schedule an ETag job (from Folder only)
void slotScheduleETagJob(const QString &alias, RequestEtagJob *job);
/** Wipe folder */
void slotWipeFolderForAccount(AccountState *accountState);
private slots:
void slotFolderSyncPaused(Folder *, bool paused);
void slotFolderCanSyncChanged();

View File

@@ -40,7 +40,7 @@ namespace OCC {
FolderStatusDelegate::FolderStatusDelegate()
: QStyledItemDelegate()
{
m_moreIcon = QIcon(QLatin1String(":/client/resources/more.svg"));
customizeStyle();
}
QString FolderStatusDelegate::addFolderText()
@@ -168,6 +168,7 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
QString itemString = qvariant_cast<QString>(index.data(SyncProgressItemString));
int warningCount = qvariant_cast<int>(index.data(WarningCount));
bool syncOngoing = qvariant_cast<bool>(index.data(SyncRunning));
QDateTime syncDate = qvariant_cast<QDateTime>(index.data(SyncDate));
bool syncEnabled = qvariant_cast<bool>(index.data(FolderAccountConnected));
QRect iconRect = option.rect;
@@ -252,7 +253,7 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
if (!showProgess) {
painter->setFont(subFont);
QString elidedRemotePathText = subFm.elidedText(
tr("Synchronized with local folder"),
tr("Synchronized with local folder (%1)").arg(syncDate.toTimeSpec(Qt::LocalTime).toString(Qt::SystemLocaleShortDate)),
Qt::ElideRight, remotePathRect.width());
painter->drawText(QStyle::visualRect(option.direction, option.rect, remotePathRect),
textAlign, elidedRemotePathText);
@@ -272,6 +273,11 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
rect.setHeight(texts.count() * subFm.height() + 2 * margin);
rect.setRight(option.rect.right() - margin);
// save previous state to not mess up colours with the background (fixes issue: https://github.com/nextcloud/desktop/issues/1237)
auto oldBrush = painter->brush();
auto oldPen = painter->pen();
auto oldFont = painter->font();
painter->setBrush(color);
painter->setPen(QColor(0xaa, 0xaa, 0xaa));
painter->drawRoundedRect(QStyle::visualRect(option.direction, option.rect, rect),
@@ -289,6 +295,11 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
textRect.translate(0, textRect.height());
}
// restore previous state
painter->setBrush(oldBrush);
painter->setPen(oldPen);
painter->setFont(oldFont);
h = rect.bottom() + margin;
};
@@ -348,7 +359,7 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
btnOpt.arrowType = Qt::NoArrow;
btnOpt.subControls = QStyle::SC_ToolButton;
btnOpt.rect = optionsButtonVisualRect;
btnOpt.icon = m_moreIcon;
btnOpt.icon = _iconMore;
int e = QApplication::style()->pixelMetric(QStyle::PM_ButtonIconSize);
btnOpt.iconSize = QSize(e,e);
QApplication::style()->drawComplexControl(QStyle::CC_ToolButton, &btnOpt, painter);
@@ -422,5 +433,14 @@ QRect FolderStatusDelegate::errorsListRect(QRect within)
return within;
}
void FolderStatusDelegate::slotStyleChanged()
{
customizeStyle();
}
void FolderStatusDelegate::customizeStyle()
{
_iconMore = Theme::createColorAwareIcon(QLatin1String(":/client/resources/more.svg"));
}
} // namespace OCC

View File

@@ -26,7 +26,6 @@ class FolderStatusDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
QIcon m_moreIcon;
FolderStatusDelegate();
enum datarole { FolderAliasRole = Qt::UserRole + 100,
@@ -44,6 +43,7 @@ public:
SyncProgressItemString,
WarningCount,
SyncRunning,
SyncDate,
AddButton // 1 = enabled; 2 = disabled
};
@@ -61,9 +61,16 @@ public:
static QRect errorsListRect(QRect within);
static int rootFolderHeightWithoutErrors(const QFontMetrics &fm, const QFontMetrics &aliasFm);
public slots:
void slotStyleChanged();
private:
void customizeStyle();
static QString addFolderText();
QPersistentModelIndex _pressedIndex;
QIcon _iconMore;
};
} // namespace OCC

View File

@@ -186,7 +186,7 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
return QVariant(tr("Error while loading the list of folders from the server.")
+ QString("\n") + x->_lastErrorString);
} else {
return tr("Fetching folder list from server...");
return tr("Fetching folder list from server");
}
break;
default:
@@ -218,6 +218,8 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
return f->syncResult().errorStrings();
case FolderStatusDelegate::SyncRunning:
return f->syncResult().status() == SyncResult::SyncRunning;
case FolderStatusDelegate::SyncDate:
return f->syncResult().syncTime();
case FolderStatusDelegate::HeaderRole:
return f->shortGuiRemotePathOrAppName();
case FolderStatusDelegate::FolderAliasRole:
@@ -1097,15 +1099,15 @@ void FolderStatusModel::slotFolderSyncStateChange(Folder *f)
}
QString message;
if (pos <= 0) {
message = tr("Waiting...");
message = tr("Waiting");
} else {
message = tr("Waiting for %n other folder(s)...", "", pos);
message = tr("Waiting for %n other folder(s)", "", pos);
}
pi = SubFolderInfo::Progress();
pi._overallSyncString = message;
} else if (state == SyncResult::SyncPrepare) {
pi = SubFolderInfo::Progress();
pi._overallSyncString = tr("Preparing to sync...");
pi._overallSyncString = tr("Preparing to sync");
} else if (state == SyncResult::Problem || state == SyncResult::Success) {
// Reset the progress info after a sync.
pi = SubFolderInfo::Progress();

View File

@@ -19,6 +19,8 @@
#include "folderwatcher.h"
#include "folderwatcher_win.h"
#include "common/utility.h"
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
@@ -52,7 +54,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
// QVarLengthArray ensures the stack-buffer is aligned like double and qint64.
QVarLengthArray<char, 4096 * 10> fileNotifyBuffer;
fileNotifyBuffer.resize(fileNotifyBufferSize);
fileNotifyBuffer.resize(OCC::Utility::convertSizeToInt(fileNotifyBufferSize));
const size_t fileNameBufferSize = 4096;
TCHAR fileNameBuffer[fileNameBufferSize];
@@ -66,7 +68,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
DWORD dwBytesReturned = 0;
SecureZeroMemory(pFileNotifyBuffer, fileNotifyBufferSize);
if (!ReadDirectoryChangesW(_directory, (LPVOID)pFileNotifyBuffer,
fileNotifyBufferSize, true,
OCC::Utility::convertSizeToDWORD(fileNotifyBufferSize), true,
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
&dwBytesReturned,
&overlapped,
@@ -113,7 +115,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
FILE_NOTIFY_INFORMATION *curEntry = pFileNotifyBuffer;
forever {
size_t len = curEntry->FileNameLength / 2;
QString file = _path + "\\" + QString::fromWCharArray(curEntry->FileName, len);
QString file = _path + "\\" + QString::fromWCharArray(curEntry->FileName, OCC::Utility::convertSizeToInt(len));
// Unless the file was removed or renamed, get its full long name
// TODO: We could still try expanding the path in the tricky cases...
@@ -122,7 +124,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
&& curEntry->Action != FILE_ACTION_RENAMED_OLD_NAME) {
size_t longNameSize = GetLongPathNameW(reinterpret_cast<LPCWSTR>(file.utf16()), fileNameBuffer, fileNameBufferSize);
if (longNameSize > 0) {
longfile = QString::fromUtf16(reinterpret_cast<const ushort *>(fileNameBuffer), longNameSize);
longfile = QString::fromUtf16(reinterpret_cast<const ushort *>(fileNameBuffer), OCC::Utility::convertSizeToInt(longNameSize));
} else {
qCWarning(lcFolderWatcher) << "Error converting file name to full length, keeping original name.";
}

View File

@@ -41,7 +41,7 @@
<item>
<widget class="QPushButton" name="localFolderChooseBtn">
<property name="text">
<string>&amp;Choose...</string>
<string>&amp;Choose</string>
</property>
</widget>
</item>

View File

@@ -107,7 +107,7 @@
<enum>QFrame::Plain</enum>
</property>
<property name="text">
<string>TextLabel</string>
<string notr="true">TextLabel</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
@@ -140,7 +140,7 @@
<item row="1" column="1">
<widget class="QPushButton" name="addFolderButton">
<property name="text">
<string>Create Folder</string>
<string>Create folder</string>
</property>
</widget>
</item>

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