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

Compare commits

...

103 Commits

Author SHA1 Message Date
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
158 changed files with 27923 additions and 22249 deletions

View File

@@ -344,10 +344,9 @@ steps:
from_secret: DEBIAN_SECRET_IV
trigger:
branch:
- master
- stable-2.6
event:
- pull_request
- push
- tag
---
kind: pipeline
name: Documentation

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-Synchronisation
Comment[de_DE]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
GenericName[de_DE]=Synchronisationsordner

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,6 +1,6 @@
set( MIRALL_VERSION_MAJOR 2 )
set( MIRALL_VERSION_MINOR 5 )
set( MIRALL_VERSION_PATCH 3 )
set( MIRALL_VERSION_MINOR 6 )
set( MIRALL_VERSION_PATCH 1 )
set( MIRALL_VERSION_YEAR 2019 )
set( MIRALL_SOVERSION 0 )

View File

@@ -7,7 +7,6 @@ Build-Depends: cmake,
cdbs,
dh-python,
extra-cmake-modules (>= 5.16),
kdelibs5-dev,
libkf5kio-dev,
libcmocka-dev,
libhttp-dav-perl,

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

@@ -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

@@ -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];

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

@@ -33,8 +33,8 @@ 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
@@ -322,7 +322,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 +342,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

@@ -104,6 +104,7 @@ set(client_SRCS
guiutility.cpp
elidedlabel.cpp
iconjob.cpp
remotewipe.cpp
creds/credentialsfactory.cpp
creds/httpcredentialsgui.cpp
creds/oauth.cpp
@@ -181,6 +182,9 @@ if (APPLE)
../3rdparty/qtmacgoodies/src/macstandardicon.mm
../3rdparty/qtmacgoodies/src/macwindow.mm
)
# We want to access Cocoa specific structures in the code above
# and need the platform plugin interface for that - which is private.
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
endif()
if(NOT WIN32)

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

@@ -147,6 +147,8 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
createAccountToolbox();
connect(AccountManager::instance(), &AccountManager::accountAdded,
this, &AccountSettings::slotAccountAdded);
connect(this, &AccountSettings::removeAccountFolders,
AccountManager::instance(), &AccountManager::removeAccountFolders);
connect(ui->_folderList, &QWidget::customContextMenuRequested,
this, &AccountSettings::slotCustomContextMenuRequested);
connect(ui->_folderList, &QAbstractItemView::clicked,
@@ -334,9 +336,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 +350,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)

View File

@@ -63,6 +63,7 @@ signals:
void openFolderAlias(const QString &);
void showIssuesList(AccountState *account);
void requesetMnemonic();
void removeAccountFolders(AccountState *account);
public slots:
void slotOpenOC();

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>

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,
@@ -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

@@ -26,6 +26,8 @@
#include <QPainter>
#include <QApplication>
#define HASQT5_11 (QT_VERSION >= QT_VERSION_CHECK(5,11,0))
namespace OCC {
int ActivityItemDelegate::_iconHeight = 0;
@@ -106,7 +108,11 @@ 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);
@@ -114,7 +120,11 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
// 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);
@@ -129,7 +139,11 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
// time box rect
QRect timeBox = messageTextBox;
QString timeStr = tr("%1").arg(timeText);
#if (HASQT5_11)
int timeTextWidth = fm.horizontalAdvance(timeStr);
#else
int timeTextWidth = fm.width(timeStr);
#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;
@@ -180,7 +194,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;
@@ -196,7 +214,12 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
// 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;

View File

