1
0
mirror of https://github.com/chylex/Nextcloud-Desktop.git synced 2026-04-14 01:30:37 +02:00

Compare commits

...

223 Commits

Author SHA1 Message Date
allexzander
6d3270dd25 Merge pull request #3934 from nextcloud/bump-version-3.3.6
Bump version to 3.3.6
2021-10-28 12:25:40 +03:00
alex-z
680ab37542 Bump version to 3.3.6
Signed-off-by: alex-z <blackslayer4@gmail.com>
2021-10-28 12:11:05 +03:00
allexzander
b59ec4a0bf Merge pull request #3931 from nextcloud/backport/3901/stable-3.3
[stable-3.3] Windows. Remove CWD from DLL search paths.
2021-10-28 12:04:14 +03:00
alex-z
9f74f8521e Windows. Remove CWD from DLL search paths.
Signed-off-by: alex-z <blackslayer4@gmail.com>
2021-10-28 09:03:55 +00:00
allexzander
e9a9455872 Merge pull request #3932 from nextcloud/backport/3844/stable-3.3
[stable-3.3] Remove Temporary solution for file restoration issue due to set the data-fingerprint.
2021-10-28 12:00:36 +03:00
alex-z
4584e8fa01 Remove Temporary solution for file restoration issue due to failing to set the data-fingerprint.
Signed-off-by: alex-z <blackslayer4@gmail.com>
2021-10-28 08:33:47 +00:00
Nextcloud bot
39831da3be [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-28 03:48:30 +00:00
Nextcloud bot
33e71a248c [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-27 03:52:38 +00:00
Nextcloud bot
44970c84f0 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-26 03:47:57 +00:00
Nextcloud bot
0f81d41935 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-25 03:44:38 +00:00
Nextcloud bot
c264a6025f [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-24 03:46:44 +00:00
Nextcloud bot
e0ead91e51 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-23 03:50:42 +00:00
Nextcloud bot
c63421ceaf [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-22 03:47:06 +00:00
Nextcloud bot
4ecd861aec [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-21 03:50:08 +00:00
Nextcloud bot
6b2d6abbed [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-20 04:08:11 +00:00
Matthieu Gallien
f751c951cf Merge pull request #3904 from nextcloud/backport/3885/stable-3.3
[stable-3.3] Only use basic authentication if needed
2021-10-19 14:35:49 +02:00
Felix Weilbach
68cb6a4d4e Only use basic authentication if needed
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-10-19 07:27:27 +00:00
Nextcloud bot
c207231dd1 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-19 03:48:43 +00:00
Nextcloud bot
c82b07a3f7 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-18 03:48:58 +00:00
Nextcloud bot
3ec9b62c10 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-17 03:48:09 +00:00
Nextcloud bot
3d9f2a2d8c [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-16 03:48:20 +00:00
Nextcloud bot
52cf1b1db3 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-15 03:53:57 +00:00
Nextcloud bot
ac96c05a1d [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-14 03:48:18 +00:00
Nextcloud bot
d9b53527d2 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-13 03:47:26 +00:00
Nextcloud bot
fc101f01ca [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-12 03:50:09 +00:00
Nextcloud bot
f6487b65a6 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-11 03:47:41 +00:00
Nextcloud bot
78612ae03b [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-10 03:49:03 +00:00
Nextcloud bot
80017d9eb0 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-09 04:05:50 +00:00
Nextcloud bot
7887e31447 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-08 03:48:47 +00:00
Nextcloud bot
ae319a1b17 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-07 03:50:25 +00:00
Nextcloud bot
90e89a7f94 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-06 03:47:22 +00:00
Nextcloud bot
840c5dcaa6 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-05 03:47:47 +00:00
Nextcloud bot
71133a3ab3 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-04 03:51:20 +00:00
Nextcloud bot
cfa4ac994f [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-03 03:53:03 +00:00
Nextcloud bot
5de9fb3cd4 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-10-01 03:51:10 +00:00
Felix Weilbach
0d9a6987eb Merge pull request #3857 from nextcloud/bump-version-3.3.5
Bump version to 3.3.5
2021-09-30 13:13:39 +02:00
Felix Weilbach
229bd8a745 Bump version to 3.3.5
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-09-30 13:10:53 +02:00
Felix Weilbach
2ded349f9c Merge pull request #3851 from nextcloud/backport/3827/stable-3.3
[stable-3.3] Don't log encryption data in release mode
2021-09-30 12:39:33 +02:00
Felix Weilbach
b27eb606ed Don't log encryption data in release mode
We deliver our builds to users with debug logging enabled to have an
easier time finding problems. However, logging all the encryption data
in this loop is too much and should not be done in release mode.

Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-09-30 10:23:19 +00:00
Matthieu Gallien
412be77929 Merge pull request #3850 from nextcloud/backport/3832/stable-3.3
[stable-3.3] Fix incorrect db name for nextcloud command line client.
2021-09-30 12:10:58 +02:00
alex-z
8d1aa2f38c Fix review comments + also check against trailing bakslash.
Signed-off-by: alex-z <blackslayer4@gmail.com>
2021-09-30 08:55:43 +00:00
alex-z
8233131897 Fix incorrect db name for nextcloud command line client.
Signed-off-by: alex-z <blackslayer4@gmail.com>
2021-09-30 08:55:43 +00:00
Nextcloud bot
e7e1114237 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-30 04:15:49 +00:00
Nextcloud bot
25b7f8f1f9 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-29 03:53:11 +00:00
Nextcloud bot
d23264f254 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-28 03:54:36 +00:00
Nextcloud bot
c5099f9134 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-27 03:55:14 +00:00
Nextcloud bot
5295340649 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-26 03:56:16 +00:00
Nextcloud bot
0be98b1610 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-25 03:54:53 +00:00
Nextcloud bot
12557272f7 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-24 03:58:39 +00:00
Nextcloud bot
c666592142 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-23 04:12:56 +00:00
Nextcloud bot
bf865f930d [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-22 03:57:03 +00:00
Nextcloud bot
9e932c9af9 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-21 03:57:32 +00:00
allexzander
dcc0fa9f9d Merge pull request #3817 from nextcloud/bump-3.3.4
Bump version to 3.3.4
2021-09-20 15:51:07 +03:00
alex-z
26dfa3983f Bump version to 3.3.4
Signed-off-by: alex-z <blackslayer4@gmail.com>
2021-09-20 14:44:22 +02:00
Nextcloud bot
ed99ffaeec [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-20 03:53:21 +00:00
Nextcloud bot
adf8f4bdb2 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-19 03:53:52 +00:00
Nextcloud bot
524eeac107 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-18 03:58:32 +00:00
Nextcloud bot
45830fbf0d [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-17 03:53:24 +00:00
Nextcloud bot
ac0cf09335 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-16 03:56:20 +00:00
Nextcloud bot
5c77aacfe9 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-15 03:55:59 +00:00
Matthieu Gallien
cc2548bcc7 Merge pull request #3791 from nextcloud/backport/3773/stable-3.3
[stable-3.3] Accept nc scheme in provider page
2021-09-14 18:49:23 +02:00
Felix Weilbach
63aaa8419d Accept nc scheme in provider page
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-09-14 14:33:53 +00:00
Nextcloud bot
6db2028725 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-14 04:00:36 +00:00
Nextcloud bot
8dcc0a3cbe [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-13 03:56:12 +00:00
Nextcloud bot
fee7801f98 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-12 03:57:52 +00:00
Nextcloud bot
735179047d [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-11 03:54:42 +00:00
Nextcloud bot
1badf7955a [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-10 04:06:13 +00:00
Nextcloud bot
5dd18690a0 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-09 03:54:52 +00:00
Matthieu Gallien
c4b188caee Merge pull request #3757 from nextcloud/backport/3746/stable-3.3
[stable-3.3] prevent infinte recursion when closing a websocket in case of SSL errors
2021-09-07 12:24:45 +02:00
Matthieu Gallien
5dccbbf343 prevent infinte recursion when closing a websocket in case of SSL errors
the slots connected to the web socket can be called even during close
and lead to infinite calls to close -> error slot -> close -> ...

Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
2021-09-07 12:24:10 +02:00
Matthieu Gallien
5ec5e2f03c Merge pull request #3756 from nextcloud/backport/3750/stable-3.3
[stable-3.3] macOS client is not able to do auto updates
2021-09-07 12:23:19 +02:00
Felix Weilbach
62ec748f57 macOS client is not able to do auto updates
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-09-07 07:43:15 +00:00
Nextcloud bot
d515337e36 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-07 03:55:29 +00:00
Nextcloud bot
8237f0085b [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-06 03:54:21 +00:00
Nextcloud bot
7841de3bee [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-05 03:53:55 +00:00
Nextcloud bot
2c3cef1c27 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-04 03:52:09 +00:00
Felix Weilbach
2d54bc4d17 Merge pull request #3742 from nextcloud/bump-3.3.3
Bump version to 3.3.3
2021-09-03 11:40:46 +02:00
Felix Weilbach
664ab345fa Bump version to 3.3.3
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-09-03 11:39:01 +02:00
Felix Weilbach
2eee656dec Merge pull request #3739 from nextcloud/backport/3727/stable-3.3
[stable-3.3] Only set dav user after login
2021-09-03 11:33:55 +02:00
Felix Weilbach
28c135c26f Only set dav user after login.
Setting the credentials of the account inside the auth widget is not a
good idea as that will destroy the previous credentials object which
may wait for a signal to be emitted by the credentials dialog that
was created by the credentials that are going to be deleted. Uff.

It should be enough to set the dav user only after login because the
dav user will never change.

See also the discussion here
https://github.com/nextcloud/desktop/issues/3677#issuecomment-907976839

Fixes #3677

Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-09-03 09:24:08 +00:00
Nextcloud bot
01fdd229ab [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-03 03:55:24 +00:00
Nextcloud bot
c1fefa3251 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-02 03:52:39 +00:00
Nextcloud bot
dcbb7847d0 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-09-01 03:52:14 +00:00
Nextcloud bot
0ee03468c6 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-31 03:53:32 +00:00
Nextcloud bot
ef7e29a0d8 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-30 03:52:25 +00:00
Nextcloud bot
c19d489852 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-29 03:51:22 +00:00
Nextcloud bot
3e56ebcfff [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-28 04:23:37 +00:00
Nextcloud bot
189ada15fd [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-27 03:53:56 +00:00
Matthieu Gallien
50453d9d7e Merge pull request #3718 from nextcloud/release-3.3.2
Release 3.3.2
2021-08-26 11:08:51 +02:00
Matthieu Gallien
2740fea577 release 3.3.2 version
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
2021-08-26 11:04:41 +02:00
allexzander
02a95b6f57 Merge pull request #3717 from nextcloud/backport/3698/stable-3.3
[stable-3.3] Update nextcloudcmd documentation.
2021-08-26 11:01:53 +03:00
allexzander
3aeeeb56ff Update nextcloudcmd documentation.
Signed-off-by: allexzander <blackslayer4@gmail.com>
2021-08-26 07:51:51 +00:00
Nextcloud bot
9e6750f3d2 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-26 03:53:38 +00:00
Nextcloud bot
ff38f1cffc [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-25 03:51:33 +00:00
Matthieu Gallien
58f34bd0c6 Merge pull request #3711 from nextcloud/backport/3709/stable-3.3
[stable-3.3] support server versions for one year after it is end of life
2021-08-24 17:01:14 +02:00
Matthieu Gallien
44f89224b3 support server versions for one year after it is end of life
according to https://github.com/nextcloud/server/wiki/Maintenance-and-Release-Schedule

Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
2021-08-24 14:48:33 +00:00
Nextcloud bot
cf8b2c98c7 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-24 03:52:28 +00:00
Matthieu Gallien
35b55d7221 Merge pull request #3706 from nextcloud/backport/3621/stable-3.3
[stable-3.3] Bugfix/nextcloud cmd dav fix
2021-08-23 17:20:14 +02:00
allexzander
9492defbe2 Use separate arguments for a remote root and do not use dav or webdav in the server's URL
Signed-off-by: allexzander <blackslayer4@gmail.com>
2021-08-23 15:11:44 +00:00
Nextcloud bot
8fbc25a0d7 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-23 03:49:39 +00:00
Nextcloud bot
c05136ce50 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-22 03:50:11 +00:00
Nextcloud bot
60542aec87 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-21 03:54:46 +00:00
Nextcloud bot
6155b24c60 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-19 03:50:39 +00:00
Matthieu Gallien
3b75cddefb Merge pull request #3686 from nextcloud/backport/3680/stable-3.3
[stable-3.3] Fix macOS app bundle name in packaging scripts
2021-08-18 11:29:45 +02:00
znerol
75307b70c2 Fix macOS app bundle name in packaging scripts
Signed-off-by: znerol <lo+github@znerol.ch>
2021-08-18 07:54:02 +00:00
Nextcloud bot
23591f385e [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-18 03:52:40 +00:00
Nextcloud bot
82d8c363c5 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-17 03:53:23 +00:00
Matthieu Gallien
b05d2d791e Merge pull request #3676 from nextcloud/bugfix/checksumsParseIssue
Bugfix/checksums parse issue
2021-08-16 14:08:41 +02:00
Hannah von Reth
4df0ddcbd5 Add workaround for issue discovered in https://github.com/owncloud/core/pull/38304 2021-08-16 13:05:39 +02:00
Hannah von Reth
26ca566428 Make findBestChecksum case insensitive
Especially the casing of ADLER32 did not match the server.
2021-08-16 13:05:34 +02:00
Nextcloud bot
21caff6dd5 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-16 03:51:49 +00:00
Nextcloud bot
5d3cd92631 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-15 03:51:24 +00:00
Nextcloud bot
aa8521c70f [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-14 03:53:15 +00:00
Nextcloud bot
1865bc6881 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-13 03:51:38 +00:00
Matthieu Gallien
cd934ba80c Merge pull request #3656 from nextcloud/backport/3655/stable-3.3
[stable-3.3] Return the login name instead of user id
2021-08-12 15:29:22 +02:00
Felix Weilbach
5202df4407 Return the login name instead of user id
App password and login name need to match. If authResult() returns the
user id the user id will be stored in webdav_user

Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-08-12 13:17:57 +00:00
Felix Weilbach
99bcf30f77 Merge pull request #3650 from nextcloud/bump-3.3.1
Bump to version 3.3.1
2021-08-12 10:36:42 +02:00
Felix Weilbach
56e8561e64 Bump to version 3.3.1
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-08-12 10:35:11 +02:00
Nextcloud bot
05fef8e463 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-12 03:53:16 +00:00
Matthieu Gallien
6f5c61e442 Merge pull request #3648 from nextcloud/backport/3646/stable-3.3
[stable-3.3] Enforce fetching of user id
2021-08-11 18:51:29 +02:00
Felix Weilbach
1e28185ee9 Enforce fetching of user id
With the change of commit 3e61bdc431 and
the relase of v3.3.0 users that had their email address used as login
are not able to login anymore. The dav_user should be empty if users
tried to create a account in the meantime. Therefore we fetch the user
id in the case dav_user (and then Account::_davUser) is empty. We then
store the user id in dav_user.

Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-08-11 16:43:11 +00:00
Matthieu Gallien
4d7f72e3a1 Merge pull request #3647 from nextcloud/backport/3632/stable-3.3
[stable-3.3] Ensure that the users id is used for accessing webdav
2021-08-11 16:58:39 +02:00
Felix Weilbach
6a414d5fb3 Ensure that the users id is used for accessing webdav
https://docs.nextcloud.com/server/latest/developer_manual/client_apis/LoginFlow/index.html#obtaining-the-login-credentials
states that the email address can be used for login but it's not
allowed to use the email address to access webdav.

Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-08-11 14:18:35 +00:00
Nextcloud bot
694c6e7214 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-11 03:53:48 +00:00
Nextcloud bot
e0e4e9778b [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-10 04:09:05 +00:00
Nextcloud bot
7baa66b83e [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-09 03:53:21 +00:00
Nextcloud bot
301bb2024e [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-08 03:48:27 +00:00
Nextcloud bot
f7fce0100b [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-07 03:57:06 +00:00
Nextcloud bot
af894485b4 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-06 04:01:23 +00:00
Nextcloud bot
2fb609fa98 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-05 03:53:30 +00:00
Nextcloud bot
c4627c3c04 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-04 03:53:10 +00:00
Nextcloud bot
5f0e8b8268 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-03 03:52:44 +00:00
Nextcloud bot
99c6bee64b [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-02 03:26:03 +00:00
Nextcloud bot
853bfed89a [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-08-01 03:27:14 +00:00
Nextcloud bot
86dc3fefc8 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-31 03:32:43 +00:00
Nextcloud bot
ea800b638d [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-30 03:24:19 +00:00
Matthieu Gallien
a2e69d8574 Merge pull request #3610 from nextcloud/backport/3609/stable-3.3
[stable-3.3] Update supported server versions
2021-07-29 12:03:32 +02:00
Felix Weilbach
0178b322f9 Update supported server versions
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-29 10:03:10 +00:00
Felix Weilbach
acf3bf0959 Merge pull request #3607 from nextcloud/bump-version-3.3.0
Bump version 3.3.0
2021-07-29 10:40:19 +02:00
Felix Weilbach
49647c6267 Bump version 3.3.0
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-29 10:36:26 +02:00
Matthieu Gallien
0569b2bab3 Merge pull request #3602 from nextcloud/bugfix/crashInAccountDavPath
prevent crash in Accont::davPath without credentials
2021-07-29 10:31:48 +02:00
Matthieu Gallien
badb5c1fba fix review comment
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
2021-07-29 08:27:53 +00:00
Matthieu Gallien
391935c90f prevent crash in Accont::davPath without credentials
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
2021-07-29 08:27:53 +00:00
Nextcloud bot
9808f83913 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-29 03:23:50 +00:00
Matthieu Gallien
ae33a89844 Merge pull request #3595 from ivaradi/remove-groovy
Do not build for Groovy
2021-07-28 17:31:42 +02:00
István Váradi
e0697eefa0 Do not build for Groovy
Signed-off-by: István Váradi <ivaradi@varadiistvan.hu>
2021-07-28 14:46:55 +00:00
Matthieu Gallien
b50851726d Merge pull request #3599 from nextcloud/update-docs-news
Update improvements and news in the documentation
2021-07-28 16:44:47 +02:00
Felix Weilbach
55067c55a7 Update improvements and news in the documentation
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-28 12:59:36 +00:00
Matthieu Gallien
8d5612219c Merge pull request #3596 from nextcloud/bugfix/main-dialog-dont-constrain-background-size
Don't constrain size of hover background
2021-07-28 12:44:39 +02:00
Felix Weilbach
7bb0c588c1 Don't constrain size of hover background
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-28 10:29:04 +00:00
Matthieu Gallien
d5857730d1 Merge pull request #3592 from nextcloud/bugfix/properWebdavUrlOnAccountSetup
in wizard always use the correct way to get dav path
2021-07-28 12:27:58 +02:00
Matthieu Gallien
d2133da3ee fix review comments
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
2021-07-28 12:27:02 +02:00
Matthieu Gallien
c40d276770 remove dead code around overriding dav path in URL
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
2021-07-28 12:12:17 +02:00
Matthieu Gallien
77433f7e1d in wizard always use the correct way to get dav path
fixes listing being incorrect when using dav endpoint

Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
2021-07-28 09:45:49 +00:00
Matthieu Gallien
6ac719d74c Merge pull request #3339 from nextcloud/ci/addCodeCoverage
takes ECMCoverageOption from ECM to enable code coverage analysis
2021-07-28 11:43:49 +02:00
Matthieu Gallien
f9bfd8adec takes ECMCoverageOption from ECM to enable code coverage analysis
Signed-off-by: Matthieu Gallien <matthieu_gallien@yahoo.fr>
2021-07-28 09:26:40 +00:00
Matthieu Gallien
1e91e1bd96 Merge pull request #3586 from nextcloud/bugfix/fix-crash-folder-isSyncRunning
Fix crash in Folder::isSyncRunning()
2021-07-28 11:25:17 +02:00
allexzander
88d18fd5f3 Invoke 'bool Folder::isSyncRunning() const' from tests.
Signed-off-by: allexzander <blackslayer4@gmail.com>
2021-07-28 08:58:00 +00:00
allexzander
98ae715905 Fix crash in Folder::isSyncRunning()
Signed-off-by: allexzander <blackslayer4@gmail.com>
2021-07-28 08:58:00 +00:00
allexzander
e3ca1f09de Merge pull request #3594 from nextcloud/bugfix/revert-checksum-mismatch-skip
Revert: Added config parameter that allows to bypass checksum validation failure.
2021-07-28 11:55:21 +03:00
allexzander
8122c63ebc Revert Added config parameter that allows to bypass checksum validation failure.
Signed-off-by: allexzander <blackslayer4@gmail.com>
2021-07-28 07:57:10 +00:00
Nextcloud bot
76308d5155 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-28 03:26:46 +00:00
John Molakvoæ
f5210c893e Merge pull request #3492 from nextcloud/feat/rebase-template 2021-07-27 14:41:23 +02:00
John Molakvoæ
7c54065ed7 Delete rebase.yml 2021-07-27 10:47:21 +00:00
John Molakvoæ
dd9836ea5f Create command-rebase.yml 2021-07-27 10:47:21 +00:00
Nextcloud bot
ac6cf3ef96 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-27 03:25:18 +00:00
Nextcloud bot
a87c3f28a2 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-26 03:26:18 +00:00
Nextcloud bot
afac8c384d [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-25 03:27:44 +00:00
Nextcloud bot
b628349dc7 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-24 03:30:34 +00:00
Valdnet
a4dc7a938a Merge pull request #3579 from nextcloud/Valdnet-patch-3
l10n: Change to uppercase
2021-07-23 09:56:48 +02:00
Valdnet
9dee4b1a7a Merge branch 'master' into Valdnet-patch-3 2021-07-23 09:07:18 +02:00
Nextcloud bot
2addea18ff [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-23 03:26:47 +00:00
Felix Weilbach
8bbe71c8a2 Merge pull request #3582 from nextcloud/bugfix/make-main-dialog-window
Make main dialog normal window when displayed as regular window
2021-07-22 18:06:48 +02:00
Valdnet
bc9d3c5936 l10n: Change to uppercase 2021-07-22 15:47:52 +00:00
Valdnet
7db51e9029 l10n: Change to uppercase
Signed-off-by: Valdnet <47037905+Valdnet@users.noreply.github.com>
2021-07-22 15:47:52 +00:00
Felix Weilbach
a421ebf01c Make main dialog normal window when displayed as regular window
This will enable users to minimize the dialog.

Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-22 10:34:13 +02:00
allexzander
2e07e93a42 Merge pull request #3581 from nextcloud/bump-version-3.2.82
Bump version to 3.3.0-rc2
2021-07-22 10:19:31 +03:00
allexzander
d9a8a7e0ac Bump version to 3.3.0-rc2
Signed-off-by: allexzander <blackslayer4@gmail.com>
2021-07-22 10:16:37 +03:00
Nextcloud bot
898fb3c6a8 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-22 03:28:31 +00:00
Matthieu Gallien
a8aa035065 Merge pull request #3542 from nextcloud/bugfix/enforce-https-with-flow2
Enforce https in flow2 for https connections
2021-07-21 20:34:42 +02:00
Felix Weilbach
302651620b Use Q_UNUSED instead of commenting out arg names
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-21 17:15:11 +00:00
Felix Weilbach
3f6bb4a929 Use QStringLiteral instead of plain strings
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-21 17:15:11 +00:00
Felix Weilbach
ee49a7ed52 Fix review comments
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-21 17:15:11 +00:00
Felix Weilbach
e4f92ad1a1 Enforce https in flow1 and flow2 for https connections
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-21 17:15:11 +00:00
Matthieu Gallien
15affdbfda Merge pull request #3498 from nextcloud/bugfix/qml-warnings
Fix QML Warnings and create custom component for the activity list
2021-07-21 19:13:00 +02:00
Camila
6886d6213a Add custom component ActivityItem.
That also addresses QML warnings.

Signed-off-by: Camila <hello@camila.codes>
2021-07-21 17:03:26 +02:00
Camila
79dd4f73fe Fix QML warning: Unable to assign [undefined] to QFont.
Signed-off-by: Camila <hello@camila.codes>
2021-07-21 14:46:04 +00:00
Matthieu Gallien
b536b73c97 Merge pull request #3565 from nextcloud/bugfix/fixSlowMenuInSettings
do not block account menu: availability checking can be slow
2021-07-21 16:42:35 +02:00
Matthieu Gallien
a8ef8bdcb8 do not block account menu: availability checking can be slow
ignore availability that can be very slow to check with CfApi virtual
files plugin

Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
2021-07-21 12:58:23 +00:00
Matthieu Gallien
45538857cf Merge pull request #3345 from nextcloud/ci/testAppveyor
Ci/test appveyor
2021-07-21 14:12:52 +02:00
Matthieu Gallien
2bf757a657 only run the pipeline for master branch and pull requests
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
2021-07-21 11:33:07 +00:00
Matthieu Gallien
bbcfe56cfd execute automated tests but do not fail if there are errors
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
2021-07-21 11:33:07 +00:00
Matthieu Gallien
360118634d build the nextcloud client and not something else
Signed-off-by: Matthieu Gallien <matthieu_gallien@yahoo.fr>
2021-07-21 11:33:07 +00:00
Matthieu Gallien
9295bb42d6 update CraftMaster git repository
Signed-off-by: Matthieu Gallien <matthieu_gallien@yahoo.fr>
2021-07-21 11:33:07 +00:00
Matthieu Gallien
505121f394 upgrade appveyor support to MSVC 2019
Signed-off-by: Matthieu Gallien <matthieu_gallien@yahoo.fr>
2021-07-21 11:33:07 +00:00
allexzander
309e8bd183 Merge pull request #3566 from nextcloud/bugfix/desktop-client-high-cpu-usage-on-auto-update
Show custom QDialog instead of QMessageBox when update is ready.
2021-07-21 14:26:11 +03:00
allexzander
801e4ad363 Create QMessageBox on heap when the update is ready. Do not return true from OCUpdater to allow for a proper app::quit
Signed-off-by: allexzander <blackslayer4@gmail.com>
2021-07-21 14:23:43 +03:00
Matthieu Gallien
58cf46f435 Merge pull request #3569 from nextcloud/bugfix/fixPermissionsLog
print the real permissions string instead of its address
2021-07-21 10:39:10 +02:00
Matthieu Gallien
1fca07546c print the real permissions string instead of its address
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
2021-07-21 08:25:42 +00:00
Felix Weilbach
9d2cb53cff Merge pull request #3574 from nextcloud/bugfix/open-main-dialog-gnome-always
Open main dialog gnome always
2021-07-21 09:16:01 +02:00
Felix Weilbach
4e95e32791 Call setClosed() on correct Object
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-20 12:56:00 +02:00
Felix Weilbach
89fea30a3b Remove Q_INVOKABLE from signals because it's not needed
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-20 12:55:37 +02:00
Felix Weilbach
e283c166de Merge pull request #3488 from nextcloud/bugfix/remove-unused-variable
Remove unused pushNotifications variable
2021-07-20 11:05:13 +02:00
Felix Weilbach
12bdd8742b Remove unnused variable
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-20 07:43:36 +00:00
Felix Weilbach
38467b2e30 Remove unused pushNotifications variable
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-20 07:43:36 +00:00
Nextcloud bot
e46ac74ba4 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-20 03:27:06 +00:00
Nextcloud bot
07b390fccc [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-18 03:48:19 +00:00
Nextcloud bot
c1b807dbff [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-17 04:08:12 +00:00
Matthieu Gallien
dc452feadd Merge pull request #3558 from nextcloud/bugfix/userStatusTooLongAccountMenu
Bugfix/user status too long account menu
2021-07-16 17:40:22 +02:00
Matthieu Gallien
064f64f06d fix width of user status message to not overlap other elements
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
2021-07-16 15:19:20 +00:00
Matthieu Gallien
260e1d77f5 clean indentation in UserLine.qml
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
2021-07-16 15:19:20 +00:00
Matthieu Gallien
1eca55a386 Merge pull request #3557 from nextcloud/bugfix/userStatusTooLong
fix size of the Label with user status
2021-07-16 17:18:03 +02:00
Matthieu Gallien
c2602135ab fix size of the Label with user status
ensure the label width is not higher than the parent to ensure log
string get elided as expected

Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
2021-07-16 13:04:33 +00:00
Matthieu Gallien
b72d1af50a Merge pull request #3541 from nextcloud/bugfix/use-dav-instead-of-webdav
Use dav instead of webdav
2021-07-16 15:03:17 +02:00
Felix Weilbach
3e61bdc431 Use dav instead of webdav
Fixes #3342

Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-16 12:42:02 +00:00
Matthieu Gallien
545592c472 Merge pull request #3552 from nextcloud/bugfix/remove-request-to-config-for-uservisibleurl
Remove request to config for userVisibleURL.
2021-07-16 14:32:36 +02:00
allexzander
de627a9b7c Remove request to config for userVisibleURL.
Signed-off-by: allexzander <blackslayer4@gmail.com>
2021-07-16 06:45:41 +00:00
Nextcloud bot
5fe4784cbc [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-16 03:51:28 +00:00
Matthieu Gallien
ff4f4255b3 Merge pull request #3548 from nextcloud/bugfix/screenshots
Update screenshot in README.md
2021-07-15 19:04:01 +02:00
Felix Weilbach
c00f871b95 Update screenshot in README.md
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-15 15:33:17 +00:00
Felix Weilbach
3a99010cdb Remove unused screenshots
Signed-off-by: Felix Weilbach <felix.weilbach@nextcloud.com>
2021-07-15 15:33:17 +00:00
Nextcloud bot
d9246910b4 [tx-robot] updated from transifex
Signed-off-by: Nextcloud bot <bot@nextcloud.com>
2021-07-15 12:15:40 +00:00
Nextcloud bot
387bb29cbd [tx-robot] updated from transifex 2021-07-15 09:30:49 +00:00
138 changed files with 66698 additions and 32805 deletions

27
.github/workflows/command-rebase.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
# This workflow is provided via the organization template repository
#
# https://github.com/nextcloud/.github
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
on:
issue_comment:
types: [ created ]
name: Automatic Rebase
jobs:
rebase:
name: Rebase
# On pull requests and if the comment starts with `/rebase`
if: github.event.issue.pull_request != '' && startsWith(github.event.comment.body, '/rebase')
runs-on: ubuntu-latest
steps:
- name: Checkout the latest code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Automatic Rebase
uses: cirrus-actions/rebase@1.5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,18 +0,0 @@
on:
issue_comment:
types: [created]
name: Automatic Rebase
jobs:
rebase:
name: Rebase
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase')
runs-on: ubuntu-latest
steps:
- name: Checkout the latest code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Automatic Rebase
uses: cirrus-actions/rebase@1.3.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -22,5 +22,6 @@ Icon=@APPLICATION_EXECUTABLE@
# Translations # Translations
Icon[bg_BG]=@APPLICATION_ICON_NAME@ Icon[bg_BG]=@APPLICATION_ICON_NAME@
Name[bg_BG]=@APPLICATION_NAME@ десктоп клиент за синхронизиране
Comment[bg_BG]=@APPLICATION_NAME@ десктоп клиент за синхронизиране Comment[bg_BG]=@APPLICATION_NAME@ десктоп клиент за синхронизиране
GenericName[bg_BG]=Синхронизиране на папка GenericName[bg_BG]=Синхронизиране на папка

View File

@@ -21,7 +21,7 @@ Icon=@APPLICATION_EXECUTABLE@
# Translations # Translations
Icon[de]=@APPLICATION_ICON_NAME@ Icon[de_DE]=@APPLICATION_ICON_NAME@
Name[de]=@APPLICATION_NAME@ Desktop Name[de_DE]=@APPLICATION_NAME@ Client zur Desktop-Synchronisierung
Comment[de]=@APPLICATION_NAME@ Client zur Desktop-Synchronisierung Comment[de_DE]=@APPLICATION_NAME@ Client zur Desktop-Synchronisierung
GenericName[de]=Ordner-Synchronisation GenericName[de_DE]=Ordnersynchronisierung

View File

@@ -22,5 +22,6 @@ Icon=@APPLICATION_EXECUTABLE@
# Translations # Translations
Icon[en_GB]=@APPLICATION_ICON_NAME@ Icon[en_GB]=@APPLICATION_ICON_NAME@
Name[en_GB]=@APPLICATION_NAME@ Desktop
Comment[en_GB]=@APPLICATION_NAME@ desktop synchronisation client Comment[en_GB]=@APPLICATION_NAME@ desktop synchronisation client
GenericName[en_GB]=Folder Sync GenericName[en_GB]=Folder Sync

View File

@@ -22,5 +22,6 @@ Icon=@APPLICATION_EXECUTABLE@
# Translations # Translations
Icon[hr]=@APPLICATION_ICON_NAME@ Icon[hr]=@APPLICATION_ICON_NAME@
Name[hr]=@APPLICATION_NAME@ Desktop
Comment[hr]=@APPLICATION_NAME@ klijent za sinkronizaciju računala Comment[hr]=@APPLICATION_NAME@ klijent za sinkronizaciju računala
GenericName[hr]=Sinkronizacija mapa GenericName[hr]=Sinkronizacija mapa

View File

@@ -22,5 +22,6 @@ Icon=@APPLICATION_EXECUTABLE@
# Translations # Translations
Icon[mk]=@APPLICATION_ICON_NAME@ Icon[mk]=@APPLICATION_ICON_NAME@
Name[mk]=@APPLICATION_NAME@ Десктоп
Comment[mk]=@APPLICATION_NAME@ клиент за синхронизација на компјутер Comment[mk]=@APPLICATION_NAME@ клиент за синхронизација на компјутер
GenericName[mk]=Папка за синхронизација GenericName[mk]=Папка за синхронизација

View File

@@ -22,5 +22,6 @@ Icon=@APPLICATION_EXECUTABLE@
# Translations # Translations
Icon[ro]=@APPLICATION_ICON_NAME@ Icon[ro]=@APPLICATION_ICON_NAME@
Name[ro]=@Numele_aplicației@ Client de sincronizare pentru PC
Comment[ro]=@APPLICATION_NAME@ client de sincronizare pentru desktop Comment[ro]=@APPLICATION_NAME@ client de sincronizare pentru desktop
GenericName[ro]=Sincronizare director GenericName[ro]=Sincronizare director

View File

@@ -22,5 +22,6 @@ Icon=@APPLICATION_EXECUTABLE@
# Translations # Translations
Icon[ru]=@APPLICATION_ICON_NAME@ Icon[ru]=@APPLICATION_ICON_NAME@
Name[ru]=@APPLICATION_NAME@ Desktop
Comment[ru]=Клиент синхронизации @APPLICATION_NAME@ для ПК Comment[ru]=Клиент синхронизации @APPLICATION_NAME@ для ПК
GenericName[ru]=Синхронизация папок GenericName[ru]=Синхронизация папок

View File

@@ -22,5 +22,6 @@ Icon=@APPLICATION_EXECUTABLE@
# Translations # Translations
Icon[sc]=@NÙMENE_ICONA_APLICATZIONE@ Icon[sc]=@NÙMENE_ICONA_APLICATZIONE@
Name[sc]=@NÙMENE_APLICATZIONE@ Iscrivania
Comment[sc]=@NÙMENE_APLICATZIONE@ cliente de sincronizatzione iscrivania Comment[sc]=@NÙMENE_APLICATZIONE@ cliente de sincronizatzione iscrivania
GenericName[sc]=Sincronizadore de cartellas GenericName[sc]=Sincronizadore de cartellas

View File

@@ -0,0 +1,27 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ Desktop
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_ICON_NAME@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
MimeType=application/vnd.@APPLICATION_EXECUTABLE@;
Actions=Quit;
# Translations
[Desktop Action Quit]
Exec=@APPLICATION_EXECUTABLE@ --quit
Name=Quit @APPLICATION_NAME@
Icon=@APPLICATION_EXECUTABLE@
# Translations
Icon[th_TH]=@APPLICATION_ICON_NAME@
Name[th_TH]=@APPLICATION_NAME@ เดสก์ท็อป
Comment[th_TH]=ไคลเอ็นต์ซิงโครไนซ์ @APPLICATION_NAME@ บนเดสก์ท็อป
GenericName[th_TH]=ซิงค์โฟลเดอร์

View File

@@ -0,0 +1,27 @@
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=@APPLICATION_EXECUTABLE@
Name=@APPLICATION_NAME@ Desktop
Comment=@APPLICATION_NAME@ desktop synchronization client
GenericName=Folder Sync
Icon=@APPLICATION_ICON_NAME@
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
MimeType=application/vnd.@APPLICATION_EXECUTABLE@;
Actions=Quit;
# Translations
[Desktop Action Quit]
Exec=@APPLICATION_EXECUTABLE@ --quit
Name=Quit @APPLICATION_NAME@
Icon=@APPLICATION_EXECUTABLE@
# Translations
Icon[vi]=@APPLICATION_ICON_NAME@
Name[vi]=@APPLICATION_NAME@ Máy tính
Comment[vi]=Ứng dụng đồng bộ @APPLICATION_NAME@ cho máy tính
GenericName[vi]=Đồng bộ thư mục

View File

@@ -36,6 +36,8 @@ endif()
set( CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules ) set( CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules )
include(ECMCoverageOption)
if(NOT CRASHREPORTER_EXECUTABLE) if(NOT CRASHREPORTER_EXECUTABLE)
set(CRASHREPORTER_EXECUTABLE "${APPLICATION_EXECUTABLE}_crash_reporter") set(CRASHREPORTER_EXECUTABLE "${APPLICATION_EXECUTABLE}_crash_reporter")
endif() endif()

View File

@@ -4,7 +4,7 @@ The :computer: Nextcloud Desktop Client is a tool to synchronize files from Next
with your computer. with your computer.
<p align="center"> <p align="center">
<img src="https://nextcloud.com/wp-content/themes/next/assets/img/clients/desktop/macsettings.png?x16328" alt="Desktop Client on Mac OS]"> <img src="doc/images/main_dialog_christine.png" alt="Desktop Client on Windows" width="450">
</p> </p>
## :blue_heart: :tada: Contributing ## :blue_heart: :tada: Contributing

View File

@@ -1,11 +1,11 @@
set( MIRALL_VERSION_MAJOR 3 ) set( MIRALL_VERSION_MAJOR 3 )
set( MIRALL_VERSION_MINOR 2 ) set( MIRALL_VERSION_MINOR 3 )
set( MIRALL_VERSION_PATCH 81 ) set( MIRALL_VERSION_PATCH 6 )
set( MIRALL_VERSION_YEAR 2021 ) set( MIRALL_VERSION_YEAR 2021 )
set( MIRALL_SOVERSION 0 ) set( MIRALL_SOVERSION 0 )
# Minimum supported server version according to https://docs.nextcloud.com/server/latest/admin_manual/release_schedule.html # Minimum supported server version according to https://docs.nextcloud.com/server/latest/admin_manual/release_schedule.html
set(NEXTCLOUD_SERVER_VERSION_MIN_SUPPORTED_MAJOR 19) set(NEXTCLOUD_SERVER_VERSION_MIN_SUPPORTED_MAJOR 16)
set(NEXTCLOUD_SERVER_VERSION_MIN_SUPPORTED_MINOR 0) set(NEXTCLOUD_SERVER_VERSION_MIN_SUPPORTED_MINOR 0)
set(NEXTCLOUD_SERVER_VERSION_MIN_SUPPORTED_PATCH 0) set(NEXTCLOUD_SERVER_VERSION_MIN_SUPPORTED_PATCH 0)

View File

@@ -15,10 +15,10 @@ OBS_PROJECT_BETA=home:ivaradi:beta
OBS_PACKAGE=nextcloud-desktop OBS_PACKAGE=nextcloud-desktop
if test "${DRONE_TARGET_BRANCH}" = "stable-2.6"; then if test "${DRONE_TARGET_BRANCH}" = "stable-2.6"; then
UBUNTU_DISTRIBUTIONS="bionic focal groovy hirsute impish" UBUNTU_DISTRIBUTIONS="bionic focal hirsute impish"
DEBIAN_DISTRIBUTIONS="buster stretch testing" DEBIAN_DISTRIBUTIONS="buster stretch testing"
else else
UBUNTU_DISTRIBUTIONS="focal groovy hirsute impish" UBUNTU_DISTRIBUTIONS="focal hirsute impish"
DEBIAN_DISTRIBUTIONS="testing" DEBIAN_DISTRIBUTIONS="testing"
fi fi

View File

@@ -3,7 +3,7 @@
# Always enable the new 10.10 finder plugin if available # Always enable the new 10.10 finder plugin if available
if [ -x "$(command -v pluginkit)" ]; then if [ -x "$(command -v pluginkit)" ]; then
# add it to DB. This happens automatically too but we try to push it a bit harder for issue #3463 # add it to DB. This happens automatically too but we try to push it a bit harder for issue #3463
pluginkit -a "/Applications/@APPLICATION_EXECUTABLE@.app/Contents/PlugIns/FinderSyncExt.appex/" pluginkit -a "/Applications/@APPLICATION_NAME@.app/Contents/PlugIns/FinderSyncExt.appex/"
# Since El Capitan we need to sleep #4650 # Since El Capitan we need to sleep #4650
sleep 10s sleep 10s
# enable it # enable it

View File

@@ -2,5 +2,6 @@
# kill the old version. see issue #2044 # kill the old version. see issue #2044
killall @APPLICATION_EXECUTABLE@ killall @APPLICATION_EXECUTABLE@
killall @APPLICATION_NAME@
exit 0 exit 0

View File

@@ -1,7 +1,6 @@
[General] [General]
Branch = master Branch = master
ShallowClone = True ShallowClone = True
Command=craft
# Variables defined here override the default value # Variables defined here override the default value
# The variable names are casesensitive # The variable names are casesensitive
@@ -13,33 +12,42 @@ CreateCache = False
# Settings applicable for all Crafts matrices # Settings applicable for all Crafts matrices
# Settings are Category/key=value # Settings are Category/key=value
# Category is case sensitive # Category is case sensitive
[GeneralSettings] [GeneralSettings]
General/EMERGE_PKGDSTDIR=${Variables:APPVEYOR_BUILD_FOLDER}/binaries
Paths/python = C:\Python36 ## This is the location of your python installation.
Paths/python27 = C:\Python27 ## This value must be set.
Paths/Python = C:\Python39-x64
Paths/Python27 = C:\Python27-x64
Compile/BuildType = RelWithDebInfo
Compile/UseNinja = True
Paths/downloaddir = ${Variables:Root}\downloads Paths/downloaddir = ${Variables:Root}\downloads
ShortPath/Enabled = False ShortPath/Enabled = False
ShortPath/EnableJunctions = True ShortPath/EnableJunctions = True
ShortPath/JunctionDir = C:\CM-SP\ ShortPath/JunctionDir = C:\CM-SP\
Packager/CacheDir = ${Variables:Root}\cache
; Packager/RepositoryUrl = https://files.kde.org/craft/
Packager/PackageType = NullsoftInstallerPackager
Packager/RepositoryUrl = http://ftp.acc.umu.se/mirror/kde.org/files/craft/master/
ContinuousIntegration/Enabled = True
## This option can be used to override the default make program
## change the value to the path of the executable you want to use instead.
Compile/MakeProgram = jom
Packager/UseCache = ${Variables:UseCache} Packager/UseCache = ${Variables:UseCache}
Packager/CreateCache = ${Variables:CreateCache} Packager/CreateCache = ${Variables:CreateCache}
; Packager/RepositoryUrl = https://files.kde.org/craft/ Packager/CacheDir = ${Variables:Root}\cache
Packager/PackageType = PortablePackager
Packager/RepositoryUrl = http://ftp.acc.umu.se/mirror/kde.org/files/craft/master/
Compile/BuildType = RelWithDebInfo
ContinuousIntegration/Enabled = True
[BlueprintSettings] [BlueprintSettings]
# don't try to pip install on the ci # don't try to pip install on the ci
python-modules.ignored = True python-modules.ignored = True
nextcloud-client.buildTests = True
binary/mysql.useMariaDB = False
libs/qt5.version = 5.9.3 [windows-msvc2019_64-cl]
craft/craft-core.version = master QtSDK/Compiler = msvc2019_64
General/ABI = windows-msvc2019_64-cl
[windows-msvc2017_64-cl]
General/ABI = windows-msvc2017_64-cl
[windows-msvc2017_32-cl]
General/ABI = windows-msvc2017_32-cl

View File

@@ -1,50 +1,49 @@
version: '{build}-{branch}' version: '{build}-{branch}'
image: Visual Studio 2019
branches: branches:
only: only:
- master - master
clone_depth: 50 clone_depth: 1
init: init:
- ps: | - ps: |
function craft($target) { function craft() {
& C:\Python36\python.exe "C:\CraftMaster\CraftMaster\CraftMaster.py" --config "$env:APPVEYOR_BUILD_FOLDER\appveyor.ini" --variables "APPVEYOR_BUILD_FOLDER=$env:APPVEYOR_BUILD_FOLDER" --target $target -c $args cmd /C "echo %PATH%"
& "C:\Python39-x64\python.exe" "C:\CraftMaster\CraftMaster\CraftMaster.py" --config "$env:APPVEYOR_BUILD_FOLDER\appveyor.ini" --variables "APPVEYOR_BUILD_FOLDER=$env:APPVEYOR_BUILD_FOLDER" --target $env:TARGET -c $args
if($LASTEXITCODE -ne 0) {exit $LASTEXITCODE} if($LASTEXITCODE -ne 0) {exit $LASTEXITCODE}
} }
function crafttests() {
cmd /C "echo %PATH%"
& "C:\Python39-x64\python.exe" "C:\CraftMaster\CraftMaster\CraftMaster.py" --config "$env:APPVEYOR_BUILD_FOLDER\appveyor.ini" --variables "APPVEYOR_BUILD_FOLDER=$env:APPVEYOR_BUILD_FOLDER" --target $env:TARGET -c $args
}
install: install:
- ps: | - ps: |
#use cmd to silence powershell behaviour for stderr #use cmd to silence powershell behaviour for stderr
& cmd /C "git clone -q --depth=1 git://anongit.kde.org/craftmaster.git C:\CraftMaster\CraftMaster 2>&1" & cmd /C "git clone -q --depth=1 https://invent.kde.org/packaging/craftmaster.git C:\CraftMaster\CraftMaster 2>&1"
craft --add-blueprint-repository [git]https://github.com/nextcloud/desktop-client-blueprints.git
craft $env:TARGET -i craft craft craft
craft $env:TARGET --install-deps owncloud-client craft --install-deps nextcloud-client
craft nsis
build_script: build_script:
- ps: | - ps: |
craft $env:TARGET --no-cache --src-dir $env:APPVEYOR_BUILD_FOLDER owncloud-client craft --src-dir $env:APPVEYOR_BUILD_FOLDER nextcloud-client
craft --package --src-dir $env:APPVEYOR_BUILD_FOLDER nextcloud-client
after_build: cp C:\CraftMaster\windows-msvc2019_64-cl\tmp\*.7z $env:APPVEYOR_BUILD_FOLDER
- ps: | cp C:\CraftMaster\windows-msvc2019_64-cl\tmp\*.exe $env:APPVEYOR_BUILD_FOLDER
craft $env:TARGET --src-dir $env:APPVEYOR_BUILD_FOLDER --package owncloud-client
on_finish:
- ps: |
Get-ChildItem $env:USERPROFILE\.craft\* | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
test_script: test_script:
- ps: | - ps: |
craft $env:TARGET --src-dir $env:APPVEYOR_BUILD_FOLDER --test owncloud-client crafttests --test --src-dir $env:APPVEYOR_BUILD_FOLDER nextcloud-client
environment: environment:
matrix: matrix:
- TARGET: windows-msvc2017_32-cl - TARGET: windows-msvc2019_64-cl
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
- TARGET: windows-msvc2017_64-cl
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
artifacts: artifacts:
- path: binaries/* - path: '*.7z'
- path: '*.exe'

View File

@@ -0,0 +1,29 @@
# SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez <aleixpol@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause
#[=======================================================================[.rst:
ECMCoverageOption
--------------------
Allow users to easily enable GCov code coverage support.
Code coverage allows you to check how much of your codebase is covered by
your tests. This module makes it easy to build with support for
`GCov <https://gcc.gnu.org/onlinedocs/gcc/Gcov.html>`_.
When this module is included, a ``BUILD_COVERAGE`` option is added (default
OFF). Turning this option on enables GCC's coverage instrumentation, and
links against ``libgcov``.
Note that this will probably break the build if you are not using GCC.
Since 1.3.0.
#]=======================================================================]
option(BUILD_COVERAGE "Build the project with gcov support" OFF)
if(BUILD_COVERAGE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov")
endif()

View File

@@ -152,7 +152,7 @@ Conflict files are always created on the client and never on the server.
"capabilities":{ "capabilities":{
"core":{ "core":{
"pollinterval":60, "pollinterval":60,
"webdav-root":"remote.php/webdav" "webdav-root":"remote.php/dav"
}, },
"dav":{ "dav":{
"chunking":"1.0" "chunking":"1.0"

View File

@@ -32,10 +32,9 @@ itself. Should the silent update fail, the client offers a manual download.
macOS macOS
^^^^^ ^^^^^
If a new update is available, the Nextcloud client initializes a pop-up dialog There is no automatic updater on macOS. If a new update is available,
to alert you of the update and requesting that you update to the latest the Nextcloud client initializes a pop-up dialog to alert you of the
version. Due to their use of the Sparkle frameworks, this is the default update and requesting that you update to the latest version manually.
process for macOS applications.
Linux Linux
^^^^^ ^^^^^
@@ -96,14 +95,6 @@ To prevent automatic updates and disallow manual overrides:
.. note:: branded clients have different key names .. note:: branded clients have different key names
Preventing Automatic Updates in macOS Environments
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can disable the automatic update mechanism, in the macOS operating system,
by copying the file
``nextcloud.app/Contents/Resources/deny_autoupdate_com.nextcloud.desktopclient.plist``
to ``/Library/Preferences/com.nextcloud.desktopclient.plist``.
Preventing Automatic Updates in Linux Environments Preventing Automatic Updates in Linux Environments
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@@ -48,9 +48,9 @@ copyright = u'2013-2021, The Nextcloud developers'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '3.2' version = '3.3'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '3.2.81' release = '3.3.6'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

View File

@@ -8,7 +8,7 @@ There are clients for Linux, macOs, and Microsoft Windows.
The currently supported server releases are the latest three stable versions The currently supported server releases are the latest three stable versions
at time of publication. It means that the |version| release series is supporting at time of publication. It means that the |version| release series is supporting
server major version 19, 20 and 21. server major version 20, 21 and 22.
Installation on Mac OS X and Windows is the same as for any software Installation on Mac OS X and Windows is the same as for any software
application: download the program and then double-click it to launch the application: download the program and then double-click it to launch the

View File

@@ -18,8 +18,8 @@ Improvements and New Features
The |version| release of the Nextcloud desktop sync client has many new features and The |version| release of the Nextcloud desktop sync client has many new features and
improvements. improvements.
* Virtual Files on Windows * Main dialog will be a regular window if tray icons are not available on the system.
* Support for the user status from the server * Virtual files wil be optional. That enables the desktop client to run on older Windows versions.
* Many improvements to the sync engine * Improvements for the virtual files on Windows
* Make the end-to-end encryption work more reliable * Network traffic performance improvements
* Improve sync performance * Improvements to the sync engine

View File

@@ -46,6 +46,9 @@ the server URL.
Other command line switches supported by ``nextcloudcmd`` include the following: Other command line switches supported by ``nextcloudcmd`` include the following:
``--path``
Overrides default remote root folder to a specific subfolder on the server(e.g.: /Documents would sync the Documents subfolder on the server)
``--user``, ``-u`` ``[user]`` ``--user``, ``-u`` ``[user]``
Use ``user`` as the login name. Use ``user`` as the login name.
@@ -67,12 +70,6 @@ Other command line switches supported by ``nextcloudcmd`` include the following:
``--httpproxy http://[user@pass:]<server>:<port>`` ``--httpproxy http://[user@pass:]<server>:<port>``
Uses ``server`` as HTTP proxy. Uses ``server`` as HTTP proxy.
``--nonshib``
Uses Non Shibboleth WebDAV Authentication
``--davpath [path]``
Overrides the WebDAV Path with ``path``
``--exclude [file]`` ``--exclude [file]``
Exclude list file Exclude list file
@@ -92,15 +89,15 @@ Credential Handling
:: ::
$ nextcloudcmd /home/user/my_sync_folder https://carla:secret@server/nextcloud/remote.php/webdav/ $ nextcloudcmd /home/user/my_sync_folder https://carla:secret@server/nextcloud
To synchronize the Nextcloud directory ``Music`` to the local directory To synchronize the Nextcloud directory ``Music`` to the local directory
``media/music``, through a proxy listening on port ``8080``, and on a gateway ``media/music``, through a proxy listening on port ``8080``, and on a gateway
machine using IP address ``192.168.178.1``, the command line would be:: machine using IP address ``192.168.178.1``, the command line would be::
$ nextcloudcmd --httpproxy http://192.168.178.1:8080 \ $ nextcloudcmd --httpproxy http://192.168.178.1:8080 --path /Music \
$HOME/media/music \ $HOME/media/music \
https://server/nextcloud/remote.php/webdav/Music https://server/nextcloud
``nextcloudcmd`` will prompt for the user name and password, unless they have ``nextcloudcmd`` will prompt for the user name and password, unless they have
been specified on the command line or ``-n`` has been passed. been specified on the command line or ``-n`` has been passed.
@@ -120,5 +117,5 @@ Example
:: ::
$ nextcloudcmd /home/user/<my_sync_folder> \ $ nextcloudcmd --path /<Directory_that_has_been_created> /home/user/<my_sync_folder> \
https://<username>:<secret>@<server_address>/remote.php/webdav/<Directory_that_has_been_created> https://<username>:<secret>@<server_address>

View File

@@ -34,7 +34,7 @@ Identifying Basic Functionality Problems
For example, if your Nextcloud instance is installed at For example, if your Nextcloud instance is installed at
``http://yourserver.com/nextcloud``, your WebDAV server address is ``http://yourserver.com/nextcloud``, your WebDAV server address is
``http://yourserver.com/nextcloud/remote.php/webdav``. ``http://yourserver.com/nextcloud/remote.php/dav``.
If you are prompted for your username and password but, after providing the If you are prompted for your username and password but, after providing the
correct credentials, authentication fails, please ensure that your correct credentials, authentication fails, please ensure that your

View File

@@ -24,11 +24,14 @@ The first parameter is the local directory. The second parameter is
the server URL. the server URL.
.. note:: Prior to the 1.6 release of nextcloudcmd, the tool only accepted .. note:: Prior to the 1.6 release of nextcloudcmd, the tool only accepted
``nextcloud://`` or ``nextclouds://`` in place of ``http://`` and ``https://`` as ``owncloud://`` or ``ownclouds://`` in place of ``http://`` and ``https://`` as
a scheme. See ``Examples`` for details. a scheme. See ``Examples`` for details.
OPTIONS OPTIONS
======= =======
``--path``
Overrides default remote root folder to a specific subfolder on the server(e.g.: /Documents would sync the Documents subfolder on the server)
``—user``, ``-u`` ``[user]`` ``—user``, ``-u`` ``[user]``
Use ``user`` as the login name. Use ``user`` as the login name.
@@ -50,12 +53,6 @@ OPTIONS
``—httpproxy http://[user@pass:]<server>:<port>`` ``—httpproxy http://[user@pass:]<server>:<port>``
Uses ``server`` as HTTP proxy. Uses ``server`` as HTTP proxy.
``—nonshib``
Uses Non Shibboleth WebDAV Authentication
``—davpath [path]``
Overrides the WebDAV Path with ``path``
``—exclude [file]`` ``—exclude [file]``
Exclude list file Exclude list file
@@ -74,18 +71,18 @@ To synchronize the nextCloud directory ``Music`` to the local directory ``media/
through a proxy listening on port ``8080`` on the gateway machine ``192.168.178.1``, through a proxy listening on port ``8080`` on the gateway machine ``192.168.178.1``,
the command line would be:: the command line would be::
$ nextcloudcmd —httpproxy http://192.168.178.1:8080 \ $ nextcloudcmd —httpproxy http://192.168.178.1:8080 --path /Music \
$HOME/media/music \ $HOME/media/music \
https://server/nextcloud/remote.php/webdav/Music https://server/nextcloud
``nextcloudcmd`` will enquire user name and password, unless they have ``nextcloudcmd`` will enquire user name and password, unless they have
been specified on the command line or ``-n`` (see `netrc(5)`) has been passed. been specified on the command line or ``-n`` (see `netrc(5)`) has been passed.
Using the legacy scheme, it would be:: Using the legacy scheme, it would be::
$ nextcloudcmd —httpproxy http://192.168.178.1:8080 \ $ nextcloudcmd —httpproxy http://192.168.178.1:8080 --path /Music \
$HOME/media/music \ $HOME/media/music \
nextclouds://server/nextcloud/remote.php/webdav/Music ownclouds://server/nextcloud
BUGS BUGS

View File

@@ -6,5 +6,6 @@
<file>theme/Style/Style.qml</file> <file>theme/Style/Style.qml</file>
<file>theme/Style/qmldir</file> <file>theme/Style/qmldir</file>
<file>src/gui/tray/ActivityActionButton.qml</file> <file>src/gui/tray/ActivityActionButton.qml</file>
<file>src/gui/tray/ActivityItem.qml</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@@ -66,6 +66,7 @@ struct CmdOptions
{ {
QString source_dir; QString source_dir;
QString target_url; QString target_url;
QString remotePath = QStringLiteral("/");
QString config_directory; QString config_directory;
QString user; QString user;
QString password; QString password;
@@ -75,10 +76,8 @@ struct CmdOptions
bool useNetrc; bool useNetrc;
bool interactive; bool interactive;
bool ignoreHiddenFiles; bool ignoreHiddenFiles;
bool nonShib;
QString exclude; QString exclude;
QString unsyncedfolders; QString unsyncedfolders;
QString davPath;
int restartTimes; int restartTimes;
int downlimit; int downlimit;
int uplimit; int uplimit;
@@ -188,14 +187,13 @@ void help()
std::cout << " --password, -p [pass] Use [pass] as password" << std::endl; std::cout << " --password, -p [pass] Use [pass] as password" << std::endl;
std::cout << " -n Use netrc (5) for login" << std::endl; std::cout << " -n Use netrc (5) for login" << std::endl;
std::cout << " --non-interactive Do not block execution with interaction" << std::endl; std::cout << " --non-interactive Do not block execution with interaction" << std::endl;
std::cout << " --nonshib Use Non Shibboleth WebDAV authentication" << std::endl;
std::cout << " --davpath [path] Custom themed dav path, overrides --nonshib" << std::endl;
std::cout << " --max-sync-retries [n] Retries maximum n times (default to 3)" << std::endl; std::cout << " --max-sync-retries [n] Retries maximum n times (default to 3)" << std::endl;
std::cout << " --uplimit [n] Limit the upload speed of files to n KB/s" << std::endl; std::cout << " --uplimit [n] Limit the upload speed of files to n KB/s" << std::endl;
std::cout << " --downlimit [n] Limit the download speed of files to n KB/s" << std::endl; std::cout << " --downlimit [n] Limit the download speed of files to n KB/s" << std::endl;
std::cout << " -h Sync hidden files, do not ignore them" << std::endl; std::cout << " -h Sync hidden files, do not ignore them" << std::endl;
std::cout << " --version, -v Display version and exit" << std::endl; std::cout << " --version, -v Display version and exit" << std::endl;
std::cout << " --logdebug More verbose logging" << std::endl; std::cout << " --logdebug More verbose logging" << std::endl;
std::cout << " --path Path to a folder on a remote server" << std::endl;
std::cout << "" << std::endl; std::cout << "" << std::endl;
exit(0); exit(0);
} }
@@ -263,10 +261,6 @@ void parseOptions(const QStringList &app_args, CmdOptions *options)
options->exclude = it.next(); options->exclude = it.next();
} else if (option == "--unsyncedfolders" && !it.peekNext().startsWith("-")) { } else if (option == "--unsyncedfolders" && !it.peekNext().startsWith("-")) {
options->unsyncedfolders = it.next(); options->unsyncedfolders = it.next();
} else if (option == "--nonshib") {
options->nonShib = true;
} else if (option == "--davpath" && !it.peekNext().startsWith("-")) {
options->davPath = it.next();
} else if (option == "--max-sync-retries" && !it.peekNext().startsWith("-")) { } else if (option == "--max-sync-retries" && !it.peekNext().startsWith("-")) {
options->restartTimes = it.next().toInt(); options->restartTimes = it.next().toInt();
} else if (option == "--uplimit" && !it.peekNext().startsWith("-")) { } else if (option == "--uplimit" && !it.peekNext().startsWith("-")) {
@@ -276,7 +270,10 @@ void parseOptions(const QStringList &app_args, CmdOptions *options)
} else if (option == "--logdebug") { } else if (option == "--logdebug") {
Logger::instance()->setLogFile("-"); Logger::instance()->setLogFile("-");
Logger::instance()->setLogDebug(true); Logger::instance()->setLogDebug(true);
} else { } else if (option == "--path" && !it.peekNext().startsWith("-")) {
options->remotePath = it.next();
}
else {
help(); help();
} }
} }
@@ -312,6 +309,9 @@ void selectiveSyncFixup(OCC::SyncJournalDb *journal, const QStringList &newList)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
#ifdef Q_OS_WIN
SetDllDirectory(L"");
#endif
QCoreApplication app(argc, argv); QCoreApplication app(argc, argv);
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
@@ -328,7 +328,6 @@ int main(int argc, char **argv)
options.useNetrc = false; options.useNetrc = false;
options.interactive = true; options.interactive = true;
options.ignoreHiddenFiles = false; // Default is to sync hidden files options.ignoreHiddenFiles = false; // Default is to sync hidden files
options.nonShib = false;
options.restartTimes = 3; options.restartTimes = 3;
options.uplimit = 0; options.uplimit = 0;
options.downlimit = 0; options.downlimit = 0;
@@ -347,24 +346,15 @@ int main(int argc, char **argv)
qFatal("Could not initialize account!"); qFatal("Could not initialize account!");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// check if the webDAV path was added to the url and append if not.
if (!options.target_url.endsWith("/")) { if (options.target_url.contains("/webdav", Qt::CaseInsensitive) || options.target_url.contains("/dav", Qt::CaseInsensitive)) {
options.target_url.append("/"); qWarning("Dav or webdav in server URL.");
std::cerr << "Error! Please specify only the base URL of your host with username and password. Example:" << std::endl
<< "http(s)://username:password@cloud.example.com" << std::endl;
return EXIT_FAILURE;
} }
if (options.nonShib) { QUrl hostUrl = QUrl::fromUserInput((options.target_url.endsWith(QLatin1Char('/')) || options.target_url.endsWith(QLatin1Char('\\'))) ? options.target_url.chopped(1) : options.target_url);
account->setNonShib(true);
}
if (!options.davPath.isEmpty()) {
account->setDavPath(options.davPath);
}
if (!options.target_url.contains(account->davPath())) {
options.target_url.append(account->davPath());
}
QUrl url = QUrl::fromUserInput(options.target_url);
// Order of retrieval attempt (later attempts override earlier ones): // Order of retrieval attempt (later attempts override earlier ones):
// 1. From URL // 1. From URL
@@ -372,8 +362,8 @@ int main(int argc, char **argv)
// 3. From netrc (if enabled) // 3. From netrc (if enabled)
// 4. From prompt (if interactive) // 4. From prompt (if interactive)
QString user = url.userName(); QString user = hostUrl.userName();
QString password = url.password(); QString password = hostUrl.password();
if (!options.user.isEmpty()) { if (!options.user.isEmpty()) {
user = options.user; user = options.user;
@@ -386,7 +376,7 @@ int main(int argc, char **argv)
if (options.useNetrc) { if (options.useNetrc) {
NetrcParser parser; NetrcParser parser;
if (parser.parse()) { if (parser.parse()) {
NetrcParser::LoginPair pair = parser.find(url.host()); NetrcParser::LoginPair pair = parser.find(hostUrl.host());
user = pair.first; user = pair.first;
password = pair.second; password = pair.second;
} }
@@ -404,24 +394,15 @@ int main(int argc, char **argv)
} }
} }
// take the unmodified url to pass to csync_create()
QByteArray remUrl = options.target_url.toUtf8();
// Find the folder and the original owncloud url // Find the folder and the original owncloud url
QStringList splitted = url.path().split("/" + account->davPath());
url.setPath(splitted.value(0));
url.setScheme(url.scheme().replace("owncloud", "http")); hostUrl.setScheme(hostUrl.scheme().replace("owncloud", "http"));
QUrl credentialFreeUrl = url; QUrl credentialFreeUrl = hostUrl;
credentialFreeUrl.setUserName(QString()); credentialFreeUrl.setUserName(QString());
credentialFreeUrl.setPassword(QString()); credentialFreeUrl.setPassword(QString());
// Remote folders typically start with a / and don't end with one const QString folder = options.remotePath;
QString folder = "/" + splitted.value(1);
if (folder.endsWith("/") && folder != "/") {
folder.chop(1);
}
if (!options.proxy.isNull()) { if (!options.proxy.isNull()) {
QString host; QString host;
@@ -458,44 +439,36 @@ int main(int argc, char **argv)
} }
#endif #endif
account->setUrl(url); account->setUrl(hostUrl);
account->setSslErrorHandler(sslErrorHandler); account->setSslErrorHandler(sslErrorHandler);
// Perform a call to get the capabilities. QEventLoop loop;
if (!options.nonShib) { auto *job = new JsonApiJob(account, QLatin1String("ocs/v1.php/cloud/capabilities"));
// Do not do it if '--nonshib' was passed. This mean we should only connect to the 'nonshib' QObject::connect(job, &JsonApiJob::jsonReceived, [&](const QJsonDocument &json) {
// dav endpoint. Since we do not get the capabilities, in that case, this has the additional auto caps = json.object().value("ocs").toObject().value("data").toObject().value("capabilities").toObject();
// side effect that chunking-ng will be disabled. (because otherwise it would use the new qDebug() << "Server capabilities" << caps;
// 'dav' endpoint instead of the nonshib one (which still use the old chunking) account->setCapabilities(caps.toVariantMap());
account->setServerVersion(caps["core"].toObject()["status"].toObject()["version"].toString());
loop.quit();
});
job->start();
loop.exec();
QEventLoop loop; if (job->reply()->error() != QNetworkReply::NoError){
auto *job = new JsonApiJob(account, QLatin1String("ocs/v1.php/cloud/capabilities")); std::cout<<"Error connecting to server\n";
QObject::connect(job, &JsonApiJob::jsonReceived, [&](const QJsonDocument &json) { return EXIT_FAILURE;
auto caps = json.object().value("ocs").toObject().value("data").toObject().value("capabilities").toObject();
qDebug() << "Server capabilities" << caps;
account->setCapabilities(caps.toVariantMap());
account->setServerVersion(caps["core"].toObject()["status"].toObject()["version"].toString());
loop.quit();
});
job->start();
loop.exec();
if (job->reply()->error() != QNetworkReply::NoError){
std::cout<<"Error connecting to server\n";
return EXIT_FAILURE;
}
job = new JsonApiJob(account, QLatin1String("ocs/v1.php/cloud/user"));
QObject::connect(job, &JsonApiJob::jsonReceived, [&](const QJsonDocument &json) {
const QJsonObject data = json.object().value("ocs").toObject().value("data").toObject();
account->setDavUser(data.value("id").toString());
account->setDavDisplayName(data.value("display-name").toString());
loop.quit();
});
job->start();
loop.exec();
} }
job = new JsonApiJob(account, QLatin1String("ocs/v1.php/cloud/user"));
QObject::connect(job, &JsonApiJob::jsonReceived, [&](const QJsonDocument &json) {
const QJsonObject data = json.object().value("ocs").toObject().value("data").toObject();
account->setDavUser(data.value("id").toString());
account->setDavDisplayName(data.value("display-name").toString());
loop.quit();
});
job->start();
loop.exec();
// much lower age than the default since this utility is usually made to be run right after a change in the tests // much lower age than the default since this utility is usually made to be run right after a change in the tests
SyncEngine::minimumFileAgeForUpload = std::chrono::milliseconds(0); SyncEngine::minimumFileAgeForUpload = std::chrono::milliseconds(0);

View File

@@ -142,20 +142,26 @@ QByteArray makeChecksumHeader(const QByteArray &checksumType, const QByteArray &
return header; return header;
} }
QByteArray findBestChecksum(const QByteArray &checksums) QByteArray findBestChecksum(const QByteArray &_checksums)
{ {
const auto checksums = QString::fromUtf8(_checksums);
int i = 0; int i = 0;
// The order of the searches here defines the preference ordering. // The order of the searches here defines the preference ordering.
if (-1 != (i = checksums.indexOf("SHA3-256:")) if (-1 != (i = checksums.indexOf(QLatin1String("SHA3-256:"), 0, Qt::CaseInsensitive))
|| -1 != (i = checksums.indexOf("SHA256:")) || -1 != (i = checksums.indexOf(QLatin1String("SHA256:"), 0, Qt::CaseInsensitive))
|| -1 != (i = checksums.indexOf("SHA1:")) || -1 != (i = checksums.indexOf(QLatin1String("SHA1:"), 0, Qt::CaseInsensitive))
|| -1 != (i = checksums.indexOf("MD5:")) || -1 != (i = checksums.indexOf(QLatin1String("MD5:"), 0, Qt::CaseInsensitive))
|| -1 != (i = checksums.indexOf("Adler32:"))) { || -1 != (i = checksums.indexOf(QLatin1String("ADLER32:"), 0, Qt::CaseInsensitive))) {
// Now i is the start of the best checksum // Now i is the start of the best checksum
// Grab it until the next space or end of string. // Grab it until the next space or end of xml or end of string.
auto checksum = checksums.mid(i); int end = _checksums.indexOf(' ', i);
return checksum.mid(0, checksum.indexOf(" ")); // workaround for https://github.com/owncloud/core/pull/38304
if (end == -1) {
end = _checksums.indexOf('<', i);
}
return _checksums.mid(i, end - i);
} }
qCWarning(lcChecksums) << "Failed to parse" << _checksums;
return QByteArray(); return QByteArray();
} }
@@ -328,7 +334,7 @@ ComputeChecksum *ValidateChecksumHeader::prepareStart(const QByteArray &checksum
if (!parseChecksumHeader(checksumHeader, &_expectedChecksumType, &_expectedChecksum)) { if (!parseChecksumHeader(checksumHeader, &_expectedChecksumType, &_expectedChecksum)) {
qCWarning(lcChecksums) << "Checksum header malformed:" << checksumHeader; qCWarning(lcChecksums) << "Checksum header malformed:" << checksumHeader;
emit validationFailed(tr("The checksum header is malformed."), {}, {}, _filePath); emit validationFailed(tr("The checksum header is malformed."));
return nullptr; return nullptr;
} }
@@ -341,7 +347,6 @@ ComputeChecksum *ValidateChecksumHeader::prepareStart(const QByteArray &checksum
void ValidateChecksumHeader::start(const QString &filePath, const QByteArray &checksumHeader) void ValidateChecksumHeader::start(const QString &filePath, const QByteArray &checksumHeader)
{ {
_filePath = filePath;
if (auto calculator = prepareStart(checksumHeader)) if (auto calculator = prepareStart(checksumHeader))
calculator->start(filePath); calculator->start(filePath);
} }
@@ -356,11 +361,11 @@ void ValidateChecksumHeader::slotChecksumCalculated(const QByteArray &checksumTy
const QByteArray &checksum) const QByteArray &checksum)
{ {
if (checksumType != _expectedChecksumType) { if (checksumType != _expectedChecksumType) {
emit validationFailed(tr("The checksum header contained an unknown checksum type '%1'").arg(QString::fromLatin1(_expectedChecksumType)), {}, {}, _filePath); emit validationFailed(tr("The checksum header contained an unknown checksum type '%1'").arg(QString::fromLatin1(_expectedChecksumType)));
return; return;
} }
if (checksum != _expectedChecksum) { if (checksum != _expectedChecksum) {
emit validationFailed(tr("The downloaded file does not match the checksum, it will be resumed. '%1' != '%2'").arg(QString::fromUtf8(_expectedChecksum), QString::fromUtf8(checksum)), checksumType, checksum, _filePath); emit validationFailed(tr("The downloaded file does not match the checksum, it will be resumed. '%1' != '%2'").arg(QString::fromUtf8(_expectedChecksum), QString::fromUtf8(checksum)));
return; return;
} }
emit validated(checksumType, checksum); emit validated(checksumType, checksum);

View File

@@ -163,7 +163,7 @@ public:
signals: signals:
void validated(const QByteArray &checksumType, const QByteArray &checksum); void validated(const QByteArray &checksumType, const QByteArray &checksum);
void validationFailed(const QString &errMsg, const QByteArray &checksumType, const QByteArray &checksum, const QString &filePath); void validationFailed(const QString &errMsg);
private slots: private slots:
void slotChecksumCalculated(const QByteArray &checksumType, const QByteArray &checksum); void slotChecksumCalculated(const QByteArray &checksumType, const QByteArray &checksum);
@@ -173,8 +173,6 @@ private:
QByteArray _expectedChecksumType; QByteArray _expectedChecksumType;
QByteArray _expectedChecksum; QByteArray _expectedChecksum;
QString _filePath;
}; };
/** /**

View File

@@ -99,7 +99,7 @@ public:
friend QDebug operator<<(QDebug &dbg, RemotePermissions p) friend QDebug operator<<(QDebug &dbg, RemotePermissions p)
{ {
return dbg << p.toString().constData(); return dbg << p.toString();
} }
}; };

View File

@@ -36,6 +36,7 @@ set(client_UI_SRCS
proxyauthdialog.ui proxyauthdialog.ui
mnemonicdialog.ui mnemonicdialog.ui
tray/ActivityActionButton.qml tray/ActivityActionButton.qml
tray/ActivityItem.qml
tray/Window.qml tray/Window.qml
tray/UserLine.qml tray/UserLine.qml
wizard/flow2authwidget.ui wizard/flow2authwidget.ui

View File

@@ -317,7 +317,7 @@ AccountPtr AccountManager::loadAccountHelper(QSettings &settings)
qCInfo(lcAccountManager) << "Account for" << acc->url() << "using auth type" << authType; qCInfo(lcAccountManager) << "Account for" << acc->url() << "using auth type" << authType;
acc->_serverVersion = settings.value(QLatin1String(serverVersionC)).toString(); acc->_serverVersion = settings.value(QLatin1String(serverVersionC)).toString();
acc->_davUser = settings.value(QLatin1String(davUserC)).toString(); acc->_davUser = settings.value(QLatin1String(davUserC), "").toString();
// We want to only restore settings for that auth type and the user value // We want to only restore settings for that auth type and the user value
acc->_settingsMap.insert(QLatin1String(userC), settings.value(userC)); acc->_settingsMap.insert(QLatin1String(userC), settings.value(userC));

View File

@@ -511,20 +511,10 @@ void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index
const auto path = rec.isValid() ? rec._path : remotePath; const auto path = rec.isValid() ? rec._path : remotePath;
auto availability = folder->vfs().availability(path);
if (availability) {
ac = availabilityMenu->addAction(Utility::vfsCurrentAvailabilityText(*availability));
ac->setEnabled(false);
}
ac = availabilityMenu->addAction(Utility::vfsPinActionText()); ac = availabilityMenu->addAction(Utility::vfsPinActionText());
ac->setEnabled(!availability || *availability != VfsItemAvailability::AlwaysLocal);
connect(ac, &QAction::triggered, this, [this, folder, path] { slotSetSubFolderAvailability(folder, path, PinState::AlwaysLocal); }); connect(ac, &QAction::triggered, this, [this, folder, path] { slotSetSubFolderAvailability(folder, path, PinState::AlwaysLocal); });
ac = availabilityMenu->addAction(Utility::vfsFreeSpaceActionText()); ac = availabilityMenu->addAction(Utility::vfsFreeSpaceActionText());
ac->setEnabled(!availability
|| !(*availability == VfsItemAvailability::OnlineOnly
|| *availability == VfsItemAvailability::AllDehydrated));
connect(ac, &QAction::triggered, this, [this, folder, path] { slotSetSubFolderAvailability(folder, path, PinState::OnlineOnly); }); connect(ac, &QAction::triggered, this, [this, folder, path] { slotSetSubFolderAvailability(folder, path, PinState::OnlineOnly); });
} }
@@ -594,20 +584,11 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
if (folder->virtualFilesEnabled()) { if (folder->virtualFilesEnabled()) {
auto availabilityMenu = menu->addMenu(tr("Availability")); auto availabilityMenu = menu->addMenu(tr("Availability"));
auto availability = folder->vfs().availability(QString());
if (availability) {
ac = availabilityMenu->addAction(Utility::vfsCurrentAvailabilityText(*availability));
ac->setEnabled(false);
}
ac = availabilityMenu->addAction(Utility::vfsPinActionText()); ac = availabilityMenu->addAction(Utility::vfsPinActionText());
ac->setEnabled(!availability || *availability != VfsItemAvailability::AlwaysLocal);
connect(ac, &QAction::triggered, this, [this]() { slotSetCurrentFolderAvailability(PinState::AlwaysLocal); }); connect(ac, &QAction::triggered, this, [this]() { slotSetCurrentFolderAvailability(PinState::AlwaysLocal); });
ac = availabilityMenu->addAction(Utility::vfsFreeSpaceActionText()); ac = availabilityMenu->addAction(Utility::vfsFreeSpaceActionText());
ac->setEnabled(!availability
|| !(*availability == VfsItemAvailability::OnlineOnly
|| *availability == VfsItemAvailability::AllDehydrated));
connect(ac, &QAction::triggered, this, [this]() { slotSetCurrentFolderAvailability(PinState::OnlineOnly); }); connect(ac, &QAction::triggered, this, [this]() { slotSetCurrentFolderAvailability(PinState::OnlineOnly); });
ac = menu->addAction(tr("Disable virtual file support …")); ac = menu->addAction(tr("Disable virtual file support …"));

View File

@@ -227,17 +227,6 @@ void ConnectionValidator::checkServerCapabilities()
job->setTimeout(timeoutToUseMsec); job->setTimeout(timeoutToUseMsec);
QObject::connect(job, &JsonApiJob::jsonReceived, this, &ConnectionValidator::slotCapabilitiesRecieved); QObject::connect(job, &JsonApiJob::jsonReceived, this, &ConnectionValidator::slotCapabilitiesRecieved);
job->start(); job->start();
// And we'll retrieve the ocs config in parallel
// note that 'this' might be destroyed before the job finishes, so intentionally not parented
auto configJob = new JsonApiJob(_account, QLatin1String("ocs/v1.php/config"));
configJob->setTimeout(timeoutToUseMsec);
auto account = _account; // capturing account by value will make it live long enough
QObject::connect(configJob, &JsonApiJob::jsonReceived, _account.data(),
[=](const QJsonDocument &json) {
ocsConfigReceived(json, account);
});
configJob->start();
} }
void ConnectionValidator::slotCapabilitiesRecieved(const QJsonDocument &json) void ConnectionValidator::slotCapabilitiesRecieved(const QJsonDocument &json)
@@ -260,17 +249,6 @@ void ConnectionValidator::slotCapabilitiesRecieved(const QJsonDocument &json)
fetchUser(); fetchUser();
} }
void ConnectionValidator::ocsConfigReceived(const QJsonDocument &json, AccountPtr account)
{
QString host = json.object().value("ocs").toObject().value("data").toObject().value("host").toString();
if (host.isEmpty()) {
qCWarning(lcConnectionValidator) << "Could not extract 'host' from ocs config reply";
return;
}
qCInfo(lcConnectionValidator) << "Determined user-visible host to be" << host;
account->setUserVisibleHost(host);
}
void ConnectionValidator::fetchUser() void ConnectionValidator::fetchUser()
{ {
auto *userInfo = new UserInfo(_accountState.data(), true, true, this); auto *userInfo = new UserInfo(_accountState.data(), true, true, this);

View File

@@ -60,8 +60,7 @@ namespace OCC {
+---------------------------+ +---------------------------+
| |
+-> checkServerCapabilities --------------v (in parallel) +-> checkServerCapabilities --------------v (in parallel)
JsonApiJob (cloud/capabilities) JsonApiJob (ocs/v1.php/config) JsonApiJob (cloud/capabilities)
| +-> ocsConfigReceived
+-> slotCapabilitiesRecieved -+ +-> slotCapabilitiesRecieved -+
| |
+---------------------------------+ +---------------------------------+
@@ -131,7 +130,6 @@ private:
void reportResult(Status status); void reportResult(Status status);
void checkServerCapabilities(); void checkServerCapabilities();
void fetchUser(); void fetchUser();
static void ocsConfigReceived(const QJsonDocument &json, AccountPtr account);
/** Sets the account's server version /** Sets the account's server version
* *

View File

@@ -79,6 +79,7 @@ void Flow2Auth::fetchNewToken(const TokenAction action)
// Step 1: Initiate a login, do an anonymous POST request // Step 1: Initiate a login, do an anonymous POST request
QUrl url = Utility::concatUrlPath(_account->url().toString(), QLatin1String("/index.php/login/v2")); QUrl url = Utility::concatUrlPath(_account->url().toString(), QLatin1String("/index.php/login/v2"));
_enforceHttps = url.scheme() == QStringLiteral("https");
// add 'Content-Length: 0' header (see https://github.com/nextcloud/desktop/issues/1473) // add 'Content-Length: 0' header (see https://github.com/nextcloud/desktop/issues/1473)
QNetworkRequest req; QNetworkRequest req;
@@ -98,6 +99,11 @@ void Flow2Auth::fetchNewToken(const TokenAction action)
&& !json.isEmpty()) { && !json.isEmpty()) {
pollToken = json.value("poll").toObject().value("token").toString(); pollToken = json.value("poll").toObject().value("token").toString();
pollEndpoint = json.value("poll").toObject().value("endpoint").toString(); pollEndpoint = json.value("poll").toObject().value("endpoint").toString();
if (_enforceHttps && QUrl(pollEndpoint).scheme() != QStringLiteral("https")) {
qCWarning(lcFlow2auth) << "Can not poll endpoint because the returned url" << _pollEndpoint << "does not start with https";
emit result(Error, tr("The polling URL does not start with HTTPS despite the login URL started with HTTPS. Login will not be possible because this might be a security issue. Please contact your administrator."));
return;
}
loginUrl = json["login"].toString(); loginUrl = json["login"].toString();
} }
@@ -200,6 +206,11 @@ void Flow2Auth::slotPollTimerTimeout()
if (reply->error() == QNetworkReply::NoError && jsonParseError.error == QJsonParseError::NoError if (reply->error() == QNetworkReply::NoError && jsonParseError.error == QJsonParseError::NoError
&& !json.isEmpty()) { && !json.isEmpty()) {
serverUrl = json["server"].toString(); serverUrl = json["server"].toString();
if (_enforceHttps && serverUrl.scheme() != QStringLiteral("https")) {
qCWarning(lcFlow2auth) << "Returned server url" << serverUrl << "does not start with https";
emit result(Error, tr("The returned server URL does not start with HTTPS despite the login URL started with HTTPS. Login will not be possible because this might be a security issue. Please contact your administrator."));
return;
}
loginName = json["loginName"].toString(); loginName = json["loginName"].toString();
appPassword = json["appPassword"].toString(); appPassword = json["appPassword"].toString();
} }

View File

@@ -81,6 +81,7 @@ private:
qint64 _secondsInterval; qint64 _secondsInterval;
bool _isBusy; bool _isBusy;
bool _hasToken; bool _hasToken;
bool _enforceHttps = false;
}; };
} // namespace OCC } // namespace OCC

View File

@@ -252,7 +252,7 @@ bool Folder::isBusy() const
bool Folder::isSyncRunning() const bool Folder::isSyncRunning() const
{ {
return _engine->isSyncRunning() || _vfs->isHydrating(); return _engine->isSyncRunning() || (_vfs && _vfs->isHydrating());
} }
QString Folder::remotePath() const QString Folder::remotePath() const

View File

@@ -850,9 +850,6 @@ void FolderMan::slotEtagPollTimerTimeout()
// Some folders need not to be checked because they use the push notifications // Some folders need not to be checked because they use the push notifications
std::copy_if(folderMapValues.begin(), folderMapValues.end(), std::back_inserter(foldersToRun), [this](Folder *folder) -> bool { std::copy_if(folderMapValues.begin(), folderMapValues.end(), std::back_inserter(foldersToRun), [this](Folder *folder) -> bool {
const auto account = folder->accountState()->account(); const auto account = folder->accountState()->account();
const auto capabilities = account->capabilities();
const auto pushNotifications = account->pushNotifications();
return !pushNotificationsFilesReady(account.data()); return !pushNotificationsFilesReady(account.data());
}); });

View File

@@ -51,6 +51,9 @@ void warnSystray()
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
#ifdef Q_OS_WIN
SetDllDirectory(L"");
#endif
Q_INIT_RESOURCE(resources); Q_INIT_RESOURCE(resources);
Q_INIT_RESOURCE(theme); Q_INIT_RESOURCE(theme);

View File

@@ -323,12 +323,29 @@ void OwncloudSetupWizard::slotConnectToOCUrl(const QString &url)
qCInfo(lcWizard) << "Connect to url: " << url; qCInfo(lcWizard) << "Connect to url: " << url;
AbstractCredentials *creds = _ocWizard->getCredentials(); AbstractCredentials *creds = _ocWizard->getCredentials();
_ocWizard->account()->setCredentials(creds); _ocWizard->account()->setCredentials(creds);
_ocWizard->setField(QLatin1String("OCUrl"), url);
_ocWizard->appendToConfigurationLog(tr("Trying to connect to %1 at %2 …")
.arg(Theme::instance()->appNameGUI())
.arg(url));
testOwnCloudConnect(); const auto fetchUserNameJob = new JsonApiJob(_ocWizard->account()->sharedFromThis(), QStringLiteral("/ocs/v1.php/cloud/user"));
connect(fetchUserNameJob, &JsonApiJob::jsonReceived, this, [this, url](const QJsonDocument &json, int statusCode) {
if (statusCode != 100) {
qCWarning(lcWizard) << "Could not fetch username.";
}
sender()->deleteLater();
const auto objData = json.object().value("ocs").toObject().value("data").toObject();
const auto userId = objData.value("id").toString("");
const auto displayName = objData.value("display-name").toString("");
_ocWizard->account()->setDavUser(userId);
_ocWizard->account()->setDavDisplayName(displayName);
_ocWizard->setField(QLatin1String("OCUrl"), url);
_ocWizard->appendToConfigurationLog(tr("Trying to connect to %1 at %2 …")
.arg(Theme::instance()->appNameGUI())
.arg(url));
testOwnCloudConnect();
});
fetchUserNameJob->start();
} }
void OwncloudSetupWizard::testOwnCloudConnect() void OwncloudSetupWizard::testOwnCloudConnect()
@@ -465,7 +482,7 @@ void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString &localFo
* *
* Purpose: Don't rely on unsafe paths, be extra careful. * Purpose: Don't rely on unsafe paths, be extra careful.
* *
* Example: https://cloud.example.com/remote.php/webdav// * Example: https://cloud.example.com/remote.php/dav//
* *
*/ */
qCInfo(lcWizard) << "Sanitize got URL path:" << QString(_ocWizard->account()->url().toString() + '/' + _ocWizard->account()->davPath() + remoteFolder); qCInfo(lcWizard) << "Sanitize got URL path:" << QString(_ocWizard->account()->url().toString() + '/' + _ocWizard->account()->davPath() + remoteFolder);

View File

@@ -76,9 +76,9 @@ signals:
void openHelp(); void openHelp();
void shutdown(); void shutdown();
Q_INVOKABLE void hideWindow(); void hideWindow();
Q_INVOKABLE void showWindow(); void showWindow();
Q_INVOKABLE void openShareDialog(const QString &sharePath, const QString &localPath); void openShareDialog(const QString &sharePath, const QString &localPath);
public slots: public slots:
void slotNewUserSelected(); void slotNewUserSelected();

View File

@@ -9,6 +9,9 @@ Item {
// label value // label value
property string text: "" property string text: ""
// font value
property var font: label.font
// icon value // icon value
property string imageSource: "" property string imageSource: ""

View File

@@ -0,0 +1,260 @@
import QtQml 2.12
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.2
import Style 1.0
import com.nextcloud.desktopclient 1.0
MouseArea {
id: activityMouseArea
enabled: (path !== "" || link !== "")
hoverEnabled: true
Rectangle {
anchors.fill: parent
anchors.margins: 2
color: (parent.containsMouse ? Style.lightHover : "transparent")
}
RowLayout {
id: activityItem
readonly property variant links: model.links
readonly property int itemIndex: model.index
width: activityMouseArea.width
height: Style.trayWindowHeaderHeight
spacing: 0
Accessible.role: Accessible.ListItem
Accessible.name: path !== "" ? qsTr("Open %1 locally").arg(displayPath)
: message
Accessible.onPressAction: activityMouseArea.clicked()
Image {
id: activityIcon
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
Layout.leftMargin: 8
Layout.preferredWidth: shareButton.icon.width
Layout.preferredHeight: shareButton.icon.height
verticalAlignment: Qt.AlignCenter
cache: true
source: icon
sourceSize.height: 64
sourceSize.width: 64
}
Column {
id: activityTextColumn
Layout.leftMargin: 8
Layout.topMargin: 4
Layout.bottomMargin: 4
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 4
Layout.alignment: Qt.AlignLeft
Text {
id: activityTextTitle
text: (type === "Activity" || type === "Notification") ? subject : message
width: parent.width
elide: Text.ElideRight
font.pixelSize: Style.topLinePixelSize
color: activityTextTitleColor
}
Text {
id: activityTextInfo
text: (type === "Sync") ? displayPath
: (type === "File") ? subject
: (type === "Notification") ? message
: ""
height: (text === "") ? 0 : activityTextTitle.height
width: parent.width
elide: Text.ElideRight
font.pixelSize: Style.subLinePixelSize
}
Text {
id: activityTextDateTime
text: dateTime
height: (text === "") ? 0 : activityTextTitle.height
width: parent.width
elide: Text.ElideRight
font.pixelSize: Style.subLinePixelSize
color: "#808080"
}
}
RowLayout {
id: activityActionsLayout
spacing: 0
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.minimumWidth: 28
Layout.fillWidth: true
function actionButtonIcon(actionIndex) {
const verb = String(model.links[actionIndex].verb);
if (verb === "WEB" && (model.objectType === "chat" || model.objectType === "call")) {
return "qrc:///client/theme/reply.svg";
} else if (verb === "DELETE") {
return "qrc:///client/theme/close.svg";
}
return "qrc:///client/theme/confirm.svg";
}
Repeater {
model: activityItem.links.length > activityListView.maxActionButtons ? 1 : activityItem.links.length
ActivityActionButton {
id: activityActionButton
readonly property int actionIndex: model.index
readonly property bool primary: model.index === 0 && String(activityItem.links[actionIndex].verb) !== "DELETE"
Layout.fillHeight: true
text: !primary ? "" : activityItem.links[actionIndex].label
imageSource: !primary ? activityActionsLayout.actionButtonIcon(actionIndex) : ""
textColor: primary ? Style.ncBlue : "black"
textColorHovered: Style.lightHover
textBorderColor: Style.ncBlue
textBgColor: "transparent"
textBgColorHovered: Style.ncBlue
tooltipText: activityItem.links[actionIndex].label
Layout.minimumWidth: primary ? 80 : -1
Layout.minimumHeight: parent.height
Layout.preferredWidth: primary ? -1 : parent.height
onClicked: activityModel.triggerAction(activityItem.itemIndex, actionIndex)
}
}
Button {
id: moreActionsButton
Layout.preferredWidth: parent.height
Layout.preferredHeight: parent.height
Layout.alignment: Qt.AlignRight
flat: true
hoverEnabled: true
visible: activityItem.links.length > activityListView.maxActionButtons
display: AbstractButton.IconOnly
icon.source: "qrc:///client/theme/more.svg"
icon.color: "transparent"
background: Rectangle {
color: parent.hovered ? Style.lightHover : "transparent"
}
ToolTip.visible: hovered
ToolTip.delay: 1000
ToolTip.text: qsTr("Show more actions")
Accessible.role: Accessible.Button
Accessible.name: qsTr("Show more actions")
Accessible.onPressAction: moreActionsButton.clicked()
onClicked: moreActionsButtonContextMenu.popup();
Connections {
target: trayWindow
onActiveChanged: {
if (!trayWindow.active) {
moreActionsButtonContextMenu.close();
}
}
}
Connections {
target: activityListView
onMovementStarted: {
moreActionsButtonContextMenu.close();
}
}
Container {
id: moreActionsButtonContextMenuContainer
visible: moreActionsButtonContextMenu.opened
width: moreActionsButtonContextMenu.width
height: moreActionsButtonContextMenu.height
anchors.right: moreActionsButton.right
anchors.top: moreActionsButton.top
Menu {
id: moreActionsButtonContextMenu
anchors.centerIn: parent
// transform model to contain indexed actions with primary action filtered out
function actionListToContextMenuList(actionList) {
// early out with non-altered data
if (activityItem.links.length <= activityListView.maxActionButtons) {
return actionList;
}
// add index to every action and filter 'primary' action out
var reducedActionList = actionList.reduce(function(reduced, action, index) {
if (!action.primary) {
var actionWithIndex = { actionIndex: index, label: action.label };
reduced.push(actionWithIndex);
}
return reduced;
}, []);
return reducedActionList;
}
Repeater {
id: moreActionsButtonContextMenuRepeater
model: moreActionsButtonContextMenu.actionListToContextMenuList(activityItem.links)
delegate: MenuItem {
id: moreActionsButtonContextMenuEntry
text: model.modelData.label
onTriggered: activityModel.triggerAction(activityItem.itemIndex, model.modelData.actionIndex)
}
}
}
}
}
Button {
id: shareButton
Layout.preferredWidth: (path === "") ? 0 : parent.height
Layout.preferredHeight: parent.height
Layout.alignment: Qt.AlignRight
flat: true
hoverEnabled: true
visible: (path === "") ? false : true
display: AbstractButton.IconOnly
icon.source: "qrc:///client/theme/share.svg"
icon.color: "transparent"
background: Rectangle {
color: parent.hovered ? Style.lightHover : "transparent"
}
ToolTip.visible: hovered
ToolTip.delay: 1000
ToolTip.text: qsTr("Open share dialog")
onClicked: Systray.openShareDialog(displayPath,absolutePath)
Accessible.role: Accessible.Button
Accessible.name: qsTr("Share %1").arg(displayPath)
Accessible.onPressAction: shareButton.clicked()
}
}
}
}

View File

@@ -14,236 +14,237 @@ MenuItem {
Accessible.role: Accessible.MenuItem Accessible.role: Accessible.MenuItem
Accessible.name: qsTr("Account entry") Accessible.name: qsTr("Account entry")
RowLayout { RowLayout {
id: userLineLayout id: userLineLayout
spacing: 0 spacing: 0
width: Style.currentAccountButtonWidth anchors.fill: parent
height: parent.height
Button { Button {
id: accountButton id: accountButton
Layout.preferredWidth: (userLineLayout.width * (5/6)) Layout.preferredWidth: (userLineLayout.width * (5/6))
Layout.preferredHeight: (userLineLayout.height) Layout.preferredHeight: (userLineLayout.height)
display: AbstractButton.IconOnly display: AbstractButton.IconOnly
hoverEnabled: true
flat: true
Accessible.role: Accessible.Button
Accessible.name: qsTr("Switch to account") + " " + name
MouseArea {
anchors.fill: parent
hoverEnabled: true hoverEnabled: true
flat: true onContainsMouseChanged: {
accountStatusIndicatorBackground.color = (containsMouse ? "#f6f6f6" : "white")
Accessible.role: Accessible.Button
Accessible.name: qsTr("Switch to account") + " " + name
MouseArea {
anchors.fill: parent
hoverEnabled: true
onContainsMouseChanged: {
accountStatusIndicatorBackground.color = (containsMouse ? "#f6f6f6" : "white")
}
onClicked: {
if (!isCurrentUser) {
UserModel.switchCurrentUser(id)
} else {
accountMenu.close()
}
}
} }
onClicked: {
if (!isCurrentUser) {
background: Item { UserModel.switchCurrentUser(id)
height: parent.height } else {
width: userLine.menu ? userLine.menu.width : 0 accountMenu.close()
Rectangle {
anchors.fill: parent
anchors.margins: 1
color: parent.parent.hovered ? Style.lightHover : "transparent"
}
}
RowLayout {
id: accountControlRowLayout
height: accountButton.height
width: accountButton.width
spacing: Style.userStatusSpacing
Image {
id: accountAvatar
Layout.leftMargin: 7
verticalAlignment: Qt.AlignCenter
cache: false
source: model.avatar != "" ? model.avatar : "image://avatars/fallbackBlack"
Layout.preferredHeight: Style.accountAvatarSize
Layout.preferredWidth: Style.accountAvatarSize
Rectangle {
id: accountStatusIndicatorBackground
visible: model.isConnected &&
model.serverHasUserStatus
width: accountStatusIndicator.sourceSize.width + 2
height: width
anchors.bottom: accountAvatar.bottom
anchors.right: accountAvatar.right
color: "white"
radius: width*0.5
}
Image {
id: accountStatusIndicator
visible: model.isConnected &&
model.serverHasUserStatus
source: model.statusIcon
cache: false
x: accountStatusIndicatorBackground.x + 1
y: accountStatusIndicatorBackground.y + 1
sourceSize.width: Style.accountAvatarStateIndicatorSize
sourceSize.height: Style.accountAvatarStateIndicatorSize
Accessible.role: Accessible.Indicator
Accessible.name: model.desktopNotificationsAllowed ? qsTr("Current user status is online") : qsTr("Current user status is do not disturb")
}
}
Column {
id: accountLabels
Layout.leftMargin: Style.accountLabelsSpacing
Label {
id: accountUser
width: 128
text: name
elide: Text.ElideRight
color: "black"
font.pixelSize: Style.topLinePixelSize
font.bold: true
}
Row {
visible: model.isConnected &&
model.serverHasUserStatus
width: Style.currentAccountLabelWidth + Style.userStatusEmojiSize
Label {
id: emoji
height: Style.topLinePixelSize
visible: model.statusEmoji !== ""
text: statusEmoji
topPadding: -Style.accountLabelsSpacing
}
Label {
id: message
height: Style.topLinePixelSize
visible: model.statusMessage !== ""
text: statusMessage
elide: Text.ElideRight
color: "black"
font.pixelSize: Style.subLinePixelSize
leftPadding: Style.accountLabelsSpacing
}
}
Label {
id: accountServer
width: Style.currentAccountLabelWidth
height: Style.topLinePixelSize
text: server
elide: Text.ElideRight
color: "black"
font.pixelSize: Style.subLinePixelSize
}
}
}
} // accountButton
Button {
id: userMoreButton
Layout.preferredWidth: (userLineLayout.width * (1/6))
Layout.preferredHeight: userLineLayout.height
flat: true
icon.source: "qrc:///client/theme/more.svg"
icon.color: "transparent"
Accessible.role: Accessible.ButtonMenu
Accessible.name: qsTr("Account actions")
Accessible.onPressAction: userMoreButtonMouseArea.clicked()
MouseArea {
id: userMoreButtonMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
if (userMoreButtonMenu.visible) {
userMoreButtonMenu.close()
} else {
userMoreButtonMenu.popup()
}
}
}
background:
Rectangle {
color: userMoreButtonMouseArea.containsMouse ? "grey" : "transparent"
opacity: 0.2
height: userMoreButton.height - 2
y: userMoreButton.y + 1
}
Menu {
id: userMoreButtonMenu
width: 120
closePolicy: Menu.CloseOnPressOutsideParent | Menu.CloseOnEscape
background: Rectangle {
border.color: Style.menuBorder
radius: 2
}
MenuItem {
text: model.isConnected ? qsTr("Log out") : qsTr("Log in")
font.pixelSize: Style.topLinePixelSize
hoverEnabled: true
onClicked: {
model.isConnected ? UserModel.logout(index) : UserModel.login(index)
accountMenu.close()
}
background: Item {
height: parent.height
width: parent.menu.width
Rectangle {
anchors.fill: parent
anchors.margins: 1
color: parent.parent.hovered ? Style.lightHover : "transparent"
}
}
Accessible.role: Accessible.Button
Accessible.name: model.isConnected ? qsTr("Log out") : qsTr("Log in")
onPressed: {
if (model.isConnected) {
UserModel.logout(index)
} else {
UserModel.login(index)
}
accountMenu.close()
}
}
MenuItem {
id: removeAccountButton
text: qsTr("Remove account")
font.pixelSize: Style.topLinePixelSize
hoverEnabled: true
onClicked: {
UserModel.removeAccount(index)
accountMenu.close()
}
background: Item {
height: parent.height
width: parent.menu.width
Rectangle {
anchors.fill: parent
anchors.margins: 1
color: parent.parent.hovered ? Style.lightHover : "transparent"
}
}
Accessible.role: Accessible.Button
Accessible.name: text
Accessible.onPressAction: removeAccountButton.clicked()
} }
} }
} }
background: Item {
height: parent.height
width: userLine.menu ? userLine.menu.width : 0
Rectangle {
anchors.fill: parent
anchors.margins: 1
color: parent.parent.hovered ? Style.lightHover : "transparent"
}
}
RowLayout {
id: accountControlRowLayout
anchors.fill: parent
spacing: Style.userStatusSpacing
Image {
id: accountAvatar
Layout.leftMargin: 7
verticalAlignment: Qt.AlignCenter
cache: false
source: model.avatar != "" ? model.avatar : "image://avatars/fallbackBlack"
Layout.preferredHeight: Style.accountAvatarSize
Layout.preferredWidth: Style.accountAvatarSize
Rectangle {
id: accountStatusIndicatorBackground
visible: model.isConnected &&
model.serverHasUserStatus
width: accountStatusIndicator.sourceSize.width + 2
height: width
anchors.bottom: accountAvatar.bottom
anchors.right: accountAvatar.right
color: "white"
radius: width*0.5
}
Image {
id: accountStatusIndicator
visible: model.isConnected &&
model.serverHasUserStatus
source: model.statusIcon
cache: false
x: accountStatusIndicatorBackground.x + 1
y: accountStatusIndicatorBackground.y + 1
sourceSize.width: Style.accountAvatarStateIndicatorSize
sourceSize.height: Style.accountAvatarStateIndicatorSize
Accessible.role: Accessible.Indicator
Accessible.name: model.desktopNotificationsAllowed ? qsTr("Current user status is online") : qsTr("Current user status is do not disturb")
}
}
Column {
id: accountLabels
Layout.leftMargin: Style.accountLabelsSpacing
Layout.fillWidth: true
Layout.maximumWidth: parent.width - Style.accountLabelsSpacing
Label {
id: accountUser
text: name
elide: Text.ElideRight
color: "black"
font.pixelSize: Style.topLinePixelSize
font.bold: true
width: parent.width
}
Row {
visible: model.isConnected &&
model.serverHasUserStatus
width: parent.width
Label {
id: emoji
height: Style.topLinePixelSize
visible: model.statusEmoji !== ""
text: statusEmoji
topPadding: -Style.accountLabelsSpacing
}
Label {
id: message
height: Style.topLinePixelSize
width: parent.width - parent.spacing - emoji.width
visible: model.statusMessage !== ""
text: statusMessage
elide: Text.ElideRight
color: "black"
font.pixelSize: Style.subLinePixelSize
leftPadding: Style.accountLabelsSpacing
}
}
Label {
id: accountServer
width: Style.currentAccountLabelWidth
height: Style.topLinePixelSize
text: server
elide: Text.ElideRight
color: "black"
font.pixelSize: Style.subLinePixelSize
}
}
}
} // accountButton
Button {
id: userMoreButton
Layout.preferredWidth: (userLineLayout.width * (1/6))
Layout.preferredHeight: userLineLayout.height
flat: true
icon.source: "qrc:///client/theme/more.svg"
icon.color: "transparent"
Accessible.role: Accessible.ButtonMenu
Accessible.name: qsTr("Account actions")
Accessible.onPressAction: userMoreButtonMouseArea.clicked()
MouseArea {
id: userMoreButtonMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
if (userMoreButtonMenu.visible) {
userMoreButtonMenu.close()
} else {
userMoreButtonMenu.popup()
}
}
}
background:
Rectangle {
color: userMoreButtonMouseArea.containsMouse ? "grey" : "transparent"
opacity: 0.2
height: userMoreButton.height - 2
y: userMoreButton.y + 1
}
Menu {
id: userMoreButtonMenu
width: 120
closePolicy: Menu.CloseOnPressOutsideParent | Menu.CloseOnEscape
background: Rectangle {
border.color: Style.menuBorder
radius: 2
}
MenuItem {
text: model.isConnected ? qsTr("Log out") : qsTr("Log in")
font.pixelSize: Style.topLinePixelSize
hoverEnabled: true
onClicked: {
model.isConnected ? UserModel.logout(index) : UserModel.login(index)
accountMenu.close()
}
background: Item {
height: parent.height
width: parent.menu.width
Rectangle {
anchors.fill: parent
anchors.margins: 1
color: parent.parent.hovered ? Style.lightHover : "transparent"
}
}
Accessible.role: Accessible.Button
Accessible.name: model.isConnected ? qsTr("Log out") : qsTr("Log in")
onPressed: {
if (model.isConnected) {
UserModel.logout(index)
} else {
UserModel.login(index)
}
accountMenu.close()
}
}
MenuItem {
id: removeAccountButton
text: qsTr("Remove account")
font.pixelSize: Style.topLinePixelSize
hoverEnabled: true
onClicked: {
UserModel.removeAccount(index)
accountMenu.close()
}
background: Item {
height: parent.height
width: parent.menu.width
Rectangle {
anchors.fill: parent
anchors.margins: 1
color: parent.parent.hovered ? Style.lightHover : "transparent"
}
}
Accessible.role: Accessible.Button
Accessible.name: text
Accessible.onPressAction: removeAccountButton.clicked()
}
}
} }
}
} // MenuItem userLine } // MenuItem userLine

View File

@@ -1,4 +1,4 @@
import QtQml 2.1 import QtQml 2.12
import QtQml.Models 2.1 import QtQml.Models 2.1
import QtQuick 2.9 import QtQuick 2.9
import QtQuick.Window 2.3 import QtQuick.Window 2.3
@@ -19,7 +19,7 @@ Window {
width: Systray.useNormalWindow ? Style.trayWindowHeight : Style.trayWindowWidth width: Systray.useNormalWindow ? Style.trayWindowHeight : Style.trayWindowWidth
height: Style.trayWindowHeight height: Style.trayWindowHeight
color: "transparent" color: "transparent"
flags: Qt.WindowTitleHint | Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint | (Systray.useNormalWindow ? Qt.Dialog : Qt.Dialog | Qt.FramelessWindowHint) flags: Systray.useNormalWindow ? Qt.Window : Qt.Dialog | Qt.FramelessWindowHint
readonly property int maxMenuHeight: Style.trayWindowHeight - Style.trayWindowHeaderHeight - 2 * Style.trayWindowBorderWidth readonly property int maxMenuHeight: Style.trayWindowHeight - Style.trayWindowHeaderHeight - 2 * Style.trayWindowBorderWidth
@@ -30,7 +30,7 @@ Window {
onActiveChanged: { onActiveChanged: {
if (!Systray.useNormalWindow && !active) { if (!Systray.useNormalWindow && !active) {
hide(); hide();
setClosed(); Systray.setClosed();
} }
} }
@@ -362,6 +362,9 @@ Window {
spacing: 0 spacing: 0
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.leftMargin: Style.userStatusSpacing Layout.leftMargin: Style.userStatusSpacing
Layout.fillWidth: true
Layout.maximumWidth: parent.width
Label { Label {
id: currentAccountUser id: currentAccountUser
Layout.alignment: Qt.AlignLeft | Qt.AlignBottom Layout.alignment: Qt.AlignLeft | Qt.AlignBottom
@@ -372,11 +375,14 @@ Window {
font.pixelSize: Style.topLinePixelSize font.pixelSize: Style.topLinePixelSize
font.bold: true font.bold: true
} }
RowLayout { RowLayout {
id: currentUserStatus id: currentUserStatus
visible: UserModel.currentUser.isConnected && visible: UserModel.currentUser.isConnected &&
UserModel.currentUser.serverHasUserStatus UserModel.currentUser.serverHasUserStatus
spacing: Style.accountLabelsSpacing spacing: Style.accountLabelsSpacing
width: parent.width
Label { Label {
id: emoji id: emoji
visible: UserModel.currentUser.statusEmoji !== "" visible: UserModel.currentUser.statusEmoji !== ""
@@ -386,6 +392,7 @@ Window {
Label { Label {
id: message id: message
Layout.alignment: Qt.AlignLeft | Qt.AlignBottom Layout.alignment: Qt.AlignLeft | Qt.AlignBottom
Layout.fillWidth: true
visible: UserModel.currentUser.statusMessage !== "" visible: UserModel.currentUser.statusMessage !== ""
width: Style.currentAccountLabelWidth width: Style.currentAccountLabelWidth
text: UserModel.currentUser.statusMessage !== "" text: UserModel.currentUser.statusMessage !== ""
@@ -572,296 +579,11 @@ Window {
model: activityModel model: activityModel
delegate: RowLayout { delegate: ActivityItem {
id: activityItem width: activityListView.width
readonly property variant links: model.links
readonly property int itemIndex: model.index
width: parent.width
height: Style.trayWindowHeaderHeight height: Style.trayWindowHeaderHeight
spacing: 0 onClicked: activityModel.triggerDefaultAction(model.index)
Accessible.role: Accessible.ListItem
Accessible.name: path !== "" ? qsTr("Open %1 locally").arg(displayPath)
: message
Accessible.onPressAction: activityMouseArea.clicked()
MouseArea {
id: activityMouseArea
enabled: (path !== "" || link !== "")
anchors.left: activityItem.left
anchors.right: activityActionsLayout.right
height: parent.height
anchors.margins: 2
hoverEnabled: true
onClicked: activityModel.triggerDefaultAction(model.index)
Rectangle {
anchors.fill: parent
color: (parent.containsMouse ? Style.lightHover : "transparent")
}
}
Image {
id: activityIcon
anchors.left: activityItem.left
anchors.leftMargin: 8
anchors.rightMargin: 8
Layout.preferredWidth: shareButton.icon.width
Layout.preferredHeight: shareButton.icon.height
verticalAlignment: Qt.AlignCenter
cache: true
source: icon
sourceSize.height: 64
sourceSize.width: 64
}
Column {
id: activityTextColumn
anchors.left: activityIcon.right
anchors.right: activityActionsLayout.left
anchors.leftMargin: 8
spacing: 4
Layout.alignment: Qt.AlignLeft
Text {
id: activityTextTitle
text: (type === "Activity" || type === "Notification") ? subject : message
width: parent.width
elide: Text.ElideRight
font.pixelSize: Style.topLinePixelSize
color: activityTextTitleColor
}
Text {
id: activityTextInfo
text: (type === "Sync") ? displayPath
: (type === "File") ? subject
: (type === "Notification") ? message
: ""
height: (text === "") ? 0 : activityTextTitle.height
width: parent.width
elide: Text.ElideRight
font.pixelSize: Style.subLinePixelSize
}
Text {
id: activityTextDateTime
text: dateTime
height: (text === "") ? 0 : activityTextTitle.height
width: parent.width
elide: Text.ElideRight
font.pixelSize: Style.subLinePixelSize
color: "#808080"
}
ToolTip {
id: toolTip
visible: activityMouseArea.containsMouse
text: activityTextTitle.text + ((activityTextInfo.text !== "") ? "\n\n" + activityTextInfo.text : "")
delay: 250
timeout: 10000
// Can be dropped on more recent Qt, but on 5.12 it doesn't wrap...
contentItem: Text {
text: toolTip.text
font: toolTip.font
wrapMode: Text.Wrap
color: toolTip.palette.toolTipText
}
}
}
RowLayout {
id: activityActionsLayout
anchors.right: activityItem.right
spacing: 0
Layout.alignment: Qt.AlignRight
function actionButtonIcon(actionIndex) {
const verb = String(model.links[actionIndex].verb);
if (verb === "WEB" && (model.objectType === "chat" || model.objectType === "call")) {
return "qrc:///client/theme/reply.svg";
} else if (verb === "DELETE") {
return "qrc:///client/theme/close.svg";
}
return "qrc:///client/theme/confirm.svg";
}
Repeater {
model: activityItem.links.length > activityListView.maxActionButtons ? 1 : activityItem.links.length
ActivityActionButton {
id: activityActionButton
readonly property int actionIndex: model.index
readonly property bool primary: model.index === 0 && String(activityItem.links[actionIndex].verb) !== "DELETE"
height: activityItem.height
text: !primary ? "" : activityItem.links[actionIndex].label
imageSource: !primary ? activityActionsLayout.actionButtonIcon(actionIndex) : ""
textColor: primary ? Style.ncBlue : "black"
textColorHovered: Style.lightHover
textBorderColor: Style.ncBlue
textBgColor: "transparent"
textBgColorHovered: Style.ncBlue
tooltipText: activityItem.links[actionIndex].label
Layout.minimumWidth: primary ? 80 : -1
Layout.minimumHeight: parent.height
Layout.preferredWidth: primary ? -1 : parent.height
onClicked: activityModel.triggerAction(activityItem.itemIndex, actionIndex)
}
}
Button {
id: moreActionsButton
Layout.preferredWidth: parent.height
Layout.preferredHeight: parent.height
Layout.alignment: Qt.AlignRight
flat: true
hoverEnabled: true
visible: activityItem.links.length > activityListView.maxActionButtons
display: AbstractButton.IconOnly
icon.source: "qrc:///client/theme/more.svg"
icon.color: "transparent"
background: Rectangle {
color: parent.hovered ? Style.lightHover : "transparent"
}
ToolTip.visible: hovered
ToolTip.delay: 1000
ToolTip.text: qsTr("Show more actions")
Accessible.role: Accessible.Button
Accessible.name: qsTr("Show more actions")
Accessible.onPressAction: moreActionsButton.clicked()
onClicked: moreActionsButtonContextMenu.popup();
Connections {
target: trayWindow
onActiveChanged: {
if (!trayWindow.active) {
moreActionsButtonContextMenu.close();
}
}
}
Connections {
target: activityListView
onMovementStarted: {
moreActionsButtonContextMenu.close();
}
}
Container {
id: moreActionsButtonContextMenuContainer
visible: moreActionsButtonContextMenu.opened
width: moreActionsButtonContextMenu.width
height: moreActionsButtonContextMenu.height
anchors.right: moreActionsButton.right
anchors.top: moreActionsButton.top
Menu {
id: moreActionsButtonContextMenu
anchors.centerIn: parent
// transform model to contain indexed actions with primary action filtered out
function actionListToContextMenuList(actionList) {
// early out with non-altered data
if (activityItem.links.length <= activityListView.maxActionButtons) {
return actionList;
}
// add index to every action and filter 'primary' action out
var reducedActionList = actionList.reduce(function(reduced, action, index) {
if (!action.primary) {
var actionWithIndex = { actionIndex: index, label: action.label };
reduced.push(actionWithIndex);
}
return reduced;
}, []);
return reducedActionList;
}
Repeater {
id: moreActionsButtonContextMenuRepeater
model: moreActionsButtonContextMenu.actionListToContextMenuList(activityItem.links)
delegate: MenuItem {
id: moreActionsButtonContextMenuEntry
readonly property int actionIndex: model.modelData.actionIndex
readonly property string label: model.modelData.label
text: label
onTriggered: activityModel.triggerAction(activityItem.itemIndex, actionIndex)
}
}
}
}
}
Button {
id: shareButton
Layout.preferredWidth: (path === "") ? 0 : parent.height
Layout.preferredHeight: parent.height
Layout.alignment: Qt.AlignRight
flat: true
hoverEnabled: true
visible: (path === "") ? false : true
display: AbstractButton.IconOnly
icon.source: "qrc:///client/theme/share.svg"
icon.color: "transparent"
background: Rectangle {
color: parent.hovered ? Style.lightHover : "transparent"
}
ToolTip.visible: hovered
ToolTip.delay: 1000
ToolTip.text: qsTr("Open share dialog")
onClicked: Systray.openShareDialog(displayPath,absolutePath)
Accessible.role: Accessible.Button
Accessible.name: qsTr("Share %1").arg(displayPath)
Accessible.onPressAction: shareButton.clicked()
}
}
} }
/*add: Transition {
NumberAnimation { properties: "y"; from: -60; duration: 100; easing.type: Easing.Linear }
}
remove: Transition {
NumberAnimation { property: "opacity"; from: 1.0; to: 0; duration: 100 }
}
removeDisplaced: Transition {
SequentialAnimation {
PauseAnimation { duration: 100}
NumberAnimation { properties: "y"; duration: 100; easing.type: Easing.Linear }
}
}
displaced: Transition {
NumberAnimation { properties: "y"; duration: 100; easing.type: Easing.Linear }
}*/
} }
} // Rectangle trayWindowBackground } // Rectangle trayWindowBackground
} }

View File

@@ -104,15 +104,20 @@ bool OCUpdater::performUpdate()
QString updateFile = settings.value(updateAvailableC).toString(); QString updateFile = settings.value(updateAvailableC).toString();
if (!updateFile.isEmpty() && QFile(updateFile).exists() if (!updateFile.isEmpty() && QFile(updateFile).exists()
&& !updateSucceeded() /* Someone might have run the updater manually between restarts */) { && !updateSucceeded() /* Someone might have run the updater manually between restarts */) {
const QString name = Theme::instance()->appNameGUI(); const auto messageBoxStartInstaller = new QMessageBox(QMessageBox::Information,
if (QMessageBox::information(nullptr, tr("New %1 Update Ready").arg(name), tr("New %1 update ready").arg(Theme::instance()->appNameGUI()),
tr("A new update for %1 is about to be installed. The updater may ask\n" tr("A new update for %1 is about to be installed. The updater may ask\n"
"for additional privileges during the process.") "for additional privileges during the process.")
.arg(name), .arg(Theme::instance()->appNameGUI()),
QMessageBox::Ok)) { QMessageBox::Ok,
nullptr);
messageBoxStartInstaller->setAttribute(Qt::WA_DeleteOnClose);
connect(messageBoxStartInstaller, &QMessageBox::finished, this, [this] {
slotStartInstaller(); slotStartInstaller();
return true; });
} messageBoxStartInstaller->open();
} }
return false; return false;
} }
@@ -216,6 +221,7 @@ void OCUpdater::slotStartInstaller()
QProcess::startDetached("powershell.exe", QStringList{"-Command", command}); QProcess::startDetached("powershell.exe", QStringList{"-Command", command});
} }
qApp->quit();
} }
void OCUpdater::checkForUpdate() void OCUpdater::checkForUpdate()
@@ -476,7 +482,6 @@ void NSISUpdater::showUpdateErrorDialog(const QString &targetVersion)
// askagain: do nothing // askagain: do nothing
connect(retry, &QAbstractButton::clicked, this, [this]() { connect(retry, &QAbstractButton::clicked, this, [this]() {
slotStartInstaller(); slotStartInstaller();
qApp->quit();
}); });
connect(getupdate, &QAbstractButton::clicked, this, [this]() { connect(getupdate, &QAbstractButton::clicked, this, [this]() {
slotOpenUpdateUrl(); slotOpenUpdateUrl();

View File

@@ -16,12 +16,18 @@
#include "common/utility.h" #include "common/utility.h"
#include "account.h" #include "account.h"
#include "creds/webflowcredentials.h"
#include "networkjobs.h"
#include "wizard/owncloudwizardcommon.h" #include "wizard/owncloudwizardcommon.h"
#include "theme.h" #include "theme.h"
#include "linklabel.h" #include "linklabel.h"
#include "QProgressIndicator.h" #include "QProgressIndicator.h"
#include <QJsonDocument>
#include <QStringLiteral>
#include <QJsonObject>
namespace OCC { namespace OCC {
Q_LOGGING_CATEGORY(lcFlow2AuthWidget, "nextcloud.gui.wizard.flow2authwidget", QtInfoMsg) Q_LOGGING_CATEGORY(lcFlow2AuthWidget, "nextcloud.gui.wizard.flow2authwidget", QtInfoMsg)

View File

@@ -168,7 +168,7 @@ void OwncloudAdvancedSetupPage::initializePage()
_ui.confCheckBoxExternal->setChecked(cfgFile.confirmExternalStorage()); _ui.confCheckBoxExternal->setChecked(cfgFile.confirmExternalStorage());
fetchUserAvatar(); fetchUserAvatar();
fetchUserData(); setUserInformation();
customizeStyle(); customizeStyle();
@@ -201,20 +201,9 @@ void OwncloudAdvancedSetupPage::fetchUserAvatar()
avatarJob->start(); avatarJob->start();
} }
void OwncloudAdvancedSetupPage::fetchUserData() void OwncloudAdvancedSetupPage::setUserInformation()
{ {
const auto account = _ocWizard->account(); const auto account = _ocWizard->account();
// Fetch user data
const auto userJob = new JsonApiJob(account, QLatin1String("ocs/v1.php/cloud/user"), this);
userJob->setTimeout(20 * 1000);
connect(userJob, &JsonApiJob::jsonReceived, this, [this](const QJsonDocument &json) {
const auto objData = json.object().value("ocs").toObject().value("data").toObject();
const auto displayName = objData.value("display-name").toString();
_ui.userNameLabel->setText(displayName);
});
userJob->start();
const auto serverUrl = account->url().toString(); const auto serverUrl = account->url().toString();
setServerAddressLabelUrl(serverUrl); setServerAddressLabelUrl(serverUrl);
const auto userName = account->davDisplayName(); const auto userName = account->davDisplayName();

View File

@@ -82,7 +82,7 @@ private:
void setResolutionGuiVisible(bool value); void setResolutionGuiVisible(bool value);
void setupResoultionWidget(); void setupResoultionWidget();
void fetchUserAvatar(); void fetchUserAvatar();
void fetchUserData(); void setUserInformation();
// TODO: remove when UX decision is made // TODO: remove when UX decision is made
void refreshVirtualFilesAvailibility(const QString &path); void refreshVirtualFilesAvailibility(const QString &path);

View File

@@ -52,6 +52,11 @@ public:
protected: protected:
bool certificateError(const QWebEngineCertificateError &certificateError) override; bool certificateError(const QWebEngineCertificateError &certificateError) override;
bool acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame) override;
private:
bool _enforceHttps = false;
}; };
// We need a separate class here, since we cannot simply return the same WebEnginePage object // We need a separate class here, since we cannot simply return the same WebEnginePage object
@@ -186,8 +191,10 @@ QWebEnginePage * WebEnginePage::createWindow(QWebEnginePage::WebWindowType type)
return view; return view;
} }
void WebEnginePage::setUrl(const QUrl &url) { void WebEnginePage::setUrl(const QUrl &url)
{
QWebEnginePage::setUrl(url); QWebEnginePage::setUrl(url);
_enforceHttps = url.scheme() == QStringLiteral("https");
} }
bool WebEnginePage::certificateError(const QWebEngineCertificateError &certificateError) bool WebEnginePage::certificateError(const QWebEngineCertificateError &certificateError)
@@ -211,6 +218,18 @@ bool WebEnginePage::certificateError(const QWebEngineCertificateError &certifica
return ret == QMessageBox::Yes; return ret == QMessageBox::Yes;
} }
bool WebEnginePage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame)
{
Q_UNUSED(type);
Q_UNUSED(isMainFrame);
if (_enforceHttps && url.scheme() != QStringLiteral("https") && url.scheme() != QStringLiteral("nc")) {
QMessageBox::warning(nullptr, "Security warning", "Can not follow non https link on a https website. This might be a security issue. Please contact your administrator");
return false;
}
return true;
}
ExternalWebEnginePage::ExternalWebEnginePage(QWebEngineProfile *profile, QObject* parent) : QWebEnginePage(profile, parent) { ExternalWebEnginePage::ExternalWebEnginePage(QWebEngineProfile *profile, QObject* parent) : QWebEnginePage(profile, parent) {
} }

View File

@@ -59,7 +59,6 @@ const char app_password[] = "_app-password";
Account::Account(QObject *parent) Account::Account(QObject *parent)
: QObject(parent) : QObject(parent)
, _capabilities(QVariantMap()) , _capabilities(QVariantMap())
, _davPath(Theme::instance()->webDavPath())
{ {
qRegisterMetaType<AccountPtr>("AccountPtr"); qRegisterMetaType<AccountPtr>("AccountPtr");
qRegisterMetaType<Account *>("Account*"); qRegisterMetaType<Account *>("Account*");
@@ -85,18 +84,7 @@ Account::~Account() = default;
QString Account::davPath() const QString Account::davPath() const
{ {
if (capabilities().chunkingNg()) { return davPathBase() + QLatin1Char('/') + davUser() + QLatin1Char('/');
// The chunking-ng means the server prefer to use the new webdav URL
return QLatin1String("/remote.php/dav/files/") + davUser() + QLatin1Char('/');
}
// make sure to have a trailing slash
if (!_davPath.endsWith('/')) {
QString dp(_davPath);
dp.append('/');
return dp;
}
return _davPath;
} }
void Account::setSharedThis(AccountPtr sharedThis) void Account::setSharedThis(AccountPtr sharedThis)
@@ -104,6 +92,11 @@ void Account::setSharedThis(AccountPtr sharedThis)
_sharedThis = sharedThis.toWeakRef(); _sharedThis = sharedThis.toWeakRef();
} }
QString Account::davPathBase()
{
return QStringLiteral("/remote.php/dav/files");
}
AccountPtr Account::sharedFromThis() AccountPtr Account::sharedFromThis()
{ {
return _sharedThis.toStrongRef(); return _sharedThis.toStrongRef();
@@ -111,7 +104,7 @@ AccountPtr Account::sharedFromThis()
QString Account::davUser() const QString Account::davUser() const
{ {
return _davUser.isEmpty() ? _credentials->user() : _davUser; return _davUser.isEmpty() && _credentials ? _credentials->user() : _davUser;
} }
void Account::setDavUser(const QString &newDavUser) void Account::setDavUser(const QString &newDavUser)
@@ -498,7 +491,27 @@ void Account::slotHandleSslErrors(QNetworkReply *reply, QList<QSslError> errors)
void Account::slotCredentialsFetched() void Account::slotCredentialsFetched()
{ {
emit credentialsFetched(_credentials.data()); if (_davUser.isEmpty()) {
qCDebug(lcAccount) << "User id not set. Fetch it.";
const auto fetchUserNameJob = new JsonApiJob(sharedFromThis(), QStringLiteral("/ocs/v1.php/cloud/user"));
connect(fetchUserNameJob, &JsonApiJob::jsonReceived, this, [this, fetchUserNameJob](const QJsonDocument &json, int statusCode) {
fetchUserNameJob->deleteLater();
if (statusCode != 100) {
qCWarning(lcAccount) << "Could not fetch user id. Login will probably not work.";
emit credentialsFetched(_credentials.data());
return;
}
const auto objData = json.object().value("ocs").toObject().value("data").toObject();
const auto userId = objData.value("id").toString("");
setDavUser(userId);
emit credentialsFetched(_credentials.data());
});
fetchUserNameJob->start();
} else {
qCDebug(lcAccount) << "User id already fetched.";
emit credentialsFetched(_credentials.data());
}
} }
void Account::slotCredentialsAsked() void Account::slotCredentialsAsked()
@@ -571,15 +584,6 @@ void Account::setServerVersion(const QString &version)
emit serverVersionChanged(this, oldServerVersion, version); emit serverVersionChanged(this, oldServerVersion, version);
} }
void Account::setNonShib(bool nonShib)
{
if (nonShib) {
_davPath = Theme::instance()->webDavPathNonShib();
} else {
_davPath = Theme::instance()->webDavPath();
}
}
void Account::writeAppPasswordOnce(QString appPassword){ void Account::writeAppPasswordOnce(QString appPassword){
if(_wroteAppPassword) if(_wroteAppPassword)
return; return;

View File

@@ -124,8 +124,6 @@ public:
* @returns the (themeable) dav path for the account. * @returns the (themeable) dav path for the account.
*/ */
QString davPath() const; QString davPath() const;
void setDavPath(const QString &s) { _davPath = s; }
void setNonShib(bool nonShib);
/** Returns webdav entry URL, based on url() */ /** Returns webdav entry URL, based on url() */
QUrl davUrl() const; QUrl davUrl() const;
@@ -296,6 +294,8 @@ private:
Account(QObject *parent = nullptr); Account(QObject *parent = nullptr);
void setSharedThis(AccountPtr sharedThis); void setSharedThis(AccountPtr sharedThis);
static QString davPathBase();
QWeakPointer<Account> _sharedThis; QWeakPointer<Account> _sharedThis;
QString _id; QString _id;
QString _davUser; QString _davUser;
@@ -329,7 +329,6 @@ private:
static QString _configFileName; static QString _configFileName;
QString _davPath; // defaults to value from theme, might be overwritten in brandings
ClientSideEncryption _e2e; ClientSideEncryption _e2e;
/// Used in RemoteWipe /// Used in RemoteWipe

View File

@@ -1663,7 +1663,6 @@ bool EncryptionHelper::fileEncryption(const QByteArray &key, const QByteArray &i
return false; return false;
} }
qCDebug(lcCse) << "Encrypting " << data;
if(!EVP_EncryptUpdate(ctx, unsignedData(out), &len, (unsigned char *)data.constData(), data.size())) { if(!EVP_EncryptUpdate(ctx, unsignedData(out), &len, (unsigned char *)data.constData(), data.size())) {
qCInfo(lcCse()) << "Could not encrypt"; qCInfo(lcCse()) << "Could not encrypt";
return false; return false;

View File

@@ -50,7 +50,6 @@
#define DEFAULT_MAX_LOG_LINES 20000 #define DEFAULT_MAX_LOG_LINES 20000
namespace { namespace {
static constexpr char allowChecksumValidationFailC[] = "allowChecksumValidationFail";
static constexpr char showMainDialogAsNormalWindowC[] = "showMainDialogAsNormalWindow"; static constexpr char showMainDialogAsNormalWindowC[] = "showMainDialogAsNormalWindow";
} }
@@ -892,11 +891,6 @@ void ConfigFile::setMoveToTrash(bool isChecked)
setValue(moveToTrashC, isChecked); setValue(moveToTrashC, isChecked);
} }
bool ConfigFile::allowChecksumValidationFail() const
{
return getValue(allowChecksumValidationFailC, {}, false).toBool();
}
bool ConfigFile::showMainDialogAsNormalWindow() const { bool ConfigFile::showMainDialogAsNormalWindow() const {
return getValue(showMainDialogAsNormalWindowC, {}, false).toBool(); return getValue(showMainDialogAsNormalWindowC, {}, false).toBool();
} }

View File

@@ -145,9 +145,6 @@ public:
bool moveToTrash() const; bool moveToTrash() const;
void setMoveToTrash(bool); void setMoveToTrash(bool);
/** should we allow checksum validation to fail? set to true to workaround corrupted checksums **/
bool allowChecksumValidationFail() const;
bool showMainDialogAsNormalWindow() const; bool showMainDialogAsNormalWindow() const;
static bool setConfDir(const QString &value); static bool setConfDir(const QString &value);

View File

@@ -403,7 +403,7 @@ bool LsColJob::finished()
connect(&parser, &LsColXMLParser::finishedWithoutError, connect(&parser, &LsColXMLParser::finishedWithoutError,
this, &LsColJob::finishedWithoutError); this, &LsColJob::finishedWithoutError);
QString expectedPath = reply()->request().url().path(); // something like "/owncloud/remote.php/webdav/folder" QString expectedPath = reply()->request().url().path(); // something like "/owncloud/remote.php/dav/folder"
if (!parser.parse(reply()->readAll(), &_folderInfos, expectedPath)) { if (!parser.parse(reply()->readAll(), &_folderInfos, expectedPath)) {
// XML parse error // XML parse error
emit finishedWithError(reply()); emit finishedWithError(reply());
@@ -926,7 +926,10 @@ void DetermineAuthTypeJob::start()
oldFlowRequired->setIgnoreCredentialFailure(true); oldFlowRequired->setIgnoreCredentialFailure(true);
connect(get, &SimpleNetworkJob::finishedSignal, this, [this, get]() { connect(get, &SimpleNetworkJob::finishedSignal, this, [this, get]() {
if (get->reply()->error() == QNetworkReply::AuthenticationRequiredError) { const auto reply = get->reply();
const auto wwwAuthenticateHeader = reply->rawHeader("WWW-Authenticate");
if (reply->error() == QNetworkReply::AuthenticationRequiredError
&& (wwwAuthenticateHeader.startsWith("Basic") || wwwAuthenticateHeader.startsWith("Bearer"))) {
_resultGet = Basic; _resultGet = Basic;
} else { } else {
_resultGet = LoginFlowV2; _resultGet = LoginFlowV2;

View File

@@ -28,8 +28,6 @@
#include "propagatedownloadencrypted.h" #include "propagatedownloadencrypted.h"
#include "common/vfs.h" #include "common/vfs.h"
#include "configfile.h"
#include <QLoggingCategory> #include <QLoggingCategory>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QFileInfo> #include <QFileInfo>
@@ -40,11 +38,6 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
namespace {
constexpr quint16 numChecksumFailuresAllowed = 1;
constexpr char *checksumFailureDbRecordPrefix = "ChecksumValidationFailed_";
}
namespace OCC { namespace OCC {
Q_LOGGING_CATEGORY(lcGetJob, "nextcloud.sync.networkjob.get", QtInfoMsg) Q_LOGGING_CATEGORY(lcGetJob, "nextcloud.sync.networkjob.get", QtInfoMsg)
@@ -830,38 +823,8 @@ void PropagateDownloadFile::slotGetFinished()
validator->start(_tmpFile.fileName(), checksumHeader); validator->start(_tmpFile.fileName(), checksumHeader);
} }
void PropagateDownloadFile::slotChecksumFail(const QString &errMsg, const QByteArray &checksumType, const QByteArray &checksum, const QString &filePath) void PropagateDownloadFile::slotChecksumFail(const QString &errMsg)
{ {
if (!checksumType.isEmpty() && !checksum.isEmpty() && !filePath.isEmpty()) {
ConfigFile cfgFile;
if (cfgFile.allowChecksumValidationFail()) {
const auto key = QString(checksumFailureDbRecordPrefix + _item->_fileId);
const QStringList mismatchEntryForFileSplitted = propagator()->_journal->keyValueStoreGet(key).toString().split(":", QString::SkipEmptyParts);
const QByteArray mismatchChecksumForFile = mismatchEntryForFileSplitted.size() > 0 ? mismatchEntryForFileSplitted[0].toUtf8() : QByteArray();
const auto numChecksumMismatchCases = mismatchEntryForFileSplitted.size() > 1 ? mismatchEntryForFileSplitted[1].toInt() : 0;
// format must be CHECKSUM:COUNT
Q_ASSERT(mismatchEntryForFileSplitted.size() != 1);
if (mismatchEntryForFileSplitted.size() == 1) {
qCCritical(lcPropagateDownload) << "mismatchEntryForFile has incorrect format. Should be CHECKSUM:COUNT";
}
if (numChecksumMismatchCases < numChecksumFailuresAllowed || mismatchChecksumForFile != checksum) {
// not enough failures or different checksum this time
qCInfo(lcPropagateDownload) << "Checksum validation has failed" << numChecksumMismatchCases << " times, with previous checksum<" << mismatchChecksumForFile << "> and, current checksum<" << checksum << ">, but, allowChecksumValidationFail is set.Let's give it another try...";
const auto numCasesToSet = mismatchChecksumForFile != checksum ? 1 : numChecksumMismatchCases + 1;
const QString value = QString::fromUtf8(checksum) + QStringLiteral(":") + QString::number(numCasesToSet);
propagator()->_journal->keyValueStoreSet(key, value);
} else {
propagator()->_journal->keyValueStoreDelete(key);
qCInfo(lcPropagateDownload) << "Checksum validation has failed" << numChecksumMismatchCases << " times, but, allowChecksumValidationFail is set, so, let's continue...";
startContentChecksumCompute(checksumType, filePath);
return;
}
}
}
FileSystem::remove(_tmpFile.fileName()); FileSystem::remove(_tmpFile.fileName());
propagator()->_anotherSyncNeeded = true; propagator()->_anotherSyncNeeded = true;
done(SyncFileItem::SoftError, errMsg); // tr("The file downloaded with a broken checksum, will be redownloaded.")); done(SyncFileItem::SoftError, errMsg); // tr("The file downloaded with a broken checksum, will be redownloaded."));
@@ -889,18 +852,6 @@ void PropagateDownloadFile::deleteExistingFolder()
} }
} }
void PropagateDownloadFile::startContentChecksumCompute(const QByteArray &checksumType, const QString &path)
{
qCInfo(lcPropagateDownload) << "Start checksum compute with checksumType:" << checksumType << " for path:" << path;
// Compute the content checksum.
const auto computeChecksum = new ComputeChecksum(this);
computeChecksum->setChecksumType(checksumType);
connect(computeChecksum, &ComputeChecksum::done,
this, &PropagateDownloadFile::contentChecksumComputed);
computeChecksum->start(path);
}
namespace { // Anonymous namespace for the recall feature namespace { // Anonymous namespace for the recall feature
static QString makeRecallFileName(const QString &fn) static QString makeRecallFileName(const QString &fn)
{ {
@@ -989,9 +940,13 @@ void PropagateDownloadFile::transmissionChecksumValidated(const QByteArray &chec
return contentChecksumComputed(checksumType, checksum); return contentChecksumComputed(checksumType, checksum);
} }
startContentChecksumCompute(theContentChecksumType, _tmpFile.fileName()); // Compute the content checksum.
auto computeChecksum = new ComputeChecksum(this);
computeChecksum->setChecksumType(theContentChecksumType);
propagator()->_journal->keyValueStoreDelete(QString(checksumFailureDbRecordPrefix + _item->_fileId)); connect(computeChecksum, &ComputeChecksum::done,
this, &PropagateDownloadFile::contentChecksumComputed);
computeChecksum->start(_tmpFile.fileName());
} }
void PropagateDownloadFile::contentChecksumComputed(const QByteArray &checksumType, const QByteArray &checksum) void PropagateDownloadFile::contentChecksumComputed(const QByteArray &checksumType, const QByteArray &checksum)

View File

@@ -202,14 +202,12 @@ private slots:
void abort(PropagatorJob::AbortType abortType) override; void abort(PropagatorJob::AbortType abortType) override;
void slotDownloadProgress(qint64, qint64); void slotDownloadProgress(qint64, qint64);
void slotChecksumFail(const QString &errMsg, const QByteArray &checksumType, const QByteArray &checksum, const QString &filePath); void slotChecksumFail(const QString &errMsg);
private: private:
void startAfterIsEncryptedIsChecked(); void startAfterIsEncryptedIsChecked();
void deleteExistingFolder(); void deleteExistingFolder();
void startContentChecksumCompute(const QByteArray &checksumType, const QString &path);
qint64 _resumeStart; qint64 _resumeStart;
qint64 _downloadProgress; qint64 _downloadProgress;
QPointer<GETFileJob> _job; QPointer<GETFileJob> _job;

View File

@@ -76,6 +76,9 @@ void PushNotifications::closeWebSocket()
_reconnectTimer->stop(); _reconnectTimer->stop();
} }
disconnect(_webSocket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), this, &PushNotifications::onWebSocketError);
disconnect(_webSocket, &QWebSocket::sslErrors, this, &PushNotifications::onWebSocketSslErrors);
_webSocket->close(); _webSocket->close();
} }
@@ -171,6 +174,8 @@ void PushNotifications::openWebSocket()
const auto webSocketUrl = capabilities.pushNotificationsWebSocketUrl(); const auto webSocketUrl = capabilities.pushNotificationsWebSocketUrl();
qCInfo(lcPushNotifications) << "Open connection to websocket on" << webSocketUrl << "for account" << _account->url(); qCInfo(lcPushNotifications) << "Open connection to websocket on" << webSocketUrl << "for account" << _account->url();
connect(_webSocket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), this, &PushNotifications::onWebSocketError);
connect(_webSocket, &QWebSocket::sslErrors, this, &PushNotifications::onWebSocketSslErrors);
_webSocket->open(webSocketUrl); _webSocket->open(webSocketUrl);
} }

View File

@@ -799,55 +799,8 @@ void SyncEngine::slotPropagationFinished(bool success)
_anotherSyncNeeded = ImmediateFollowUp; _anotherSyncNeeded = ImmediateFollowUp;
} }
// TODO: Remove this when the file restoration problem is fixed for a user
bool shouldStartSyncAgain = false;
const auto checkAndOverrideSetDataFingerprint = [this, &shouldStartSyncAgain] {
const int dataFingerprintOverrideThreshold = 9;
const QString dataFingerprintOverrideHostHash = QStringLiteral("63debc9ef6d217649ea70632ca573a1db7a237ba61c48cdd2bf797f7060233db");
const auto accountHost = account()->url().host();
const auto accountDisplayName = account()->displayName();
if (_dataFingerprintSetFailCount >= 0) {
qCWarning(lcEngine) << "setDataFingerprint has failed for account" << accountDisplayName << "on host" << accountHost << "due to sync errors. Checking the possibility for override...";
if (_dataFingerprintSetFailCount > 0) {
if (_dataFingerprintSetFailCount >= dataFingerprintOverrideThreshold) {
qCWarning(lcEngine) << "All sync attempts failed for account" << accountDisplayName << "on host" << accountHost << "setting the dataFingerprint anyway.";
_journal->setDataFingerprint(_discoveryPhase->_dataFingerprint);
// this mechanism should only run once per app launch
_dataFingerprintSetFailCount = -1;
} else {
++_dataFingerprintSetFailCount;
// request to start sync again as it won't happen by itself unless the file has changed on the server or in the local folder
shouldStartSyncAgain = true;
}
} else {
// only compare hash once
// if it matches - we don't need to calculate it again while _dataFingerprintSetFailCount is greater than 0
const auto accountHostHash = QString::fromUtf8(QCryptographicHash::hash(accountHost.toUtf8(), QCryptographicHash::Sha256).toHex());
if (accountHostHash == dataFingerprintOverrideHostHash) {
qCInfo(lcEngine) << "accountHostHash" << accountHostHash << "equals to dataFingerprintOverrideHostHash" << dataFingerprintOverrideHostHash << "_dataFingerprintSetFailCount" << _dataFingerprintSetFailCount;
++_dataFingerprintSetFailCount;
// request to start sync again as it won't happen by itself unless the file has changed on the server or in the local folder
shouldStartSyncAgain = true;
} else {
qCInfo(lcEngine) << "accountHostHash" << accountHostHash << "differs from dataFingerprintOverrideHostHash" << dataFingerprintOverrideHostHash;
// give up on calculating the has next time, as it's not the host we are looking for
_dataFingerprintSetFailCount = -1;
}
}
} else {
qCWarning(lcEngine) << "setDataFingerprint was overridden already for account" << accountDisplayName << "on host" << accountHost << "but is failing again! Or, it's not the host that we are looking for.";
}
};
//
if (success && _discoveryPhase) { if (success && _discoveryPhase) {
_journal->setDataFingerprint(_discoveryPhase->_dataFingerprint); _journal->setDataFingerprint(_discoveryPhase->_dataFingerprint);
} else if (_discoveryPhase) {
// TODO: Remove this when the file restoration problem is fixed for a user
checkAndOverrideSetDataFingerprint();
} }
conflictRecordMaintenance(); conflictRecordMaintenance();
@@ -863,12 +816,6 @@ void SyncEngine::slotPropagationFinished(bool success)
emit transmissionProgress(*_progressInfo); emit transmissionProgress(*_progressInfo);
finalize(success); finalize(success);
if (shouldStartSyncAgain) {
// TODO: Remove this when the file restoration problem is fixed for a user
qCWarning(lcEngine) << "Starting sync again for account" << account()->displayName() << "on host" << account()->url().host() << "due to setDataFingerprint override is running.";
startSync();
}
} }
void SyncEngine::finalize(bool success) void SyncEngine::finalize(bool success)

View File

@@ -291,9 +291,6 @@ private:
LocalDiscoveryStyle _lastLocalDiscoveryStyle = LocalDiscoveryStyle::FilesystemOnly; LocalDiscoveryStyle _lastLocalDiscoveryStyle = LocalDiscoveryStyle::FilesystemOnly;
LocalDiscoveryStyle _localDiscoveryStyle = LocalDiscoveryStyle::FilesystemOnly; LocalDiscoveryStyle _localDiscoveryStyle = LocalDiscoveryStyle::FilesystemOnly;
std::set<QString> _localDiscoveryPaths; std::set<QString> _localDiscoveryPaths;
// TODO: Remove this when the file restoration problem is fixed for a user
int _dataFingerprintSetFailCount = 0;
}; };
} }

View File

@@ -643,16 +643,6 @@ bool Theme::wizardSelectiveSyncDefaultNothing() const
return false; return false;
} }
QString Theme::webDavPath() const
{
return QLatin1String("remote.php/webdav/");
}
QString Theme::webDavPathNonShib() const
{
return QLatin1String("remote.php/nonshib-webdav/");
}
bool Theme::linkSharing() const bool Theme::linkSharing() const
{ {
return true; return true;

View File

@@ -337,15 +337,6 @@ public:
*/ */
virtual bool wizardHideExternalStorageConfirmationCheckbox() const; virtual bool wizardHideExternalStorageConfirmationCheckbox() const;
/**
* Alternative path on the server that provides access to the webdav capabilities
*
* Attention: Make sure that this string does NOT have a leading slash and that
* it has a trailing slash, for example "remote.php/webdav/".
*/
virtual QString webDavPath() const;
virtual QString webDavPathNonShib() const;
/** /**
* @brief Sharing options * @brief Sharing options
* *

View File

@@ -75,6 +75,7 @@ endif()
nextcloud_add_benchmark(LargeSync) nextcloud_add_benchmark(LargeSync)
nextcloud_add_test(Account)
nextcloud_add_test(FolderMan) nextcloud_add_test(FolderMan)
nextcloud_add_test(RemoteWipe) nextcloud_add_test(RemoteWipe)

View File

@@ -34,18 +34,19 @@
*/ */
static const QUrl sRootUrl("owncloud://somehost/owncloud/remote.php/webdav/"); static const QUrl sRootUrl("owncloud://somehost/owncloud/remote.php/dav/");
static const QUrl sRootUrl2("owncloud://somehost/owncloud/remote.php/dav/files/admin/"); static const QUrl sRootUrl2("owncloud://somehost/owncloud/remote.php/dav/files/admin/");
static const QUrl sUploadUrl("owncloud://somehost/owncloud/remote.php/dav/uploads/admin/"); static const QUrl sUploadUrl("owncloud://somehost/owncloud/remote.php/dav/uploads/admin/");
inline QString getFilePathFromUrl(const QUrl &url) { inline QString getFilePathFromUrl(const QUrl &url)
{
QString path = url.path(); QString path = url.path();
if (path.startsWith(sRootUrl.path()))
return path.mid(sRootUrl.path().length());
if (path.startsWith(sRootUrl2.path())) if (path.startsWith(sRootUrl2.path()))
return path.mid(sRootUrl2.path().length()); return path.mid(sRootUrl2.path().length());
if (path.startsWith(sUploadUrl.path())) if (path.startsWith(sUploadUrl.path()))
return path.mid(sUploadUrl.path().length()); return path.mid(sUploadUrl.path().length());
if (path.startsWith(sRootUrl.path()))
return path.mid(sRootUrl.path().length());
return {}; return {};
} }

34
test/testaccount.cpp Normal file
View File

@@ -0,0 +1,34 @@
/*
* 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 "common/utility.h"
#include "folderman.h"
#include "account.h"
#include "accountstate.h"
#include "configfile.h"
#include "testhelper.h"
using namespace OCC;
class TestAccount: public QObject
{
Q_OBJECT
private slots:
void testAccountDavPath_unitialized_noCrash()
{
AccountPtr account = Account::create();
account->davPath();
}
};
QTEST_APPLESS_MAIN(TestAccount)
#include "testaccount.moc"

View File

@@ -214,10 +214,11 @@ private slots:
if (verb == "PROPFIND") { if (verb == "PROPFIND") {
auto data = stream->readAll(); auto data = stream->readAll();
if (data.contains("data-fingerprint")) { if (data.contains("data-fingerprint")) {
if (request.url().path().endsWith("webdav/")) if (request.url().path().endsWith("dav/files/admin/")) {
++fingerprintRequests; ++fingerprintRequests;
else } else {
fingerprintRequests = -10000; // fingerprint queried on incorrect path fingerprintRequests = -10000; // fingerprint queried on incorrect path
}
} }
} }
return nullptr; return nullptr;

View File

@@ -42,7 +42,8 @@ using namespace OCC::Utility;
_successDown = true; _successDown = true;
} }
void slotDownError(const QString &errMsg, const QByteArray&, const QByteArray&, const QString&) { void slotDownError(const QString &errMsg)
{
QCOMPARE(_expectedError, errMsg); QCOMPARE(_expectedError, errMsg);
_errorSeen = true; _errorSeen = true;
} }

View File

@@ -57,6 +57,12 @@ private slots:
QVERIFY(folderman->addFolder(newAccountState.data(), folderDefinition(dirPath + "/sub/ownCloud1"))); QVERIFY(folderman->addFolder(newAccountState.data(), folderDefinition(dirPath + "/sub/ownCloud1")));
QVERIFY(folderman->addFolder(newAccountState.data(), folderDefinition(dirPath + "/ownCloud2"))); QVERIFY(folderman->addFolder(newAccountState.data(), folderDefinition(dirPath + "/ownCloud2")));
const auto folderList = folderman->map();
for (const auto &folder : folderList) {
QVERIFY(!folder->isSyncRunning());
}
// those should be allowed // those should be allowed
// QString FolderMan::checkPathValidityForNewFolder(const QString& path, const QUrl &serverUrl, bool forNewDirectory) // QString FolderMan::checkPathValidityForNewFolder(const QString& path, const QUrl &serverUrl, bool forNewDirectory)

View File

@@ -91,7 +91,7 @@ private slots:
auto oldLocalState = fakeFolder.currentLocalState(); auto oldLocalState = fakeFolder.currentLocalState();
auto oldRemoteState = fakeFolder.currentRemoteState(); auto oldRemoteState = fakeFolder.currentRemoteState();
QString errorFolder = "webdav/B"; QString errorFolder = "dav/files/admin/B";
QString fatalErrorPrefix = "Server replied with an error while reading directory 'B' : "; QString fatalErrorPrefix = "Server replied with an error while reading directory 'B' : ";
fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *) fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *)
-> QNetworkReply *{ -> QNetworkReply *{
@@ -133,7 +133,7 @@ private slots:
// //
// Check the same discovery error on the sync root // Check the same discovery error on the sync root
// //
errorFolder = "webdav/"; errorFolder = "dav/files/admin/";
fatalErrorPrefix = "Server replied with an error while reading directory '' : "; fatalErrorPrefix = "Server replied with an error while reading directory '' : ";
errorSpy.clear(); errorSpy.clear();
QVERIFY(!fakeFolder.syncOnce()); QVERIFY(!fakeFolder.syncOnce());

View File

@@ -53,7 +53,7 @@ private slots:
const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>" const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>"
"<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">" "<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
"<d:response>" "<d:response>"
"<d:href>/oc/remote.php/webdav/sharefolder/</d:href>" "<d:href>/oc/remote.php/dav/sharefolder/</d:href>"
"<d:propstat>" "<d:propstat>"
"<d:prop>" "<d:prop>"
"<oc:id>00004213ocobzus5kn6s</oc:id>" "<oc:id>00004213ocobzus5kn6s</oc:id>"
@@ -77,7 +77,7 @@ private slots:
"</d:propstat>" "</d:propstat>"
"</d:response>" "</d:response>"
"<d:response>" "<d:response>"
"<d:href>/oc/remote.php/webdav/sharefolder/quitte.pdf</d:href>" "<d:href>/oc/remote.php/dav/sharefolder/quitte.pdf</d:href>"
"<d:propstat>" "<d:propstat>"
"<d:prop>" "<d:prop>"
"<oc:id>00004215ocobzus5kn6s</oc:id>" "<oc:id>00004215ocobzus5kn6s</oc:id>"
@@ -110,16 +110,16 @@ private slots:
this, SLOT(slotFinishedSuccessfully()) ); this, SLOT(slotFinishedSuccessfully()) );
QHash <QString, ExtraFolderInfo> sizes; QHash <QString, ExtraFolderInfo> sizes;
QVERIFY(parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); QVERIFY(parser.parse( testXml, &sizes, "/oc/remote.php/dav/sharefolder" ));
QVERIFY(_success); QVERIFY(_success);
QCOMPARE(sizes.size(), 1 ); // Quota info in the XML QCOMPARE(sizes.size(), 1 ); // Quota info in the XML
QVERIFY(_items.contains("/oc/remote.php/webdav/sharefolder/quitte.pdf")); QVERIFY(_items.contains("/oc/remote.php/dav/sharefolder/quitte.pdf"));
QVERIFY(_items.contains("/oc/remote.php/webdav/sharefolder")); QVERIFY(_items.contains("/oc/remote.php/dav/sharefolder"));
QVERIFY(_items.size() == 2 ); QVERIFY(_items.size() == 2 );
QVERIFY(_subdirs.contains("/oc/remote.php/webdav/sharefolder/")); QVERIFY(_subdirs.contains("/oc/remote.php/dav/sharefolder/"));
QVERIFY(_subdirs.size() == 1); QVERIFY(_subdirs.size() == 1);
} }
@@ -127,7 +127,7 @@ private slots:
const QByteArray testXml = "X<?xml version='1.0' encoding='utf-8'?>" const QByteArray testXml = "X<?xml version='1.0' encoding='utf-8'?>"
"<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">" "<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
"<d:response>" "<d:response>"
"<d:href>/oc/remote.php/webdav/sharefolder/</d:href>" "<d:href>/oc/remote.php/dav/sharefolder/</d:href>"
"<d:propstat>" "<d:propstat>"
"<d:prop>" "<d:prop>"
"<oc:id>00004213ocobzus5kn6s</oc:id>" "<oc:id>00004213ocobzus5kn6s</oc:id>"
@@ -151,7 +151,7 @@ private slots:
"</d:propstat>" "</d:propstat>"
"</d:response>" "</d:response>"
"<d:response>" "<d:response>"
"<d:href>/oc/remote.php/webdav/sharefolder/quitte.pdf</d:href>" "<d:href>/oc/remote.php/dav/sharefolder/quitte.pdf</d:href>"
"<d:propstat>" "<d:propstat>"
"<d:prop>" "<d:prop>"
"<oc:id>00004215ocobzus5kn6s</oc:id>" "<oc:id>00004215ocobzus5kn6s</oc:id>"
@@ -184,7 +184,7 @@ private slots:
this, SLOT(slotFinishedSuccessfully()) ); this, SLOT(slotFinishedSuccessfully()) );
QHash <QString, ExtraFolderInfo> sizes; QHash <QString, ExtraFolderInfo> sizes;
QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); // verify false QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/dav/sharefolder" )); // verify false
QVERIFY(!_success); QVERIFY(!_success);
QVERIFY(sizes.size() == 0 ); // No quota info in the XML QVERIFY(sizes.size() == 0 ); // No quota info in the XML
@@ -207,7 +207,7 @@ private slots:
this, SLOT(slotFinishedSuccessfully()) ); this, SLOT(slotFinishedSuccessfully()) );
QHash <QString, ExtraFolderInfo> sizes; QHash <QString, ExtraFolderInfo> sizes;
QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); // verify false QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/dav/sharefolder" )); // verify false
QVERIFY(!_success); QVERIFY(!_success);
QVERIFY(sizes.size() == 0 ); // No quota info in the XML QVERIFY(sizes.size() == 0 ); // No quota info in the XML
@@ -229,7 +229,7 @@ private slots:
this, SLOT(slotFinishedSuccessfully()) ); this, SLOT(slotFinishedSuccessfully()) );
QHash <QString, ExtraFolderInfo> sizes; QHash <QString, ExtraFolderInfo> sizes;
QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); // verify false QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/dav/sharefolder" )); // verify false
QVERIFY(!_success); QVERIFY(!_success);
QVERIFY(sizes.size() == 0 ); // No quota info in the XML QVERIFY(sizes.size() == 0 ); // No quota info in the XML
@@ -242,7 +242,7 @@ private slots:
const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>" const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>"
"<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">" "<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
"<d:response>" "<d:response>"
"<d:href>/oc/remote.php/webdav/sharefolder/</d:href>" "<d:href>/oc/remote.php/dav/sharefolder/</d:href>"
"<d:propstat>" "<d:propstat>"
"<d:prop>" "<d:prop>"
"<oc:id>00004213ocobzus5kn6s</oc:id>" "<oc:id>00004213ocobzus5kn6s</oc:id>"
@@ -268,7 +268,7 @@ private slots:
this, SLOT(slotFinishedSuccessfully()) ); this, SLOT(slotFinishedSuccessfully()) );
QHash <QString, ExtraFolderInfo> sizes; QHash <QString, ExtraFolderInfo> sizes;
QVERIFY(!parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); QVERIFY(!parser.parse( testXml, &sizes, "/oc/remote.php/dav/sharefolder" ));
QVERIFY(!_success); QVERIFY(!_success);
} }
@@ -276,7 +276,7 @@ private slots:
const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>" const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>"
"<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">" "<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
"<d:response>" "<d:response>"
"<d:href>http://127.0.0.1:81/oc/remote.php/webdav/sharefolder/</d:href>" "<d:href>http://127.0.0.1:81/oc/remote.php/dav/sharefolder/</d:href>"
"<d:propstat>" "<d:propstat>"
"<d:prop>" "<d:prop>"
"<oc:id>00004213ocobzus5kn6s</oc:id>" "<oc:id>00004213ocobzus5kn6s</oc:id>"
@@ -300,7 +300,7 @@ private slots:
"</d:propstat>" "</d:propstat>"
"</d:response>" "</d:response>"
"<d:response>" "<d:response>"
"<d:href>http://127.0.0.1:81/oc/remote.php/webdav/sharefolder/quitte.pdf</d:href>" "<d:href>http://127.0.0.1:81/oc/remote.php/dav/sharefolder/quitte.pdf</d:href>"
"<d:propstat>" "<d:propstat>"
"<d:prop>" "<d:prop>"
"<oc:id>00004215ocobzus5kn6s</oc:id>" "<oc:id>00004215ocobzus5kn6s</oc:id>"
@@ -333,7 +333,7 @@ private slots:
this, SLOT(slotFinishedSuccessfully()) ); this, SLOT(slotFinishedSuccessfully()) );
QHash <QString, ExtraFolderInfo> sizes; QHash <QString, ExtraFolderInfo> sizes;
QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/dav/sharefolder" ));
QVERIFY(!_success); QVERIFY(!_success);
} }
@@ -398,7 +398,7 @@ private slots:
this, SLOT(slotFinishedSuccessfully()) ); this, SLOT(slotFinishedSuccessfully()) );
QHash <QString, ExtraFolderInfo> sizes; QHash <QString, ExtraFolderInfo> sizes;
QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); QVERIFY(false == parser.parse( testXml, &sizes, "/oc/remote.php/dav/sharefolder" ));
QVERIFY(!_success); QVERIFY(!_success);
} }
@@ -406,7 +406,7 @@ private slots:
const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>" const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>"
"<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">" "<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
"<d:response>" "<d:response>"
"<d:href>/oc/remote.php/webdav/sharefolder/</d:href>" "<d:href>/oc/remote.php/dav/sharefolder/</d:href>"
"<d:propstat>" "<d:propstat>"
"<d:prop>" "<d:prop>"
"<oc:id>00004213ocobzus5kn6s</oc:id>" "<oc:id>00004213ocobzus5kn6s</oc:id>"
@@ -430,7 +430,7 @@ private slots:
"</d:propstat>" "</d:propstat>"
"</d:response>" "</d:response>"
"<d:response>" "<d:response>"
"<d:href>/oc/remote.php/webdav/sharefolder/../sharefolder/quitte.pdf</d:href>" "<d:href>/oc/remote.php/dav/sharefolder/../sharefolder/quitte.pdf</d:href>"
"<d:propstat>" "<d:propstat>"
"<d:prop>" "<d:prop>"
"<oc:id>00004215ocobzus5kn6s</oc:id>" "<oc:id>00004215ocobzus5kn6s</oc:id>"
@@ -463,16 +463,16 @@ private slots:
this, SLOT(slotFinishedSuccessfully()) ); this, SLOT(slotFinishedSuccessfully()) );
QHash <QString, ExtraFolderInfo> sizes; QHash <QString, ExtraFolderInfo> sizes;
QVERIFY(parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); QVERIFY(parser.parse( testXml, &sizes, "/oc/remote.php/dav/sharefolder" ));
QVERIFY(_success); QVERIFY(_success);
QCOMPARE(sizes.size(), 1 ); // Quota info in the XML QCOMPARE(sizes.size(), 1 ); // Quota info in the XML
QVERIFY(_items.contains("/oc/remote.php/webdav/sharefolder/quitte.pdf")); QVERIFY(_items.contains("/oc/remote.php/dav/sharefolder/quitte.pdf"));
QVERIFY(_items.contains("/oc/remote.php/webdav/sharefolder")); QVERIFY(_items.contains("/oc/remote.php/dav/sharefolder"));
QVERIFY(_items.size() == 2 ); QVERIFY(_items.size() == 2 );
QVERIFY(_subdirs.contains("/oc/remote.php/webdav/sharefolder/")); QVERIFY(_subdirs.contains("/oc/remote.php/dav/sharefolder/"));
QVERIFY(_subdirs.size() == 1); QVERIFY(_subdirs.size() == 1);
} }
@@ -480,7 +480,7 @@ private slots:
const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>" const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>"
"<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">" "<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
"<d:response>" "<d:response>"
"<d:href>/oc/remote.php/webdav/sharefolder/</d:href>" "<d:href>/oc/remote.php/dav/sharefolder/</d:href>"
"<d:propstat>" "<d:propstat>"
"<d:prop>" "<d:prop>"
"<oc:id>00004213ocobzus5kn6s</oc:id>" "<oc:id>00004213ocobzus5kn6s</oc:id>"
@@ -504,7 +504,7 @@ private slots:
"</d:propstat>" "</d:propstat>"
"</d:response>" "</d:response>"
"<d:response>" "<d:response>"
"<d:href>/oc/remote.php/webdav/sharefolder/../quitte.pdf</d:href>" "<d:href>/oc/remote.php/dav/sharefolder/../quitte.pdf</d:href>"
"<d:propstat>" "<d:propstat>"
"<d:prop>" "<d:prop>"
"<oc:id>00004215ocobzus5kn6s</oc:id>" "<oc:id>00004215ocobzus5kn6s</oc:id>"
@@ -537,7 +537,7 @@ private slots:
this, SLOT(slotFinishedSuccessfully()) ); this, SLOT(slotFinishedSuccessfully()) );
QHash <QString, ExtraFolderInfo> sizes; QHash <QString, ExtraFolderInfo> sizes;
QVERIFY(!parser.parse( testXml, &sizes, "/oc/remote.php/webdav/sharefolder" )); QVERIFY(!parser.parse( testXml, &sizes, "/oc/remote.php/dav/sharefolder" ));
QVERIFY(!_success); QVERIFY(!_success);
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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