mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2026-04-03 09:11:33 +02:00
Compare commits
486 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f4ffd0f72 | ||
|
|
e6b06d0a6b | ||
|
|
e160788204 | ||
|
|
f5d4ac518f | ||
|
|
31d3ce7663 | ||
|
|
9266ecc2e8 | ||
|
|
14105d4ec6 | ||
|
|
6e8658dc2c | ||
|
|
1d7b7c26d3 | ||
|
|
b2dfa29325 | ||
|
|
09c2279bb5 | ||
|
|
4886525e08 | ||
|
|
f2fd083898 | ||
|
|
8a2eb71c4f | ||
|
|
8e29935195 | ||
|
|
5517ff2c02 | ||
|
|
bd959018a1 | ||
|
|
a527e85fe6 | ||
|
|
f04281cb69 | ||
|
|
7721832ee0 | ||
|
|
f9991e180c | ||
|
|
bc38c0ba3f | ||
|
|
9ff8d97647 | ||
|
|
62bf777cda | ||
|
|
3d9d5f2fe7 | ||
|
|
57e1f2ac07 | ||
|
|
0fdb423fe0 | ||
|
|
7bfd8ea23c | ||
|
|
57a4cd926d | ||
|
|
de4edb6099 | ||
|
|
70dbbbeaa4 | ||
|
|
9614d051a5 | ||
|
|
8d1fe8ed3c | ||
|
|
4d133ba9a5 | ||
|
|
bdd3465e7b | ||
|
|
998e93ac13 | ||
|
|
820ab12561 | ||
|
|
c38189e981 | ||
|
|
a50c665051 | ||
|
|
6962cbf582 | ||
|
|
60d3696ccd | ||
|
|
c4987aa641 | ||
|
|
104d3c0661 | ||
|
|
4906353f2e | ||
|
|
038644f378 | ||
|
|
d30cd0f0fd | ||
|
|
c76095859a | ||
|
|
a7f010c370 | ||
|
|
1bf895cadc | ||
|
|
c58f00abc7 | ||
|
|
1df3f5b6df | ||
|
|
1aca005267 | ||
|
|
9a375211d7 | ||
|
|
d2991210c5 | ||
|
|
aa7409f401 | ||
|
|
0b3512f49c | ||
|
|
9596eb7f20 | ||
|
|
f2c3ef741b | ||
|
|
ae38b88d1c | ||
|
|
e93972824d | ||
|
|
5e518419de | ||
|
|
d069fda9ab | ||
|
|
dfac8c0e59 | ||
|
|
ed0dc68db2 | ||
|
|
08b5981fb6 | ||
|
|
412e43b696 | ||
|
|
4b39731c27 | ||
|
|
311e3a3bd8 | ||
|
|
a8ad946758 | ||
|
|
65035d1990 | ||
|
|
c24b81c081 | ||
|
|
08014b6dc3 | ||
|
|
5a432a193f | ||
|
|
28e4fc54a1 | ||
|
|
e97fc430bf | ||
|
|
74382ddcc0 | ||
|
|
21b931dc6b | ||
|
|
351bada552 | ||
|
|
fe29290564 | ||
|
|
29ca1404cc | ||
|
|
d4c14f8f4f | ||
|
|
92733e9069 | ||
|
|
2aa3d17e5c | ||
|
|
7cf3f14f78 | ||
|
|
922b322337 | ||
|
|
f530758f78 | ||
|
|
665a8c4217 | ||
|
|
10cb0a71eb | ||
|
|
e6ea3878a9 | ||
|
|
8faa103ebf | ||
|
|
d0004230b9 | ||
|
|
44f2bc24ff | ||
|
|
6f25840ec9 | ||
|
|
1950efcfff | ||
|
|
d026aa9301 | ||
|
|
0d7865e6f8 | ||
|
|
fa1f20ca8e | ||
|
|
771bac2279 | ||
|
|
ebcdb41fb9 | ||
|
|
d2e0959b47 | ||
|
|
2316cb6ce4 | ||
|
|
f66b091e12 | ||
|
|
00a47fefaf | ||
|
|
4f7876f520 | ||
|
|
0b731eb516 | ||
|
|
1b553b93b9 | ||
|
|
cebd39aa85 | ||
|
|
2e97a7fb74 | ||
|
|
6c463442ef | ||
|
|
1288ee0437 | ||
|
|
3ffc699058 | ||
|
|
95487d8bfc | ||
|
|
863db075eb | ||
|
|
e69b26e363 | ||
|
|
4382193519 | ||
|
|
7a093592a0 | ||
|
|
942d8ba86a | ||
|
|
9f9bcecd31 | ||
|
|
46aba0832d | ||
|
|
86d240f7b4 | ||
|
|
6445a61d80 | ||
|
|
3749fe15b6 | ||
|
|
50e038cfaa | ||
|
|
44a55674ac | ||
|
|
0e617d020f | ||
|
|
3427dadaeb | ||
|
|
dfd6cce978 | ||
|
|
5a8c2bab89 | ||
|
|
a14930c293 | ||
|
|
a3914482d7 | ||
|
|
56d067d7a9 | ||
|
|
18c1bc0bd6 | ||
|
|
ef86d4b738 | ||
|
|
a74861dbb5 | ||
|
|
9593cea18c | ||
|
|
3e6b257ccd | ||
|
|
d17c9af044 | ||
|
|
204cced445 | ||
|
|
f116c39b0a | ||
|
|
6b794ddd5a | ||
|
|
8fad88055e | ||
|
|
1627522695 | ||
|
|
62fa8028a6 | ||
|
|
92801816e0 | ||
|
|
599cf0143f | ||
|
|
38205cab68 | ||
|
|
fa8f37e987 | ||
|
|
2bcc99792d | ||
|
|
24964e2b9b | ||
|
|
802d27ed0f | ||
|
|
b835092ae9 | ||
|
|
4116c90c9c | ||
|
|
910f0c9339 | ||
|
|
c42f4abd25 | ||
|
|
e3b97b0a04 | ||
|
|
49c478cd2a | ||
|
|
67e81fcd0f | ||
|
|
4fdb203cdb | ||
|
|
26d62a9712 | ||
|
|
00e901f5a7 | ||
|
|
f62be57ef2 | ||
|
|
e70371f408 | ||
|
|
b982a17998 | ||
|
|
7699004a11 | ||
|
|
0fb10163a3 | ||
|
|
40aa53bf76 | ||
|
|
bb43127633 | ||
|
|
c6c2d4cf4c | ||
|
|
a2e3f9d63a | ||
|
|
7536e4c00b | ||
|
|
de63e5e221 | ||
|
|
0e9efe728a | ||
|
|
60da0cee25 | ||
|
|
10cb4170c7 | ||
|
|
b5fdbefb0e | ||
|
|
399b97442e | ||
|
|
cbc40b5a15 | ||
|
|
8e3ca71763 | ||
|
|
9aeb7046d2 | ||
|
|
cfb66ddadd | ||
|
|
65b90f4bb1 | ||
|
|
534f0567bf | ||
|
|
03b1c0b84a | ||
|
|
671ca522ea | ||
|
|
0927b9bc90 | ||
|
|
b7ea6530c5 | ||
|
|
ecc170decc | ||
|
|
e502e71926 | ||
|
|
3329df4caf | ||
|
|
801c77401c | ||
|
|
f6824de126 | ||
|
|
61dc4b9137 | ||
|
|
e656d67f39 | ||
|
|
38f4843582 | ||
|
|
ca57221b74 | ||
|
|
7efaa2ed68 | ||
|
|
ec945b8ac7 | ||
|
|
9ec4b5ef8e | ||
|
|
5e472e629f | ||
|
|
d0a9d21de8 | ||
|
|
e980682b4d | ||
|
|
e5b307c81f | ||
|
|
3c986ead91 | ||
|
|
206c98688e | ||
|
|
e787054d1c | ||
|
|
6f17bbe6d5 | ||
|
|
142894b2f7 | ||
|
|
f5860928d9 | ||
|
|
1d939121fc | ||
|
|
bfe9b0ba91 | ||
|
|
3148705df6 | ||
|
|
643e43dcfb | ||
|
|
a53a87a3eb | ||
|
|
fc9ceb5af9 | ||
|
|
ab67741d87 | ||
|
|
3d8af05037 | ||
|
|
836de0358d | ||
|
|
50dd715f4d | ||
|
|
d0ce8bc1ae | ||
|
|
211dbadd1a | ||
|
|
3fca307fbb | ||
|
|
8ce137cc53 | ||
|
|
8fb673457b | ||
|
|
15d294e7fb | ||
|
|
607347289e | ||
|
|
167800320f | ||
|
|
b0a38816fc | ||
|
|
f90ae66d94 | ||
|
|
e78312f094 | ||
|
|
099d25a56c | ||
|
|
e356acbcee | ||
|
|
d6f53d66f4 | ||
|
|
a2a58eefde | ||
|
|
36002701ed | ||
|
|
f39542688a | ||
|
|
01152d3f37 | ||
|
|
b552c77128 | ||
|
|
ce279d0bbd | ||
|
|
c5ff288b37 | ||
|
|
2476dcb425 | ||
|
|
bf6980d31a | ||
|
|
8e48d53b04 | ||
|
|
0e5d9a5a6b | ||
|
|
d1c0481338 | ||
|
|
06177b1a7c | ||
|
|
ebe7cbf0ed | ||
|
|
a0b351b145 | ||
|
|
bb30633d31 | ||
|
|
5979ae30e1 | ||
|
|
4b985ab3b3 | ||
|
|
5467909389 | ||
|
|
ef6773bd60 | ||
|
|
c1feecc727 | ||
|
|
fbeba931d2 | ||
|
|
ce2dec0194 | ||
|
|
48524fc1f4 | ||
|
|
954544830d | ||
|
|
2cb919a684 | ||
|
|
6569ecbd27 | ||
|
|
7721da25e5 | ||
|
|
061ef027ff | ||
|
|
074a94ceb9 | ||
|
|
62bf4c5fda | ||
|
|
677997b2b3 | ||
|
|
5bd2529ca6 | ||
|
|
e343b4b947 | ||
|
|
225fdabf6a | ||
|
|
1898782781 | ||
|
|
5f4cec870b | ||
|
|
1b1975e01d | ||
|
|
dc12cdf196 | ||
|
|
d2eb24a9a8 | ||
|
|
b9873cac63 | ||
|
|
d50ad548d2 | ||
|
|
68ba07a45a | ||
|
|
10b23200ab | ||
|
|
b96b7e20c7 | ||
|
|
1053c58b0f | ||
|
|
8abe4219a5 | ||
|
|
a69898371f | ||
|
|
a4151d71bc | ||
|
|
3287ec2387 | ||
|
|
c6047e4d63 | ||
|
|
43bf703806 | ||
|
|
a7a079a335 | ||
|
|
5763e1e9d8 | ||
|
|
836638815f | ||
|
|
eefa46a8e7 | ||
|
|
d58af951f3 | ||
|
|
78a3e45456 | ||
|
|
7b1ba31c13 | ||
|
|
78b03739a7 | ||
|
|
16b709edbc | ||
|
|
a2899eba74 | ||
|
|
5fa2a13f8d | ||
|
|
dde4dd78fb | ||
|
|
ce71ffe9f9 | ||
|
|
122493eeeb | ||
|
|
3ca6f4b0f2 | ||
|
|
b72bfb5c65 | ||
|
|
e024aa3f16 | ||
|
|
a9014f9852 | ||
|
|
f321cd8ae6 | ||
|
|
68776fe319 | ||
|
|
fc365df5de | ||
|
|
fad9b2c969 | ||
|
|
58b88de936 | ||
|
|
3a53afd704 | ||
|
|
c127052f2d | ||
|
|
ed972a0e3f | ||
|
|
5d7e1b6a69 | ||
|
|
0f2784107c | ||
|
|
3171cb2720 | ||
|
|
f451e1d2d5 | ||
|
|
9c5a51bb07 | ||
|
|
091c805f9e | ||
|
|
54364e7374 | ||
|
|
f8f3190cb4 | ||
|
|
ed3eb1ac9c | ||
|
|
61a74e67c9 | ||
|
|
d09b0284dd | ||
|
|
5eba2e9163 | ||
|
|
0e1e3a29ce | ||
|
|
7f5b7f637c | ||
|
|
dbe8422c5d | ||
|
|
9d05bc0a8b | ||
|
|
f3c2632f8c | ||
|
|
16dda17334 | ||
|
|
63c3580755 | ||
|
|
8aaa533a3e | ||
|
|
797df2b5d5 | ||
|
|
14993d4de6 | ||
|
|
6ee37b5975 | ||
|
|
f7efe6a902 | ||
|
|
eb0cedebfa | ||
|
|
4f5d707e44 | ||
|
|
7ccb016397 | ||
|
|
54b09a1fbb | ||
|
|
9d3a905cc5 | ||
|
|
88a573a643 | ||
|
|
01986df8ca | ||
|
|
9ab256b4b4 | ||
|
|
95f634ce28 | ||
|
|
c1086c9886 | ||
|
|
a432501d80 | ||
|
|
301a926f4d | ||
|
|
9822079cae | ||
|
|
528fa92e86 | ||
|
|
1444500f77 | ||
|
|
e2737b5067 | ||
|
|
f931bc832c | ||
|
|
fdb35e5f9f | ||
|
|
de3ba2721b | ||
|
|
0f03e3091d | ||
|
|
fecc62b7e1 | ||
|
|
5adb720630 | ||
|
|
a61dd7cf46 | ||
|
|
2db125dca0 | ||
|
|
6c69ac6602 | ||
|
|
a4cb7e3040 | ||
|
|
3077a1378b | ||
|
|
fd29a0ae57 | ||
|
|
18b16a3ede | ||
|
|
ee92e5af9a | ||
|
|
2916144fe3 | ||
|
|
c7c37f9bef | ||
|
|
9a0713fab7 | ||
|
|
f323f8b4bc | ||
|
|
9ec4e772eb | ||
|
|
b6591be973 | ||
|
|
310693be2c | ||
|
|
aa63889e5b | ||
|
|
0909f00a8b | ||
|
|
80cc196f6f | ||
|
|
5cec1373ad | ||
|
|
608bf025e6 | ||
|
|
c8ea848596 | ||
|
|
4cb9bec23a | ||
|
|
4e61181b45 | ||
|
|
4ee80bfe2e | ||
|
|
eb76682b1e | ||
|
|
1a0945a973 | ||
|
|
7236af78af | ||
|
|
b01299349b | ||
|
|
78fa448c7e | ||
|
|
75aa94be79 | ||
|
|
01a722821a | ||
|
|
e45be65996 | ||
|
|
1f536a7e1b | ||
|
|
5945f18d5a | ||
|
|
bd519ffe7a | ||
|
|
e973c43a7a | ||
|
|
24a2b21c2c | ||
|
|
07bde18c3a | ||
|
|
b20ea25201 | ||
|
|
af1bb7e98c | ||
|
|
c1cb3e6c49 | ||
|
|
cbea02390e | ||
|
|
c4b87cd465 | ||
|
|
c746e65a8e | ||
|
|
6c36041829 | ||
|
|
c687fb0291 | ||
|
|
d4183aebb3 | ||
|
|
7af6e18491 | ||
|
|
5b8ec5cede | ||
|
|
cd303e313d | ||
|
|
32880507b2 | ||
|
|
b60239c29e | ||
|
|
4df8db4ff6 | ||
|
|
db05f65e0d | ||
|
|
11632da7ea | ||
|
|
0ba5df597f | ||
|
|
8ce13b7bdb | ||
|
|
4675869fb3 | ||
|
|
bfd7707ff4 | ||
|
|
34e9e2f288 | ||
|
|
6c9a31f6ee | ||
|
|
13d4b91935 | ||
|
|
e4b53b12e1 | ||
|
|
906556640d | ||
|
|
77cc262337 | ||
|
|
6274462036 | ||
|
|
c6fc46aa09 | ||
|
|
d446431804 | ||
|
|
ed5e9de9f6 | ||
|
|
07388e0f22 | ||
|
|
b67c61bf4a | ||
|
|
d6cc9fe829 | ||
|
|
3540f1e460 | ||
|
|
71fbc65eb0 | ||
|
|
f6e36523d2 | ||
|
|
2456f943af | ||
|
|
c8b6bc6029 | ||
|
|
60ce985828 | ||
|
|
770e3e7b85 | ||
|
|
387df7ae71 | ||
|
|
2e69680812 | ||
|
|
89d4b6e12a | ||
|
|
74c1710ed4 | ||
|
|
4117ac2913 | ||
|
|
ef6d2600ca | ||
|
|
a7847a4e82 | ||
|
|
c2324327ef | ||
|
|
c74c0d8e6e | ||
|
|
2684ba149e | ||
|
|
866ffc2a6b | ||
|
|
a5b4922a0e | ||
|
|
0e2af4b502 | ||
|
|
2f8c29082a | ||
|
|
2d4d66b998 | ||
|
|
cdf6e7d72b | ||
|
|
3ff899cff9 | ||
|
|
6ae1d0ddf6 | ||
|
|
97af14a4f0 | ||
|
|
d58ec4bf70 | ||
|
|
7bb54e34d7 | ||
|
|
07b7753216 | ||
|
|
1767c0295f | ||
|
|
3e79e1861b | ||
|
|
c50a968a1e | ||
|
|
ed1c2eaab4 | ||
|
|
14bfa5025f | ||
|
|
571e15c6eb | ||
|
|
5116f4d255 | ||
|
|
db5c186202 | ||
|
|
725f1e742d | ||
|
|
6da67ef653 | ||
|
|
65407483e5 | ||
|
|
1e8340cd48 | ||
|
|
9016ffe4b7 | ||
|
|
be6a9dab01 | ||
|
|
d264f7078b | ||
|
|
c3cd06ddad | ||
|
|
c5343e10f5 | ||
|
|
37e20698ca | ||
|
|
a1dbfd71cb | ||
|
|
d08c160b69 | ||
|
|
ef3c516598 | ||
|
|
595eb78c8a | ||
|
|
d5339265fb | ||
|
|
54a19945fd | ||
|
|
26b88131cc | ||
|
|
aac1f2ae56 | ||
|
|
7e2c3b2516 | ||
|
|
a813602124 | ||
|
|
53f346fa9b |
23
.clang-tidy
23
.clang-tidy
@@ -1,22 +1,45 @@
|
||||
Checks: '-*,
|
||||
bugprone-*,
|
||||
-bugprone-forward-declaration-namespace,
|
||||
cppcoreguidelines-init-variables,
|
||||
misc-*,
|
||||
-misc-non-private-member-variables-in-classes,
|
||||
modernize-avoid-bind,
|
||||
modernize-concat-nested-namespaces,
|
||||
modernize-deprecated-headers,
|
||||
modernize-deprecated-ios-base-aliases,
|
||||
modernize-loop-convert,
|
||||
modernize-make-*,
|
||||
modernize-raw-string-literal,
|
||||
modernize-redundant-void-arg,
|
||||
modernize-replace-*,
|
||||
modernize-return-braced-init-list,
|
||||
modernize-shrink-to-fit,
|
||||
modernize-unary-static-assert,
|
||||
modernize-use-auto,
|
||||
modernize-use-bool-literals,
|
||||
modernize-use-default-member-init,
|
||||
modernize-use-emplace,
|
||||
modernize-use-equals-delete,
|
||||
modernize-use-nodiscard,
|
||||
modernize-use-equals-default,
|
||||
modernize-use-noexcept,
|
||||
modernize-user-override,
|
||||
modernize-use-nullptr,
|
||||
modernize-use-transparent-functors,
|
||||
modernize-use-uncaught-exceptions,
|
||||
modernize-use-using,
|
||||
'
|
||||
WarningsAsErrors: '*'
|
||||
HeaderFilterRegex: '.*'
|
||||
AnalyzeTemporaryDtors: false
|
||||
FormatStyle: none
|
||||
CheckOptions:
|
||||
- key: bugprone-assert-side-effect.AssertMacros
|
||||
value: 'assert;Q_ASSERT'
|
||||
- key: bugprone-dangling-handle.HandleClasses
|
||||
value: 'std::basic_string_view;std::experimental::basic_string_view;QStringView'
|
||||
- key: bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression
|
||||
value: 1
|
||||
- key: modernize-use-default-member-init.UseAssignment
|
||||
value: 1
|
||||
|
||||
@@ -122,7 +122,7 @@ steps:
|
||||
- name: build
|
||||
image: nextcloudci/client-debian-ci:client-debian-ci-2
|
||||
commands:
|
||||
- /bin/bash -c "./admin/linux/debian/drone-build.sh"
|
||||
- /bin/bash -c "./admin/linux/debian/drone-build.sh" || echo "[WARNING] Debian build failed but this is a non-blocking CI event"
|
||||
environment:
|
||||
DEBIAN_SECRET_KEY:
|
||||
from_secret: DEBIAN_SECRET_KEY
|
||||
|
||||
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
@@ -1,3 +0,0 @@
|
||||
|
||||
# You can add one username per supported platform and one custom link
|
||||
custom: https://www.bountysource.com/teams/nextcloud/issues?tracker_ids=74294474
|
||||
47
.github/issue_template.md
vendored
47
.github/issue_template.md
vendored
@@ -1,20 +1,41 @@
|
||||
<!--
|
||||
Dear user,
|
||||
Please understand that at the moment, we are very busy with customer issues
|
||||
and some high priority development work. A lot of issues are getting reported.
|
||||
Right now we can't keep up and timely respond to all of them.
|
||||
We're sorry for that and are expanding our team, if you're looking for a C++
|
||||
job or know somebody who is, please point them to https://nextcloud.com/jobs
|
||||
Don't forget that Github is not a support system or a place to ask for
|
||||
features but only a place to report verified bugs - see nextcloud.com/support
|
||||
for support options!
|
||||
Thanks for reporting issues back to Nextcloud!
|
||||
|
||||
Note: This is the **issue tracker of Nextcloud**, please do NOT use this to get answers to your questions or get help for fixing your installation. This is a place to report bugs to developers, after your server has been debugged. You can find help debugging your system on our home user forums: https://help.nextcloud.com or, if you use Nextcloud in a large organization, ask our engineers on https://portal.nextcloud.com. See also https://nextcloud.com/support for support options.
|
||||
|
||||
Nextcloud is an open source project backed by Nextcloud GmbH. Most of our volunteers are home users and thus primarily care about issues that affect home users. Our paid engineers prioritize issues of our customers. If you are neither a home user nor a customer, consider paying somebody to fix your issue, do it yourself or become a customer.
|
||||
|
||||
Please understand that at the moment, we are very busy with customer issues and some high priority development work. A lot of issues are getting reported. We can't always keep up and timely respond to all of them, but we try!
|
||||
|
||||
Guidelines for submitting issues:
|
||||
|
||||
* Please search the existing issues first, it's likely that your issue was already reported or even fixed.
|
||||
- Go to https://github.com/nextcloud and type any word in the top search/command bar. You probably see something like "We couldn’t find any repositories matching ..." then click "Issues" in the left navigation.
|
||||
- You can also filter by appending e. g. "state:open" to the search string.
|
||||
- More info on search syntax within github: https://help.github.com/articles/searching-issues
|
||||
|
||||
* Please fill in as much of the template below as possible. We know it is a pain sometimes, but especially without logs there is often not much we can do: really, if we would have seen the issue you encoutered before, we would already have fixed it. So we did NOT see it, and we will need YOUR help to find out what is wrong and fix it. The logs are absoutely crucial for that. Expect us to quickly close issues without logs or other information we need. If you don't have time to gather the required information, we don't either.
|
||||
|
||||
Please also note that we have a https://nextcloud.com/contribute/code-of-conduct/ that applies on Github. To summarize it: please, be kind. We try our best to be nice, too. If you can't be bothered to be polite, please just don't bother to report issues as we won't feel motivated to help you. Remember, we don't get paid to help you!
|
||||
-->
|
||||
|
||||
<!--- Please keep the note below for others who read your bug report -->
|
||||
|
||||
### How to use GitHub
|
||||
|
||||
* Please use the 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to show that you are affected by the same issue.
|
||||
* Please don't comment if you have no relevant information to add. It's just extra noise for everyone subscribed to this issue.
|
||||
* Subscribe to receive notifications on status change and new comments.
|
||||
|
||||
|
||||
### Expected behaviour
|
||||
Tell us what should happen
|
||||
|
||||
### Actual behaviour
|
||||
Tell us what happens instead
|
||||
<!--
|
||||
Did you try end-to-end encryption before version 3.0? Following the instructions from this post might solve your problem since you might need to clean up the keys as that can break the functioning of >3.0 if you had a malformed key: https://help.nextcloud.com/t/help-test-the-latest-version-of-e2ee/87590
|
||||
-->
|
||||
|
||||
### Steps to reproduce
|
||||
1.
|
||||
@@ -25,8 +46,8 @@ Tell us what happens instead
|
||||
Client version:
|
||||
<!---
|
||||
Please try to only report a bug if it happens with the latest version
|
||||
The latest version can be seen by checking https://download.nextcloud.com/desktop/
|
||||
For support try our forums: https://help.nextcloud.com
|
||||
The latest version can be seen by checking https://nextcloud.com/install/#install-clients
|
||||
In the case of end-to-end encryption bug reports the client must be at least 3.0 and the server at least 19 with the end to end encryption app version at least 1.5.2.
|
||||
--->
|
||||
|
||||
Operating system:
|
||||
@@ -53,7 +74,9 @@ Storage backend (external storage):
|
||||
Please use Gist (https://gist.github.com/) or a similar code paster for longer
|
||||
logs.
|
||||
|
||||
1. Client logfile: Output of `nextcloud --logwindow` or `nextcloud --logfile log.txt`
|
||||
1. Client logfile:
|
||||
<!-- desktop client logs are a hard requirement for bug reports because we don't know how to do magic here :) -->
|
||||
Output of `nextcloud --logdebug --logwindow` or `nextcloud --logdebug --logfile log.txt`
|
||||
(On Windows using `cmd.exe`, you might need to first `cd` into the Nextcloud directory)
|
||||
(See also https://docs.nextcloud.com/desktop/2.3/troubleshooting.html#log-files)
|
||||
|
||||
|
||||
@@ -199,5 +199,6 @@ X-GNOME-Autostart-Delay=3
|
||||
|
||||
# Translations
|
||||
Icon[ko]=@APPLICATION_ICON_NAME@
|
||||
Name[ko]=@APPLICATION_NAME@ 데스크톱 동기화 클라이언트
|
||||
Comment[ko]=@APPLICATION_NAME@ 데스크톱 동기화 클라이언트
|
||||
GenericName[ko]=폴더 동기화
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
set( MIRALL_VERSION_MAJOR 3 )
|
||||
set( MIRALL_VERSION_MINOR 0 )
|
||||
set( MIRALL_VERSION_PATCH 3 )
|
||||
set( MIRALL_VERSION_MINOR 1 )
|
||||
set( MIRALL_VERSION_PATCH 0 )
|
||||
set( MIRALL_VERSION_YEAR 2020 )
|
||||
set( MIRALL_SOVERSION 0 )
|
||||
|
||||
|
||||
@@ -21,16 +21,16 @@ if [ $SUFFIX != "master" ]; then
|
||||
SUFFIX="PR-$SUFFIX"
|
||||
fi
|
||||
|
||||
#QtKeyChain master
|
||||
#QtKeyChain v0.10.0
|
||||
cd /build
|
||||
git clone https://github.com/frankosterfeld/qtkeychain.git
|
||||
cd qtkeychain
|
||||
git checkout master
|
||||
git checkout v0.10.0
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -D CMAKE_INSTALL_PREFIX=/usr ../
|
||||
make -j4
|
||||
make DESTDIR=/app install
|
||||
make install
|
||||
|
||||
#Build client
|
||||
cd /build
|
||||
@@ -39,8 +39,6 @@ cd build-client
|
||||
cmake -D CMAKE_INSTALL_PREFIX=/usr \
|
||||
-D NO_SHIBBOLETH=1 \
|
||||
-D BUILD_UPDATER=ON \
|
||||
-D QTKEYCHAIN_LIBRARY=/app/usr/lib/x86_64-linux-gnu/libqt5keychain.so \
|
||||
-D QTKEYCHAIN_INCLUDE_DIR=/app/usr/include/qt5keychain/ \
|
||||
-DMIRALL_VERSION_SUFFIX=PR-$DRONE_PULL_REQUEST \
|
||||
-DMIRALL_VERSION_BUILD=$DRONE_BUILD_NUMBER \
|
||||
$DRONE_WORKSPACE
|
||||
|
||||
@@ -76,7 +76,7 @@ for distribution in ${UBUNTU_DISTRIBUTIONS} ${DEBIAN_DISTRIBUTIONS}; do
|
||||
|
||||
git merge ${DRONE_COMMIT}
|
||||
|
||||
admin/linux/debian/scripts/git2changelog.py /tmp/tmpchangelog ${distribution} ${revdate}
|
||||
admin/linux/debian/scripts/git2changelog.py /tmp/tmpchangelog ${distribution} ${revdate} ${basever}
|
||||
cat /tmp/tmpchangelog debian/changelog > debian/changelog.new
|
||||
mv debian/changelog.new debian/changelog
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ def getCommitVersion(commit):
|
||||
try:
|
||||
for line in subprocess.check_output(["git", "show",
|
||||
commit + ":VERSION.cmake"]).splitlines():
|
||||
m = re.match("set\( MIRALL_VERSION_([A-Z]+) +([0-9])+ *\)", line)
|
||||
m = re.match("set\( MIRALL_VERSION_([A-Z]+) +([0-9]+) *\)", line)
|
||||
if m is not None:
|
||||
kind=m.group(1)
|
||||
version=m.group(2)
|
||||
@@ -48,7 +48,7 @@ def getCommitVersion(commit):
|
||||
except:
|
||||
return None
|
||||
|
||||
def collectEntries(baseCommit, baseVersion, kind, finalRevDate, config):
|
||||
def collectEntries(baseCommit, baseVersion, kind, finalBaseVersion, finalRevDate, config):
|
||||
|
||||
newVersionCommit = None
|
||||
newVersionTag = None
|
||||
@@ -89,7 +89,6 @@ def collectEntries(baseCommit, baseVersion, kind, finalRevDate, config):
|
||||
newVersionOrigTag = lastVersionTag
|
||||
(baseVersion, _kind) = result
|
||||
|
||||
|
||||
version=getCommitVersion(commit)
|
||||
if version and version!=lastCMAKEVersion:
|
||||
tag = "v" + version
|
||||
@@ -119,6 +118,8 @@ def collectEntries(baseCommit, baseVersion, kind, finalRevDate, config):
|
||||
revdate = datetime.datetime.now().strftime("%Y%m%d.%H%M%S")+ "." + commit
|
||||
else:
|
||||
revdate = finalRevDate
|
||||
if finalBaseVersion is not None:
|
||||
baseVersion = finalBaseVersion
|
||||
entries[-1] = (commit, name, email, date, revdate, subject, baseVersion, kind)
|
||||
|
||||
entries.reverse()
|
||||
@@ -167,8 +168,10 @@ if __name__ == "__main__":
|
||||
|
||||
distribution = sys.argv[2]
|
||||
finalRevDate = sys.argv[3] if len(sys.argv)>3 else None
|
||||
finalBaseVersion = sys.argv[4] if len(sys.argv)>4 else None
|
||||
|
||||
entries = collectEntries(baseCommit, baseVersion, "alpha", finalRevDate, config)
|
||||
entries = collectEntries(baseCommit, baseVersion, "alpha",
|
||||
finalBaseVersion, finalRevDate, config)
|
||||
|
||||
with open(sys.argv[1], "wt") as f:
|
||||
(baseVersion, revdate, kind) = genChangeLogEntries(f, entries, distribution)
|
||||
|
||||
@@ -34,9 +34,9 @@ StrCpy $UNINSTALL_ABORT "Uninstall aborted by user"
|
||||
StrCpy $INIT_NO_QUICK_LAUNCH "Quick Launch Shortcut (N/A)"
|
||||
StrCpy $INIT_NO_DESKTOP "Desktop Shortcut (overwrites existing)"
|
||||
StrCpy $UAC_ERROR_ELEVATE "Unable to elevate, error:"
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "This installer requires admin access, try again"
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "This installer requires admin access, try again."
|
||||
StrCpy $INIT_INSTALLER_RUNNING "The installer is already running."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "This uninstaller requires admin access, try again"
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "This uninstaller requires admin access, try again."
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Logon service is not running, aborting!"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "The uninstaller is already running."
|
||||
StrCpy $SectionGroup_Shortcuts "Shortcuts"
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
# (c) 2014 Copyright ownCloud GmbH
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
# - Try to find QtKeychain
|
||||
# Once done this will define
|
||||
# QTKEYCHAIN_FOUND - System has QtKeychain
|
||||
# QTKEYCHAIN_INCLUDE_DIRS - The QtKeychain include directories
|
||||
# QTKEYCHAIN_LIBRARIES - The libraries needed to use QtKeychain
|
||||
# QTKEYCHAIN_DEFINITIONS - Compiler switches required for using LibXml2
|
||||
|
||||
# When we build our own Qt we also need to build QtKeychain with it
|
||||
# so that it doesn't pull a different Qt version. For that reason
|
||||
# first look in the Qt lib directory for QtKeychain.
|
||||
get_target_property(_QTCORE_LIB_PATH Qt5::Core IMPORTED_LOCATION_RELEASE)
|
||||
|
||||
# Use PATH here because Debian 7.0 has CMake 2.8.9 and DIRECTORY is only available from 2.8.12+
|
||||
get_filename_component(QT_LIB_DIR "${_QTCORE_LIB_PATH}" PATH)
|
||||
|
||||
find_path(QTKEYCHAIN_INCLUDE_DIR
|
||||
NAMES
|
||||
keychain.h
|
||||
HINTS
|
||||
${QT_LIB_DIR}/../include
|
||||
PATH_SUFFIXES
|
||||
qt5keychain
|
||||
)
|
||||
|
||||
find_library(QTKEYCHAIN_LIBRARY
|
||||
NAMES
|
||||
qt5keychain
|
||||
lib5qtkeychain
|
||||
HINTS
|
||||
${QT_LIB_DIR}
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/lib/${CMAKE_ARCH_TRIPLET}
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
${CMAKE_LIBRARY_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
# handle the QUIETLY and REQUIRED arguments and set QTKEYCHAIN_FOUND to TRUE
|
||||
# if all listed variables are TRUE
|
||||
find_package_handle_standard_args(Qt5Keychain DEFAULT_MSG
|
||||
QTKEYCHAIN_LIBRARY QTKEYCHAIN_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(QTKEYCHAIN_INCLUDE_DIR QTKEYCHAIN_LIBRARY)
|
||||
@@ -2,8 +2,7 @@
|
||||
#
|
||||
# Once done this will define
|
||||
# SPARKLE_FOUND - system has Sparkle
|
||||
# SPARKLE_INCLUDE_DIR - the Sparkle include directory
|
||||
# SPARKLE_LIBRARY - The library needed to use Sparkle
|
||||
# SPARKLE_LIBRARY - The framework needed to use Sparkle
|
||||
# Copyright (c) 2009, Vittorio Giovara <vittorio.giovara@gmail.com>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
@@ -15,9 +14,8 @@
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_path(SPARKLE_INCLUDE_DIR Sparkle.h)
|
||||
find_library(SPARKLE_LIBRARY NAMES Sparkle)
|
||||
|
||||
find_package_handle_standard_args(Sparkle DEFAULT_MSG SPARKLE_INCLUDE_DIR SPARKLE_LIBRARY)
|
||||
mark_as_advanced(SPARKLE_INCLUDE_DIR SPARKLE_LIBRARY)
|
||||
find_package_handle_standard_args(Sparkle DEFAULT_MSG SPARKLE_LIBRARY)
|
||||
mark_as_advanced(SPARKLE_LIBRARY)
|
||||
|
||||
|
||||
@@ -33,22 +33,31 @@ Some interesting values that can be set on the configuration file are:
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
|
||||
|
||||
+----------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``[General]`` section |
|
||||
+=================================+===============+========================================================================================================+
|
||||
| Variable | Default | Meaning |
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``chunkSize`` | ``5242880`` | Specifies the chunk size of uploaded files in bytes. |
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``promptDeleteAllFiles`` | ``true`` | If a UI prompt should ask for confirmation if it was detected that all files and folders were deleted. |
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``maxLogLines`` | ``20000`` | Specifies the maximum number of log lines displayed in the log window. |
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``timeout`` | ``300`` | The timeout for network connections in seconds. |
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``moveToTrash`` | ``false`` | If non-locally deleted files should be moved to trash instead of deleting them completely. |
|
||||
| | | This option only works on linux |
|
||||
+---------------------------------+---------------+--------------------------------------------------------------------------------------------------------+
|
||||
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``[General]`` section |
|
||||
+=================================+===============+=================================================================================================================+
|
||||
| Variable | Default | Meaning |
|
||||
+---------------------------------+------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``chunkSize`` | ``10000000`` (10 MB) | Specifies the chunk size of uploaded files in bytes. |
|
||||
| | | The client will dynamically adjust this size within the maximum and minimum bounds (see below). |
|
||||
+---------------------------------+------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``maxChunkSize`` | ``100000000`` (100 MB) | Specifies the maximum chunk size of uploaded files in bytes. |
|
||||
+---------------------------------+------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``minChunkSize`` | ``1000000`` (1 MB) | Specifies the minimum chunk size of uploaded files in bytes. |
|
||||
+---------------------------------+------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``targetChunkUploadDuration`` | ``6000`` (1 minute) | Target duration in milliseconds for chunk uploads. |
|
||||
| | | The client adjusts the chunk size until each chunk upload takes approximately this long. |
|
||||
| | | Set to 0 to disable dynamic chunk sizing. |
|
||||
+---------------------------------+------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``promptDeleteAllFiles`` | ``true`` | If a UI prompt should ask for confirmation if it was detected that all files and folders were deleted. |
|
||||
+---------------------------------+------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``maxLogLines`` | ``20000`` | Specifies the maximum number of log lines displayed in the log window. |
|
||||
+---------------------------------+------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``timeout`` | ``300`` | The timeout for network connections in seconds. |
|
||||
+---------------------------------+------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
| ``moveToTrash`` | ``false`` | If non-locally deleted files should be moved to trash instead of deleting them completely. |
|
||||
| | | This option only works on linux |
|
||||
+---------------------------------+------------------------+--------------------------------------------------------------------------------------------------------+
|
||||
|
||||
|
||||
+----------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
@@ -153,10 +153,42 @@ Saving Files Directly
|
||||
|
||||
The Nextcloud client enables you to save log files directly to a predefined file
|
||||
or directory. This is a useful option for troubleshooting sporadic issues as
|
||||
it enables you to log large amounts of data and bypasses the limited buffer
|
||||
it enables you to log large amounts of data and bypass the limited buffer
|
||||
settings associated with the log window.
|
||||
|
||||
To save log files to a file or a directory:
|
||||
To enable logging to a directory, stop the client and add the following to the General section in the configuration file:
|
||||
|
||||
```
|
||||
[General]
|
||||
logDebug=true
|
||||
logExpire=<hours>
|
||||
logDir=<dir>
|
||||
```
|
||||
|
||||
.. note:: Independent of platform you must use slash (/) as a path reparator:
|
||||
|
||||
* Correct: C:/Temp
|
||||
* Not correct: C:\Temp
|
||||
|
||||
As an example, to keep log data for two days in a directory called temp:
|
||||
|
||||
```
|
||||
[General]
|
||||
logDebug=true
|
||||
logExpire=48
|
||||
logDir=C:/Temp
|
||||
```
|
||||
|
||||
Once you restart the client, you will find the log file in the ``<dir>`` defined in ``logDir``.
|
||||
|
||||
.. note:: You will find the configuration file in the following locations:
|
||||
|
||||
* Microsoft Windows systems: ``%APPDATA%\Nextcloud\nextcloud.cfg``
|
||||
* macOS systems: ``$HOME/Library/Preferences/Nextcloud/nextcloud.cfg``
|
||||
* Linux distributions: ``$HOME/.config/Nextcloud/nextcloud.cfg``
|
||||
|
||||
|
||||
Alternatively, you can start the client in the command line with parameters:
|
||||
|
||||
1. To save to a file, start the client using the ``--logfile <file>`` command,
|
||||
where ``<file>`` is the filename to which you want to save the file.
|
||||
@@ -177,21 +209,6 @@ issue the following command:
|
||||
nextcloud --logdir /tmp/nextcloud_logs --logexpire 48
|
||||
```
|
||||
|
||||
Alternatively, you can add the following to the configuration file:
|
||||
```
|
||||
logDebug=true
|
||||
logExpire=<hours>
|
||||
logDir=<dir>
|
||||
```
|
||||
|
||||
Once you restart the client, you will find the log file in the ``<dir>`` defined in ``logDir``.
|
||||
|
||||
.. note:: You will find the configuration file in the following locations:
|
||||
|
||||
* Microsoft Windows systems: ``%APPDATA%\Nextcloud\nextcloud.cfg``
|
||||
* macOS systems: ``$HOME/Library/Preferences/Nextcloud/nextcloud.cfg``
|
||||
* Linux distributions: ``$HOME/.config/Nextcloud/nextcloud.cfg``
|
||||
|
||||
Nextcloud server Log File
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -5,5 +5,6 @@
|
||||
<file>src/gui/tray/HeaderButton.qml</file>
|
||||
<file>theme/Style/Style.qml</file>
|
||||
<file>theme/Style/qmldir</file>
|
||||
<file>src/gui/tray/ActivityActionButton.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -30,7 +30,7 @@ class OwncloudDolphinPlugin : public KOverlayIconPlugin
|
||||
Q_PLUGIN_METADATA(IID "com.owncloud.ovarlayiconplugin" FILE "ownclouddolphinoverlayplugin.json")
|
||||
Q_OBJECT
|
||||
|
||||
typedef QHash<QByteArray, QByteArray> StatusMap;
|
||||
using StatusMap = QHash<QByteArray, QByteArray>;
|
||||
StatusMap m_status;
|
||||
|
||||
public:
|
||||
|
||||
@@ -83,7 +83,7 @@ HRESULT NCContextMenuRegHandler::RegisterInprocServer(PCWSTR pszModule, const CL
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
|
||||
// Create the HKCR\CLSID\{<CLSID>} key.
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), L"CLSID\\%s", szCLSID);
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), LR"(CLSID\%s)", szCLSID);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey, nullptr, pszFriendlyName);
|
||||
@@ -92,7 +92,7 @@ HRESULT NCContextMenuRegHandler::RegisterInprocServer(PCWSTR pszModule, const CL
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
|
||||
L"CLSID\\%s\\InprocServer32", szCLSID);
|
||||
LR"(CLSID\%s\InprocServer32)", szCLSID);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Set the default value of the InprocServer32 key to the
|
||||
@@ -121,7 +121,7 @@ HRESULT NCContextMenuRegHandler::UnregisterInprocServer(const CLSID& clsid)
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
|
||||
// Delete the HKCR\CLSID\{<CLSID>} key.
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), L"CLSID\\%s", szCLSID);
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), LR"(CLSID\%s)", szCLSID);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(RegDelnode(HKEY_CLASSES_ROOT, szSubkey));
|
||||
@@ -165,7 +165,7 @@ HRESULT NCContextMenuRegHandler::RegisterShellExtContextMenuHandler(
|
||||
|
||||
// Create the key HKCR\<File Type>\shellex\ContextMenuHandlers\{friendlyName>}
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
|
||||
L"%s\\shellex\\ContextMenuHandlers\\%s", pszFileType, pszFriendlyName);
|
||||
LR"(%s\shellex\ContextMenuHandlers\%s)", pszFileType, pszFriendlyName);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Set the default value of the key.
|
||||
@@ -206,7 +206,7 @@ HRESULT NCContextMenuRegHandler::UnregisterShellExtContextMenuHandler(
|
||||
|
||||
// Remove the HKCR\<File Type>\shellex\ContextMenuHandlers\{friendlyName} key.
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
|
||||
L"%s\\shellex\\ContextMenuHandlers\\%s", pszFileType, pszFriendlyName);
|
||||
LR"(%s\shellex\ContextMenuHandlers\%s)", pszFileType, pszFriendlyName);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(RegDelnode(HKEY_CLASSES_ROOT, szSubkey));
|
||||
|
||||
@@ -113,23 +113,23 @@ void QProgressIndicator::paintEvent(QPaintEvent * /*event*/)
|
||||
QPainter p(this);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
int outerRadius = (width-1)*0.5;
|
||||
int innerRadius = (width-1)*0.5*0.38;
|
||||
int outerRadius = qRound((width - 1) * 0.5);
|
||||
int innerRadius = qRound((width - 1) * 0.5 * 0.38);
|
||||
|
||||
int capsuleHeight = outerRadius - innerRadius;
|
||||
int capsuleWidth = (width > 32 ) ? capsuleHeight *.23 : capsuleHeight *.35;
|
||||
int capsuleWidth = qRound((width > 32 ) ? capsuleHeight * 0.23 : capsuleHeight * 0.35);
|
||||
int capsuleRadius = capsuleWidth/2;
|
||||
|
||||
for (int i=0; i<12; i++)
|
||||
{
|
||||
QColor color = m_color;
|
||||
color.setAlphaF(1.0f - (i/12.0f));
|
||||
color.setAlphaF(1.0f - (static_cast<float>(i) / 12.0f));
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(color);
|
||||
p.save();
|
||||
p.translate(rect().center());
|
||||
p.rotate(m_angle - i*30.0f);
|
||||
p.drawRoundedRect(-capsuleWidth*0.5, -(innerRadius+capsuleHeight), capsuleWidth, capsuleHeight, capsuleRadius, capsuleRadius);
|
||||
p.rotate(m_angle - i * 30);
|
||||
p.drawRoundedRect(qRound(-capsuleWidth * 0.5), -(innerRadius + capsuleHeight), capsuleWidth, capsuleHeight, capsuleRadius, capsuleRadius);
|
||||
p.restore();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ class QProgressIndicator : public QWidget
|
||||
Q_PROPERTY(bool displayedWhenStopped READ isDisplayedWhenStopped WRITE setDisplayedWhenStopped)
|
||||
Q_PROPERTY(QColor color READ color WRITE setColor)
|
||||
public:
|
||||
QProgressIndicator(QWidget* parent = 0);
|
||||
QProgressIndicator(QWidget* parent = nullptr);
|
||||
|
||||
/*! Returns the delay between animation steps.
|
||||
\return The number of milliseconds between animation steps. By default, the animation delay is set to 40 milliseconds.
|
||||
|
||||
@@ -197,9 +197,9 @@ void KMessageWidgetPrivate::applyStyleSheet()
|
||||
const QColor border = bgBaseColor;
|
||||
|
||||
// Generate a final background color from overlaying bgBaseColor over windowColor
|
||||
const int newRed = (bgBaseColor.red() * bgBaseColorAlpha) + (windowColor.red() * (1 - bgBaseColorAlpha));
|
||||
const int newGreen = (bgBaseColor.green() * bgBaseColorAlpha) + (windowColor.green() * (1 - bgBaseColorAlpha));
|
||||
const int newBlue = (bgBaseColor.blue() * bgBaseColorAlpha) + (windowColor.blue() * (1 - bgBaseColorAlpha));
|
||||
const int newRed = qRound(bgBaseColor.red() * bgBaseColorAlpha) + qRound(windowColor.red() * (1 - bgBaseColorAlpha));
|
||||
const int newGreen = qRound(bgBaseColor.green() * bgBaseColorAlpha) + qRound(windowColor.green() * (1 - bgBaseColorAlpha));
|
||||
const int newBlue = qRound(bgBaseColor.blue() * bgBaseColorAlpha) + qRound(windowColor.blue() * (1 - bgBaseColorAlpha));
|
||||
|
||||
const QColor bgFinalColor = QColor(newRed, newGreen, newBlue);
|
||||
|
||||
@@ -241,7 +241,7 @@ void KMessageWidgetPrivate::updateSnapShot()
|
||||
|
||||
void KMessageWidgetPrivate::slotTimeLineChanged(qreal value)
|
||||
{
|
||||
q->setFixedHeight(qMin(value * 2, qreal(1.0)) * content->height());
|
||||
q->setFixedHeight(qMin(qRound(value * 2.0), 1) * content->height());
|
||||
q->update();
|
||||
}
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
|
||||
#include "qtlockedfile.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
21
src/3rdparty/qtokenizer/qtokenizer.h
vendored
21
src/3rdparty/qtokenizer/qtokenizer.h
vendored
@@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
template <class T, class const_iterator>
|
||||
struct QTokenizerPrivate {
|
||||
typedef typename T::value_type char_type;
|
||||
using char_type = typename T::value_type;
|
||||
|
||||
struct State {
|
||||
bool inQuote = false;
|
||||
@@ -110,10 +110,10 @@ struct QTokenizerPrivate {
|
||||
bool returnQuotes;
|
||||
};
|
||||
|
||||
template <class T, class const_iterator>
|
||||
template <class T, class const_iterator = typename T::const_iterator>
|
||||
class QTokenizer {
|
||||
public:
|
||||
typedef typename T::value_type char_type;
|
||||
using char_type = typename T::value_type;
|
||||
|
||||
/*!
|
||||
\class QTokenizer
|
||||
@@ -220,7 +220,7 @@ public:
|
||||
Use \c hasNext() to fetch the next token.
|
||||
*/
|
||||
T next() const {
|
||||
int len = d->tokenEnd-d->tokenBegin;
|
||||
int len = std::distance(d->tokenBegin, d->tokenEnd);
|
||||
const_iterator tmpStart = d->tokenBegin;
|
||||
if (!d->returnQuotes && len > 1 && d->isQuote(*d->tokenBegin)) {
|
||||
tmpStart++;
|
||||
@@ -234,7 +234,7 @@ private:
|
||||
QSharedPointer<QTokenizerPrivate<T, const_iterator> > d;
|
||||
};
|
||||
|
||||
class QStringTokenizer : public QTokenizer<QString, QString::const_iterator> {
|
||||
class QStringTokenizer : public QTokenizer<QString> {
|
||||
public:
|
||||
QStringTokenizer(const QString &string, const QString &delim) :
|
||||
QTokenizer<QString, QString::const_iterator>(string, delim) {}
|
||||
@@ -243,8 +243,9 @@ public:
|
||||
* @return A reference to the token within the string
|
||||
*/
|
||||
QStringRef stringRef() {
|
||||
int begin = d->tokenBegin-d->begin;
|
||||
int end = d->tokenEnd-d->tokenBegin;
|
||||
// If those differences overflow an int we'd have a veeeeeery long string in memory
|
||||
int begin = std::distance(d->begin, d->tokenBegin);
|
||||
int end = std::distance(d->tokenBegin, d->tokenEnd);
|
||||
if (!d->returnQuotes && d->isQuote(*d->tokenBegin)) {
|
||||
begin++;
|
||||
end -= 2;
|
||||
@@ -253,9 +254,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
typedef QTokenizer<QByteArray, QByteArray::const_iterator> QByteArrayTokenizer;
|
||||
typedef QTokenizer<std::string, std::string::const_iterator> StringTokenizer;
|
||||
typedef QTokenizer<std::wstring, std::wstring::const_iterator> WStringTokenizer;
|
||||
using QByteArrayTokenizer = QTokenizer<QByteArray>;
|
||||
using StringTokenizer = QTokenizer<std::string>;
|
||||
using WStringTokenizer = QTokenizer<std::wstring>;
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
|
||||
@@ -36,12 +36,12 @@
|
||||
#if defined(Q_OS_WIN)
|
||||
#include <QLibrary>
|
||||
#include <qt_windows.h>
|
||||
typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
|
||||
using PProcessIdToSessionId = BOOL (WINAPI*)(DWORD, DWORD*);
|
||||
static PProcessIdToSessionId pProcessIdToSessionId = 0;
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_UNIX)
|
||||
#include <time.h>
|
||||
#include <ctime>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ class QtLocalPeer : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
|
||||
explicit QtLocalPeer(QObject *parent = nullptr, const QString &appId = QString());
|
||||
bool isClient();
|
||||
bool sendMessage(const QString &message, int timeout, bool block);
|
||||
QString applicationId() const
|
||||
|
||||
@@ -293,8 +293,8 @@ void selectiveSyncFixup(OCC::SyncJournalDb *journal, const QStringList &newList)
|
||||
auto oldBlackListSet = journal->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &ok).toSet();
|
||||
if (ok) {
|
||||
auto blackListSet = newList.toSet();
|
||||
auto changes = (oldBlackListSet - blackListSet) + (blackListSet - oldBlackListSet);
|
||||
foreach (const auto &it, changes) {
|
||||
const auto changes = (oldBlackListSet - blackListSet) + (blackListSet - oldBlackListSet);
|
||||
for (const auto &it : changes) {
|
||||
journal->avoidReadFromDbOnNextSync(it);
|
||||
}
|
||||
|
||||
@@ -499,7 +499,7 @@ restart_sync:
|
||||
}
|
||||
|
||||
Cmd cmd;
|
||||
QString dbPath = SyncJournalDb::makeDbName(credentialFreeUrl, folder, user);
|
||||
QString dbPath = options.source_dir + SyncJournalDb::makeDbName(options.source_dir, credentialFreeUrl, folder, user);
|
||||
SyncJournalDb db(dbPath);
|
||||
|
||||
if (!selectiveSyncList.empty()) {
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace OCC {
|
||||
class NetrcParser
|
||||
{
|
||||
public:
|
||||
typedef QPair<QString, QString> LoginPair;
|
||||
using LoginPair = QPair<QString, QString>;
|
||||
|
||||
NetrcParser(const QString &file = QString());
|
||||
bool parse();
|
||||
|
||||
@@ -27,7 +27,7 @@ bool SimpleSslErrorHandler::handleErrors(QList<QSslError> errors, const QSslConf
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (QSslError error, errors) {
|
||||
for (const auto &error : qAsConst(errors)) {
|
||||
certs->append(error.certificate());
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#ifndef _C_JHASH_H
|
||||
#define _C_JHASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdint.h> // NOLINT
|
||||
|
||||
#define c_hashsize(n) ((uint8_t) 1 << (n))
|
||||
#define c_hashmask(n) (xhashsize(n) - 1)
|
||||
@@ -57,15 +57,15 @@
|
||||
*/
|
||||
#define _c_mix(a,b,c) \
|
||||
{ \
|
||||
a -= b; a -= c; a ^= (c>>13); \
|
||||
b -= c; b -= a; b ^= (a<<8); \
|
||||
c -= a; c -= b; c ^= (b>>13); \
|
||||
a -= b; a -= c; a ^= (c>>12); \
|
||||
b -= c; b -= a; b ^= (a<<16); \
|
||||
c -= a; c -= b; c ^= (b>>5); \
|
||||
a -= b; a -= c; a ^= (c>>3); \
|
||||
b -= c; b -= a; b ^= (a<<10); \
|
||||
c -= a; c -= b; c ^= (b>>15); \
|
||||
(a) -= (b); (a) -= (c); (a) ^= ((c)>>13); \
|
||||
(b) -= (c); (b) -= (a); (b) ^= ((a)<<8); \
|
||||
(c) -= (a); (c) -= (b); (c) ^= ((b)>>13); \
|
||||
(a) -= (b); (a) -= (c); (a) ^= ((c)>>12); \
|
||||
(b) -= (c); (b) -= (a); (b) ^= ((a)<<16); \
|
||||
(c) -= (a); (c) -= (b); (c) ^= ((b)>>5); \
|
||||
(a) -= (b); (a) -= (c); (a) ^= ((c)>>3); \
|
||||
(b) -= (c); (b) -= (a); (b) ^= ((a)<<10); \
|
||||
(c) -= (a); (c) -= (b); (c) ^= ((b)>>15); \
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,18 +88,18 @@
|
||||
*/
|
||||
#define _c_mix64(a,b,c) \
|
||||
{ \
|
||||
a -= b; a -= c; a ^= (c>>43); \
|
||||
b -= c; b -= a; b ^= (a<<9); \
|
||||
c -= a; c -= b; c ^= (b>>8); \
|
||||
a -= b; a -= c; a ^= (c>>38); \
|
||||
b -= c; b -= a; b ^= (a<<23); \
|
||||
c -= a; c -= b; c ^= (b>>5); \
|
||||
a -= b; a -= c; a ^= (c>>35); \
|
||||
b -= c; b -= a; b ^= (a<<49); \
|
||||
c -= a; c -= b; c ^= (b>>11); \
|
||||
a -= b; a -= c; a ^= (c>>12); \
|
||||
b -= c; b -= a; b ^= (a<<18); \
|
||||
c -= a; c -= b; c ^= (b>>22); \
|
||||
(a) -= (b); (a) -= (c); (a) ^= ((c)>>43); \
|
||||
(b) -= (c); (b) -= (a); (b) ^= ((a)<<9); \
|
||||
(c) -= (a); (c) -= (b); (c) ^= ((b)>>8); \
|
||||
(a) -= (b); (a) -= (c); (a) ^= ((c)>>38); \
|
||||
(b) -= (c); (b) -= (a); (b) ^= ((a)<<23); \
|
||||
(c) -= (a); (c) -= (b); (c) ^= ((b)>>5); \
|
||||
(a) -= (b); (a) -= (c); (a) ^= ((c)>>35); \
|
||||
(b) -= (c); (b) -= (a); (b) ^= ((a)<<49); \
|
||||
(c) -= (a); (c) -= (b); (c) ^= ((b)>>11); \
|
||||
(a) -= (b); (a) -= (c); (a) ^= ((c)>>12); \
|
||||
(b) -= (c); (b) -= (a); (b) ^= ((a)<<18); \
|
||||
(c) -= (a); (c) -= (b); (c) ^= ((b)>>22); \
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -70,7 +70,7 @@ class OCSYNC_EXPORT ComputeChecksum : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ComputeChecksum(QObject *parent = 0);
|
||||
explicit ComputeChecksum(QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* Sets the checksum type to be used. The default is empty.
|
||||
@@ -112,7 +112,7 @@ class OCSYNC_EXPORT ValidateChecksumHeader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ValidateChecksumHeader(QObject *parent = 0);
|
||||
explicit ValidateChecksumHeader(QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* Check a file's actual checksum against the provided checksumHeader
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace FileSystem {
|
||||
* Equivalent to QFile::remove(), except on Windows, where it will also
|
||||
* successfully remove read-only files.
|
||||
*/
|
||||
bool OCSYNC_EXPORT remove(const QString &fileName, QString *errorString = 0);
|
||||
bool OCSYNC_EXPORT remove(const QString &fileName, QString *errorString = nullptr);
|
||||
|
||||
/**
|
||||
* Move the specified file or folder to the trash. (Only implemented on linux)
|
||||
@@ -175,10 +175,10 @@ namespace FileSystem {
|
||||
if( str[0] == '/' || str[0] == '\\' ) {
|
||||
// Don't prepend if already UNC
|
||||
if( !(len > 1 && (str[1] == '/' || str[1] == '\\')) ) {
|
||||
longStr.append("\\\\?");
|
||||
longStr.append(R"(\\?)");
|
||||
}
|
||||
} else {
|
||||
longStr.append("\\\\?\\"); // prepend string by this four magic chars.
|
||||
longStr.append(R"(\\?\)"); // prepend string by this four magic chars.
|
||||
}
|
||||
longStr += str;
|
||||
|
||||
|
||||
@@ -43,9 +43,7 @@ namespace OCC {
|
||||
|
||||
Q_LOGGING_CATEGORY(lcSql, "nextcloud.sync.database.sql", QtInfoMsg)
|
||||
|
||||
SqlDatabase::SqlDatabase()
|
||||
{
|
||||
}
|
||||
SqlDatabase::SqlDatabase() = default;
|
||||
|
||||
SqlDatabase::~SqlDatabase()
|
||||
{
|
||||
@@ -369,14 +367,14 @@ void SqlQuery::bindValue(int pos, const QVariant &value)
|
||||
const QDateTime dateTime = value.toDateTime();
|
||||
const QString str = dateTime.toString(QLatin1String("yyyy-MM-ddThh:mm:ss.zzz"));
|
||||
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
||||
str.size() * sizeof(ushort), SQLITE_TRANSIENT);
|
||||
str.size() * static_cast<int>(sizeof(ushort)), SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
case QVariant::Time: {
|
||||
const QTime time = value.toTime();
|
||||
const QString str = time.toString(QLatin1String("hh:mm:ss.zzz"));
|
||||
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
||||
str.size() * sizeof(ushort), SQLITE_TRANSIENT);
|
||||
str.size() * static_cast<int>(sizeof(ushort)), SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
case QVariant::String: {
|
||||
@@ -384,7 +382,7 @@ void SqlQuery::bindValue(int pos, const QVariant &value)
|
||||
// lifetime of string == lifetime of its qvariant
|
||||
const auto *str = static_cast<const QString *>(value.constData());
|
||||
res = sqlite3_bind_text16(_stmt, pos, str->utf16(),
|
||||
(str->size()) * sizeof(QChar), SQLITE_TRANSIENT);
|
||||
(str->size()) * static_cast<int>(sizeof(QChar)), SQLITE_TRANSIENT);
|
||||
} else {
|
||||
res = sqlite3_bind_null(_stmt, pos);
|
||||
}
|
||||
@@ -399,7 +397,7 @@ void SqlQuery::bindValue(int pos, const QVariant &value)
|
||||
QString str = value.toString();
|
||||
// SQLITE_TRANSIENT makes sure that sqlite buffers the data
|
||||
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
||||
(str.size()) * sizeof(QChar), SQLITE_TRANSIENT);
|
||||
(str.size()) * static_cast<int>(sizeof(QChar)), SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <QElapsedTimer>
|
||||
#include <QUrl>
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include "common/syncjournaldb.h"
|
||||
@@ -104,15 +103,11 @@ SyncJournalDb::SyncJournalDb(const QString &dbFilePath, QObject *parent)
|
||||
}
|
||||
}
|
||||
|
||||
QString SyncJournalDb::makeDbName(const QUrl &remoteUrl,
|
||||
QString SyncJournalDb::makeDbName(const QString &localPath,
|
||||
const QUrl &remoteUrl,
|
||||
const QString &remotePath,
|
||||
const QString &user)
|
||||
{
|
||||
const QString dbPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||
if (!QDir(dbPath).exists()) {
|
||||
QDir().mkdir(dbPath);
|
||||
}
|
||||
|
||||
QString journalPath = QLatin1String("._sync_");
|
||||
|
||||
QString key = QString::fromUtf8("%1@%2:%3").arg(user, remoteUrl.toString(), remotePath);
|
||||
@@ -121,16 +116,17 @@ QString SyncJournalDb::makeDbName(const QUrl &remoteUrl,
|
||||
journalPath.append(ba.left(6).toHex());
|
||||
journalPath.append(".db");
|
||||
|
||||
journalPath = dbPath + QLatin1Char('/') + journalPath;
|
||||
|
||||
// If the journal doesn't exist and we can't create a file
|
||||
// at that location, try again with a journal name that doesn't
|
||||
// have the ._ prefix.
|
||||
//
|
||||
// The disadvantage of that filename is that it will only be ignored
|
||||
// by client versions >2.3.2.
|
||||
//
|
||||
// See #5633: "._*" is often forbidden on samba shared folders.
|
||||
|
||||
// If it exists already, the path is clearly usable
|
||||
QFile file(QDir(dbPath).filePath(journalPath));
|
||||
QFile file(QDir(localPath).filePath(journalPath));
|
||||
if (file.exists()) {
|
||||
return journalPath;
|
||||
}
|
||||
@@ -145,7 +141,7 @@ QString SyncJournalDb::makeDbName(const QUrl &remoteUrl,
|
||||
|
||||
// Can we create it if we drop the underscore?
|
||||
QString alternateJournalPath = journalPath.mid(2).prepend(".");
|
||||
QFile file2(QDir(dbPath).filePath(alternateJournalPath));
|
||||
QFile file2(QDir(localPath).filePath(alternateJournalPath));
|
||||
if (file2.open(QIODevice::ReadWrite)) {
|
||||
// The alternative worked, use it
|
||||
qCInfo(lcDb) << "Using alternate database path" << alternateJournalPath;
|
||||
@@ -729,10 +725,10 @@ bool SyncJournalDb::updateMetadataTableStructure()
|
||||
SqlQuery query(_db);
|
||||
query.prepare("ALTER TABLE metadata ADD COLUMN isE2eEncrypted INTEGER;");
|
||||
if (!query.exec()) {
|
||||
sqlFail("updateMetadataTableStructure: add e2eMangledName column", query);
|
||||
sqlFail("updateMetadataTableStructure: add isE2eEncrypted column", query);
|
||||
re = false;
|
||||
}
|
||||
commitInternal("update database structure: add e2eMangledName col");
|
||||
commitInternal("update database structure: add isE2eEncrypted col");
|
||||
}
|
||||
|
||||
if (!tableColumns("uploadinfo").contains("contentChecksum")) {
|
||||
@@ -1456,7 +1452,7 @@ SyncJournalDb::UploadInfo SyncJournalDb::getUploadInfo(const QString &file)
|
||||
if (_getUploadInfoQuery.next()) {
|
||||
bool ok = true;
|
||||
res._chunk = _getUploadInfoQuery.intValue(0);
|
||||
res._transferid = _getUploadInfoQuery.intValue(1);
|
||||
res._transferid = _getUploadInfoQuery.int64Value(1);
|
||||
res._errorCount = _getUploadInfoQuery.intValue(2);
|
||||
res._size = _getUploadInfoQuery.int64Value(3);
|
||||
res._modtime = _getUploadInfoQuery.int64Value(4);
|
||||
@@ -2031,6 +2027,23 @@ QByteArrayList SyncJournalDb::conflictRecordPaths()
|
||||
return paths;
|
||||
}
|
||||
|
||||
QByteArray SyncJournalDb::conflictFileBaseName(const QByteArray &conflictName)
|
||||
{
|
||||
auto conflict = conflictRecord(conflictName);
|
||||
QByteArray result;
|
||||
if (conflict.isValid()) {
|
||||
getFileRecordsByFileId(conflict.baseFileId, [&result](const SyncJournalFileRecord &record) {
|
||||
if (!record._path.isEmpty())
|
||||
result = record._path;
|
||||
});
|
||||
}
|
||||
|
||||
if (result.isEmpty()) {
|
||||
result = Utility::conflictFileBaseNameFromPattern(conflictName);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void SyncJournalDb::clearFileTable()
|
||||
{
|
||||
QMutexLocker lock(&_mutex);
|
||||
|
||||
@@ -42,11 +42,12 @@ class OCSYNC_EXPORT SyncJournalDb : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SyncJournalDb(const QString &dbFilePath, QObject *parent = 0);
|
||||
explicit SyncJournalDb(const QString &dbFilePath, QObject *parent = nullptr);
|
||||
virtual ~SyncJournalDb();
|
||||
|
||||
/// Create a journal path for a specific configuration
|
||||
static QString makeDbName(const QUrl &remoteUrl,
|
||||
static QString makeDbName(const QString &localPath,
|
||||
const QUrl &remoteUrl,
|
||||
const QString &remotePath,
|
||||
const QString &user);
|
||||
|
||||
@@ -94,7 +95,7 @@ public:
|
||||
struct UploadInfo
|
||||
{
|
||||
int _chunk = 0;
|
||||
int _transferid = 0;
|
||||
quint64 _transferid = 0;
|
||||
quint64 _size = 0; //currently unused
|
||||
qint64 _modtime = 0;
|
||||
int _errorCount = 0;
|
||||
@@ -225,6 +226,13 @@ public:
|
||||
/// Return all paths of files with a conflict tag in the name and records in the db
|
||||
QByteArrayList conflictRecordPaths();
|
||||
|
||||
/** Find the base name for a conflict file name, using journal or name pattern
|
||||
*
|
||||
* The path must be sync-folder relative.
|
||||
*
|
||||
* Will return an empty string if it's not even a conflict file by pattern.
|
||||
*/
|
||||
QByteArray conflictFileBaseName(const QByteArray &conflictName);
|
||||
|
||||
/**
|
||||
* Delete any file entry. This will force the next sync to re-sync everything as if it was new,
|
||||
|
||||
@@ -21,9 +21,7 @@
|
||||
|
||||
namespace OCC {
|
||||
|
||||
SyncJournalFileRecord::SyncJournalFileRecord()
|
||||
{
|
||||
}
|
||||
SyncJournalFileRecord::SyncJournalFileRecord() = default;
|
||||
|
||||
QByteArray SyncJournalFileRecord::numericFileId() const
|
||||
{
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <cmath>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
@@ -190,6 +190,13 @@ QByteArray Utility::userAgentString()
|
||||
return re.toLatin1();
|
||||
}
|
||||
|
||||
QByteArray Utility::friendlyUserAgentString()
|
||||
{
|
||||
const auto pattern = QStringLiteral("%1 (Desktop Client - %2)");
|
||||
const auto userAgent = pattern.arg(QSysInfo::machineHostName(), platform());
|
||||
return userAgent.toUtf8();
|
||||
}
|
||||
|
||||
bool Utility::hasLaunchOnStartup(const QString &appName)
|
||||
{
|
||||
return hasLaunchOnStartup_private(appName);
|
||||
@@ -407,7 +414,7 @@ uint Utility::convertSizeToUint(size_t &convertVar)
|
||||
return static_cast<uint>(convertVar);
|
||||
}
|
||||
|
||||
uint Utility::convertSizeToInt(size_t &convertVar)
|
||||
int Utility::convertSizeToInt(size_t &convertVar)
|
||||
{
|
||||
if (convertVar > INT_MAX) {
|
||||
//throw std::bad_cast();
|
||||
@@ -634,7 +641,7 @@ bool Utility::isConflictFile(const QString &name)
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray Utility::conflictFileBaseName(const QByteArray &conflictName)
|
||||
QByteArray Utility::conflictFileBaseNameFromPattern(const QByteArray &conflictName)
|
||||
{
|
||||
// This function must be able to deal with conflict files for conflict files.
|
||||
// To do this, we scan backwards, for the outermost conflict marker and
|
||||
@@ -666,7 +673,7 @@ QByteArray Utility::conflictFileBaseName(const QByteArray &conflictName)
|
||||
|
||||
QString Utility::sanitizeForFileName(const QString &name)
|
||||
{
|
||||
const auto invalid = QStringLiteral("/?<>\\:*|\"");
|
||||
const auto invalid = QStringLiteral(R"(/?<>\:*|")");
|
||||
QString result;
|
||||
result.reserve(name.size());
|
||||
for (const auto c : name) {
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
#include <QMap>
|
||||
#include <QUrl>
|
||||
#include <QUrlQuery>
|
||||
#include <QtQuick/QQuickImageProvider>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <QRect>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
@@ -42,6 +42,8 @@ class QSettings;
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class SyncJournal;
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcUtility)
|
||||
|
||||
/** \addtogroup libsync
|
||||
@@ -55,10 +57,11 @@ namespace Utility {
|
||||
OCSYNC_EXPORT bool writeRandomFile(const QString &fname, int size = -1);
|
||||
OCSYNC_EXPORT QString octetsToString(qint64 octets);
|
||||
OCSYNC_EXPORT QByteArray userAgentString();
|
||||
OCSYNC_EXPORT QByteArray friendlyUserAgentString();
|
||||
OCSYNC_EXPORT bool hasLaunchOnStartup(const QString &appName);
|
||||
OCSYNC_EXPORT void setLaunchOnStartup(const QString &appName, const QString &guiName, bool launch);
|
||||
OCSYNC_EXPORT uint convertSizeToUint(size_t &convertVar);
|
||||
OCSYNC_EXPORT uint convertSizeToInt(size_t &convertVar);
|
||||
OCSYNC_EXPORT int convertSizeToInt(size_t &convertVar);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
OCSYNC_EXPORT DWORD convertSizeToDWORD(size_t &convertVar);
|
||||
@@ -188,7 +191,7 @@ namespace Utility {
|
||||
|
||||
/** Returns a new settings pre-set in a specific group. The Settings will be created
|
||||
with the given parent. If no parent is specified, the caller must destroy the settings */
|
||||
OCSYNC_EXPORT std::unique_ptr<QSettings> settingsWithGroup(const QString &group, QObject *parent = 0);
|
||||
OCSYNC_EXPORT std::unique_ptr<QSettings> settingsWithGroup(const QString &group, QObject *parent = nullptr);
|
||||
|
||||
/** Sanitizes a string that shall become part of a filename.
|
||||
*
|
||||
@@ -214,16 +217,17 @@ namespace Utility {
|
||||
OCSYNC_EXPORT bool isConflictFile(const char *name);
|
||||
OCSYNC_EXPORT bool isConflictFile(const QString &name);
|
||||
|
||||
/** Find the base name for a conflict file name
|
||||
/** Find the base name for a conflict file name, using name pattern only
|
||||
*
|
||||
* Will return an empty string if it's not a conflict file.
|
||||
*
|
||||
* Prefer to use the data from the conflicts table in the journal to determine
|
||||
* a conflict's base file.
|
||||
* a conflict's base file, see SyncJournal::conflictFileBaseName()
|
||||
*/
|
||||
OCSYNC_EXPORT QByteArray conflictFileBaseName(const QByteArray &conflictName);
|
||||
OCSYNC_EXPORT QByteArray conflictFileBaseNameFromPattern(const QByteArray &conflictName);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
OCSYNC_EXPORT bool registryKeyExists(HKEY hRootKey, const QString &subKey);
|
||||
OCSYNC_EXPORT QVariant registryGetKeyValue(HKEY hRootKey, const QString &subKey, const QString &valueName);
|
||||
OCSYNC_EXPORT bool registrySetKeyValue(HKEY hRootKey, const QString &subKey, const QString &valueName, DWORD type, const QVariant &value);
|
||||
OCSYNC_EXPORT bool registryDeleteKeyTree(HKEY hRootKey, const QString &subKey);
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace OCC {
|
||||
static void setupFavLink_private(const QString &folder)
|
||||
{
|
||||
// Nautilus: add to ~/.gtk-bookmarks
|
||||
QFile gtkBookmarks(QDir::homePath() + QLatin1String("/.gtk-bookmarks"));
|
||||
QFile gtkBookmarks(QDir::homePath() + QLatin1String("/.config/gtk-3.0/bookmarks"));
|
||||
QByteArray folderUrl = "file://" + folder.toUtf8();
|
||||
if (gtkBookmarks.open(QFile::ReadWrite)) {
|
||||
QByteArray places = gtkBookmarks.readAll();
|
||||
@@ -47,6 +47,7 @@ QString getUserAutostartDir_private()
|
||||
|
||||
bool hasLaunchOnStartup_private(const QString &appName)
|
||||
{
|
||||
Q_UNUSED(appName)
|
||||
QString desktopFileLocation = getUserAutostartDir_private()
|
||||
+ QLatin1String(LINUX_APPLICATION_ID)
|
||||
+ QLatin1String(".desktop");
|
||||
@@ -55,6 +56,7 @@ bool hasLaunchOnStartup_private(const QString &appName)
|
||||
|
||||
void setLaunchOnStartup_private(const QString &appName, const QString &guiName, bool enable)
|
||||
{
|
||||
Q_UNUSED(appName)
|
||||
QString userAutoStartPath = getUserAutostartDir_private();
|
||||
QString desktopFileLocation = userAutoStartPath
|
||||
+ QLatin1String(LINUX_APPLICATION_ID)
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <string>
|
||||
#include <QLibrary>
|
||||
|
||||
static const char runPathC[] = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run";
|
||||
static const char runPathC[] = R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run)";
|
||||
|
||||
namespace OCC {
|
||||
|
||||
@@ -91,7 +91,7 @@ void setLaunchOnStartup_private(const QString &appName, const QString &guiName,
|
||||
static inline bool hasDarkSystray_private()
|
||||
{
|
||||
if(Utility::registryGetKeyValue( HKEY_CURRENT_USER,
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
R"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)",
|
||||
"SystemUsesLightTheme" ) == 1) {
|
||||
return false;
|
||||
}
|
||||
@@ -114,6 +114,17 @@ QRect Utility::getTaskbarDimensions()
|
||||
return QRect(barRect.left, barRect.top, (barRect.right - barRect.left), (barRect.bottom - barRect.top));
|
||||
}
|
||||
|
||||
bool Utility::registryKeyExists(HKEY hRootKey, const QString &subKey)
|
||||
{
|
||||
HKEY hKey;
|
||||
|
||||
REGSAM sam = KEY_READ | KEY_WOW64_64KEY;
|
||||
LONG result = RegOpenKeyEx(hRootKey, reinterpret_cast<LPCWSTR>(subKey.utf16()), 0, sam, &hKey);
|
||||
|
||||
RegCloseKey(hKey);
|
||||
return result != ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
QVariant Utility::registryGetKeyValue(HKEY hRootKey, const QString &subKey, const QString &valueName)
|
||||
{
|
||||
QVariant value;
|
||||
|
||||
@@ -25,13 +25,13 @@
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "csync_private.h"
|
||||
@@ -326,7 +326,7 @@ int csync_abort_requested(CSYNC *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<csync_file_stat_t> csync_file_stat_s::fromSyncJournalFileRecord(const OCC::SyncJournalFileRecord &rec)
|
||||
std::unique_ptr<csync_file_stat_t> csync_file_stat_t::fromSyncJournalFileRecord(const OCC::SyncJournalFileRecord &rec)
|
||||
{
|
||||
std::unique_ptr<csync_file_stat_t> st(new csync_file_stat_t);
|
||||
st->path = rec._path;
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
#include "ocsynclib.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <sys/types.h>
|
||||
#include <config_csync.h>
|
||||
#include <functional>
|
||||
@@ -59,7 +59,7 @@ class SyncJournalFileRecord;
|
||||
#define BITFIELD(size) :size
|
||||
#endif
|
||||
|
||||
enum csync_status_codes_e {
|
||||
enum CSYNC_STATUS {
|
||||
CSYNC_STATUS_OK = 0,
|
||||
|
||||
CSYNC_STATUS_ERROR = 1024, /* don't use this code,
|
||||
@@ -95,8 +95,6 @@ enum csync_status_codes_e {
|
||||
CSYNC_STATUS_INDIVIDUAL_CANNOT_ENCODE
|
||||
};
|
||||
|
||||
typedef enum csync_status_codes_e CSYNC_STATUS;
|
||||
|
||||
#ifndef likely
|
||||
# define likely(x) (x)
|
||||
#endif
|
||||
@@ -146,9 +144,7 @@ enum ItemType {
|
||||
// currently specified at https://github.com/owncloud/core/issues/8322 are 9 to 10
|
||||
#define REMOTE_PERM_BUF_SIZE 15
|
||||
|
||||
typedef struct csync_file_stat_s csync_file_stat_t;
|
||||
|
||||
struct OCSYNC_EXPORT csync_file_stat_s {
|
||||
struct OCSYNC_EXPORT csync_file_stat_t {
|
||||
time_t modtime = 0;
|
||||
int64_t size = 0;
|
||||
uint64_t inode = 0;
|
||||
@@ -179,7 +175,7 @@ struct OCSYNC_EXPORT csync_file_stat_s {
|
||||
|
||||
enum csync_instructions_e instruction = CSYNC_INSTRUCTION_NONE; /* u32 */
|
||||
|
||||
csync_file_stat_s()
|
||||
csync_file_stat_t()
|
||||
: type(ItemTypeSkip)
|
||||
, child_modified(false)
|
||||
, has_ignored_files(false)
|
||||
@@ -193,26 +189,19 @@ struct OCSYNC_EXPORT csync_file_stat_s {
|
||||
/**
|
||||
* csync handle
|
||||
*/
|
||||
typedef struct csync_s CSYNC;
|
||||
using CSYNC = struct csync_s;
|
||||
|
||||
typedef int (*csync_auth_callback) (const char *prompt, char *buf, size_t len,
|
||||
int echo, int verify, void *userdata);
|
||||
using csync_auth_callback = int (*)(const char *prompt, char *buf, size_t len, int echo, int verify, void *userdata);
|
||||
|
||||
typedef void (*csync_update_callback) (bool local,
|
||||
const char *dirUrl,
|
||||
void *userdata);
|
||||
using csync_update_callback = void (*)(bool local, const char *dirUrl, void *userdata);
|
||||
|
||||
typedef void csync_vio_handle_t;
|
||||
typedef csync_vio_handle_t* (*csync_vio_opendir_hook) (const char *url,
|
||||
void *userdata);
|
||||
typedef std::unique_ptr<csync_file_stat_t> (*csync_vio_readdir_hook) (csync_vio_handle_t *dhhandle,
|
||||
void *userdata);
|
||||
typedef void (*csync_vio_closedir_hook) (csync_vio_handle_t *dhhandle,
|
||||
void *userdata);
|
||||
using csync_vio_handle_t = void;
|
||||
using csync_vio_opendir_hook = csync_vio_handle_t *(*)(const char *url, void *userdata);
|
||||
using csync_vio_readdir_hook = std::unique_ptr<csync_file_stat_t> (*)(csync_vio_handle_t *dhandle, void *userdata);
|
||||
using csync_vio_closedir_hook = void (*)(csync_vio_handle_t *dhandle, void *userdata);
|
||||
|
||||
/* Compute the checksum of the given \a checksumTypeId for \a path. */
|
||||
typedef QByteArray (*csync_checksum_hook)(
|
||||
const QByteArray &path, const QByteArray &otherChecksumHeader, void *userdata);
|
||||
using csync_checksum_hook = QByteArray (*)(const QByteArray &path, const QByteArray &otherChecksumHeader, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Update detection
|
||||
|
||||
@@ -317,17 +317,20 @@ bool ExcludedFiles::loadExcludeFile(const QByteArray & basePath, const QString &
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
return false;
|
||||
|
||||
QList<QByteArray> patterns;
|
||||
while (!f.atEnd()) {
|
||||
QByteArray line = f.readLine().trimmed();
|
||||
if (line.isEmpty() || line.startsWith('#'))
|
||||
continue;
|
||||
csync_exclude_expand_escapes(line);
|
||||
_allExcludes[basePath].append(line);
|
||||
patterns.append(line);
|
||||
}
|
||||
_allExcludes.insert(basePath, patterns);
|
||||
|
||||
// nothing to prepare if the user decided to not exclude anything
|
||||
if(_allExcludes.size())
|
||||
if (!_allExcludes.value(basePath).isEmpty()){
|
||||
prepare(basePath);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -411,10 +414,12 @@ CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(const char *path, ItemTy
|
||||
|
||||
// Directories are guaranteed to be visited before their files
|
||||
if (filetype == ItemTypeDirectory) {
|
||||
QFileInfo fi = QFileInfo(_localPath + path + "/.sync-exclude.lst");
|
||||
const auto basePath = QString(_localPath + path + QLatin1Char('/')).toUtf8();
|
||||
const auto fi = QFileInfo(basePath + QStringLiteral(".sync-exclude.lst"));
|
||||
|
||||
if (fi.isReadable()) {
|
||||
addInTreeExcludeFilePath(fi.absoluteFilePath());
|
||||
loadExcludeFile(fi.absolutePath().toUtf8(), fi.absoluteFilePath());
|
||||
loadExcludeFile(basePath, fi.absoluteFilePath());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
#include <functional>
|
||||
|
||||
enum csync_exclude_type_e {
|
||||
enum CSYNC_EXCLUDE_TYPE {
|
||||
CSYNC_NOT_EXCLUDED = 0,
|
||||
CSYNC_FILE_SILENTLY_EXCLUDED,
|
||||
CSYNC_FILE_EXCLUDE_AND_REMOVE,
|
||||
@@ -45,7 +45,6 @@ enum csync_exclude_type_e {
|
||||
CSYNC_FILE_EXCLUDE_CONFLICT,
|
||||
CSYNC_FILE_EXCLUDE_CANNOT_ENCODE
|
||||
};
|
||||
typedef enum csync_exclude_type_e CSYNC_EXCLUDE_TYPE;
|
||||
|
||||
class ExcludedFilesTest;
|
||||
|
||||
|
||||
@@ -22,20 +22,20 @@
|
||||
#ifndef _CSYNC_MACROS_H
|
||||
#define _CSYNC_MACROS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
/* How many elements there are in a static array */
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
|
||||
|
||||
/* Some special custom errno values to report bugs properly. The BASE value
|
||||
* should always be larger than the highest system errno. */
|
||||
#define CSYNC_CUSTOM_ERRNO_BASE 10000
|
||||
|
||||
#define ERRNO_WRONG_CONTENT CSYNC_CUSTOM_ERRNO_BASE+11
|
||||
#define ERRNO_SERVICE_UNAVAILABLE CSYNC_CUSTOM_ERRNO_BASE+14
|
||||
#define ERRNO_STORAGE_UNAVAILABLE CSYNC_CUSTOM_ERRNO_BASE+17
|
||||
#define ERRNO_FORBIDDEN CSYNC_CUSTOM_ERRNO_BASE+18
|
||||
#define ERRNO_WRONG_CONTENT (CSYNC_CUSTOM_ERRNO_BASE+11)
|
||||
#define ERRNO_SERVICE_UNAVAILABLE (CSYNC_CUSTOM_ERRNO_BASE+14)
|
||||
#define ERRNO_STORAGE_UNAVAILABLE (CSYNC_CUSTOM_ERRNO_BASE+17)
|
||||
#define ERRNO_FORBIDDEN (CSYNC_CUSTOM_ERRNO_BASE+18)
|
||||
|
||||
#endif /* _CSYNC_MACROS_H */
|
||||
/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */
|
||||
|
||||
@@ -25,12 +25,12 @@
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <cerrno>
|
||||
|
||||
#if _WIN32
|
||||
# ifndef _WIN32_IE
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
|
||||
#include <unordered_map>
|
||||
#include <QHash>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <cstdint>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
@@ -189,7 +189,7 @@ struct OCSYNC_EXPORT csync_s {
|
||||
csync_file_stat_t *current_fs = nullptr;
|
||||
|
||||
/* csync error code */
|
||||
enum csync_status_codes_e status_code = CSYNC_STATUS_OK;
|
||||
enum CSYNC_STATUS status_code = CSYNC_STATUS_OK;
|
||||
|
||||
char *error_string = nullptr;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#include "config_csync.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <cassert>
|
||||
#include "csync_private.h"
|
||||
#include "csync_reconcile.h"
|
||||
#include "csync_util.h"
|
||||
@@ -34,7 +34,7 @@ Q_LOGGING_CATEGORY(lcReconcile, "nextcloud.sync.csync.reconciler", QtInfoMsg)
|
||||
|
||||
// Needed for PRIu64 on MinGW in C++ mode.
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include "inttypes.h"
|
||||
#include <cinttypes>
|
||||
|
||||
/* Check if a file is ignored because one parent is ignored.
|
||||
* return the node of the ignored directoy if it's the case, or \c nullptr if it is not ignored */
|
||||
@@ -188,11 +188,12 @@ static void _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx)
|
||||
}();
|
||||
auto curParent = our_tree->findFile(curParentPath);
|
||||
|
||||
if(!other) {
|
||||
// Stick with the NEW
|
||||
return;
|
||||
} else if (!other->e2eMangledName.isEmpty() || (curParent && curParent->isE2eEncrypted)) {
|
||||
// Stick with the NEW as well, we want to always issue delete + upload in such cases
|
||||
if (!other
|
||||
|| !other->e2eMangledName.isEmpty()
|
||||
|| (curParent && curParent->isE2eEncrypted)) {
|
||||
// Stick with the NEW since there's no "other" file
|
||||
// or if there's an "other" file it involves E2EE and
|
||||
// we want to always issue delete + upload in such cases
|
||||
return;
|
||||
} else if (other->instruction == CSYNC_INSTRUCTION_RENAME) {
|
||||
// Some other EVAL_RENAME already claimed other.
|
||||
@@ -343,7 +344,9 @@ static void _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx)
|
||||
auto remoteNode = ctx->current == REMOTE_REPLICA ? cur : other;
|
||||
auto localNode = ctx->current == REMOTE_REPLICA ? other : cur;
|
||||
remoteNode->instruction = CSYNC_INSTRUCTION_NONE;
|
||||
localNode->instruction = up._modtime == localNode->modtime ? CSYNC_INSTRUCTION_UPDATE_METADATA : CSYNC_INSTRUCTION_SYNC;
|
||||
localNode->instruction = up._modtime == localNode->modtime && up._size == localNode->size ?
|
||||
CSYNC_INSTRUCTION_UPDATE_METADATA : CSYNC_INSTRUCTION_SYNC;
|
||||
|
||||
// Update the etag and other server metadata in the journal already
|
||||
// (We can't use a typical CSYNC_INSTRUCTION_UPDATE_METADATA because
|
||||
// we must not store the size/modtime from the file system)
|
||||
|
||||
@@ -25,11 +25,11 @@
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <cmath>
|
||||
|
||||
#include "c_lib.h"
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
// Needed for PRIu64 on MinGW in C++ mode.
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
#include <cinttypes>
|
||||
|
||||
Q_LOGGING_CATEGORY(lcUpdate, "nextcloud.sync.csync.updater", QtInfoMsg)
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef int (*csync_walker_fn) (CSYNC *ctx, std::unique_ptr<csync_file_stat_t> fs);
|
||||
using csync_walker_fn = int (*)(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> fs);
|
||||
|
||||
/**
|
||||
* @brief The walker function to use in the file tree walker.
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
|
||||
#include "common/c_jhash.h"
|
||||
#include "csync_util.h"
|
||||
@@ -37,10 +37,10 @@
|
||||
Q_LOGGING_CATEGORY(lcCSyncUtils, "nextcloud.sync.csync.utils", QtInfoMsg)
|
||||
|
||||
|
||||
typedef struct {
|
||||
struct _instr_code_struct {
|
||||
const char *instr_str;
|
||||
enum csync_instructions_e instr_code;
|
||||
} _instr_code_struct;
|
||||
};
|
||||
|
||||
static const _instr_code_struct _instr[] =
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#ifndef _CSYNC_UTIL_H
|
||||
#define _CSYNC_UTIL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
|
||||
#include "csync_private.h"
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdlib.h> // NOLINT this is sometimes compiled in C mode
|
||||
|
||||
#include "c_macro.h"
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h> // NOLINT this is sometimes compiled in C mode
|
||||
#include <string.h> // NOLINT this is sometimes compiled in C mode
|
||||
|
||||
#include "c_macro.h"
|
||||
#include "c_alloc.h"
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
#ifndef _C_MACRO_H
|
||||
#define _C_MACRO_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h> // NOLINT this is sometimes compiled in C mode
|
||||
#include <string.h> // NOLINT this is sometimes compiled in C mode
|
||||
|
||||
#define INT_TO_POINTER(i) (void *) i
|
||||
#define POINTER_TO_INT(p) *((int *) (p))
|
||||
@@ -44,7 +44,7 @@
|
||||
#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
|
||||
|
||||
/** Free memory and zero the pointer */
|
||||
#define SAFE_FREE(x) do { if ((x) != NULL) {free((void*)x); x=NULL;} } while(0)
|
||||
#define SAFE_FREE(x) do { if ((x) != NULL) {free((void*)(x)); (x)=NULL;} } while(0)
|
||||
|
||||
/** Get the smaller value */
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
@@ -53,7 +53,7 @@
|
||||
#define MAX(a,b) ((a) < (b) ? (b) : (a))
|
||||
|
||||
/** Get the size of an array */
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
|
||||
|
||||
/**
|
||||
* This is a hack to fix warnings. The idea is to use this everywhere that we
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <errno.h> // NOLINT this is sometimes compiled in C mode
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#define EDQUOT 0
|
||||
@@ -80,10 +80,10 @@
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef struct stat64 csync_stat_t;
|
||||
typedef struct stat64 csync_stat_t; // NOLINT this is sometimes compiled in C mode
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#else
|
||||
typedef struct stat csync_stat_t;
|
||||
typedef struct stat csync_stat_t; // NOLINT this is sometimes compiled in C mode
|
||||
#endif
|
||||
|
||||
#ifndef O_NOATIME
|
||||
@@ -112,7 +112,7 @@ typedef struct stat csync_stat_t;
|
||||
#endif
|
||||
|
||||
#if defined _WIN32 && defined _UNICODE
|
||||
typedef wchar_t mbchar_t;
|
||||
typedef wchar_t mbchar_t; // NOLINT this is sometimes compiled in C mode
|
||||
#define _topen _wopen
|
||||
#define _tdirent _wdirent
|
||||
#define _topendir _wopendir
|
||||
@@ -133,7 +133,7 @@ typedef wchar_t mbchar_t;
|
||||
#define _tchdir _wchdir
|
||||
#define _tgetcwd _wgetcwd
|
||||
#else
|
||||
typedef char mbchar_t;
|
||||
typedef char mbchar_t; // NOLINT this is sometimes compiled in C mode
|
||||
#define _tdirent dirent
|
||||
#define _topen open
|
||||
#define _topendir opendir
|
||||
|
||||
@@ -39,7 +39,7 @@ extern "C" {
|
||||
#include "c_private.h"
|
||||
#include "c_macro.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdlib.h> // NOLINT this is sometimes compiled in C mode
|
||||
|
||||
/**
|
||||
* @brief Compare to strings case insensitively.
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include "common/asserts.h"
|
||||
|
||||
#include "csync_private.h"
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
#include "csync.h"
|
||||
#include "csync_private.h"
|
||||
|
||||
typedef struct fhandle_s {
|
||||
struct fhandle_t {
|
||||
int fd;
|
||||
} fhandle_t;
|
||||
};
|
||||
|
||||
csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name);
|
||||
int csync_vio_closedir(CSYNC *ctx, csync_vio_handle_t *dhandle);
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <cerrno>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <cstdio>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -43,10 +43,10 @@ Q_LOGGING_CATEGORY(lcCSyncVIOLocal, "nextcloud.sync.csync.vio_local", QtInfoMsg)
|
||||
* directory functions
|
||||
*/
|
||||
|
||||
typedef struct dhandle_s {
|
||||
struct dhandle_t {
|
||||
DIR *dh;
|
||||
char *path;
|
||||
} dhandle_t;
|
||||
};
|
||||
|
||||
static int _csync_vio_local_stat_mb(const mbchar_t *wuri, csync_file_stat_t *buf);
|
||||
|
||||
|
||||
@@ -43,12 +43,12 @@ Q_LOGGING_CATEGORY(lcCSyncVIOLocal, "nextcloud.sync.csync.vio_local", QtInfoMsg)
|
||||
* directory functions
|
||||
*/
|
||||
|
||||
typedef struct dhandle_s {
|
||||
struct dhandle_t {
|
||||
WIN32_FIND_DATA ffd;
|
||||
HANDLE hFind;
|
||||
int firstFind;
|
||||
mbchar_t *path; // Always ends with '\'
|
||||
} dhandle_t;
|
||||
};
|
||||
|
||||
static int _csync_vio_local_stat_mb(const mbchar_t *uri, csync_file_stat_t *buf);
|
||||
|
||||
|
||||
@@ -4,6 +4,10 @@ set(CMAKE_AUTOMOC TRUE)
|
||||
set(CMAKE_AUTOUIC TRUE)
|
||||
set(CMAKE_AUTORCC TRUE)
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
add_definitions(-DQT_QML_DEBUG)
|
||||
endif()
|
||||
|
||||
IF(BUILD_UPDATER)
|
||||
add_subdirectory(updater)
|
||||
endif()
|
||||
@@ -21,6 +25,7 @@ endif()
|
||||
|
||||
set(client_UI_SRCS
|
||||
accountsettings.ui
|
||||
conflictdialog.ui
|
||||
folderwizardsourcepage.ui
|
||||
folderwizardtargetpage.ui
|
||||
generalsettings.ui
|
||||
@@ -38,6 +43,7 @@ set(client_UI_SRCS
|
||||
addcertificatedialog.ui
|
||||
proxyauthdialog.ui
|
||||
mnemonicdialog.ui
|
||||
tray/ActivityActionButton.qml
|
||||
tray/Window.qml
|
||||
tray/UserLine.qml
|
||||
wizard/flow2authwidget.ui
|
||||
@@ -54,6 +60,8 @@ set(client_SRCS
|
||||
accountmanager.cpp
|
||||
accountsettings.cpp
|
||||
application.cpp
|
||||
conflictdialog.cpp
|
||||
conflictsolver.cpp
|
||||
connectionvalidator.cpp
|
||||
folder.cpp
|
||||
folderman.cpp
|
||||
@@ -154,9 +162,16 @@ IF( APPLE )
|
||||
list(APPEND client_SRCS systray.mm)
|
||||
|
||||
if(SPARKLE_FOUND AND BUILD_UPDATER)
|
||||
# Define this, we need to check in updater.cpp
|
||||
add_definitions( -DHAVE_SPARKLE )
|
||||
list(APPEND updater_SRCS updater/sparkleupdater_mac.mm)
|
||||
# Define this, we need to check in updater.cpp
|
||||
add_definitions(-DHAVE_SPARKLE)
|
||||
list(APPEND updater_SRCS updater/sparkleupdater_mac.mm updater/sparkleupdater.h)
|
||||
list(APPEND updater_DEPS ${SPARKLE_LIBRARY})
|
||||
|
||||
# Sparkle.framework is installed from here because macdeployqt's CopyFramework breaks on this bundle
|
||||
# as its logic is tightly tailored around Qt5 frameworks
|
||||
install(DIRECTORY "${SPARKLE_LIBRARY}"
|
||||
DESTINATION "${OWNCLOUD_OSX_BUNDLE}/Contents/Frameworks" USE_SOURCE_PERMISSIONS)
|
||||
|
||||
endif()
|
||||
ENDIF()
|
||||
|
||||
@@ -224,9 +239,8 @@ set( final_src
|
||||
${3rdparty_MOC}
|
||||
)
|
||||
|
||||
if(QTKEYCHAIN_FOUND OR QT5KEYCHAIN_FOUND)
|
||||
list(APPEND libsync_LINK_TARGETS ${QTKEYCHAIN_LIBRARY})
|
||||
include_directories(${QTKEYCHAIN_INCLUDE_DIR})
|
||||
if(Qt5Keychain_FOUND)
|
||||
list(APPEND libsync_LINK_TARGETS qt5keychain)
|
||||
endif()
|
||||
|
||||
# add executable icon on windows and osx
|
||||
@@ -303,7 +317,7 @@ endif()
|
||||
|
||||
IF(BUILD_UPDATER)
|
||||
add_library(updater STATIC ${updater_SRCS})
|
||||
target_link_libraries(updater ${synclib_NAME} Qt5::Widgets Qt5::Svg Qt5::Network Qt5::Xml)
|
||||
target_link_libraries(updater ${synclib_NAME} ${updater_DEPS} Qt5::Widgets Qt5::Svg Qt5::Network Qt5::Xml)
|
||||
target_include_directories(updater PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
@@ -314,7 +328,7 @@ set_target_properties( ${APPLICATION_EXECUTABLE} PROPERTIES
|
||||
set_target_properties( ${APPLICATION_EXECUTABLE} PROPERTIES
|
||||
INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}/${APPLICATION_EXECUTABLE};${CMAKE_INSTALL_RPATH}" )
|
||||
|
||||
target_link_libraries( ${APPLICATION_EXECUTABLE} Qt5::Widgets Qt5::Svg Qt5::Network Qt5::Xml Qt5::Qml Qt5::Quick Qt5::QuickControls2 Qt5::WebEngineWidgets)
|
||||
target_link_libraries( ${APPLICATION_EXECUTABLE} Qt5::Widgets Qt5::GuiPrivate Qt5::Svg Qt5::Network Qt5::Xml Qt5::Qml Qt5::Quick Qt5::QuickControls2 Qt5::WebEngineWidgets)
|
||||
target_link_libraries( ${APPLICATION_EXECUTABLE} ${synclib_NAME} )
|
||||
IF(BUILD_UPDATER)
|
||||
target_link_libraries( ${APPLICATION_EXECUTABLE} updater )
|
||||
|
||||
@@ -65,7 +65,7 @@ bool AccountManager::restore()
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (const auto &accountId, settings->childGroups()) {
|
||||
for (const auto &accountId : settings->childGroups()) {
|
||||
settings->beginGroup(accountId);
|
||||
if (auto acc = loadAccountHelper(*settings)) {
|
||||
acc->_id = accountId;
|
||||
@@ -140,7 +140,7 @@ void AccountManager::save(bool saveCredentials)
|
||||
{
|
||||
auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
|
||||
settings->setValue(QLatin1String(versionC), 2);
|
||||
foreach (const auto &acc, _accounts) {
|
||||
for (const auto &acc : qAsConst(_accounts)) {
|
||||
settings->beginGroup(acc->account()->id());
|
||||
saveAccountHelper(acc->account().data(), *settings, saveCredentials);
|
||||
acc->writeToSettings(*settings);
|
||||
@@ -187,7 +187,7 @@ void AccountManager::saveAccountHelper(Account *acc, QSettings &settings, bool s
|
||||
// re-persisting them)
|
||||
acc->_credentials->persist();
|
||||
}
|
||||
Q_FOREACH (QString key, acc->_settingsMap.keys()) {
|
||||
for (const auto &key : acc->_settingsMap.keys()) {
|
||||
settings.setValue(key, acc->_settingsMap.value(key));
|
||||
}
|
||||
settings.setValue(QLatin1String(authTypeC), acc->_credentials->authType());
|
||||
@@ -201,7 +201,7 @@ void AccountManager::saveAccountHelper(Account *acc, QSettings &settings, bool s
|
||||
settings.beginGroup(QLatin1String("General"));
|
||||
qCInfo(lcAccountManager) << "Saving " << acc->approvedCerts().count() << " unknown certs.";
|
||||
QByteArray certs;
|
||||
Q_FOREACH (const QSslCertificate &cert, acc->approvedCerts()) {
|
||||
for (const auto &cert : acc->approvedCerts()) {
|
||||
certs += cert.toPem() + '\n';
|
||||
}
|
||||
if (!certs.isEmpty()) {
|
||||
@@ -258,7 +258,7 @@ AccountPtr AccountManager::loadAccountHelper(QSettings &settings)
|
||||
authType = "webflow";
|
||||
settings.setValue(QLatin1String(authTypeC), authType);
|
||||
|
||||
foreach(QString key, settings.childKeys()) {
|
||||
for (const QString &key : settings.childKeys()) {
|
||||
if (!key.startsWith("http_"))
|
||||
continue;
|
||||
auto newkey = QString::fromLatin1("webflow_").append(key.mid(5));
|
||||
@@ -274,7 +274,7 @@ AccountPtr AccountManager::loadAccountHelper(QSettings &settings)
|
||||
// We want to only restore settings for that auth type and the user value
|
||||
acc->_settingsMap.insert(QLatin1String(userC), settings.value(userC));
|
||||
QString authTypePrefix = authType + "_";
|
||||
Q_FOREACH (QString key, settings.childKeys()) {
|
||||
for (const auto &key : settings.childKeys()) {
|
||||
if (!key.startsWith(authTypePrefix))
|
||||
continue;
|
||||
acc->_settingsMap.insert(key, settings.value(key));
|
||||
@@ -292,12 +292,10 @@ AccountPtr AccountManager::loadAccountHelper(QSettings &settings)
|
||||
|
||||
AccountStatePtr AccountManager::account(const QString &name)
|
||||
{
|
||||
foreach (const auto &acc, _accounts) {
|
||||
if (acc->account()->displayName() == name) {
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
return AccountStatePtr();
|
||||
const auto it = std::find_if(_accounts.cbegin(), _accounts.cend(), [name](const auto &acc) {
|
||||
return acc->account()->displayName() == name;
|
||||
});
|
||||
return it != _accounts.cend() ? *it : AccountStatePtr();
|
||||
}
|
||||
|
||||
AccountState *AccountManager::addAccount(const AccountPtr &newAccount)
|
||||
@@ -364,9 +362,9 @@ void AccountManager::displayMnemonic(const QString& mnemonic)
|
||||
|
||||
void AccountManager::shutdown()
|
||||
{
|
||||
auto accountsCopy = _accounts;
|
||||
const auto accountsCopy = _accounts;
|
||||
_accounts.clear();
|
||||
foreach (const auto &acc, accountsCopy) {
|
||||
for (const auto &acc : accountsCopy) {
|
||||
emit accountRemoved(acc.data());
|
||||
emit removeAccountFolders(acc.data());
|
||||
}
|
||||
@@ -374,12 +372,9 @@ void AccountManager::shutdown()
|
||||
|
||||
bool AccountManager::isAccountIdAvailable(const QString &id) const
|
||||
{
|
||||
foreach (const auto &acc, _accounts) {
|
||||
if (acc->account()->id() == id) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return std::none_of(_accounts.cbegin(), _accounts.cend(), [id](const auto &acc) {
|
||||
return acc->account()->id() == id;
|
||||
});
|
||||
}
|
||||
|
||||
QString AccountManager::generateFreeAccountId() const
|
||||
|
||||
@@ -28,7 +28,7 @@ class AccountManager : public QObject
|
||||
Q_OBJECT
|
||||
public:
|
||||
static AccountManager *instance();
|
||||
~AccountManager() {}
|
||||
~AccountManager() = default;
|
||||
|
||||
/**
|
||||
* Saves the accounts to a given settings file
|
||||
@@ -89,7 +89,7 @@ private:
|
||||
// Adds an account to the tracked list, emitting accountAdded()
|
||||
void addAccountState(AccountState *accountState);
|
||||
|
||||
AccountManager() {}
|
||||
AccountManager() = default;
|
||||
QList<AccountStatePtr> _accounts;
|
||||
|
||||
public slots:
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "syncresult.h"
|
||||
#include "ignorelisttablewidget.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QDialogButtonBox>
|
||||
@@ -761,8 +761,8 @@ void AccountSettings::slotAccountStateChanged()
|
||||
AccountPtr account = _accountState->account();
|
||||
QUrl safeUrl(account->url());
|
||||
safeUrl.setPassword(QString()); // Remove the password from the URL to avoid showing it in the UI
|
||||
FolderMan *folderMan = FolderMan::instance();
|
||||
foreach (Folder *folder, folderMan->map().values()) {
|
||||
const auto folders = FolderMan::instance()->map().values();
|
||||
for (Folder *folder : folders) {
|
||||
_model->slotUpdateFolderState(folder);
|
||||
}
|
||||
|
||||
@@ -894,15 +894,16 @@ void AccountSettings::refreshSelectiveSyncStatus()
|
||||
|
||||
QString msg;
|
||||
int cnt = 0;
|
||||
foreach (Folder *folder, FolderMan::instance()->map().values()) {
|
||||
const auto folders = FolderMan::instance()->map().values();
|
||||
for (Folder *folder : folders) {
|
||||
if (folder->accountState() != _accountState) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
auto undecidedList = folder->journalDb()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncUndecidedList, &ok);
|
||||
const auto undecidedList = folder->journalDb()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncUndecidedList, &ok);
|
||||
QString p;
|
||||
foreach (const auto &it, undecidedList) {
|
||||
for (const auto &it : undecidedList) {
|
||||
// FIXME: add the folder alias in a hoover hint.
|
||||
// folder->alias() + QLatin1String("/")
|
||||
if (cnt++) {
|
||||
|
||||
@@ -54,6 +54,13 @@ AccountState::AccountState(AccountPtr account)
|
||||
connect(account.data(), &Account::credentialsAsked,
|
||||
this, &AccountState::slotCredentialsAsked);
|
||||
_timeSinceLastETagCheck.invalidate();
|
||||
|
||||
connect(this, &AccountState::isConnectedChanged, [=]{
|
||||
// Get the Apps available on the server if we're now connected.
|
||||
if (isConnected()) {
|
||||
fetchNavigationApps();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
AccountState::~AccountState() = default;
|
||||
@@ -236,9 +243,6 @@ void AccountState::checkConnectivity()
|
||||
// Use a small authed propfind as a minimal ping when we're
|
||||
// already connected.
|
||||
conValidator->checkAuthentication();
|
||||
|
||||
// Get the Apps available on the server.
|
||||
fetchNavigationApps();
|
||||
} else {
|
||||
// Check the server and then the auth.
|
||||
|
||||
@@ -441,10 +445,10 @@ void AccountState::slotNavigationAppsFetched(const QJsonDocument &reply, int sta
|
||||
|
||||
if(!reply.isEmpty()){
|
||||
auto element = reply.object().value("ocs").toObject().value("data");
|
||||
auto navLinks = element.toArray();
|
||||
const auto navLinks = element.toArray();
|
||||
|
||||
if(navLinks.size() > 0){
|
||||
foreach (const QJsonValue &value, navLinks) {
|
||||
for (const QJsonValue &value : navLinks) {
|
||||
auto navLink = value.toObject();
|
||||
|
||||
auto *app = new AccountApp(navLink.value("name").toString(), QUrl(navLink.value("href").toString()),
|
||||
@@ -468,9 +472,12 @@ AccountAppList AccountState::appList() const
|
||||
AccountApp* AccountState::findApp(const QString &appId) const
|
||||
{
|
||||
if(!appId.isEmpty()) {
|
||||
foreach(AccountApp *app, appList()) {
|
||||
if(app->id() == appId)
|
||||
return app;
|
||||
const auto apps = appList();
|
||||
const auto it = std::find_if(apps.cbegin(), apps.cend(), [appId](const auto &app) {
|
||||
return app->id() == appId;
|
||||
});
|
||||
if (it != apps.cend()) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ class Account;
|
||||
class AccountApp;
|
||||
class RemoteWipe;
|
||||
|
||||
typedef QExplicitlySharedDataPointer<AccountState> AccountStatePtr;
|
||||
typedef QList<AccountApp*> AccountAppList;
|
||||
using AccountStatePtr = QExplicitlySharedDataPointer<AccountState>;
|
||||
using AccountAppList = QList<AccountApp *>;
|
||||
|
||||
/**
|
||||
* @brief Extra info about an ownCloud server account.
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
};
|
||||
|
||||
/// The actual current connectivity status.
|
||||
typedef ConnectionValidator::Status ConnectionStatus;
|
||||
using ConnectionStatus = ConnectionValidator::Status;
|
||||
|
||||
/// Use the account as parent
|
||||
explicit AccountState(AccountPtr account);
|
||||
@@ -229,7 +229,7 @@ class AccountApp : public QObject
|
||||
public:
|
||||
AccountApp(const QString &name, const QUrl &url,
|
||||
const QString &id, const QUrl &iconUrl,
|
||||
QObject* parent = 0);
|
||||
QObject* parent = nullptr);
|
||||
|
||||
QString name() const;
|
||||
QUrl url() const;
|
||||
|
||||
@@ -241,7 +241,7 @@ Application::Application(int &argc, char **argv)
|
||||
this, &Application::slotAccountStateAdded);
|
||||
connect(AccountManager::instance(), &AccountManager::accountRemoved,
|
||||
this, &Application::slotAccountStateRemoved);
|
||||
foreach (auto ai, AccountManager::instance()->accounts()) {
|
||||
for (const auto &ai : AccountManager::instance()->accounts()) {
|
||||
slotAccountStateAdded(ai.data());
|
||||
}
|
||||
|
||||
@@ -349,8 +349,8 @@ void Application::slotSystemOnlineConfigurationChanged(QNetworkConfiguration cnf
|
||||
|
||||
void Application::slotCheckConnection()
|
||||
{
|
||||
auto list = AccountManager::instance()->accounts();
|
||||
foreach (const auto &accountState, list) {
|
||||
const auto list = AccountManager::instance()->accounts();
|
||||
for (const auto &accountState : list) {
|
||||
AccountState::State state = accountState->state();
|
||||
|
||||
// Don't check if we're manually signed out or
|
||||
@@ -408,7 +408,9 @@ void Application::setupLogging()
|
||||
// might be called from second instance
|
||||
auto logger = Logger::instance();
|
||||
logger->setLogFile(_logFile);
|
||||
logger->setLogDir(!_logDir.isEmpty() ? _logDir : ConfigFile().logDir());
|
||||
if (_logFile.isEmpty()) {
|
||||
logger->setLogDir(_logDir.isEmpty() ? ConfigFile().logDir() : _logDir);
|
||||
}
|
||||
logger->setLogExpire(_logExpire > 0 ? _logExpire : ConfigFile().logExpire());
|
||||
logger->setLogFlush(_logFlush || ConfigFile().logFlush());
|
||||
logger->setLogDebug(_logDebug || ConfigFile().logDebug());
|
||||
@@ -612,7 +614,7 @@ void Application::setupTranslations()
|
||||
auto *qtTranslator = new QTranslator(this);
|
||||
auto *qtkeychainTranslator = new QTranslator(this);
|
||||
|
||||
foreach (QString lang, uiLanguages) {
|
||||
for (QString lang : qAsConst(uiLanguages)) {
|
||||
lang.replace(QLatin1Char('-'), QLatin1Char('_')); // work around QTBUG-25973
|
||||
lang = substLang(lang);
|
||||
const QString trPath = applicationTrPath();
|
||||
|
||||
@@ -20,17 +20,17 @@
|
||||
|
||||
/* Forward declaration required since gio header files interfere with QObject headers */
|
||||
struct _CloudProvidersProviderExporter;
|
||||
typedef _CloudProvidersProviderExporter CloudProvidersProviderExporter;
|
||||
using CloudProvidersProviderExporter = _CloudProvidersProviderExporter;
|
||||
struct _CloudProvidersAccountExporter;
|
||||
typedef _CloudProvidersAccountExporter CloudProvidersAccountExporter;
|
||||
using CloudProvidersAccountExporter = _CloudProvidersAccountExporter;
|
||||
struct _GMenuModel;
|
||||
typedef _GMenuModel GMenuModel;
|
||||
using GMenuModel = _GMenuModel;
|
||||
struct _GMenu;
|
||||
typedef _GMenu GMenu;
|
||||
using GMenu = _GMenu;
|
||||
struct _GActionGroup;
|
||||
typedef _GActionGroup GActionGroup;
|
||||
typedef char gchar;
|
||||
typedef void* gpointer;
|
||||
using GActionGroup = _GActionGroup;
|
||||
using gchar = char;
|
||||
using gpointer = void*;
|
||||
|
||||
using namespace OCC;
|
||||
|
||||
|
||||
181
src/gui/conflictdialog.cpp
Normal file
181
src/gui/conflictdialog.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (C) by Kevin Ottens <kevin.ottens@nextcloud.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "conflictdialog.h"
|
||||
#include "ui_conflictdialog.h"
|
||||
|
||||
#include "conflictsolver.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QDesktopServices>
|
||||
#include <QFileInfo>
|
||||
#include <QMimeDatabase>
|
||||
#include <QPushButton>
|
||||
#include <QUrl>
|
||||
|
||||
namespace {
|
||||
void forceHeaderFont(QWidget *widget)
|
||||
{
|
||||
auto font = widget->font();
|
||||
font.setPointSizeF(font.pointSizeF() * 1.5);
|
||||
widget->setFont(font);
|
||||
}
|
||||
|
||||
void setBoldFont(QWidget *widget, bool bold)
|
||||
{
|
||||
auto font = widget->font();
|
||||
font.setBold(bold);
|
||||
widget->setFont(font);
|
||||
}
|
||||
}
|
||||
|
||||
namespace OCC {
|
||||
|
||||
ConflictDialog::ConflictDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, _ui(new Ui::ConflictDialog)
|
||||
, _solver(new ConflictSolver(this))
|
||||
{
|
||||
_ui->setupUi(this);
|
||||
forceHeaderFont(_ui->conflictMessage);
|
||||
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||
_ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Keep selected version"));
|
||||
|
||||
connect(_ui->localVersionRadio, &QCheckBox::toggled, this, &ConflictDialog::updateButtonStates);
|
||||
connect(_ui->localVersionButton, &QToolButton::clicked, this, [=] {
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(_solver->localVersionFilename()));
|
||||
});
|
||||
|
||||
connect(_ui->remoteVersionRadio, &QCheckBox::toggled, this, &ConflictDialog::updateButtonStates);
|
||||
connect(_ui->remoteVersionButton, &QToolButton::clicked, this, [=] {
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(_solver->remoteVersionFilename()));
|
||||
});
|
||||
|
||||
connect(_solver, &ConflictSolver::localVersionFilenameChanged, this, &ConflictDialog::updateWidgets);
|
||||
connect(_solver, &ConflictSolver::remoteVersionFilenameChanged, this, &ConflictDialog::updateWidgets);
|
||||
}
|
||||
|
||||
QString ConflictDialog::baseFilename() const
|
||||
{
|
||||
return _baseFilename;
|
||||
}
|
||||
|
||||
ConflictDialog::~ConflictDialog() = default;
|
||||
|
||||
QString ConflictDialog::localVersionFilename() const
|
||||
{
|
||||
return _solver->localVersionFilename();
|
||||
}
|
||||
|
||||
QString ConflictDialog::remoteVersionFilename() const
|
||||
{
|
||||
return _solver->remoteVersionFilename();
|
||||
}
|
||||
|
||||
void ConflictDialog::setBaseFilename(const QString &baseFilename)
|
||||
{
|
||||
if (_baseFilename == baseFilename) {
|
||||
return;
|
||||
}
|
||||
|
||||
_baseFilename = baseFilename;
|
||||
_ui->conflictMessage->setText(tr("Conflicting versions of %1.").arg(_baseFilename));
|
||||
}
|
||||
|
||||
void ConflictDialog::setLocalVersionFilename(const QString &localVersionFilename)
|
||||
{
|
||||
_solver->setLocalVersionFilename(localVersionFilename);
|
||||
}
|
||||
|
||||
void ConflictDialog::setRemoteVersionFilename(const QString &remoteVersionFilename)
|
||||
{
|
||||
_solver->setRemoteVersionFilename(remoteVersionFilename);
|
||||
}
|
||||
|
||||
void ConflictDialog::accept()
|
||||
{
|
||||
const auto isLocalPicked = _ui->localVersionRadio->isChecked();
|
||||
const auto isRemotePicked = _ui->remoteVersionRadio->isChecked();
|
||||
|
||||
Q_ASSERT(isLocalPicked || isRemotePicked);
|
||||
if (!isLocalPicked && !isRemotePicked) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto solution = isLocalPicked && isRemotePicked ? ConflictSolver::KeepBothVersions
|
||||
: isLocalPicked ? ConflictSolver::KeepLocalVersion
|
||||
: ConflictSolver::KeepRemoteVersion;
|
||||
if (_solver->exec(solution)) {
|
||||
QDialog::accept();
|
||||
}
|
||||
}
|
||||
|
||||
void ConflictDialog::updateWidgets()
|
||||
{
|
||||
QMimeDatabase mimeDb;
|
||||
|
||||
const auto updateGroup = [this, &mimeDb](const QString &filename, QLabel *linkLabel, const QString &linkText, QLabel *mtimeLabel, QLabel *sizeLabel, QToolButton *button) {
|
||||
const auto fileUrl = QUrl::fromLocalFile(filename).toString();
|
||||
linkLabel->setText(QStringLiteral("<a href='%1'>%2</a>").arg(fileUrl).arg(linkText));
|
||||
|
||||
const auto info = QFileInfo(filename);
|
||||
mtimeLabel->setText(info.lastModified().toString());
|
||||
sizeLabel->setText(locale().formattedDataSize(info.size()));
|
||||
|
||||
const auto mime = mimeDb.mimeTypeForFile(filename);
|
||||
if (QIcon::hasThemeIcon(mime.iconName())) {
|
||||
button->setIcon(QIcon::fromTheme(mime.iconName()));
|
||||
} else {
|
||||
button->setIcon(QIcon(":/qt-project.org/styles/commonstyle/images/file-128.png"));
|
||||
}
|
||||
};
|
||||
|
||||
const auto localVersion = _solver->localVersionFilename();
|
||||
updateGroup(localVersion,
|
||||
_ui->localVersionLink,
|
||||
tr("Open local version"),
|
||||
_ui->localVersionMtime,
|
||||
_ui->localVersionSize,
|
||||
_ui->localVersionButton);
|
||||
|
||||
const auto remoteVersion = _solver->remoteVersionFilename();
|
||||
updateGroup(remoteVersion,
|
||||
_ui->remoteVersionLink,
|
||||
tr("Open server version"),
|
||||
_ui->remoteVersionMtime,
|
||||
_ui->remoteVersionSize,
|
||||
_ui->remoteVersionButton);
|
||||
|
||||
const auto localMtime = QFileInfo(localVersion).lastModified();
|
||||
const auto remoteMtime = QFileInfo(remoteVersion).lastModified();
|
||||
|
||||
setBoldFont(_ui->localVersionMtime, localMtime > remoteMtime);
|
||||
setBoldFont(_ui->remoteVersionMtime, remoteMtime > localMtime);
|
||||
}
|
||||
|
||||
void ConflictDialog::updateButtonStates()
|
||||
{
|
||||
const auto isLocalPicked = _ui->localVersionRadio->isChecked();
|
||||
const auto isRemotePicked = _ui->remoteVersionRadio->isChecked();
|
||||
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(isLocalPicked || isRemotePicked);
|
||||
|
||||
const auto text = isLocalPicked && isRemotePicked ? tr("Keep both versions")
|
||||
: isLocalPicked ? tr("Keep local version")
|
||||
: isRemotePicked ? tr("Keep server version")
|
||||
: tr("Keep selected version");
|
||||
_ui->buttonBox->button(QDialogButtonBox::Ok)->setText(text);
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
57
src/gui/conflictdialog.h
Normal file
57
src/gui/conflictdialog.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) by Kevin Ottens <kevin.ottens@nextcloud.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef CONFLICTDIALOG_H
|
||||
#define CONFLICTDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class ConflictSolver;
|
||||
|
||||
namespace Ui {
|
||||
class ConflictDialog;
|
||||
}
|
||||
|
||||
class ConflictDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ConflictDialog(QWidget *parent = nullptr);
|
||||
~ConflictDialog() override;
|
||||
|
||||
QString baseFilename() const;
|
||||
QString localVersionFilename() const;
|
||||
QString remoteVersionFilename() const;
|
||||
|
||||
public slots:
|
||||
void setBaseFilename(const QString &baseFilename);
|
||||
void setLocalVersionFilename(const QString &localVersionFilename);
|
||||
void setRemoteVersionFilename(const QString &remoteVersionFilename);
|
||||
|
||||
void accept() override;
|
||||
|
||||
private:
|
||||
void updateWidgets();
|
||||
void updateButtonStates();
|
||||
|
||||
QString _baseFilename;
|
||||
QScopedPointer<Ui::ConflictDialog> _ui;
|
||||
ConflictSolver *_solver;
|
||||
};
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
#endif // CONFLICTDIALOG_H
|
||||
305
src/gui/conflictdialog.ui
Normal file
305
src/gui/conflictdialog.ui
Normal file
@@ -0,0 +1,305 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>OCC::ConflictDialog</class>
|
||||
<widget class="QDialog" name="OCC::ConflictDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>504</width>
|
||||
<height>407</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Sync Conflict</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="conflictMessage">
|
||||
<property name="text">
|
||||
<string>Conflicting versions of %1.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<property name="spacing">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Which version of the file do you want to keep?<br/>If you select both versions, the local file will have a number added to its name.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="localVersionRadio">
|
||||
<property name="text">
|
||||
<string>Local version</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QToolButton" name="localVersionButton">
|
||||
<property name="toolTip">
|
||||
<string>Click to open the file</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>64</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,0,1">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="localVersionMtime">
|
||||
<property name="text">
|
||||
<string>today</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="localVersionSize">
|
||||
<property name="text">
|
||||
<string>0 byte</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="localVersionLink">
|
||||
<property name="text">
|
||||
<string><a href="%1">Open local version</a></string>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="remoteVersionRadio">
|
||||
<property name="text">
|
||||
<string>Server version</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QToolButton" name="remoteVersionButton">
|
||||
<property name="toolTip">
|
||||
<string>Click to open the file</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>64</width>
|
||||
<height>64</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,1">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="remoteVersionMtime">
|
||||
<property name="text">
|
||||
<string>today</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="remoteVersionSize">
|
||||
<property name="text">
|
||||
<string>0 byte</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="remoteVersionLink">
|
||||
<property name="text">
|
||||
<string><a href="%1">Open server version</a></string>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>OCC::ConflictDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>123</x>
|
||||
<y>218</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>148</x>
|
||||
<y>248</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>OCC::ConflictDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>181</x>
|
||||
<y>215</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>240</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
164
src/gui/conflictsolver.cpp
Normal file
164
src/gui/conflictsolver.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) by Kevin Ottens <kevin.ottens@nextcloud.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "conflictsolver.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "common/utility.h"
|
||||
#include "filesystem.h"
|
||||
|
||||
namespace OCC {
|
||||
|
||||
Q_LOGGING_CATEGORY(lcConflict, "nextcloud.gui.conflictsolver", QtInfoMsg)
|
||||
|
||||
ConflictSolver::ConflictSolver(QWidget *parent)
|
||||
: QObject(parent)
|
||||
, _parentWidget(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QString ConflictSolver::localVersionFilename() const
|
||||
{
|
||||
return _localVersionFilename;
|
||||
}
|
||||
|
||||
QString ConflictSolver::remoteVersionFilename() const
|
||||
{
|
||||
return _remoteVersionFilename;
|
||||
}
|
||||
|
||||
bool ConflictSolver::exec(ConflictSolver::Solution solution)
|
||||
{
|
||||
switch (solution) {
|
||||
case KeepLocalVersion:
|
||||
return overwriteRemoteVersion();
|
||||
case KeepRemoteVersion:
|
||||
return deleteLocalVersion();
|
||||
case KeepBothVersions:
|
||||
return renameLocalVersion();
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConflictSolver::setLocalVersionFilename(const QString &localVersionFilename)
|
||||
{
|
||||
if (_localVersionFilename == localVersionFilename) {
|
||||
return;
|
||||
}
|
||||
|
||||
_localVersionFilename = localVersionFilename;
|
||||
emit localVersionFilenameChanged();
|
||||
}
|
||||
|
||||
void ConflictSolver::setRemoteVersionFilename(const QString &remoteVersionFilename)
|
||||
{
|
||||
if (_remoteVersionFilename == remoteVersionFilename) {
|
||||
return;
|
||||
}
|
||||
|
||||
_remoteVersionFilename = remoteVersionFilename;
|
||||
emit remoteVersionFilenameChanged();
|
||||
}
|
||||
|
||||
bool ConflictSolver::deleteLocalVersion()
|
||||
{
|
||||
if (_localVersionFilename.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo info(_localVersionFilename);
|
||||
if (!info.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto message = info.isDir() ? tr("Do you want to delete the directory <i>%1</i> and all its contents permanently?").arg(info.dir().dirName())
|
||||
: tr("Do you want to delete the file <i>%1</i> permanently?").arg(info.fileName());
|
||||
const auto result = QMessageBox::question(_parentWidget, tr("Confirm deletion"), message, QMessageBox::Yes, QMessageBox::No);
|
||||
if (result != QMessageBox::Yes)
|
||||
return false;
|
||||
|
||||
if (info.isDir()) {
|
||||
return FileSystem::removeRecursively(_localVersionFilename);
|
||||
} else {
|
||||
return QFile(_localVersionFilename).remove();
|
||||
}
|
||||
}
|
||||
|
||||
bool ConflictSolver::renameLocalVersion()
|
||||
{
|
||||
if (_localVersionFilename.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo info(_localVersionFilename);
|
||||
if (!info.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto renamePattern = [=] {
|
||||
auto result = QString::fromUtf8(OCC::Utility::conflictFileBaseNameFromPattern(_localVersionFilename.toUtf8()));
|
||||
const auto dotIndex = result.lastIndexOf('.');
|
||||
return QString(result.left(dotIndex) + "_%1" + result.mid(dotIndex));
|
||||
}();
|
||||
|
||||
const auto targetFilename = [=] {
|
||||
uint i = 1;
|
||||
auto result = renamePattern.arg(i);
|
||||
while (QFileInfo::exists(result)) {
|
||||
Q_ASSERT(i > 0);
|
||||
i++;
|
||||
result = renamePattern.arg(i);
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
|
||||
QString error;
|
||||
if (FileSystem::uncheckedRenameReplace(_localVersionFilename, targetFilename, &error)) {
|
||||
return true;
|
||||
} else {
|
||||
qCWarning(lcConflict) << "Rename error:" << error;
|
||||
QMessageBox::warning(_parentWidget, tr("Error"), tr("Moving file failed:\n\n%1").arg(error));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ConflictSolver::overwriteRemoteVersion()
|
||||
{
|
||||
if (_localVersionFilename.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_remoteVersionFilename.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo info(_localVersionFilename);
|
||||
if (!info.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QString error;
|
||||
if (FileSystem::uncheckedRenameReplace(_localVersionFilename, _remoteVersionFilename, &error)) {
|
||||
return true;
|
||||
} else {
|
||||
qCWarning(lcConflict) << "Rename error:" << error;
|
||||
QMessageBox::warning(_parentWidget, tr("Error"), tr("Moving file failed:\n\n%1").arg(error));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
63
src/gui/conflictsolver.h
Normal file
63
src/gui/conflictsolver.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) by Kevin Ottens <kevin.ottens@nextcloud.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef CONFLICTSOLVER_H
|
||||
#define CONFLICTSOLVER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class QWidget;
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class ConflictSolver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString localVersionFilename READ localVersionFilename WRITE setLocalVersionFilename NOTIFY localVersionFilenameChanged)
|
||||
Q_PROPERTY(QString remoteVersionFilename READ remoteVersionFilename WRITE setRemoteVersionFilename NOTIFY remoteVersionFilenameChanged)
|
||||
public:
|
||||
enum Solution {
|
||||
KeepLocalVersion,
|
||||
KeepRemoteVersion,
|
||||
KeepBothVersions
|
||||
};
|
||||
|
||||
explicit ConflictSolver(QWidget *parent = nullptr);
|
||||
|
||||
QString localVersionFilename() const;
|
||||
QString remoteVersionFilename() const;
|
||||
|
||||
bool exec(Solution solution);
|
||||
|
||||
public slots:
|
||||
void setLocalVersionFilename(const QString &localVersionFilename);
|
||||
void setRemoteVersionFilename(const QString &remoteVersionFilename);
|
||||
|
||||
signals:
|
||||
void localVersionFilenameChanged();
|
||||
void remoteVersionFilenameChanged();
|
||||
|
||||
private:
|
||||
bool deleteLocalVersion();
|
||||
bool renameLocalVersion();
|
||||
bool overwriteRemoteVersion();
|
||||
|
||||
QWidget *_parentWidget;
|
||||
QString _localVersionFilename;
|
||||
QString _remoteVersionFilename;
|
||||
};
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
#endif // CONFLICTSOLVER_H
|
||||
@@ -82,6 +82,7 @@ void Flow2Auth::fetchNewToken(const TokenAction action)
|
||||
// add 'Content-Length: 0' header (see https://github.com/nextcloud/desktop/issues/1473)
|
||||
QNetworkRequest req;
|
||||
req.setHeader(QNetworkRequest::ContentLengthHeader, "0");
|
||||
req.setHeader(QNetworkRequest::UserAgentHeader, Utility::friendlyUserAgentString());
|
||||
|
||||
auto job = _account->sendRequest("POST", url, req);
|
||||
job->setTimeout(qMin(30 * 1000ll, job->timeoutMsec()));
|
||||
|
||||
@@ -77,8 +77,8 @@ private:
|
||||
QString _pollToken;
|
||||
QString _pollEndpoint;
|
||||
QTimer _pollTimer;
|
||||
int _secondsLeft;
|
||||
int _secondsInterval;
|
||||
qint64 _secondsLeft;
|
||||
qint64 _secondsInterval;
|
||||
bool _isBusy;
|
||||
bool _hasToken;
|
||||
};
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#include "owncloudgui.h"
|
||||
#include "syncengine.h"
|
||||
|
||||
#include <keychain.h>
|
||||
#include <qt5keychain/keychain.h>
|
||||
|
||||
using namespace QKeychain;
|
||||
|
||||
|
||||
@@ -85,10 +85,7 @@ static void addSettingsToJob(Account *account, QKeychain::Job *job)
|
||||
}
|
||||
#endif
|
||||
|
||||
WebFlowCredentials::WebFlowCredentials()
|
||||
{
|
||||
|
||||
}
|
||||
WebFlowCredentials::WebFlowCredentials() = default;
|
||||
|
||||
WebFlowCredentials::WebFlowCredentials(const QString &user, const QString &password, const QSslCertificate &certificate, const QSslKey &key, const QList<QSslCertificate> &caCertificates)
|
||||
: _user(user)
|
||||
@@ -252,6 +249,7 @@ void WebFlowCredentials::persist() {
|
||||
|
||||
void WebFlowCredentials::slotWriteClientCertPEMJobDone(KeychainChunk::WriteJob *writeJob)
|
||||
{
|
||||
Q_UNUSED(writeJob)
|
||||
// write ssl key if there is one
|
||||
if (!_clientSslKey.isNull()) {
|
||||
auto job = new KeychainChunk::WriteJob(_account,
|
||||
@@ -298,6 +296,7 @@ void WebFlowCredentials::writeSingleClientCaCertPEM()
|
||||
|
||||
void WebFlowCredentials::slotWriteClientKeyPEMJobDone(KeychainChunk::WriteJob *writeJob)
|
||||
{
|
||||
Q_UNUSED(writeJob)
|
||||
_clientSslCaCertificatesWriteQueue.clear();
|
||||
|
||||
// write ca certs if there are any
|
||||
|
||||
@@ -159,6 +159,7 @@ void WebFlowCredentialsDialog::slotShowSettingsDialog()
|
||||
|
||||
void WebFlowCredentialsDialog::slotFlow2AuthResult(Flow2Auth::Result r, const QString &errorString, const QString &user, const QString &appPassword)
|
||||
{
|
||||
Q_UNUSED(errorString)
|
||||
if(r == Flow2Auth::LoggedIn) {
|
||||
emit urlCatched(user, appPassword, QString());
|
||||
} else {
|
||||
|
||||
@@ -441,7 +441,7 @@ int Folder::slotDiscardDownloadProgress()
|
||||
QSet<QString> keep_nothing;
|
||||
const QVector<SyncJournalDb::DownloadInfo> deleted_infos =
|
||||
_journal.getAndDeleteStaleDownloadInfos(keep_nothing);
|
||||
foreach (const SyncJournalDb::DownloadInfo &deleted_info, deleted_infos) {
|
||||
for (const auto &deleted_info : deleted_infos) {
|
||||
const QString tmppath = folderpath.filePath(deleted_info._tmpfile);
|
||||
qCInfo(lcFolder) << "Deleting temporary file: " << tmppath;
|
||||
FileSystem::remove(tmppath);
|
||||
@@ -528,13 +528,10 @@ void Folder::saveToSettings() const
|
||||
// This ensures that older clients will not read a configuration
|
||||
// where two folders for different accounts point at the same
|
||||
// local folders.
|
||||
bool oneAccountOnly = true;
|
||||
foreach (Folder *other, FolderMan::instance()->map()) {
|
||||
if (other != this && other->cleanPath() == this->cleanPath()) {
|
||||
oneAccountOnly = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const auto folderMap = FolderMan::instance()->map();
|
||||
const auto oneAccountOnly = std::none_of(folderMap.cbegin(), folderMap.cend(), [this](const auto *other) {
|
||||
return other != this && other->cleanPath() == this->cleanPath();
|
||||
});
|
||||
|
||||
bool compatible = _saveBackwardsCompatible || oneAccountOnly;
|
||||
|
||||
@@ -901,43 +898,6 @@ void Folder::slotItemCompleted(const SyncFileItemPtr &item)
|
||||
return;
|
||||
}
|
||||
|
||||
// add new directories or remove gone away dirs to the watcher
|
||||
if (_folderWatcher && item->isDirectory()) {
|
||||
switch (item->_instruction) {
|
||||
case CSYNC_INSTRUCTION_NEW:
|
||||
_folderWatcher->addPath(path() + item->_file);
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_REMOVE:
|
||||
_folderWatcher->removePath(path() + item->_file);
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_RENAME:
|
||||
_folderWatcher->removePath(path() + item->_file);
|
||||
_folderWatcher->addPath(path() + item->destination());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Success and failure of sync items adjust what the next sync is
|
||||
// supposed to do.
|
||||
//
|
||||
// For successes, we want to wipe the file from the list to ensure we don't
|
||||
// rediscover it even if this overall sync fails.
|
||||
//
|
||||
// For failures, we want to add the file to the list so the next sync
|
||||
// will be able to retry it.
|
||||
if (item->_status == SyncFileItem::Success
|
||||
|| item->_status == SyncFileItem::FileIgnored
|
||||
|| item->_status == SyncFileItem::Restoration
|
||||
|| item->_status == SyncFileItem::Conflict) {
|
||||
if (_previousLocalDiscoveryPaths.erase(item->_file.toUtf8()))
|
||||
qCDebug(lcFolder) << "local discovery: wiped" << item->_file;
|
||||
} else {
|
||||
_localDiscoveryPaths.insert(item->_file.toUtf8());
|
||||
qCDebug(lcFolder) << "local discovery: inserted" << item->_file << "due to sync failure";
|
||||
}
|
||||
|
||||
_syncResult.processCompletedItem(item);
|
||||
|
||||
_fileLog->logItem(*item);
|
||||
@@ -1080,6 +1040,7 @@ void Folder::registerFolderWatcher()
|
||||
connect(_folderWatcher.data(), &FolderWatcher::becameUnreliable,
|
||||
this, &Folder::slotWatcherUnreliable);
|
||||
_folderWatcher->init(path());
|
||||
_folderWatcher->startNotificatonTest(path() + QLatin1String(".owncloudsync.log"));
|
||||
}
|
||||
|
||||
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction dir, bool *cancel)
|
||||
@@ -1207,7 +1168,7 @@ QString FolderDefinition::absoluteJournalPath() const
|
||||
|
||||
QString FolderDefinition::defaultJournalPath(AccountPtr account)
|
||||
{
|
||||
return SyncJournalDb::makeDbName(account->url(), targetPath, account->credentials()->user());
|
||||
return SyncJournalDb::makeDbName(localPath, account->url(), targetPath, account->credentials()->user());
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
QString alias;
|
||||
/// path on local machine
|
||||
QString localPath;
|
||||
/// path to the journal, usually in QStandardPaths::AppDataLocation
|
||||
/// path to the journal, usually relative to localPath
|
||||
QString journalPath;
|
||||
/// path on remote
|
||||
QString targetPath;
|
||||
@@ -95,8 +95,8 @@ public:
|
||||
|
||||
~Folder();
|
||||
|
||||
typedef QMap<QString, Folder *> Map;
|
||||
typedef QMapIterator<QString, Folder *> MapIterator;
|
||||
using Map = QMap<QString, Folder *>;
|
||||
using MapIterator = QMapIterator<QString, Folder *>;
|
||||
|
||||
/**
|
||||
* The account the folder is configured on.
|
||||
|
||||
@@ -171,7 +171,7 @@ int FolderMan::setupFolders()
|
||||
|
||||
qCInfo(lcFolderMan) << "Setup folders from settings file";
|
||||
|
||||
foreach (const auto &account, AccountManager::instance()->accounts()) {
|
||||
for (const auto &account : AccountManager::instance()->accounts()) {
|
||||
const auto id = account->account()->id();
|
||||
if (!accountsWithSettings.contains(id)) {
|
||||
continue;
|
||||
@@ -197,7 +197,7 @@ int FolderMan::setupFolders()
|
||||
|
||||
void FolderMan::setupFoldersHelper(QSettings &settings, AccountStatePtr account, bool backwardsCompatible)
|
||||
{
|
||||
foreach (const auto &folderAlias, settings.childGroups()) {
|
||||
for (const auto &folderAlias : settings.childGroups()) {
|
||||
FolderDefinition folderDefinition;
|
||||
if (FolderDefinition::load(settings, folderAlias, &folderDefinition)) {
|
||||
auto defaultJournalPath = folderDefinition.defaultJournalPath(account->account());
|
||||
@@ -207,11 +207,11 @@ void FolderMan::setupFoldersHelper(QSettings &settings, AccountStatePtr account,
|
||||
folderDefinition.journalPath = defaultJournalPath;
|
||||
}
|
||||
|
||||
// Migration #2: journalPath now in DataAppDir, not root of local tree (cross-platform persistent user roaming files)
|
||||
if (folderDefinition.journalPath.at(0) == QChar('.')) {
|
||||
QFile oldJournal(folderDefinition.localPath + "/" + folderDefinition.journalPath);
|
||||
QFile oldJournalShm(folderDefinition.localPath + "/" + folderDefinition.journalPath.append("-shm"));
|
||||
QFile oldJournalWal(folderDefinition.localPath + "/" + folderDefinition.journalPath.append("-wal"));
|
||||
// Migration #2: journalPath might be absolute (in DataAppDir most likely) move it back to the root of local tree
|
||||
if (folderDefinition.journalPath.at(0) != QChar('.')) {
|
||||
QFile oldJournal(folderDefinition.journalPath);
|
||||
QFile oldJournalShm(folderDefinition.journalPath + QStringLiteral("-shm"));
|
||||
QFile oldJournalWal(folderDefinition.journalPath + QStringLiteral("-wal"));
|
||||
|
||||
folderDefinition.journalPath = defaultJournalPath;
|
||||
|
||||
@@ -221,17 +221,17 @@ void FolderMan::setupFoldersHelper(QSettings &settings, AccountStatePtr account,
|
||||
auto journalFileMoveSuccess = true;
|
||||
// Due to db logic can't be sure which of these file exist.
|
||||
if (oldJournal.exists()) {
|
||||
journalFileMoveSuccess &= oldJournal.rename(folderDefinition.journalPath);
|
||||
journalFileMoveSuccess &= oldJournal.rename(folderDefinition.localPath + "/" + folderDefinition.journalPath);
|
||||
}
|
||||
if (oldJournalShm.exists()) {
|
||||
journalFileMoveSuccess &= oldJournalShm.rename(folderDefinition.journalPath.append("-shm"));
|
||||
journalFileMoveSuccess &= oldJournalShm.rename(folderDefinition.localPath + "/" + folderDefinition.journalPath + QStringLiteral("-shm"));
|
||||
}
|
||||
if (oldJournalWal.exists()) {
|
||||
journalFileMoveSuccess &= oldJournalWal.rename(folderDefinition.journalPath.append("-wal"));
|
||||
journalFileMoveSuccess &= oldJournalWal.rename(folderDefinition.localPath + "/" + folderDefinition.journalPath + QStringLiteral("-wal"));
|
||||
}
|
||||
|
||||
if (!journalFileMoveSuccess) {
|
||||
qCWarning(lcFolderMan) << "Wasn't able to move pre-2.7 syncjournal database files to new location. One-time loss off sync settings possible.";
|
||||
qCWarning(lcFolderMan) << "Wasn't able to move 3.0 syncjournal database files to new location. One-time loss off sync settings possible.";
|
||||
} else {
|
||||
qCInfo(lcFolderMan) << "Successfully migrated syncjournal database.";
|
||||
}
|
||||
@@ -280,11 +280,11 @@ int FolderMan::setupFoldersMigration()
|
||||
QDir dir(_folderConfigPath);
|
||||
//We need to include hidden files just in case the alias starts with '.'
|
||||
dir.setFilter(QDir::Files | QDir::Hidden);
|
||||
QStringList list = dir.entryList();
|
||||
const auto list = dir.entryList();
|
||||
|
||||
// Normally there should be only one account when migrating.
|
||||
AccountState *accountState = AccountManager::instance()->accounts().value(0).data();
|
||||
foreach (const QString &alias, list) {
|
||||
for (const auto &alias : list) {
|
||||
Folder *f = setupFolderFromOldConfigFile(alias, accountState);
|
||||
if (f) {
|
||||
scheduleFolder(f);
|
||||
@@ -508,7 +508,7 @@ Folder *FolderMan::folder(const QString &alias)
|
||||
|
||||
void FolderMan::scheduleAllFolders()
|
||||
{
|
||||
foreach (Folder *f, _folderMap.values()) {
|
||||
for (Folder *f : _folderMap.values()) {
|
||||
if (f && f->canSync()) {
|
||||
scheduleFolder(f);
|
||||
}
|
||||
@@ -595,7 +595,7 @@ void FolderMan::slotRunOneEtagJob()
|
||||
{
|
||||
if (_currentEtagJob.isNull()) {
|
||||
Folder *folder = nullptr;
|
||||
foreach (Folder *f, _folderMap) {
|
||||
for (Folder *f : qAsConst(_folderMap)) {
|
||||
if (f->etagJob()) {
|
||||
// Caveat: always grabs the first folder with a job, but we think this is Ok for now and avoids us having a seperate queue.
|
||||
_currentEtagJob = f->etagJob();
|
||||
@@ -628,7 +628,7 @@ void FolderMan::slotAccountStateChanged()
|
||||
if (accountState->isConnected()) {
|
||||
qCInfo(lcFolderMan) << "Account" << accountName << "connected, scheduling its folders";
|
||||
|
||||
foreach (Folder *f, _folderMap.values()) {
|
||||
for (Folder *f : _folderMap.values()) {
|
||||
if (f
|
||||
&& f->canSync()
|
||||
&& f->accountState() == accountState) {
|
||||
@@ -758,7 +758,7 @@ void FolderMan::slotEtagPollTimerTimeout()
|
||||
ConfigFile cfg;
|
||||
auto polltime = cfg.remotePollInterval();
|
||||
|
||||
foreach (Folder *f, _folderMap) {
|
||||
for (Folder *f : qAsConst(_folderMap)) {
|
||||
if (!f) {
|
||||
continue;
|
||||
}
|
||||
@@ -793,7 +793,7 @@ void FolderMan::slotRemoveFoldersForAccount(AccountState *accountState)
|
||||
}
|
||||
}
|
||||
|
||||
foreach (const auto &f, foldersToRemove) {
|
||||
for (const auto &f : qAsConst(foldersToRemove)) {
|
||||
removeFolder(f);
|
||||
}
|
||||
emit folderListChanged(_folderMap);
|
||||
@@ -813,7 +813,7 @@ void FolderMan::slotServerVersionChanged(Account *account)
|
||||
qCWarning(lcFolderMan) << "The server version is unsupported:" << account->serverVersion()
|
||||
<< "pausing all folders on the account";
|
||||
|
||||
foreach (auto &f, _folderMap) {
|
||||
for (auto &f : qAsConst(_folderMap)) {
|
||||
if (f->accountState()->account().data() == account) {
|
||||
f->setSyncPaused(true);
|
||||
}
|
||||
@@ -830,7 +830,7 @@ void FolderMan::slotWatchedFileUnlocked(const QString &path)
|
||||
|
||||
void FolderMan::slotScheduleFolderByTime()
|
||||
{
|
||||
foreach (auto &f, _folderMap) {
|
||||
for (const auto &f : qAsConst(_folderMap)) {
|
||||
// Never schedule if syncing is disabled or when we're currently
|
||||
// querying the server for etags
|
||||
if (!f->canSync() || f->etagJob()) {
|
||||
@@ -913,13 +913,11 @@ Folder *FolderMan::addFolder(AccountState *accountState, const FolderDefinition
|
||||
|
||||
// Migration: The first account that's configured for a local folder shall
|
||||
// be saved in a backwards-compatible way.
|
||||
bool oneAccountOnly = true;
|
||||
foreach (Folder *other, FolderMan::instance()->map()) {
|
||||
if (other != folder && other->cleanPath() == folder->cleanPath()) {
|
||||
oneAccountOnly = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const auto folderList = FolderMan::instance()->map();
|
||||
const auto oneAccountOnly = std::none_of(folderList.cbegin(), folderList.cend(), [this, folder](const auto *other) {
|
||||
return other != folder && other->cleanPath() == folder->cleanPath();
|
||||
});
|
||||
|
||||
folder->setSaveBackwardsCompatible(oneAccountOnly);
|
||||
|
||||
if (folder) {
|
||||
@@ -976,22 +974,20 @@ Folder *FolderMan::folderForPath(const QString &path)
|
||||
{
|
||||
QString absolutePath = QDir::cleanPath(path) + QLatin1Char('/');
|
||||
|
||||
foreach (Folder *folder, this->map().values()) {
|
||||
const auto folders = this->map().values();
|
||||
const auto it = std::find_if(folders.cbegin(), folders.cend(), [absolutePath](const auto *folder) {
|
||||
const QString folderPath = folder->cleanPath() + QLatin1Char('/');
|
||||
return absolutePath.startsWith(folderPath, (Utility::isWindows() || Utility::isMac()) ? Qt::CaseInsensitive : Qt::CaseSensitive);
|
||||
});
|
||||
|
||||
if (absolutePath.startsWith(folderPath, (Utility::isWindows() || Utility::isMac()) ? Qt::CaseInsensitive : Qt::CaseSensitive)) {
|
||||
return folder;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return it != folders.cend() ? *it : nullptr;
|
||||
}
|
||||
|
||||
QStringList FolderMan::findFileInLocalFolders(const QString &relPath, const AccountPtr acc)
|
||||
{
|
||||
QStringList re;
|
||||
|
||||
foreach (Folder *folder, this->map().values()) {
|
||||
for (Folder *folder : this->map().values()) {
|
||||
if (acc && folder->accountState()->account() != acc) {
|
||||
continue;
|
||||
}
|
||||
@@ -1134,7 +1130,7 @@ void FolderMan::slotWipeFolderForAccount(AccountState *accountState)
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
foreach (const auto &f, foldersToRemove) {
|
||||
for (const auto &f : qAsConst(foldersToRemove)) {
|
||||
if (!f) {
|
||||
qCCritical(lcFolderMan) << "Can not remove null folder";
|
||||
return;
|
||||
@@ -1190,7 +1186,7 @@ void FolderMan::slotWipeFolderForAccount(AccountState *accountState)
|
||||
|
||||
void FolderMan::setDirtyProxy()
|
||||
{
|
||||
foreach (Folder *f, _folderMap.values()) {
|
||||
for (const Folder *f : _folderMap.values()) {
|
||||
if (f) {
|
||||
if (f->accountState() && f->accountState()->account()
|
||||
&& f->accountState()->account()->networkAccessManager()) {
|
||||
@@ -1204,7 +1200,7 @@ void FolderMan::setDirtyProxy()
|
||||
|
||||
void FolderMan::setDirtyNetworkLimits()
|
||||
{
|
||||
foreach (Folder *f, _folderMap.values()) {
|
||||
for (Folder *f : _folderMap.values()) {
|
||||
// set only in busy folders. Otherwise they read the config anyway.
|
||||
if (f && f->isBusy()) {
|
||||
f->setDirtyNetworkLimits();
|
||||
@@ -1255,7 +1251,7 @@ void FolderMan::trayOverallStatus(const QList<Folder *> &folders,
|
||||
int runSeen = 0;
|
||||
int various = 0;
|
||||
|
||||
foreach (Folder *folder, folders) {
|
||||
for (const Folder *folder : qAsConst(folders)) {
|
||||
SyncResult folderResult = folder->syncResult();
|
||||
if (folder->syncPaused()) {
|
||||
abortOrPausedSeen++;
|
||||
@@ -1478,7 +1474,7 @@ void FolderMan::setIgnoreHiddenFiles(bool ignore)
|
||||
{
|
||||
// Note that the setting will revert to 'true' if all folders
|
||||
// are deleted...
|
||||
foreach (Folder *folder, _folderMap) {
|
||||
for (Folder *folder : qAsConst(_folderMap)) {
|
||||
folder->setIgnoreHiddenFiles(ignore);
|
||||
folder->saveToSettings();
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ void FolderStatusModel::setAccountState(const AccountState *accountState)
|
||||
Qt::ItemFlags FolderStatusModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!_accountState) {
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
switch (classify(index)) {
|
||||
case AddButton: {
|
||||
@@ -120,7 +120,7 @@ Qt::ItemFlags FolderStatusModel::flags(const QModelIndex &index) const
|
||||
case SubFolder:
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable;
|
||||
}
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
|
||||
@@ -250,9 +250,7 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
|
||||
if (f->syncPaused()) {
|
||||
return theme->folderDisabledIcon();
|
||||
} else {
|
||||
if (status == SyncResult::SyncPrepare) {
|
||||
return theme->syncStateIcon(SyncResult::SyncRunning);
|
||||
} else if (status == SyncResult::Undefined) {
|
||||
if (status == SyncResult::SyncPrepare || status == SyncResult::Undefined) {
|
||||
return theme->syncStateIcon(SyncResult::SyncRunning);
|
||||
} else {
|
||||
// The "Problem" *result* just means some files weren't
|
||||
@@ -409,24 +407,6 @@ FolderStatusModel::SubFolderInfo *FolderStatusModel::infoForIndex(const QModelIn
|
||||
}
|
||||
}
|
||||
|
||||
/* Recursivelly traverse the file info looking for the id */
|
||||
FolderStatusModel::SubFolderInfo *FolderStatusModel::infoForFileId(const QByteArray& fileId, SubFolderInfo* info) const
|
||||
{
|
||||
const QVector<SubFolderInfo>& infoVec = info ? info->_subs : _folders;
|
||||
for(int i = 0, end = infoVec.size(); i < end; i++) {
|
||||
auto *info = const_cast<SubFolderInfo *>(&infoVec[i]);
|
||||
if (info->_fileId == fileId) {
|
||||
return info;
|
||||
} else if (info->_subs.size()) {
|
||||
if (auto *subInfo = infoForFileId(fileId, info)) {
|
||||
return subInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QModelIndex FolderStatusModel::indexForPath(Folder *f, const QString &path) const
|
||||
{
|
||||
if (!f) {
|
||||
@@ -748,8 +728,8 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
for (auto it = undecidedIndexes.begin(); it != undecidedIndexes.end(); ++it) {
|
||||
suggestExpand(index(*it, 0, idx));
|
||||
for (int undecidedIndex : qAsConst(undecidedIndexes)) {
|
||||
suggestExpand(index(undecidedIndex, 0, idx));
|
||||
}
|
||||
|
||||
/* We need lambda function for the following code.
|
||||
@@ -1090,7 +1070,7 @@ void FolderStatusModel::slotFolderSyncStateChange(Folder *f)
|
||||
auto &pi = _folders[folderIndex]._progress;
|
||||
|
||||
SyncResult::Status state = f->syncResult().status();
|
||||
if (!f->canSync()) {
|
||||
if (!f->canSync() || state == SyncResult::Problem || state == SyncResult::Success || state == SyncResult::Error) {
|
||||
// Reset progress info.
|
||||
pi = SubFolderInfo::Progress();
|
||||
} else if (state == SyncResult::NotYetStarted) {
|
||||
@@ -1111,11 +1091,6 @@ void FolderStatusModel::slotFolderSyncStateChange(Folder *f)
|
||||
} else if (state == SyncResult::SyncPrepare) {
|
||||
pi = SubFolderInfo::Progress();
|
||||
pi._overallSyncString = tr("Preparing to sync …");
|
||||
} else if (state == SyncResult::Problem || state == SyncResult::Success) {
|
||||
// Reset the progress info after a sync.
|
||||
pi = SubFolderInfo::Progress();
|
||||
} else if (state == SyncResult::Error) {
|
||||
pi = SubFolderInfo::Progress();
|
||||
}
|
||||
|
||||
// update the icon etc. now
|
||||
|
||||
@@ -105,7 +105,6 @@ public:
|
||||
FetchLabel };
|
||||
ItemType classify(const QModelIndex &index) const;
|
||||
SubFolderInfo *infoForIndex(const QModelIndex &index) const;
|
||||
SubFolderInfo *infoForFileId(const QByteArray &fileId, SubFolderInfo *info = nullptr) const;
|
||||
// If the selective sync check boxes were changed
|
||||
bool isDirty() { return _dirty; }
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// event masks
|
||||
#include "folderwatcher.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QFlags>
|
||||
@@ -33,6 +33,7 @@
|
||||
#endif
|
||||
|
||||
#include "folder.h"
|
||||
#include "filesystem.h"
|
||||
|
||||
namespace OCC {
|
||||
|
||||
@@ -60,7 +61,7 @@ bool FolderWatcher::pathIsIgnored(const QString &path)
|
||||
return false;
|
||||
|
||||
#ifndef OWNCLOUD_TEST
|
||||
if (_folder->isFileExcludedAbsolute(path)) {
|
||||
if (_folder->isFileExcludedAbsolute(path) && !Utility::isConflictFile(path)) {
|
||||
qCDebug(lcFolderWatcher) << "* Ignoring file" << path;
|
||||
return true;
|
||||
}
|
||||
@@ -86,6 +87,57 @@ void FolderWatcher::appendSubPaths(QDir dir, QStringList& subPaths) {
|
||||
}
|
||||
}
|
||||
|
||||
void FolderWatcher::startNotificatonTest(const QString &path)
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
// Testing the folder watcher on OSX is harder because the watcher
|
||||
// automatically discards changes that were performed by our process.
|
||||
// It would still be useful to test but the OSX implementation
|
||||
// is deferred until later.
|
||||
return;
|
||||
#endif
|
||||
|
||||
Q_ASSERT(_testNotificationPath.isEmpty());
|
||||
_testNotificationPath = path;
|
||||
|
||||
// Don't do the local file modification immediately:
|
||||
// wait for FolderWatchPrivate::_ready
|
||||
startNotificationTestWhenReady();
|
||||
}
|
||||
|
||||
void FolderWatcher::startNotificationTestWhenReady()
|
||||
{
|
||||
if (!_d->_ready) {
|
||||
QTimer::singleShot(1000, this, &FolderWatcher::startNotificationTestWhenReady);
|
||||
return;
|
||||
}
|
||||
|
||||
auto path = _testNotificationPath;
|
||||
if (QFile::exists(path)) {
|
||||
auto mtime = FileSystem::getModTime(path);
|
||||
FileSystem::setModTime(path, mtime + 1);
|
||||
} else {
|
||||
QFile f(path);
|
||||
f.open(QIODevice::WriteOnly | QIODevice::Append);
|
||||
}
|
||||
|
||||
QTimer::singleShot(5000, this, [this]() {
|
||||
if (!_testNotificationPath.isEmpty())
|
||||
emit becameUnreliable(tr("The watcher did not receive a test notification."));
|
||||
_testNotificationPath.clear();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
int FolderWatcher::testLinuxWatchCount() const
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
return _d->testWatchCount();
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void FolderWatcher::changeDetected(const QString &path)
|
||||
{
|
||||
QFileInfo fileInfo(path);
|
||||
@@ -118,6 +170,10 @@ void FolderWatcher::changeDetected(const QStringList &paths)
|
||||
// ------- handle ignores:
|
||||
for (int i = 0; i < paths.size(); ++i) {
|
||||
QString path = paths[i];
|
||||
if (!_testNotificationPath.isEmpty()
|
||||
&& Utility::fileNamesEqual(path, _testNotificationPath)) {
|
||||
_testNotificationPath.clear();
|
||||
}
|
||||
if (pathIsIgnored(path)) {
|
||||
continue;
|
||||
}
|
||||
@@ -134,15 +190,4 @@ void FolderWatcher::changeDetected(const QStringList &paths)
|
||||
}
|
||||
}
|
||||
|
||||
void FolderWatcher::addPath(const QString &path)
|
||||
{
|
||||
_d->addPath(path);
|
||||
}
|
||||
|
||||
void FolderWatcher::removePath(const QString &path)
|
||||
{
|
||||
_d->removePath(path);
|
||||
}
|
||||
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTime>
|
||||
#include <QElapsedTimer>
|
||||
#include <QHash>
|
||||
#include <QScopedPointer>
|
||||
#include <QSet>
|
||||
@@ -44,11 +44,6 @@ class Folder;
|
||||
* for changes in the local file system. Changes are signalled
|
||||
* through the pathChanged() signal.
|
||||
*
|
||||
* Note that if new folders are created, this folderwatcher class
|
||||
* does not automatically add them to the list of monitored
|
||||
* dirs. That is the responsibility of the user of this class to
|
||||
* call addPath() with the new dir.
|
||||
*
|
||||
* @ingroup gui
|
||||
*/
|
||||
|
||||
@@ -65,14 +60,6 @@ public:
|
||||
*/
|
||||
void init(const QString &root);
|
||||
|
||||
/**
|
||||
* Not all backends are recursive by default.
|
||||
* Those need to be notified when a directory is added or removed while the watcher is disabled.
|
||||
* This is a no-op for backends that are recursive
|
||||
*/
|
||||
void addPath(const QString &);
|
||||
void removePath(const QString &);
|
||||
|
||||
/* Check if the path is ignored. */
|
||||
bool pathIsIgnored(const QString &path);
|
||||
|
||||
@@ -85,6 +72,17 @@ public:
|
||||
*/
|
||||
bool isReliable() const;
|
||||
|
||||
/**
|
||||
* Triggers a change in the path and verifies a notification arrives.
|
||||
*
|
||||
* If no notification is seen, the folderwatcher marks itself as unreliable.
|
||||
* The path must be ignored by the watcher.
|
||||
*/
|
||||
void startNotificatonTest(const QString &path);
|
||||
|
||||
/// For testing linux behavior only
|
||||
int testLinuxWatchCount() const;
|
||||
|
||||
signals:
|
||||
/** Emitted when one of the watched directories or one
|
||||
* of the contained files is changed. */
|
||||
@@ -111,18 +109,24 @@ protected slots:
|
||||
void changeDetected(const QString &path);
|
||||
void changeDetected(const QStringList &paths);
|
||||
|
||||
private slots:
|
||||
void startNotificationTestWhenReady();
|
||||
|
||||
protected:
|
||||
QHash<QString, int> _pendingPathes;
|
||||
|
||||
private:
|
||||
QScopedPointer<FolderWatcherPrivate> _d;
|
||||
QTime _timer;
|
||||
QElapsedTimer _timer;
|
||||
QSet<QString> _lastPaths;
|
||||
Folder *_folder;
|
||||
bool _isReliable = true;
|
||||
|
||||
void appendSubPaths(QDir dir, QStringList& subPaths);
|
||||
|
||||
/** Path of the expected test notification */
|
||||
QString _testNotificationPath;
|
||||
|
||||
friend class FolderWatcherPrivate;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -71,34 +71,37 @@ bool FolderWatcherPrivate::findFoldersBelow(const QDir &dir, QStringList &fullLi
|
||||
|
||||
void FolderWatcherPrivate::inotifyRegisterPath(const QString &path)
|
||||
{
|
||||
if (!path.isEmpty()) {
|
||||
int wd = inotify_add_watch(_fd, path.toUtf8().constData(),
|
||||
IN_CLOSE_WRITE | IN_ATTRIB | IN_MOVE | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT | IN_ONLYDIR);
|
||||
if (wd > -1) {
|
||||
_watches.insert(wd, path);
|
||||
} else {
|
||||
// If we're running out of memory or inotify watches, become
|
||||
// unreliable.
|
||||
if (_parent->_isReliable && (errno == ENOMEM || errno == ENOSPC)) {
|
||||
_parent->_isReliable = false;
|
||||
emit _parent->becameUnreliable(
|
||||
tr("This problem usually happens when the inotify watches are exhausted. "
|
||||
"Check the FAQ for details."));
|
||||
}
|
||||
if (path.isEmpty())
|
||||
return;
|
||||
|
||||
int wd = inotify_add_watch(_fd, path.toUtf8().constData(),
|
||||
IN_CLOSE_WRITE | IN_ATTRIB | IN_MOVE | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT | IN_ONLYDIR);
|
||||
if (wd > -1) {
|
||||
_watchToPath.insert(wd, path);
|
||||
_pathToWatch.insert(path, wd);
|
||||
} else {
|
||||
// If we're running out of memory or inotify watches, become
|
||||
// unreliable.
|
||||
if (_parent->_isReliable && (errno == ENOMEM || errno == ENOSPC)) {
|
||||
_parent->_isReliable = false;
|
||||
emit _parent->becameUnreliable(
|
||||
tr("This problem usually happens when the inotify watches are exhausted. "
|
||||
"Check the FAQ for details."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FolderWatcherPrivate::slotAddFolderRecursive(const QString &path)
|
||||
{
|
||||
if (_pathToWatch.contains(path))
|
||||
return;
|
||||
|
||||
int subdirs = 0;
|
||||
qCDebug(lcFolderWatcher) << "(+) Watcher:" << path;
|
||||
|
||||
QDir inPath(path);
|
||||
inotifyRegisterPath(inPath.absolutePath());
|
||||
|
||||
const QStringList watchedFolders = _watches.values();
|
||||
|
||||
QStringList allSubfolders;
|
||||
if (!findFoldersBelow(QDir(path), allSubfolders)) {
|
||||
qCWarning(lcFolderWatcher) << "Could not traverse all sub folders";
|
||||
@@ -107,7 +110,7 @@ void FolderWatcherPrivate::slotAddFolderRecursive(const QString &path)
|
||||
while (subfoldersIt.hasNext()) {
|
||||
QString subfolder = subfoldersIt.next();
|
||||
QDir folder(subfolder);
|
||||
if (folder.exists() && !watchedFolders.contains(folder.absolutePath())) {
|
||||
if (folder.exists() && !_pathToWatch.contains(folder.absolutePath())) {
|
||||
subdirs++;
|
||||
if (_parent->pathIsIgnored(subfolder)) {
|
||||
qCDebug(lcFolderWatcher) << "* Not adding" << folder.path();
|
||||
@@ -128,81 +131,89 @@ void FolderWatcherPrivate::slotReceivedNotification(int fd)
|
||||
{
|
||||
int len = 0;
|
||||
struct inotify_event *event = nullptr;
|
||||
int i = 0;
|
||||
size_t i = 0;
|
||||
int error = 0;
|
||||
QVarLengthArray<char, 2048> buffer(2048);
|
||||
|
||||
do {
|
||||
len = read(fd, buffer.data(), buffer.size());
|
||||
error = errno;
|
||||
/**
|
||||
* From inotify documentation:
|
||||
*
|
||||
* The behavior when the buffer given to read(2) is too
|
||||
* small to return information about the next event
|
||||
* depends on the kernel version: in kernels before 2.6.21,
|
||||
* read(2) returns 0; since kernel 2.6.21, read(2) fails with
|
||||
* the error EINVAL.
|
||||
*/
|
||||
while (len < 0 && error == EINVAL) {
|
||||
// double the buffer size
|
||||
buffer.resize(buffer.size() * 2);
|
||||
|
||||
/* and try again ... */
|
||||
len = read(fd, buffer.data(), buffer.size());
|
||||
error = errno;
|
||||
/**
|
||||
* From inotify documentation:
|
||||
*
|
||||
* The behavior when the buffer given to read(2) is too
|
||||
* small to return information about the next event
|
||||
* depends on the kernel version: in kernels before 2.6.21,
|
||||
* read(2) returns 0; since kernel 2.6.21, read(2) fails with
|
||||
* the error EINVAL.
|
||||
*/
|
||||
if (len < 0 && error == EINVAL) {
|
||||
// double the buffer size
|
||||
buffer.resize(buffer.size() * 2);
|
||||
/* and try again ... */
|
||||
continue;
|
||||
}
|
||||
} while (false);
|
||||
}
|
||||
|
||||
// reset counter
|
||||
i = 0;
|
||||
// while there are enough events in the buffer
|
||||
while (i + sizeof(struct inotify_event) < static_cast<unsigned int>(len)) {
|
||||
// iterate events in buffer
|
||||
unsigned int ulen = len;
|
||||
for (i = 0; i + sizeof(inotify_event) < ulen; i += sizeof(inotify_event) + (event ? event->len : 0)) {
|
||||
// cast an inotify_event
|
||||
event = (struct inotify_event *)&buffer[i];
|
||||
if (!event) {
|
||||
qCDebug(lcFolderWatcher) << "NULL event";
|
||||
i += sizeof(struct inotify_event);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Fire event for the path that was changed.
|
||||
if (event->len > 0 && event->wd > -1) {
|
||||
QByteArray fileName(event->name);
|
||||
if (fileName.startsWith("._sync_")
|
||||
|| fileName.startsWith(".csync_journal.db")
|
||||
|| fileName.startsWith(".owncloudsync.log")
|
||||
|| fileName.startsWith(".sync_")) {
|
||||
} else {
|
||||
const QString p = _watches[event->wd] + '/' + fileName;
|
||||
_parent->changeDetected(p);
|
||||
}
|
||||
if (event->len == 0 || event->wd <= -1)
|
||||
continue;
|
||||
QByteArray fileName(event->name);
|
||||
// Filter out journal changes - redundant with filtering in
|
||||
// FolderWatcher::pathIsIgnored.
|
||||
if (fileName.startsWith("._sync_")
|
||||
|| fileName.startsWith(".csync_journal.db")
|
||||
|| fileName.startsWith(".sync_")) {
|
||||
continue;
|
||||
}
|
||||
const QString p = _watchToPath[event->wd] + '/' + fileName;
|
||||
_parent->changeDetected(p);
|
||||
|
||||
// increment counter
|
||||
i += sizeof(struct inotify_event) + event->len;
|
||||
if ((event->mask & (IN_MOVED_TO | IN_CREATE))
|
||||
&& QFileInfo(p).isDir()
|
||||
&& !_parent->pathIsIgnored(p)) {
|
||||
slotAddFolderRecursive(p);
|
||||
}
|
||||
if (event->mask & (IN_MOVED_FROM | IN_DELETE)) {
|
||||
removeFoldersBelow(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FolderWatcherPrivate::addPath(const QString &path)
|
||||
void FolderWatcherPrivate::removeFoldersBelow(const QString &path)
|
||||
{
|
||||
slotAddFolderRecursive(path);
|
||||
}
|
||||
auto it = _pathToWatch.find(path);
|
||||
if (it == _pathToWatch.end())
|
||||
return;
|
||||
|
||||
void FolderWatcherPrivate::removePath(const QString &path)
|
||||
{
|
||||
int wid = -1;
|
||||
// Remove the inotify watch.
|
||||
QHash<int, QString>::const_iterator i = _watches.constBegin();
|
||||
QString pathSlash = path + '/';
|
||||
|
||||
while (i != _watches.constEnd()) {
|
||||
if (i.value() == path) {
|
||||
wid = i.key();
|
||||
// Remove the entry and all subentries
|
||||
while (it != _pathToWatch.end()) {
|
||||
auto itPath = it.key();
|
||||
if (!itPath.startsWith(path))
|
||||
break;
|
||||
if (itPath != path && !itPath.startsWith(pathSlash)) {
|
||||
// order is 'foo', 'foo bar', 'foo/bar'
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
if (wid > -1) {
|
||||
|
||||
auto wid = it.value();
|
||||
inotify_rm_watch(_fd, wid);
|
||||
_watches.remove(wid);
|
||||
_watchToPath.remove(wid);
|
||||
it = _pathToWatch.erase(it);
|
||||
qCDebug(lcFolderWatcher) << "Removed watch for" << itPath;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
#include "folderwatcher.h"
|
||||
|
||||
class QTimer;
|
||||
|
||||
namespace OCC {
|
||||
|
||||
/**
|
||||
@@ -33,12 +35,14 @@ class FolderWatcherPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FolderWatcherPrivate() {}
|
||||
FolderWatcherPrivate() = default;
|
||||
FolderWatcherPrivate(FolderWatcher *p, const QString &path);
|
||||
~FolderWatcherPrivate();
|
||||
|
||||
void addPath(const QString &path);
|
||||
void removePath(const QString &);
|
||||
int testWatchCount() const { return _pathToWatch.size(); }
|
||||
|
||||
/// On linux the watcher is ready when the ctor finished.
|
||||
bool _ready = true;
|
||||
|
||||
protected slots:
|
||||
void slotReceivedNotification(int fd);
|
||||
@@ -47,12 +51,14 @@ protected slots:
|
||||
protected:
|
||||
bool findFoldersBelow(const QDir &dir, QStringList &fullList);
|
||||
void inotifyRegisterPath(const QString &path);
|
||||
void removeFoldersBelow(const QString &path);
|
||||
|
||||
private:
|
||||
FolderWatcher *_parent;
|
||||
|
||||
QString _folder;
|
||||
QHash<int, QString> _watches;
|
||||
QHash<int, QString> _watchToPath;
|
||||
QMap<QString, int> _pathToWatch;
|
||||
QScopedPointer<QSocketNotifier> _socket;
|
||||
int _fd;
|
||||
};
|
||||
|
||||
@@ -33,13 +33,13 @@ public:
|
||||
FolderWatcherPrivate(FolderWatcher *p, const QString &path);
|
||||
~FolderWatcherPrivate();
|
||||
|
||||
void addPath(const QString &) {}
|
||||
void removePath(const QString &) {}
|
||||
|
||||
void startWatching();
|
||||
QStringList addCoalescedPaths(const QStringList &) const;
|
||||
void doNotifyParent(const QStringList &);
|
||||
|
||||
/// On OSX the watcher is ready when the ctor finished.
|
||||
bool _ready = true;
|
||||
|
||||
private:
|
||||
FolderWatcher *_parent;
|
||||
|
||||
|
||||
@@ -84,6 +84,8 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
||||
break;
|
||||
}
|
||||
|
||||
emit ready();
|
||||
|
||||
HANDLE handles[] = { _resultEvent, _stopEvent };
|
||||
DWORD result = WaitForMultipleObjects(
|
||||
2, handles,
|
||||
@@ -139,6 +141,8 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
||||
|
||||
if (!skip) {
|
||||
emit changed(longfile);
|
||||
} else {
|
||||
qCDebug(lcFolderWatcher) << "Skipping syncing of" << longfile;
|
||||
}
|
||||
|
||||
if (curEntry->NextEntryOffset == 0) {
|
||||
@@ -204,6 +208,8 @@ FolderWatcherPrivate::FolderWatcherPrivate(FolderWatcher *p, const QString &path
|
||||
_parent, SLOT(changeDetected(const QString &)));
|
||||
connect(_thread, SIGNAL(lostChanges()),
|
||||
_parent, SIGNAL(lostChanges()));
|
||||
connect(_thread, &WatcherThread::ready,
|
||||
this, [this]() { _ready = 1; });
|
||||
_thread->start();
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ protected:
|
||||
signals:
|
||||
void changed(const QString &path);
|
||||
void lostChanges();
|
||||
void ready();
|
||||
|
||||
private:
|
||||
QString _path;
|
||||
@@ -74,8 +75,8 @@ public:
|
||||
FolderWatcherPrivate(FolderWatcher *p, const QString &path);
|
||||
~FolderWatcherPrivate();
|
||||
|
||||
void addPath(const QString &) {}
|
||||
void removePath(const QString &) {}
|
||||
/// Set to non-zero once the WatcherThread is capturing events.
|
||||
QAtomicInt _ready;
|
||||
|
||||
private:
|
||||
FolderWatcher *_parent;
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include <QVBoxLayout>
|
||||
#include <QEvent>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
|
||||
@@ -26,18 +26,28 @@
|
||||
#if defined(BUILD_UPDATER)
|
||||
#include "updater/updater.h"
|
||||
#include "updater/ocupdater.h"
|
||||
#ifdef Q_OS_MAC
|
||||
// FIXME We should unify those, but Sparkle does everything behind the scene transparently
|
||||
#include "updater/sparkleupdater.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "ignorelisteditor.h"
|
||||
#include "common/utility.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "legalnotice.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QNetworkProxy>
|
||||
#include <QDir>
|
||||
#include <QScopedValueRollback>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <private/qzipwriter_p.h>
|
||||
|
||||
#define QTLEGACY (QT_VERSION < QT_VERSION_CHECK(5,9,0))
|
||||
|
||||
@@ -45,6 +55,87 @@
|
||||
#include <QOperatingSystemVersion>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
struct ZipEntry {
|
||||
QString localFilename;
|
||||
QString zipFilename;
|
||||
};
|
||||
|
||||
ZipEntry fileInfoToZipEntry(const QFileInfo &info)
|
||||
{
|
||||
return {
|
||||
info.absoluteFilePath(),
|
||||
info.fileName()
|
||||
};
|
||||
}
|
||||
|
||||
ZipEntry fileInfoToLogZipEntry(const QFileInfo &info)
|
||||
{
|
||||
auto entry = fileInfoToZipEntry(info);
|
||||
entry.zipFilename.prepend(QStringLiteral("logs/"));
|
||||
return entry;
|
||||
}
|
||||
|
||||
ZipEntry syncFolderToZipEntry(OCC::Folder *f)
|
||||
{
|
||||
const auto journalPath = f->journalDb()->databaseFilePath();
|
||||
const auto journalInfo = QFileInfo(journalPath);
|
||||
return fileInfoToZipEntry(journalInfo);
|
||||
}
|
||||
|
||||
QVector<ZipEntry> createFileList()
|
||||
{
|
||||
auto list = QVector<ZipEntry>();
|
||||
OCC::ConfigFile cfg;
|
||||
|
||||
list.append(fileInfoToZipEntry(QFileInfo(cfg.configFile())));
|
||||
|
||||
const auto logger = OCC::Logger::instance();
|
||||
|
||||
if (!logger->logDir().isEmpty()) {
|
||||
list.append({QString(), QStringLiteral("logs")});
|
||||
|
||||
QDir dir(logger->logDir());
|
||||
const auto infoList = dir.entryInfoList(QDir::Files);
|
||||
std::transform(std::cbegin(infoList), std::cend(infoList),
|
||||
std::back_inserter(list),
|
||||
fileInfoToLogZipEntry);
|
||||
} else if (!logger->logFile().isEmpty()) {
|
||||
list.append(fileInfoToZipEntry(QFileInfo(logger->logFile())));
|
||||
}
|
||||
|
||||
const auto folders = OCC::FolderMan::instance()->map().values();
|
||||
std::transform(std::cbegin(folders), std::cend(folders),
|
||||
std::back_inserter(list),
|
||||
syncFolderToZipEntry);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void createDebugArchive(const QString &filename)
|
||||
{
|
||||
const auto entries = createFileList();
|
||||
|
||||
QZipWriter zip(filename);
|
||||
for (const auto &entry : entries) {
|
||||
if (entry.localFilename.isEmpty()) {
|
||||
zip.addDirectory(entry.zipFilename);
|
||||
} else {
|
||||
QFile file(entry.localFilename);
|
||||
if (!file.open(QFile::ReadOnly)) {
|
||||
continue;
|
||||
}
|
||||
zip.addFile(entry.zipFilename, &file);
|
||||
}
|
||||
}
|
||||
|
||||
zip.addFile("__nextcloud_client_parameters.txt", QCoreApplication::arguments().join(' ').toUtf8());
|
||||
|
||||
const auto buildInfo = QString(OCC::Theme::instance()->about() + "\n\n" + OCC::Theme::instance()->aboutDetails());
|
||||
zip.addFile("__nextcloud_client_buildinfo.txt", buildInfo.toUtf8());
|
||||
}
|
||||
}
|
||||
|
||||
namespace OCC {
|
||||
|
||||
GeneralSettings::GeneralSettings(QWidget *parent)
|
||||
@@ -122,6 +213,7 @@ GeneralSettings::GeneralSettings(QWidget *parent)
|
||||
_ui->monoIconsCheckBox->setVisible(Theme::instance()->monoIconsAvailable());
|
||||
|
||||
connect(_ui->ignoredFilesButton, &QAbstractButton::clicked, this, &GeneralSettings::slotIgnoreFilesEditor);
|
||||
connect(_ui->debugArchiveButton, &QAbstractButton::clicked, this, &GeneralSettings::slotCreateDebugArchive);
|
||||
|
||||
// accountAdded means the wizard was finished and the wizard might change some options.
|
||||
connect(AccountManager::instance(), &AccountManager::accountAdded, this, &GeneralSettings::loadMiscSettings);
|
||||
@@ -161,34 +253,88 @@ void GeneralSettings::loadMiscSettings()
|
||||
#if defined(BUILD_UPDATER)
|
||||
void GeneralSettings::slotUpdateInfo()
|
||||
{
|
||||
// Note: the sparkle-updater is not an OCUpdater
|
||||
auto *updater = qobject_cast<OCUpdater *>(Updater::instance());
|
||||
if (ConfigFile().skipUpdateCheck()) {
|
||||
updater = nullptr; // don't show update info if updates are disabled
|
||||
if (ConfigFile().skipUpdateCheck() || !Updater::instance()) {
|
||||
// updater disabled on compile
|
||||
_ui->updatesGroupBox->setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (updater) {
|
||||
connect(updater, &OCUpdater::downloadStateChanged, this, &GeneralSettings::slotUpdateInfo, Qt::UniqueConnection);
|
||||
connect(_ui->restartButton, &QAbstractButton::clicked, updater, &OCUpdater::slotStartInstaller, Qt::UniqueConnection);
|
||||
// Note: the sparkle-updater is not an OCUpdater
|
||||
auto *ocupdater = qobject_cast<OCUpdater *>(Updater::instance());
|
||||
if (ocupdater) {
|
||||
connect(ocupdater, &OCUpdater::downloadStateChanged, this, &GeneralSettings::slotUpdateInfo, Qt::UniqueConnection);
|
||||
connect(_ui->restartButton, &QAbstractButton::clicked, ocupdater, &OCUpdater::slotStartInstaller, Qt::UniqueConnection);
|
||||
connect(_ui->restartButton, &QAbstractButton::clicked, qApp, &QApplication::quit, Qt::UniqueConnection);
|
||||
connect(_ui->updateButton, &QAbstractButton::clicked, this, &GeneralSettings::slotUpdateCheckNow, Qt::UniqueConnection);
|
||||
connect(_ui->autoCheckForUpdatesCheckBox, &QAbstractButton::toggled, this, &GeneralSettings::slotToggleAutoUpdateCheck);
|
||||
|
||||
QString status = updater->statusString();
|
||||
QString status = ocupdater->statusString();
|
||||
Theme::replaceLinkColorStringBackgroundAware(status);
|
||||
_ui->updateStateLabel->setText(status);
|
||||
|
||||
_ui->restartButton->setVisible(updater->downloadState() == OCUpdater::DownloadComplete);
|
||||
_ui->restartButton->setVisible(ocupdater->downloadState() == OCUpdater::DownloadComplete);
|
||||
|
||||
_ui->updateButton->setEnabled(updater->downloadState() != OCUpdater::CheckingServer &&
|
||||
updater->downloadState() != OCUpdater::Downloading &&
|
||||
updater->downloadState() != OCUpdater::DownloadComplete);
|
||||
_ui->updateButton->setEnabled(ocupdater->downloadState() != OCUpdater::CheckingServer &&
|
||||
ocupdater->downloadState() != OCUpdater::Downloading &&
|
||||
ocupdater->downloadState() != OCUpdater::DownloadComplete);
|
||||
|
||||
_ui->autoCheckForUpdatesCheckBox->setChecked(ConfigFile().autoUpdateCheck());
|
||||
} else {
|
||||
// can't have those infos from sparkle currently
|
||||
_ui->updatesGroupBox->setVisible(false);
|
||||
}
|
||||
#if defined(Q_OS_MAC) && defined(HAVE_SPARKLE)
|
||||
else if (auto sparkleUpdater = qobject_cast<SparkleUpdater *>(Updater::instance())) {
|
||||
_ui->updateStateLabel->setText(sparkleUpdater->statusString());
|
||||
_ui->restartButton->setVisible(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Channel selection
|
||||
_ui->updateChannel->setCurrentIndex(ConfigFile().updateChannel() == "beta" ? 1 : 0);
|
||||
connect(_ui->updateChannel, &QComboBox::currentTextChanged,
|
||||
this, &GeneralSettings::slotUpdateChannelChanged, Qt::UniqueConnection);
|
||||
}
|
||||
|
||||
void GeneralSettings::slotUpdateChannelChanged(const QString &channel)
|
||||
{
|
||||
if (channel == ConfigFile().updateChannel())
|
||||
return;
|
||||
|
||||
auto msgBox = new QMessageBox(
|
||||
QMessageBox::Warning,
|
||||
tr("Change update channel?"),
|
||||
tr("The update channel determines which client updates will be offered "
|
||||
"for installation. The \"stable\" channel contains only upgrades that "
|
||||
"are considered reliable, while the versions in the \"beta\" channel "
|
||||
"may contain newer features and bugfixes, but have not yet been tested "
|
||||
"thoroughly."
|
||||
"\n\n"
|
||||
"Note that this selects only what pool upgrades are taken from, and that "
|
||||
"there are no downgrades: So going back from the beta channel to "
|
||||
"the stable channel usually cannot be done immediately and means waiting "
|
||||
"for a stable version that is newer than the currently installed beta "
|
||||
"version."),
|
||||
QMessageBox::NoButton,
|
||||
this);
|
||||
msgBox->addButton(tr("Change update channel"), QMessageBox::AcceptRole);
|
||||
msgBox->addButton(tr("Cancel"), QMessageBox::RejectRole);
|
||||
connect(msgBox, &QMessageBox::finished, msgBox, [this, channel, msgBox](int result) {
|
||||
msgBox->deleteLater();
|
||||
if (result == QMessageBox::AcceptRole) {
|
||||
ConfigFile().setUpdateChannel(channel);
|
||||
if (auto updater = qobject_cast<OCUpdater *>(Updater::instance())) {
|
||||
updater->setUpdateUrl(Updater::updateUrl());
|
||||
updater->checkForUpdate();
|
||||
}
|
||||
#if defined(Q_OS_MAC) && defined(HAVE_SPARKLE)
|
||||
else if (auto updater = qobject_cast<SparkleUpdater *>(Updater::instance())) {
|
||||
updater->setUpdateUrl(Updater::updateUrl());
|
||||
updater->checkForUpdate();
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
_ui->updateChannel->setCurrentText(ConfigFile().updateChannel());
|
||||
}
|
||||
});
|
||||
msgBox->open();
|
||||
}
|
||||
|
||||
void GeneralSettings::slotUpdateCheckNow()
|
||||
@@ -260,6 +406,17 @@ void GeneralSettings::slotIgnoreFilesEditor()
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralSettings::slotCreateDebugArchive()
|
||||
{
|
||||
const auto filename = QFileDialog::getSaveFileName(this, tr("Create Debug Archive"), QString(), tr("Zip Archives") + " (*.zip)");
|
||||
if (filename.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
createDebugArchive(filename);
|
||||
QMessageBox::information(this, tr("Debug Archive Created"), tr("Debug archive is created at %1").arg(filename));
|
||||
}
|
||||
|
||||
void GeneralSettings::slotShowLegalNotice()
|
||||
{
|
||||
auto notice = new LegalNotice();
|
||||
|
||||
@@ -48,10 +48,12 @@ private slots:
|
||||
void slotToggleOptionalServerNotifications(bool);
|
||||
void slotShowInExplorerNavigationPane(bool);
|
||||
void slotIgnoreFilesEditor();
|
||||
void slotCreateDebugArchive();
|
||||
void loadMiscSettings();
|
||||
void slotShowLegalNotice();
|
||||
#if defined(BUILD_UPDATER)
|
||||
void slotUpdateInfo();
|
||||
void slotUpdateChannelChanged(const QString &channel);
|
||||
void slotUpdateCheckNow();
|
||||
void slotToggleAutoUpdateCheck();
|
||||
#endif
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>516</width>
|
||||
<height>523</height>
|
||||
<width>553</width>
|
||||
<height>558</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -124,26 +124,46 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Preferred</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="updateChannelLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Channel</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>updateChannel</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="updateChannel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>stable</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>beta</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="updateStateLabel">
|
||||
<property name="text">
|
||||
@@ -170,22 +190,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Preferred</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -219,6 +223,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="debugArchiveButton">
|
||||
<property name="text">
|
||||
<string>Create Debug Archive …</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
|
||||
@@ -73,7 +73,7 @@ class HeaderBanner : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
HeaderBanner(QWidget *parent = 0);
|
||||
HeaderBanner(QWidget *parent = nullptr);
|
||||
|
||||
void setup(const QString &title, const QPixmap &logo, const QPixmap &banner,
|
||||
const Qt::TextFormat titleFormat, const QString &styleSheet);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#include "logbrowser.h"
|
||||
|
||||
#include "stdio.h"
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <cmath>
|
||||
#include <signal.h>
|
||||
#include <csignal>
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#include <sys/time.h>
|
||||
|
||||
@@ -66,17 +66,18 @@ void NavigationPaneHelper::updateCloudStorageRegistry()
|
||||
// that matches ours when we saved.
|
||||
QVector<QUuid> entriesToRemove;
|
||||
#ifdef Q_OS_WIN
|
||||
Utility::registryWalkSubKeys(
|
||||
HKEY_CURRENT_USER,
|
||||
QStringLiteral("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\NameSpace"),
|
||||
[&entriesToRemove](HKEY key, const QString &subKey) {
|
||||
QVariant appName = Utility::registryGetKeyValue(key, subKey, QStringLiteral("ApplicationName"));
|
||||
if (appName.toString() == QLatin1String(APPLICATION_NAME)) {
|
||||
QUuid clsid{ subKey };
|
||||
Q_ASSERT(!clsid.isNull());
|
||||
entriesToRemove.append(clsid);
|
||||
}
|
||||
});
|
||||
QString nameSpaceKey = QStringLiteral(R"(Software\Microsoft\Windows\CurrentVersion\Explorer\Desktop\NameSpace)");
|
||||
if (Utility::registryKeyExists(HKEY_CURRENT_USER, nameSpaceKey)) {
|
||||
Utility::registryWalkSubKeys(HKEY_CURRENT_USER, nameSpaceKey,
|
||||
[&entriesToRemove](HKEY key, const QString &subKey) {
|
||||
QVariant appName = Utility::registryGetKeyValue(key, subKey, QStringLiteral("ApplicationName"));
|
||||
if (appName.toString() == QLatin1String(APPLICATION_NAME)) {
|
||||
QUuid clsid{ subKey };
|
||||
Q_ASSERT(!clsid.isNull());
|
||||
entriesToRemove.append(clsid);
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
// Only save folder entries if the option is enabled.
|
||||
@@ -138,7 +139,7 @@ void NavigationPaneHelper::updateCloudStorageRegistry()
|
||||
// Step 11: Register your extension in the namespace root
|
||||
Utility::registrySetKeyValue(HKEY_CURRENT_USER, namespacePath, QString(), REG_SZ, title);
|
||||
// Step 12: Hide your extension from the Desktop
|
||||
Utility::registrySetKeyValue(HKEY_CURRENT_USER, QStringLiteral("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\HideDesktopIcons\\NewStartPanel"), clsidStr, REG_DWORD, 0x1);
|
||||
Utility::registrySetKeyValue(HKEY_CURRENT_USER, QStringLiteral(R"(Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel)"), clsidStr, REG_DWORD, 0x1);
|
||||
|
||||
// For us, to later be able to iterate and find our own namespace entries and associated CLSID.
|
||||
// Use the macro instead of the theme to make sure it matches with the uninstaller.
|
||||
|
||||
@@ -28,7 +28,8 @@ OcsShareeJob::OcsShareeJob(AccountPtr account)
|
||||
void OcsShareeJob::getSharees(const QString &search,
|
||||
const QString &itemType,
|
||||
int page,
|
||||
int perPage)
|
||||
int perPage,
|
||||
bool lookup)
|
||||
{
|
||||
setVerb("GET");
|
||||
|
||||
@@ -36,6 +37,7 @@ void OcsShareeJob::getSharees(const QString &search,
|
||||
addParam(QString::fromLatin1("itemType"), itemType);
|
||||
addParam(QString::fromLatin1("page"), QString::number(page));
|
||||
addParam(QString::fromLatin1("perPage"), QString::number(perPage));
|
||||
addParam(QString::fromLatin1("lookup"), QVariant(lookup).toString());
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
*
|
||||
* @param path Path to request shares for (default all shares)
|
||||
*/
|
||||
void getSharees(const QString &search, const QString &itemType, int page = 1, int perPage = 50);
|
||||
void getSharees(const QString &search, const QString &itemType, int page = 1, int perPage = 50, bool lookup = false);
|
||||
signals:
|
||||
/**
|
||||
* Result of the OCS request
|
||||
|
||||
@@ -144,6 +144,7 @@ void OcsShareJob::createShare(const QString &path,
|
||||
const QString &shareWith,
|
||||
const Share::Permissions permissions)
|
||||
{
|
||||
Q_UNUSED(permissions)
|
||||
setVerb("POST");
|
||||
|
||||
addParam(QString::fromLatin1("path"), path);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user