@@ -108,6 +108,7 @@ Application::Application(int &argc, char **argv)
, _userTriggeredConnect(false)
, _debugMode(false)
, _backgroundMode(false)
, _isQuitting(false)
{
_startedAt.start();
@@ -264,6 +265,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 +286,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 +309,8 @@ void Application::slotAccountStateAdded(AccountState *accountState)
void Application::slotCleanup()
{
_isQuitting = true;
AccountManager::instance()->save();
FolderMan::instance()->unloadAndDeleteAllFolders();

View File

@@ -114,6 +114,7 @@ private:
bool _userTriggeredConnect;
bool _debugMode;
bool _backgroundMode;
bool _isQuitting;
ClientProxy _proxy;

View File

@@ -52,7 +52,11 @@ void Flow2Auth::openBrowser()
// 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) {

View File

@@ -358,6 +358,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!";
@@ -372,7 +374,7 @@ void WebFlowCredentials::forgetSensitiveData() {
invalidateToken();
/* IMPORTANT
/* TODO: For "Log out" & "Remove account": Remove client CA certs and KEY!
* 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.
*
@@ -416,6 +418,9 @@ void WebFlowCredentials::slotFinished(QNetworkReply *reply) {
if (reply->error() == QNetworkReply::NoError) {
_credentialsValid = true;
/// Used later for remote wipe
_account->setAppPassword(_password);
}
}
@@ -539,7 +544,7 @@ void WebFlowCredentials::slotReadClientCaCertsPEMJobDone(QKeychain::Job *incomin
return;
} else {
if (readJob->error() != QKeychain::Error::EntryNotFound ||
(readJob->error() == QKeychain::Error::EntryNotFound) && _clientSslCaCertificates.count() == 0) {
((readJob->error() == QKeychain::Error::EntryNotFound) && _clientSslCaCertificates.count() == 0)) {
qCWarning(lcWebFlowCredentials) << "Unable to read client CA cert slot " << QString::number(_clientSslCaCertificates.count()) << readJob->errorString();
}
}

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

@@ -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);

View File

@@ -44,6 +44,7 @@ public:
SyncProgressItemString,
WarningCount,
SyncRunning,
SyncDate,
AddButton // 1 = enabled; 2 = disabled
};

View File

@@ -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:

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

@@ -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>

View File

@@ -26,6 +26,7 @@
#include "updater/updater.h"
#include "updater/ocupdater.h"
#include "ignorelisteditor.h"
#include "common/utility.h"
#include "config.h"
@@ -35,6 +36,12 @@
#include <QDir>
#include <QScopedValueRollback>
#define QTLEGACY (QT_VERSION < QT_VERSION_CHECK(5,9,0))
#if !(QTLEGACY)
#include <QOperatingSystemVersion>
#endif
namespace OCC {
GeneralSettings::GeneralSettings(QWidget *parent)
@@ -79,9 +86,13 @@ GeneralSettings::GeneralSettings(QWidget *parent)
// Hide on non-Windows, or WindowsVersion < 10.
// The condition should match the default value of ConfigFile::showInExplorerNavigationPane.
#ifdef Q_OS_WIN
if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS10)
#if QTLEGACY
if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS10)
#else
if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows10)
#endif
_ui->showInExplorerNavigationPaneCheckBox->setVisible(false);
#endif
_ui->showInExplorerNavigationPaneCheckBox->setVisible(false);
/* Set the left contents margin of the layout to zero to make the checkboxes
* align properly vertically , fixes bug #3758

View File

@@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>IgnoreListTableWidget</string>
<string notr="true">IgnoreListTableWidget</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0" rowspan="4">

View File

@@ -55,7 +55,7 @@
</size>
</property>
<property name="text">
<string>Label</string>
<string notr="true">Label</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>542</width>
<height>396</height>
<width>563</width>
<height>444</height>
</rect>
</property>
<property name="windowTitle">
@@ -228,7 +228,7 @@
<bool>false</bool>
</property>
<property name="maximum">
<number>9999</number>
<number>999999</number>
</property>
<property name="value">
<number>80</number>
@@ -307,7 +307,7 @@
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
<number>999999</number>
</property>
<property name="value">
<number>10</number>

View File

@@ -22,6 +22,12 @@
#include <QDesktopServices>
#include <QApplication>
#define QTLEGACY (QT_VERSION < QT_VERSION_CHECK(5,9,0))
#if !(QTLEGACY)
#include <QOperatingSystemVersion>
#endif
namespace OCC {
// according to the QStandardDir impl from Qt5
@@ -89,10 +95,14 @@ void showInFileManager(const QString &localPath)
{
if (Utility::isWindows()) {
#ifdef Q_OS_WIN
if (QSysInfo::windowsVersion() <= QSysInfo::WV_2003) {
return;
}
#if QTLEGACY
if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS10)
#else
if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows7)
#endif
return;
#endif
QString explorer = "explorer.exe "; // FIXME: we trust it's in PATH
QFileInfo fi(localPath);

View File

@@ -675,6 +675,12 @@ void ownCloudGui::updateContextMenu()
_contextMenu->addSeparator();
if (_navLinksMenu) {
_contextMenu->addMenu(_navLinksMenu);
}
_contextMenu->addSeparator();
if (accountList.isEmpty()) {
_contextMenu->addAction(_actionNewAccountWizard);
}
@@ -688,6 +694,7 @@ void ownCloudGui::updateContextMenu()
}
_contextMenu->addSeparator();
if (atLeastOnePaused) {
QString text;
if (accountList.count() > 1) {
@@ -777,6 +784,8 @@ void ownCloudGui::setupActions()
{
_actionStatus = new QAction(tr("Unknown status"), this);
_actionStatus->setEnabled(false);
_navLinksMenu = new QMenu(tr("Apps"));
_navLinksMenu->setEnabled(false);
_actionSettings = new QAction(tr("Settings..."), this);
_actionNewAccountWizard = new QAction(tr("New account..."), this);
_actionRecent = new QAction(tr("View more activity..."), this);
@@ -818,8 +827,11 @@ void ownCloudGui::fetchNavigationApps(AccountStatePtr account){
void ownCloudGui::buildNavigationAppsMenu(AccountStatePtr account, QMenu *accountMenu){
auto navLinks = _navApps.value(account);
if(navLinks.size() > 0){
_navLinksMenu->clear();
_navLinksMenu->setEnabled(navLinks.size() > 0);
if(navLinks.size() > 0){
// when there is only one account add the nav links above the settings
QAction *actionBefore = _actionSettings;
@@ -838,17 +850,13 @@ void ownCloudGui::buildNavigationAppsMenu(AccountStatePtr account, QMenu *accoun
}
// Create submenu with links
QMenu *navLinksMenu = new QMenu(tr("Apps"));
accountMenu->insertSeparator(actionBefore);
accountMenu->insertMenu(actionBefore, navLinksMenu);
foreach (const QJsonValue &value, navLinks) {
auto navLink = value.toObject();
QAction *action = new QAction(navLink.value("name").toString(), this);
QUrl href(navLink.value("href").toString());
connect(action, &QAction::triggered, this, [href] { QDesktopServices::openUrl(href); });
navLinksMenu->addAction(action);
_navLinksMenu->addAction(action);
}
accountMenu->insertSeparator(actionBefore);
}
}

View File

@@ -168,6 +168,7 @@ private:
QAction *_actionQuit;
QAction *_actionCrash;
QMenu *_navLinksMenu;
QMap<AccountStatePtr, QJsonArray> _navApps;
QList<QAction *> _recentItemsActions;

View File

@@ -466,7 +466,41 @@ void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString &localFo
_ocWizard->appendToConfigurationLog(res);
}
if (nextStep) {
EntityExistsJob *job = new EntityExistsJob(_ocWizard->account(), _ocWizard->account()->davPath() + remoteFolder, this);
/*
* BEGIN - Sanitize URL paths to eliminate double-slashes
*
* Purpose: Don't rely on unsafe paths, be extra careful.
*
* Example: https://cloud.example.com/remote.php/webdav//
*
*/
qCInfo(lcWizard) << "Sanitize got URL path:" << QString(_ocWizard->account()->url().toString() + '/' + _ocWizard->account()->davPath() + remoteFolder);
QString newDavPath = _ocWizard->account()->davPath(),
newRemoteFolder = remoteFolder;
while (newDavPath.startsWith('/')) {
newDavPath.remove(0, 1);
}
while (newDavPath.endsWith('/')) {
newDavPath.chop(1);
}
while (newRemoteFolder.startsWith('/')) {
newRemoteFolder.remove(0, 1);
}
while (newRemoteFolder.endsWith('/')) {
newRemoteFolder.chop(1);
}
QString newUrlPath = newDavPath + '/' + newRemoteFolder;
qCInfo(lcWizard) << "Sanitized to URL path:" << _ocWizard->account()->url().toString() + '/' + newUrlPath;
/*
* END - Sanitize URL paths to eliminate double-slashes
*/
EntityExistsJob *job = new EntityExistsJob(_ocWizard->account(), newUrlPath, this);
connect(job, &EntityExistsJob::exists, this, &OwncloudSetupWizard::slotRemoteFolderExists);
job->start();
} else {

View File

@@ -71,7 +71,7 @@
<item row="2" column="1">
<widget class="QLabel" name="proxyAddress">
<property name="text">
<string>TextLabel</string>
<string notr="true">TextLabel</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>

161
src/gui/remotewipe.cpp Normal file
View File

@@ -0,0 +1,161 @@
/*
* Copyright (C) by Camila Ayres <hello@camila.codes>
*
* 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 "remotewipe.h"
#include "folderman.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkRequest>
#include <QBuffer>
namespace OCC {
Q_LOGGING_CATEGORY(lcRemoteWipe, "nextcloud.gui.remotewipe", QtInfoMsg)
RemoteWipe::RemoteWipe(AccountPtr account, QObject *parent)
: _account(account),
_appPassword(QString()),
_accountRemoved(false),
_networkManager(nullptr),
_networkReplyCheck(nullptr),
_networkReplySuccess(nullptr)
{
QObject::connect(AccountManager::instance(), &AccountManager::accountRemoved,
this, [=](AccountState *) {
_accountRemoved = true;
});
QObject::connect(this, &RemoteWipe::authorized, FolderMan::instance(),
&FolderMan::slotWipeFolderForAccount);
QObject::connect(FolderMan::instance(), &FolderMan::wipeDone, this,
&RemoteWipe::notifyServerSuccessJob);
QObject::connect(_account.data(), &Account::appPasswordRetrieved, this,
&RemoteWipe::startCheckJobWithAppPassword);
}
void RemoteWipe::startCheckJobWithAppPassword(QString pwd){
if(pwd.isEmpty())
return;
_appPassword = pwd;
QUrl requestUrl = Utility::concatUrlPath(_account->url().toString(),
QLatin1String("/index.php/core/wipe/check"));
QNetworkRequest request;
request.setHeader(QNetworkRequest::ContentTypeHeader,
"application/x-www-form-urlencoded");
request.setUrl(requestUrl);
request.setSslConfiguration(_account->getOrCreateSslConfig());
auto requestBody = new QBuffer;
QUrlQuery arguments(QString("token=%1").arg(_appPassword));
requestBody->setData(arguments.query(QUrl::FullyEncoded).toLatin1());
_networkReplyCheck = _networkManager.post(request, requestBody);
QObject::connect(&_networkManager, SIGNAL(sslErrors(QNetworkReply *, QList<QSslError>)),
_account.data(), SLOT(slotHandleSslErrors(QNetworkReply *, QList<QSslError>)));
QObject::connect(_networkReplyCheck, &QNetworkReply::finished, this,
&RemoteWipe::checkJobSlot);
}
void RemoteWipe::checkJobSlot()
{
auto jsonData = _networkReplyCheck->readAll();
QJsonParseError jsonParseError;
QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object();
bool wipe = false;
//check for errors
if (_networkReplyCheck->error() != QNetworkReply::NoError ||
jsonParseError.error != QJsonParseError::NoError) {
QString errorReason;
QString errorFromJson = json["error"].toString();
if (!errorFromJson.isEmpty()) {
qCWarning(lcRemoteWipe) << QString("Error returned from the server: <em>%1<em>")
.arg(errorFromJson.toHtmlEscaped());
} else if (_networkReplyCheck->error() != QNetworkReply::NoError) {
qCWarning(lcRemoteWipe) << QString("There was an error accessing the 'token' endpoint: <br><em>%1</em>")
.arg(_networkReplyCheck->errorString().toHtmlEscaped());
} else if (jsonParseError.error != QJsonParseError::NoError) {
qCWarning(lcRemoteWipe) << QString("Could not parse the JSON returned from the server: <br><em>%1</em>")
.arg(jsonParseError.errorString());
} else {
qCWarning(lcRemoteWipe) << QString("The reply from the server did not contain all expected fields");
}
// check for wipe request
} else if(!json.value("wipe").isUndefined()){
wipe = json["wipe"].toBool();
}
auto manager = AccountManager::instance();
auto accountState = manager->account(_account->displayName()).data();
if(wipe){
// delete account
manager->deleteAccount(accountState);
manager->save();
// delete data
emit authorized(accountState);
} else {
// ask user for his credentials again
accountState->handleInvalidCredentials();
}
_networkReplyCheck->deleteLater();
}
void RemoteWipe::notifyServerSuccessJob(AccountState *accountState, bool dataWiped){
if(_accountRemoved && dataWiped && _account == accountState->account()){
QUrl requestUrl = Utility::concatUrlPath(_account->url().toString(),
QLatin1String("/index.php/core/wipe/success"));
QNetworkRequest request;
request.setHeader(QNetworkRequest::ContentTypeHeader,
"application/x-www-form-urlencoded");
request.setUrl(requestUrl);
request.setSslConfiguration(_account->getOrCreateSslConfig());
auto requestBody = new QBuffer;
QUrlQuery arguments(QString("token=%1").arg(_appPassword));
requestBody->setData(arguments.query(QUrl::FullyEncoded).toLatin1());
_networkReplySuccess = _networkManager.post(request, requestBody);
QObject::connect(_networkReplySuccess, &QNetworkReply::finished, this,
&RemoteWipe::notifyServerSuccessJobSlot);
}
}
void RemoteWipe::notifyServerSuccessJobSlot()
{
auto jsonData = _networkReplySuccess->readAll();
QJsonParseError jsonParseError;
QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object();
if (_networkReplySuccess->error() != QNetworkReply::NoError ||
jsonParseError.error != QJsonParseError::NoError) {
QString errorReason;
QString errorFromJson = json["error"].toString();
if (!errorFromJson.isEmpty()) {
qCWarning(lcRemoteWipe) << QString("Error returned from the server: <em>%1</em>")
.arg(errorFromJson.toHtmlEscaped());
} else if (_networkReplySuccess->error() != QNetworkReply::NoError) {
qCWarning(lcRemoteWipe) << QString("There was an error accessing the 'success' endpoint: <br><em>%1</em>")
.arg(_networkReplySuccess->errorString().toHtmlEscaped());
} else if (jsonParseError.error != QJsonParseError::NoError) {
qCWarning(lcRemoteWipe) << QString("Could not parse the JSON returned from the server: <br><em>%1</em>")
.arg(jsonParseError.errorString());
} else {
qCWarning(lcRemoteWipe) << QString("The reply from the server did not contain all expected fields.");
}
}
_networkReplySuccess->deleteLater();
}
}

61
src/gui/remotewipe.h Normal file
View File

@@ -0,0 +1,61 @@
#ifndef REMOTEWIPE_H
#define REMOTEWIPE_H
#include "accountmanager.h"
#include <QNetworkAccessManager>
class QJsonDocument;
class TestRemoteWipe;
namespace OCC {
class RemoteWipe : public QObject
{
Q_OBJECT
public:
explicit RemoteWipe(AccountPtr account, QObject *parent = nullptr);
signals:
/**
* Notify if wipe was requested
*/
void authorized(AccountState*);
/**
* Notify if user only needs to login again
*/
void askUserCredentials();
public slots:
/**
* Once receives a 401 or 403 status response it will do a fetch to
* <server>/index.php/core/wipe/check
*/
void startCheckJobWithAppPassword(QString);
private slots:
/**
* If wipe is requested, delete account and data, if not continue by asking
* the user to login again
*/
void checkJobSlot();
/**
* Once the client has wiped all the required data a POST to
* <server>/index.php/core/wipe/success
*/
void notifyServerSuccessJob(AccountState *accountState, bool);
void notifyServerSuccessJobSlot();
private:
AccountPtr _account;
QString _appPassword;
bool _accountRemoved;
QNetworkAccessManager _networkManager;
QNetworkReply *_networkReplyCheck;
QNetworkReply *_networkReplySuccess;
friend class ::TestRemoteWipe;
};
}
#endif // REMOTEWIPE_H

View File

@@ -48,7 +48,7 @@ const char TOOLBAR_CSS[] =
"QToolBar QToolBarExtension { padding:0; } "
"QToolBar QToolButton:checked { background: %3; color: %4; }";
static const float buttonSizeRatio = 1.618; // golden ratio
static const float buttonSizeRatio = 1.618f; // golden ratio
}

View File

@@ -89,7 +89,7 @@
</size>
</property>
<property name="text">
<string>share label</string>
<string notr="true">share label</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
@@ -120,7 +120,7 @@
</size>
</property>
<property name="text">
<string>Icon</string>
<string notr="true">Icon</string>
</property>
</widget>
</item>
@@ -151,8 +151,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>352</width>
<height>68</height>
<width>367</width>
<height>85</height>
</rect>
</property>
<layout class="QVBoxLayout" name="scrollAreaVerticalLayout"/>

View File

@@ -277,6 +277,7 @@ void ShareLinkWidget::slotCreatePassword()
void ShareLinkWidget::slotCreateShareLink(bool clicked)
{
Q_UNUSED(clicked);
slotToggleAnimation(true);
emit createLinkShare();
}

View File

@@ -109,7 +109,7 @@
</palette>
</property>
<property name="text">
<string>TextLabel</string>
<string notr="true">TextLabel</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>

View File

@@ -622,13 +622,13 @@ void OCC::SocketApi::openPrivateLink(const QString &link)
void SocketApi::command_GET_STRINGS(const QString &argument, SocketListener *listener)
{
static std::array<std::pair<const char *, QString>, 5> strings { {
{ "SHARE_MENU_TITLE", tr("Share...") },
{ "CONTEXT_MENU_TITLE", Theme::instance()->appNameGUI() },
{ "SHARE_MENU_TITLE", tr("Share options") },
{ "CONTEXT_MENU_TITLE", tr("Share via ") + Theme::instance()->appNameGUI()},
{ "COPY_PRIVATE_LINK_MENU_TITLE", tr("Copy private link to clipboard") },
{ "EMAIL_PRIVATE_LINK_MENU_TITLE", tr("Send private link by email...") },
} };
listener->sendMessage(QString("GET_STRINGS:BEGIN"));
for (auto key_value : strings) {
for (const auto& key_value : strings) {
if (argument.isEmpty() || argument == QLatin1String(key_value.first)) {
listener->sendMessage(QString("STRING:%1:%2").arg(key_value.first, key_value.second));
}
@@ -652,7 +652,7 @@ void SocketApi::sendSharingContextMenuOptions(const FileData &fileData, SocketLi
if (isOnTheServer && !record._remotePerm.isNull() && !record._remotePerm.hasPermission(RemotePermissions::CanReshare)) {
listener->sendMessage(QLatin1String("MENU_ITEM:DISABLED:d:") + tr("Resharing this file is not allowed"));
} else {
listener->sendMessage(QLatin1String("MENU_ITEM:SHARE") + flagString + tr("Share..."));
listener->sendMessage(QLatin1String("MENU_ITEM:SHARE") + flagString + tr("Share options"));
// Do we have public links?
bool publicLinksEnabled = theme->linkSharing() && capabilities.sharePublicLink();
@@ -663,13 +663,13 @@ void SocketApi::sendSharingContextMenuOptions(const FileData &fileData, SocketLi
&& !capabilities.sharePublicLinkEnforcePassword();
if (canCreateDefaultPublicLink) {
listener->sendMessage(QLatin1String("MENU_ITEM:COPY_PUBLIC_LINK") + flagString + tr("Copy public link to clipboard"));
listener->sendMessage(QLatin1String("MENU_ITEM:COPY_PUBLIC_LINK") + flagString + tr("Copy public link"));
} else if (publicLinksEnabled) {
listener->sendMessage(QLatin1String("MENU_ITEM:MANAGE_PUBLIC_LINKS") + flagString + tr("Copy public link to clipboard"));
listener->sendMessage(QLatin1String("MENU_ITEM:MANAGE_PUBLIC_LINKS") + flagString + tr("Copy public link"));
}
}
listener->sendMessage(QLatin1String("MENU_ITEM:COPY_PRIVATE_LINK") + flagString + tr("Copy private link to clipboard"));
listener->sendMessage(QLatin1String("MENU_ITEM:COPY_PRIVATE_LINK") + flagString + tr("Copy internal link"));
// Disabled: only providing email option for private links would look odd,
// and the copy option is more general.

View File

@@ -37,6 +37,7 @@ SslButton::SslButton(QWidget *parent)
_menu = new QMenu(this);
QObject::connect(_menu, &QMenu::aboutToShow,
this, &SslButton::slotUpdateMenu);
setMenu(_menu);
}
static QString addCertDetailsField(const QString &key, const QString &value)
@@ -171,11 +172,9 @@ void SslButton::updateAccountState(AccountState *accountState)
setIcon(QIcon(QLatin1String(":/client/resources/lock-https.png")));
QSslCipher cipher = account->_sessionCipher;
setToolTip(tr("This connection is encrypted using %1 bit %2.\n").arg(cipher.usedBits()).arg(cipher.name()));
setMenu(_menu);
} else {
setIcon(QIcon(QLatin1String(":/client/resources/lock-http.png")));
setToolTip(tr("This connection is NOT secure as it is not encrypted.\n"));
setMenu(nullptr);
}
}
@@ -189,6 +188,8 @@ void SslButton::slotUpdateMenu()
AccountPtr account = _accountState->account();
_menu->addAction(tr("Server version: %1").arg(account->serverVersion()))->setEnabled(false);
if (account->isHttp2Supported()) {
_menu->addAction("HTTP/2")->setEnabled(false);
}
@@ -239,6 +240,8 @@ void SslButton::slotUpdateMenu()
_menu->addMenu(buildCertMenu(_menu, it.previous(), account->approvedCerts(), i, systemCerts));
i++;
}
} else {
_menu->addAction(tr("The connection is not secure"))->setEnabled(false);
}
}

View File

@@ -148,7 +148,7 @@ QString OCUpdater::statusString() const
case DownloadTimedOut:
return tr("Could not check for new updates.");
case UpdateOnlyAvailableThroughSystem:
return tr("New %1 version %2 available. Please use the system's update tool to install it.").arg(Theme::instance()->appNameGUI(), updateVersion);
return tr("New %1 version %2 is available. Please click <a href='%3'>here</a> to download the update.").arg(Theme::instance()->appNameGUI(), updateVersion, _updateInfo.web());
case CheckingServer:
return tr("Checking update server...");
case Unknown:

View File

@@ -99,6 +99,7 @@ void Flow2AuthCredsPage::asyncAuthResult(Flow2Auth::Result r, const QString &use
_appPassword = appPassword;
OwncloudWizard *ocWizard = qobject_cast<OwncloudWizard *>(wizard());
Q_ASSERT(ocWizard);
emit connectToOCUrl(ocWizard->account()->url().toString());
break;
}

View File

@@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string>Browser Authentication</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
@@ -61,6 +61,7 @@
<widget class="QCommandLinkButton" name="copyLinkButton">
<property name="font">
<font>
<family>Segoe UI</family>
<weight>50</weight>
<bold>false</bold>
</font>

View File

@@ -23,7 +23,7 @@
</size>
</property>
<property name="windowTitle">
<string>Form</string>
<string>Browser Authentication</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
@@ -73,6 +73,7 @@
<widget class="QCommandLinkButton" name="copyLinkButton">
<property name="font">
<font>
<family>Segoe UI</family>
<weight>50</weight>
<bold>false</bold>
</font>

View File

@@ -42,6 +42,8 @@ OwncloudAdvancedSetupPage::OwncloudAdvancedSetupPage()
, _localFolderValid(false)
, _progressIndi(new QProgressIndicator(this))
, _remoteFolder()
, _rSize(-1)
, _rSelectedSize(-1)
{
_ui.setupUi(this);
@@ -368,6 +370,8 @@ void OwncloudAdvancedSetupPage::slotQuotaRetrieved(const QVariantMap &result)
{
_rSize = result["size"].toDouble();
_ui.lSyncEverythingSizeLabel->setText(tr("(%1)").arg(Utility::octetsToString(_rSize)));
updateStatus();
}
qint64 OwncloudAdvancedSetupPage::availableLocalSpace() const

View File

@@ -399,7 +399,7 @@
<item>
<widget class="QLabel" name="syncModeLabel">
<property name="text">
<string>Status message</string>
<string notr="true">Status message</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>

View File

@@ -25,67 +25,24 @@
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="16" column="0">
<widget class="QLabel" name="bottomLabel">
<property name="minimumSize">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="text">
<string notr="true">TextLabel</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
</widget>
</spacer>
</item>
<item row="14" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="installLink">
<property name="text">
<string>&lt;a href=&quot;https://docs.nextcloud.com/server/15/admin_manual/installation/index.html#installation&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Host your own server&lt;/span&gt;&lt;/a&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="3" column="0">
<item>
<widget class="QLabel" name="topLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
@@ -107,117 +64,66 @@
</property>
</widget>
</item>
<item row="11" column="0" rowspan="2">
<layout class="QHBoxLayout" name="buttons" stretch="0,0,0,0">
<property name="spacing">
<number>6</number>
</property>
<property name="topMargin">
<number>20</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<widget class="QPushButton" name="prevButton">
<property name="minimumSize">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="createAccountButton">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="text">
<string>Register with a provider</string>
</property>
<property name="default">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="loginButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<property name="maximumSize">
<size>
<width>150</width>
<height>0</height>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Log in</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="default">
<bool>true</bool>
<string/>
</property>
<property name="flat">
<bool>false</bool>
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<widget class="OCC::SlideShow" name="slideShow" native="true">
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="sizeHint" stdset="0">
</widget>
</item>
<item>
<widget class="QPushButton" name="nextButton">
<property name="minimumSize">
<size>
<width>40</width>
<height>20</height>
<height>0</height>
</size>
</property>
</spacer>
<property name="maximumSize">
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0">
<widget class="OCC::SlideShow" name="slideShow">
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
</widget>
</item>
<item row="4" column="0">
<item>
<widget class="QWidget" name="login" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
@@ -301,7 +207,7 @@
</sizepolicy>
</property>
<property name="placeholderText">
<string>https://...</string>
<string notr="true">https://...</string>
</property>
</widget>
</item>
@@ -336,7 +242,7 @@
</sizepolicy>
</property>
<property name="text">
<string>Error Label</string>
<string notr="true">Error Label</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
@@ -385,8 +291,8 @@
</layout>
</widget>
</item>
<item row="0" column="0">
<spacer name="verticalSpacer_5">
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@@ -401,6 +307,157 @@
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="buttons" stretch="0,0,0,0">
<property name="spacing">
<number>6</number>
</property>
<property name="topMargin">
<number>20</number>
</property>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="createAccountButton">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="text">
<string>Register with a provider</string>
</property>
<property name="default">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="loginButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Log in</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="default">
<bool>true</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="installLink">
<property name="text">
<string notr="true">&lt;a href=&quot;https://docs.nextcloud.com/server/latest/admin_manual/installation/#installation&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#7a7a7a;&quot;&gt;Host your own server&lt;/span&gt;&lt;/a&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="bottomLabel">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string notr="true">TextLabel</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>

View File

@@ -84,7 +84,22 @@ OwncloudSetupPage::OwncloudSetupPage(QWidget *parent)
_ui.slideShow->addSlide(Theme::hidpiFileName(":/client/theme/colored/wizard-files.png"), tr("Secure collaboration & file exchange"));
_ui.slideShow->addSlide(Theme::hidpiFileName(":/client/theme/colored/wizard-groupware.png"), tr("Easy-to-use web mail, calendaring & contacts"));
_ui.slideShow->addSlide(Theme::hidpiFileName(":/client/theme/colored/wizard-talk.png"), tr("Screensharing, online meetings & web conferences"));
connect(_ui.slideShow, &SlideShow::clicked, _ui.slideShow, &SlideShow::nextSlide);
connect(_ui.slideShow, &SlideShow::clicked, _ui.slideShow, &SlideShow::stopShow);
connect(_ui.nextButton, &QPushButton::clicked, _ui.slideShow, &SlideShow::nextSlide);
connect(_ui.prevButton, &QPushButton::clicked, _ui.slideShow, &SlideShow::prevSlide);
auto widgetBgLightness = OwncloudSetupPage::palette().color(OwncloudSetupPage::backgroundRole()).lightness();
bool widgetHasDarkBg =
(widgetBgLightness >= 125)
? false
: true;
_ui.nextButton->setIcon(theme->uiThemeIcon(QString("control-next.svg"), widgetHasDarkBg));
_ui.prevButton->setIcon(theme->uiThemeIcon(QString("control-prev.svg"), widgetHasDarkBg));
// QPushButtons are a mess when it comes to consistent background coloring without stylesheets,
// so we do it here even though this is an exceptional styling method here
_ui.createAccountButton->setStyleSheet("QPushButton {background-color: #0082C9; color: white}");
_ui.slideShow->startShow();
QPalette pal = _ui.slideShow->palette();

View File

@@ -19,6 +19,8 @@
#include <QStyle>
#include <QStyleHints>
#define HASQT5_11 (QT_VERSION >= QT_VERSION_CHECK(5,11,0))
namespace OCC {
static const int Spacing = 6;
@@ -88,7 +90,11 @@ QSize SlideShow::sizeHint() const
QFontMetrics fm = fontMetrics();
QSize labelSize(0, fm.height());
for (const QString &label : _labels) {
#if (HASQT5_11)
labelSize.setWidth(std::max(fm.horizontalAdvance(label), labelSize.width()));
#else
labelSize.setWidth(std::max(fm.width(label), labelSize.width()));
#endif
}
QSize pixmapSize;
for (const QPixmap &pixmap : _pixmaps) {
@@ -116,7 +122,7 @@ void SlideShow::nextSlide()
_reverse = false;
}
void SlideShow::previousSlide()
void SlideShow::prevSlide()
{
setCurrentSlide((_currentIndex > 0 ? _currentIndex : _labels.count()) - 1);
_reverse = true;

View File

@@ -51,7 +51,7 @@ public slots:
void startShow(int interval = 0);
void stopShow();
void nextSlide();
void previousSlide();
void prevSlide();
void reset();
signals:

View File

@@ -4,6 +4,9 @@
#include <QWebEngineProfile>
#include <QWebEngineUrlRequestInterceptor>
#include <QWebEngineUrlRequestJob>
#if QT_VERSION >= 0x051200
#include <QWebEngineUrlScheme>
#endif
#include <QWebEngineUrlSchemeHandler>
#include <QWebEngineView>
#include <QDesktopServices>
@@ -65,7 +68,10 @@ WebView::WebView(QWidget *parent)
_ui()
{
_ui.setupUi(this);
#if QT_VERSION >= 0x051200
QWebEngineUrlScheme _ncsheme("nc");
QWebEngineUrlScheme::registerScheme(_ncsheme);
#endif
_webview = new QWebEngineView(this);
_profile = new QWebEngineProfile(this);
_page = new WebEnginePage(_profile);
@@ -175,6 +181,7 @@ WebEnginePage::WebEnginePage(QWebEngineProfile *profile, QObject* parent) : QWeb
}
QWebEnginePage * WebEnginePage::createWindow(QWebEnginePage::WebWindowType type) {
Q_UNUSED(type);
ExternalWebEnginePage *view = new ExternalWebEnginePage(this->profile());
return view;
}
@@ -216,6 +223,8 @@ ExternalWebEnginePage::ExternalWebEnginePage(QWebEngineProfile *profile, QObject
bool ExternalWebEnginePage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame)
{
Q_UNUSED(type);
Q_UNUSED(isMainFrame);
QDesktopServices::openUrl(url);
return false;
}

View File

@@ -160,6 +160,37 @@ void AbstractNetworkJob::slotFinished()
qCWarning(lcNetworkJob) << "SslHandshakeFailedError: " << errorString() << " : can be caused by a webserver wanting SSL client certificates";
}
// Qt doesn't yet transparently resend HTTP2 requests, do so here
const auto maxHttp2Resends = 5;
QByteArray verb = requestVerb(*reply());
if (_reply->error() == QNetworkReply::ContentReSendError
&& _reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute).toBool()) {
if ((_requestBody && !_requestBody->isSequential()) || verb.isEmpty()) {
qCWarning(lcNetworkJob) << "Can't resend HTTP2 request, verb or body not suitable"
<< _reply->request().url() << verb << _requestBody;
} else if (_http2ResendCount >= maxHttp2Resends) {
qCWarning(lcNetworkJob) << "Not resending HTTP2 request, number of resends exhausted"
<< _reply->request().url() << _http2ResendCount;
} else {
qCInfo(lcNetworkJob) << "HTTP2 resending" << _reply->request().url();
_http2ResendCount++;
resetTimeout();
if (_requestBody) {
if(!_requestBody->isOpen())
_requestBody->open(QIODevice::ReadOnly);
_requestBody->seek(0);
}
sendRequest(
verb,
_reply->request().url(),
_reply->request(),
_requestBody);
return;
}
}
if (_reply->error() != QNetworkReply::NoError) {
if (!_ignoreCredentialFailure || _reply->error() != QNetworkReply::AuthenticationRequiredError) {
qCWarning(lcNetworkJob) << _reply->error() << errorString()

View File

@@ -188,7 +188,8 @@ private:
QPointer<QNetworkReply> _reply; // (QPointer because the NetworkManager may be destroyed before the jobs at exit)
QString _path;
QTimer _timer;
int _redirectCount;
int _redirectCount = 0;
int _http2ResendCount = 0;
// Set by the xyzRequest() functions and needed to be able to redirect
// requests, should it be required.

View File

@@ -36,9 +36,15 @@
#include <QAuthenticator>
#include <QStandardPaths>
#include <keychain.h>
#include "creds/abstractcredentials.h"
using namespace QKeychain;
namespace OCC {
Q_LOGGING_CATEGORY(lcAccount, "nextcloud.sync.account", QtInfoMsg)
const char app_password[] = "_app-password";
Account::Account(QObject *parent)
: QObject(parent)
@@ -53,16 +59,17 @@ AccountPtr Account::create()
AccountPtr acc = AccountPtr(new Account);
acc->setSharedThis(acc);
//TODO: This probably needs to have a better
// coupling, but it should work for now.
acc->e2e()->setAccount(acc);
//TODO: This probably needs to have a better
// coupling, but it should work for now.
acc->e2e()->setAccount(acc);
return acc;
}
ClientSideEncryption* Account::e2e()
{
// Qt expects everything in the connect to be a pointer, so return a pointer.
return &_e2e;
// Qt expects everything in the connect to be a pointer, so return a pointer.
return &_e2e;
}
Account::~Account()
@@ -432,6 +439,9 @@ void Account::slotCredentialsAsked()
void Account::handleInvalidCredentials()
{
// Retrieving password will trigger remote wipe check job
retrieveAppPassword();
emit invalidCredentials();
}
@@ -503,4 +513,63 @@ void Account::setNonShib(bool nonShib)
}
}
void Account::setAppPassword(QString appPassword){
const QString kck = AbstractCredentials::keychainKey(
url().toString(),
davUser() + app_password,
id()
);
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
job->setInsecureFallback(false);
job->setKey(kck);
job->setBinaryData(appPassword.toLatin1());
connect(job, &WritePasswordJob::finished, [](Job *) {
qCInfo(lcAccount) << "appPassword stored in keychain";
});
job->start();
}
void Account::retrieveAppPassword(){
const QString kck = AbstractCredentials::keychainKey(
url().toString(),
credentials()->user() + app_password,
id()
);
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
job->setInsecureFallback(false);
job->setKey(kck);
connect(job, &WritePasswordJob::finished, [this](Job *incoming) {
ReadPasswordJob *readJob = static_cast<ReadPasswordJob *>(incoming);
QString pwd("");
// Error or no valid public key error out
if (readJob->error() == NoError &&
readJob->binaryData().length() > 0) {
pwd = readJob->binaryData();
}
emit appPasswordRetrieved(pwd);
});
job->start();
}
void Account::deleteAppPassword(){
const QString kck = AbstractCredentials::keychainKey(
url().toString(),
credentials()->user() + app_password,
id()
);
if (kck.isEmpty()) {
qCDebug(lcAccount) << "appPassword is empty";
return;
}
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
job->setInsecureFallback(false);
job->setKey(kck);
job->start();
}
} // namespace OCC

View File

@@ -41,6 +41,12 @@ class QNetworkReply;
class QUrl;
class QNetworkAccessManager;
namespace QKeychain {
class Job;
class WritePasswordJob;
class ReadPasswordJob;
}
namespace OCC {
class AbstractCredentials;
@@ -50,7 +56,6 @@ class QuotaInfo;
class AccessManager;
class SimpleNetworkJob;
/**
* @brief Reimplement this to handle SSL errors from libsync
* @ingroup libsync
@@ -236,6 +241,11 @@ public:
ClientSideEncryption* e2e();
/// Used in RemoteWipe
void retrieveAppPassword();
void setAppPassword(QString appPassword);
void deleteAppPassword();
public slots:
/// Used when forgetting credentials
void clearQNAMCache();
@@ -262,6 +272,9 @@ signals:
void accountChangedAvatar();
void accountChangedDisplayName();
/// Used in RemoteWipe
void appPasswordRetrieved(QString);
protected Q_SLOTS:
void slotCredentialsFetched();
void slotCredentialsAsked();

View File

@@ -32,6 +32,7 @@
#include <QUuid>
#include <keychain.h>
#include "common/utility.h"
#include "wordlist.h"
@@ -62,11 +63,11 @@ namespace {
namespace {
QByteArray BIO2ByteArray(BIO *b) {
int pending = BIO_ctrl_pending(b);
size_t pending = BIO_ctrl_pending(b);
char *tmp = (char *)calloc(pending+1, sizeof(char));
BIO_read(b, tmp, pending);
BIO_read(b, tmp, OCC::Utility::convertSizeToInt(pending));
QByteArray res(tmp, pending);
QByteArray res(tmp, OCC::Utility::convertSizeToInt(pending));
free(tmp);
return res;
@@ -549,7 +550,7 @@ QByteArray decryptStringAsymmetric(EVP_PKEY *privateKey, const QByteArray& data)
}
const auto ret = std::string((char*) out, outlen);
QByteArray raw((const char*) out, outlen);
QByteArray raw((const char*) out, OCC::Utility::convertSizeToInt(outlen));
qCInfo(lcCse()) << raw;
return raw;
}
@@ -603,7 +604,7 @@ QByteArray encryptStringAsymmetric(EVP_PKEY *publicKey, const QByteArray& data)
}
// Transform the encrypted data into base64.
QByteArray raw((const char*) out, outLen);
QByteArray raw((const char*) out, OCC::Utility::convertSizeToInt(outLen));
qCInfo(lcCse()) << raw.toBase64();
return raw.toBase64();
}

View File

@@ -432,6 +432,7 @@ void SignPublicKeyApiJob::start()
{
QNetworkRequest req;
req.setRawHeader("OCS-APIREQUEST", "true");
req.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/x-www-form-urlencoded"));
QUrlQuery query;
query.addQueryItem(QLatin1String("format"), QLatin1String("json"));
QUrl url = Utility::concatUrlPath(account()->url(), path());

View File

@@ -37,6 +37,12 @@
#include <QNetworkProxy>
#include <QStandardPaths>
#define QTLEGACY (QT_VERSION < QT_VERSION_CHECK(5,9,0))
#if !(QTLEGACY)
#include <QOperatingSystemVersion>
#endif
#define DEFAULT_REMOTE_POLL_INTERVAL 5000 // default remote poll time in milliseconds
#define DEFAULT_MAX_LOG_LINES 20000
@@ -174,7 +180,11 @@ bool ConfigFile::showInExplorerNavigationPane() const
{
const bool defaultValue =
#ifdef Q_OS_WIN
QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS10
#if QTLEGACY
(QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS10);
#else
QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10;
#endif
#else
false
#endif

View File

@@ -798,7 +798,11 @@ namespace { // Anonymous namespace for the recall feature
static void preserveGroupOwnership(const QString &fileName, const QFileInfo &fi)
{
#ifdef Q_OS_UNIX
chown(fileName.toLocal8Bit().constData(), -1, fi.groupId());
int chownErr = chown(fileName.toLocal8Bit().constData(), -1, fi.groupId());
if (chownErr) {
// TODO: Consider further error handling!
qCWarning(lcPropagateDownload) << QString("preserveGroupOwnership: chown error %1: setting group %2 failed on file %3").arg(chownErr).arg(fi.groupId()).arg(fileName);
}
#else
Q_UNUSED(fileName);
Q_UNUSED(fi);

View File

@@ -346,6 +346,7 @@ void PropagateUploadFileCommon::slotStartUpload(const QByteArray &transmissionCh
}
qDebug() << "prevModtime" << prevModtime << "Curr" << _item->_modtime;
done(SyncFileItem::SoftError, tr("Local file changed during syncing. It will be resumed."));
return;
}
quint64 fileSize = FileSystem::getSize(fullFilePath);

View File

@@ -177,6 +177,14 @@ QIcon Theme::themeIcon(const QString &name, bool sysTray, bool sysTrayMenuVisibl
return cached;
}
QIcon Theme::uiThemeIcon(const QString &iconName, bool uiHasDarkBg) const
{
QString themeResBasePath = ":/client/theme/";
QString iconPath = themeResBasePath + (uiHasDarkBg?"white/":"black/") + iconName;
std::string icnPath = iconPath.toUtf8().constData();
return QIcon(QPixmap(iconPath));
}
QString Theme::hidpiFileName(const QString &fileName, QPaintDevice *dev)
{
qreal devicePixelRatio = dev ? dev->devicePixelRatio() : qApp->primaryScreen()->devicePixelRatio();

View File

@@ -347,6 +347,14 @@ public:
* important dependency versions.
*/
virtual QString versionSwitchOutput() const;
/**
* @brief Request suitable QIcon resource depending on the background colour of the parent widget.
*
* This should be replaced (TODO) by a real theming implementation for the client UI
* (actually 2019/09/13 only systray theming).
*/
virtual QIcon uiThemeIcon(const QString &iconName, bool uiHasDarkBg) const;
protected:
#ifndef TOKEN_AUTH_ONLY

View File

@@ -40,3 +40,5 @@ System Volume Information
.nfs*
My Saved Places.
\#*#

View File

@@ -12,10 +12,10 @@ include_directories(${CMAKE_SOURCE_DIR}/src
${SQLITE3_INCLUDE_DIR}
)
include(owncloud_add_test.cmake)
include(nextcloud_add_test.cmake)
owncloud_add_test(OwncloudPropagator "")
owncloud_add_test(Updater "")
nextcloud_add_test(NextcloudPropagator "")
nextcloud_add_test(Updater "")
SET(FolderWatcher_SRC ../src/gui/folderwatcher.cpp)
@@ -29,49 +29,64 @@ IF( APPLE )
list(APPEND FolderWatcher_SRC ../src/gui/folderwatcher_mac.cpp)
list(APPEND FolderWatcher_SRC ../src/gui/socketapisocket_mac.mm)
ENDIF()
owncloud_add_test(NetrcParser ../src/cmd/netrcparser.cpp)
owncloud_add_test(OwnSql "")
owncloud_add_test(SyncJournalDB "")
owncloud_add_test(SyncFileItem "")
owncloud_add_test(ConcatUrl "")
owncloud_add_test(XmlParse "")
owncloud_add_test(ChecksumValidator "")
nextcloud_add_test(NetrcParser ../src/cmd/netrcparser.cpp)
nextcloud_add_test(OwnSql "")
nextcloud_add_test(SyncJournalDB "")
nextcloud_add_test(SyncFileItem "")
nextcloud_add_test(ConcatUrl "")
nextcloud_add_test(XmlParse "")
nextcloud_add_test(ChecksumValidator "")
owncloud_add_test(ExcludedFiles "")
nextcloud_add_test(ExcludedFiles "")
owncloud_add_test(FileSystem "")
owncloud_add_test(Utility "")
owncloud_add_test(SyncEngine "syncenginetestutils.h")
owncloud_add_test(SyncMove "syncenginetestutils.h")
owncloud_add_test(SyncConflict "syncenginetestutils.h")
owncloud_add_test(SyncFileStatusTracker "syncenginetestutils.h")
owncloud_add_test(ChunkingNg "syncenginetestutils.h")
owncloud_add_test(UploadReset "syncenginetestutils.h")
owncloud_add_test(AllFilesDeleted "syncenginetestutils.h")
owncloud_add_test(Blacklist "syncenginetestutils.h")
owncloud_add_test(FolderWatcher "${FolderWatcher_SRC}")
nextcloud_add_test(FileSystem "")
nextcloud_add_test(Utility "")
nextcloud_add_test(SyncEngine "syncenginetestutils.h")
nextcloud_add_test(SyncMove "syncenginetestutils.h")
nextcloud_add_test(SyncConflict "syncenginetestutils.h")
nextcloud_add_test(SyncFileStatusTracker "syncenginetestutils.h")
nextcloud_add_test(ChunkingNg "syncenginetestutils.h")
nextcloud_add_test(UploadReset "syncenginetestutils.h")
nextcloud_add_test(AllFilesDeleted "syncenginetestutils.h")
nextcloud_add_test(Blacklist "syncenginetestutils.h")
nextcloud_add_test(FolderWatcher "${FolderWatcher_SRC}")
if( UNIX AND NOT APPLE )
owncloud_add_test(InotifyWatcher "${FolderWatcher_SRC}")
nextcloud_add_test(InotifyWatcher "${FolderWatcher_SRC}")
endif(UNIX AND NOT APPLE)
owncloud_add_benchmark(LargeSync "syncenginetestutils.h")
nextcloud_add_benchmark(LargeSync "syncenginetestutils.h")
SET(FolderMan_SRC ../src/gui/folderman.cpp)
list(APPEND FolderMan_SRC ../src/gui/folder.cpp )
list(APPEND FolderMan_SRC ../src/gui/socketapi.cpp )
list(APPEND FolderMan_SRC ../src/gui/accountstate.cpp )
list(APPEND FolderMan_SRC ../src/gui/syncrunfilelog.cpp )
list(APPEND FolderMan_SRC ../src/gui/lockwatcher.cpp )
list(APPEND FolderMan_SRC ../src/gui/guiutility.cpp )
list(APPEND FolderMan_SRC ../src/gui/navigationpanehelper.cpp )
list(APPEND FolderMan_SRC ../src/gui/connectionvalidator.cpp )
list(APPEND FolderMan_SRC ../src/gui/clientproxy.cpp )
list(APPEND FolderMan_SRC ../src/gui/accountstate.cpp )
list(APPEND FolderMan_SRC ../src/gui/remotewipe.cpp )
list(APPEND FolderMan_SRC ${FolderWatcher_SRC})
list(APPEND FolderMan_SRC stub.cpp )
owncloud_add_test(FolderMan "${FolderMan_SRC}")
list(APPEND FolderMan_SRC stubfolderman.cpp )
nextcloud_add_test(FolderMan "${FolderMan_SRC}")
owncloud_add_test(OAuth "syncenginetestutils.h;../src/gui/creds/oauth.cpp")
SET(RemoteWipe_SRC ../src/gui/remotewipe.cpp)
list(APPEND RemoteWipe_SRC ../src/gui/clientproxy.cpp )
list(APPEND RemoteWipe_SRC ../src/gui/guiutility.cpp )
list(APPEND RemoteWipe_SRC ../src/gui/connectionvalidator.cpp )
list(APPEND RemoteWipe_SRC ../src/gui/accountstate.cpp )
list(APPEND RemoteWipe_SRC ../src/gui/socketapi.cpp )
list(APPEND RemoteWipe_SRC ../src/gui/folder.cpp )
list(APPEND RemoteWipe_SRC ../src/gui/syncrunfilelog.cpp )
list(APPEND RemoteWipe_SRC ../src/gui/folderwatcher_linux.cpp )
list(APPEND RemoteWipe_SRC ../src/gui/folderwatcher.cpp )
list(APPEND RemoteWipe_SRC ${RemoteWipe_SRC})
list(APPEND RemoteWipe_SRC stubremotewipe.cpp )
nextcloud_add_test(RemoteWipe "${RemoteWipe_SRC}")
nextcloud_add_test(OAuth "syncenginetestutils.h;../src/gui/creds/oauth.cpp")
configure_file(test_journal.db "${PROJECT_BINARY_DIR}/bin/test_journal.db" COPYONLY)

View File

@@ -1,6 +1,6 @@
find_package(Qt5 COMPONENTS Core Test Xml Network REQUIRED)
macro(owncloud_add_test test_class additional_cpp)
macro(nextcloud_add_test test_class additional_cpp)
set(CMAKE_AUTOMOC TRUE)
set(OWNCLOUD_TEST_CLASS ${test_class})
string(TOLOWER "${OWNCLOUD_TEST_CLASS}" OWNCLOUD_TEST_CLASS_LOWERCASE)
@@ -19,7 +19,7 @@ macro(owncloud_add_test test_class additional_cpp)
add_test(NAME ${OWNCLOUD_TEST_CLASS}Test COMMAND ${OWNCLOUD_TEST_CLASS}Test)
endmacro()
macro(owncloud_add_benchmark test_class additional_cpp)
macro(nextcloud_add_benchmark test_class additional_cpp)
set(CMAKE_AUTOMOC TRUE)
set(OWNCLOUD_TEST_CLASS ${test_class})
string(TOLOWER "${OWNCLOUD_TEST_CLASS}" OWNCLOUD_TEST_CLASS_LOWERCASE)

View File

@@ -1,7 +1,11 @@
// stub to prevent linker error
#include "accountmanager.h"
OCC::AccountManager *OCC::AccountManager::instance() { return static_cast<AccountManager *>(new QObject); }
void OCC::AccountManager::save(bool) { }
void OCC::AccountManager::saveAccountState(AccountState *) { }
void OCC::AccountManager::save(bool saveCredentials) { Q_UNUSED(saveCredentials); }
void OCC::AccountManager::deleteAccount(AccountState *) { }
void OCC::AccountManager::accountRemoved(OCC::AccountState*) { }
OCC::AccountStatePtr OCC::AccountManager::account(const QString &){ return AccountStatePtr(); }
void OCC::AccountManager::removeAccountFolders(OCC::AccountState*) { }
const QMetaObject OCC::AccountManager::staticMetaObject = QObject::staticMetaObject;

30
test/stubremotewipe.cpp Normal file
View File

@@ -0,0 +1,30 @@
// stub to prevent linker error
#include "accountmanager.h"
#include "accountstate.h"
#include "socketapi.h"
#include "folderman.h"
OCC::AccountManager *OCC::AccountManager::instance() { return static_cast<AccountManager *>(new QObject); }
void OCC::AccountManager::save(bool) { }
OCC::AccountState *OCC::AccountManager::addAccount(const AccountPtr& ac) { return new OCC::AccountState(ac); }
void OCC::AccountManager::deleteAccount(AccountState *) { }
void OCC::AccountManager::accountRemoved(OCC::AccountState*) { }
OCC::AccountStatePtr OCC::AccountManager::account(const QString &){ return AccountStatePtr(); }
const QMetaObject OCC::AccountManager::staticMetaObject = QObject::staticMetaObject;
OCC::FolderMan *OCC::FolderMan::instance() { return static_cast<FolderMan *>(new QObject); }
void OCC::FolderMan::wipeDone(OCC::AccountState*, bool) { }
OCC::Folder* OCC::FolderMan::addFolder(OCC::AccountState* as, OCC::FolderDefinition const &f) { return nullptr; }
void OCC::FolderMan::slotWipeFolderForAccount(OCC::AccountState*) { }
QString OCC::FolderMan::unescapeAlias(QString const&){ return QString(); }
QString OCC::FolderMan::escapeAlias(QString const&){ return QString(); }
void OCC::FolderMan::scheduleFolder(OCC::Folder*){ }
OCC::SocketApi *OCC::FolderMan::socketApi(){ return new SocketApi; }
OCC::Folder::Map OCC::FolderMan::map() { return OCC::Folder::Map(); }
void OCC::FolderMan::setSyncEnabled(bool) { }
void OCC::FolderMan::slotSyncOnceFileUnlocks(QString const&) { }
void OCC::FolderMan::slotScheduleETagJob(QString const&, OCC::RequestEtagJob*){ }
OCC::Folder *OCC::FolderMan::folderForPath(QString const&) { return nullptr; }
OCC::Folder* OCC::FolderMan::folder(QString const&) { return nullptr; }
void OCC::FolderMan::folderSyncStateChange(OCC::Folder*) { }
const QMetaObject OCC::FolderMan::staticMetaObject = QObject::staticMetaObject;

View File

@@ -39,6 +39,8 @@ private slots:
QVERIFY(excluded.isExcluded("/a/foo_conflict-bar", "/a", keepHidden));
QVERIFY(excluded.isExcluded("/a/foo (conflicted copy bar)", "/a", keepHidden));
QVERIFY(excluded.isExcluded("/a/.b", "/a", excludeHidden));
QVERIFY(excluded.isExcluded("/a/#b#", "/a", keepHidden));
}
};

View File

@@ -14,29 +14,10 @@
#include "account.h"
#include "accountstate.h"
#include "configfile.h"
#include "creds/httpcredentials.h"
#include "testhelper.h"
using namespace OCC;
class HttpCredentialsTest : public HttpCredentials {
public:
HttpCredentialsTest(const QString& user, const QString& password)
: HttpCredentials(user, password)
{}
void askFromUser() Q_DECL_OVERRIDE {
}
};
static FolderDefinition folderDefinition(const QString &path) {
FolderDefinition d;
d.localPath = path;
d.targetPath = path;
d.alias = path;
return d;
}
class HttpCredentials;
class TestFolderMan: public QObject
{

28
test/testhelper.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef TESTHELPER_H
#define TESTHELPER_H
#include "folder.h"
#include "creds/httpcredentials.h"
using namespace OCC;
class HttpCredentialsTest : public HttpCredentials {
public:
HttpCredentialsTest(const QString& user, const QString& password)
: HttpCredentials(user, password)
{}
void askFromUser() Q_DECL_OVERRIDE {
}
};
static FolderDefinition folderDefinition(const QString &path) {
FolderDefinition d;
d.localPath = path;
d.targetPath = path;
d.alias = path;
return d;
}
#endif // TESTHELPER_H

View File

@@ -8,21 +8,21 @@
#include <QDebug>
#include "propagatedownload.h"
#include "owncloudpropagator_p.h"
#include "nextcloudpropagator_p.h"
using namespace OCC;
namespace OCC {
QString OWNCLOUDSYNC_EXPORT createDownloadTmpFileName(const QString &previous);
}
class TestOwncloudPropagator : public QObject
class TestNextcloudPropagator : public QObject
{
Q_OBJECT
private slots:
void testUpdateErrorFromSession()
{
// OwncloudPropagator propagator( NULL, QLatin1String("test1"), QLatin1String("test2"), new ProgressDatabase);
// NextcloudPropagator propagator( NULL, QLatin1String("test1"), QLatin1String("test2"), new ProgressDatabase);
QVERIFY( true );
}
@@ -78,5 +78,5 @@ private slots:
}
};
QTEST_APPLESS_MAIN(TestOwncloudPropagator)
#include "testowncloudpropagator.moc"
QTEST_APPLESS_MAIN(TestNextcloudPropagator)
#include "testnextcloudpropagator.moc"

83
test/testremotewipe.cpp Normal file
View File

@@ -0,0 +1,83 @@
/*
* This software is in the public domain, furnished "as is", without technical
* support, and with no warranty, express or implied, as to its usefulness for
* any purpose.
*
*/
#include <qglobal.h>
#include <QTemporaryDir>
#include <QtTest>
#include "remotewipe.h"
#include "common/utility.h"
#include "folderman.h"
#include "account.h"
#include "accountstate.h"
#include "configfile.h"
#include "testhelper.h"
using namespace OCC;
class TestRemoteWipe: public QObject
{
Q_OBJECT
private slots:
// TODO
void testWipe(){
// QTemporaryDir dir;
// ConfigFile::setConfDir(dir.path()); // we don't want to pollute the user's config file
// QVERIFY(dir.isValid());
// QDir dirToRemove(dir.path());
// QVERIFY(dirToRemove.mkpath("nextcloud"));
// QString dirPath = dirToRemove.canonicalPath();
// AccountPtr account = Account::create();
// QVERIFY(account);
// auto manager = AccountManager::instance();
// QVERIFY(manager);
// AccountState *newAccountState = manager->addAccount(account);
// manager->save();
// QVERIFY(newAccountState);
// QUrl url("http://example.de");
// HttpCredentialsTest *cred = new HttpCredentialsTest("testuser", "secret");
// account->setCredentials(cred);
// account->setUrl( url );
// FolderMan *folderman = FolderMan::instance();
// folderman->addFolder(newAccountState, folderDefinition(dirPath + "/sub/nextcloud/"));
// // check if account exists
// qDebug() << "Does account exists?!";
// QVERIFY(!account->id().isEmpty());
// manager->deleteAccount(newAccountState);
// manager->save();
// // check if account exists
// qDebug() << "Does account exists yet?!";
// QVERIFY(account);
// // check if folder exists
// QVERIFY(dirToRemove.exists());
// // remote folders
// qDebug() << "Removing folder for account " << newAccountState->account()->url();
// folderman->slotWipeFolderForAccount(newAccountState);
// // check if folders dont exist anymore
// QCOMPARE(dirToRemove.exists(), false);
}
};
QTEST_APPLESS_MAIN(TestRemoteWipe)
#include "testremotewipe.moc"

View File

@@ -543,7 +543,7 @@ private slots:
QVERIFY(conflicts.size() == 2);
QVERIFY(conflicts[0].contains("A (conflicted copy"));
QVERIFY(conflicts[1].contains("B (conflicted copy"));
for (auto conflict : conflicts)
for (const auto& conflict : conflicts)
QDir(fakeFolder.localPath() + conflict).removeRecursively();
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
@@ -581,7 +581,7 @@ private slots:
auto conflicts = findConflicts(fakeFolder.currentLocalState());
QVERIFY(conflicts.size() == 1);
QVERIFY(conflicts[0].contains("A (conflicted copy"));
for (auto conflict : conflicts)
for (const auto& conflict : conflicts)
QDir(fakeFolder.localPath() + conflict).removeRecursively();
QVERIFY(fakeFolder.syncEngine().isAnotherSyncNeeded() == ImmediateFollowUp);

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