mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2026-04-10 18:57:40 +02:00
Compare commits
1369 Commits
v2.0.2-rc2
...
v2.2.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eaeed08544 | ||
|
|
f1e2e42d99 | ||
|
|
3e1690ff7a | ||
|
|
826a675f32 | ||
|
|
323ebf9bf2 | ||
|
|
e4bf3ec19a | ||
|
|
f2721aff1d | ||
|
|
29bd8658bb | ||
|
|
8b9ca63eeb | ||
|
|
6f1b03c560 | ||
|
|
3bd3ffb8e2 | ||
|
|
a810d69daa | ||
|
|
8496817db2 | ||
|
|
3d06f4b7c9 | ||
|
|
b228488eb7 | ||
|
|
907918dca3 | ||
|
|
5ffaf3a90f | ||
|
|
1040e7b57b | ||
|
|
65c49e1de6 | ||
|
|
4abaee7736 | ||
|
|
3cdcd8dea0 | ||
|
|
cb19ebc9e3 | ||
|
|
37adaa7872 | ||
|
|
9d93afb2a1 | ||
|
|
7c24ed769e | ||
|
|
65110f7a91 | ||
|
|
c33abd468d | ||
|
|
584b205bd5 | ||
|
|
b75f50d62c | ||
|
|
14457e93e6 | ||
|
|
9c0ecad420 | ||
|
|
85b5fdb3d3 | ||
|
|
f2c6669224 | ||
|
|
d8f9bf3a0b | ||
|
|
d5fa8faa91 | ||
|
|
d1a1b95926 | ||
|
|
ee2a67e332 | ||
|
|
7362575d64 | ||
|
|
6a9b6c1167 | ||
|
|
8e00fd66de | ||
|
|
ef035ea7f9 | ||
|
|
77b5c5e963 | ||
|
|
687549c455 | ||
|
|
677c34fbf8 | ||
|
|
465639af82 | ||
|
|
583f9586aa | ||
|
|
573d942969 | ||
|
|
02df088843 | ||
|
|
cd9335e043 | ||
|
|
20531e57a8 | ||
|
|
e2e16aeaaa | ||
|
|
a46a69f250 | ||
|
|
3187a22300 | ||
|
|
9626021a63 | ||
|
|
b72a19ad64 | ||
|
|
2ae37c6beb | ||
|
|
f8f376ac03 | ||
|
|
632d231435 | ||
|
|
fc868d89f3 | ||
|
|
5a57e4a7a6 | ||
|
|
70a1671dc1 | ||
|
|
7de70516f1 | ||
|
|
50bd4b8f4f | ||
|
|
4a7f3cb486 | ||
|
|
b7663d00b9 | ||
|
|
b307f2b65c | ||
|
|
6c94d56b53 | ||
|
|
c51a80bffa | ||
|
|
87f4f70abb | ||
|
|
19a52b9e6b | ||
|
|
4ea70ebd18 | ||
|
|
b9a6970282 | ||
|
|
a58ef9c586 | ||
|
|
cef24da44c | ||
|
|
23c7f10b79 | ||
|
|
9e514d6cc7 | ||
|
|
4d109e43fa | ||
|
|
b575ded464 | ||
|
|
03a90bf03f | ||
|
|
ff7b2381e9 | ||
|
|
24cd8041a8 | ||
|
|
3eaadfe52f | ||
|
|
ebcec44202 | ||
|
|
7b0b7fde51 | ||
|
|
fa9ec12ae7 | ||
|
|
54aa4dce46 | ||
|
|
7c19f748b7 | ||
|
|
5aa82944a4 | ||
|
|
0d9cf26890 | ||
|
|
a4837e9291 | ||
|
|
5672557a84 | ||
|
|
0b31f2601d | ||
|
|
a5850d4515 | ||
|
|
c39eb315dd | ||
|
|
6c8e88e2ed | ||
|
|
eeea255104 | ||
|
|
8e2af57b57 | ||
|
|
f3f387c36b | ||
|
|
b53ce78eb6 | ||
|
|
bc4753e938 | ||
|
|
aefbca0787 | ||
|
|
653b42216f | ||
|
|
3ec9cd1d9e | ||
|
|
20d0c835b6 | ||
|
|
3335c733d7 | ||
|
|
4da55b69df | ||
|
|
b7085987b8 | ||
|
|
a1b44cd82a | ||
|
|
11b44358f6 | ||
|
|
651cc25e3f | ||
|
|
a338b9f269 | ||
|
|
81ff4e02c5 | ||
|
|
8a1a2eb5b3 | ||
|
|
0c646b974f | ||
|
|
e661bf2324 | ||
|
|
2abb5c95bb | ||
|
|
c3ef1a996f | ||
|
|
7a2a439426 | ||
|
|
ce26afb262 | ||
|
|
56e1737c61 | ||
|
|
dff57362f9 | ||
|
|
05a7c18635 | ||
|
|
3a77074b97 | ||
|
|
446e7cbd93 | ||
|
|
b4d26ba952 | ||
|
|
622017adcf | ||
|
|
088a4f0bbe | ||
|
|
ba96fb89a5 | ||
|
|
70ae11fcad | ||
|
|
86fd982b00 | ||
|
|
bdb304f8ec | ||
|
|
001075daf0 | ||
|
|
2a98aa7130 | ||
|
|
9904fb200e | ||
|
|
6822ae5bec | ||
|
|
440a804836 | ||
|
|
9b66dd7166 | ||
|
|
7601783553 | ||
|
|
c0b0bd5b63 | ||
|
|
28d86cee17 | ||
|
|
32bb8295a2 | ||
|
|
5d71ad83ec | ||
|
|
ab24980001 | ||
|
|
07dea72c37 | ||
|
|
a734be347b | ||
|
|
1443ddc7c9 | ||
|
|
191177ff22 | ||
|
|
43a2aec92b | ||
|
|
c848097c6b | ||
|
|
096e2cf233 | ||
|
|
7181aedb4b | ||
|
|
edfd75949d | ||
|
|
7fb134b4e0 | ||
|
|
87e3553c85 | ||
|
|
6f3aaecb78 | ||
|
|
40e3653722 | ||
|
|
5a4f50a0ff | ||
|
|
3342ebfcc5 | ||
|
|
b4900d60b7 | ||
|
|
92309013da | ||
|
|
4895589e4d | ||
|
|
05d199881e | ||
|
|
147cf798a6 | ||
|
|
d40c56eda5 | ||
|
|
6dade0b114 | ||
|
|
5de44407bf | ||
|
|
2df741e456 | ||
|
|
8b5f71f49e | ||
|
|
77791ccb34 | ||
|
|
a6e4f9939c | ||
|
|
523cdff1cf | ||
|
|
c4d6277ce3 | ||
|
|
70196eb48c | ||
|
|
9b249716a3 | ||
|
|
a4b46db91e | ||
|
|
ebc44fa494 | ||
|
|
355a8a0a27 | ||
|
|
ab050f9093 | ||
|
|
bf9cffe4b3 | ||
|
|
43f727cf69 | ||
|
|
256331fbaa | ||
|
|
32e6585ae6 | ||
|
|
d072e4a678 | ||
|
|
b99c8fe28b | ||
|
|
5a3120bd52 | ||
|
|
9ea69be6ab | ||
|
|
801cb42d57 | ||
|
|
51f8a59a9a | ||
|
|
ebbe5acf2b | ||
|
|
6ccd9e872d | ||
|
|
da69756bb0 | ||
|
|
1787da8a9d | ||
|
|
f0f82d02ff | ||
|
|
ff20cd4d57 | ||
|
|
9ab812f89b | ||
|
|
de82d8fcdb | ||
|
|
af2b712dc6 | ||
|
|
a507558dee | ||
|
|
e73c3199c0 | ||
|
|
d88ab4653b | ||
|
|
9a2450c4c1 | ||
|
|
3c1f5e662f | ||
|
|
100ee69ddd | ||
|
|
d45d6ca9da | ||
|
|
2608c7007e | ||
|
|
06a88ea9a4 | ||
|
|
0194ebb222 | ||
|
|
dc654ac846 | ||
|
|
370fd5062c | ||
|
|
00d20b4a42 | ||
|
|
a2b238e2e5 | ||
|
|
0e2c16e827 | ||
|
|
b9fdae6d67 | ||
|
|
c34115610e | ||
|
|
275ad1e157 | ||
|
|
1855950fa1 | ||
|
|
fff5c280b3 | ||
|
|
e960b265a8 | ||
|
|
f6b35e5d58 | ||
|
|
1d93af5f64 | ||
|
|
75efa8b252 | ||
|
|
009a0b03da | ||
|
|
8379a36a75 | ||
|
|
2f1a40ff7c | ||
|
|
c041ca6163 | ||
|
|
eacc0c8bd6 | ||
|
|
171de99e00 | ||
|
|
bf02ccc1e8 | ||
|
|
7ba961c21a | ||
|
|
cb7be78352 | ||
|
|
6cb194e0d5 | ||
|
|
552ba94c41 | ||
|
|
fc1933803e | ||
|
|
46e4ec3183 | ||
|
|
03e3b3bf50 | ||
|
|
9aed8dbce8 | ||
|
|
c6794cd338 | ||
|
|
65ec1b74d5 | ||
|
|
1a3c9a9c1a | ||
|
|
a038c99232 | ||
|
|
30c8fa1c93 | ||
|
|
010649f997 | ||
|
|
597f2a4dfc | ||
|
|
cf1fe690a3 | ||
|
|
31b27bea38 | ||
|
|
04f99f3bd7 | ||
|
|
fbf92ac239 | ||
|
|
669a72f0e1 | ||
|
|
2f0e65d37c | ||
|
|
5676685f58 | ||
|
|
db9ccb40a4 | ||
|
|
d4c15d2c38 | ||
|
|
edb3759684 | ||
|
|
0f9c32452c | ||
|
|
45dd1d0acf | ||
|
|
552af7b94d | ||
|
|
8934979ba1 | ||
|
|
b3e16e0eb0 | ||
|
|
7773380deb | ||
|
|
e22050a434 | ||
|
|
7b0231bfce | ||
|
|
edc58c045f | ||
|
|
035058934f | ||
|
|
9b1f46e560 | ||
|
|
9e7a8e619b | ||
|
|
9c0cd2b13e | ||
|
|
58ad781bd4 | ||
|
|
9d6701ecbe | ||
|
|
d659c54798 | ||
|
|
0e9170cb36 | ||
|
|
8820bc1c17 | ||
|
|
74f67c97a9 | ||
|
|
fd96b482c5 | ||
|
|
727e73d640 | ||
|
|
d7804d8df3 | ||
|
|
3d9d106bb1 | ||
|
|
15dc3408ef | ||
|
|
928643f597 | ||
|
|
7110091fdd | ||
|
|
064c2b678a | ||
|
|
e58739de00 | ||
|
|
7c2fdee78b | ||
|
|
7bfe46962f | ||
|
|
32b3023a8e | ||
|
|
a5df44c757 | ||
|
|
641125eac1 | ||
|
|
d340017a0a | ||
|
|
a67173610d | ||
|
|
e833d01288 | ||
|
|
3047682223 | ||
|
|
c91dd94728 | ||
|
|
52f9f44b51 | ||
|
|
49748191a9 | ||
|
|
e6b937f508 | ||
|
|
31c13f74fb | ||
|
|
be466b47b7 | ||
|
|
11b144957b | ||
|
|
817e97c148 | ||
|
|
29932004ae | ||
|
|
6d83e841a9 | ||
|
|
b43a9421d2 | ||
|
|
e70b78d14b | ||
|
|
6814342d1f | ||
|
|
68126dcff6 | ||
|
|
e7f00339e6 | ||
|
|
a36b4ec863 | ||
|
|
074f8eadb1 | ||
|
|
6a51ae5b1b | ||
|
|
af5f2d3860 | ||
|
|
38bad564a0 | ||
|
|
c2fa3fb4c8 | ||
|
|
f7082ee3df | ||
|
|
f7c6efb391 | ||
|
|
051a348afd | ||
|
|
d0af3ede05 | ||
|
|
0da2adcbe0 | ||
|
|
07bdd519e9 | ||
|
|
0829a94c92 | ||
|
|
faf2514be2 | ||
|
|
4ea2edcf4a | ||
|
|
cd29875b76 | ||
|
|
85bc3b276f | ||
|
|
ce5ca8a42e | ||
|
|
ce6a365328 | ||
|
|
09eea7f5f2 | ||
|
|
043350f49d | ||
|
|
f657bd0cd9 | ||
|
|
b4cf17d99d | ||
|
|
12bf6e39b7 | ||
|
|
4e7c09de83 | ||
|
|
31f2c3e76a | ||
|
|
64b6486327 | ||
|
|
335e333e28 | ||
|
|
41eb5f0a3f | ||
|
|
030184fad9 | ||
|
|
7d285d0225 | ||
|
|
d3a93322d2 | ||
|
|
8694db1c49 | ||
|
|
19eca84d4f | ||
|
|
665c3f40e1 | ||
|
|
f8f394eb0a | ||
|
|
0711abbf56 | ||
|
|
84ac2e64e0 | ||
|
|
57f0603e0e | ||
|
|
b61ae351dd | ||
|
|
277a1cfb5a | ||
|
|
6ba7c6e2d3 | ||
|
|
055c2ef73f | ||
|
|
e5a5b95b9a | ||
|
|
7acdf50a2c | ||
|
|
361ebf5464 | ||
|
|
7a82fac0d5 | ||
|
|
8b39c6e6ce | ||
|
|
e29d7e0128 | ||
|
|
dbcb94e7d4 | ||
|
|
522f7afa9e | ||
|
|
fa69d089cf | ||
|
|
1935c78f17 | ||
|
|
b56919d0c4 | ||
|
|
f72c7f43bf | ||
|
|
add29befee | ||
|
|
f9fb7a59dd | ||
|
|
1a51b6718a | ||
|
|
a3a9417630 | ||
|
|
53a72148d3 | ||
|
|
c379593c0f | ||
|
|
bd37eab3ad | ||
|
|
edb942ba61 | ||
|
|
a17f37d8ae | ||
|
|
33459b48c8 | ||
|
|
598941948c | ||
|
|
038b7db606 | ||
|
|
9f30e83413 | ||
|
|
2ab4caf007 | ||
|
|
11d3aa3c4f | ||
|
|
93ad61aeef | ||
|
|
6a36d1b4fb | ||
|
|
c0ec481436 | ||
|
|
df0833d7f9 | ||
|
|
6a9655aab6 | ||
|
|
0f3d6d4160 | ||
|
|
c4577cb2a1 | ||
|
|
fafca26144 | ||
|
|
06c19b0b6f | ||
|
|
d1649ce4df | ||
|
|
ea40e314d4 | ||
|
|
e2622310df | ||
|
|
4ad8e04bc3 | ||
|
|
74301e4373 | ||
|
|
053dcbf1f5 | ||
|
|
700c7bcbc6 | ||
|
|
bc6c57aa0b | ||
|
|
a0521caf52 | ||
|
|
8007331462 | ||
|
|
12330b38e9 | ||
|
|
8eb53fa9ae | ||
|
|
dfd7d4d2f9 | ||
|
|
484a2c800d | ||
|
|
8d300b049f | ||
|
|
48e594ebbf | ||
|
|
910c61b492 | ||
|
|
8155c1c426 | ||
|
|
97a6d3df82 | ||
|
|
f7aafb081f | ||
|
|
9cc981c8c7 | ||
|
|
ed3203d25d | ||
|
|
a4f606ceab | ||
|
|
15988c6fda | ||
|
|
f443377978 | ||
|
|
fdcdddca16 | ||
|
|
bf99306a53 | ||
|
|
844777d43f | ||
|
|
4f79f1b5e8 | ||
|
|
6f454feb39 | ||
|
|
68b7437afb | ||
|
|
41b950b7e6 | ||
|
|
2d08754f91 | ||
|
|
868edb1f0d | ||
|
|
aaf43bd0d3 | ||
|
|
d5f1d1c6b2 | ||
|
|
6cb94e8849 | ||
|
|
d433c24186 | ||
|
|
c48b5c4f61 | ||
|
|
976f4dfabe | ||
|
|
f8dc263338 | ||
|
|
e896d16f32 | ||
|
|
2ec642aadb | ||
|
|
bd3a079a7b | ||
|
|
6ee7e82913 | ||
|
|
648328fbe2 | ||
|
|
ee58cc3b66 | ||
|
|
74a75f6399 | ||
|
|
a0baca25ff | ||
|
|
4b5c9c5ee5 | ||
|
|
4ce97633cd | ||
|
|
f1732d66d6 | ||
|
|
329f512a40 | ||
|
|
c64720eac5 | ||
|
|
8f7b833c12 | ||
|
|
48bfcde97d | ||
|
|
42439490cc | ||
|
|
4dd8d61e4e | ||
|
|
271bea39ff | ||
|
|
a0827c5ef2 | ||
|
|
058cd33324 | ||
|
|
e4604b406f | ||
|
|
7b1f02fcda | ||
|
|
52a5234122 | ||
|
|
4e17dabcb6 | ||
|
|
15bdb7be64 | ||
|
|
9bdc84c6f4 | ||
|
|
252aea25da | ||
|
|
efb0faa14e | ||
|
|
5b40921587 | ||
|
|
7994b3d91a | ||
|
|
65e740301a | ||
|
|
f495daf1cf | ||
|
|
3334067d9f | ||
|
|
73e2a503d7 | ||
|
|
bc6eebddf4 | ||
|
|
434d16941b | ||
|
|
6b0d535120 | ||
|
|
8b3ea7aa97 | ||
|
|
84ad0d234e | ||
|
|
87e4370bf4 | ||
|
|
fa1bb309ca | ||
|
|
e05819370b | ||
|
|
d65808b1e1 | ||
|
|
a115f4b9d0 | ||
|
|
9ea191f63d | ||
|
|
17c645ce43 | ||
|
|
f427955512 | ||
|
|
dd8b0c3e4a | ||
|
|
6c283c7a48 | ||
|
|
c150350096 | ||
|
|
c35e74d264 | ||
|
|
cdbc25ede8 | ||
|
|
a0260c29c0 | ||
|
|
2c0caf8b75 | ||
|
|
56064c9366 | ||
|
|
98995f45e6 | ||
|
|
5636dc1386 | ||
|
|
127291e35d | ||
|
|
885f8b382f | ||
|
|
8166c52f4a | ||
|
|
ef57d4ae11 | ||
|
|
fbf23b6abb | ||
|
|
47a552f8c2 | ||
|
|
cd3f612857 | ||
|
|
2e30a0e5bc | ||
|
|
9f438cb768 | ||
|
|
cacb751ab8 | ||
|
|
4d59f5ec66 | ||
|
|
69e8e15884 | ||
|
|
1730569f77 | ||
|
|
98091aeab7 | ||
|
|
c5fbde412c | ||
|
|
10a7128d1a | ||
|
|
41f43feecf | ||
|
|
4915bbf8f3 | ||
|
|
ffbd5df25f | ||
|
|
82190eaa81 | ||
|
|
69aa39f1f6 | ||
|
|
ea5e6d367b | ||
|
|
da7b9916e5 | ||
|
|
dac4bd8370 | ||
|
|
6e16e34799 | ||
|
|
6d3fe9d865 | ||
|
|
c090a511fd | ||
|
|
a4e0899af4 | ||
|
|
2d2c7bc9b8 | ||
|
|
df386b64ba | ||
|
|
80bd86a305 | ||
|
|
d55c31d93b | ||
|
|
68cbaf1bd6 | ||
|
|
6867c2ffb3 | ||
|
|
ecb34f60f2 | ||
|
|
5989a07339 | ||
|
|
7730e826b0 | ||
|
|
2d24585a8f | ||
|
|
84a6d1e920 | ||
|
|
05fae8ee7f | ||
|
|
1fe5d6bb0c | ||
|
|
0c944a06f9 | ||
|
|
1bb3a4a45d | ||
|
|
161d21904a | ||
|
|
ea2f19b78a | ||
|
|
f70c6282ca | ||
|
|
ad60e8ac89 | ||
|
|
d03fcc95e4 | ||
|
|
588646f7a2 | ||
|
|
fb75adcd57 | ||
|
|
d407aacc4a | ||
|
|
02a69d5487 | ||
|
|
57acde758b | ||
|
|
f587f35ef0 | ||
|
|
8c00d5e1ee | ||
|
|
f02148e8ca | ||
|
|
476d628c01 | ||
|
|
c55ac504a3 | ||
|
|
6735126c09 | ||
|
|
b9663456d8 | ||
|
|
cabeeba7c5 | ||
|
|
6c517638d0 | ||
|
|
0e1b9a346d | ||
|
|
03db1894d8 | ||
|
|
ff4cdc3161 | ||
|
|
0febe9b0df | ||
|
|
ceb4a23dab | ||
|
|
7f22a07312 | ||
|
|
328d254f7f | ||
|
|
15f6e133a5 | ||
|
|
0a590b7cbe | ||
|
|
f04895a407 | ||
|
|
41b43bf961 | ||
|
|
05de710b67 | ||
|
|
f71fdab997 | ||
|
|
6d8e570420 | ||
|
|
d7bd1300a8 | ||
|
|
2bba68e059 | ||
|
|
4b19cdeca0 | ||
|
|
3d157cbb02 | ||
|
|
80b5f3f43d | ||
|
|
254361cb87 | ||
|
|
f7f412007e | ||
|
|
45c32ec0b1 | ||
|
|
97e323ac3a | ||
|
|
04faee4a0f | ||
|
|
4900703970 | ||
|
|
7bd4f95b8c | ||
|
|
ecd44f70de | ||
|
|
9d5307d04c | ||
|
|
6e697bae97 | ||
|
|
366abb5350 | ||
|
|
9460aa7f21 | ||
|
|
a4dcc2784a | ||
|
|
9a2f1456c5 | ||
|
|
9d219a18f3 | ||
|
|
97f1694f7e | ||
|
|
73cd5a9c27 | ||
|
|
25baa995ec | ||
|
|
39a95d3bd5 | ||
|
|
22acc004cc | ||
|
|
6c07f08175 | ||
|
|
62d4ed8087 | ||
|
|
adf9570a92 | ||
|
|
2c2a18af43 | ||
|
|
2d1ab27cb5 | ||
|
|
903e79a7c4 | ||
|
|
6b8636f79b | ||
|
|
8a0ce463da | ||
|
|
7d13a1d8e1 | ||
|
|
b97c832306 | ||
|
|
4a4dac22e2 | ||
|
|
32e16b323c | ||
|
|
688c5502a8 | ||
|
|
eb00b34191 | ||
|
|
a831b7417f | ||
|
|
0eb1041290 | ||
|
|
c0623295e0 | ||
|
|
e82a13803d | ||
|
|
5cb45bf738 | ||
|
|
a14b495864 | ||
|
|
ad1c343cd7 | ||
|
|
17003cec19 | ||
|
|
2843214d09 | ||
|
|
b456ded5e7 | ||
|
|
d4848880e1 | ||
|
|
e41bb8af6d | ||
|
|
3a608dda8f | ||
|
|
41d38b37cf | ||
|
|
54612455e6 | ||
|
|
9c5b9f932b | ||
|
|
debaff6f7a | ||
|
|
25ce5f1c22 | ||
|
|
a441e4e30d | ||
|
|
50c32f45ac | ||
|
|
5f24575ed9 | ||
|
|
e91a5c85ff | ||
|
|
7561f5c717 | ||
|
|
c554f5383c | ||
|
|
4f48c888ef | ||
|
|
4ff6dc2992 | ||
|
|
266508b691 | ||
|
|
d78c3679e7 | ||
|
|
d6d3502960 | ||
|
|
7ed7512f27 | ||
|
|
ffa78b99d9 | ||
|
|
f66c28900a | ||
|
|
40c109597e | ||
|
|
6e9019120f | ||
|
|
17f40f7efd | ||
|
|
b0db709960 | ||
|
|
216956da4a | ||
|
|
e4ec09dd87 | ||
|
|
ba42d40df9 | ||
|
|
d521232587 | ||
|
|
10e8f03ea4 | ||
|
|
8877f04835 | ||
|
|
f24fa46789 | ||
|
|
a9b00a7489 | ||
|
|
3f462403a9 | ||
|
|
6aa418f7c4 | ||
|
|
6493421109 | ||
|
|
49f00499f7 | ||
|
|
0052386b41 | ||
|
|
e1909c3bd1 | ||
|
|
8ce9388d29 | ||
|
|
b8227afcaa | ||
|
|
b8dee63d7a | ||
|
|
75c99bf2b1 | ||
|
|
e6f81d3965 | ||
|
|
1fafb1325b | ||
|
|
8222295ab1 | ||
|
|
744464aca6 | ||
|
|
c13637b105 | ||
|
|
60c101d90b | ||
|
|
b685f6b6b6 | ||
|
|
424bf6f06a | ||
|
|
46c3c9e0fc | ||
|
|
85f6c5fda8 | ||
|
|
7e5d89293d | ||
|
|
fe7630954e | ||
|
|
47ce4bd9e5 | ||
|
|
8fe4f1f0d7 | ||
|
|
b3d57f3c7c | ||
|
|
a76ba06817 | ||
|
|
86fb83261a | ||
|
|
cf0762a067 | ||
|
|
99b3b752e3 | ||
|
|
5d7aa792e7 | ||
|
|
28b694b170 | ||
|
|
74f74e0363 | ||
|
|
64ca8a668a | ||
|
|
bd72408e7a | ||
|
|
a32381a2a4 | ||
|
|
841973d399 | ||
|
|
cf47523b2c | ||
|
|
2918e45343 | ||
|
|
e3b56fb559 | ||
|
|
667f2a7c4c | ||
|
|
e846b36bf6 | ||
|
|
7f18d087e6 | ||
|
|
3cc9019b37 | ||
|
|
37924b9c7f | ||
|
|
a6c2ccc6cc | ||
|
|
c84051c737 | ||
|
|
fe24ba55c4 | ||
|
|
ed06fc51a0 | ||
|
|
14de3b460b | ||
|
|
dd89ab59e4 | ||
|
|
cd83772112 | ||
|
|
83adb7b55b | ||
|
|
49ba58e991 | ||
|
|
7db3bc91b5 | ||
|
|
c93ecfbfb5 | ||
|
|
893e22691d | ||
|
|
41d8d77535 | ||
|
|
e9307bb797 | ||
|
|
c98bf174ed | ||
|
|
ae3b9f112c | ||
|
|
7fd9e751e0 | ||
|
|
96f50d0c47 | ||
|
|
95a58e74ca | ||
|
|
b70a95ba30 | ||
|
|
72e14643f7 | ||
|
|
93308faeb9 | ||
|
|
f140d3447c | ||
|
|
16ab3ca6a6 | ||
|
|
6b643c7501 | ||
|
|
24920a4ad1 | ||
|
|
65655584e9 | ||
|
|
e397056d2e | ||
|
|
f442195b8a | ||
|
|
54a278edb9 | ||
|
|
b0acc475b0 | ||
|
|
aa8b772bff | ||
|
|
834a971e2a | ||
|
|
6701927840 | ||
|
|
e4ae279f7b | ||
|
|
25e0d1eac3 | ||
|
|
d42faa80a6 | ||
|
|
a92c756fa9 | ||
|
|
4cf94ed62a | ||
|
|
57c7727479 | ||
|
|
8480fc7ae5 | ||
|
|
5ae81aa96c | ||
|
|
28907ec0c3 | ||
|
|
7ddfa79950 | ||
|
|
dd76d72d61 | ||
|
|
ba87178dee | ||
|
|
d8af949a6a | ||
|
|
74a8c4aae8 | ||
|
|
8de21cc37f | ||
|
|
063444801a | ||
|
|
46e384a2f2 | ||
|
|
5092243080 | ||
|
|
110f3710be | ||
|
|
6096a836a4 | ||
|
|
c3724068e5 | ||
|
|
7eba784b0c | ||
|
|
8486a2fd2b | ||
|
|
f15f4aa886 | ||
|
|
3b60f6e238 | ||
|
|
c23ae5aa14 | ||
|
|
93986e0234 | ||
|
|
47710d167a | ||
|
|
62ded39416 | ||
|
|
1534dad5b2 | ||
|
|
f705c56cb3 | ||
|
|
4d52838e2b | ||
|
|
7f44e83cc7 | ||
|
|
2c6546f46f | ||
|
|
76bf93e3de | ||
|
|
7a676a748a | ||
|
|
17895f3a30 | ||
|
|
21e3df4f34 | ||
|
|
f03f845d04 | ||
|
|
a87727844c | ||
|
|
e88410d07b | ||
|
|
3f704a7a0e | ||
|
|
81204ee0db | ||
|
|
d12c0939b9 | ||
|
|
a41fbc0454 | ||
|
|
9d6d14d623 | ||
|
|
439eddb523 | ||
|
|
7beb6f2234 | ||
|
|
19a3a10524 | ||
|
|
2e5f28d7c1 | ||
|
|
bbedeed1c5 | ||
|
|
a18b13d56e | ||
|
|
31da3e98c9 | ||
|
|
272755e1ec | ||
|
|
580b6e2349 | ||
|
|
9800101748 | ||
|
|
1ed02f6494 | ||
|
|
bb5c370575 | ||
|
|
74b0d2d9f1 | ||
|
|
8c531873a8 | ||
|
|
9c9b9f3931 | ||
|
|
95615eaca7 | ||
|
|
54c2c9ac4e | ||
|
|
ea03f9da13 | ||
|
|
536fd105ae | ||
|
|
d89edc35d2 | ||
|
|
4d8f81d802 | ||
|
|
ed6f76ca28 | ||
|
|
63bc383dfa | ||
|
|
0f658e5ca9 | ||
|
|
49824b930d | ||
|
|
abf5a5ad1e | ||
|
|
d4b6b5cb1d | ||
|
|
ce6f90397a | ||
|
|
bb6a50be02 | ||
|
|
e7e918dafe | ||
|
|
81b7798ac2 | ||
|
|
868d4c781a | ||
|
|
71ad94ddb2 | ||
|
|
06ffc44073 | ||
|
|
e9ba7c612e | ||
|
|
fd7afa87b7 | ||
|
|
51a70cee3d | ||
|
|
aafab73a82 | ||
|
|
e3c1d96519 | ||
|
|
9c7066ac47 | ||
|
|
cede7ec971 | ||
|
|
2f355c473a | ||
|
|
a63ebe0904 | ||
|
|
ef9483c82d | ||
|
|
10f1ed771a | ||
|
|
93e8bbab10 | ||
|
|
62df938465 | ||
|
|
634dad033f | ||
|
|
6e3809528e | ||
|
|
60a6b2b0c3 | ||
|
|
2662203fb7 | ||
|
|
1bb76f5343 | ||
|
|
d4edab02b0 | ||
|
|
5cc4c03b6a | ||
|
|
5382901859 | ||
|
|
2e7a3f9e37 | ||
|
|
c8b3df6668 | ||
|
|
69d9840b89 | ||
|
|
639301e9e9 | ||
|
|
970cdcfdbb | ||
|
|
0ef9bd9e23 | ||
|
|
16030a61eb | ||
|
|
5487fc1f9c | ||
|
|
92677da3e4 | ||
|
|
6d38d4e085 | ||
|
|
a16361e823 | ||
|
|
03415b286c | ||
|
|
72a503e93f | ||
|
|
6a6bce4bef | ||
|
|
e64833a217 | ||
|
|
a759ba1d9e | ||
|
|
7ed243d3cd | ||
|
|
afa8d671be | ||
|
|
c607707580 | ||
|
|
8f26bb698d | ||
|
|
a0b913f65d | ||
|
|
271b2f8c5b | ||
|
|
cf5b1e401c | ||
|
|
11174ddf4c | ||
|
|
48a0ffdc9e | ||
|
|
3664be1480 | ||
|
|
c5cd584b63 | ||
|
|
ca1c8a0121 | ||
|
|
3649c90605 | ||
|
|
89cb27f224 | ||
|
|
0d808114b6 | ||
|
|
0555c88425 | ||
|
|
e2d1a5a41d | ||
|
|
df1b309b36 | ||
|
|
e3b53b7e74 | ||
|
|
d8d9fcf2f4 | ||
|
|
ae806e8214 | ||
|
|
8b5474ff67 | ||
|
|
f65a29df5d | ||
|
|
fd18c565b0 | ||
|
|
fbb85fab81 | ||
|
|
db0674dc76 | ||
|
|
3572e7ffa4 | ||
|
|
fe75c6ad28 | ||
|
|
3de8f27a02 | ||
|
|
4dfce57a58 | ||
|
|
179b25d289 | ||
|
|
230b6bc547 | ||
|
|
a2eee7e349 | ||
|
|
cec4b803cf | ||
|
|
1a519ac1fb | ||
|
|
d92c8bec86 | ||
|
|
eb28d171f3 | ||
|
|
fdeb7ccda6 | ||
|
|
73acad2c92 | ||
|
|
7eca3c9d3b | ||
|
|
64ca94d960 | ||
|
|
c01220fd95 | ||
|
|
4d175ae77b | ||
|
|
78df3a35b4 | ||
|
|
68057c1c5a | ||
|
|
e67bb1c5ce | ||
|
|
f2c9a49c50 | ||
|
|
903dd8acef | ||
|
|
480861efb6 | ||
|
|
9a252995c2 | ||
|
|
9a9446d13d | ||
|
|
3d71d6c96f | ||
|
|
41c3c107d4 | ||
|
|
24cad42a86 | ||
|
|
1a564b1672 | ||
|
|
c4006795cc | ||
|
|
cf06083d1b | ||
|
|
89004437c5 | ||
|
|
f0e3eca8a1 | ||
|
|
d15cf0c2ff | ||
|
|
770ad54229 | ||
|
|
a75209d104 | ||
|
|
ab5e543099 | ||
|
|
451ebd447b | ||
|
|
1f8af40361 | ||
|
|
685f2a259f | ||
|
|
e27374324d | ||
|
|
4a2b5f7cc8 | ||
|
|
52dc55d044 | ||
|
|
e6ab047751 | ||
|
|
4f5cf01cbc | ||
|
|
442cc63d22 | ||
|
|
c24a8ba208 | ||
|
|
db7d70a929 | ||
|
|
d2f1c141d8 | ||
|
|
01faf102ba | ||
|
|
76d1296053 | ||
|
|
559bf75189 | ||
|
|
339caf9dc8 | ||
|
|
b26c36b4bf | ||
|
|
c79879aa07 | ||
|
|
e85475780f | ||
|
|
b033a8e731 | ||
|
|
0b5b4a5eea | ||
|
|
af0d0bd2ac | ||
|
|
48097467f9 | ||
|
|
895f0b29aa | ||
|
|
499400916d | ||
|
|
3f0d575df7 | ||
|
|
4cb9d6763b | ||
|
|
d62c51890e | ||
|
|
10707c8288 | ||
|
|
b896d8aa15 | ||
|
|
9e66a6bec6 | ||
|
|
17566febe9 | ||
|
|
f54f48615d | ||
|
|
06bb97e6d9 | ||
|
|
0763f65329 | ||
|
|
db5a86bc06 | ||
|
|
2d604cee25 | ||
|
|
e3a846bb1f | ||
|
|
aaa5c1bc5f | ||
|
|
1ad8e539aa | ||
|
|
29e2877d35 | ||
|
|
a708f8d8ad | ||
|
|
8777982629 | ||
|
|
f1435c86ed | ||
|
|
ece164f679 | ||
|
|
698f47d5ad | ||
|
|
1aa570326e | ||
|
|
1cc9070a50 | ||
|
|
127c107094 | ||
|
|
f1faf8745a | ||
|
|
60a51f8085 | ||
|
|
df63579071 | ||
|
|
5216648d0b | ||
|
|
fcdab1e804 | ||
|
|
9f15ba3972 | ||
|
|
c6a65c692e | ||
|
|
b468767184 | ||
|
|
76ce9ff8c4 | ||
|
|
23ed68c8dd | ||
|
|
2982c79444 | ||
|
|
7e56408331 | ||
|
|
bcfdcec3ee | ||
|
|
f96d94f143 | ||
|
|
adea301e5b | ||
|
|
f9dc569b0a | ||
|
|
f7932bb0c7 | ||
|
|
f20e052ad7 | ||
|
|
02daca9cb9 | ||
|
|
b52a3a415c | ||
|
|
33dcb0c8d9 | ||
|
|
709da37be2 | ||
|
|
2458f07ca1 | ||
|
|
6cf5fc7f7d | ||
|
|
10db6cee6c | ||
|
|
3b7927366a | ||
|
|
a25f094c4c | ||
|
|
bdf830f691 | ||
|
|
bd72642a58 | ||
|
|
b3f5885a50 | ||
|
|
aa168ec8b9 | ||
|
|
d89cb3e575 | ||
|
|
9e1f215f22 | ||
|
|
ffd0b19660 | ||
|
|
0020211857 | ||
|
|
1a59b4e208 | ||
|
|
94e7c762bf | ||
|
|
421c6a92f3 | ||
|
|
d6aa667971 | ||
|
|
575fc9acbd | ||
|
|
d581550130 | ||
|
|
952a134745 | ||
|
|
887aa952fe | ||
|
|
5f715a7af7 | ||
|
|
eea982fb14 | ||
|
|
5a7eebe16e | ||
|
|
55a96af7cc | ||
|
|
8abaf92083 | ||
|
|
b0c29d5c66 | ||
|
|
41a6f6df84 | ||
|
|
4984da7e0d | ||
|
|
be88e5a2c3 | ||
|
|
e7ad7d405c | ||
|
|
62d26814b2 | ||
|
|
f2d8143511 | ||
|
|
3c1a605f62 | ||
|
|
300c1c2055 | ||
|
|
fb42183bc7 | ||
|
|
65ec8a9e94 | ||
|
|
60598c0d34 | ||
|
|
3d7fc711ca | ||
|
|
46dbca1bf5 | ||
|
|
f5da95a5b7 | ||
|
|
b37361e21c | ||
|
|
32a208a176 | ||
|
|
40395bdc0e | ||
|
|
5ec4fd94e0 | ||
|
|
c9ef4d5fa0 | ||
|
|
1cdf0e8597 | ||
|
|
7ba88cc9e3 | ||
|
|
914df32587 | ||
|
|
e0f54428d0 | ||
|
|
52a11b0835 | ||
|
|
ef17dc6482 | ||
|
|
9978dc3f6c | ||
|
|
f618ed3dfb | ||
|
|
ef915fb2e5 | ||
|
|
6e42405113 | ||
|
|
11ef07c74a | ||
|
|
486d7690c4 | ||
|
|
b3c2c594bd | ||
|
|
8852911f67 | ||
|
|
e38bc6eab8 | ||
|
|
459e200ac0 | ||
|
|
c781155b60 | ||
|
|
87aa1de67a | ||
|
|
ccb871c30b | ||
|
|
74ed0b4f09 | ||
|
|
becbb7b284 | ||
|
|
ff76a842d0 | ||
|
|
a56926b8d9 | ||
|
|
0d21503ee5 | ||
|
|
631cb095dd | ||
|
|
caba719950 | ||
|
|
786b602c26 | ||
|
|
f4bfce153d | ||
|
|
e1ab50b17c | ||
|
|
7e4c0bd515 | ||
|
|
ddcec2971e | ||
|
|
72d119a05f | ||
|
|
d423cf2c7f | ||
|
|
3d847b50cf | ||
|
|
731a13cfd1 | ||
|
|
81296fae9d | ||
|
|
aa38f7a4f2 | ||
|
|
bac69f9984 | ||
|
|
c46547592c | ||
|
|
6123fab091 | ||
|
|
fd4a5100a6 | ||
|
|
ff4a8c9202 | ||
|
|
c871d721fd | ||
|
|
05d1cc9a94 | ||
|
|
196ee05fcc | ||
|
|
e50cfa4e1b | ||
|
|
3224a959a4 | ||
|
|
2ccb3648c7 | ||
|
|
01aa647527 | ||
|
|
eb3388de68 | ||
|
|
beb970646b | ||
|
|
25c177ca3b | ||
|
|
1d9c591c08 | ||
|
|
f753960add | ||
|
|
5e98894a97 | ||
|
|
15fe3b569b | ||
|
|
0e0b6026fc | ||
|
|
17dd199cba | ||
|
|
8f7dbe71a1 | ||
|
|
4b5c3d8f09 | ||
|
|
9955b0756a | ||
|
|
76d9b9c0e2 | ||
|
|
175ad6fb77 | ||
|
|
51896902e3 | ||
|
|
b55220905e | ||
|
|
bd65eb32b7 | ||
|
|
b29d1e94b5 | ||
|
|
b74e812671 | ||
|
|
aa27b5db14 | ||
|
|
81e3a62360 | ||
|
|
b0dc264369 | ||
|
|
ac3f179420 | ||
|
|
d9af837974 | ||
|
|
4784b327e7 | ||
|
|
1a1541ecd6 | ||
|
|
cf9fec73cf | ||
|
|
a1551ef6ab | ||
|
|
0163839cfb | ||
|
|
914a942e33 | ||
|
|
5e482ad4f7 | ||
|
|
6901fc9e38 | ||
|
|
0070835330 | ||
|
|
6431a2aa46 | ||
|
|
572d9bdf1a | ||
|
|
4cf2422a83 | ||
|
|
806ec98eab | ||
|
|
20fd349e17 | ||
|
|
dae724b21c | ||
|
|
3e4612a1f0 | ||
|
|
6052e49bcc | ||
|
|
90cbd461ab | ||
|
|
517f2ed03d | ||
|
|
5fccc25f36 | ||
|
|
cb1571c6c5 | ||
|
|
99b0d659bd | ||
|
|
854264c3d2 | ||
|
|
d2a6cae695 | ||
|
|
be9ed2f6a9 | ||
|
|
3ee8beb8a3 | ||
|
|
f816e5e2af | ||
|
|
448d8bff18 | ||
|
|
b82ffb52c7 | ||
|
|
3bccfb8993 | ||
|
|
6fb4e59120 | ||
|
|
309be57a12 | ||
|
|
37098c96f9 | ||
|
|
03cc67a2b1 | ||
|
|
cb4fba7658 | ||
|
|
0bcb13f02e | ||
|
|
42ef09e3bb | ||
|
|
1ab44655e0 | ||
|
|
89734b95c4 | ||
|
|
8f5658bc01 | ||
|
|
a59c3ef278 | ||
|
|
b600ac882a | ||
|
|
71849c4372 | ||
|
|
9545af0d43 | ||
|
|
6c6ee358d4 | ||
|
|
060f4f291b | ||
|
|
3fb43d2322 | ||
|
|
4895683bab | ||
|
|
43800e3d1c | ||
|
|
3b8e1dcd89 | ||
|
|
302d6b321e | ||
|
|
3f85694394 | ||
|
|
8c5ef2f1c3 | ||
|
|
aa1a2d1247 | ||
|
|
3993a7f636 | ||
|
|
aaf16ff0e8 | ||
|
|
16c078963b | ||
|
|
9279bcdba4 | ||
|
|
0c467ef5b4 | ||
|
|
49cd53ee44 | ||
|
|
0e6a463564 | ||
|
|
d38b190317 | ||
|
|
29558cb7bb | ||
|
|
d2cd237e25 | ||
|
|
c7b814337a | ||
|
|
ced51813c7 | ||
|
|
dd8d02b8ef | ||
|
|
c3cf6aef7d | ||
|
|
38a8e5ee03 | ||
|
|
46269dac4e | ||
|
|
8c0297f688 | ||
|
|
bc5890d8b5 | ||
|
|
ee65315520 | ||
|
|
12f7cfde87 | ||
|
|
6d80f3d756 | ||
|
|
b32f752d31 | ||
|
|
cf8be7de91 | ||
|
|
30a3498c22 | ||
|
|
239603e24c | ||
|
|
390daed3de | ||
|
|
918c06aba3 | ||
|
|
726be08917 | ||
|
|
a127debc54 | ||
|
|
6aa26654f6 | ||
|
|
0fde7f0e6b | ||
|
|
d9f8edd259 | ||
|
|
251679253a | ||
|
|
64756c5dce | ||
|
|
9788055147 | ||
|
|
4d7fde59c2 | ||
|
|
4737c16996 | ||
|
|
c97dfbf60c | ||
|
|
496b1e907d | ||
|
|
566131209d | ||
|
|
b7823dc648 | ||
|
|
6d28a1b645 | ||
|
|
b6aa18bfbc | ||
|
|
d91ffc216a | ||
|
|
a6c9e8c5b4 | ||
|
|
9337927722 | ||
|
|
c81b02c7d9 | ||
|
|
5ea09d2668 | ||
|
|
b9fc4c5994 | ||
|
|
f1b500d3e0 | ||
|
|
dff37e11eb | ||
|
|
b1387f801b | ||
|
|
60b2312ab6 | ||
|
|
0354289795 | ||
|
|
c11c35c459 | ||
|
|
7c5e70ac3c | ||
|
|
d2e5ba123d | ||
|
|
0c9568f6dc | ||
|
|
f1d48a9356 | ||
|
|
89f2a9e6dc | ||
|
|
a203da3919 | ||
|
|
1c1ef52cf1 | ||
|
|
40c82c5c36 | ||
|
|
81f0c6535e | ||
|
|
46558d79a5 | ||
|
|
e86b4203b9 | ||
|
|
05dd9554f9 | ||
|
|
30a0423f81 | ||
|
|
26e1223f9a | ||
|
|
84a04de7be | ||
|
|
3ff7fa0092 | ||
|
|
3f2a2cb14b | ||
|
|
fac00348d9 | ||
|
|
3c93fd4fb7 | ||
|
|
6b71273380 | ||
|
|
dccf4e9c34 | ||
|
|
39289a3164 | ||
|
|
6611d878ea | ||
|
|
c3fc711095 | ||
|
|
84f1bdbc87 | ||
|
|
2eb5715599 | ||
|
|
c93defc82d | ||
|
|
bd39c64798 | ||
|
|
42a6b242c7 | ||
|
|
e5570c24f2 | ||
|
|
6d87bd15cd | ||
|
|
d657c00b11 | ||
|
|
6fae06f1d0 | ||
|
|
f18b40f7e7 | ||
|
|
6a0633083d | ||
|
|
899f52be4f | ||
|
|
91525a7d33 | ||
|
|
455c3ae57d | ||
|
|
b5390b5aa2 | ||
|
|
a608b4e9e0 | ||
|
|
f6a543ada3 | ||
|
|
c7bf09c3d4 | ||
|
|
c8ae54d9e8 | ||
|
|
daf6d8772f | ||
|
|
c80e72da83 | ||
|
|
ec351e00ad | ||
|
|
cf242871ea | ||
|
|
597d36dcf2 | ||
|
|
9c388787bb | ||
|
|
f739d8fdd3 | ||
|
|
78d782601e | ||
|
|
86a83dc32c | ||
|
|
c67e53c7b2 | ||
|
|
5659e04e89 | ||
|
|
8ff3055b47 | ||
|
|
71827549d6 | ||
|
|
de5de7acc5 | ||
|
|
c8590c4468 | ||
|
|
5f43c9cfad | ||
|
|
98b966d274 | ||
|
|
674b6f2373 | ||
|
|
407ff0a99d | ||
|
|
0b6d21e3d5 | ||
|
|
557b704069 | ||
|
|
4369e31a49 | ||
|
|
23b5a74c17 | ||
|
|
ee69ab2021 | ||
|
|
374f29c4d3 | ||
|
|
67910e7d60 | ||
|
|
c80b033466 | ||
|
|
671af9f8fe | ||
|
|
6ea05ff6e3 | ||
|
|
00485e133f | ||
|
|
c520ee4eab | ||
|
|
5408ec79f7 | ||
|
|
f8e68ae823 | ||
|
|
184412d88e | ||
|
|
82d1d04774 | ||
|
|
731d4b3d4d | ||
|
|
ccec186b98 | ||
|
|
c66c259447 | ||
|
|
4ad165ce26 | ||
|
|
5cac90b3eb | ||
|
|
df135a0bb2 | ||
|
|
4a04dc1a3e | ||
|
|
0e97fbb730 | ||
|
|
40ab3ee751 | ||
|
|
f95fea9866 | ||
|
|
03719334ea | ||
|
|
4441053b1c | ||
|
|
a34b663828 | ||
|
|
db1f4d4016 | ||
|
|
3ea944d1b3 | ||
|
|
b293aa762c | ||
|
|
b5e75afc17 | ||
|
|
027a865fbc | ||
|
|
132b5f5130 | ||
|
|
c3754e1fdd | ||
|
|
963eb1f29b | ||
|
|
c418d67920 | ||
|
|
6e09e3af86 | ||
|
|
67e9a06d30 | ||
|
|
abd63035c1 | ||
|
|
df2418d9c5 | ||
|
|
2fdae6d72f | ||
|
|
05471d0acd | ||
|
|
05eee16959 | ||
|
|
a752eadd0f | ||
|
|
028dc8d6c3 | ||
|
|
4a7242c8f9 | ||
|
|
efdb29d2f9 | ||
|
|
225da68832 | ||
|
|
51a2e6c580 | ||
|
|
7fe03c715d | ||
|
|
419d18c128 | ||
|
|
74a7755ad9 | ||
|
|
c1ba927b37 | ||
|
|
a8eb913535 | ||
|
|
cb3a301f2c | ||
|
|
6d6903ef62 | ||
|
|
f5daf50dc4 | ||
|
|
b8ccbbc72a | ||
|
|
f0e17fd9c0 | ||
|
|
b09f1d591c | ||
|
|
8fd2b8d829 | ||
|
|
d610693af1 | ||
|
|
7d1886684e | ||
|
|
95fc792745 | ||
|
|
efefc2d986 | ||
|
|
9f8d109a7e | ||
|
|
cf9e5ffb0b | ||
|
|
1383023b2e | ||
|
|
afd081f40b | ||
|
|
3812fd0866 | ||
|
|
24c41ed0da | ||
|
|
36e8e9ebf5 | ||
|
|
12dc372b21 | ||
|
|
20ea9015ca | ||
|
|
0c148025a3 | ||
|
|
a7cf1b04ad | ||
|
|
a08a90a718 | ||
|
|
1cb518cb13 | ||
|
|
cac219aca8 | ||
|
|
a159dfc7ec | ||
|
|
b7061618b1 | ||
|
|
d823809021 | ||
|
|
0329a8be2e | ||
|
|
79f64abfc3 | ||
|
|
63636aca9b | ||
|
|
fdfab07d07 | ||
|
|
cc5f8e5122 | ||
|
|
21dbf97a02 | ||
|
|
39bff056a6 | ||
|
|
128d46e19a | ||
|
|
6d027ebd40 | ||
|
|
89f69209dd | ||
|
|
94a57fe8d5 | ||
|
|
dcb687929f | ||
|
|
628957de21 | ||
|
|
bcfc16c0f6 | ||
|
|
3ba5e27d02 | ||
|
|
950bc578d0 | ||
|
|
ccfcdff190 | ||
|
|
45835f1cf9 | ||
|
|
cf543d1eb0 | ||
|
|
9f24f10186 | ||
|
|
bc37668e9f | ||
|
|
22d87218b7 | ||
|
|
62d64acd7b | ||
|
|
c6ff73f3e5 | ||
|
|
a87602af3f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,7 +7,6 @@ CMakeLists.txt.user*
|
|||||||
doc/_build/*
|
doc/_build/*
|
||||||
*.kate-swp
|
*.kate-swp
|
||||||
*.kdev4
|
*.kdev4
|
||||||
win/
|
|
||||||
admin/win/nsi/l10n/pofiles/*.po
|
admin/win/nsi/l10n/pofiles/*.po
|
||||||
*.swp
|
*.swp
|
||||||
*~$
|
*~$
|
||||||
|
|||||||
5
.gitmodules
vendored
5
.gitmodules
vendored
@@ -3,10 +3,13 @@
|
|||||||
url = https://github.com/owncloud/documentation
|
url = https://github.com/owncloud/documentation
|
||||||
[submodule "src/3rdparty/qtmacgoodies"]
|
[submodule "src/3rdparty/qtmacgoodies"]
|
||||||
path = src/3rdparty/qtmacgoodies
|
path = src/3rdparty/qtmacgoodies
|
||||||
url = git://github.com/guruz/qtmacgoodies.git
|
url = https://github.com/guruz/qtmacgoodies.git
|
||||||
[submodule "binary"]
|
[submodule "binary"]
|
||||||
path = binary
|
path = binary
|
||||||
url = git://github.com/owncloud/owncloud-client-binary.git
|
url = git://github.com/owncloud/owncloud-client-binary.git
|
||||||
[submodule "src/3rdparty/libcrashreporter-qt"]
|
[submodule "src/3rdparty/libcrashreporter-qt"]
|
||||||
path = src/3rdparty/libcrashreporter-qt
|
path = src/3rdparty/libcrashreporter-qt
|
||||||
url = git://github.com/dschmidt/libcrashreporter-qt.git
|
url = git://github.com/dschmidt/libcrashreporter-qt.git
|
||||||
|
[submodule "src/3rdparty/qtkeychain"]
|
||||||
|
path = src/3rdparty/qtkeychain
|
||||||
|
url = https://github.com/frankosterfeld/qtkeychain.git
|
||||||
|
|||||||
14
.travis.yml
14
.travis.yml
@@ -1,15 +1,21 @@
|
|||||||
|
sudo: required
|
||||||
|
|
||||||
language: cpp
|
language: cpp
|
||||||
|
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- coverity_scan
|
- coverity_scan
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- sudo sh -c "echo 'deb http://download.opensuse.org/repositories/isv:/ownCloud:/desktop/xUbuntu_12.04/ /' >> /etc/apt/sources.list.d/owncloud-client.list"
|
- sudo sh -c "echo 'deb http://download.opensuse.org/repositories/isv:/ownCloud:/desktop/Ubuntu_14.04/ /' >> /etc/apt/sources.list.d/owncloud-client.list"
|
||||||
- sudo sh -c "echo 'deb-src http://download.opensuse.org/repositories/isv:/ownCloud:/desktop/xUbuntu_12.04/ /' >> /etc/apt/sources.list.d/owncloud-client.list"
|
- sudo sh -c "echo 'deb-src http://download.opensuse.org/repositories/isv:/ownCloud:/desktop/Ubuntu_14.04/ /' >> /etc/apt/sources.list.d/owncloud-client.list"
|
||||||
- wget http://download.opensuse.org/repositories/isv:ownCloud:desktop/xUbuntu_12.04/Release.key
|
- wget http://download.opensuse.org/repositories/isv:ownCloud:desktop/Ubuntu_14.04/Release.key
|
||||||
- sudo apt-key add - < Release.key
|
- sudo apt-key add - < Release.key
|
||||||
- sudo apt-get update
|
- sudo apt-get update
|
||||||
- sudo apt-get build-dep owncloud-client
|
- sudo apt-get -y build-dep owncloud-client
|
||||||
- checkout=$(git show-ref --head --hash head)
|
- checkout=$(git show-ref --head --hash head)
|
||||||
- cd ../
|
- cd ../
|
||||||
- wget https://scan.coverity.com/download/linux-64 --post-data "token=$token&project=owncloud%2Fmirall" -O coverity_tool.tgz
|
- wget https://scan.coverity.com/download/linux-64 --post-data "token=$token&project=owncloud%2Fmirall" -O coverity_tool.tgz
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
cmake_minimum_required(VERSION 2.6)
|
cmake_minimum_required(VERSION 2.6)
|
||||||
cmake_policy(VERSION 2.8.0)
|
cmake_policy(VERSION 2.8.0)
|
||||||
|
|
||||||
@@ -20,6 +21,11 @@ if (NOT DEFINED APPLICATION_SHORTNAME)
|
|||||||
set ( APPLICATION_SHORTNAME ${APPLICATION_NAME} )
|
set ( APPLICATION_SHORTNAME ${APPLICATION_NAME} )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# For usage in XML files we preprocess
|
||||||
|
string(REPLACE "&" "&" APPLICATION_NAME_XML_ESCAPED "${APPLICATION_NAME}")
|
||||||
|
string(REPLACE "<" "<" APPLICATION_NAME_XML_ESCAPED "${APPLICATION_NAME_XML_ESCAPED}")
|
||||||
|
string(REPLACE ">" ">" APPLICATION_NAME_XML_ESCAPED "${APPLICATION_NAME_XML_ESCAPED}")
|
||||||
|
|
||||||
set(PACKAGE "${APPLICATION_SHORTNAME}-client")
|
set(PACKAGE "${APPLICATION_SHORTNAME}-client")
|
||||||
set( CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules )
|
set( CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules )
|
||||||
|
|
||||||
@@ -30,7 +36,7 @@ endif()
|
|||||||
include(Warnings)
|
include(Warnings)
|
||||||
|
|
||||||
include(${CMAKE_SOURCE_DIR}/VERSION.cmake)
|
include(${CMAKE_SOURCE_DIR}/VERSION.cmake)
|
||||||
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR} "${CMAKE_CURRENT_BINARY_DIR}/src/mirall/")
|
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
# disable the crashreporter if libcrashreporter-qt is not available or we're building for ARM
|
# disable the crashreporter if libcrashreporter-qt is not available or we're building for ARM
|
||||||
if( CMAKE_SYSTEM_PROCESSOR MATCHES "arm" OR NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/3rdparty/libcrashreporter-qt/CMakeLists.txt")
|
if( CMAKE_SYSTEM_PROCESSOR MATCHES "arm" OR NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/3rdparty/libcrashreporter-qt/CMakeLists.txt")
|
||||||
@@ -51,9 +57,7 @@ endif()
|
|||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
include(DefineInstallationPaths)
|
include(DefineInstallationPaths)
|
||||||
include(QtVersionAbstraction)
|
|
||||||
|
|
||||||
setup_qt()
|
|
||||||
|
|
||||||
include(GetGitRevisionDescription)
|
include(GetGitRevisionDescription)
|
||||||
|
|
||||||
@@ -122,45 +126,23 @@ if(OWNCLOUD_5XX_NO_BLACKLIST)
|
|||||||
add_definitions(-DOWNCLOUD_5XX_NO_BLACKLIST=1)
|
add_definitions(-DOWNCLOUD_5XX_NO_BLACKLIST=1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# When this option is enabled, a rename that is not allowed will be renamed back
|
||||||
|
# do the original as a restoration step. Withut this option, the restoration will
|
||||||
|
# re-download the file instead.
|
||||||
|
# The default is off because we don't want to rename the files back behind the user's back
|
||||||
|
# Added for IL issue #550
|
||||||
|
option(OWNCLOUD_RESTORE_RENAME "OWNCLOUD_RESTORE_RENAME" OFF)
|
||||||
|
if(OWNCLOUD_RESTORE_RENAME)
|
||||||
|
add_definitions(-DOWNCLOUD_RESTORE_RENAME=1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set( SOCKETAPI_TEAM_IDENTIFIER_PREFIX "" CACHE STRING "SocketApi prefix (including a following dot) that must match the codesign key's TeamIdentifier/Organizational Unit" )
|
set( SOCKETAPI_TEAM_IDENTIFIER_PREFIX "" CACHE STRING "SocketApi prefix (including a following dot) that must match the codesign key's TeamIdentifier/Organizational Unit" )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#### find libs
|
|
||||||
#find_package(Qt4 4.7.0 COMPONENTS QtCore QtGui QtXml QtNetwork QtTest QtWebkit REQUIRED )
|
|
||||||
#if( UNIX AND NOT APPLE ) # Fdo notifications
|
|
||||||
# find_package(Qt4 4.7.0 COMPONENTS QtDBus REQUIRED )
|
|
||||||
#endif()
|
|
||||||
|
|
||||||
|
|
||||||
set(USE_NEON TRUE)
|
|
||||||
if(HAVE_QT5)
|
|
||||||
message(STATUS "Using Qt ${Qt5Core_VERSION_MAJOR}.${Qt5Core_VERSION_MINOR}.x")
|
|
||||||
if (${Qt5Core_VERSION_MAJOR} EQUAL "5")
|
|
||||||
if (${Qt5Core_VERSION_MINOR} EQUAL "4" OR ${Qt5Core_VERSION_MINOR} GREATER 4)
|
|
||||||
message(STATUS "We do not require Neon in this setup, compile without!")
|
|
||||||
set(USE_NEON FALSE)
|
|
||||||
else()
|
|
||||||
message(STATUS "If possible compile me with Qt 5.4 or higher.")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
message(STATUS "If possible compile me with Qt 5.4 or higher.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (USE_NEON)
|
|
||||||
find_package(Neon REQUIRED)
|
|
||||||
endif(USE_NEON)
|
|
||||||
find_package(OpenSSL 1.0.0 REQUIRED)
|
find_package(OpenSSL 1.0.0 REQUIRED)
|
||||||
|
|
||||||
if(NOT TOKEN_AUTH_ONLY)
|
|
||||||
if (Qt5Core_DIR)
|
|
||||||
find_package(Qt5Keychain REQUIRED)
|
|
||||||
else()
|
|
||||||
find_package(QtKeychain REQUIRED)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
find_package(Sparkle)
|
find_package(Sparkle)
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|||||||
201
ChangeLog
201
ChangeLog
@@ -1,49 +1,186 @@
|
|||||||
ChangeLog
|
ChangeLog
|
||||||
=========
|
=========
|
||||||
version 2.0.2 (release 2015-10-xx)
|
|
||||||
|
version 2.2.4 (release 2016-09-27)
|
||||||
|
* Dolphin Plugin: Use the Application name for the socket path (#5172)
|
||||||
|
* SyncEngine: Fix renaming of folder when file are changed (#5195)
|
||||||
|
* Selective Sync: Fix HTTP request loop and show error in view (#5154)
|
||||||
|
* ConnectionValidator: properly handle error in status.php request (#5188)
|
||||||
|
* Discovery: Set thread priority to low (#5017)
|
||||||
|
* ExcludeFiles: Fix when the folder casing is not the same in the settings and in the FS
|
||||||
|
* ShareLink: Ensure the password line edit is enabled (#5117)
|
||||||
|
|
||||||
|
version 2.2.3 (release 2016-08-08)
|
||||||
|
* SyncEngine: Fix detection of backup (#5104)
|
||||||
|
* Fix bug with overriding URL in config (#5016)
|
||||||
|
* Sharing: Fix bug with file names containing percent encodes (#5042, #5043)
|
||||||
|
* Sharing: Permissions for federated shares on servers >=9.1 (#4996, #5001)
|
||||||
|
* Overlays: Fix issues with file name casing on OS X and Windows
|
||||||
|
* Windows: Skip symlinks and junctions again (#5019)
|
||||||
|
* Only accept notification API Capability if endpoint is OCS-enabled (#5034)
|
||||||
|
* Fix windows HiDPI (#4994)
|
||||||
|
* SocketAPI: Use different pipe name to avoid unusual delay (#4977)
|
||||||
|
* Tray: Add minimal mode as workaround and testing tool for Linux issues (#4985, #4990)
|
||||||
|
* owncloudcmd: Fix --exclude regression #4979
|
||||||
|
* Small memleak: Use the full file stat destructors (#4992)
|
||||||
|
* Fix small QAction memleak (#5008)
|
||||||
|
* Fix crash on shutting down during propagation (#4979)
|
||||||
|
* Decrease memory usage during sync #4979
|
||||||
|
* Setup csync logging earlier to get all log output (#4991)
|
||||||
|
* Enable Shibboleth debug view with OWNCLOUD_SHIBBOLETH_DEBUG env
|
||||||
|
|
||||||
|
version 2.2.2 (release 2016-06-21)
|
||||||
|
* Excludes: Don't redundantly add the same exclude files (memleak) (#4967, #4988)
|
||||||
|
* Excludes: Only log if the pattern was really logged. (#4989)
|
||||||
|
|
||||||
|
version 2.2.1 (release 2016-06-06)
|
||||||
|
* Fix out of memory error when too many uploads happen (#4611)
|
||||||
|
* Fix display errors in progress display (#4803 #4856)
|
||||||
|
* LockWatcher: Remember to upload files after they become unlocked (#4865)
|
||||||
|
* Fix overlay icons for files with umlauts (#4884)
|
||||||
|
* Certs: Re-ask for different cert after rejection (#4898, #4911)
|
||||||
|
* Progress: Don't count items without propagation jobs (#4856, #4910)
|
||||||
|
* Utility: Fix for the translation of minutes, second (#4855)
|
||||||
|
* SyncEngine: invalid the blacklist entry when the rename destination change
|
||||||
|
|
||||||
|
version 2.2.0 (release 2016-05-12)
|
||||||
|
* Overlay icons: Refactoring - mainly for performance improvements
|
||||||
|
* Improved error handling with Sync Journal on USB storages (#4632)
|
||||||
|
* Sharing Completion: Improved UI of completion in sharing from desktop. (#3737)
|
||||||
|
* Show server notifications on the client (#3733)
|
||||||
|
* Improved Speed with small files by dynamic parallel request count (#4529)
|
||||||
|
* LockWatcher: Make sure to sync files after apps released exclusive locks on Windows.
|
||||||
|
* Improved handling of Win32 file locks and network files
|
||||||
|
* Workaround Ubuntu 16.04 tray icon bug (#4693)
|
||||||
|
* Removed the Alias field from the folder definition (#4695)
|
||||||
|
* Improved netrc parser (#4691)
|
||||||
|
* Improved user notifications about ignored files and conflicts (#4761, #3222)
|
||||||
|
* Add warnings for old server versions (#4523)
|
||||||
|
* Enable tranportation checksums if the server supports based on server capabilities (#3735)
|
||||||
|
|
||||||
|
* Default Chunk-size changed to 10MB (#4354)
|
||||||
|
* Documentation Improvements, ie. about overlay icons
|
||||||
|
* Translation fixes
|
||||||
|
* Countless other bugfixes
|
||||||
|
* Sqlite Update to recent version
|
||||||
|
* Update of QtKeyChain to support Windows credential store
|
||||||
|
* Packaging of dolphin overlay icon module for bleeding edge distros
|
||||||
|
|
||||||
|
version 2.1.1 (release 2016-02-10)
|
||||||
|
* UI improvements for HiDPI screens, error messages, RTL languages
|
||||||
|
* Fix occurences of "Connection Closed" when a new unauthenticated TCP socket is used
|
||||||
|
* Fix undeliberate WiFi scanning done by Qt Network classes
|
||||||
|
* Several fixes/improvements to the sharing dialog
|
||||||
|
* Several fixes/improvements to the server activity tab
|
||||||
|
* Create the directory when using --confdir and it does not exist
|
||||||
|
* Windows Overlay icons: Fix DLL and icon oddities
|
||||||
|
* Mac Overlay icons: Don't install legacy Finder plugin on >= 10.10
|
||||||
|
* Linux Overlay icons: Nemo plugin
|
||||||
|
* Overlay icons: Fix several wrong icon state computations
|
||||||
|
* Allow changeable upload chunk size in owncloud.cfg
|
||||||
|
* Crash fixes on account deletion
|
||||||
|
* Forget password on explicit sign-out
|
||||||
|
* OS X: Fix the file system watcher ignoring unicode paths (#4424)
|
||||||
|
* Windows Installer: Update to NSIS 2.50, fixes possible DLL injection
|
||||||
|
* Sync Engine: .lnk files
|
||||||
|
* Sync Engine: symlinked syn directories
|
||||||
|
* Sync Engine: Windows: Fix deleting and replacing of read-only files (#4308, #4277)
|
||||||
|
* Sync Engine: Fixes for files becoming directories and vice versa (#4302)
|
||||||
|
* Misc other fixes/improvements
|
||||||
|
|
||||||
|
version 2.1 (release 2015-12-03)
|
||||||
|
* GUI: Added a display of server activities
|
||||||
|
* GUI: Added a separate view for not synced items, ignores, errors
|
||||||
|
* GUI: Improved upload/download progress UI (#3403, #3569)
|
||||||
|
* Allowed sharing with ownCloud internal users and groups from Desktop
|
||||||
|
* Changed files starting in .* to be considered hidden on all platforms (#4023)
|
||||||
|
* Reflect read-only permissions in filesystem (#3244)
|
||||||
|
* Blacklist: Clear on successful chunk upload (#3934)
|
||||||
|
* Improved reconnecting after network change/disconnect (#4167 #3969 ...)
|
||||||
|
* Improved performance in Windows file system discovery
|
||||||
|
* Removed libneon-based propagator. As a consequence, The client can no
|
||||||
|
longer provide bandwith limiting on Linux-distributions where it is
|
||||||
|
using Qt < 5.4
|
||||||
|
* Performance improvements in the logging functions
|
||||||
|
* Ensured that local disk space problems are handled gracefully (#2939)
|
||||||
|
* Improved handling of checksums: transport validation, db (#3735)
|
||||||
|
* For *eml-files don't reupload if size and checksum are unchanged (#3235)
|
||||||
|
* Ensured 403 reply code is handled properly (File Firewall) (#3490)
|
||||||
|
* Reduced number of PROPFIND requests to server(#3964)
|
||||||
|
* GUI: Added Account toolbox widget to keep account actions (#4139)
|
||||||
|
* Tray Menu: Added fixes for Recent Activity menu (#4093, #3969)
|
||||||
|
* FolderMan: Fixed infinite wait on pause (#4093)
|
||||||
|
* Renamed env variables to include unit (#2939)
|
||||||
|
* FolderStatusModel: Attempt to detect removed undecided files (#3612)
|
||||||
|
* SyncEngine: Don't whipe the white list if the sync was aborted (#4018)
|
||||||
|
* Quota: Handle special negative value for the quota (#3940)
|
||||||
|
* State app name in update notification (#4020)
|
||||||
|
* PropagateUpload: Fixed double-emission of finished (#3844)
|
||||||
|
* GUI: Ensured folder names which are excluded from sync can be clicked
|
||||||
|
* Shell Integration: Dolphin support, requires KF 5.16 and KDE Application 15.12
|
||||||
|
* FolderStatusModel: Ensured reset also if a folder was renamed (#4011)
|
||||||
|
* GUI: Fixed accessiblity of remaing items in full settings toolbar (#3795)
|
||||||
|
* Introduced the term "folder sync connection" in more places (#3757)
|
||||||
|
* AccountSettings: Don't disable pause when offline (#4010)
|
||||||
|
* Fixed handling of hidden files (#3980)
|
||||||
|
* Handle download errors while resuming as soft errors (#4000)
|
||||||
|
* SocketAPI: Ensured that the command isn't trimmed (#3297)
|
||||||
|
* Shutdown socket API before removing the db (#3824)
|
||||||
|
* GUI: Made "Keep" default in the delete-all dialog (#3824)
|
||||||
|
* owncloudcmd: Introduced return code 0 for --version and --help
|
||||||
|
* owncloudcmd: Added --max-sync-retries (#4037)
|
||||||
|
* owncloudcmd: Don't do a check that file are older than 2s (#4160)
|
||||||
|
* Fixed getting size for selective sync (#3986)
|
||||||
|
* Re-added close button in the settings window (#3713)
|
||||||
|
* Added abililty to handle storage limitations gracefully (#3736)
|
||||||
|
* Updated 3rdparty dependencies: sqlite version 3.9.1
|
||||||
|
* Organized patches to our base Qt version into admin/qt/patches
|
||||||
|
* Plus: A lot of unmentioned improvements and fixes
|
||||||
|
|
||||||
|
version 2.0.2 (release 2015-10-21)
|
||||||
* csync_file_stat_s: Save a bit of memory
|
* csync_file_stat_s: Save a bit of memory
|
||||||
* Shibboleth: Add our base user agent to WebKit
|
* Shibboleth: Add our base user agent to WebKit
|
||||||
* SelectiveSync: Increase folder list timeout to 60
|
* SelectiveSync: Increase folder list timeout to 60
|
||||||
* Propagation: Try another sync on 423 Locked #3387
|
* Propagation: Try another sync on 423 Locked (#3387)
|
||||||
* Propagation: Make 423 Locked a soft error #3387
|
* Propagation: Make 423 Locked a soft error (#3387)
|
||||||
* Propagation: Reset upload blacklist if a chunk suceeds
|
* Propagation: Reset upload blacklist if a chunk succeeds
|
||||||
* Application: Fix crash on early shutdown #3898
|
* Application: Fix crash on early shutdown (#3898)
|
||||||
* Linux: Don't show settings dialog always when launched twice #3273 #3771 #3485
|
* Linux: Don't show settings dialog always when launched twice (#3273, #3771, #3485)
|
||||||
* win32 vio: Add the OPEN_REPARSE_POINTS flag to the CreateFileW call. #3813
|
* win32 vio: Add the OPEN_REPARSE_POINTS flag to the CreateFileW call. (#3813)
|
||||||
* AccountSettings: only expand root elements on single click.
|
* AccountSettings: only expand root elements on single click.
|
||||||
* AccountSettings: Do not allow to expand the folder list when disconnected.
|
* AccountSettings: Do not allow to expand the folder list when disconnected.
|
||||||
* Use application SHORT name for the name of the MacOSX pkg file (ownBrander).
|
* Use application SHORT name for the name of the MacOSX pkg file (ownBrander).
|
||||||
* FolderMan: Fix for removing a syncing folder #3843
|
* FolderMan: Fix for removing a syncing folder (#3843)
|
||||||
* ConnectionMethodDialog: Don't be insecure on close #3863
|
* ConnectionMethodDialog: Don't be insecure on close (#3863)
|
||||||
* Updater: Ensure folders are not removed #3747
|
* Updater: Ensure folders are not removed (#3747)
|
||||||
* Folder settings: Ensure path is cleaned #3811
|
* Folder settings: Ensure path is cleaned (#3811)
|
||||||
* Propagator: Simplify sub job finished counting #3844
|
* Propagator: Simplify sub job finished counting (#3844)
|
||||||
* Share dialog: Hide settings dialog before showing #3783
|
* Share dialog: Hide settings dialog before showing (#3783)
|
||||||
* UI: Only expand 1 level in folder list #3585
|
* UI: Only expand 1 level in folder list (#3585)
|
||||||
* UI: Allow folder expanding from button click #3585
|
* UI: Allow folder expanding from button click (#3585)
|
||||||
* UI: Expand folder treeview on single click #3585
|
* UI: Expand folder treeview on single click (#3585)
|
||||||
* GUI: Change tray menu order #3657
|
* GUI: Change tray menu order (#3657)
|
||||||
* GUI: Replace term "sign in" with "Log in" and friends.
|
* GUI: Replace term "sign in" with "Log in" and friends.
|
||||||
* SetupPage: Fix crash caused by uninitialized Account object.
|
* SetupPage: Fix crash caused by uninitialized Account object.
|
||||||
* Use a themable WebDAV path all over.
|
* Use a themable WebDAV path all over.
|
||||||
* Units: Back to the "usual" mix units (JEDEC standard).
|
* Units: Back to the "usual" mix units (JEDEC standard).
|
||||||
* csync io: Full UNC path support on Win #3748
|
* csync io: Full UNC path support on Win (#3748)
|
||||||
* Tray: Don't use the tray workaround with the KDE theme #3706, #3765
|
* Tray: Don't use the tray workaround with the KDE theme (#3706, #3765)
|
||||||
* ShareDialog: Fix folder display #3659
|
* ShareDialog: Fix folder display (#3659)
|
||||||
* AccountSettings: Restore from legacy only once #3565
|
* AccountSettings: Restore from legacy only once (#3565)
|
||||||
* SSL Certificate Error Dialog: show account name #3729
|
* SSL Certificate Error Dialog: show account name (#3729)
|
||||||
* Tray notification: Don't show a message about modified folder #3613
|
* Tray notification: Don't show a message about modified folder (#3613)
|
||||||
* PropagateLocalRemove: remove entries from the DB even if there was an error.
|
* PropagateLocalRemove: remove entries from the DB even if there was an error.
|
||||||
* Settings UI improvements (eg. #3713, #3721, #3619 and others)
|
* Settings UI improvements (eg. #3713, #3721, #3619 and others)
|
||||||
* Folder: Do not create the sync folder if it does not exist #3692
|
* Folder: Do not create the sync folder if it does not exist (#3692)
|
||||||
* Shell integratioon: don't show share menu item for top level folders
|
* Shell integration: don't show share menu item for top level folders
|
||||||
* Tray: Hide while modifying menus #3656 #3672
|
* Tray: Hide while modifying menus (#3656, #3672)
|
||||||
* AddFolder: Improve remote path selection error handling #3573
|
* AddFolder: Improve remote path selection error handling (#3573)
|
||||||
* csync_update: Use excluded_traversal() to improve performance #3638
|
* csync_update: Use excluded_traversal() to improve performance (#3638)
|
||||||
* csync_excluded: Add fast _traversal() function #3638
|
* csync_excluded: Add fast _traversal() function (#3638)
|
||||||
* csync_exclude: Speed up siginificantly #3638
|
* csync_exclude: Speed up significantly (#3638)
|
||||||
* AccountSettings: Adjust quota info design #3644 #3651
|
* AccountSettings: Adjust quota info design (#3644, #3651)
|
||||||
* Adjust buttons on remove folder/account questions #3654
|
* Adjust buttons on remove folder/account questions (#3654)
|
||||||
|
|
||||||
version 2.0.1 (release 2015-09-01)
|
version 2.0.1 (release 2015-09-01)
|
||||||
* AccountWizard: fix when the theme specify a override URL (#3699)
|
* AccountWizard: fix when the theme specify a override URL (#3699)
|
||||||
|
|||||||
58
Jenkinsfile
vendored
Normal file
58
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#!groovy
|
||||||
|
|
||||||
|
node('CLIENT') {
|
||||||
|
stage 'Checkout'
|
||||||
|
checkout scm
|
||||||
|
sh '''git submodule update --init'''
|
||||||
|
|
||||||
|
stage 'Qt4'
|
||||||
|
sh '''rm -rf build
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -DUNIT_TESTING=1 -DBUILD_WITH_QT4=ON ..
|
||||||
|
make
|
||||||
|
ctest --output-on-failure'''
|
||||||
|
|
||||||
|
stage 'Qt4 - clang'
|
||||||
|
sh '''rm -rf build
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUNIT_TESTING=1 -DBUILD_WITH_QT4=ON ..
|
||||||
|
make
|
||||||
|
ctest --output-on-failure'''
|
||||||
|
|
||||||
|
stage 'Qt5'
|
||||||
|
sh '''rm -rf build
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -DUNIT_TESTING=1 -DBUILD_WITH_QT4=OFF ..
|
||||||
|
make
|
||||||
|
ctest --output-on-failure'''
|
||||||
|
|
||||||
|
stage 'Qt5 - clang'
|
||||||
|
sh '''rm -rf build
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUNIT_TESTING=1 -DBUILD_WITH_QT4=OFF ..
|
||||||
|
make
|
||||||
|
ctest --output-on-failure'''
|
||||||
|
|
||||||
|
|
||||||
|
stage 'Win32'
|
||||||
|
def win32 = docker.image('deepdiver/docker-owncloud-client-win32:latest')
|
||||||
|
win32.pull() // make sure we have the latest available from Docker Hub
|
||||||
|
win32.inside {
|
||||||
|
sh '''
|
||||||
|
rm -rf build-win32
|
||||||
|
mkdir build-win32
|
||||||
|
cd build-win32
|
||||||
|
../admin/win/download_runtimes.sh
|
||||||
|
cmake .. -DCMAKE_TOOLCHAIN_FILE=../admin/win/Toolchain-mingw32-openSUSE.cmake -DWITH_CRASHREPORTER=ON
|
||||||
|
make -j4
|
||||||
|
make package
|
||||||
|
ctest .
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
|-----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| client-build-matrix | [](https://ci.owncloud.org/job/client-build-matrix-linux/) |
|
| client-build-matrix | [](https://ci.owncloud.org/job/client-build-matrix-linux/) |
|
||||||
| client-test-matrix-linux-no-build | [](https://ci.owncloud.org/job/client-test-matrix-linux-no-build/) |
|
| client-test-matrix-linux-no-build | [](https://ci.owncloud.org/job/client-test-matrix-linux-no-build/) |
|
||||||
|
| coverity_scan | [](https://scan.coverity.com/projects/owncloud-mirall)
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ with your computer.
|
|||||||
|
|
||||||
### Binary packages
|
### Binary packages
|
||||||
|
|
||||||
* Refer to the download page http://owncloud.org/sync-clients/
|
* Refer to the download page https://owncloud.org/install/#install-clients
|
||||||
|
|
||||||
### Source code
|
### Source code
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
set( MIRALL_VERSION_MAJOR 2 )
|
set( MIRALL_VERSION_MAJOR 2 )
|
||||||
set( MIRALL_VERSION_MINOR 0 )
|
set( MIRALL_VERSION_MINOR 2 )
|
||||||
set( MIRALL_VERSION_PATCH 2 )
|
set( MIRALL_VERSION_PATCH 4 )
|
||||||
|
set( MIRALL_VERSION_YEAR 2016 )
|
||||||
set( MIRALL_SOVERSION 0 )
|
set( MIRALL_SOVERSION 0 )
|
||||||
|
|
||||||
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||||
set( MIRALL_VERSION_SUFFIX "rc2") #e.g. beta1, beta2, rc1
|
set( MIRALL_VERSION_SUFFIX "") #e.g. beta1, beta2, rc1
|
||||||
endif( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
endif( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||||
|
|
||||||
if( NOT DEFINED MIRALL_VERSION_BUILD )
|
if( NOT DEFINED MIRALL_VERSION_BUILD )
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ def extractDeps(macho):
|
|||||||
deps = [macho]
|
deps = [macho]
|
||||||
otool = subprocess.Popen(['otool', '-L', macho], stdout=subprocess.PIPE)
|
otool = subprocess.Popen(['otool', '-L', macho], stdout=subprocess.PIPE)
|
||||||
for l in otool.communicate()[0].splitlines():
|
for l in otool.communicate()[0].splitlines():
|
||||||
|
if 'is not an object file' in l:
|
||||||
|
return []
|
||||||
m = re.search(r'@[^\s]+', l)
|
m = re.search(r'@[^\s]+', l)
|
||||||
if m:
|
if m:
|
||||||
path = resolvePath(m.group(0))
|
path = resolvePath(m.group(0))
|
||||||
|
|||||||
@@ -144,6 +144,10 @@ def FindFramework(path):
|
|||||||
search_pathes = FRAMEWORK_SEARCH_PATH
|
search_pathes = FRAMEWORK_SEARCH_PATH
|
||||||
search_pathes.insert(0, QueryQMake('QT_INSTALL_LIBS'))
|
search_pathes.insert(0, QueryQMake('QT_INSTALL_LIBS'))
|
||||||
for search_path in search_pathes:
|
for search_path in search_pathes:
|
||||||
|
# The following two lines are needed for a custom built Qt from version 5.5 on, possibly not for the one from the Qt SDK.
|
||||||
|
# Looks like the upstream macdeployqt also had an issue there https://bugreports.qt.io/browse/QTBUG-47868
|
||||||
|
if path.find( "\@rpath/"):
|
||||||
|
path = path.replace("@rpath/", "")
|
||||||
abs_path = os.path.join(search_path, path)
|
abs_path = os.path.join(search_path, path)
|
||||||
if os.path.exists(abs_path):
|
if os.path.exists(abs_path):
|
||||||
return abs_path
|
return abs_path
|
||||||
@@ -245,35 +249,38 @@ def CopyPlugin(path, subdir):
|
|||||||
commands.append(args)
|
commands.append(args)
|
||||||
return new_path
|
return new_path
|
||||||
|
|
||||||
def CopyFramework(path):
|
def CopyFramework(source_dylib):
|
||||||
parts = path.split(os.sep)
|
parts = source_dylib.split(os.sep)
|
||||||
print "CopyFramework:", path
|
print "CopyFramework:", source_dylib
|
||||||
for i, part in enumerate(parts):
|
for i, part in enumerate(parts):
|
||||||
matchObj = re.match(r'(\w+\.framework)', part)
|
matchObj = re.match(r'(\w+\.framework)', part)
|
||||||
if matchObj:
|
if matchObj:
|
||||||
full_path = os.path.join(frameworks_dir, *parts[i:-1])
|
|
||||||
framework = matchObj.group(1)
|
framework = matchObj.group(1)
|
||||||
|
dylib_name = parts[-1]
|
||||||
|
source_path = os.path.join('/', *parts[:i+1])
|
||||||
|
dest_path = os.path.join(frameworks_dir, framework)
|
||||||
|
dest_dylib_path = os.path.join(frameworks_dir, *parts[i:-1])
|
||||||
break
|
break
|
||||||
args = ['mkdir', '-p', full_path]
|
if os.path.exists(dest_path):
|
||||||
commands.append(args)
|
print dest_path, "already exists, skipping copy..."
|
||||||
args = ['ditto', '--arch=x86_64', path, full_path]
|
return os.path.join(dest_dylib_path, dylib_name)
|
||||||
commands.append(args)
|
|
||||||
args = ['chmod', 'u+w', os.path.join(full_path, parts[-1])]
|
|
||||||
commands.append(args)
|
|
||||||
resources_dir = os.path.join(frameworks_dir, framework, "Resources")
|
|
||||||
|
|
||||||
args = ['mkdir', resources_dir]
|
args = ['mkdir', '-p', dest_dylib_path]
|
||||||
commands.append(args)
|
commands.append(args)
|
||||||
args = ['chmod', 'u+w', resources_dir]
|
args = ['ditto', '--arch=x86_64', source_dylib, dest_dylib_path]
|
||||||
|
commands.append(args)
|
||||||
|
args = ['chmod', 'u+w', os.path.join(dest_dylib_path, parts[-1])]
|
||||||
|
commands.append(args)
|
||||||
|
args = ['ln', '-s', '5', os.path.join(dest_path, 'Versions', 'Current')]
|
||||||
|
commands.append(args)
|
||||||
|
args = ['ln', '-s', os.path.join('Versions', 'Current', dylib_name), os.path.join(dest_path, dylib_name)]
|
||||||
|
commands.append(args)
|
||||||
|
args = ['ln', '-s', os.path.join('Versions', 'Current', 'Resources'), os.path.join(dest_path, 'Resources')]
|
||||||
|
commands.append(args)
|
||||||
|
args = ['cp', '-r', os.path.join(source_path, 'Versions', '5', 'Resources'), os.path.join(dest_path, 'Versions', '5')]
|
||||||
commands.append(args)
|
commands.append(args)
|
||||||
|
|
||||||
info_plist = os.path.join(os.path.split(path)[0], '..', '..', 'Contents', 'Info.plist')
|
return os.path.join(dest_dylib_path, dylib_name)
|
||||||
if not os.path.exists(info_plist):
|
|
||||||
info_plist = os.path.join(os.path.split(path)[0], 'Resources', 'Info.plist')
|
|
||||||
if os.path.exists(info_plist):
|
|
||||||
args = ['cp', '-r', info_plist, resources_dir]
|
|
||||||
commands.append(args)
|
|
||||||
return os.path.join(full_path, parts[-1])
|
|
||||||
|
|
||||||
def FixId(path, library_name):
|
def FixId(path, library_name):
|
||||||
id = '@executable_path/../Frameworks/%s' % library_name
|
id = '@executable_path/../Frameworks/%s' % library_name
|
||||||
|
|||||||
@@ -497,7 +497,7 @@
|
|||||||
<key>IDENTIFIER</key>
|
<key>IDENTIFIER</key>
|
||||||
<string>@APPLICATION_REV_DOMAIN_INSTALLER@</string>
|
<string>@APPLICATION_REV_DOMAIN_INSTALLER@</string>
|
||||||
<key>NAME</key>
|
<key>NAME</key>
|
||||||
<string>@APPLICATION_NAME@</string>
|
<string>@APPLICATION_NAME_XML_ESCAPED@</string>
|
||||||
<key>OVERWRITE_PERMISSIONS</key>
|
<key>OVERWRITE_PERMISSIONS</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>VERSION</key>
|
<key>VERSION</key>
|
||||||
@@ -1115,6 +1115,28 @@
|
|||||||
</dict>
|
</dict>
|
||||||
<key>PACKAGE_UUID</key>
|
<key>PACKAGE_UUID</key>
|
||||||
<string>39F61FCD-6EAA-4F3A-81C6-25E3F667DFB5</string>
|
<string>39F61FCD-6EAA-4F3A-81C6-25E3F667DFB5</string>
|
||||||
|
<key>REQUIREMENTS</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>BEHAVIOR</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>DICTIONARY</key>
|
||||||
|
<dict>
|
||||||
|
<key>IC_REQUIREMENT_JAVASCRIPT_FUNCTION</key>
|
||||||
|
<string>olderOsx</string>
|
||||||
|
<key>IC_REQUIREMENT_JAVASCRIPT_PARAMETERS</key>
|
||||||
|
<array/>
|
||||||
|
</dict>
|
||||||
|
<key>IDENTIFIER</key>
|
||||||
|
<string>fr.whitebox.Packages.requirement.javascript</string>
|
||||||
|
<key>MESSAGE</key>
|
||||||
|
<array/>
|
||||||
|
<key>NAME</key>
|
||||||
|
<string>JavaScript</string>
|
||||||
|
<key>STATE</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
<key>TITLE</key>
|
<key>TITLE</key>
|
||||||
<array/>
|
<array/>
|
||||||
<key>TOOLTIP</key>
|
<key>TOOLTIP</key>
|
||||||
@@ -1223,7 +1245,7 @@
|
|||||||
<key>LANGUAGE</key>
|
<key>LANGUAGE</key>
|
||||||
<string>English</string>
|
<string>English</string>
|
||||||
<key>VALUE</key>
|
<key>VALUE</key>
|
||||||
<string>@APPLICATION_NAME@ Client</string>
|
<string>@APPLICATION_NAME_XML_ESCAPED@ Client</string>
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
@@ -1423,11 +1445,23 @@
|
|||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>NAME</key>
|
<key>NAME</key>
|
||||||
<string>@APPLICATION_NAME@ Installer</string>
|
<string>@APPLICATION_NAME_XML_ESCAPED@ Installer</string>
|
||||||
<key>REFERENCE_FOLDER_PATH</key>
|
<key>REFERENCE_FOLDER_PATH</key>
|
||||||
<string>@CMAKE_INSTALL_DIR@</string>
|
<string>@CMAKE_INSTALL_DIR@</string>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>SHARED_GLOBAL_DATA</key>
|
||||||
|
<dict>
|
||||||
|
<key>IC_REQUIREMENT_JAVASCRIPT_SHARED_SOURCE_CODE</key>
|
||||||
|
<string>
|
||||||
|
function olderOsx() {
|
||||||
|
if(system.compareVersions(system.version.ProductVersion, '10.10') == -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
</string>
|
||||||
|
</dict>
|
||||||
<key>TYPE</key>
|
<key>TYPE</key>
|
||||||
<integer>0</integer>
|
<integer>0</integer>
|
||||||
<key>VERSION</key>
|
<key>VERSION</key>
|
||||||
|
|||||||
@@ -12,8 +12,10 @@ EOF
|
|||||||
if [ -x "$(command -v pluginkit)" ]; then
|
if [ -x "$(command -v pluginkit)" ]; then
|
||||||
# add it to DB. This happens automatically too but we try to push it a bit harder for issue #3463
|
# add it to DB. This happens automatically too but we try to push it a bit harder for issue #3463
|
||||||
pluginkit -a "/Applications/@APPLICATION_EXECUTABLE@.app/Contents/PlugIns/FinderSyncExt.appex/"
|
pluginkit -a "/Applications/@APPLICATION_EXECUTABLE@.app/Contents/PlugIns/FinderSyncExt.appex/"
|
||||||
|
# Since El Capitan we need to sleep #4650
|
||||||
|
sleep 10s
|
||||||
# enable it
|
# enable it
|
||||||
pluginkit -e use -i @APPLICATION_REV_DOMAIN@.FinderSyncExt
|
pluginkit -e use -i @APPLICATION_REV_DOMAIN@.FinderSyncExt
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ team_identifier="$3"
|
|||||||
codesign -s "$identity" --force --preserve-metadata=entitlements --verbose=4 --deep "$src_app"
|
codesign -s "$identity" --force --preserve-metadata=entitlements --verbose=4 --deep "$src_app"
|
||||||
|
|
||||||
# Verify the signature
|
# Verify the signature
|
||||||
spctl -a -t exec -vv $src_app
|
|
||||||
codesign -dv $src_app
|
codesign -dv $src_app
|
||||||
|
codesign --verify -v $src_app
|
||||||
|
spctl -a -t exec -vv $src_app
|
||||||
|
|
||||||
# Validate that the key used for signing the binary matches the expected TeamIdentifier
|
# Validate that the key used for signing the binary matches the expected TeamIdentifier
|
||||||
# needed to pass the SocketApi through the sandbox
|
# needed to pass the SocketApi through the sandbox
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
From ea4dcc5931d455e4ee3e958ffa54a9f54ab022c8 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Molkentin <daniel@molkentin.de>
|
||||||
|
Date: Mon, 5 Jan 2015 10:45:25 +0100
|
||||||
|
Subject: [PATCH 1/3] Fix crash on Mac OS if PAC URL contains non-URL legal
|
||||||
|
chars
|
||||||
|
|
||||||
|
macQueryInternal() was retrieving the PAC URL string as-entered by
|
||||||
|
the user in the 'Proxies' tab of the system network settings dialog
|
||||||
|
and passing it to CFURLCreateWithString().
|
||||||
|
|
||||||
|
CFURLCreateWithString() returns null if the input string contains
|
||||||
|
non-URL legal chars or is empty.
|
||||||
|
|
||||||
|
Change-Id: I9166d0433a62c7b2274b5435a7dea0a16997d10e
|
||||||
|
Patch-By: Robert Knight
|
||||||
|
Task-number: QTBUG-36787
|
||||||
|
Reviewed-by: Peter Hartmann <phartmann@blackberry.com>
|
||||||
|
Reviewed-by: Markus Goetz <markus@woboq.com>
|
||||||
|
---
|
||||||
|
src/network/kernel/qnetworkproxy_mac.cpp | 6 +++++-
|
||||||
|
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/network/kernel/qnetworkproxy_mac.cpp b/src/network/kernel/qnetworkproxy_mac.cpp
|
||||||
|
index 7d26246..81bce0c 100644
|
||||||
|
--- a/src/network/kernel/qnetworkproxy_mac.cpp
|
||||||
|
+++ b/src/network/kernel/qnetworkproxy_mac.cpp
|
||||||
|
@@ -221,7 +221,11 @@ QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query)
|
||||||
|
int enabled;
|
||||||
|
if (CFNumberGetValue(pacEnabled, kCFNumberIntType, &enabled) && enabled) {
|
||||||
|
// PAC is enabled
|
||||||
|
- CFStringRef cfPacLocation = (CFStringRef)CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigURLString);
|
||||||
|
+ // kSCPropNetProxiesProxyAutoConfigURLString returns the URL string
|
||||||
|
+ // as entered in the system proxy configuration dialog
|
||||||
|
+ CFStringRef pacLocationSetting = (CFStringRef)CFDictionaryGetValue(dict, kSCPropNetProxiesProxyAutoConfigURLString);
|
||||||
|
+ QCFType<CFStringRef> cfPacLocation = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, pacLocationSetting, NULL, NULL,
|
||||||
|
+ kCFStringEncodingUTF8);
|
||||||
|
|
||||||
|
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
|
||||||
|
QCFType<CFDataRef> pacData;
|
||||||
|
--
|
||||||
|
1.8.3.4 (Apple Git-47)
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
From a83e4d1d9dd90d4563ce60f27dfb7802a780e33e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Molkentin <daniel@molkentin.de>
|
||||||
|
Date: Mon, 5 Jan 2015 11:42:52 +0100
|
||||||
|
Subject: [PATCH 2/3] Fix possible crash when passing an invalid PAC URL
|
||||||
|
|
||||||
|
This commit checks whether CFURLCreateWithString() succeeded.
|
||||||
|
|
||||||
|
It does not appear to be possible to enter an empty URL directly in the
|
||||||
|
PAC configuration dialog but I can't rule out the possibility
|
||||||
|
that it could find its way into the settings via some other means.
|
||||||
|
|
||||||
|
Change-Id: I6c2053d385503bf0330f5ae9fb1ec36a473d425d
|
||||||
|
Patch-By: Robert Knight
|
||||||
|
Task-number: QTBUG-36787
|
||||||
|
Reviewed-by: Markus Goetz <markus@woboq.com>
|
||||||
|
Reviewed-by: Peter Hartmann <phartmann@blackberry.com>
|
||||||
|
---
|
||||||
|
src/network/kernel/qnetworkproxy_mac.cpp | 4 ++++
|
||||||
|
1 file changed, 4 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/src/network/kernel/qnetworkproxy_mac.cpp b/src/network/kernel/qnetworkproxy_mac.cpp
|
||||||
|
index 81bce0c..6be032e 100644
|
||||||
|
--- a/src/network/kernel/qnetworkproxy_mac.cpp
|
||||||
|
+++ b/src/network/kernel/qnetworkproxy_mac.cpp
|
||||||
|
@@ -230,6 +230,10 @@ QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query)
|
||||||
|
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
|
||||||
|
QCFType<CFDataRef> pacData;
|
||||||
|
QCFType<CFURLRef> pacUrl = CFURLCreateWithString(kCFAllocatorDefault, cfPacLocation, NULL);
|
||||||
|
+ if (!pacUrl) {
|
||||||
|
+ qWarning("Invalid PAC URL \"%s\"", qPrintable(QCFString::toQString(cfPacLocation)));
|
||||||
|
+ return result;
|
||||||
|
+ }
|
||||||
|
SInt32 errorCode;
|
||||||
|
if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, pacUrl, &pacData, NULL, NULL, &errorCode)) {
|
||||||
|
QString pacLocation = QCFString::toQString(cfPacLocation);
|
||||||
|
--
|
||||||
|
1.8.3.4 (Apple Git-47)
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
From 83bd9393e5564ea9168fda90c0f44456633a483a Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Molkentin <daniel@molkentin.de>
|
||||||
|
Date: Mon, 5 Jan 2015 15:22:57 +0100
|
||||||
|
Subject: [PATCH 3/3] Fix crash if PAC script retrieval returns a null CFData
|
||||||
|
instance
|
||||||
|
|
||||||
|
The documentation for CFURLCreateDataAndPropertiesFromResource()
|
||||||
|
does not make this clear but from looking at the CFNetwork implementation
|
||||||
|
and a user stacktrace it appears that this function can return true
|
||||||
|
but not set the data argument under certain circumstances.
|
||||||
|
|
||||||
|
Change-Id: I48034a640d6f47a51cd5883bbafacad4bcbd0415
|
||||||
|
Task-number: QTBUG-36787
|
||||||
|
Patch-By: Robert Knight
|
||||||
|
Reviewed-by: Markus Goetz <markus@woboq.com>
|
||||||
|
Reviewed-by: Peter Hartmann <phartmann@blackberry.com>
|
||||||
|
---
|
||||||
|
src/network/kernel/qnetworkproxy_mac.cpp | 5 ++++-
|
||||||
|
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/network/kernel/qnetworkproxy_mac.cpp b/src/network/kernel/qnetworkproxy_mac.cpp
|
||||||
|
index 6be032e..a1ac349 100644
|
||||||
|
--- a/src/network/kernel/qnetworkproxy_mac.cpp
|
||||||
|
+++ b/src/network/kernel/qnetworkproxy_mac.cpp
|
||||||
|
@@ -240,7 +240,10 @@ QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query)
|
||||||
|
qWarning("Unable to get the PAC script at \"%s\" (%s)", qPrintable(pacLocation), cfurlErrorDescription(errorCode));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+ if (!pacData) {
|
||||||
|
+ qWarning("\"%s\" returned an empty PAC script", qPrintable(QCFString::toQString(cfPacLocation)));
|
||||||
|
+ return result;
|
||||||
|
+ }
|
||||||
|
QCFType<CFStringRef> pacScript = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, pacData, kCFStringEncodingISOLatin1);
|
||||||
|
if (!pacScript) {
|
||||||
|
// This should never happen, but the documentation says it may return NULL if there was a problem creating the object.
|
||||||
|
--
|
||||||
|
1.8.3.4 (Apple Git-47)
|
||||||
|
|
||||||
32
admin/qt/patches/0004-Cocoa-Fix-systray-SVG-icons.patch
Normal file
32
admin/qt/patches/0004-Cocoa-Fix-systray-SVG-icons.patch
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
From 22f3d359350fd65e4bbe2e9420fcc4460e8a590a Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= <morten.sorvig@digia.com>
|
||||||
|
Date: Tue, 10 Mar 2015 22:37:39 +0100
|
||||||
|
Subject: [PATCH] Cocoa: Fix systray SVG icons.
|
||||||
|
|
||||||
|
Regression caused by f3699510.
|
||||||
|
|
||||||
|
Task-number: QTBUG-44686
|
||||||
|
Change-Id: I546422a67d4da29fac196025b09bddcb45c1b641
|
||||||
|
Reviewed-by: Timur Pocheptsov <Timur.Pocheptsov@digia.com>
|
||||||
|
---
|
||||||
|
src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm | 4 ++++
|
||||||
|
1 file changed, 4 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||||
|
index e449fd3..8a35705 100755
|
||||||
|
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||||
|
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||||
|
@@ -234,6 +234,10 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Handle SVG icons, which do not return anything for availableSizes().
|
||||||
|
+ if (!selectedSize.isValid())
|
||||||
|
+ selectedSize = icon.actualSize(QSize(maxPixmapHeight, maxPixmapHeight), mode);
|
||||||
|
+
|
||||||
|
QPixmap pixmap = icon.pixmap(selectedSize, mode);
|
||||||
|
|
||||||
|
// Draw a low-resolution icon if there is not enough pixels for a retina
|
||||||
|
--
|
||||||
|
1.9.1
|
||||||
|
|
||||||
115
admin/qt/patches/0005-OSX-Fix-disapearing-tray-icon.patch
Normal file
115
admin/qt/patches/0005-OSX-Fix-disapearing-tray-icon.patch
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
From ee7fea33383726f0bb72e8082a357820e3ee3675 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jocelyn Turcotte <jturcotte@woboq.com>
|
||||||
|
Date: Tue, 24 Feb 2015 17:02:02 +0100
|
||||||
|
Subject: [PATCH] OSX Fix disapearing tray icon
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
It would happen together with an error:
|
||||||
|
QPainter::begin: Paint device returned engine == 0
|
||||||
|
and would be caused by the size provided to QIcon::pixmap being empty,
|
||||||
|
itself caused by the availableSizes list being empty for the Selected
|
||||||
|
mode.
|
||||||
|
|
||||||
|
This bug was most often hidden by the fact that the Selected icon mode
|
||||||
|
was not triggered properly since we usually only set menuVisible after
|
||||||
|
calling updateIcon, and most of the time when it did, we would overwrite
|
||||||
|
it right after with a Normal mode icon.
|
||||||
|
|
||||||
|
Fix the issue by disabling the broken feature completely since the
|
||||||
|
default Selected icon is grayed out while tray icons are now usually
|
||||||
|
black (or white when selected). To support the dark menu bar mode on
|
||||||
|
10.10 we'll need to use NSImage's setTemplate anyway and that
|
||||||
|
knowing in advance if we can invert the colors ourselves would also
|
||||||
|
better solve the menuVisible usecase.
|
||||||
|
|
||||||
|
Task-number: QTBUG-42910
|
||||||
|
Change-Id: If9ec9659af28ecceb841bfc2f11721e6029fe891
|
||||||
|
Reviewed-by: Morten Johan Sørvig <morten.sorvig@theqtcompany.com>
|
||||||
|
---
|
||||||
|
src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm | 17 +++--------------
|
||||||
|
1 file changed, 3 insertions(+), 14 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||||
|
index 8a35705..d366a3c 100755
|
||||||
|
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||||
|
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||||
|
@@ -102,7 +102,6 @@ QT_USE_NAMESPACE
|
||||||
|
QCocoaSystemTrayIcon *systray;
|
||||||
|
NSStatusItem *item;
|
||||||
|
QCocoaMenu *menu;
|
||||||
|
- bool menuVisible;
|
||||||
|
QIcon icon;
|
||||||
|
QT_MANGLE_NAMESPACE(QNSImageView) *imageCell;
|
||||||
|
}
|
||||||
|
@@ -202,8 +201,6 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
|
||||||
|
|
||||||
|
m_sys->item->icon = icon;
|
||||||
|
|
||||||
|
- const bool menuVisible = m_sys->item->menu && m_sys->item->menuVisible;
|
||||||
|
-
|
||||||
|
// The reccomended maximum title bar icon height is 18 points
|
||||||
|
// (device independent pixels). The menu height on past and
|
||||||
|
// current OS X versions is 22 points. Provide some future-proofing
|
||||||
|
@@ -218,9 +215,8 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
|
||||||
|
// devicePixelRatio for the "best" screen on the system.
|
||||||
|
qreal devicePixelRatio = qApp->devicePixelRatio();
|
||||||
|
const int maxPixmapHeight = maxImageHeight * devicePixelRatio;
|
||||||
|
- const QIcon::Mode mode = menuVisible ? QIcon::Selected : QIcon::Normal;
|
||||||
|
QSize selectedSize;
|
||||||
|
- Q_FOREACH (const QSize& size, sortByHeight(icon.availableSizes(mode))) {
|
||||||
|
+ Q_FOREACH (const QSize& size, sortByHeight(icon.availableSizes())) {
|
||||||
|
// Select a pixmap based on the height. We want the largest pixmap
|
||||||
|
// with a height smaller or equal to maxPixmapHeight. The pixmap
|
||||||
|
// may rectangular; assume it has a reasonable size. If there is
|
||||||
|
@@ -236,9 +232,9 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
|
||||||
|
|
||||||
|
// Handle SVG icons, which do not return anything for availableSizes().
|
||||||
|
if (!selectedSize.isValid())
|
||||||
|
- selectedSize = icon.actualSize(QSize(maxPixmapHeight, maxPixmapHeight), mode);
|
||||||
|
+ selectedSize = icon.actualSize(QSize(maxPixmapHeight, maxPixmapHeight));
|
||||||
|
|
||||||
|
- QPixmap pixmap = icon.pixmap(selectedSize, mode);
|
||||||
|
+ QPixmap pixmap = icon.pixmap(selectedSize);
|
||||||
|
|
||||||
|
// Draw a low-resolution icon if there is not enough pixels for a retina
|
||||||
|
// icon. This prevents showing a small icon on retina displays.
|
||||||
|
@@ -385,9 +381,6 @@ QT_END_NAMESPACE
|
||||||
|
Q_UNUSED(notification);
|
||||||
|
down = NO;
|
||||||
|
|
||||||
|
- parent->systray->updateIcon(parent->icon);
|
||||||
|
- parent->menuVisible = false;
|
||||||
|
-
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -397,8 +390,6 @@ QT_END_NAMESPACE
|
||||||
|
int clickCount = [mouseEvent clickCount];
|
||||||
|
[self setNeedsDisplay:YES];
|
||||||
|
|
||||||
|
- parent->systray->updateIcon(parent->icon);
|
||||||
|
-
|
||||||
|
if (clickCount == 2) {
|
||||||
|
[self menuTrackingDone:nil];
|
||||||
|
[parent doubleClickSelector:self];
|
||||||
|
@@ -454,7 +445,6 @@ QT_END_NAMESPACE
|
||||||
|
if (self) {
|
||||||
|
item = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
|
||||||
|
menu = 0;
|
||||||
|
- menuVisible = false;
|
||||||
|
systray = sys;
|
||||||
|
imageCell = [[QNSImageView alloc] initWithParent:self];
|
||||||
|
[item setView: imageCell];
|
||||||
|
@@ -498,7 +488,6 @@ QT_END_NAMESPACE
|
||||||
|
selector:@selector(menuTrackingDone:)
|
||||||
|
name:NSMenuDidEndTrackingNotification
|
||||||
|
object:m];
|
||||||
|
- menuVisible = true;
|
||||||
|
[item popUpStatusItemMenu: m];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--
|
||||||
|
1.9.1
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
From f3cd07c11e0b7327ffc629f48a89c8c457cdba75 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jocelyn Turcotte <jturcotte@woboq.com>
|
||||||
|
Date: Fri, 6 Mar 2015 16:12:37 +0100
|
||||||
|
Subject: [PATCH] Fix -force-debug-info with macx-clang
|
||||||
|
|
||||||
|
---
|
||||||
|
mkspecs/common/clang.conf | 2 ++
|
||||||
|
1 file changed, 2 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/mkspecs/common/clang.conf b/mkspecs/common/clang.conf
|
||||||
|
index 2c29bb8..110d380 100644
|
||||||
|
--- a/mkspecs/common/clang.conf
|
||||||
|
+++ b/mkspecs/common/clang.conf
|
||||||
|
@@ -20,11 +20,13 @@ QMAKE_CFLAGS_ISYSTEM = -isystem
|
||||||
|
QMAKE_CFLAGS_PRECOMPILE = -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT}
|
||||||
|
QMAKE_CFLAGS_USE_PRECOMPILE = -Xclang -include-pch -Xclang ${QMAKE_PCH_OUTPUT}
|
||||||
|
QMAKE_CFLAGS_LTCG = -flto
|
||||||
|
+QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO = $$QMAKE_CFLAGS_OPTIMIZE -g
|
||||||
|
|
||||||
|
QMAKE_CXXFLAGS_PRECOMPILE = -x c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT}
|
||||||
|
QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE
|
||||||
|
QMAKE_CXXFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG
|
||||||
|
QMAKE_CXXFLAGS_CXX11 = -std=c++11
|
||||||
|
+QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
|
||||||
|
|
||||||
|
QMAKE_LFLAGS_CXX11 =
|
||||||
|
QMAKE_LFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG
|
||||||
|
--
|
||||||
|
2.2.0
|
||||||
|
|
||||||
@@ -0,0 +1,691 @@
|
|||||||
|
From cff39fba10ffc10ee4dcfdc66ff6528eb26462d3 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Markus Goetz <markus@woboq.com>
|
||||||
|
Date: Fri, 10 Apr 2015 14:09:53 +0200
|
||||||
|
Subject: [PATCH] QNAM: Fix upload corruptions when server closes connection
|
||||||
|
|
||||||
|
This patch fixes several upload corruptions if the server closes the connection
|
||||||
|
while/before we send data into it. They happen inside multiple places in the HTTP
|
||||||
|
layer and are explained in the comments.
|
||||||
|
Corruptions are:
|
||||||
|
* The upload byte device has an in-flight signal with pending upload data, if
|
||||||
|
it gets reset (because server closes the connection) then the re-send of the
|
||||||
|
request was sometimes taking this stale in-flight pending upload data.
|
||||||
|
* Because some signals were DirectConnection and some were QueuedConnection, there
|
||||||
|
was a chance that a direct signal overtakes a queued signal. The state machine
|
||||||
|
then sent data down the socket which was buffered there (and sent later) although
|
||||||
|
it did not match the current state of the state machine when it was actually sent.
|
||||||
|
* A socket was seen as being able to have requests sent even though it was not
|
||||||
|
encrypted yet. This relates to the previous corruption where data is stored inside
|
||||||
|
the socket's buffer and then sent later.
|
||||||
|
|
||||||
|
The included auto test produces all fixed corruptions, I detected no regressions
|
||||||
|
via the other tests.
|
||||||
|
This code also adds a bit of sanity checking to protect from possible further
|
||||||
|
problems.
|
||||||
|
|
||||||
|
[ChangeLog][QtNetwork] Fix HTTP(s) upload corruption when server closes connection
|
||||||
|
|
||||||
|
Change-Id: I54c883925ec897050941498f139c4b523030432e
|
||||||
|
Reviewed-by: Peter Hartmann <peter-qt@hartmann.tk>
|
||||||
|
---
|
||||||
|
src/corelib/io/qnoncontiguousbytedevice.cpp | 18 +++
|
||||||
|
src/corelib/io/qnoncontiguousbytedevice_p.h | 4 +
|
||||||
|
.../access/qhttpnetworkconnectionchannel.cpp | 35 ++++-
|
||||||
|
.../access/qhttpnetworkconnectionchannel_p.h | 2 +
|
||||||
|
src/network/access/qhttpprotocolhandler.cpp | 7 +
|
||||||
|
src/network/access/qhttpthreaddelegate_p.h | 36 ++++-
|
||||||
|
src/network/access/qnetworkreplyhttpimpl.cpp | 25 ++-
|
||||||
|
src/network/access/qnetworkreplyhttpimpl_p.h | 7 +-
|
||||||
|
.../access/qnetworkreply/tst_qnetworkreply.cpp | 175 ++++++++++++++++++++-
|
||||||
|
9 files changed, 279 insertions(+), 30 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp
|
||||||
|
index 11510a8..760ca3d 100644
|
||||||
|
--- a/src/corelib/io/qnoncontiguousbytedevice.cpp
|
||||||
|
+++ b/src/corelib/io/qnoncontiguousbytedevice.cpp
|
||||||
|
@@ -236,6 +236,11 @@ qint64 QNonContiguousByteDeviceByteArrayImpl::size()
|
||||||
|
return byteArray->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
+qint64 QNonContiguousByteDeviceByteArrayImpl::pos()
|
||||||
|
+{
|
||||||
|
+ return currentPosition;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QSharedPointer<QRingBuffer> rb)
|
||||||
|
: QNonContiguousByteDevice(), currentPosition(0)
|
||||||
|
{
|
||||||
|
@@ -273,6 +278,11 @@ bool QNonContiguousByteDeviceRingBufferImpl::atEnd()
|
||||||
|
return currentPosition >= size();
|
||||||
|
}
|
||||||
|
|
||||||
|
+qint64 QNonContiguousByteDeviceRingBufferImpl::pos()
|
||||||
|
+{
|
||||||
|
+ return currentPosition;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
bool QNonContiguousByteDeviceRingBufferImpl::reset()
|
||||||
|
{
|
||||||
|
if (resetDisabled)
|
||||||
|
@@ -406,6 +416,14 @@ qint64 QNonContiguousByteDeviceIoDeviceImpl::size()
|
||||||
|
return device->size() - initialPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
+qint64 QNonContiguousByteDeviceIoDeviceImpl::pos()
|
||||||
|
+{
|
||||||
|
+ if (device->isSequential())
|
||||||
|
+ return -1;
|
||||||
|
+
|
||||||
|
+ return device->pos();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0)
|
||||||
|
{
|
||||||
|
byteDevice = bd;
|
||||||
|
diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h
|
||||||
|
index c05ae11..4d7b7b0 100644
|
||||||
|
--- a/src/corelib/io/qnoncontiguousbytedevice_p.h
|
||||||
|
+++ b/src/corelib/io/qnoncontiguousbytedevice_p.h
|
||||||
|
@@ -61,6 +61,7 @@ public:
|
||||||
|
virtual const char* readPointer(qint64 maximumLength, qint64 &len) = 0;
|
||||||
|
virtual bool advanceReadPointer(qint64 amount) = 0;
|
||||||
|
virtual bool atEnd() = 0;
|
||||||
|
+ virtual qint64 pos() { return -1; }
|
||||||
|
virtual bool reset() = 0;
|
||||||
|
void disableReset();
|
||||||
|
bool isResetDisabled() { return resetDisabled; }
|
||||||
|
@@ -106,6 +107,7 @@ public:
|
||||||
|
bool atEnd();
|
||||||
|
bool reset();
|
||||||
|
qint64 size();
|
||||||
|
+ qint64 pos() Q_DECL_OVERRIDE;
|
||||||
|
protected:
|
||||||
|
QByteArray* byteArray;
|
||||||
|
qint64 currentPosition;
|
||||||
|
@@ -121,6 +123,7 @@ public:
|
||||||
|
bool atEnd();
|
||||||
|
bool reset();
|
||||||
|
qint64 size();
|
||||||
|
+ qint64 pos() Q_DECL_OVERRIDE;
|
||||||
|
protected:
|
||||||
|
QSharedPointer<QRingBuffer> ringBuffer;
|
||||||
|
qint64 currentPosition;
|
||||||
|
@@ -138,6 +141,7 @@ public:
|
||||||
|
bool atEnd();
|
||||||
|
bool reset();
|
||||||
|
qint64 size();
|
||||||
|
+ qint64 pos() Q_DECL_OVERRIDE;
|
||||||
|
protected:
|
||||||
|
QIODevice* device;
|
||||||
|
QByteArray* currentReadBuffer;
|
||||||
|
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||||
|
index 9f63280..49c6793 100644
|
||||||
|
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||||
|
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||||
|
@@ -106,15 +106,19 @@ void QHttpNetworkConnectionChannel::init()
|
||||||
|
socket->setProxy(QNetworkProxy::NoProxy);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+ // We want all signals (except the interactive ones) be connected as QueuedConnection
|
||||||
|
+ // because else we're falling into cases where we recurse back into the socket code
|
||||||
|
+ // and mess up the state. Always going to the event loop (and expecting that when reading/writing)
|
||||||
|
+ // is safer.
|
||||||
|
QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
|
||||||
|
this, SLOT(_q_bytesWritten(qint64)),
|
||||||
|
- Qt::DirectConnection);
|
||||||
|
+ Qt::QueuedConnection);
|
||||||
|
QObject::connect(socket, SIGNAL(connected()),
|
||||||
|
this, SLOT(_q_connected()),
|
||||||
|
- Qt::DirectConnection);
|
||||||
|
+ Qt::QueuedConnection);
|
||||||
|
QObject::connect(socket, SIGNAL(readyRead()),
|
||||||
|
this, SLOT(_q_readyRead()),
|
||||||
|
- Qt::DirectConnection);
|
||||||
|
+ Qt::QueuedConnection);
|
||||||
|
|
||||||
|
// The disconnected() and error() signals may already come
|
||||||
|
// while calling connectToHost().
|
||||||
|
@@ -143,13 +147,13 @@ void QHttpNetworkConnectionChannel::init()
|
||||||
|
// won't be a sslSocket if encrypt is false
|
||||||
|
QObject::connect(sslSocket, SIGNAL(encrypted()),
|
||||||
|
this, SLOT(_q_encrypted()),
|
||||||
|
- Qt::DirectConnection);
|
||||||
|
+ Qt::QueuedConnection);
|
||||||
|
QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
|
||||||
|
this, SLOT(_q_sslErrors(QList<QSslError>)),
|
||||||
|
Qt::DirectConnection);
|
||||||
|
QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
|
||||||
|
this, SLOT(_q_encryptedBytesWritten(qint64)),
|
||||||
|
- Qt::DirectConnection);
|
||||||
|
+ Qt::QueuedConnection);
|
||||||
|
|
||||||
|
if (ignoreAllSslErrors)
|
||||||
|
sslSocket->ignoreSslErrors();
|
||||||
|
@@ -186,8 +190,11 @@ void QHttpNetworkConnectionChannel::close()
|
||||||
|
// pendingEncrypt must only be true in between connected and encrypted states
|
||||||
|
pendingEncrypt = false;
|
||||||
|
|
||||||
|
- if (socket)
|
||||||
|
+ if (socket) {
|
||||||
|
+ // socket can be 0 since the host lookup is done from qhttpnetworkconnection.cpp while
|
||||||
|
+ // there is no socket yet.
|
||||||
|
socket->close();
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -353,6 +360,14 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // This code path for ConnectedState
|
||||||
|
+ if (pendingEncrypt) {
|
||||||
|
+ // Let's only be really connected when we have received the encrypted() signal. Else the state machine seems to mess up
|
||||||
|
+ // and corrupt the things sent to the server.
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -659,6 +674,12 @@ bool QHttpNetworkConnectionChannel::isSocketReading() const
|
||||||
|
void QHttpNetworkConnectionChannel::_q_bytesWritten(qint64 bytes)
|
||||||
|
{
|
||||||
|
Q_UNUSED(bytes);
|
||||||
|
+ if (ssl) {
|
||||||
|
+ // In the SSL case we want to send data from encryptedBytesWritten signal since that one
|
||||||
|
+ // is the one going down to the actual network, not only into some SSL buffer.
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
// bytes have been written to the socket. write even more of them :)
|
||||||
|
if (isSocketWriting())
|
||||||
|
sendRequest();
|
||||||
|
@@ -734,7 +755,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
|
||||||
|
|
||||||
|
// ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again!
|
||||||
|
//channels[i].reconnectAttempts = 2;
|
||||||
|
- if (pendingEncrypt) {
|
||||||
|
+ if (ssl || pendingEncrypt) { // FIXME: Didn't work properly with pendingEncrypt only, we should refactor this into an EncrypingState
|
||||||
|
#ifndef QT_NO_SSL
|
||||||
|
if (connection->sslContext().isNull()) {
|
||||||
|
// this socket is making the 1st handshake for this connection,
|
||||||
|
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
|
||||||
|
index 692c0e6..231fe11 100644
|
||||||
|
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
|
||||||
|
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
|
||||||
|
@@ -83,6 +83,8 @@ typedef QPair<QHttpNetworkRequest, QHttpNetworkReply*> HttpMessagePair;
|
||||||
|
class QHttpNetworkConnectionChannel : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
+ // TODO: Refactor this to add an EncryptingState (and remove pendingEncrypt).
|
||||||
|
+ // Also add an Unconnected state so IdleState does not have double meaning.
|
||||||
|
enum ChannelState {
|
||||||
|
IdleState = 0, // ready to send request
|
||||||
|
ConnectingState = 1, // connecting to host
|
||||||
|
diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
|
||||||
|
index 28e10f7..3357948 100644
|
||||||
|
--- a/src/network/access/qhttpprotocolhandler.cpp
|
||||||
|
+++ b/src/network/access/qhttpprotocolhandler.cpp
|
||||||
|
@@ -368,6 +368,13 @@ bool QHttpProtocolHandler::sendRequest()
|
||||||
|
// nothing to read currently, break the loop
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
+ if (m_channel->written != uploadByteDevice->pos()) {
|
||||||
|
+ // Sanity check. This was useful in tracking down an upload corruption.
|
||||||
|
+ qWarning() << "QHttpProtocolHandler: Internal error in sendRequest. Expected to write at position" << m_channel->written << "but read device is at" << uploadByteDevice->pos();
|
||||||
|
+ Q_ASSERT(m_channel->written == uploadByteDevice->pos());
|
||||||
|
+ m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::ProtocolFailure);
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
qint64 currentWriteSize = m_socket->write(readPointer, currentReadSize);
|
||||||
|
if (currentWriteSize == -1 || currentWriteSize != currentReadSize) {
|
||||||
|
// socket broke down
|
||||||
|
diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h
|
||||||
|
index 1661082..b553409 100644
|
||||||
|
--- a/src/network/access/qhttpthreaddelegate_p.h
|
||||||
|
+++ b/src/network/access/qhttpthreaddelegate_p.h
|
||||||
|
@@ -187,6 +187,7 @@ protected:
|
||||||
|
QByteArray m_dataArray;
|
||||||
|
bool m_atEnd;
|
||||||
|
qint64 m_size;
|
||||||
|
+ qint64 m_pos; // to match calls of haveDataSlot with the expected position
|
||||||
|
public:
|
||||||
|
QNonContiguousByteDeviceThreadForwardImpl(bool aE, qint64 s)
|
||||||
|
: QNonContiguousByteDevice(),
|
||||||
|
@@ -194,7 +195,8 @@ public:
|
||||||
|
m_amount(0),
|
||||||
|
m_data(0),
|
||||||
|
m_atEnd(aE),
|
||||||
|
- m_size(s)
|
||||||
|
+ m_size(s),
|
||||||
|
+ m_pos(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -202,6 +204,11 @@ public:
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
+ qint64 pos() Q_DECL_OVERRIDE
|
||||||
|
+ {
|
||||||
|
+ return m_pos;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
const char* readPointer(qint64 maximumLength, qint64 &len)
|
||||||
|
{
|
||||||
|
if (m_amount > 0) {
|
||||||
|
@@ -229,11 +236,10 @@ public:
|
||||||
|
|
||||||
|
m_amount -= a;
|
||||||
|
m_data += a;
|
||||||
|
+ m_pos += a;
|
||||||
|
|
||||||
|
- // To main thread to inform about our state
|
||||||
|
- emit processedData(a);
|
||||||
|
-
|
||||||
|
- // FIXME possible optimization, already ask user thread for some data
|
||||||
|
+ // To main thread to inform about our state. The m_pos will be sent as a sanity check.
|
||||||
|
+ emit processedData(m_pos, a);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@@ -250,10 +256,21 @@ public:
|
||||||
|
{
|
||||||
|
m_amount = 0;
|
||||||
|
m_data = 0;
|
||||||
|
+ m_dataArray.clear();
|
||||||
|
+
|
||||||
|
+ if (wantDataPending) {
|
||||||
|
+ // had requested the user thread to send some data (only 1 in-flight at any moment)
|
||||||
|
+ wantDataPending = false;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
// Communicate as BlockingQueuedConnection
|
||||||
|
bool b = false;
|
||||||
|
emit resetData(&b);
|
||||||
|
+ if (b) {
|
||||||
|
+ // the reset succeeded, we're at pos 0 again
|
||||||
|
+ m_pos = 0;
|
||||||
|
+ // the HTTP code will anyway abort the request if !b.
|
||||||
|
+ }
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -264,8 +281,13 @@ public:
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
// From user thread:
|
||||||
|
- void haveDataSlot(QByteArray dataArray, bool dataAtEnd, qint64 dataSize)
|
||||||
|
+ void haveDataSlot(qint64 pos, QByteArray dataArray, bool dataAtEnd, qint64 dataSize)
|
||||||
|
{
|
||||||
|
+ if (pos != m_pos) {
|
||||||
|
+ // Sometimes when re-sending a request in the qhttpnetwork* layer there is a pending haveData from the
|
||||||
|
+ // user thread on the way to us. We need to ignore it since it is the data for the wrong(later) chunk.
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
wantDataPending = false;
|
||||||
|
|
||||||
|
m_dataArray = dataArray;
|
||||||
|
@@ -285,7 +307,7 @@ signals:
|
||||||
|
|
||||||
|
// to main thread:
|
||||||
|
void wantData(qint64);
|
||||||
|
- void processedData(qint64);
|
||||||
|
+ void processedData(qint64 pos, qint64 amount);
|
||||||
|
void resetData(bool *b);
|
||||||
|
};
|
||||||
|
|
||||||
|
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
|
||||||
|
index 4ce7303..974a101 100644
|
||||||
|
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
|
||||||
|
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
|
||||||
|
@@ -424,6 +424,7 @@ QNetworkReplyHttpImplPrivate::QNetworkReplyHttpImplPrivate()
|
||||||
|
, synchronous(false)
|
||||||
|
, state(Idle)
|
||||||
|
, statusCode(0)
|
||||||
|
+ , uploadByteDevicePosition(false)
|
||||||
|
, uploadDeviceChoking(false)
|
||||||
|
, outgoingData(0)
|
||||||
|
, bytesUploaded(-1)
|
||||||
|
@@ -863,9 +864,9 @@ void QNetworkReplyHttpImplPrivate::postRequest()
|
||||||
|
q, SLOT(uploadByteDeviceReadyReadSlot()),
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
|
||||||
|
- // From main thread to user thread:
|
||||||
|
- QObject::connect(q, SIGNAL(haveUploadData(QByteArray,bool,qint64)),
|
||||||
|
- forwardUploadDevice, SLOT(haveDataSlot(QByteArray,bool,qint64)), Qt::QueuedConnection);
|
||||||
|
+ // From user thread to http thread:
|
||||||
|
+ QObject::connect(q, SIGNAL(haveUploadData(qint64,QByteArray,bool,qint64)),
|
||||||
|
+ forwardUploadDevice, SLOT(haveDataSlot(qint64,QByteArray,bool,qint64)), Qt::QueuedConnection);
|
||||||
|
QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()),
|
||||||
|
forwardUploadDevice, SIGNAL(readyRead()),
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
@@ -873,8 +874,8 @@ void QNetworkReplyHttpImplPrivate::postRequest()
|
||||||
|
// From http thread to user thread:
|
||||||
|
QObject::connect(forwardUploadDevice, SIGNAL(wantData(qint64)),
|
||||||
|
q, SLOT(wantUploadDataSlot(qint64)));
|
||||||
|
- QObject::connect(forwardUploadDevice, SIGNAL(processedData(qint64)),
|
||||||
|
- q, SLOT(sentUploadDataSlot(qint64)));
|
||||||
|
+ QObject::connect(forwardUploadDevice,SIGNAL(processedData(qint64, qint64)),
|
||||||
|
+ q, SLOT(sentUploadDataSlot(qint64,qint64)));
|
||||||
|
QObject::connect(forwardUploadDevice, SIGNAL(resetData(bool*)),
|
||||||
|
q, SLOT(resetUploadDataSlot(bool*)),
|
||||||
|
Qt::BlockingQueuedConnection); // this is the only one with BlockingQueued!
|
||||||
|
@@ -1268,12 +1269,22 @@ void QNetworkReplyHttpImplPrivate::replySslConfigurationChanged(const QSslConfig
|
||||||
|
void QNetworkReplyHttpImplPrivate::resetUploadDataSlot(bool *r)
|
||||||
|
{
|
||||||
|
*r = uploadByteDevice->reset();
|
||||||
|
+ if (*r) {
|
||||||
|
+ // reset our own position which is used for the inter-thread communication
|
||||||
|
+ uploadByteDevicePosition = 0;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread
|
||||||
|
-void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 amount)
|
||||||
|
+void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 pos, qint64 amount)
|
||||||
|
{
|
||||||
|
+ if (uploadByteDevicePosition + amount != pos) {
|
||||||
|
+ // Sanity check, should not happen.
|
||||||
|
+ error(QNetworkReply::UnknownNetworkError, "");
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
uploadByteDevice->advanceReadPointer(amount);
|
||||||
|
+ uploadByteDevicePosition += amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread
|
||||||
|
@@ -1298,7 +1309,7 @@ void QNetworkReplyHttpImplPrivate::wantUploadDataSlot(qint64 maxSize)
|
||||||
|
QByteArray dataArray(data, currentUploadDataLength);
|
||||||
|
|
||||||
|
// Communicate back to HTTP thread
|
||||||
|
- emit q->haveUploadData(dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size());
|
||||||
|
+ emit q->haveUploadData(uploadByteDevicePosition, dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void QNetworkReplyHttpImplPrivate::uploadByteDeviceReadyReadSlot()
|
||||||
|
diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h
|
||||||
|
index 77d9c5a..1940922 100644
|
||||||
|
--- a/src/network/access/qnetworkreplyhttpimpl_p.h
|
||||||
|
+++ b/src/network/access/qnetworkreplyhttpimpl_p.h
|
||||||
|
@@ -120,7 +120,7 @@ public:
|
||||||
|
|
||||||
|
Q_PRIVATE_SLOT(d_func(), void resetUploadDataSlot(bool *r))
|
||||||
|
Q_PRIVATE_SLOT(d_func(), void wantUploadDataSlot(qint64))
|
||||||
|
- Q_PRIVATE_SLOT(d_func(), void sentUploadDataSlot(qint64))
|
||||||
|
+ Q_PRIVATE_SLOT(d_func(), void sentUploadDataSlot(qint64,qint64))
|
||||||
|
Q_PRIVATE_SLOT(d_func(), void uploadByteDeviceReadyReadSlot())
|
||||||
|
Q_PRIVATE_SLOT(d_func(), void emitReplyUploadProgress(qint64, qint64))
|
||||||
|
Q_PRIVATE_SLOT(d_func(), void _q_cacheSaveDeviceAboutToClose())
|
||||||
|
@@ -144,7 +144,7 @@ signals:
|
||||||
|
|
||||||
|
void startHttpRequestSynchronously();
|
||||||
|
|
||||||
|
- void haveUploadData(QByteArray dataArray, bool dataAtEnd, qint64 dataSize);
|
||||||
|
+ void haveUploadData(const qint64 pos, QByteArray dataArray, bool dataAtEnd, qint64 dataSize);
|
||||||
|
};
|
||||||
|
|
||||||
|
class QNetworkReplyHttpImplPrivate: public QNetworkReplyPrivate
|
||||||
|
@@ -195,6 +195,7 @@ public:
|
||||||
|
// upload
|
||||||
|
QNonContiguousByteDevice* createUploadByteDevice();
|
||||||
|
QSharedPointer<QNonContiguousByteDevice> uploadByteDevice;
|
||||||
|
+ qint64 uploadByteDevicePosition;
|
||||||
|
bool uploadDeviceChoking; // if we couldn't readPointer() any data at the moment
|
||||||
|
QIODevice *outgoingData;
|
||||||
|
QSharedPointer<QRingBuffer> outgoingDataBuffer;
|
||||||
|
@@ -283,7 +284,7 @@ public:
|
||||||
|
// From QNonContiguousByteDeviceThreadForwardImpl in HTTP thread:
|
||||||
|
void resetUploadDataSlot(bool *r);
|
||||||
|
void wantUploadDataSlot(qint64);
|
||||||
|
- void sentUploadDataSlot(qint64);
|
||||||
|
+ void sentUploadDataSlot(qint64, qint64);
|
||||||
|
|
||||||
|
// From user's QNonContiguousByteDevice
|
||||||
|
void uploadByteDeviceReadyReadSlot();
|
||||||
|
diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
|
||||||
|
index 3ccedf6..d2edf67 100644
|
||||||
|
--- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
|
||||||
|
+++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
|
||||||
|
@@ -457,6 +457,10 @@ private Q_SLOTS:
|
||||||
|
|
||||||
|
void putWithRateLimiting();
|
||||||
|
|
||||||
|
+#ifndef QT_NO_SSL
|
||||||
|
+ void putWithServerClosingConnectionImmediately();
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
// NOTE: This test must be last!
|
||||||
|
void parentingRepliesToTheApp();
|
||||||
|
private:
|
||||||
|
@@ -4718,18 +4722,22 @@ void tst_QNetworkReply::ioPostToHttpNoBufferFlag()
|
||||||
|
class SslServer : public QTcpServer {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
- SslServer() : socket(0) {};
|
||||||
|
+ SslServer() : socket(0), m_ssl(true) {}
|
||||||
|
void incomingConnection(qintptr socketDescriptor) {
|
||||||
|
QSslSocket *serverSocket = new QSslSocket;
|
||||||
|
serverSocket->setParent(this);
|
||||||
|
|
||||||
|
if (serverSocket->setSocketDescriptor(socketDescriptor)) {
|
||||||
|
+ connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
|
||||||
|
+ if (!m_ssl) {
|
||||||
|
+ emit newPlainConnection(serverSocket);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath();
|
||||||
|
if (testDataDir.isEmpty())
|
||||||
|
testDataDir = QCoreApplication::applicationDirPath();
|
||||||
|
|
||||||
|
connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot()));
|
||||||
|
- connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
|
||||||
|
serverSocket->setProtocol(QSsl::AnyProtocol);
|
||||||
|
connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), serverSocket, SLOT(ignoreSslErrors()));
|
||||||
|
serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem");
|
||||||
|
@@ -4740,11 +4748,12 @@ public:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signals:
|
||||||
|
- void newEncryptedConnection();
|
||||||
|
+ void newEncryptedConnection(QSslSocket *s);
|
||||||
|
+ void newPlainConnection(QSslSocket *s);
|
||||||
|
public slots:
|
||||||
|
void encryptedSlot() {
|
||||||
|
socket = (QSslSocket*) sender();
|
||||||
|
- emit newEncryptedConnection();
|
||||||
|
+ emit newEncryptedConnection(socket);
|
||||||
|
}
|
||||||
|
void readyReadSlot() {
|
||||||
|
// for the incoming sockets, not the server socket
|
||||||
|
@@ -4753,6 +4762,7 @@ public slots:
|
||||||
|
|
||||||
|
public:
|
||||||
|
QSslSocket *socket;
|
||||||
|
+ bool m_ssl;
|
||||||
|
};
|
||||||
|
|
||||||
|
// very similar to ioPostToHttpUploadProgress but for SSL
|
||||||
|
@@ -4780,7 +4790,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress()
|
||||||
|
QNetworkReplyPtr reply(manager.post(request, sourceFile));
|
||||||
|
|
||||||
|
QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64)));
|
||||||
|
- connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||||
|
+ connect(&server, SIGNAL(newEncryptedConnection(QSslSocket*)), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||||
|
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply.data(), SLOT(ignoreSslErrors()));
|
||||||
|
|
||||||
|
// get the request started and the incoming socket connected
|
||||||
|
@@ -4788,7 +4798,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress()
|
||||||
|
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||||
|
QTcpSocket *incomingSocket = server.socket;
|
||||||
|
QVERIFY(incomingSocket);
|
||||||
|
- disconnect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||||
|
+ disconnect(&server, SIGNAL(newEncryptedConnection(QSslSocket*)), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||||
|
|
||||||
|
|
||||||
|
incomingSocket->setReadBufferSize(1*1024);
|
||||||
|
@@ -7905,6 +7915,159 @@ void tst_QNetworkReply::putWithRateLimiting()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
+#ifndef QT_NO_SSL
|
||||||
|
+
|
||||||
|
+class PutWithServerClosingConnectionImmediatelyHandler: public QObject
|
||||||
|
+{
|
||||||
|
+ Q_OBJECT
|
||||||
|
+public:
|
||||||
|
+ bool m_parsedHeaders;
|
||||||
|
+ QByteArray m_receivedData;
|
||||||
|
+ QByteArray m_expectedData;
|
||||||
|
+ QSslSocket *m_socket;
|
||||||
|
+ PutWithServerClosingConnectionImmediatelyHandler(QSslSocket *s, QByteArray expected) :m_parsedHeaders(false), m_expectedData(expected), m_socket(s)
|
||||||
|
+ {
|
||||||
|
+ m_socket->setParent(this);
|
||||||
|
+ connect(m_socket, SIGNAL(readyRead()), SLOT(readyReadSlot()));
|
||||||
|
+ connect(m_socket, SIGNAL(disconnected()), SLOT(disconnectedSlot()));
|
||||||
|
+ }
|
||||||
|
+signals:
|
||||||
|
+ void correctFileUploadReceived();
|
||||||
|
+ void corruptFileUploadReceived();
|
||||||
|
+
|
||||||
|
+public slots:
|
||||||
|
+ void closeDelayed() {
|
||||||
|
+ m_socket->close();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ void readyReadSlot()
|
||||||
|
+ {
|
||||||
|
+ QByteArray data = m_socket->readAll();
|
||||||
|
+ m_receivedData += data;
|
||||||
|
+ if (!m_parsedHeaders && m_receivedData.contains("\r\n\r\n")) {
|
||||||
|
+ m_parsedHeaders = true;
|
||||||
|
+ QTimer::singleShot(qrand()%10, this, SLOT(closeDelayed())); // simulate random network latency
|
||||||
|
+ // This server simulates a web server connection closing, e.g. because of Apaches MaxKeepAliveRequests or KeepAliveTimeout
|
||||||
|
+ // In this case QNAM needs to re-send the upload data but it had a bug which then corrupts the upload
|
||||||
|
+ // This test catches that.
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+ void disconnectedSlot()
|
||||||
|
+ {
|
||||||
|
+ if (m_parsedHeaders) {
|
||||||
|
+ //qDebug() << m_receivedData.left(m_receivedData.indexOf("\r\n\r\n"));
|
||||||
|
+ m_receivedData = m_receivedData.mid(m_receivedData.indexOf("\r\n\r\n")+4); // check only actual data
|
||||||
|
+ }
|
||||||
|
+ if (m_receivedData.length() > 0 && !m_expectedData.startsWith(m_receivedData)) {
|
||||||
|
+ // We had received some data but it is corrupt!
|
||||||
|
+ qDebug() << "CORRUPT" << m_receivedData.count();
|
||||||
|
+
|
||||||
|
+ // Use this to track down the pattern of the corruption and conclude the source
|
||||||
|
+// QFile a("/tmp/corrupt");
|
||||||
|
+// a.open(QIODevice::WriteOnly);
|
||||||
|
+// a.write(m_receivedData);
|
||||||
|
+// a.close();
|
||||||
|
+
|
||||||
|
+// QFile b("/tmp/correct");
|
||||||
|
+// b.open(QIODevice::WriteOnly);
|
||||||
|
+// b.write(m_expectedData);
|
||||||
|
+// b.close();
|
||||||
|
+ //exit(1);
|
||||||
|
+ emit corruptFileUploadReceived();
|
||||||
|
+ } else {
|
||||||
|
+ emit correctFileUploadReceived();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+class PutWithServerClosingConnectionImmediatelyServer: public SslServer
|
||||||
|
+{
|
||||||
|
+ Q_OBJECT
|
||||||
|
+public:
|
||||||
|
+ int m_correctUploads;
|
||||||
|
+ int m_corruptUploads;
|
||||||
|
+ int m_repliesFinished;
|
||||||
|
+ int m_expectedReplies;
|
||||||
|
+ QByteArray m_expectedData;
|
||||||
|
+ PutWithServerClosingConnectionImmediatelyServer() : SslServer(), m_correctUploads(0), m_corruptUploads(0), m_repliesFinished(0), m_expectedReplies(0)
|
||||||
|
+ {
|
||||||
|
+ QObject::connect(this, SIGNAL(newEncryptedConnection(QSslSocket*)), this, SLOT(createHandlerForConnection(QSslSocket*)));
|
||||||
|
+ QObject::connect(this, SIGNAL(newPlainConnection(QSslSocket*)), this, SLOT(createHandlerForConnection(QSslSocket*)));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+public slots:
|
||||||
|
+ void createHandlerForConnection(QSslSocket* s) {
|
||||||
|
+ PutWithServerClosingConnectionImmediatelyHandler *handler = new PutWithServerClosingConnectionImmediatelyHandler(s, m_expectedData);
|
||||||
|
+ handler->setParent(this);
|
||||||
|
+ QObject::connect(handler, SIGNAL(correctFileUploadReceived()), this, SLOT(increaseCorrect()));
|
||||||
|
+ QObject::connect(handler, SIGNAL(corruptFileUploadReceived()), this, SLOT(increaseCorrupt()));
|
||||||
|
+ }
|
||||||
|
+ void increaseCorrect() {
|
||||||
|
+ m_correctUploads++;
|
||||||
|
+ }
|
||||||
|
+ void increaseCorrupt() {
|
||||||
|
+ m_corruptUploads++;
|
||||||
|
+ }
|
||||||
|
+ void replyFinished() {
|
||||||
|
+ m_repliesFinished++;
|
||||||
|
+ if (m_repliesFinished == m_expectedReplies) {
|
||||||
|
+ QTestEventLoop::instance().exitLoop();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+void tst_QNetworkReply::putWithServerClosingConnectionImmediately()
|
||||||
|
+{
|
||||||
|
+ const int numUploads = 40;
|
||||||
|
+ qint64 wantedSize = 512*1024; // 512 kB
|
||||||
|
+ QByteArray sourceFile;
|
||||||
|
+ for (int i = 0; i < wantedSize; ++i) {
|
||||||
|
+ sourceFile += (char)'a' +(i%26);
|
||||||
|
+ }
|
||||||
|
+ bool withSsl = false;
|
||||||
|
+
|
||||||
|
+ for (int s = 0; s <= 1; s++) {
|
||||||
|
+ withSsl = (s == 1);
|
||||||
|
+ // Test also needs to run several times because of 9c2ecf89
|
||||||
|
+ for (int j = 0; j < 20; j++) {
|
||||||
|
+ // emulate a minimal https server
|
||||||
|
+ PutWithServerClosingConnectionImmediatelyServer server;
|
||||||
|
+ server.m_ssl = withSsl;
|
||||||
|
+ server.m_expectedData = sourceFile;
|
||||||
|
+ server.m_expectedReplies = numUploads;
|
||||||
|
+ server.listen(QHostAddress(QHostAddress::LocalHost), 0);
|
||||||
|
+
|
||||||
|
+ for (int i = 0; i < numUploads; i++) {
|
||||||
|
+ // create the request
|
||||||
|
+ QUrl url = QUrl(QString("http%1://127.0.0.1:%2/file=%3").arg(withSsl ? "s" : "").arg(server.serverPort()).arg(i));
|
||||||
|
+ QNetworkRequest request(url);
|
||||||
|
+ QNetworkReply *reply = manager.put(request, sourceFile);
|
||||||
|
+ connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply, SLOT(ignoreSslErrors()));
|
||||||
|
+ connect(reply, SIGNAL(finished()), &server, SLOT(replyFinished()));
|
||||||
|
+ reply->setParent(&server);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // get the request started and the incoming socket connected
|
||||||
|
+ QTestEventLoop::instance().enterLoop(10);
|
||||||
|
+
|
||||||
|
+ //qDebug() << "correct=" << server.m_correctUploads << "corrupt=" << server.m_corruptUploads << "expected=" <<numUploads;
|
||||||
|
+
|
||||||
|
+ // Sanity check because ecause of 9c2ecf89 most replies will error out but we want to make sure at least some of them worked
|
||||||
|
+ QVERIFY(server.m_correctUploads > 5);
|
||||||
|
+ // Because actually important is that we don't get any corruption:
|
||||||
|
+ QCOMPARE(server.m_corruptUploads, 0);
|
||||||
|
+
|
||||||
|
+ server.close();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
// NOTE: This test must be last testcase in tst_qnetworkreply!
|
||||||
|
void tst_QNetworkReply::parentingRepliesToTheApp()
|
||||||
|
--
|
||||||
|
1.9.1
|
||||||
|
|
||||||
@@ -0,0 +1,434 @@
|
|||||||
|
From eae0cb09f1310e755c2aff7c1112f7a6c09d7a53 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Markus Goetz <markus@woboq.com>
|
||||||
|
Date: Fri, 19 Jun 2015 15:35:34 +0200
|
||||||
|
Subject: [PATCH] Network: Fix up previous corruption patch
|
||||||
|
|
||||||
|
This is a fix-up for cff39fba10ffc10ee4dcfdc66ff6528eb26462d3.
|
||||||
|
That patch lead to some internal state issues that lead to the QTBUG-47048
|
||||||
|
or to QNetworkReply objects erroring with "Connection Closed" when
|
||||||
|
the server closed the Keep-Alive connection.
|
||||||
|
|
||||||
|
This patch changes the QNAM socket slot connections to be DirectConnection.
|
||||||
|
We don't close the socket anymore in slots where it is anyway in a closed state
|
||||||
|
afterwards. This prevents event/stack recursions.
|
||||||
|
We also flush QSslSocket/QTcpSocket receive buffers when receiving a disconnect
|
||||||
|
so that the developer always gets the full decrypted data from the buffers.
|
||||||
|
|
||||||
|
[ChangeLog][QtNetwork] Fix HTTP issues with "Unknown Error" and "Connection Closed"
|
||||||
|
[ChangeLog][QtNetwork][Sockets] Read OS/encrypted read buffers when connection
|
||||||
|
closed by server.
|
||||||
|
|
||||||
|
Change-Id: Ib4d6a2d0d988317e3a5356f36e8dbcee4590beed
|
||||||
|
Task-number: QTBUG-47048
|
||||||
|
Reviewed-by: Kai Koehne <kai.koehne@theqtcompany.com>
|
||||||
|
Reviewed-by: Richard J. Moore <rich@kde.org>
|
||||||
|
---
|
||||||
|
src/network/access/qhttpnetworkconnection.cpp | 1 -
|
||||||
|
.../access/qhttpnetworkconnectionchannel.cpp | 108 +++++++++++++--------
|
||||||
|
.../access/qhttpnetworkconnectionchannel_p.h | 1 +
|
||||||
|
src/network/access/qhttpnetworkreply.cpp | 2 +-
|
||||||
|
src/network/access/qhttpprotocolhandler.cpp | 1 -
|
||||||
|
src/network/socket/qabstractsocket.cpp | 7 +-
|
||||||
|
src/network/ssl/qsslsocket.cpp | 8 ++
|
||||||
|
src/network/ssl/qsslsocket_openssl.cpp | 7 ++
|
||||||
|
.../access/qnetworkreply/tst_qnetworkreply.cpp | 9 +-
|
||||||
|
9 files changed, 94 insertions(+), 50 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
|
||||||
|
index 365ce55..543c70e 100644
|
||||||
|
--- a/src/network/access/qhttpnetworkconnection.cpp
|
||||||
|
+++ b/src/network/access/qhttpnetworkconnection.cpp
|
||||||
|
@@ -917,7 +917,6 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
|
||||||
|
for (int i = 0; i < channelCount; ++i) {
|
||||||
|
if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) {
|
||||||
|
channels[i].resendCurrent = false;
|
||||||
|
- channels[i].state = QHttpNetworkConnectionChannel::IdleState;
|
||||||
|
|
||||||
|
// if this is not possible, error will be emitted and connection terminated
|
||||||
|
if (!channels[i].resetUploadData())
|
||||||
|
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||||
|
index 49c6793..e2f6307 100644
|
||||||
|
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||||
|
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||||
|
@@ -58,6 +58,11 @@ QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
// TODO: Put channel specific stuff here so it does not polute qhttpnetworkconnection.cpp
|
||||||
|
|
||||||
|
+// Because in-flight when sending a request, the server might close our connection (because the persistent HTTP
|
||||||
|
+// connection times out)
|
||||||
|
+// We use 3 because we can get a _q_error 3 times depending on the timing:
|
||||||
|
+static const int reconnectAttemptsDefault = 3;
|
||||||
|
+
|
||||||
|
QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
|
||||||
|
: socket(0)
|
||||||
|
, ssl(false)
|
||||||
|
@@ -69,7 +74,7 @@ QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
|
||||||
|
, resendCurrent(false)
|
||||||
|
, lastStatus(0)
|
||||||
|
, pendingEncrypt(false)
|
||||||
|
- , reconnectAttempts(2)
|
||||||
|
+ , reconnectAttempts(reconnectAttemptsDefault)
|
||||||
|
, authMethod(QAuthenticatorPrivate::None)
|
||||||
|
, proxyAuthMethod(QAuthenticatorPrivate::None)
|
||||||
|
, authenticationCredentialsSent(false)
|
||||||
|
@@ -106,19 +111,18 @@ void QHttpNetworkConnectionChannel::init()
|
||||||
|
socket->setProxy(QNetworkProxy::NoProxy);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
- // We want all signals (except the interactive ones) be connected as QueuedConnection
|
||||||
|
- // because else we're falling into cases where we recurse back into the socket code
|
||||||
|
- // and mess up the state. Always going to the event loop (and expecting that when reading/writing)
|
||||||
|
- // is safer.
|
||||||
|
+ // After some back and forth in all the last years, this is now a DirectConnection because otherwise
|
||||||
|
+ // the state inside the *Socket classes gets messed up, also in conjunction with the socket notifiers
|
||||||
|
+ // which behave slightly differently on Windows vs Linux
|
||||||
|
QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
|
||||||
|
this, SLOT(_q_bytesWritten(qint64)),
|
||||||
|
- Qt::QueuedConnection);
|
||||||
|
+ Qt::DirectConnection);
|
||||||
|
QObject::connect(socket, SIGNAL(connected()),
|
||||||
|
this, SLOT(_q_connected()),
|
||||||
|
- Qt::QueuedConnection);
|
||||||
|
+ Qt::DirectConnection);
|
||||||
|
QObject::connect(socket, SIGNAL(readyRead()),
|
||||||
|
this, SLOT(_q_readyRead()),
|
||||||
|
- Qt::QueuedConnection);
|
||||||
|
+ Qt::DirectConnection);
|
||||||
|
|
||||||
|
// The disconnected() and error() signals may already come
|
||||||
|
// while calling connectToHost().
|
||||||
|
@@ -129,10 +133,10 @@ void QHttpNetworkConnectionChannel::init()
|
||||||
|
qRegisterMetaType<QAbstractSocket::SocketError>();
|
||||||
|
QObject::connect(socket, SIGNAL(disconnected()),
|
||||||
|
this, SLOT(_q_disconnected()),
|
||||||
|
- Qt::QueuedConnection);
|
||||||
|
+ Qt::DirectConnection);
|
||||||
|
QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
|
||||||
|
this, SLOT(_q_error(QAbstractSocket::SocketError)),
|
||||||
|
- Qt::QueuedConnection);
|
||||||
|
+ Qt::DirectConnection);
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef QT_NO_NETWORKPROXY
|
||||||
|
@@ -147,13 +151,13 @@ void QHttpNetworkConnectionChannel::init()
|
||||||
|
// won't be a sslSocket if encrypt is false
|
||||||
|
QObject::connect(sslSocket, SIGNAL(encrypted()),
|
||||||
|
this, SLOT(_q_encrypted()),
|
||||||
|
- Qt::QueuedConnection);
|
||||||
|
+ Qt::DirectConnection);
|
||||||
|
QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
|
||||||
|
this, SLOT(_q_sslErrors(QList<QSslError>)),
|
||||||
|
Qt::DirectConnection);
|
||||||
|
QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
|
||||||
|
this, SLOT(_q_encryptedBytesWritten(qint64)),
|
||||||
|
- Qt::QueuedConnection);
|
||||||
|
+ Qt::DirectConnection);
|
||||||
|
|
||||||
|
if (ignoreAllSslErrors)
|
||||||
|
sslSocket->ignoreSslErrors();
|
||||||
|
@@ -397,7 +401,7 @@ void QHttpNetworkConnectionChannel::allDone()
|
||||||
|
|
||||||
|
// reset the reconnection attempts after we receive a complete reply.
|
||||||
|
// in case of failures, each channel will attempt two reconnects before emitting error.
|
||||||
|
- reconnectAttempts = 2;
|
||||||
|
+ reconnectAttempts = reconnectAttemptsDefault;
|
||||||
|
|
||||||
|
// now the channel can be seen as free/idle again, all signal emissions for the reply have been done
|
||||||
|
if (state != QHttpNetworkConnectionChannel::ClosingState)
|
||||||
|
@@ -651,6 +655,15 @@ void QHttpNetworkConnectionChannel::closeAndResendCurrentRequest()
|
||||||
|
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
+void QHttpNetworkConnectionChannel::resendCurrentRequest()
|
||||||
|
+{
|
||||||
|
+ requeueCurrentlyPipelinedRequests();
|
||||||
|
+ if (reply)
|
||||||
|
+ resendCurrent = true;
|
||||||
|
+ if (qobject_cast<QHttpNetworkConnection*>(connection))
|
||||||
|
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
bool QHttpNetworkConnectionChannel::isSocketBusy() const
|
||||||
|
{
|
||||||
|
return (state & QHttpNetworkConnectionChannel::BusyState);
|
||||||
|
@@ -694,8 +707,8 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- // read the available data before closing
|
||||||
|
- if (isSocketWaiting() || isSocketReading()) {
|
||||||
|
+ // read the available data before closing (also done in _q_error for other codepaths)
|
||||||
|
+ if ((isSocketWaiting() || isSocketReading()) && socket->bytesAvailable()) {
|
||||||
|
if (reply) {
|
||||||
|
state = QHttpNetworkConnectionChannel::ReadingState;
|
||||||
|
_q_receiveReply();
|
||||||
|
@@ -707,7 +720,8 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
|
||||||
|
state = QHttpNetworkConnectionChannel::IdleState;
|
||||||
|
|
||||||
|
requeueCurrentlyPipelinedRequests();
|
||||||
|
- close();
|
||||||
|
+
|
||||||
|
+ pendingEncrypt = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -789,11 +803,19 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||||
|
errorCode = QNetworkReply::ConnectionRefusedError;
|
||||||
|
break;
|
||||||
|
case QAbstractSocket::RemoteHostClosedError:
|
||||||
|
- // try to reconnect/resend before sending an error.
|
||||||
|
- // while "Reading" the _q_disconnected() will handle this.
|
||||||
|
- if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
|
||||||
|
+ // This error for SSL comes twice in a row, first from SSL layer ("The TLS/SSL connection has been closed") then from TCP layer.
|
||||||
|
+ // Depending on timing it can also come three times in a row (first time when we try to write into a closing QSslSocket).
|
||||||
|
+ // The reconnectAttempts handling catches the cases where we can re-send the request.
|
||||||
|
+ if (!reply && state == QHttpNetworkConnectionChannel::IdleState) {
|
||||||
|
+ // Not actually an error, it is normal for Keep-Alive connections to close after some time if no request
|
||||||
|
+ // is sent on them. No need to error the other replies below. Just bail out here.
|
||||||
|
+ // The _q_disconnected will handle the possibly pipelined replies
|
||||||
|
+ return;
|
||||||
|
+ } else if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
|
||||||
|
+ // Try to reconnect/resend before sending an error.
|
||||||
|
+ // While "Reading" the _q_disconnected() will handle this.
|
||||||
|
if (reconnectAttempts-- > 0) {
|
||||||
|
- closeAndResendCurrentRequest();
|
||||||
|
+ resendCurrentRequest();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
errorCode = QNetworkReply::RemoteHostClosedError;
|
||||||
|
@@ -818,24 +840,15 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||||
|
// we can ignore the readbuffersize as the data is already
|
||||||
|
// in memory and we will not receive more data on the socket.
|
||||||
|
reply->setReadBufferSize(0);
|
||||||
|
+ reply->setDownstreamLimited(false);
|
||||||
|
_q_receiveReply();
|
||||||
|
-#ifndef QT_NO_SSL
|
||||||
|
- if (ssl) {
|
||||||
|
- // QT_NO_OPENSSL. The QSslSocket can still have encrypted bytes in the plainsocket.
|
||||||
|
- // So we need to check this if the socket is a QSslSocket. When the socket is flushed
|
||||||
|
- // it will force a decrypt of the encrypted data in the plainsocket.
|
||||||
|
- QSslSocket *sslSocket = static_cast<QSslSocket*>(socket);
|
||||||
|
- qint64 beforeFlush = sslSocket->encryptedBytesAvailable();
|
||||||
|
- while (sslSocket->encryptedBytesAvailable()) {
|
||||||
|
- sslSocket->flush();
|
||||||
|
- _q_receiveReply();
|
||||||
|
- qint64 afterFlush = sslSocket->encryptedBytesAvailable();
|
||||||
|
- if (afterFlush == beforeFlush)
|
||||||
|
- break;
|
||||||
|
- beforeFlush = afterFlush;
|
||||||
|
- }
|
||||||
|
+ if (!reply) {
|
||||||
|
+ // No more reply assigned after the previous call? Then it had been finished successfully.
|
||||||
|
+ requeueCurrentlyPipelinedRequests();
|
||||||
|
+ state = QHttpNetworkConnectionChannel::IdleState;
|
||||||
|
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
|
||||||
|
+ return;
|
||||||
|
}
|
||||||
|
-#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
errorCode = QNetworkReply::RemoteHostClosedError;
|
||||||
|
@@ -846,7 +859,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||||
|
case QAbstractSocket::SocketTimeoutError:
|
||||||
|
// try to reconnect/resend before sending an error.
|
||||||
|
if (state == QHttpNetworkConnectionChannel::WritingState && (reconnectAttempts-- > 0)) {
|
||||||
|
- closeAndResendCurrentRequest();
|
||||||
|
+ resendCurrentRequest();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
errorCode = QNetworkReply::TimeoutError;
|
||||||
|
@@ -860,7 +873,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||||
|
case QAbstractSocket::ProxyConnectionClosedError:
|
||||||
|
// try to reconnect/resend before sending an error.
|
||||||
|
if (reconnectAttempts-- > 0) {
|
||||||
|
- closeAndResendCurrentRequest();
|
||||||
|
+ resendCurrentRequest();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
errorCode = QNetworkReply::ProxyConnectionClosedError;
|
||||||
|
@@ -868,7 +881,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||||
|
case QAbstractSocket::ProxyConnectionTimeoutError:
|
||||||
|
// try to reconnect/resend before sending an error.
|
||||||
|
if (reconnectAttempts-- > 0) {
|
||||||
|
- closeAndResendCurrentRequest();
|
||||||
|
+ resendCurrentRequest();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
errorCode = QNetworkReply::ProxyTimeoutError;
|
||||||
|
@@ -916,8 +929,18 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||||
|
// send the next request
|
||||||
|
QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
|
||||||
|
|
||||||
|
- if (that) //signal emission triggered event loop
|
||||||
|
- close();
|
||||||
|
+ if (that) {
|
||||||
|
+ //signal emission triggered event loop
|
||||||
|
+ if (!socket)
|
||||||
|
+ state = QHttpNetworkConnectionChannel::IdleState;
|
||||||
|
+ else if (socket->state() == QAbstractSocket::UnconnectedState)
|
||||||
|
+ state = QHttpNetworkConnectionChannel::IdleState;
|
||||||
|
+ else
|
||||||
|
+ state = QHttpNetworkConnectionChannel::ClosingState;
|
||||||
|
+
|
||||||
|
+ // pendingEncrypt must only be true in between connected and encrypted states
|
||||||
|
+ pendingEncrypt = false;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef QT_NO_NETWORKPROXY
|
||||||
|
@@ -941,7 +964,8 @@ void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetwor
|
||||||
|
|
||||||
|
void QHttpNetworkConnectionChannel::_q_uploadDataReadyRead()
|
||||||
|
{
|
||||||
|
- sendRequest();
|
||||||
|
+ if (reply)
|
||||||
|
+ sendRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef QT_NO_SSL
|
||||||
|
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
|
||||||
|
index 231fe11..a834b7d 100644
|
||||||
|
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
|
||||||
|
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
|
||||||
|
@@ -169,6 +169,7 @@ public:
|
||||||
|
|
||||||
|
void handleUnexpectedEOF();
|
||||||
|
void closeAndResendCurrentRequest();
|
||||||
|
+ void resendCurrentRequest();
|
||||||
|
|
||||||
|
bool isSocketBusy() const;
|
||||||
|
bool isSocketWriting() const;
|
||||||
|
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
|
||||||
|
index 55863a3..8b71bd8 100644
|
||||||
|
--- a/src/network/access/qhttpnetworkreply.cpp
|
||||||
|
+++ b/src/network/access/qhttpnetworkreply.cpp
|
||||||
|
@@ -191,7 +191,7 @@ QByteArray QHttpNetworkReply::readAny()
|
||||||
|
return QByteArray();
|
||||||
|
|
||||||
|
// we'll take the last buffer, so schedule another read from http
|
||||||
|
- if (d->downstreamLimited && d->responseData.bufferCount() == 1)
|
||||||
|
+ if (d->downstreamLimited && d->responseData.bufferCount() == 1 && !isFinished())
|
||||||
|
d->connection->d_func()->readMoreLater(this);
|
||||||
|
return d->responseData.read();
|
||||||
|
}
|
||||||
|
diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
|
||||||
|
index 3357948..380aaac 100644
|
||||||
|
--- a/src/network/access/qhttpprotocolhandler.cpp
|
||||||
|
+++ b/src/network/access/qhttpprotocolhandler.cpp
|
||||||
|
@@ -250,7 +250,6 @@ bool QHttpProtocolHandler::sendRequest()
|
||||||
|
if (!m_reply) {
|
||||||
|
// heh, how should that happen!
|
||||||
|
qWarning() << "QAbstractProtocolHandler::sendRequest() called without QHttpNetworkReply";
|
||||||
|
- m_channel->state = QHttpNetworkConnectionChannel::IdleState;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
|
||||||
|
index 2666771..0e82d4a 100644
|
||||||
|
--- a/src/network/socket/qabstractsocket.cpp
|
||||||
|
+++ b/src/network/socket/qabstractsocket.cpp
|
||||||
|
@@ -768,6 +768,7 @@ bool QAbstractSocketPrivate::canReadNotification()
|
||||||
|
void QAbstractSocketPrivate::canCloseNotification()
|
||||||
|
{
|
||||||
|
Q_Q(QAbstractSocket);
|
||||||
|
+ // Note that this method is only called on Windows. Other platforms close in the canReadNotification()
|
||||||
|
|
||||||
|
#if defined (QABSTRACTSOCKET_DEBUG)
|
||||||
|
qDebug("QAbstractSocketPrivate::canCloseNotification()");
|
||||||
|
@@ -777,7 +778,11 @@ void QAbstractSocketPrivate::canCloseNotification()
|
||||||
|
if (isBuffered) {
|
||||||
|
// Try to read to the buffer, if the read fail we can close the socket.
|
||||||
|
newBytes = buffer.size();
|
||||||
|
- if (!readFromSocket()) {
|
||||||
|
+ qint64 oldReadBufferMaxSize = readBufferMaxSize;
|
||||||
|
+ readBufferMaxSize = 0; // temporarily disable max read buffer, we want to empty the OS buffer
|
||||||
|
+ bool hadReadFromSocket = readFromSocket();
|
||||||
|
+ readBufferMaxSize = oldReadBufferMaxSize;
|
||||||
|
+ if (!hadReadFromSocket) {
|
||||||
|
q->disconnectFromHost();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
|
||||||
|
index c1fab94..2b9e923 100644
|
||||||
|
--- a/src/network/ssl/qsslsocket.cpp
|
||||||
|
+++ b/src/network/ssl/qsslsocket.cpp
|
||||||
|
@@ -2294,6 +2294,14 @@ void QSslSocketPrivate::_q_errorSlot(QAbstractSocket::SocketError error)
|
||||||
|
qCDebug(lcSsl) << "\tstate =" << q->state();
|
||||||
|
qCDebug(lcSsl) << "\terrorString =" << q->errorString();
|
||||||
|
#endif
|
||||||
|
+ // this moves encrypted bytes from plain socket into our buffer
|
||||||
|
+ if (plainSocket->bytesAvailable()) {
|
||||||
|
+ qint64 tmpReadBufferMaxSize = readBufferMaxSize;
|
||||||
|
+ readBufferMaxSize = 0; // reset temporarily so the plain sockets completely drained drained
|
||||||
|
+ transmit();
|
||||||
|
+ readBufferMaxSize = tmpReadBufferMaxSize;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
q->setSocketError(plainSocket->error());
|
||||||
|
q->setErrorString(plainSocket->errorString());
|
||||||
|
emit q->error(error);
|
||||||
|
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
|
||||||
|
index ac4336a..94655fe 100644
|
||||||
|
--- a/src/network/ssl/qsslsocket_openssl.cpp
|
||||||
|
+++ b/src/network/ssl/qsslsocket_openssl.cpp
|
||||||
|
@@ -1419,6 +1419,13 @@ void QSslSocketBackendPrivate::disconnected()
|
||||||
|
{
|
||||||
|
if (plainSocket->bytesAvailable() <= 0)
|
||||||
|
destroySslContext();
|
||||||
|
+ else {
|
||||||
|
+ // Move all bytes into the plain buffer
|
||||||
|
+ qint64 tmpReadBufferMaxSize = readBufferMaxSize;
|
||||||
|
+ readBufferMaxSize = 0; // reset temporarily so the plain socket buffer is completely drained
|
||||||
|
+ transmit();
|
||||||
|
+ readBufferMaxSize = tmpReadBufferMaxSize;
|
||||||
|
+ }
|
||||||
|
//if there is still buffered data in the plain socket, don't destroy the ssl context yet.
|
||||||
|
//it will be destroyed when the socket is deleted.
|
||||||
|
}
|
||||||
|
diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
|
||||||
|
index d2edf67..138f528 100644
|
||||||
|
--- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
|
||||||
|
+++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
|
||||||
|
@@ -1051,7 +1051,7 @@ protected:
|
||||||
|
// clean up QAbstractSocket's residue:
|
||||||
|
while (client->bytesToWrite() > 0) {
|
||||||
|
qDebug() << "Still having" << client->bytesToWrite() << "bytes to write, doing that now";
|
||||||
|
- if (!client->waitForBytesWritten(2000)) {
|
||||||
|
+ if (!client->waitForBytesWritten(10000)) {
|
||||||
|
qDebug() << "ERROR: FastSender:" << client->error() << "cleaning up residue";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@@ -1071,7 +1071,7 @@ protected:
|
||||||
|
measuredSentBytes += writeNextData(client, bytesToWrite);
|
||||||
|
|
||||||
|
while (client->bytesToWrite() > 0) {
|
||||||
|
- if (!client->waitForBytesWritten(2000)) {
|
||||||
|
+ if (!client->waitForBytesWritten(10000)) {
|
||||||
|
qDebug() << "ERROR: FastSender:" << client->error() << "during blocking write";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@@ -7946,7 +7946,7 @@ public slots:
|
||||||
|
m_receivedData += data;
|
||||||
|
if (!m_parsedHeaders && m_receivedData.contains("\r\n\r\n")) {
|
||||||
|
m_parsedHeaders = true;
|
||||||
|
- QTimer::singleShot(qrand()%10, this, SLOT(closeDelayed())); // simulate random network latency
|
||||||
|
+ QTimer::singleShot(qrand()%60, this, SLOT(closeDelayed())); // simulate random network latency
|
||||||
|
// This server simulates a web server connection closing, e.g. because of Apaches MaxKeepAliveRequests or KeepAliveTimeout
|
||||||
|
// In this case QNAM needs to re-send the upload data but it had a bug which then corrupts the upload
|
||||||
|
// This test catches that.
|
||||||
|
@@ -8052,11 +8052,12 @@ void tst_QNetworkReply::putWithServerClosingConnectionImmediately()
|
||||||
|
|
||||||
|
// get the request started and the incoming socket connected
|
||||||
|
QTestEventLoop::instance().enterLoop(10);
|
||||||
|
+ QVERIFY(!QTestEventLoop::instance().timeout());
|
||||||
|
|
||||||
|
//qDebug() << "correct=" << server.m_correctUploads << "corrupt=" << server.m_corruptUploads << "expected=" <<numUploads;
|
||||||
|
|
||||||
|
// Sanity check because ecause of 9c2ecf89 most replies will error out but we want to make sure at least some of them worked
|
||||||
|
- QVERIFY(server.m_correctUploads > 5);
|
||||||
|
+ QVERIFY(server.m_correctUploads > 2);
|
||||||
|
// Because actually important is that we don't get any corruption:
|
||||||
|
QCOMPARE(server.m_corruptUploads, 0);
|
||||||
|
|
||||||
|
--
|
||||||
|
1.9.1
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
From bc32c0ebc0bc00db84ca2f28eb16ab2e5b53a1b6 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Markus Goetz <markus@woboq.com>
|
||||||
|
Date: Fri, 24 Jul 2015 09:53:20 +0200
|
||||||
|
Subject: [PATCH] QNAM: Fix reply deadlocks on server closing connection
|
||||||
|
|
||||||
|
The _q_readyRead can also be called from readMoreLater() because we implemented
|
||||||
|
it so that bandwidth limited reading can be implemented.
|
||||||
|
This can lead to a race condition if the socket is closing at the specific moment
|
||||||
|
and then deadlock the channel: It will stay unusable with a zombie request.
|
||||||
|
The fix in QHttpProtocolaHandler checks if there is actually bytes available to read
|
||||||
|
from the socket and only then continue.
|
||||||
|
|
||||||
|
The fix in the HTTP channel needs to be done to properly finish the reply in
|
||||||
|
cases of a server replying with HTTP/1.0 or "Connection: close".
|
||||||
|
The delayed incovation of _q_receiveReply will properly finish up the reply.
|
||||||
|
|
||||||
|
Change-Id: I19ce2ae595f91d56386cc7406ccacc9935672b6b
|
||||||
|
Reviewed-by: Richard J. Moore <rich@kde.org>
|
||||||
|
---
|
||||||
|
src/network/access/qhttpnetworkconnectionchannel.cpp | 4 ++++
|
||||||
|
src/network/access/qhttpprotocolhandler.cpp | 7 ++++++-
|
||||||
|
2 files changed, 10 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||||
|
index 7428f9b..257aa13 100644
|
||||||
|
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||||
|
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||||
|
@@ -829,11 +829,15 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||||
|
|
||||||
|
if (!reply->d_func()->expectContent()) {
|
||||||
|
// No content expected, this is a valid way to have the connection closed by the server
|
||||||
|
+ // We need to invoke this asynchronously to make sure the state() of the socket is on QAbstractSocket::UnconnectedState
|
||||||
|
+ QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (reply->contentLength() == -1 && !reply->d_func()->isChunked()) {
|
||||||
|
// There was no content-length header and it's not chunked encoding,
|
||||||
|
// so this is a valid way to have the connection closed by the server
|
||||||
|
+ // We need to invoke this asynchronously to make sure the state() of the socket is on QAbstractSocket::UnconnectedState
|
||||||
|
+ QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// ok, we got a disconnect even though we did not expect it
|
||||||
|
diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
|
||||||
|
index ab2e3da..a208315 100644
|
||||||
|
--- a/src/network/access/qhttpprotocolhandler.cpp
|
||||||
|
+++ b/src/network/access/qhttpprotocolhandler.cpp
|
||||||
|
@@ -237,7 +237,12 @@ void QHttpProtocolHandler::_q_readyRead()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_channel->isSocketWaiting() || m_channel->isSocketReading()) {
|
||||||
|
- m_channel->state = QHttpNetworkConnectionChannel::ReadingState;
|
||||||
|
+ if (m_socket->bytesAvailable()) {
|
||||||
|
+ // We might get a spurious call from readMoreLater()
|
||||||
|
+ // call of the QHttpNetworkConnection even while the socket is disconnecting.
|
||||||
|
+ // Therefore check if there is actually bytes available before changing the channel state.
|
||||||
|
+ m_channel->state = QHttpNetworkConnectionChannel::ReadingState;
|
||||||
|
+ }
|
||||||
|
if (m_reply)
|
||||||
|
_q_receiveReply();
|
||||||
|
}
|
||||||
|
--
|
||||||
|
1.9.1
|
||||||
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
From 63cf5d3d26a6f65938c3cdec1734eac9faaaf8cb Mon Sep 17 00:00:00 2001
|
||||||
|
From: Markus Goetz <markus@woboq.com>
|
||||||
|
Date: Tue, 22 Sep 2015 14:26:24 -0400
|
||||||
|
Subject: [PATCH] QNAM: Assign proper channel before sslErrors() emission
|
||||||
|
|
||||||
|
There can be a race condition where another channel connects
|
||||||
|
and gets the sslErrors() from the socket first. Then the
|
||||||
|
QSslConfiguration from the wrong socket (the default
|
||||||
|
channel 0's socket) was used.
|
||||||
|
|
||||||
|
Task-number: QTBUG-18722
|
||||||
|
Change-Id: Ibbfa48c27f181563745daf540fa792a57cc09682
|
||||||
|
Reviewed-by: Richard J. Moore <rich@kde.org>
|
||||||
|
---
|
||||||
|
src/network/access/qhttpnetworkconnectionchannel.cpp | 2 ++
|
||||||
|
1 file changed, 2 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||||
|
index 257aa13..477cba2 100644
|
||||||
|
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||||
|
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||||
|
@@ -1066,6 +1066,8 @@ void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
|
||||||
|
connection->d_func()->pauseConnection();
|
||||||
|
if (pendingEncrypt && !reply)
|
||||||
|
connection->d_func()->dequeueRequest(socket);
|
||||||
|
+ if (reply) // a reply was actually dequeued.
|
||||||
|
+ reply->d_func()->connectionChannel = this; // set correct channel like in sendRequest() and queueRequest();
|
||||||
|
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP) {
|
||||||
|
if (reply)
|
||||||
|
emit reply->sslErrors(errors);
|
||||||
|
--
|
||||||
|
1.9.1
|
||||||
|
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
From 0df5d079290b4c3b13e58e9397fabdc1dfdba96b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ulf Hermann <ulf.hermann@theqtcompany.com>
|
||||||
|
Date: Fri, 25 Sep 2015 13:23:46 +0200
|
||||||
|
Subject: [PATCH] Don't let closed http sockets pass as valid connections
|
||||||
|
|
||||||
|
A QAbstractSocket can be close()'d at any time, independently of its
|
||||||
|
current connection state. being closed means that we cannot use it to
|
||||||
|
read or write data, but internally it might still have some data to
|
||||||
|
send or receive, for example to an http server. We can even get a
|
||||||
|
connected() signal after close()'ing the socket.
|
||||||
|
|
||||||
|
We need to catch this condition and mark any pending data not yet
|
||||||
|
written to the socket for resending.
|
||||||
|
|
||||||
|
Task-number: QTBUG-48326
|
||||||
|
Change-Id: I6f61c35f2c567f2a138f8cfe9ade7fd1ec039be6
|
||||||
|
Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
|
||||||
|
---
|
||||||
|
.../access/qhttpnetworkconnectionchannel.cpp | 7 ++-
|
||||||
|
.../tst_qhttpnetworkconnection.cpp | 54 ++++++++++++++++++++++
|
||||||
|
2 files changed, 60 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||||
|
index 293909c..b4eda34 100644
|
||||||
|
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||||
|
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
|
||||||
|
@@ -272,7 +272,12 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
|
||||||
|
QAbstractSocket::SocketState socketState = socket->state();
|
||||||
|
|
||||||
|
// resend this request after we receive the disconnected signal
|
||||||
|
- if (socketState == QAbstractSocket::ClosingState) {
|
||||||
|
+ // If !socket->isOpen() then we have already called close() on the socket, but there was still a
|
||||||
|
+ // pending connectToHost() for which we hadn't seen a connected() signal, yet. The connected()
|
||||||
|
+ // has now arrived (as indicated by socketState != ClosingState), but we cannot send anything on
|
||||||
|
+ // such a socket anymore.
|
||||||
|
+ if (socketState == QAbstractSocket::ClosingState ||
|
||||||
|
+ (socketState != QAbstractSocket::UnconnectedState && !socket->isOpen())) {
|
||||||
|
if (reply)
|
||||||
|
resendCurrent = true;
|
||||||
|
return false;
|
||||||
|
diff --git a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp
|
||||||
|
index 5d072af..0d188a8 100644
|
||||||
|
--- a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp
|
||||||
|
+++ b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp
|
||||||
|
@@ -36,6 +36,7 @@
|
||||||
|
#include "private/qhttpnetworkconnection_p.h"
|
||||||
|
#include "private/qnoncontiguousbytedevice_p.h"
|
||||||
|
#include <QAuthenticator>
|
||||||
|
+#include <QTcpServer>
|
||||||
|
|
||||||
|
#include "../../../network-settings.h"
|
||||||
|
|
||||||
|
@@ -106,6 +107,8 @@ private Q_SLOTS:
|
||||||
|
|
||||||
|
void getAndThenDeleteObject();
|
||||||
|
void getAndThenDeleteObject_data();
|
||||||
|
+
|
||||||
|
+ void overlappingCloseAndWrite();
|
||||||
|
};
|
||||||
|
|
||||||
|
tst_QHttpNetworkConnection::tst_QHttpNetworkConnection()
|
||||||
|
@@ -1112,6 +1115,57 @@ void tst_QHttpNetworkConnection::getAndThenDeleteObject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+class TestTcpServer : public QTcpServer
|
||||||
|
+{
|
||||||
|
+ Q_OBJECT
|
||||||
|
+public:
|
||||||
|
+ TestTcpServer() : errorCodeReports(0)
|
||||||
|
+ {
|
||||||
|
+ connect(this, &QTcpServer::newConnection, this, &TestTcpServer::onNewConnection);
|
||||||
|
+ QVERIFY(listen(QHostAddress::LocalHost));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ int errorCodeReports;
|
||||||
|
+
|
||||||
|
+public slots:
|
||||||
|
+ void onNewConnection()
|
||||||
|
+ {
|
||||||
|
+ QTcpSocket *socket = nextPendingConnection();
|
||||||
|
+ if (!socket)
|
||||||
|
+ return;
|
||||||
|
+ // close socket instantly!
|
||||||
|
+ connect(socket, &QTcpSocket::readyRead, socket, &QTcpSocket::close);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ void onReply(QNetworkReply::NetworkError code)
|
||||||
|
+ {
|
||||||
|
+ QCOMPARE(code, QNetworkReply::RemoteHostClosedError);
|
||||||
|
+ ++errorCodeReports;
|
||||||
|
+ }
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+void tst_QHttpNetworkConnection::overlappingCloseAndWrite()
|
||||||
|
+{
|
||||||
|
+ // server accepts connections, but closes the socket instantly
|
||||||
|
+ TestTcpServer server;
|
||||||
|
+ QNetworkAccessManager accessManager;
|
||||||
|
+
|
||||||
|
+ // ten requests are scheduled. All should result in an RemoteHostClosed...
|
||||||
|
+ QUrl url;
|
||||||
|
+ url.setScheme(QStringLiteral("http"));
|
||||||
|
+ url.setHost(server.serverAddress().toString());
|
||||||
|
+ url.setPort(server.serverPort());
|
||||||
|
+ for (int i = 0; i < 10; ++i) {
|
||||||
|
+ QNetworkRequest request(url);
|
||||||
|
+ QNetworkReply *reply = accessManager.get(request);
|
||||||
|
+ // Not using Qt5 connection syntax here because of overly baroque syntax to discern between
|
||||||
|
+ // different error() methods.
|
||||||
|
+ QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
|
||||||
|
+ &server, SLOT(onReply(QNetworkReply::NetworkError)));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ QTRY_COMPARE(server.errorCodeReports, 10);
|
||||||
|
+}
|
||||||
|
|
||||||
|
|
||||||
|
QTEST_MAIN(tst_QHttpNetworkConnection)
|
||||||
|
--
|
||||||
|
1.9.1
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
From c056e63cea1915667997c982f48296ce5acdcc80 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lorn Potter <lorn.potter@gmail.com>
|
||||||
|
Date: Tue, 2 Jun 2015 13:22:23 +1000
|
||||||
|
Subject: [PATCH] Make sure to report correct NetworkAccessibility
|
||||||
|
|
||||||
|
Task-number: QTBUG-46323
|
||||||
|
Change-Id: Ibdeb3280091a97d785d4314340678a63e88fb219
|
||||||
|
Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
|
||||||
|
Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
|
||||||
|
---
|
||||||
|
src/network/access/qnetworkaccessmanager.cpp | 25 +++++++++++++++++--------
|
||||||
|
src/network/access/qnetworkaccessmanager_p.h | 2 ++
|
||||||
|
2 files changed, 19 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
|
||||||
|
index e878feb..84931cb 100644
|
||||||
|
--- a/src/network/access/qnetworkaccessmanager.cpp
|
||||||
|
+++ b/src/network/access/qnetworkaccessmanager.cpp
|
||||||
|
@@ -472,11 +472,11 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
|
||||||
|
// the QNetworkSession's signals
|
||||||
|
connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)),
|
||||||
|
SLOT(_q_onlineStateChanged(bool)));
|
||||||
|
- // we would need all active configurations to check for
|
||||||
|
- // d->networkConfigurationManager.isOnline(), which is asynchronous
|
||||||
|
- // and potentially expensive. We can just check the configuration here
|
||||||
|
- d->online = (d->networkConfiguration.state() & QNetworkConfiguration::Active);
|
||||||
|
}
|
||||||
|
+ // we would need all active configurations to check for
|
||||||
|
+ // d->networkConfigurationManager.isOnline(), which is asynchronous
|
||||||
|
+ // and potentially expensive. We can just check the configuration here
|
||||||
|
+ d->online = (d->networkConfiguration.state() & QNetworkConfiguration::Active);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -946,6 +946,7 @@ QNetworkConfiguration QNetworkAccessManager::activeConfiguration() const
|
||||||
|
void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkAccessibility accessible)
|
||||||
|
{
|
||||||
|
Q_D(QNetworkAccessManager);
|
||||||
|
+ d->defaultAccessControl = false;
|
||||||
|
|
||||||
|
if (d->networkAccessible != accessible) {
|
||||||
|
NetworkAccessibility previous = networkAccessible();
|
||||||
|
@@ -964,7 +965,6 @@ void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkA
|
||||||
|
QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccessible() const
|
||||||
|
{
|
||||||
|
Q_D(const QNetworkAccessManager);
|
||||||
|
-
|
||||||
|
if (d->networkSessionRequired) {
|
||||||
|
QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession());
|
||||||
|
if (networkSession) {
|
||||||
|
@@ -975,7 +975,13 @@ QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccess
|
||||||
|
return NotAccessible;
|
||||||
|
} else {
|
||||||
|
// Network accessibility is either disabled or unknown.
|
||||||
|
- return (d->networkAccessible == NotAccessible) ? NotAccessible : UnknownAccessibility;
|
||||||
|
+ if (d->defaultAccessControl) {
|
||||||
|
+ if (d->online)
|
||||||
|
+ return d->networkAccessible;
|
||||||
|
+ else
|
||||||
|
+ return NotAccessible;
|
||||||
|
+ }
|
||||||
|
+ return (d->networkAccessible);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (d->online)
|
||||||
|
@@ -1568,7 +1574,7 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co
|
||||||
|
if (!networkSessionStrongRef) {
|
||||||
|
online = false;
|
||||||
|
|
||||||
|
- if (networkAccessible == QNetworkAccessManager::NotAccessible)
|
||||||
|
+ if (networkAccessible == QNetworkAccessManager::NotAccessible || !online)
|
||||||
|
emit q->networkAccessibleChanged(QNetworkAccessManager::NotAccessible);
|
||||||
|
else
|
||||||
|
emit q->networkAccessibleChanged(QNetworkAccessManager::UnknownAccessibility);
|
||||||
|
@@ -1616,11 +1622,14 @@ void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession
|
||||||
|
if (online) {
|
||||||
|
if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) {
|
||||||
|
online = false;
|
||||||
|
- emit q->networkAccessibleChanged(QNetworkAccessManager::NotAccessible);
|
||||||
|
+ networkAccessible = QNetworkAccessManager::NotAccessible;
|
||||||
|
+ emit q->networkAccessibleChanged(networkAccessible);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (state == QNetworkSession::Connected || state == QNetworkSession::Roaming) {
|
||||||
|
online = true;
|
||||||
|
+ if (defaultAccessControl)
|
||||||
|
+ networkAccessible = QNetworkAccessManager::Accessible;
|
||||||
|
emit q->networkAccessibleChanged(networkAccessible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
|
||||||
|
index f513324..c715da0 100644
|
||||||
|
--- a/src/network/access/qnetworkaccessmanager_p.h
|
||||||
|
+++ b/src/network/access/qnetworkaccessmanager_p.h
|
||||||
|
@@ -84,6 +84,7 @@ public:
|
||||||
|
initializeSession(true),
|
||||||
|
#endif
|
||||||
|
cookieJarCreated(false),
|
||||||
|
+ defaultAccessControl(true),
|
||||||
|
authenticationManager(QSharedPointer<QNetworkAccessAuthenticationManager>::create())
|
||||||
|
{ }
|
||||||
|
~QNetworkAccessManagerPrivate();
|
||||||
|
@@ -164,6 +165,7 @@ public:
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool cookieJarCreated;
|
||||||
|
+ bool defaultAccessControl;
|
||||||
|
|
||||||
|
// The cache with authorization data:
|
||||||
|
QSharedPointer<QNetworkAccessAuthenticationManager> authenticationManager;
|
||||||
|
--
|
||||||
|
1.9.1
|
||||||
|
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
From bb281eea179d50a413f4ec1ff172d27ee48d3a41 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lorn Potter <lorn.potter@gmail.com>
|
||||||
|
Date: Fri, 17 Jul 2015 15:32:23 +1000
|
||||||
|
Subject: [PATCH] Make sure networkAccessibilityChanged is emitted
|
||||||
|
|
||||||
|
Task-number: QTBUG-46323
|
||||||
|
Change-Id: I8297072b62763136f457ca6ae15282d1c22244f4
|
||||||
|
Reviewed-by: Timo Jyrinki <timo.jyrinki@canonical.com>
|
||||||
|
Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
|
||||||
|
---
|
||||||
|
src/network/access/qnetworkaccessmanager.cpp | 70 +++++++++++++++-------
|
||||||
|
src/network/access/qnetworkaccessmanager_p.h | 14 ++++-
|
||||||
|
.../tst_qnetworkaccessmanager.cpp | 31 +++++-----
|
||||||
|
3 files changed, 77 insertions(+), 38 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
|
||||||
|
index 84931cb..f9e9513 100644
|
||||||
|
--- a/src/network/access/qnetworkaccessmanager.cpp
|
||||||
|
+++ b/src/network/access/qnetworkaccessmanager.cpp
|
||||||
|
@@ -278,7 +278,8 @@ static void ensureInitialized()
|
||||||
|
|
||||||
|
\snippet code/src_network_access_qnetworkaccessmanager.cpp 4
|
||||||
|
|
||||||
|
- Network requests can be reenabled again by calling
|
||||||
|
+ Network requests can be re-enabled again, and this property will resume to
|
||||||
|
+ reflect the actual device state by calling
|
||||||
|
|
||||||
|
\snippet code/src_network_access_qnetworkaccessmanager.cpp 5
|
||||||
|
|
||||||
|
@@ -467,16 +468,12 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
|
||||||
|
qRegisterMetaType<QSharedPointer<char> >();
|
||||||
|
|
||||||
|
#ifndef QT_NO_BEARERMANAGEMENT
|
||||||
|
- if (!d->networkSessionRequired) {
|
||||||
|
- // if a session is required, we track online state through
|
||||||
|
- // the QNetworkSession's signals
|
||||||
|
- connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)),
|
||||||
|
- SLOT(_q_onlineStateChanged(bool)));
|
||||||
|
- }
|
||||||
|
- // we would need all active configurations to check for
|
||||||
|
- // d->networkConfigurationManager.isOnline(), which is asynchronous
|
||||||
|
- // and potentially expensive. We can just check the configuration here
|
||||||
|
- d->online = (d->networkConfiguration.state() & QNetworkConfiguration::Active);
|
||||||
|
+ // if a session is required, we track online state through
|
||||||
|
+ // the QNetworkSession's signals if a request is already made.
|
||||||
|
+ // we need to track current accessibility state by default
|
||||||
|
+ //
|
||||||
|
+ connect(&d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)),
|
||||||
|
+ SLOT(_q_onlineStateChanged(bool)));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -946,7 +943,8 @@ QNetworkConfiguration QNetworkAccessManager::activeConfiguration() const
|
||||||
|
void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkAccessibility accessible)
|
||||||
|
{
|
||||||
|
Q_D(QNetworkAccessManager);
|
||||||
|
- d->defaultAccessControl = false;
|
||||||
|
+
|
||||||
|
+ d->defaultAccessControl = accessible == NotAccessible ? false : true;
|
||||||
|
|
||||||
|
if (d->networkAccessible != accessible) {
|
||||||
|
NetworkAccessibility previous = networkAccessible();
|
||||||
|
@@ -965,6 +963,10 @@ void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkA
|
||||||
|
QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccessible() const
|
||||||
|
{
|
||||||
|
Q_D(const QNetworkAccessManager);
|
||||||
|
+
|
||||||
|
+ if (d->networkConfiguration.state().testFlag(QNetworkConfiguration::Undefined))
|
||||||
|
+ return UnknownAccessibility;
|
||||||
|
+
|
||||||
|
if (d->networkSessionRequired) {
|
||||||
|
QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession());
|
||||||
|
if (networkSession) {
|
||||||
|
@@ -1622,32 +1624,56 @@ void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession
|
||||||
|
if (online) {
|
||||||
|
if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) {
|
||||||
|
online = false;
|
||||||
|
- networkAccessible = QNetworkAccessManager::NotAccessible;
|
||||||
|
- emit q->networkAccessibleChanged(networkAccessible);
|
||||||
|
+ if (networkAccessible != QNetworkAccessManager::NotAccessible) {
|
||||||
|
+ networkAccessible = QNetworkAccessManager::NotAccessible;
|
||||||
|
+ emit q->networkAccessibleChanged(networkAccessible);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (state == QNetworkSession::Connected || state == QNetworkSession::Roaming) {
|
||||||
|
online = true;
|
||||||
|
if (defaultAccessControl)
|
||||||
|
- networkAccessible = QNetworkAccessManager::Accessible;
|
||||||
|
- emit q->networkAccessibleChanged(networkAccessible);
|
||||||
|
+ if (networkAccessible != QNetworkAccessManager::Accessible) {
|
||||||
|
+ networkAccessible = QNetworkAccessManager::Accessible;
|
||||||
|
+ emit q->networkAccessibleChanged(networkAccessible);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline)
|
||||||
|
{
|
||||||
|
- // if the user set a config, we only care whether this one is active.
|
||||||
|
+ Q_Q(QNetworkAccessManager);
|
||||||
|
+ // if the user set a config, we only care whether this one is active.
|
||||||
|
// Otherwise, this QNAM is online if there is an online config.
|
||||||
|
if (customNetworkConfiguration) {
|
||||||
|
online = (networkConfiguration.state() & QNetworkConfiguration::Active);
|
||||||
|
} else {
|
||||||
|
- if (isOnline && online != isOnline) {
|
||||||
|
- networkSessionStrongRef.clear();
|
||||||
|
- networkSessionWeakRef.clear();
|
||||||
|
+ if (online != isOnline) {
|
||||||
|
+ if (isOnline) {
|
||||||
|
+ networkSessionStrongRef.clear();
|
||||||
|
+ networkSessionWeakRef.clear();
|
||||||
|
+ }
|
||||||
|
+ online = isOnline;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (online) {
|
||||||
|
+ if (defaultAccessControl) {
|
||||||
|
+ if (networkAccessible != QNetworkAccessManager::Accessible) {
|
||||||
|
+ networkAccessible = QNetworkAccessManager::Accessible;
|
||||||
|
+ emit q->networkAccessibleChanged(networkAccessible);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ } else if (networkConfiguration.state().testFlag(QNetworkConfiguration::Undefined)) {
|
||||||
|
+ if (networkAccessible != QNetworkAccessManager::UnknownAccessibility) {
|
||||||
|
+ networkAccessible = QNetworkAccessManager::UnknownAccessibility;
|
||||||
|
+ emit q->networkAccessibleChanged(networkAccessible);
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ if (networkAccessible != QNetworkAccessManager::NotAccessible) {
|
||||||
|
+ networkAccessible = QNetworkAccessManager::NotAccessible;
|
||||||
|
+ emit q->networkAccessibleChanged(networkAccessible);
|
||||||
|
}
|
||||||
|
-
|
||||||
|
- online = isOnline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
|
||||||
|
index c715da0..54ae114 100644
|
||||||
|
--- a/src/network/access/qnetworkaccessmanager_p.h
|
||||||
|
+++ b/src/network/access/qnetworkaccessmanager_p.h
|
||||||
|
@@ -78,7 +78,6 @@ public:
|
||||||
|
customNetworkConfiguration(false),
|
||||||
|
networkSessionRequired(networkConfigurationManager.capabilities()
|
||||||
|
& QNetworkConfigurationManager::NetworkSessionRequired),
|
||||||
|
- networkAccessible(QNetworkAccessManager::Accessible),
|
||||||
|
activeReplyCount(0),
|
||||||
|
online(false),
|
||||||
|
initializeSession(true),
|
||||||
|
@@ -86,7 +85,18 @@ public:
|
||||||
|
cookieJarCreated(false),
|
||||||
|
defaultAccessControl(true),
|
||||||
|
authenticationManager(QSharedPointer<QNetworkAccessAuthenticationManager>::create())
|
||||||
|
- { }
|
||||||
|
+ {
|
||||||
|
+#ifndef QT_NO_BEARERMANAGEMENT
|
||||||
|
+ // we would need all active configurations to check for
|
||||||
|
+ // d->networkConfigurationManager.isOnline(), which is asynchronous
|
||||||
|
+ // and potentially expensive. We can just check the configuration here
|
||||||
|
+ online = (networkConfiguration.state().testFlag(QNetworkConfiguration::Active));
|
||||||
|
+ if (online)
|
||||||
|
+ networkAccessible = QNetworkAccessManager::Accessible;
|
||||||
|
+ else
|
||||||
|
+ networkAccessible = QNetworkAccessManager::NotAccessible;
|
||||||
|
+#endif
|
||||||
|
+ }
|
||||||
|
~QNetworkAccessManagerPrivate();
|
||||||
|
|
||||||
|
void _q_replyFinished();
|
||||||
|
diff --git a/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp b/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp
|
||||||
|
index b4e4b9c..8ecb57d 100644
|
||||||
|
--- a/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp
|
||||||
|
+++ b/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp
|
||||||
|
@@ -74,6 +74,10 @@ void tst_QNetworkAccessManager::networkAccessible()
|
||||||
|
// if there is no session, we cannot know in which state we are in
|
||||||
|
QNetworkAccessManager::NetworkAccessibility initialAccessibility =
|
||||||
|
manager.networkAccessible();
|
||||||
|
+
|
||||||
|
+ if (initialAccessibility == QNetworkAccessManager::UnknownAccessibility)
|
||||||
|
+ QSKIP("Unknown accessibility", SkipAll);
|
||||||
|
+
|
||||||
|
QCOMPARE(manager.networkAccessible(), initialAccessibility);
|
||||||
|
|
||||||
|
manager.setNetworkAccessible(QNetworkAccessManager::NotAccessible);
|
||||||
|
@@ -94,29 +98,28 @@ void tst_QNetworkAccessManager::networkAccessible()
|
||||||
|
QCOMPARE(manager.networkAccessible(), initialAccessibility);
|
||||||
|
|
||||||
|
QNetworkConfigurationManager configManager;
|
||||||
|
- bool sessionRequired = (configManager.capabilities()
|
||||||
|
- & QNetworkConfigurationManager::NetworkSessionRequired);
|
||||||
|
QNetworkConfiguration defaultConfig = configManager.defaultConfiguration();
|
||||||
|
if (defaultConfig.isValid()) {
|
||||||
|
manager.setConfiguration(defaultConfig);
|
||||||
|
|
||||||
|
- // the accessibility has not changed if no session is required
|
||||||
|
- if (sessionRequired) {
|
||||||
|
+ QCOMPARE(spy.count(), 0);
|
||||||
|
+
|
||||||
|
+ if (defaultConfig.state().testFlag(QNetworkConfiguration::Active))
|
||||||
|
+ QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::Accessible);
|
||||||
|
+ else
|
||||||
|
+ QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::NotAccessible);
|
||||||
|
+
|
||||||
|
+ manager.setNetworkAccessible(QNetworkAccessManager::NotAccessible);
|
||||||
|
+
|
||||||
|
+ if (defaultConfig.state().testFlag(QNetworkConfiguration::Active)) {
|
||||||
|
QCOMPARE(spy.count(), 1);
|
||||||
|
- QCOMPARE(spy.takeFirst().at(0).value<QNetworkAccessManager::NetworkAccessibility>(),
|
||||||
|
- QNetworkAccessManager::Accessible);
|
||||||
|
+ QCOMPARE(QNetworkAccessManager::NetworkAccessibility(spy.takeFirst().at(0).toInt()),
|
||||||
|
+ QNetworkAccessManager::NotAccessible);
|
||||||
|
} else {
|
||||||
|
QCOMPARE(spy.count(), 0);
|
||||||
|
}
|
||||||
|
- QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::Accessible);
|
||||||
|
-
|
||||||
|
- manager.setNetworkAccessible(QNetworkAccessManager::NotAccessible);
|
||||||
|
-
|
||||||
|
- QCOMPARE(spy.count(), 1);
|
||||||
|
- QCOMPARE(QNetworkAccessManager::NetworkAccessibility(spy.takeFirst().at(0).toInt()),
|
||||||
|
- QNetworkAccessManager::NotAccessible);
|
||||||
|
- QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::NotAccessible);
|
||||||
|
}
|
||||||
|
+ QCOMPARE(manager.networkAccessible(), QNetworkAccessManager::NotAccessible);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
--
|
||||||
|
1.9.1
|
||||||
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
From e996d68f6130847637ba287518cff1289cfa48e5 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Lorn Potter <lorn.potter@gmail.com>
|
||||||
|
Date: Fri, 6 Nov 2015 14:22:44 +1000
|
||||||
|
Subject: [PATCH] Make UnknownAccessibility not block requests
|
||||||
|
|
||||||
|
This allows requests to proceed without needing bearer plugins.
|
||||||
|
|
||||||
|
Task-number: QTBUG-49267
|
||||||
|
Change-Id: Ie5ce188ddefebd14d666bb5846e8f93ee2925ed1
|
||||||
|
Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
|
||||||
|
---
|
||||||
|
src/network/access/qnetworkaccessmanager.cpp | 3 +--
|
||||||
|
src/network/access/qnetworkaccessmanager_p.h | 2 ++
|
||||||
|
2 files changed, 3 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
|
||||||
|
index 086140f..0e5870a 100644
|
||||||
|
--- a/src/network/access/qnetworkaccessmanager.cpp
|
||||||
|
+++ b/src/network/access/qnetworkaccessmanager.cpp
|
||||||
|
@@ -976,7 +976,6 @@ QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccess
|
||||||
|
else
|
||||||
|
return NotAccessible;
|
||||||
|
} else {
|
||||||
|
- // Network accessibility is either disabled or unknown.
|
||||||
|
if (d->defaultAccessControl) {
|
||||||
|
if (d->online)
|
||||||
|
return d->networkAccessible;
|
||||||
|
@@ -1161,7 +1160,7 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
|
||||||
|
#ifndef QT_NO_BEARERMANAGEMENT
|
||||||
|
// Return a disabled network reply if network access is disabled.
|
||||||
|
// Except if the scheme is empty or file://.
|
||||||
|
- if (!d->networkAccessible && !isLocalFile) {
|
||||||
|
+ if (d->networkAccessible == NotAccessible && !isLocalFile) {
|
||||||
|
return new QDisabledNetworkReply(this, req, op);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
|
||||||
|
index 54ae114..3fc33b5 100644
|
||||||
|
--- a/src/network/access/qnetworkaccessmanager_p.h
|
||||||
|
+++ b/src/network/access/qnetworkaccessmanager_p.h
|
||||||
|
@@ -93,6 +93,8 @@ public:
|
||||||
|
online = (networkConfiguration.state().testFlag(QNetworkConfiguration::Active));
|
||||||
|
if (online)
|
||||||
|
networkAccessible = QNetworkAccessManager::Accessible;
|
||||||
|
+ else if (networkConfiguration.state().testFlag(QNetworkConfiguration::Undefined))
|
||||||
|
+ networkAccessible = QNetworkAccessManager::UnknownAccessibility;
|
||||||
|
else
|
||||||
|
networkAccessible = QNetworkAccessManager::NotAccessible;
|
||||||
|
#endif
|
||||||
|
--
|
||||||
|
1.9.1
|
||||||
|
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
From 06818f6d1c602aa3c4f9356324866432d2dd0195 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Molkentin <daniel@molkentin.de>
|
||||||
|
Date: Mon, 16 Nov 2015 15:02:37 +0100
|
||||||
|
Subject: [PATCH 1/2] Remove legacy platform code in QSslSocket for OS X < 10.5
|
||||||
|
|
||||||
|
This avoids manual symbol lookups and makes the code more readable.
|
||||||
|
Mark identical code.
|
||||||
|
|
||||||
|
Also use smart pointers instead of manual memory management.
|
||||||
|
|
||||||
|
(Backport of d42d7781f1cd62c3c7c008859507f24a1ff5bb2a to Qt 5.4)
|
||||||
|
|
||||||
|
Change-Id: I62820313dce87de6623cdc87b6e1361200ed7822
|
||||||
|
Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
src/network/ssl/qsslsocket_openssl.cpp
|
||||||
|
---
|
||||||
|
src/network/ssl/qsslsocket_openssl.cpp | 83 +++++++++++-----------------------
|
||||||
|
src/network/ssl/qsslsocket_p.h | 6 +--
|
||||||
|
2 files changed, 28 insertions(+), 61 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
|
||||||
|
index 13fc534..7d0fe00 100644
|
||||||
|
--- a/src/network/ssl/qsslsocket_openssl.cpp
|
||||||
|
+++ b/src/network/ssl/qsslsocket_openssl.cpp
|
||||||
|
@@ -69,14 +69,19 @@
|
||||||
|
#include <QtCore/qvarlengtharray.h>
|
||||||
|
#include <QLibrary> // for loading the security lib for the CA store
|
||||||
|
|
||||||
|
+#include <string.h>
|
||||||
|
+
|
||||||
|
+#ifdef Q_OS_DARWIN
|
||||||
|
+# include <private/qcore_mac_p.h>
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#ifdef Q_OS_OSX
|
||||||
|
+# include <Security/Security.h>
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
-#if defined(Q_OS_MACX)
|
||||||
|
-#define kSecTrustSettingsDomainSystem 2 // so we do not need to include the header file
|
||||||
|
- PtrSecCertificateCopyData QSslSocketPrivate::ptrSecCertificateCopyData = 0;
|
||||||
|
- PtrSecTrustSettingsCopyCertificates QSslSocketPrivate::ptrSecTrustSettingsCopyCertificates = 0;
|
||||||
|
- PtrSecTrustCopyAnchorCertificates QSslSocketPrivate::ptrSecTrustCopyAnchorCertificates = 0;
|
||||||
|
-#elif defined(Q_OS_WIN)
|
||||||
|
+#if defined(Q_OS_WIN)
|
||||||
|
PtrCertOpenSystemStoreW QSslSocketPrivate::ptrCertOpenSystemStoreW = 0;
|
||||||
|
PtrCertFindCertificateInStore QSslSocketPrivate::ptrCertFindCertificateInStore = 0;
|
||||||
|
PtrCertCloseStore QSslSocketPrivate::ptrCertCloseStore = 0;
|
||||||
|
@@ -482,23 +487,7 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
|
||||||
|
|
||||||
|
#ifndef QT_NO_LIBRARY
|
||||||
|
//load symbols needed to receive certificates from system store
|
||||||
|
-#if defined(Q_OS_MACX)
|
||||||
|
- QLibrary securityLib("/System/Library/Frameworks/Security.framework/Versions/Current/Security");
|
||||||
|
- if (securityLib.load()) {
|
||||||
|
- ptrSecCertificateCopyData = (PtrSecCertificateCopyData) securityLib.resolve("SecCertificateCopyData");
|
||||||
|
- if (!ptrSecCertificateCopyData)
|
||||||
|
- qWarning("could not resolve symbols in security library"); // should never happen
|
||||||
|
-
|
||||||
|
- ptrSecTrustSettingsCopyCertificates = (PtrSecTrustSettingsCopyCertificates) securityLib.resolve("SecTrustSettingsCopyCertificates");
|
||||||
|
- if (!ptrSecTrustSettingsCopyCertificates) { // method was introduced in Leopard, use legacy method if it's not there
|
||||||
|
- ptrSecTrustCopyAnchorCertificates = (PtrSecTrustCopyAnchorCertificates) securityLib.resolve("SecTrustCopyAnchorCertificates");
|
||||||
|
- if (!ptrSecTrustCopyAnchorCertificates)
|
||||||
|
- qWarning("could not resolve symbols in security library"); // should never happen
|
||||||
|
- }
|
||||||
|
- } else {
|
||||||
|
- qWarning("could not load security library");
|
||||||
|
- }
|
||||||
|
-#elif defined(Q_OS_WIN)
|
||||||
|
+#if defined(Q_OS_WIN)
|
||||||
|
HINSTANCE hLib = LoadLibraryW(L"Crypt32");
|
||||||
|
if (hLib) {
|
||||||
|
#if defined(Q_OS_WINCE)
|
||||||
|
@@ -635,40 +624,22 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||||
|
timer.start();
|
||||||
|
#endif
|
||||||
|
QList<QSslCertificate> systemCerts;
|
||||||
|
-#if defined(Q_OS_MACX)
|
||||||
|
- CFArrayRef cfCerts;
|
||||||
|
- OSStatus status = 1;
|
||||||
|
-
|
||||||
|
- CFDataRef SecCertificateCopyData (
|
||||||
|
- SecCertificateRef certificate
|
||||||
|
- );
|
||||||
|
-
|
||||||
|
- if (ptrSecCertificateCopyData) {
|
||||||
|
- if (ptrSecTrustSettingsCopyCertificates)
|
||||||
|
- status = ptrSecTrustSettingsCopyCertificates(kSecTrustSettingsDomainSystem, &cfCerts);
|
||||||
|
- else if (ptrSecTrustCopyAnchorCertificates)
|
||||||
|
- status = ptrSecTrustCopyAnchorCertificates(&cfCerts);
|
||||||
|
- if (!status) {
|
||||||
|
- CFIndex size = CFArrayGetCount(cfCerts);
|
||||||
|
- for (CFIndex i = 0; i < size; ++i) {
|
||||||
|
- SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i);
|
||||||
|
- CFDataRef data;
|
||||||
|
-
|
||||||
|
- data = ptrSecCertificateCopyData(cfCert);
|
||||||
|
-
|
||||||
|
- if (data == NULL) {
|
||||||
|
- qWarning("error retrieving a CA certificate from the system store");
|
||||||
|
- } else {
|
||||||
|
- QByteArray rawCert = QByteArray::fromRawData((const char *)CFDataGetBytePtr(data), CFDataGetLength(data));
|
||||||
|
- systemCerts.append(QSslCertificate::fromData(rawCert, QSsl::Der));
|
||||||
|
- CFRelease(data);
|
||||||
|
- }
|
||||||
|
+ // note: also check implementation in openssl_mac.cpp
|
||||||
|
+#if defined(Q_OS_OSX)
|
||||||
|
+ // SecTrustSettingsCopyCertificates is not defined on iOS.
|
||||||
|
+ QCFType<CFArrayRef> cfCerts;
|
||||||
|
+
|
||||||
|
+ OSStatus status = SecTrustSettingsCopyCertificates(kSecTrustSettingsDomainSystem, &cfCerts);
|
||||||
|
+ if (status == noErr ) {
|
||||||
|
+ const CFIndex size = CFArrayGetCount(cfCerts);
|
||||||
|
+ for (CFIndex i = 0; i < size; ++i) {
|
||||||
|
+ SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i);
|
||||||
|
+ QCFType<CFDataRef> derData = SecCertificateCopyData(cfCert);
|
||||||
|
+ if (derData == NULL) {
|
||||||
|
+ qWarning("error retrieving a CA certificate from the system store");
|
||||||
|
+ } else {
|
||||||
|
+ systemCerts << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der);
|
||||||
|
}
|
||||||
|
- CFRelease(cfCerts);
|
||||||
|
- }
|
||||||
|
- else {
|
||||||
|
- // no detailed error handling here
|
||||||
|
- qWarning("could not retrieve system CA certificates");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined(Q_OS_WIN)
|
||||||
|
diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h
|
||||||
|
index 6e7a2c5..c1a6f05 100644
|
||||||
|
--- a/src/network/ssl/qsslsocket_p.h
|
||||||
|
+++ b/src/network/ssl/qsslsocket_p.h
|
||||||
|
@@ -145,11 +145,7 @@ public:
|
||||||
|
static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
|
||||||
|
Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname);
|
||||||
|
|
||||||
|
-#if defined(Q_OS_MACX)
|
||||||
|
- static PtrSecCertificateCopyData ptrSecCertificateCopyData;
|
||||||
|
- static PtrSecTrustSettingsCopyCertificates ptrSecTrustSettingsCopyCertificates;
|
||||||
|
- static PtrSecTrustCopyAnchorCertificates ptrSecTrustCopyAnchorCertificates;
|
||||||
|
-#elif defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
|
||||||
|
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
|
||||||
|
static PtrCertOpenSystemStoreW ptrCertOpenSystemStoreW;
|
||||||
|
static PtrCertFindCertificateInStore ptrCertFindCertificateInStore;
|
||||||
|
static PtrCertCloseStore ptrCertCloseStore;
|
||||||
|
--
|
||||||
|
1.9.1
|
||||||
|
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
From 6b9366e7748857f14d5b0f92ced70c08ab5235b7 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Molkentin <danimo@owncloud.com>
|
||||||
|
Date: Wed, 25 Nov 2015 12:37:27 +0100
|
||||||
|
Subject: [PATCH 2/2] QSslSocket: evaluate CAs in all keychain categories
|
||||||
|
|
||||||
|
This will make sure that certs in the domainUser (login),
|
||||||
|
and domainAdmin (per machine) keychain are being picked up
|
||||||
|
in systemCaCertificates() in addition to the (usually immutable)
|
||||||
|
DomainSystem keychain.
|
||||||
|
|
||||||
|
Also consider the trust settings on OS X: If a certificate
|
||||||
|
is either fully trusted or trusted for the purpose of SSL,
|
||||||
|
it will be accepted.
|
||||||
|
|
||||||
|
[ChangeLog][Platform Specific Changes] OS X now accepts trusted
|
||||||
|
certificates from the login and system keychains.
|
||||||
|
|
||||||
|
(Backport of fe3a84138e266c425f11353f7d8dc28a588af89e to Qt 5.4)
|
||||||
|
|
||||||
|
Task-number: QTBUG-32898
|
||||||
|
Change-Id: Ia23083d5af74388eeee31ba07239735cbbe64368
|
||||||
|
Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
|
||||||
|
---
|
||||||
|
src/network/ssl/qsslsocket.cpp | 4 +
|
||||||
|
src/network/ssl/qsslsocket_mac_shared.cpp | 148 ++++++++++++++++++++++++++++++
|
||||||
|
src/network/ssl/qsslsocket_openssl.cpp | 30 +-----
|
||||||
|
src/network/ssl/ssl.pri | 4 +-
|
||||||
|
4 files changed, 158 insertions(+), 28 deletions(-)
|
||||||
|
create mode 100644 src/network/ssl/qsslsocket_mac_shared.cpp
|
||||||
|
|
||||||
|
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
|
||||||
|
index 8887f47..6347c20 100644
|
||||||
|
--- a/src/network/ssl/qsslsocket.cpp
|
||||||
|
+++ b/src/network/ssl/qsslsocket.cpp
|
||||||
|
@@ -1446,6 +1446,10 @@ QList<QSslCertificate> QSslSocket::defaultCaCertificates()
|
||||||
|
returned by defaultCaCertificates(). You can replace that database
|
||||||
|
with your own with setDefaultCaCertificates().
|
||||||
|
|
||||||
|
+ \note: On OS X, only certificates that are either trusted for all
|
||||||
|
+ purposes or trusted for the purpose of SSL in the keychain will be
|
||||||
|
+ returned.
|
||||||
|
+
|
||||||
|
\sa caCertificates(), defaultCaCertificates(), setDefaultCaCertificates()
|
||||||
|
*/
|
||||||
|
QList<QSslCertificate> QSslSocket::systemCaCertificates()
|
||||||
|
diff --git a/src/network/ssl/qsslsocket_mac_shared.cpp b/src/network/ssl/qsslsocket_mac_shared.cpp
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..60fea4c
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/network/ssl/qsslsocket_mac_shared.cpp
|
||||||
|
@@ -0,0 +1,148 @@
|
||||||
|
+/****************************************************************************
|
||||||
|
+**
|
||||||
|
+** Copyright (C) 2015 The Qt Company Ltd.
|
||||||
|
+** Copyright (C) 2015 ownCloud Inc
|
||||||
|
+** Contact: http://www.qt.io/licensing/
|
||||||
|
+**
|
||||||
|
+** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||||
|
+**
|
||||||
|
+** $QT_BEGIN_LICENSE:LGPL21$
|
||||||
|
+** Commercial License Usage
|
||||||
|
+** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
+** accordance with the commercial license agreement provided with the
|
||||||
|
+** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
+** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
+** and conditions see http://www.qt.io/terms-conditions. For further
|
||||||
|
+** information use the contact form at http://www.qt.io/contact-us.
|
||||||
|
+**
|
||||||
|
+** GNU Lesser General Public License Usage
|
||||||
|
+** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
+** General Public License version 2.1 or version 3 as published by the Free
|
||||||
|
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||||
|
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||||
|
+** following information to ensure the GNU Lesser General Public License
|
||||||
|
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||||
|
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||||
|
+**
|
||||||
|
+** As a special exception, The Qt Company gives you certain additional
|
||||||
|
+** rights. These rights are described in The Qt Company LGPL Exception
|
||||||
|
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
|
+**
|
||||||
|
+** $QT_END_LICENSE$
|
||||||
|
+**
|
||||||
|
+****************************************************************************/
|
||||||
|
+
|
||||||
|
+//#define QSSLSOCKET_DEBUG
|
||||||
|
+//#define QT_DECRYPT_SSL_TRAFFIC
|
||||||
|
+
|
||||||
|
+#include "qsslsocket.h"
|
||||||
|
+
|
||||||
|
+#ifndef QT_NO_OPENSSL
|
||||||
|
+# include "qsslsocket_openssl_p.h"
|
||||||
|
+# include "qsslsocket_openssl_symbols_p.h"
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#include "qsslcertificate_p.h"
|
||||||
|
+
|
||||||
|
+#ifdef Q_OS_DARWIN
|
||||||
|
+# include <private/qcore_mac_p.h>
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#include <QtCore/qdebug.h>
|
||||||
|
+
|
||||||
|
+#ifdef Q_OS_OSX
|
||||||
|
+# include <Security/Security.h>
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+QT_BEGIN_NAMESPACE
|
||||||
|
+
|
||||||
|
+#ifdef Q_OS_OSX
|
||||||
|
+namespace {
|
||||||
|
+
|
||||||
|
+bool hasTrustedSslServerPolicy(SecPolicyRef policy, CFDictionaryRef props) {
|
||||||
|
+ QCFType<CFDictionaryRef> policyProps = SecPolicyCopyProperties(policy);
|
||||||
|
+ // only accept certificates with policies for SSL server validation for now
|
||||||
|
+ if (CFEqual(CFDictionaryGetValue(policyProps, kSecPolicyOid), kSecPolicyAppleSSL)) {
|
||||||
|
+ CFBooleanRef policyClient;
|
||||||
|
+ if (CFDictionaryGetValueIfPresent(policyProps, kSecPolicyClient, reinterpret_cast<const void**>(&policyClient)) &&
|
||||||
|
+ CFEqual(policyClient, kCFBooleanTrue)) {
|
||||||
|
+ return false; // no client certs
|
||||||
|
+ }
|
||||||
|
+ if (!CFDictionaryContainsKey(props, kSecTrustSettingsResult)) {
|
||||||
|
+ // as per the docs, no trust settings result implies full trust
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+ CFNumberRef number = static_cast<CFNumberRef>(CFDictionaryGetValue(props, kSecTrustSettingsResult));
|
||||||
|
+ SecTrustSettingsResult settingsResult;
|
||||||
|
+ CFNumberGetValue(number, kCFNumberSInt32Type, &settingsResult);
|
||||||
|
+ switch (settingsResult) {
|
||||||
|
+ case kSecTrustSettingsResultTrustRoot:
|
||||||
|
+ case kSecTrustSettingsResultTrustAsRoot:
|
||||||
|
+ return true;
|
||||||
|
+ default:
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return false;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+bool isCaCertificateTrusted(SecCertificateRef cfCert, int domain)
|
||||||
|
+{
|
||||||
|
+ QCFType<CFArrayRef> cfTrustSettings;
|
||||||
|
+ OSStatus status = SecTrustSettingsCopyTrustSettings(cfCert, domain, &cfTrustSettings);
|
||||||
|
+ if (status == noErr) {
|
||||||
|
+ CFIndex size = CFArrayGetCount(cfTrustSettings);
|
||||||
|
+ // if empty, trust for everything (as per the Security Framework documentation)
|
||||||
|
+ if (size == 0) {
|
||||||
|
+ return true;
|
||||||
|
+ } else {
|
||||||
|
+ for (CFIndex i = 0; i < size; ++i) {
|
||||||
|
+ CFDictionaryRef props = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(cfTrustSettings, i));
|
||||||
|
+ if (CFDictionaryContainsKey(props, kSecTrustSettingsPolicy)) {
|
||||||
|
+ if (hasTrustedSslServerPolicy((SecPolicyRef)CFDictionaryGetValue(props, kSecTrustSettingsPolicy), props))
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ qWarning("Error receiving trust for a CA certificate");
|
||||||
|
+ }
|
||||||
|
+ return false;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+} // anon namespace
|
||||||
|
+#endif // Q_OS_OSX
|
||||||
|
+
|
||||||
|
+QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||||
|
+{
|
||||||
|
+ ensureInitialized();
|
||||||
|
+
|
||||||
|
+ QList<QSslCertificate> systemCerts;
|
||||||
|
+ // SecTrustSettingsCopyCertificates is not defined on iOS.
|
||||||
|
+#ifdef Q_OS_OSX
|
||||||
|
+ QCFType<CFArrayRef> cfCerts;
|
||||||
|
+ // iterate through all enum members, order:
|
||||||
|
+ // kSecTrustSettingsDomainUser, kSecTrustSettingsDomainAdmin, kSecTrustSettingsDomainSystem
|
||||||
|
+ for (int dom = kSecTrustSettingsDomainUser; dom <= kSecTrustSettingsDomainSystem; dom++) {
|
||||||
|
+ OSStatus status = SecTrustSettingsCopyCertificates(dom, &cfCerts);
|
||||||
|
+ if (status == noErr) {
|
||||||
|
+ const CFIndex size = CFArrayGetCount(cfCerts);
|
||||||
|
+ for (CFIndex i = 0; i < size; ++i) {
|
||||||
|
+ SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i);
|
||||||
|
+ QCFType<CFDataRef> derData = SecCertificateCopyData(cfCert);
|
||||||
|
+ if (::isCaCertificateTrusted(cfCert, dom)) {
|
||||||
|
+ if (derData == NULL) {
|
||||||
|
+ qWarning("Error retrieving a CA certificate from the system store");
|
||||||
|
+ } else {
|
||||||
|
+ systemCerts << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+#endif
|
||||||
|
+ return systemCerts;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+QT_END_NAMESPACE
|
||||||
|
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
|
||||||
|
index 7d0fe00..7415e32 100644
|
||||||
|
--- a/src/network/ssl/qsslsocket_openssl.cpp
|
||||||
|
+++ b/src/network/ssl/qsslsocket_openssl.cpp
|
||||||
|
@@ -71,14 +71,6 @@
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
-#ifdef Q_OS_DARWIN
|
||||||
|
-# include <private/qcore_mac_p.h>
|
||||||
|
-#endif
|
||||||
|
-
|
||||||
|
-#ifdef Q_OS_OSX
|
||||||
|
-# include <Security/Security.h>
|
||||||
|
-#endif
|
||||||
|
-
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
@@ -616,6 +608,7 @@ void QSslSocketPrivate::resetDefaultCiphers()
|
||||||
|
setDefaultCiphers(defaultCiphers);
|
||||||
|
}
|
||||||
|
|
||||||
|
+#ifndef Q_OS_DARWIN // Apple implementation in qsslsocket_mac_shared.cpp
|
||||||
|
QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||||
|
{
|
||||||
|
ensureInitialized();
|
||||||
|
@@ -624,25 +617,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||||
|
timer.start();
|
||||||
|
#endif
|
||||||
|
QList<QSslCertificate> systemCerts;
|
||||||
|
- // note: also check implementation in openssl_mac.cpp
|
||||||
|
-#if defined(Q_OS_OSX)
|
||||||
|
- // SecTrustSettingsCopyCertificates is not defined on iOS.
|
||||||
|
- QCFType<CFArrayRef> cfCerts;
|
||||||
|
-
|
||||||
|
- OSStatus status = SecTrustSettingsCopyCertificates(kSecTrustSettingsDomainSystem, &cfCerts);
|
||||||
|
- if (status == noErr ) {
|
||||||
|
- const CFIndex size = CFArrayGetCount(cfCerts);
|
||||||
|
- for (CFIndex i = 0; i < size; ++i) {
|
||||||
|
- SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i);
|
||||||
|
- QCFType<CFDataRef> derData = SecCertificateCopyData(cfCert);
|
||||||
|
- if (derData == NULL) {
|
||||||
|
- qWarning("error retrieving a CA certificate from the system store");
|
||||||
|
- } else {
|
||||||
|
- systemCerts << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der);
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
-#elif defined(Q_OS_WIN)
|
||||||
|
+#if defined(Q_OS_WIN)
|
||||||
|
if (ptrCertOpenSystemStoreW && ptrCertFindCertificateInStore && ptrCertCloseStore) {
|
||||||
|
HCERTSTORE hSystemStore;
|
||||||
|
#if defined(Q_OS_WINCE)
|
||||||
|
@@ -719,6 +694,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||||
|
|
||||||
|
return systemCerts;
|
||||||
|
}
|
||||||
|
+#endif // Q_OS_DARWIN
|
||||||
|
|
||||||
|
void QSslSocketBackendPrivate::startClientEncryption()
|
||||||
|
{
|
||||||
|
diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri
|
||||||
|
index 384e149..9546f18 100644
|
||||||
|
--- a/src/network/ssl/ssl.pri
|
||||||
|
+++ b/src/network/ssl/ssl.pri
|
||||||
|
@@ -45,7 +45,9 @@ contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
|
||||||
|
ssl/qsslsocket_openssl.cpp \
|
||||||
|
ssl/qsslsocket_openssl_symbols.cpp
|
||||||
|
|
||||||
|
-android:!android-no-sdk: SOURCES += ssl/qsslsocket_openssl_android.cpp
|
||||||
|
+ darwin:SOURCES += ssl/qsslsocket_mac_shared.cpp
|
||||||
|
+
|
||||||
|
+ android:!android-no-sdk: SOURCES += ssl/qsslsocket_openssl_android.cpp
|
||||||
|
|
||||||
|
# Add optional SSL libs
|
||||||
|
# Static linking of OpenSSL with msvc:
|
||||||
|
--
|
||||||
|
1.9.1
|
||||||
|
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
From ae9d3f4c6c1a732788cd1f24c6a928cee16c3991 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Molkentin <daniel@molkentin.de>
|
||||||
|
Date: Tue, 27 Jan 2015 16:58:32 +0100
|
||||||
|
Subject: [PATCH] Win32: Re-init system proxy if internet settings change
|
||||||
|
|
||||||
|
Because Proxy Auto Configuration performs DNS lookups,
|
||||||
|
the proxy settings are being cached. For long-running
|
||||||
|
programs this means that once users switch e.g. from or
|
||||||
|
to company networks with a proxy, they instantly will
|
||||||
|
lose connectivity because we cache the old setting.
|
||||||
|
|
||||||
|
To remedy this, we monitor the Registry (locations
|
||||||
|
courtesy of Chromium's platform support) for changes
|
||||||
|
in its settings, and requery for the current proxy in
|
||||||
|
that case.
|
||||||
|
|
||||||
|
Task-number: QTBUG-3470
|
||||||
|
Task-number: QTBUG-29990
|
||||||
|
Change-Id: Id25a51387bcd232c5f879cea0371038986d0e2de
|
||||||
|
Reviewed-by: Oliver Wolff <oliver.wolff@theqtcompany.com>
|
||||||
|
---
|
||||||
|
src/network/kernel/qnetworkproxy_win.cpp | 86 +++++++++++++++++++++++++++++++-
|
||||||
|
1 file changed, 84 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/network/kernel/qnetworkproxy_win.cpp b/src/network/kernel/qnetworkproxy_win.cpp
|
||||||
|
index da2c020..f7741ce 100644
|
||||||
|
--- a/src/network/kernel/qnetworkproxy_win.cpp
|
||||||
|
+++ b/src/network/kernel/qnetworkproxy_win.cpp
|
||||||
|
@@ -345,12 +345,66 @@ static QList<QNetworkProxy> parseServerList(const QNetworkProxyQuery &query, con
|
||||||
|
return removeDuplicateProxies(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
|
||||||
|
+namespace {
|
||||||
|
+class QRegistryWatcher {
|
||||||
|
+public:
|
||||||
|
+ void addLocation(HKEY hive, const QString& path)
|
||||||
|
+ {
|
||||||
|
+ HKEY openedKey;
|
||||||
|
+ if (RegOpenKeyEx(hive, reinterpret_cast<const wchar_t*>(path.utf16()), 0, KEY_READ, &openedKey) != ERROR_SUCCESS)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ const DWORD filter = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES |
|
||||||
|
+ REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY;
|
||||||
|
+
|
||||||
|
+ // Watch the registry key for a change of value.
|
||||||
|
+ HANDLE handle = CreateEvent(NULL, true, false, NULL);
|
||||||
|
+ if (RegNotifyChangeKeyValue(openedKey, true, filter, handle, true) != ERROR_SUCCESS) {
|
||||||
|
+ CloseHandle(handle);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ m_watchEvents.append(handle);
|
||||||
|
+ m_registryHandles.append(openedKey);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ bool hasChanged() const {
|
||||||
|
+ return !isEmpty() &&
|
||||||
|
+ WaitForMultipleObjects(m_watchEvents.size(), m_watchEvents.data(), false, 0) < WAIT_OBJECT_0 + m_watchEvents.size();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ bool isEmpty() const {
|
||||||
|
+ return m_watchEvents.isEmpty();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ void clear() {
|
||||||
|
+ foreach (HANDLE event, m_watchEvents)
|
||||||
|
+ CloseHandle(event);
|
||||||
|
+ foreach (HKEY key, m_registryHandles)
|
||||||
|
+ RegCloseKey(key);
|
||||||
|
+
|
||||||
|
+ m_watchEvents.clear();
|
||||||
|
+ m_registryHandles.clear();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ~QRegistryWatcher() {
|
||||||
|
+ clear();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+private:
|
||||||
|
+ QVector<HANDLE> m_watchEvents;
|
||||||
|
+ QVector<HKEY> m_registryHandles;
|
||||||
|
+};
|
||||||
|
+} // namespace
|
||||||
|
+#endif // !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
|
||||||
|
+
|
||||||
|
class QWindowsSystemProxy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QWindowsSystemProxy();
|
||||||
|
~QWindowsSystemProxy();
|
||||||
|
void init();
|
||||||
|
+ void reset();
|
||||||
|
|
||||||
|
QMutex mutex;
|
||||||
|
|
||||||
|
@@ -361,7 +415,9 @@ public:
|
||||||
|
QStringList proxyServerList;
|
||||||
|
QStringList proxyBypass;
|
||||||
|
QList<QNetworkProxy> defaultResult;
|
||||||
|
-
|
||||||
|
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
|
||||||
|
+ QRegistryWatcher proxySettingsWatcher;
|
||||||
|
+#endif
|
||||||
|
bool initialized;
|
||||||
|
bool functional;
|
||||||
|
bool isAutoConfig;
|
||||||
|
@@ -381,16 +437,42 @@ QWindowsSystemProxy::~QWindowsSystemProxy()
|
||||||
|
ptrWinHttpCloseHandle(hHttpSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
+void QWindowsSystemProxy::reset()
|
||||||
|
+{
|
||||||
|
+ autoConfigUrl.clear();
|
||||||
|
+ proxyServerList.clear();
|
||||||
|
+ proxyBypass.clear();
|
||||||
|
+ defaultResult.clear();
|
||||||
|
+ defaultResult << QNetworkProxy::NoProxy;
|
||||||
|
+ functional = false;
|
||||||
|
+ isAutoConfig = false;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void QWindowsSystemProxy::init()
|
||||||
|
{
|
||||||
|
- if (initialized)
|
||||||
|
+ bool proxySettingsChanged = false;
|
||||||
|
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
|
||||||
|
+ proxySettingsChanged = proxySettingsWatcher.hasChanged();
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+ if (initialized && !proxySettingsChanged)
|
||||||
|
return;
|
||||||
|
initialized = true;
|
||||||
|
|
||||||
|
+ reset();
|
||||||
|
+
|
||||||
|
#ifdef Q_OS_WINCE
|
||||||
|
// Windows CE does not have any of the following API
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
+
|
||||||
|
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
|
||||||
|
+ proxySettingsWatcher.clear(); // needs reset to trigger a new detection
|
||||||
|
+ proxySettingsWatcher.addLocation(HKEY_CURRENT_USER, QStringLiteral("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"));
|
||||||
|
+ proxySettingsWatcher.addLocation(HKEY_LOCAL_MACHINE, QStringLiteral("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"));
|
||||||
|
+ proxySettingsWatcher.addLocation(HKEY_LOCAL_MACHINE, QStringLiteral("Software\\Policies\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"));
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
// load the winhttp.dll library
|
||||||
|
QSystemLibrary lib(L"winhttp");
|
||||||
|
if (!lib.load())
|
||||||
|
--
|
||||||
|
1.9.1
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
From c1a67e7dc3a6f8876efa32cdbabbfde1c5a37bc6 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Molkentin <daniel@molkentin.de>
|
||||||
|
Date: Tue, 31 Mar 2015 17:43:44 +0200
|
||||||
|
Subject: [PATCH] Windows: Do not crash if SSL context is gone after root cert
|
||||||
|
lookup
|
||||||
|
|
||||||
|
On Windows, we perform an extra certificate lookup for root CAs that
|
||||||
|
are not in Windows' (minimal) root store. This check can take up to
|
||||||
|
15 seconds. The SSL context can already be gone once we return. Hence
|
||||||
|
we now check for a non-null SSL context on Windows before proceeding.
|
||||||
|
|
||||||
|
Change-Id: I1951569d9b17da33fa604f7c9d8b33255acf200d
|
||||||
|
Reviewed-by: Richard J. Moore <rich@kde.org>
|
||||||
|
---
|
||||||
|
src/network/ssl/qsslsocket_openssl.cpp | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
|
||||||
|
index 0e1a3e5..b132aec 100644
|
||||||
|
--- a/src/network/ssl/qsslsocket_openssl.cpp
|
||||||
|
+++ b/src/network/ssl/qsslsocket_openssl.cpp
|
||||||
|
@@ -1281,7 +1281,7 @@ void QSslSocketBackendPrivate::_q_caRootLoaded(QSslCertificate cert, QSslCertifi
|
||||||
|
if (plainSocket)
|
||||||
|
plainSocket->resume();
|
||||||
|
paused = false;
|
||||||
|
- if (checkSslErrors())
|
||||||
|
+ if (checkSslErrors() && ssl)
|
||||||
|
continueHandshake();
|
||||||
|
}
|
||||||
|
|
||||||
|
--
|
||||||
|
1.9.1
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
From cf6881c03d9f08c6ace83defe461423bb87f30d8 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?utf8?q?Tor=20Arne=20Vestb=C3=B8?= <tor.arne.vestbo@theqtcompany.com>
|
||||||
|
Date: Fri, 15 Jan 2016 14:15:51 +0100
|
||||||
|
Subject: [PATCH] OS X: Ensure system tray icon is prepared even when menu bar
|
||||||
|
is hidden
|
||||||
|
|
||||||
|
On OS X 10.11 (El Capitan) the system menu bar can be automatically
|
||||||
|
hidden, in which case the menu bar height is reported to be 0 when
|
||||||
|
using the menuBarHeight API.
|
||||||
|
|
||||||
|
This resulted in failing to prepare an image for the system tray
|
||||||
|
icon item, making the tray item "invisible".
|
||||||
|
|
||||||
|
Instead we now use the [[NSStatusBar systemStatusBar] thickness]
|
||||||
|
API, which returns the correct height regardless of the menu bar
|
||||||
|
being hidden or not.
|
||||||
|
|
||||||
|
Task-number: QTBUG-48960
|
||||||
|
Change-Id: I208fb8df13754964a6f254cadfbff06dd56c6bab
|
||||||
|
---
|
||||||
|
src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||||
|
index a3ffb5b..8152c57 100644
|
||||||
|
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||||
|
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
|
||||||
|
@@ -198,7 +198,7 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
|
||||||
|
// current OS X versions is 22 points. Provide some future-proofing
|
||||||
|
// by deriving the icon height from the menu height.
|
||||||
|
const int padding = 4;
|
||||||
|
- const int menuHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
|
||||||
|
+ const int menuHeight = [[NSStatusBar systemStatusBar] thickness];
|
||||||
|
const int maxImageHeight = menuHeight - padding;
|
||||||
|
|
||||||
|
// Select pixmap based on the device pixel height. Ideally we would use
|
||||||
|
--
|
||||||
|
2.6.2.2.g1b5ffa3
|
||||||
|
|
||||||
55
admin/qt/patches/README.md
Normal file
55
admin/qt/patches/README.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
## Patches used
|
||||||
|
|
||||||
|
There are our patches on top of Qt 5.4.0, which we are currently
|
||||||
|
using for our binary packages on Windows and Mac OS X. Most of them
|
||||||
|
have been sent upstream and are part of newer Qt releases.
|
||||||
|
|
||||||
|
All changes are designed to up upstream, and all those that are
|
||||||
|
special hacks to Qt will bear a NOUPSTREAM in their name
|
||||||
|
|
||||||
|
The git-style numeration is ordered by order of creation, their
|
||||||
|
purpose is outlined in each patches' front matter.
|
||||||
|
|
||||||
|
### Part of Qt v5.4.1 and later
|
||||||
|
* 0001-Fix-crash-on-Mac-OS-if-PAC-URL-contains-non-URL-lega.patch
|
||||||
|
* 0002-Fix-possible-crash-when-passing-an-invalid-PAC-URL.patch
|
||||||
|
* 0003-Fix-crash-if-PAC-script-retrieval-returns-a-null-CFD.patch
|
||||||
|
|
||||||
|
### Part of Qt v5.4.2 and later
|
||||||
|
* 0004-Cocoa-Fix-systray-SVG-icons.patch
|
||||||
|
* 0005-OSX-Fix-disapearing-tray-icon.patch
|
||||||
|
* 0007-QNAM-Fix-upload-corruptions-when-server-closes-conne.patch
|
||||||
|
* 0018-Windows-Do-not-crash-if-SSL-context-is-gone-after-ro.patch
|
||||||
|
|
||||||
|
### Part of Qt v5.5.0 and later
|
||||||
|
* 0017-Win32-Re-init-system-proxy-if-internet-settings-chan.patch
|
||||||
|
|
||||||
|
### Part of Qt v5.5.1 and later
|
||||||
|
* 0007-X-Network-Fix-up-previous-corruption-patch.patch
|
||||||
|
* 0008-QNAM-Fix-reply-deadlocks-on-server-closing-connectio.patch
|
||||||
|
* 0014-Fix-SNI-for-TlsV1_0OrLater-TlsV1_1OrLater-and-TlsV1_.patch
|
||||||
|
* 0016-Fix-possible-crash-when-passing-an-invalid-PAC-URL.patch
|
||||||
|
* 0011-Make-sure-to-report-correct-NetworkAccessibility.patch
|
||||||
|
|
||||||
|
### Part of Qt v5.5.2 (UNRELEASED!)
|
||||||
|
* 0009-QNAM-Assign-proper-channel-before-sslErrors-emission.patch
|
||||||
|
* 0010-Don-t-let-closed-http-sockets-pass-as-valid-connecti.patch
|
||||||
|
* 0012-Make-sure-networkAccessibilityChanged-is-emitted.patch
|
||||||
|
|
||||||
|
### Part of Qt v5.6 and later
|
||||||
|
* 0009-QNAM-Assign-proper-channel-before-sslErrors-emission.patch
|
||||||
|
* 0010-Don-t-let-closed-http-sockets-pass-as-valid-connecti.patch
|
||||||
|
* 0011-Make-sure-to-report-correct-NetworkAccessibility.patch
|
||||||
|
* 0012-Make-sure-networkAccessibilityChanged-is-emitted.patch
|
||||||
|
* 0013-Make-UnknownAccessibility-not-block-requests.patch
|
||||||
|
* 0019-Ensure-system-tray-icon-is-prepared-even-when-menu-bar.patch
|
||||||
|
|
||||||
|
### Part of Qt 5.7 and later
|
||||||
|
* 0015-Remove-legacy-platform-code-in-QSslSocket-for-OS-X-1.patch
|
||||||
|
|
||||||
|
### Not submitted upstream to be part of any release:
|
||||||
|
* 0006-Fix-force-debug-info-with-macx-clang_NOUPSTREAM.patch
|
||||||
|
This is only needed if you intent to harvest debugging symbols
|
||||||
|
for breakpad.
|
||||||
|
|
||||||
|
|
||||||
@@ -32,7 +32,3 @@ SET(QT_MOC_EXECUTABLE ${MINGW_PREFIX}-moc)
|
|||||||
SET(QT_RCC_EXECUTABLE ${MINGW_PREFIX}-rcc)
|
SET(QT_RCC_EXECUTABLE ${MINGW_PREFIX}-rcc)
|
||||||
SET(QT_UIC_EXECUTABLE ${MINGW_PREFIX}-uic)
|
SET(QT_UIC_EXECUTABLE ${MINGW_PREFIX}-uic)
|
||||||
SET(QT_LRELEASE_EXECUTABLE ${MINGW_PREFIX}-lrelease)
|
SET(QT_LRELEASE_EXECUTABLE ${MINGW_PREFIX}-lrelease)
|
||||||
|
|
||||||
# neon config
|
|
||||||
SET(NEON_CONFIG_EXECUTABLE ${CMAKE_FIND_ROOT_PATH}/bin/neon-config)
|
|
||||||
# /usr/i686-w64-mingw32/sys-root/mingw/bin/neon-config
|
|
||||||
|
|||||||
30
admin/win/create_stable_toolchain.sh
Executable file
30
admin/win/create_stable_toolchain.sh
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# This script creates a new windows toolchain repository in OBS.
|
||||||
|
# It only works for versions that do not yet exist.
|
||||||
|
#
|
||||||
|
# Make sure to adopt the variable stableversion.
|
||||||
|
|
||||||
|
# Set the new stable version accordingly:
|
||||||
|
stableversion=2.1
|
||||||
|
targetproject="isv:ownCloud:toolchains:mingw:win32:${stableversion}"
|
||||||
|
|
||||||
|
# Create the new repo
|
||||||
|
|
||||||
|
# get the xml build description of the stable repo
|
||||||
|
xml=`osc meta prj isv:ownCloud:toolchains:mingw:win32:stable`
|
||||||
|
stable_xml="${xml/stable/$stableversion}"
|
||||||
|
|
||||||
|
echo $stable_xml
|
||||||
|
|
||||||
|
echo $stable_xml | osc meta prj -F - ${targetproject}
|
||||||
|
|
||||||
|
|
||||||
|
# now copy all packages
|
||||||
|
packs=`osc ls isv:ownCloud:toolchains:mingw:win32:stable`
|
||||||
|
|
||||||
|
for pack in $packs
|
||||||
|
do
|
||||||
|
osc copypac isv:ownCloud:toolchains:mingw:win32:stable $pack $targetproject
|
||||||
|
done
|
||||||
37
admin/win/docker/Dockerfile
Normal file
37
admin/win/docker/Dockerfile
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
FROM opensuse:42.1
|
||||||
|
|
||||||
|
MAINTAINER Daniel Molkentin <danimo@owncloud.com>
|
||||||
|
|
||||||
|
ENV TERM ansi
|
||||||
|
ENV HOME /root
|
||||||
|
|
||||||
|
ENV REFRESHED_AT 20160421
|
||||||
|
|
||||||
|
RUN zypper --non-interactive --gpg-auto-import-keys refresh
|
||||||
|
RUN zypper --non-interactive --gpg-auto-import-keys ar http://download.opensuse.org/repositories/windows:/mingw/openSUSE_42.1/windows:mingw.repo
|
||||||
|
RUN zypper --non-interactive --gpg-auto-import-keys ar http://download.opensuse.org/repositories/isv:ownCloud:toolchains:mingw:win32:2.2/openSUSE_Leap_42.1/isv:ownCloud:toolchains:mingw:win32:2.2.repo
|
||||||
|
RUN zypper --non-interactive --gpg-auto-import-keys install cmake make mingw32-cross-binutils mingw32-cross-cpp mingw32-cross-gcc \
|
||||||
|
mingw32-cross-gcc-c++ mingw32-cross-pkg-config mingw32-filesystem \
|
||||||
|
mingw32-headers mingw32-runtime site-config mingw32-libwebp \
|
||||||
|
mingw32-cross-libqt5-qmake mingw32-cross-libqt5-qttools mingw32-libqt5* \
|
||||||
|
mingw32-qt5keychain* mingw32-angleproject* \
|
||||||
|
mingw32-cross-nsis mingw32-libopenssl* \
|
||||||
|
mingw32-sqlite* kdewin-png2ico \
|
||||||
|
osslsigncode wget
|
||||||
|
|
||||||
|
# RPM depends on curl for installs from HTTP
|
||||||
|
RUN zypper --non-interactive --gpg-auto-import-keys install curl
|
||||||
|
|
||||||
|
# sudo needed for building as user
|
||||||
|
RUN zypper --non-interactive --gpg-auto-import-keys install sudo
|
||||||
|
|
||||||
|
# Use packaged UAC dependencies
|
||||||
|
RUN zypper --non-interactive --gpg-auto-import-keys install mingw32-cross-nsis-plugin-uac mingw32-cross-nsis-plugin-nsprocess
|
||||||
|
|
||||||
|
# Required for checksumming
|
||||||
|
RUN zypper --non-interactive --gpg-auto-import-keys install mingw32-zlib-devel
|
||||||
|
|
||||||
|
# Required for windres not to crash
|
||||||
|
RUN zypper --non-interactive --gpg-auto-import-keys install glibc-locale
|
||||||
|
|
||||||
|
CMD /bin/bash
|
||||||
@@ -7,13 +7,13 @@ fi
|
|||||||
|
|
||||||
useradd user -u ${2:-1000}
|
useradd user -u ${2:-1000}
|
||||||
su - user << EOF
|
su - user << EOF
|
||||||
cd /home/user/$1
|
cd /home/user/$1
|
||||||
rm -rf build-win32
|
rm -rf build-win32
|
||||||
mkdir build-win32
|
mkdir build-win32
|
||||||
cd build-win32
|
cd build-win32
|
||||||
../admin/win/download_runtimes.sh
|
../admin/win/download_runtimes.sh
|
||||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=../admin/win/Toolchain-mingw32-openSUSE.cmake -DWITH_CRASHREPORTER=ON
|
cmake .. -DCMAKE_TOOLCHAIN_FILE=../admin/win/Toolchain-mingw32-openSUSE.cmake -DWITH_CRASHREPORTER=ON
|
||||||
make -j4
|
make -j4
|
||||||
make package
|
make package
|
||||||
ctest .
|
ctest .
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "${APPLICATION_NAME}erako Abiarazle
|
|||||||
StrCpy $UNINSTALLER_FILE_Detail "Desinstalatzailea idazten"
|
StrCpy $UNINSTALLER_FILE_Detail "Desinstalatzailea idazten"
|
||||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Instalatzaileko Erregistroko Giltzak idazten"
|
StrCpy $UNINSTALLER_REGISTRY_Detail "Instalatzaileko Erregistroko Giltzak idazten"
|
||||||
StrCpy $UNINSTALLER_FINISHED_Detail "Bukatuta"
|
StrCpy $UNINSTALLER_FINISHED_Detail "Bukatuta"
|
||||||
StrCpy $UNINSTALL_MESSAGEBOX "Ez dirudi ${APPLICATION_NAME} '$INSTDIR'.$ direktorioan instalatuta dagoenik.\n$\nJarraitu hala ere (ez da aholkatzen)?"
|
StrCpy $UNINSTALL_MESSAGEBOX "Ez dirudi ${APPLICATION_NAME} '$INSTDIR'.$ direktorioan instalatuta dagoenik.$\n$\nJarraitu hala ere (ez da aholkatzen)?"
|
||||||
StrCpy $UNINSTALL_ABORT "Desinstalazioak erabiltzaileak bertan behera utzi du"
|
StrCpy $UNINSTALL_ABORT "Desinstalazioak erabiltzaileak bertan behera utzi du"
|
||||||
StrCpy $INIT_NO_QUICK_LAUNCH "Abiarazle Bizkorreko Lasterbidea (E/E)"
|
StrCpy $INIT_NO_QUICK_LAUNCH "Abiarazle Bizkorreko Lasterbidea (E/E)"
|
||||||
StrCpy $INIT_NO_DESKTOP "Mahaigaineko Lasterbidea (dagoena berridazten du)"
|
StrCpy $INIT_NO_DESKTOP "Mahaigaineko Lasterbidea (dagoena berridazten du)"
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# Auto-generated - do not modify
|
# Auto-generated - do not modify
|
||||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Toon releaseopmerkingen"
|
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Toon opmerkingen bij deze uitgave"
|
||||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Gevonden ${APPLICATION_EXECUTABLE} proces(sen) moet worden gestopt.$\nWilt u dat het installatieprogramma dat voor u doet?"
|
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Gevonden ${APPLICATION_EXECUTABLE} proces(sen) moet worden gestopt.$\nWilt u dat het installatieprogramma dat voor u doet?"
|
||||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Stoppen ${APPLICATION_EXECUTABLE} processen."
|
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Stoppen ${APPLICATION_EXECUTABLE} processen."
|
||||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Het te stoppen proces is niet gevonden!"
|
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Het te stoppen proces is niet gevonden!"
|
||||||
StrCpy $PageReinstall_NEW_Field_1 "Er is een oudere versie van ${APPLICATION_NAME} geïnstalleerd op uw systeem. geadviseerd wordt om de huidige versie te de-installeren voordat de nieuwe versie wordt geïnstalleerd. Selecteer de uit te voeren actie en klik op Verder om door te gaan."
|
StrCpy $PageReinstall_NEW_Field_1 "Er is een oudere versie van ${APPLICATION_NAME} geïnstalleerd op uw systeem. geadviseerd wordt om de huidige versie te de-installeren voordat de nieuwe versie wordt geïnstalleerd. Selecteer de uit te voeren actie en klik op Verder om door te gaan."
|
||||||
StrCpy $PageReinstall_NEW_Field_2 "De-installeren voor installeren"
|
StrCpy $PageReinstall_NEW_Field_2 "Verwijder oude versie"
|
||||||
StrCpy $PageReinstall_NEW_Field_3 "Niet de-installeren"
|
StrCpy $PageReinstall_NEW_Field_3 "Behoud oude versie"
|
||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Al geïnstalleerd"
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Al geïnstalleerd"
|
||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Kies hoe u ${APPLICATION_NAME} wilt installeren."
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Kies hoe u ${APPLICATION_NAME} wilt installeren."
|
||||||
StrCpy $PageReinstall_OLD_Field_1 "Er is al een recentere versie van ${APPLICATION_NAME} geïnstalleerd! Installeren van een oudere versie wordt niet aangeraden. Als u echt de oudere versie wilt installeren, adviseren we de huidige versie eerst te verwijderen. Kies de actie die u wilt uitvoeren en druk op Verder om door te gaan."
|
StrCpy $PageReinstall_OLD_Field_1 "Er is al een recentere versie van ${APPLICATION_NAME} geïnstalleerd! Installeren van een oudere versie wordt niet aangeraden. Als u echt de oudere versie wilt installeren, adviseren we de huidige versie eerst te verwijderen. Kies de actie die u wilt uitvoeren en druk op Verder om door te gaan."
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "میانبر اجرای سریع ب
|
|||||||
StrCpy $UNINSTALLER_FILE_Detail "نوشتن حذف کننده"
|
StrCpy $UNINSTALLER_FILE_Detail "نوشتن حذف کننده"
|
||||||
StrCpy $UNINSTALLER_REGISTRY_Detail "در حال نوشتن کلید های رجیستری نصاب"
|
StrCpy $UNINSTALLER_REGISTRY_Detail "در حال نوشتن کلید های رجیستری نصاب"
|
||||||
StrCpy $UNINSTALLER_FINISHED_Detail "اتمام"
|
StrCpy $UNINSTALLER_FINISHED_Detail "اتمام"
|
||||||
StrCpy $UNINSTALL_MESSAGEBOX "به نظر نمی رسد نرم افزار ${APPLICATION_NAME} در '$INSTDIR'.$\n$\nنصب شده باشد.\nآیا می خواهید ادامه دهید ( توصیه نشده است ) ؟"
|
StrCpy $UNINSTALL_MESSAGEBOX "به نظر نمی رسد نرم افزار ${APPLICATION_NAME} در '$INSTDIR'.$\n$\nنصب شده باشد.$\nآیا می خواهید ادامه دهید ( توصیه نشده است ) ؟"
|
||||||
StrCpy $UNINSTALL_ABORT "عمل حذف توسط کاربر متوقف شد"
|
StrCpy $UNINSTALL_ABORT "عمل حذف توسط کاربر متوقف شد"
|
||||||
StrCpy $INIT_NO_QUICK_LAUNCH "میانبر بازکردن سریع ( N/A )"
|
StrCpy $INIT_NO_QUICK_LAUNCH "میانبر بازکردن سریع ( N/A )"
|
||||||
StrCpy $INIT_NO_DESKTOP "میانبر دسکتاپ (رونویسی وجود دارد)"
|
StrCpy $INIT_NO_DESKTOP "میانبر دسکتاپ (رونویسی وجود دارد)"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Auto-generated - do not modify
|
# Auto-generated - do not modify
|
||||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Näytä julkaisutiedot"
|
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Näytä julkaisutiedot"
|
||||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Havaittiin sovelluksen ${APPLICATION_EXECUTABLE} prosessi (tai prosesseja) jotka pitäisi pysäyttää.\nHaluatko että asennusohjelma pysäyttää nämä puolestasi?"
|
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Havaittiin sovelluksen ${APPLICATION_EXECUTABLE} prosessi (tai prosesseja) jotka pitäisi pysäyttää.$\nHaluatko että asennusohjelma pysäyttää nämä puolestasi?"
|
||||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Pysäytetään sovelluksen ${APPLICATION_EXECUTABLE} prosessit."
|
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Pysäytetään sovelluksen ${APPLICATION_EXECUTABLE} prosessit."
|
||||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Tapettavaa prosessia ei löytynyt!"
|
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Tapettavaa prosessia ei löytynyt!"
|
||||||
StrCpy $PageReinstall_NEW_Field_1 "Vanhempi versio sovelluksesta ${APPLICATION_NAME} on jo asennettu. On suositeltavaa että poistat vanhan asennuksen ensin. Valitse mikä toiminto suoritetaan ja napsauta Seuraava jatkaaksesi."
|
StrCpy $PageReinstall_NEW_Field_1 "Vanhempi versio sovelluksesta ${APPLICATION_NAME} on jo asennettu. On suositeltavaa että poistat vanhan asennuksen ensin. Valitse mikä toiminto suoritetaan ja napsauta Seuraava jatkaaksesi."
|
||||||
@@ -30,7 +30,7 @@ StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Pikak
|
|||||||
StrCpy $UNINSTALLER_FILE_Detail "Kirjoitetaan poisto-ohjelmaa"
|
StrCpy $UNINSTALLER_FILE_Detail "Kirjoitetaan poisto-ohjelmaa"
|
||||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Kirjoitetaan asennusohjelman rekisteriavaimia"
|
StrCpy $UNINSTALLER_REGISTRY_Detail "Kirjoitetaan asennusohjelman rekisteriavaimia"
|
||||||
StrCpy $UNINSTALLER_FINISHED_Detail "Valmis"
|
StrCpy $UNINSTALLER_FINISHED_Detail "Valmis"
|
||||||
StrCpy $UNINSTALL_MESSAGEBOX "Vaikuttaa siltä että sovellus ${APPLICATION_NAME} on asennettu kansioon '$INSTDIR'.\n\nHaluatko jatkaa tästä huolimatta (ei suositeltavaa)?"
|
StrCpy $UNINSTALL_MESSAGEBOX "Vaikuttaa siltä että sovellus ${APPLICATION_NAME} on asennettu kansioon '$INSTDIR'.$\n$\nHaluatko jatkaa tästä huolimatta (ei suositeltavaa)?"
|
||||||
StrCpy $UNINSTALL_ABORT "Poistaminen keskeytettiin käyttäjän toimesta"
|
StrCpy $UNINSTALL_ABORT "Poistaminen keskeytettiin käyttäjän toimesta"
|
||||||
StrCpy $INIT_NO_QUICK_LAUNCH "Pikakäynnistyksen pikakuvake (-)"
|
StrCpy $INIT_NO_QUICK_LAUNCH "Pikakäynnistyksen pikakuvake (-)"
|
||||||
StrCpy $INIT_NO_DESKTOP "Työpöydän pikakuvake (korvaa nykyinen)"
|
StrCpy $INIT_NO_DESKTOP "Työpöydän pikakuvake (korvaa nykyinen)"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ StrCpy $PageReinstall_NEW_Field_3 "Nicht entfernen"
|
|||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Bereits installiert"
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Bereits installiert"
|
||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Wählen Sie die Methode, mit der sie ${APPLICATION_NAME} installieren wollen."
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Wählen Sie die Methode, mit der sie ${APPLICATION_NAME} installieren wollen."
|
||||||
StrCpy $PageReinstall_OLD_Field_1 "Eine neuere Version von ${APPLICATION_NAME} ist bereits installiert! Es wird nicht empfohlen, eine ältere Version zu installieren. Wollen Sie dies trotzdem tun, so sollten Sie die aktuelle Version zunächst entfernen. Wählen Sie eine Vorgehensweise und wählen dann $\"Weiter$\"."
|
StrCpy $PageReinstall_OLD_Field_1 "Eine neuere Version von ${APPLICATION_NAME} ist bereits installiert! Es wird nicht empfohlen, eine ältere Version zu installieren. Wollen Sie dies trotzdem tun, so sollten Sie die aktuelle Version zunächst entfernen. Wählen Sie eine Vorgehensweise und wählen dann $\"Weiter$\"."
|
||||||
|
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} ist bereits installiert. $\nWählen Sie eine Vorgehensweise und klicken Sie auf $\"Weiter$\"."
|
||||||
StrCpy $PageReinstall_SAME_Field_2 "Komponenten hinzufügen"
|
StrCpy $PageReinstall_SAME_Field_2 "Komponenten hinzufügen"
|
||||||
StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} entfernen"
|
StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} entfernen"
|
||||||
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} entfernen"
|
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} entfernen"
|
||||||
@@ -37,7 +38,6 @@ StrCpy $UAC_ERROR_ELEVATE "Rechte k
|
|||||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Dieses Installationsprogramm erfordert Administrator-Rechte, bitte erneut versuchen"
|
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Dieses Installationsprogramm erfordert Administrator-Rechte, bitte erneut versuchen"
|
||||||
StrCpy $INIT_INSTALLER_RUNNING "Das Installationsprogramm wird bereits ausgeführt."
|
StrCpy $INIT_INSTALLER_RUNNING "Das Installationsprogramm wird bereits ausgeführt."
|
||||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Das Deinstallationsprogramm erfordert Administrator-Rechte. Bitte erneut versuchen."
|
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Das Deinstallationsprogramm erfordert Administrator-Rechte. Bitte erneut versuchen."
|
||||||
|
StrCpy $UAC_ERROR_LOGON_SERVICE "Anmeldedienst läuft nicht, abbruch!"
|
||||||
StrCpy $INIT_UNINSTALLER_RUNNING "Das Deinstallationsprogramm wird bereits ausgeführt."
|
StrCpy $INIT_UNINSTALLER_RUNNING "Das Deinstallationsprogramm wird bereits ausgeführt."
|
||||||
StrCpy $SectionGroup_Shortcuts "Verknüpfungen"
|
StrCpy $SectionGroup_Shortcuts "Verknüpfungen"
|
||||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
|
||||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Logon service is not running, aborting!"
|
|
||||||
|
|||||||
@@ -1,43 +1,43 @@
|
|||||||
# Auto-generated - do not modify
|
# Auto-generated - do not modify
|
||||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Kiadási jegyzetek megtekintése"
|
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Kiadási jegyzetek megtekintése"
|
||||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "A következő folyamatot(okat) meg kell állítani ${APPLICATION_EXECUTABLE}.$\nSzeretné ha a telepítő program megállítani ezeket a folyamatokat?"
|
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "A következő folyamatot(okat) meg kell állítani ${APPLICATION_EXECUTABLE}.$\nSzeretné ha a telepítő program megállítani ezeket a folyamatokat?"
|
||||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Folyamat ${APPLICATION_EXECUTABLE} kilövése."
|
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "${APPLICATION_EXECUTABLE} folyamat kilövése."
|
||||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Kilövésre szánt folyamat nem található."
|
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "A kilövésre szánt folyamat nem található!"
|
||||||
StrCpy $PageReinstall_NEW_Field_1 "Az ${APPLICATION_NAME} alkalmazás egy régebbi verziója telepítva van a rendszeren. Ajánlott a régi alkalmazás eltávolítása mielőtt a legfrissebb verziót telepítané. Válassza ki milyen műveletet szeretne végrehajtani, és nyomja meg a $\"Következő$\" gombot a folytatáshoz."
|
StrCpy $PageReinstall_NEW_Field_1 "Az ${APPLICATION_NAME} alkalmazás egy régebbi verziója telepítve van a rendszeren. Ajánlott a régi alkalmazás eltávolítása mielőtt a legfrissebb verziót telepítené. Válassza ki milyen műveletet szeretne végrehajtani, és nyomja meg a $\"Következő$\" gombot a folytatáshoz."
|
||||||
StrCpy $PageReinstall_NEW_Field_2 "Eltávolítás telepítés előtt"
|
StrCpy $PageReinstall_NEW_Field_2 "Eltávolítás telepítés előtt"
|
||||||
StrCpy $PageReinstall_NEW_Field_3 "Ne távolítsa el"
|
StrCpy $PageReinstall_NEW_Field_3 "Ne távolítsa el"
|
||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Már telepítve"
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Már telepítve"
|
||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Válaszd ki, hogy szeretnéd telepíteni a következő alkalmazást ${APPLICATION_NAME}."
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Válassza ki, hogy szeretné telepíteni a következő alkalmazást: ${APPLICATION_NAME}."
|
||||||
StrCpy $PageReinstall_OLD_Field_1 "Az ${APPLICATION_NAME} alklamazás egy újabb verziója már megtalálható a rendszeren. Nem ajánlott egy régebbi verzió telepítése. Ha valóban szeretné a régebbi verziót telepíteni, akkor ajánlott a jelenleg telepített verzió eltávolítása. Válassza ki milyen műveletet szeretne végrehajtani, és nyomja meg a $\"Következő$\" gombot a folytatáshoz."
|
StrCpy $PageReinstall_OLD_Field_1 "Az ${APPLICATION_NAME} alkalmazás egy újabb verziója már megtalálható a rendszeren. Nem ajánlott egy régebbi verzió telepítése. Ha valóban szeretné a régebbi verziót telepíteni, akkor ajánlott a jelenleg telepített verzió eltávolítása. Válassza ki milyen műveletet szeretne végrehajtani, és nyomja meg a $\"Következő$\" gombot a folytatáshoz."
|
||||||
StrCpy $PageReinstall_SAME_Field_1 "Az ${APPLICATION_NAME} alkalmazás ${VERSION} verziója már telepítve van.$↩$\nKérjük válaszd ki milyen műveletet szeretnél végrehajtani, és nyomd meg a „Következő” gombot."
|
StrCpy $PageReinstall_SAME_Field_1 "Az ${APPLICATION_NAME} alkalmazás ${VERSION} verziója már telepítve van.$↩$\nKérjük válaszd ki milyen műveletet szeretnél végrehajtani, és nyomd meg a „Következő” gombot."
|
||||||
StrCpy $PageReinstall_SAME_Field_2 "Komponens hozzáadása/újratelepítése"
|
StrCpy $PageReinstall_SAME_Field_2 "Komponens hozzáadása/újratelepítése"
|
||||||
StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} eltávolítása"
|
StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} eltávolítása"
|
||||||
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} eltávolítása"
|
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} eltávolítása"
|
||||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Kérem válassza ki milyen karbantartási műveletet szeretne elvégezni?"
|
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Válassza ki milyen karbantartási műveletet szeretne elvégezni."
|
||||||
StrCpy $SEC_APPLICATION_DETAILS "Az ${APPLICATION_NAME} alkalmazás lényeges komponenseinek telepítése."
|
StrCpy $SEC_APPLICATION_DETAILS "Az ${APPLICATION_NAME} alkalmazás lényeges komponenseinek telepítése."
|
||||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Windows Explorer Integráció"
|
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Windows Explorer integráció"
|
||||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Windows Explorer Integráció Telepítése"
|
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Windows Explorer integráció telepítése"
|
||||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Start Menü Parancsikonok"
|
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Start Menü parancsikonok"
|
||||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "A ${APPLICATION_NAME} parancsikon hozzáadása a Start Menühöz"
|
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "A ${APPLICATION_NAME} parancsikon hozzáadása a Start Menühöz"
|
||||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Asztali Parancsikon"
|
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Asztali parancsikon"
|
||||||
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "Asztali Parancsikon Létrehozása"
|
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "Asztali parancsikon létrehozása"
|
||||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Gyorsindítás Eszköztár Parancsikon"
|
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Gyorsindító eszköztár parancsikon"
|
||||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Gyorsindítás Eszköztár Parancsikon Létrehozása"
|
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Gyorsindító eszköztár parancsikon létrehozása"
|
||||||
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} lényeges komponensek."
|
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} lényeges komponensek."
|
||||||
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "${APPLICATION_NAME} parancsikon"
|
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "${APPLICATION_NAME} parancsikon"
|
||||||
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Asztali parancsikon a ${APPLICATION_NAME} alkalmazásnak."
|
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Asztali parancsikon a ${APPLICATION_NAME} alkalmazásnak."
|
||||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Gyorsindítás eszköztár parancsikon a ${APPLICATION_NAME} alkalmazásnak."
|
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Gyorsindítás eszköztár parancsikon a ${APPLICATION_NAME} alkalmazásnak."
|
||||||
StrCpy $UNINSTALLER_FILE_Detail "Program Eltávolító Írása"
|
StrCpy $UNINSTALLER_FILE_Detail "Elltávolító írása"
|
||||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Telepítési registry kulcsok írása"
|
StrCpy $UNINSTALLER_REGISTRY_Detail "Telepítési registry kulcsok írása"
|
||||||
StrCpy $UNINSTALLER_FINISHED_Detail "Befejezve"
|
StrCpy $UNINSTALLER_FINISHED_Detail "Befejezve!"
|
||||||
StrCpy $UNINSTALL_MESSAGEBOX "Nem sikerült az ${APPLICATION_NAME} alkalmazás telepítése a '$INSTDIR' könyvtárba.$\n$\nSzeretné mindenképpen folytatni (nem ajánlott)?"
|
StrCpy $UNINSTALL_MESSAGEBOX "Nem sikerült az ${APPLICATION_NAME} alkalmazás telepítése a '$INSTDIR' könyvtárba.$\n$\nSzeretné mindenképpen folytatni (nem ajánlott)?"
|
||||||
StrCpy $UNINSTALL_ABORT "Az eltávolítást egy felhasználó megszakította"
|
StrCpy $UNINSTALL_ABORT "Az eltávolítást a felhasználó megszakította"
|
||||||
StrCpy $INIT_NO_QUICK_LAUNCH "Gyorsindító Hivatkozás (N/A)"
|
StrCpy $INIT_NO_QUICK_LAUNCH "Gyorsindító hivatkozás (N/A)"
|
||||||
StrCpy $INIT_NO_DESKTOP "Asztali Hivatkozás (felülírja a meglévőt)"
|
StrCpy $INIT_NO_DESKTOP "Asztali hivatkozás (felülírja a meglévőt)"
|
||||||
StrCpy $UAC_ERROR_ELEVATE "Nem sikerült felemelni, hiba:"
|
StrCpy $UAC_ERROR_ELEVATE "Nem sikerült felemelni, hiba:"
|
||||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "A telepítő futtatásához adminisztrátori hozzáférés szükséges, próbáld újra."
|
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "A telepítő futtatásához adminisztrátori hozzáférés szükséges, próbálja újra."
|
||||||
StrCpy $INIT_INSTALLER_RUNNING "A telepítő már fut."
|
StrCpy $INIT_INSTALLER_RUNNING "A telepítő már fut."
|
||||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Az eltávolító futtatásához adminisztrátori hozzáférés szükséges, próbáld újra."
|
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Az eltávolító futtatásához adminisztrátori hozzáférés szükséges, próbálja újra."
|
||||||
StrCpy $UAC_ERROR_LOGON_SERVICE "A bejelentkező szolgáltatás nem fut, megszakítás!"
|
StrCpy $UAC_ERROR_LOGON_SERVICE "A bejelentkező szolgáltatás nem fut, megszakítás!"
|
||||||
StrCpy $INIT_UNINSTALLER_RUNNING "Az eltávolító már fut."
|
StrCpy $INIT_UNINSTALLER_RUNNING "Az eltávolító már fut."
|
||||||
StrCpy $SectionGroup_Shortcuts "Parancsikonok"
|
StrCpy $SectionGroup_Shortcuts "Parancsikonok"
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Scorciatoia per ${APPLICATION_NAME}
|
|||||||
StrCpy $UNINSTALLER_FILE_Detail "Creazione del programma di disinstallazione"
|
StrCpy $UNINSTALLER_FILE_Detail "Creazione del programma di disinstallazione"
|
||||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Scrittura delle chiavi di registro del programma di installazione"
|
StrCpy $UNINSTALLER_REGISTRY_Detail "Scrittura delle chiavi di registro del programma di installazione"
|
||||||
StrCpy $UNINSTALLER_FINISHED_Detail "Completato"
|
StrCpy $UNINSTALLER_FINISHED_Detail "Completato"
|
||||||
StrCpy $UNINSTALL_MESSAGEBOX "Non sembra che ${APPLICATION_NAME} sia installato nella cartella '$INSTDIR'.$\nVuoi continuare comunque (non consigliato)?"
|
StrCpy $UNINSTALL_MESSAGEBOX "Non sembra che ${APPLICATION_NAME} sia installato nella cartella '$INSTDIR'.$$\nVuoi continuare comunque (non consigliato)?"
|
||||||
StrCpy $UNINSTALL_ABORT "Disinstallazione interrotta dall'utente"
|
StrCpy $UNINSTALL_ABORT "Disinstallazione interrotta dall'utente"
|
||||||
StrCpy $INIT_NO_QUICK_LAUNCH "Scorciatoia dell'avvio veloce (N/D)"
|
StrCpy $INIT_NO_QUICK_LAUNCH "Scorciatoia dell'avvio veloce (N/D)"
|
||||||
StrCpy $INIT_NO_DESKTOP "Scorciatoia del desktop (sovrascrivi se esistente)"
|
StrCpy $INIT_NO_DESKTOP "Scorciatoia del desktop (sovrascrivi se esistente)"
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "
|
|||||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "${APPLICATION_EXECUTABLE} のプロセスを終了する必要があります。$\nインストーラーがそのプロセスを停止してもよろしいですか?"
|
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "${APPLICATION_EXECUTABLE} のプロセスを終了する必要があります。$\nインストーラーがそのプロセスを停止してもよろしいですか?"
|
||||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "${APPLICATION_EXECUTABLE} プロセスを停止しています。"
|
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "${APPLICATION_EXECUTABLE} プロセスを停止しています。"
|
||||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "終了するプロセスがありません"
|
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "終了するプロセスがありません"
|
||||||
StrCpy $PageReinstall_NEW_Field_1 "システムに ${APPLICATION_NAME} の旧バージョンがインストールされています。\n旧バージョンをアンインストールし、最新バージョンをインストールするのをお勧めします。\nオペレーションを選択し、次へをクリックする。"
|
StrCpy $PageReinstall_NEW_Field_1 "システムに ${APPLICATION_NAME} の旧バージョンがインストールされています。$\n旧バージョンをアンインストールし、最新バージョンをインストールするのをお勧めします。$\nオペレーションを選択し、次へをクリックする。"
|
||||||
StrCpy $PageReinstall_NEW_Field_2 "インストール前にアンインストールする"
|
StrCpy $PageReinstall_NEW_Field_2 "インストール前にアンインストールする"
|
||||||
StrCpy $PageReinstall_NEW_Field_3 "アンインストールしない"
|
StrCpy $PageReinstall_NEW_Field_3 "アンインストールしない"
|
||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "インストール済"
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "インストール済"
|
||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "${APPLICATION_NAME} のインストール方法を選択する"
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "${APPLICATION_NAME} のインストール方法を選択する"
|
||||||
StrCpy $PageReinstall_OLD_Field_1 "${APPLICATION_NAME} の最新バージョンがすでにインストールされています。\n旧バージョンのインストールはお勧めしません。旧バージョンのインストールが本当に必要な場合は、まず最新バージョンをアンインストールしてから、旧バージョンをインストールしてください。\nオペレーションを選択し、次へをクリックする。"
|
StrCpy $PageReinstall_OLD_Field_1 "${APPLICATION_NAME} の最新バージョンがすでにインストールされています。$\n旧バージョンのインストールはお勧めしません。旧バージョンのインストールが本当に必要な場合は、まず最新バージョンをアンインストールしてから、旧バージョンをインストールしてください。$\nオペレーションを選択し、次へをクリックする。"
|
||||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} は、${VERSION} が既にインストールされています。$\n$\n実行したい操作を選択し、次へをクリックする。"
|
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} は、${VERSION} が既にインストールされています。$\n$\n実行したい操作を選択し、次へをクリックする。"
|
||||||
StrCpy $PageReinstall_SAME_Field_2 "追加/再インストールコンポーネント"
|
StrCpy $PageReinstall_SAME_Field_2 "追加/再インストールコンポーネント"
|
||||||
StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} をアンインストール"
|
StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} をアンインストール"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ StrCpy $PageReinstall_NEW_Field_3 "Nie usuwaj "
|
|||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Ju¿ zainstalowane"
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Ju¿ zainstalowane"
|
||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Wybierz jak chcesz zainstalowaæ ${APPLICATION_NAME}."
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Wybierz jak chcesz zainstalowaæ ${APPLICATION_NAME}."
|
||||||
StrCpy $PageReinstall_OLD_Field_1 "Zainstalowana jest nowsza wersja ${APPLICATION_NAME}! Niezalecane jest instalowanie starszej wersji. Jeœli naprawdê chcesz zainstalowaæ starsz¹ wersjê lepiej najpierw odinstalowaæ obecn¹ aplikacjê. Wybierz operacjê któr¹ chcesz wykonaæ i naciœnij przycisk Dalej."
|
StrCpy $PageReinstall_OLD_Field_1 "Zainstalowana jest nowsza wersja ${APPLICATION_NAME}! Niezalecane jest instalowanie starszej wersji. Jeœli naprawdê chcesz zainstalowaæ starsz¹ wersjê lepiej najpierw odinstalowaæ obecn¹ aplikacjê. Wybierz operacjê któr¹ chcesz wykonaæ i naciœnij przycisk Dalej."
|
||||||
|
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} jest ju¿ zainstalowany.$\nWybierz operacjê któr¹ chcesz wykonaæ i naciœnij przycisk Dalej."
|
||||||
StrCpy $PageReinstall_SAME_Field_2 "Doda/Przeinstaluj komponenty"
|
StrCpy $PageReinstall_SAME_Field_2 "Doda/Przeinstaluj komponenty"
|
||||||
StrCpy $PageReinstall_SAME_Field_3 "Odinstaluj ${APPLICATION_NAME}"
|
StrCpy $PageReinstall_SAME_Field_3 "Odinstaluj ${APPLICATION_NAME}"
|
||||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Odinstaluj ${APPLICATION_NAME}"
|
StrCpy $UNINSTALLER_APPDATA_TITLE "Odinstaluj ${APPLICATION_NAME}"
|
||||||
@@ -37,7 +38,6 @@ StrCpy $UAC_ERROR_ELEVATE "Niemo
|
|||||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Ten instalator potrzebuje uprawnieñ administratora, spróbuj ponownie"
|
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Ten instalator potrzebuje uprawnieñ administratora, spróbuj ponownie"
|
||||||
StrCpy $INIT_INSTALLER_RUNNING "Instalator ju¿ jest uruchomiony."
|
StrCpy $INIT_INSTALLER_RUNNING "Instalator ju¿ jest uruchomiony."
|
||||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Ten dezinstalator potrzebuje uprawnieñ administratora, spróbuj ponownie"
|
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Ten dezinstalator potrzebuje uprawnieñ administratora, spróbuj ponownie"
|
||||||
|
StrCpy $UAC_ERROR_LOGON_SERVICE "Proces logowania nie jest uruchomiony, przerywam !"
|
||||||
StrCpy $INIT_UNINSTALLER_RUNNING "Dezinstalator ju¿ jest uruchomiony."
|
StrCpy $INIT_UNINSTALLER_RUNNING "Dezinstalator ju¿ jest uruchomiony."
|
||||||
StrCpy $SectionGroup_Shortcuts "Skróty"
|
StrCpy $SectionGroup_Shortcuts "Skróty"
|
||||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
|
||||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Logon service is not running, aborting!"
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
# Auto-generated - do not modify
|
# Auto-generated - do not modify
|
||||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Mostrar notas de lançamento"
|
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Mostrar notas de lançamento"
|
||||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Processos(s) ${APPLICATION_EXECUTABLE} em execução. Estes processos precisam de ser interrompidos.$\\nDeseja que o instalador os termine automaticamente?"
|
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Existem ${APPLICATION_EXECUTABLE} processo(s) em execução que precisa(m) de ser interrompido(s).$\nDeseja que o instalador o(s) termine automaticamente?"
|
||||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "A terminar os processos ${APPLICATION_EXECUTABLE}."
|
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "A terminar os processos ${APPLICATION_EXECUTABLE}."
|
||||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Não foi encontrado o processo a terminar!"
|
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Não foi encontrado o processo a terminar!"
|
||||||
StrCpy $PageReinstall_NEW_Field_1 "Uma versão antiga de ${APPLICATION_NAME} está instalada no sistema. É recomendado que você desinstale a versão atual antes de instalar. Selecione a operação que deseja executar e clique em $\"Avançar$\" para continuar."
|
StrCpy $PageReinstall_NEW_Field_1 "Uma versão antiga de ${APPLICATION_NAME} está instalada no sistema. É recomendado que você desinstale a versão atual antes de instalar a mais recente. Selecione a operação que deseja executar e clique em $\"Avançar$\" para continuar."
|
||||||
StrCpy $PageReinstall_NEW_Field_2 "Desinstalar antes de instalar"
|
StrCpy $PageReinstall_NEW_Field_2 "Desinstalar antes de instalar"
|
||||||
StrCpy $PageReinstall_NEW_Field_3 "Não desinstale"
|
StrCpy $PageReinstall_NEW_Field_3 "Não desinstale"
|
||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Já instalado"
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Já instalado"
|
||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Escolha como pretende instalar ${APPLICATION_NAME}."
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Escolha como pretende instalar ${APPLICATION_NAME}."
|
||||||
StrCpy $PageReinstall_OLD_Field_1 "Uma versão mais recente do ${APPLICATION_NAME} já está instalada! Não é recomendada a instalação de uma versão mais antiga. Se realmente deseja instalar esta versão, aconselha-se a desinstalação da versão atual primeiro. Selecione a operação que deseja executar e clique em Avançar para continuar."
|
StrCpy $PageReinstall_OLD_Field_1 "Uma versão mais recente do ${APPLICATION_NAME} já está instalada! Não é recomendada a instalação de uma versão mais antiga. Se realmente deseja instalar esta versão, aconselha-se a desinstalação da versão atual primeiro. Selecione a operação que deseja executar e clique em Avançar para continuar."
|
||||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} já está instalada.\nSelecione a operação que deseja realizar e clique em 'Seguinte' para continuar."
|
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} já está instalada.$\nSelecione a operação que deseja realizar e clique em 'Seguinte' para continuar."
|
||||||
StrCpy $PageReinstall_SAME_Field_2 "Adicionar/Reinstalar Componentes"
|
StrCpy $PageReinstall_SAME_Field_2 "Adicionar/Reinstalar Componentes"
|
||||||
StrCpy $PageReinstall_SAME_Field_3 "Desinstalar ${APPLICATION_NAME}"
|
StrCpy $PageReinstall_SAME_Field_3 "Desinstalar ${APPLICATION_NAME}"
|
||||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Desinstalar ${APPLICATION_NAME}"
|
StrCpy $UNINSTALLER_APPDATA_TITLE "Desinstalar ${APPLICATION_NAME}"
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Ярлык в меню быстро
|
|||||||
StrCpy $UNINSTALLER_FILE_Detail "Сохранение деинсталлятора"
|
StrCpy $UNINSTALLER_FILE_Detail "Сохранение деинсталлятора"
|
||||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Запись ключей реестра установщика"
|
StrCpy $UNINSTALLER_REGISTRY_Detail "Запись ключей реестра установщика"
|
||||||
StrCpy $UNINSTALLER_FINISHED_Detail "Завершено"
|
StrCpy $UNINSTALLER_FINISHED_Detail "Завершено"
|
||||||
StrCpy $UNINSTALL_MESSAGEBOX "Похоже, что приложение ${APPLICATION_NAME} не установлено в каталог '$INSTDIR'.\nВсе равно продолжить (не рекомендуется)?"
|
StrCpy $UNINSTALL_MESSAGEBOX "Похоже, что приложение ${APPLICATION_NAME} не установлено в каталог '$INSTDIR'.$\nВсе равно продолжить (не рекомендуется)?"
|
||||||
StrCpy $UNINSTALL_ABORT "Удаление отменено пользователем"
|
StrCpy $UNINSTALL_ABORT "Удаление отменено пользователем"
|
||||||
StrCpy $INIT_NO_QUICK_LAUNCH "Ярлык быстрого запуска (не доступен)"
|
StrCpy $INIT_NO_QUICK_LAUNCH "Ярлык быстрого запуска (не доступен)"
|
||||||
StrCpy $INIT_NO_DESKTOP "Ярлык на рабочем столе (перезапись существующего)"
|
StrCpy $INIT_NO_DESKTOP "Ярлык на рабочем столе (перезапись существующего)"
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# Auto-generated - do not modify
|
# Auto-generated - do not modify
|
||||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "查看版本日志"
|
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "查看版本日志"
|
||||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "有 ${APPLICATION_EXECUTABLE} 项进程需要关闭。$\n您想让安装程序关闭这些进程吗?"
|
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "有 ${APPLICATION_EXECUTABLE} 项进程需要关闭。$\n您想让安装程序关闭这些进程吗?"
|
||||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "杀死${APPLICATION_EXECUTABLE}进程。"
|
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "停止${APPLICATION_EXECUTABLE}进程。"
|
||||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "未找到要杀死的进程!"
|
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "未找到要停止的进程!"
|
||||||
StrCpy $PageReinstall_NEW_Field_1 "您的系统已经安装${APPLICATION_NAME}较老版本。建议安装前卸载当前版本。选择将要执行的操作,点击下一步继续。"
|
StrCpy $PageReinstall_NEW_Field_1 "您的系统已经安装${APPLICATION_NAME}较老版本。建议安装前卸载当前版本。选择将要执行的操作,点击下一步继续。"
|
||||||
StrCpy $PageReinstall_NEW_Field_2 "在安装前先卸载"
|
StrCpy $PageReinstall_NEW_Field_2 "在安装前先卸载"
|
||||||
StrCpy $PageReinstall_NEW_Field_3 "不要卸载"
|
StrCpy $PageReinstall_NEW_Field_3 "不要卸载"
|
||||||
@@ -38,6 +38,6 @@ StrCpy $UAC_ERROR_ELEVATE "无法获得权限,错误:"
|
|||||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "安装程序需要管理员权限,请重试"
|
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "安装程序需要管理员权限,请重试"
|
||||||
StrCpy $INIT_INSTALLER_RUNNING "安装程序已经运行。"
|
StrCpy $INIT_INSTALLER_RUNNING "安装程序已经运行。"
|
||||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "卸载程序需要管理员权限,请重试"
|
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "卸载程序需要管理员权限,请重试"
|
||||||
|
StrCpy $UAC_ERROR_LOGON_SERVICE "登录服务器未运行!"
|
||||||
StrCpy $INIT_UNINSTALLER_RUNNING "卸载程序已经运行。"
|
StrCpy $INIT_UNINSTALLER_RUNNING "卸载程序已经运行。"
|
||||||
StrCpy $SectionGroup_Shortcuts "快捷方式"
|
StrCpy $SectionGroup_Shortcuts "快捷方式"
|
||||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Logon service is not running, aborting!"
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ StrCpy $PageReinstall_NEW_Field_3 "Ne odstrani namestitve"
|
|||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Program je že nameščen"
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Program je že nameščen"
|
||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Izberite način namestitve programa ${APPLICATION_NAME}."
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Izberite način namestitve programa ${APPLICATION_NAME}."
|
||||||
StrCpy $PageReinstall_OLD_Field_1 "Novejša različica programa ${APPLICATION_NAME} je že nameščena! Ni priporočljivo namestiti starejše. V kolikor želite vseeno nadaljevati z namestitvijo, prej odstranite obstoječo različico. Izberite opravilo in pritisnite gumb za nadaljevanje."
|
StrCpy $PageReinstall_OLD_Field_1 "Novejša različica programa ${APPLICATION_NAME} je že nameščena! Ni priporočljivo namestiti starejše. V kolikor želite vseeno nadaljevati z namestitvijo, prej odstranite obstoječo različico. Izberite opravilo in pritisnite gumb za nadaljevanje."
|
||||||
|
StrCpy $PageReinstall_SAME_Field_1 "Program ${APPLICATION_NAME} ${VERSION} je že nameščen.$\n$\nIzberite opravilo, ki ga želite izvesti in kliknite za nadaljevanje."
|
||||||
StrCpy $PageReinstall_SAME_Field_2 "Dodaj/Ponovno namesti programe"
|
StrCpy $PageReinstall_SAME_Field_2 "Dodaj/Ponovno namesti programe"
|
||||||
StrCpy $PageReinstall_SAME_Field_3 "Odstrani ${APPLICATION_NAME}"
|
StrCpy $PageReinstall_SAME_Field_3 "Odstrani ${APPLICATION_NAME}"
|
||||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Odstrani ${APPLICATION_NAME}"
|
StrCpy $UNINSTALLER_APPDATA_TITLE "Odstrani ${APPLICATION_NAME}"
|
||||||
@@ -37,7 +38,6 @@ StrCpy $UAC_ERROR_ELEVATE "Ni mogo
|
|||||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Namestilnik zahteva skrbniška dovoljenja."
|
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Namestilnik zahteva skrbniška dovoljenja."
|
||||||
StrCpy $INIT_INSTALLER_RUNNING "Namestilnik je že zagnan."
|
StrCpy $INIT_INSTALLER_RUNNING "Namestilnik je že zagnan."
|
||||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Program za odstranjevanje namestitve zahteva skrbniška dovoljenja."
|
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Program za odstranjevanje namestitve zahteva skrbniška dovoljenja."
|
||||||
|
StrCpy $UAC_ERROR_LOGON_SERVICE "Storitev za prijavo ni zagnana. Opravilo je ustavljeno!"
|
||||||
StrCpy $INIT_UNINSTALLER_RUNNING "Program za odstranjevanje namestitve je že zagnan."
|
StrCpy $INIT_UNINSTALLER_RUNNING "Program za odstranjevanje namestitve je že zagnan."
|
||||||
StrCpy $SectionGroup_Shortcuts "Bližnjice"
|
StrCpy $SectionGroup_Shortcuts "Bližnjice"
|
||||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
|
||||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Logon service is not running, aborting!"
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# Auto-generated - do not modify
|
# Auto-generated - do not modify
|
||||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Mostrar notas de la versión"
|
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Mostrar notas de la versión"
|
||||||
|
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Se encontrarion ${APPLICATION_EXECUTABLE} proceso(s) que debe/n ser detenidos.$\"$\n$\"¿Quiere que el instalador lo haga por usted?"
|
||||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Parando el proceso ${APPLICATION_EXECUTABLE}."
|
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Parando el proceso ${APPLICATION_EXECUTABLE}."
|
||||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Proceso a detener no encontrado!"
|
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Proceso a detener no encontrado!"
|
||||||
StrCpy $PageReinstall_NEW_Field_1 "Una versión anterior de ${APPLICATION_NAME} esta instalada en el sistema. Es recomendado que quite esta versión antes de instalar. Elija la operación a realizar y seleccione Siguiente para continuar."
|
StrCpy $PageReinstall_NEW_Field_1 "Una versión anterior de ${APPLICATION_NAME} esta instalada en el sistema. Es recomendado que quite esta versión antes de instalar. Elija la operación a realizar y seleccione Siguiente para continuar."
|
||||||
@@ -8,36 +9,35 @@ StrCpy $PageReinstall_NEW_Field_3 "No des-instalar."
|
|||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Actualmente Instalado."
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Actualmente Instalado."
|
||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Elija como desea instalar ${APPLICATION_NAME}."
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Elija como desea instalar ${APPLICATION_NAME}."
|
||||||
StrCpy $PageReinstall_OLD_Field_1 "Una versión mas reciente de ${APPLICATION_NAME} esta actualmente instalada! No es recomendado que instale una versión antigua. Si realmente desea instalar esta versión obsoleta, es mejor que des-instale la versión actual primero. Seleccione la operación que desea realizar y presione en Siguiente para continuar. "
|
StrCpy $PageReinstall_OLD_Field_1 "Una versión mas reciente de ${APPLICATION_NAME} esta actualmente instalada! No es recomendado que instale una versión antigua. Si realmente desea instalar esta versión obsoleta, es mejor que des-instale la versión actual primero. Seleccione la operación que desea realizar y presione en Siguiente para continuar. "
|
||||||
|
StrCpy $PageReinstall_SAME_Field_1 "La ${APPLICATION_NAME} ${VERSION} ya está instalado.$\n$\nSeleccione la operación que desea realizar y haga click en Siguiente para continuar."
|
||||||
StrCpy $PageReinstall_SAME_Field_2 "Agregar/Re-Instalar componentes"
|
StrCpy $PageReinstall_SAME_Field_2 "Agregar/Re-Instalar componentes"
|
||||||
StrCpy $PageReinstall_SAME_Field_3 "Des-instalar ${APPLICATION_NAME}"
|
StrCpy $PageReinstall_SAME_Field_3 "Des-instalar ${APPLICATION_NAME}"
|
||||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Des-instalar ${APPLICATION_NAME}"
|
StrCpy $UNINSTALLER_APPDATA_TITLE "Des-instalar ${APPLICATION_NAME}"
|
||||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Elija la opción de mantenimiento a realizar."
|
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Elija la opción de mantenimiento a realizar."
|
||||||
StrCpy $SEC_APPLICATION_DETAILS "Instalar esenciales ${APPLICATION_NAME}."
|
StrCpy $SEC_APPLICATION_DETAILS "Instalar esenciales ${APPLICATION_NAME}."
|
||||||
|
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Integración para Windows Explorer"
|
||||||
|
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Instalando la integración para Windows Explorer"
|
||||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Acceso Directo en Menú de Programas"
|
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Acceso Directo en Menú de Programas"
|
||||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Agregando el Acceso Directo al Menú de Inicio para ${APPLICATION_NAME}."
|
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Agregando el Acceso Directo al Menú de Inicio para ${APPLICATION_NAME}."
|
||||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Acceso directo en Escritorio"
|
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Acceso directo en Escritorio"
|
||||||
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "Creando Accesos Directos en Escritorio"
|
StrCpy $OPTION_SECTION_SC_DESKTOP_DetailPrint "Creando Accesos Directos en Escritorio"
|
||||||
|
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Atajo de Acceso Rápido"
|
||||||
|
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Creando Atajo de Acceso Rápido"
|
||||||
|
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} esencial."
|
||||||
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "Acceso directo de ${APPLICATION_NAME}"
|
StrCpy $OPTION_SECTION_SC_START_MENU_Desc "Acceso directo de ${APPLICATION_NAME}"
|
||||||
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Acceso Directo al Escritorio para ${APPLICATION_NAME}."
|
StrCpy $OPTION_SECTION_SC_DESKTOP_Desc "Acceso Directo al Escritorio para ${APPLICATION_NAME}."
|
||||||
|
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Atajo de Acceso Rápido para ${APPLICATION_NAME}."
|
||||||
StrCpy $UNINSTALLER_FILE_Detail "Escribiendo Des-Instalador."
|
StrCpy $UNINSTALLER_FILE_Detail "Escribiendo Des-Instalador."
|
||||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Escribiendo claves de Registro del Instalador"
|
StrCpy $UNINSTALLER_REGISTRY_Detail "Escribiendo claves de Registro del Instalador"
|
||||||
StrCpy $UNINSTALLER_FINISHED_Detail "Terminado"
|
StrCpy $UNINSTALLER_FINISHED_Detail "Terminado"
|
||||||
|
StrCpy $UNINSTALL_MESSAGEBOX "Parece que ${APPLICATION_NAME} no esta instalado en el directorio '$INSTDIR'.$\n$\n¿Continuar de todos modos? (No recomendado)"
|
||||||
StrCpy $UNINSTALL_ABORT "Des-instalación abortada por el usuario"
|
StrCpy $UNINSTALL_ABORT "Des-instalación abortada por el usuario"
|
||||||
|
StrCpy $INIT_NO_QUICK_LAUNCH "Atajo de Acceso Rápido (N/A)"
|
||||||
StrCpy $INIT_NO_DESKTOP "Acceso Directo en Escritorio (Sobrescribe existentes)"
|
StrCpy $INIT_NO_DESKTOP "Acceso Directo en Escritorio (Sobrescribe existentes)"
|
||||||
|
StrCpy $UAC_ERROR_ELEVATE "No se ha podido elevar, error:"
|
||||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Este instalador requiere acceso Administrador, intente de nuevo. "
|
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Este instalador requiere acceso Administrador, intente de nuevo. "
|
||||||
StrCpy $INIT_INSTALLER_RUNNING "El instalador ya esta corriendo."
|
StrCpy $INIT_INSTALLER_RUNNING "El instalador ya esta corriendo."
|
||||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Este des-instalador requiere acceso administrador, intente de nuevo"
|
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Este des-instalador requiere acceso administrador, intente de nuevo"
|
||||||
|
StrCpy $UAC_ERROR_LOGON_SERVICE "Servicio Inicio de sesión no se está ejecutando, abortando!"
|
||||||
StrCpy $INIT_UNINSTALLER_RUNNING "El des-instalador ya esta corriendo"
|
StrCpy $INIT_UNINSTALLER_RUNNING "El des-instalador ya esta corriendo"
|
||||||
StrCpy $SectionGroup_Shortcuts "Accesos Directos"
|
StrCpy $SectionGroup_Shortcuts "Accesos Directos"
|
||||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Found ${APPLICATION_EXECUTABLE} process(s) which need to be stopped.$\nDo you want the installer to stop these for you?"
|
|
||||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
|
||||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Integration for Windows Explorer"
|
|
||||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing Integration for Windows Explorer"
|
|
||||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_SECTION "Quick Launch Shortcut"
|
|
||||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_DetailPrint "Creating Quick Launch Shortcut"
|
|
||||||
StrCpy $OPTION_SECTION_SC_APPLICATION_Desc "${APPLICATION_NAME} essentials."
|
|
||||||
StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Quick Launch shortcut for ${APPLICATION_NAME}."
|
|
||||||
StrCpy $UNINSTALL_MESSAGEBOX "It does not appear that ${APPLICATION_NAME} is installed in the directory '$INSTDIR'.$\r$\nContinue anyway (not recommended)?"
|
|
||||||
StrCpy $INIT_NO_QUICK_LAUNCH "Quick Launch Shortcut (N/A)"
|
|
||||||
StrCpy $UAC_ERROR_ELEVATE "Unable to elevate, error:"
|
|
||||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Logon service is not running, aborting!"
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ StrCpy $PageReinstall_SAME_Field_3 "Avinstallera ${APPLICATION_NAME}"
|
|||||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Avinstallera ${APPLICATION_NAME}"
|
StrCpy $UNINSTALLER_APPDATA_TITLE "Avinstallera ${APPLICATION_NAME}"
|
||||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Välj underhålls alternativ att utföra."
|
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Välj underhålls alternativ att utföra."
|
||||||
StrCpy $SEC_APPLICATION_DETAILS "Installerar ${APPLICATION_NAME} väsentligheter."
|
StrCpy $SEC_APPLICATION_DETAILS "Installerar ${APPLICATION_NAME} väsentligheter."
|
||||||
|
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Integration för Windows Explorer"
|
||||||
|
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installerar integration för Windows Explorer"
|
||||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Start-meny program genväg"
|
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Start-meny program genväg"
|
||||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Lägger till genväg för ${APPLICATION_NAME} till Start-menyn."
|
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Lägger till genväg för ${APPLICATION_NAME} till Start-menyn."
|
||||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Skrivbordsgenväg"
|
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Skrivbordsgenväg"
|
||||||
@@ -35,9 +37,7 @@ StrCpy $UAC_ERROR_ELEVATE "Kunde inte få förhöjda rättigheter, fel:"
|
|||||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Detta installationsprogram kräver adminstratörs rättigheter, försök igen"
|
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Detta installationsprogram kräver adminstratörs rättigheter, försök igen"
|
||||||
StrCpy $INIT_INSTALLER_RUNNING "Installationsprogrammet körs redan."
|
StrCpy $INIT_INSTALLER_RUNNING "Installationsprogrammet körs redan."
|
||||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Detta avinstallationsprogram kräver administratörsrättigheter, försök igen"
|
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Detta avinstallationsprogram kräver administratörsrättigheter, försök igen"
|
||||||
|
StrCpy $UAC_ERROR_LOGON_SERVICE "Login-service körs inte, avbryter!"
|
||||||
StrCpy $INIT_UNINSTALLER_RUNNING "Avinstallationsprogrammet körs redan."
|
StrCpy $INIT_UNINSTALLER_RUNNING "Avinstallationsprogrammet körs redan."
|
||||||
StrCpy $SectionGroup_Shortcuts "Genvägar"
|
StrCpy $SectionGroup_Shortcuts "Genvägar"
|
||||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
||||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Integration for Windows Explorer"
|
|
||||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing Integration for Windows Explorer"
|
|
||||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Logon service is not running, aborting!"
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
# Auto-generated - do not modify
|
# Auto-generated - do not modify
|
||||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "แสดงบันทึกประจำรุ่น"
|
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "แสดงบันทึกประจำรุ่น"
|
||||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "พบว่ากระบวนการ ${APPLICATION_EXECUTABLE} จะต้องหยุดทำงาน\nคุณต้องการติดตั้งเพื่อหยุดการทำงานเหล่านี้ของคุณ?"
|
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "พบว่ากระบวนการ ${APPLICATION_EXECUTABLE} จะต้องหยุดทำงาน$\nคุณต้องการติดตั้งเพื่อหยุดการทำงานเหล่านี้ของคุณ?"
|
||||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "ฆ่ากระบวนการทำงาน ${APPLICATION_EXECUTABLE}"
|
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "ฆ่ากระบวนการทำงาน ${APPLICATION_EXECUTABLE}"
|
||||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "ไม่พบการฆ่ากระบวนการ!"
|
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "ไม่พบการฆ่ากระบวนการ!"
|
||||||
StrCpy $PageReinstall_NEW_Field_1 "รุ่นเก่าของ ${APPLICATION_NAME} มีการติดตั้งในระบบของคุณ ขอแนะนำให้คุณถอนการติดตั้งรุ่นปัจจุบันออกก่อน เลือกการดำเนินการที่คุณต้องการที่จะดำเนินการและคลิกถัดไปเพื่อดำเนินการต่อ"
|
StrCpy $PageReinstall_NEW_Field_1 "รุ่นเก่าของ ${APPLICATION_NAME} ได้ถูกติดตั้งในระบบของคุณ ขอแนะนำให้คุณถอนการติดตั้งรุ่นปัจจุบันออกก่อน แล้วเลือกการดำเนินการที่คุณต้องการหลังจากนั้นคลิกถัดไปเพื่อดำเนินการต่อ"
|
||||||
StrCpy $PageReinstall_NEW_Field_2 "ถอนการติดตั้งก่อนการติดตั้ง"
|
StrCpy $PageReinstall_NEW_Field_2 "ถอนการติดตั้งก่อนการติดตั้ง"
|
||||||
StrCpy $PageReinstall_NEW_Field_3 "อย่าถอนการติดตั้ง"
|
StrCpy $PageReinstall_NEW_Field_3 "อย่าถอนการติดตั้ง"
|
||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "ติดตั้งแล้ว"
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "ติดตั้งแล้ว"
|
||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "เลือกวิธีที่คุณต้องการติดตั้ง ${APPLICATION_NAME}"
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "เลือกวิธีที่คุณต้องการติดตั้ง ${APPLICATION_NAME}"
|
||||||
StrCpy $PageReinstall_OLD_Field_1 "รุ่นใหม่ของ ${APPLICATION_NAME} ถูกติดตั้งแล้ว! เราไม่แนะนำให้คุณติดตั้งรุ่นเก่า ถ้าคุณอยากจะติดตั้งรุ่นเก่าก็สามารถสอนการติดตั้งได้"
|
StrCpy $PageReinstall_OLD_Field_1 "รุ่นใหม่ของ ${APPLICATION_NAME} ถูกติดตั้งแล้ว! เราไม่แนะนำให้คุณติดตั้งรุ่นที่เก่ากว่า ถ้าคุณอยากจะติดตั้งรุ่นเก่าก็สามารถถอนการติดตั้งได้"
|
||||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} ถูกติดตั้งไปแล้ว$ $\nเลือกดำเนินงานที่คุณต้องการและคลิกถัดไปเพื่อดำเนินการต่อ"
|
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} รุ่น ${VERSION} ถูกติดตั้งไปแล้ว$ $\nเลือกดำเนินงานที่คุณต้องการและคลิกถัดไปเพื่อดำเนินการต่อ"
|
||||||
StrCpy $PageReinstall_SAME_Field_2 "ส่วนประกอบ เพิ่ม/ติดตั้งใหม่ "
|
StrCpy $PageReinstall_SAME_Field_2 "ส่วนประกอบ เพิ่ม/ติดตั้งใหม่ "
|
||||||
StrCpy $PageReinstall_SAME_Field_3 "ถอนการติดตั้ง ${APPLICATION_NAME}"
|
StrCpy $PageReinstall_SAME_Field_3 "ถอนการติดตั้ง ${APPLICATION_NAME}"
|
||||||
StrCpy $UNINSTALLER_APPDATA_TITLE "ถอนการติดตั้ง ${APPLICATION_NAME}"
|
StrCpy $UNINSTALLER_APPDATA_TITLE "ถอนการติดตั้ง ${APPLICATION_NAME}"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ StrCpy $PageReinstall_NEW_Field_3 "Не видаляти"
|
|||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Установлено"
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Установлено"
|
||||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Оберіть, як ви хочете установити ${APPLICATION_NAME}."
|
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Оберіть, як ви хочете установити ${APPLICATION_NAME}."
|
||||||
StrCpy $PageReinstall_OLD_Field_1 "Знайдено новішу версію ${APPLICATION_NAME}! Ми не рекомендуємо встановлювати стару версію. Якщо ви все ж бажаєте встановити цю версію, спочатку видаліть поточну версію. Оберіть подальшу дію та натисніть $\"Далі$\"."
|
StrCpy $PageReinstall_OLD_Field_1 "Знайдено новішу версію ${APPLICATION_NAME}! Ми не рекомендуємо встановлювати стару версію. Якщо ви все ж бажаєте встановити цю версію, спочатку видаліть поточну версію. Оберіть подальшу дію та натисніть $\"Далі$\"."
|
||||||
|
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} вже встановлено.$\n$\nОберіть подальшу дію та натисніть $\"Далі$\" для продовження."
|
||||||
StrCpy $PageReinstall_SAME_Field_2 "Додати/Перевстановити компоненти"
|
StrCpy $PageReinstall_SAME_Field_2 "Додати/Перевстановити компоненти"
|
||||||
StrCpy $PageReinstall_SAME_Field_3 "Видалити ${APPLICATION_NAME}"
|
StrCpy $PageReinstall_SAME_Field_3 "Видалити ${APPLICATION_NAME}"
|
||||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Видалити ${APPLICATION_NAME}"
|
StrCpy $UNINSTALLER_APPDATA_TITLE "Видалити ${APPLICATION_NAME}"
|
||||||
@@ -37,7 +38,6 @@ StrCpy $UAC_ERROR_ELEVATE "Неможливо підняти, помилка:"
|
|||||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Для установки потрібні права адміністратора, спробуйте ще раз"
|
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Для установки потрібні права адміністратора, спробуйте ще раз"
|
||||||
StrCpy $INIT_INSTALLER_RUNNING "Установка вже запущена."
|
StrCpy $INIT_INSTALLER_RUNNING "Установка вже запущена."
|
||||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Для видалення потрібні права адміністратора, спробуйте ще раз"
|
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Для видалення потрібні права адміністратора, спробуйте ще раз"
|
||||||
|
StrCpy $UAC_ERROR_LOGON_SERVICE "Сервіс авторизації не запущений, припиняю!"
|
||||||
StrCpy $INIT_UNINSTALLER_RUNNING "Програма видалення вже запущено."
|
StrCpy $INIT_UNINSTALLER_RUNNING "Програма видалення вже запущено."
|
||||||
StrCpy $SectionGroup_Shortcuts "Ярлики"
|
StrCpy $SectionGroup_Shortcuts "Ярлики"
|
||||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
|
||||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Logon service is not running, aborting!"
|
|
||||||
|
|||||||
@@ -104,10 +104,13 @@ localeToName = {
|
|||||||
def escapeNSIS(st):
|
def escapeNSIS(st):
|
||||||
return st.replace('\\', r'$\\')\
|
return st.replace('\\', r'$\\')\
|
||||||
.replace('\t', r'$\t')\
|
.replace('\t', r'$\t')\
|
||||||
.replace('\r', r'\r')\
|
.replace('\r', r'$\r')\
|
||||||
.replace('\n', r'\n')\
|
.replace('\n', r'$\n')\
|
||||||
.replace('\"', r'$\"')\
|
.replace('\"', r'$\"')\
|
||||||
.replace('$$\\', '$\\')
|
.replace('$$\\', '$\\')\
|
||||||
|
.replace('$\\n', r'$\n')\
|
||||||
|
.replace('$\\\\n', r'$\n')
|
||||||
|
|
||||||
|
|
||||||
translationCache = {}
|
translationCache = {}
|
||||||
|
|
||||||
|
|||||||
7
admin/win/nsi/qt.conf
Normal file
7
admin/win/nsi/qt.conf
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[Paths]
|
||||||
|
Prefix = .
|
||||||
|
Plugins = .
|
||||||
|
Binaries = .
|
||||||
|
Imports = .
|
||||||
|
Qml2Imports = .
|
||||||
|
LibraryExecutables = .
|
||||||
2
binary
2
binary
Submodule binary updated: 8b72648a93...0d89ac7766
@@ -1,5 +0,0 @@
|
|||||||
--- binary
|
|
||||||
+++ binary
|
|
||||||
@@ -1 +1 @@
|
|
||||||
-Subproject commit 1fb9ddfa9a9a1b4dbc447eee10dbed89172d968a
|
|
||||||
+Subproject commit 01d73965dc8b862d1b2310d3ef801c297b697ec7
|
|
||||||
@@ -20,5 +20,8 @@
|
|||||||
<file>resources/lock-https.png</file>
|
<file>resources/lock-https.png</file>
|
||||||
<file>resources/lock-https@2x.png</file>
|
<file>resources/lock-https@2x.png</file>
|
||||||
<file>resources/account.png</file>
|
<file>resources/account.png</file>
|
||||||
|
<file>resources/more.png</file>
|
||||||
|
<file>resources/delete.png</file>
|
||||||
|
<file>resources/bell.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@@ -20,15 +20,4 @@ function (ADD_CMOCKA_TEST _testName _testSource)
|
|||||||
add_executable(${_testName} ${_testSource})
|
add_executable(${_testName} ${_testSource})
|
||||||
target_link_libraries(${_testName} ${ARGN})
|
target_link_libraries(${_testName} ${ARGN})
|
||||||
add_test(${_testName} ${CMAKE_CURRENT_BINARY_DIR}/${_testName})
|
add_test(${_testName} ${CMAKE_CURRENT_BINARY_DIR}/${_testName})
|
||||||
|
|
||||||
if(UNIT_TESTING)
|
|
||||||
INSTALL(
|
|
||||||
TARGETS
|
|
||||||
${_testName}
|
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
)
|
|
||||||
endif(UNIT_TESTING)
|
|
||||||
|
|
||||||
endfunction (ADD_CMOCKA_TEST)
|
endfunction (ADD_CMOCKA_TEST)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# (c) 2014 Copyright ownCloud, Inc.
|
# (c) 2014 Copyright ownCloud GmbH
|
||||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
# For details see the accompanying COPYING* file.
|
# For details see the accompanying COPYING* file.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# (c) 2014 Copyright ownCloud, Inc.
|
# (c) 2014 Copyright ownCloud GmbH
|
||||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
# For details see the accompanying COPYING* file.
|
# For details see the accompanying COPYING* file.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# (c) 2014 Copyright ownCloud, Inc.
|
# (c) 2014 Copyright ownCloud GmbH
|
||||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
# For details see the accompanying COPYING* file.
|
# For details see the accompanying COPYING* file.
|
||||||
|
|
||||||
@@ -41,10 +41,6 @@ if (UNIX)
|
|||||||
"${LIB_INSTALL_DIR}"
|
"${LIB_INSTALL_DIR}"
|
||||||
CACHE PATH "The subdirectory relative to the install prefix where private libs are installed"
|
CACHE PATH "The subdirectory relative to the install prefix where private libs are installed"
|
||||||
)
|
)
|
||||||
SET(PLUGIN_INSTALL_DIR
|
|
||||||
"${LIB_INSTALL_DIR}"
|
|
||||||
CACHE PATH "The subdirectory relative to the install prefix where plugins will be installed (default is prefix/lib/${APPLICATION_SHORTNAME})"
|
|
||||||
)
|
|
||||||
SET(INCLUDE_INSTALL_DIR
|
SET(INCLUDE_INSTALL_DIR
|
||||||
"${CMAKE_INSTALL_PREFIX}/include"
|
"${CMAKE_INSTALL_PREFIX}/include"
|
||||||
CACHE PATH "The subdirectory to the header prefix (default prefix/include)"
|
CACHE PATH "The subdirectory to the header prefix (default prefix/include)"
|
||||||
@@ -106,7 +102,6 @@ if (WIN32)
|
|||||||
set(SBIN_INSTALL_DIR "." CACHE PATH "-")
|
set(SBIN_INSTALL_DIR "." CACHE PATH "-")
|
||||||
set(LIB_INSTALL_DIR "lib" CACHE PATH "-")
|
set(LIB_INSTALL_DIR "lib" CACHE PATH "-")
|
||||||
set(INCLUDE_INSTALL_DIR "include" CACHE PATH "-")
|
set(INCLUDE_INSTALL_DIR "include" CACHE PATH "-")
|
||||||
set(PLUGIN_INSTALL_DIR "plugins" CACHE PATH "-")
|
|
||||||
set(HTML_INSTALL_DIR "doc/HTML" CACHE PATH "-")
|
set(HTML_INSTALL_DIR "doc/HTML" CACHE PATH "-")
|
||||||
set(ICON_INSTALL_DIR "." CACHE PATH "-")
|
set(ICON_INSTALL_DIR "." CACHE PATH "-")
|
||||||
set(SOUND_INSTALL_DIR "." CACHE PATH "-")
|
set(SOUND_INSTALL_DIR "." CACHE PATH "-")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# (c) 2014 Copyright ownCloud, Inc.
|
# (c) 2014 Copyright ownCloud GmbH
|
||||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
# For details see the accompanying COPYING* file.
|
# For details see the accompanying COPYING* file.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# (c) 2014 Copyright ownCloud, Inc.
|
# (c) 2014 Copyright ownCloud GmbH
|
||||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
# For details see the accompanying COPYING* file.
|
# For details see the accompanying COPYING* file.
|
||||||
|
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
# - Try to find Neon
|
|
||||||
# Once done this will define
|
|
||||||
#
|
|
||||||
# NEON_FOUND - system has Neon
|
|
||||||
# NEON_INCLUDE_DIRS - the Neon include directory
|
|
||||||
# NEON_LIBRARIES - Link these to use Neon
|
|
||||||
# NEON_DEFINITIONS - Compiler switches required for using Neon
|
|
||||||
#
|
|
||||||
# Copyright (c) 2011-2013 Andreas Schneider <asn@cryptomilk.org>
|
|
||||||
#
|
|
||||||
# Redistribution and use is allowed according to the terms of the New
|
|
||||||
# BSD license.
|
|
||||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
find_package(PkgConfig)
|
|
||||||
if (PKG_CONFIG_FOUND)
|
|
||||||
pkg_check_modules(_NEON neon)
|
|
||||||
endif (PKG_CONFIG_FOUND)
|
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
|
||||||
|
|
||||||
find_path(NEON_INCLUDE_DIRS
|
|
||||||
NAMES
|
|
||||||
neon/ne_basic.h
|
|
||||||
HINTS
|
|
||||||
${_NEON_INCLUDEDIR}
|
|
||||||
${CMAKE_INSTALL_INCLUDEDIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
find_library(NEON_LIBRARIES
|
|
||||||
NAMES
|
|
||||||
neon neon-27
|
|
||||||
HINTS
|
|
||||||
${_NEON_LIBDIR}
|
|
||||||
${CMAKE_INSTALL_LIBDIR}
|
|
||||||
${CMAKE_INSTALL_PREFIX}/lib
|
|
||||||
${CMAKE_INSTALL_PREFIX}/lib64
|
|
||||||
)
|
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
find_package_handle_standard_args(Neon DEFAULT_MSG NEON_LIBRARIES NEON_INCLUDE_DIRS)
|
|
||||||
|
|
||||||
# show the NEON_INCLUDE_DIRS and NEON_LIBRARIES variables only in the advanced view
|
|
||||||
mark_as_advanced(NEON_INCLUDE_DIRS NEON_LIBRARIES)
|
|
||||||
|
|
||||||
# Check if neon was compiled with LFS support, if so, the NE_LFS variable has to
|
|
||||||
# be defined in the owncloud module.
|
|
||||||
# If neon was not compiled with LFS its also ok since the underlying system
|
|
||||||
# than probably supports large files anyway.
|
|
||||||
IF( CMAKE_FIND_ROOT_PATH )
|
|
||||||
FIND_PROGRAM( NEON_CONFIG_EXECUTABLE NAMES neon-config HINTS ${CMAKE_FIND_ROOT_PATH}/bin )
|
|
||||||
ELSE( CMAKE_FIND_ROOT_PATH )
|
|
||||||
FIND_PROGRAM( NEON_CONFIG_EXECUTABLE NAMES neon-config )
|
|
||||||
ENDIF( CMAKE_FIND_ROOT_PATH )
|
|
||||||
|
|
||||||
IF ( NEON_CONFIG_EXECUTABLE )
|
|
||||||
MESSAGE(STATUS "neon-config executable: ${NEON_CONFIG_EXECUTABLE}")
|
|
||||||
# neon-config --support lfs
|
|
||||||
EXECUTE_PROCESS( COMMAND ${NEON_CONFIG_EXECUTABLE} "--support" "lfs"
|
|
||||||
RESULT_VARIABLE LFS
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE )
|
|
||||||
|
|
||||||
IF (LFS EQUAL 0)
|
|
||||||
MESSAGE(STATUS "libneon has been compiled with LFS support")
|
|
||||||
SET(NEON_WITH_LFS 1)
|
|
||||||
ELSE (LFS EQUAL 0)
|
|
||||||
MESSAGE(STATUS "libneon has not been compiled with LFS support, rely on OS")
|
|
||||||
ENDIF (LFS EQUAL 0)
|
|
||||||
ELSE ( NEON_CONFIG_EXECUTABLE )
|
|
||||||
MESSAGE(STATUS, "neon-config could not be found.")
|
|
||||||
ENDIF ( NEON_CONFIG_EXECUTABLE )
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# (c) 2014 Copyright ownCloud, Inc.
|
# (c) 2014 Copyright ownCloud GmbH
|
||||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
# For details see the accompanying COPYING* file.
|
# For details see the accompanying COPYING* file.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# (c) 2014 Copyright ownCloud, Inc.
|
# (c) 2014 Copyright ownCloud GmbH
|
||||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
# For details see the accompanying COPYING* file.
|
# For details see the accompanying COPYING* file.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# (c) 2014 Copyright ownCloud, Inc.
|
# (c) 2014 Copyright ownCloud GmbH
|
||||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
# For details see the accompanying COPYING* file.
|
# For details see the accompanying COPYING* file.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# (c) 2014 Copyright ownCloud, Inc.
|
# (c) 2014 Copyright ownCloud GmbH
|
||||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
# For details see the accompanying COPYING* file.
|
# For details see the accompanying COPYING* file.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# (c) 2014 Copyright ownCloud, Inc.
|
# (c) 2014 Copyright ownCloud GmbH
|
||||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
# For details see the accompanying COPYING* file.
|
# For details see the accompanying COPYING* file.
|
||||||
|
|
||||||
|
|||||||
@@ -134,13 +134,7 @@ if(NOT DEFINED CMAKE_INSTALL_LIBDIR OR (_libdir_set
|
|||||||
AND NOT CMAKE_CROSSCOMPILING)
|
AND NOT CMAKE_CROSSCOMPILING)
|
||||||
if (EXISTS "/etc/debian_version") # is this a debian system ?
|
if (EXISTS "/etc/debian_version") # is this a debian system ?
|
||||||
if(CMAKE_LIBRARY_ARCHITECTURE)
|
if(CMAKE_LIBRARY_ARCHITECTURE)
|
||||||
if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/?$")
|
set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
|
||||||
set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
|
|
||||||
endif()
|
|
||||||
if(DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX
|
|
||||||
AND "${_GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/?$")
|
|
||||||
set(__LAST_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
else() # not debian, rely on CMAKE_SIZEOF_VOID_P:
|
else() # not debian, rely on CMAKE_SIZEOF_VOID_P:
|
||||||
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
|
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleLongVersionString</key>
|
<key>CFBundleLongVersionString</key>
|
||||||
<string>@APPLICATION_NAME@ @MIRALL_VERSION_STRING@</string>
|
<string>@APPLICATION_NAME_XML_ESCAPED@ @MIRALL_VERSION_STRING@</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>@MIRALL_VERSION_STRING@</string>
|
<string>@MIRALL_VERSION_STRING@</string>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>(C) 2014-2015 @APPLICATION_VENDOR@</string>
|
<string>(C) 2014-2016 @APPLICATION_VENDOR@</string>
|
||||||
<key>SUShowReleaseNotes</key>
|
<key>SUShowReleaseNotes</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>LSMinimumBundleVersion</key>
|
<key>LSMinimumBundleVersion</key>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# (c) 2014 Copyright ownCloud, Inc.
|
# (c) 2014 Copyright ownCloud GmbH
|
||||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
# For details see the accompanying COPYING* file.
|
# For details see the accompanying COPYING* file.
|
||||||
|
|
||||||
|
|||||||
@@ -411,6 +411,9 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
|||||||
File "@CPACK_RESOURCE_FILE_LICENSE@"
|
File "@CPACK_RESOURCE_FILE_LICENSE@"
|
||||||
;File /oname=NOTES.txt ${NSI_PATH}\RELEASE_NOTES.txt
|
;File /oname=NOTES.txt ${NSI_PATH}\RELEASE_NOTES.txt
|
||||||
|
|
||||||
|
;Qt config:
|
||||||
|
File "${NSI_PATH}\qt.conf"
|
||||||
|
|
||||||
;Qt stuff:
|
;Qt stuff:
|
||||||
File "${QT_DLL_PATH}\Qt5Core.dll"
|
File "${QT_DLL_PATH}\Qt5Core.dll"
|
||||||
File "${QT_DLL_PATH}\Qt5Gui.dll"
|
File "${QT_DLL_PATH}\Qt5Gui.dll"
|
||||||
@@ -620,7 +623,6 @@ Section Uninstall
|
|||||||
!insertmacro UnInstallLib REGDLL NOTSHARED REBOOT_PROTECTED "$INSTDIR\shellext\OCOverlays_x64.dll"
|
!insertmacro UnInstallLib REGDLL NOTSHARED REBOOT_PROTECTED "$INSTDIR\shellext\OCOverlays_x64.dll"
|
||||||
!insertmacro UnInstallLib DLL NOTSHARED REBOOT_PROTECTED "$INSTDIR\shellext\OCUtil_x64.dll"
|
!insertmacro UnInstallLib DLL NOTSHARED REBOOT_PROTECTED "$INSTDIR\shellext\OCUtil_x64.dll"
|
||||||
!undef LIBRARY_X64
|
!undef LIBRARY_X64
|
||||||
${Else}
|
|
||||||
DetailPrint "Uninstalling x86 overlay DLLs"
|
DetailPrint "Uninstalling x86 overlay DLLs"
|
||||||
!insertmacro UnInstallLib REGDLL NOTSHARED REBOOT_PROTECTED "$INSTDIR\shellext\OCContextMenu_x86.dll"
|
!insertmacro UnInstallLib REGDLL NOTSHARED REBOOT_PROTECTED "$INSTDIR\shellext\OCContextMenu_x86.dll"
|
||||||
!insertmacro UnInstallLib REGDLL NOTSHARED REBOOT_PROTECTED "$INSTDIR\shellext\OCOverlays_x86.dll"
|
!insertmacro UnInstallLib REGDLL NOTSHARED REBOOT_PROTECTED "$INSTDIR\shellext\OCOverlays_x86.dll"
|
||||||
@@ -757,6 +759,12 @@ Function .onInit
|
|||||||
|
|
||||||
;Shutdown ${APPLICATION_NAME} in case Add/Remove re-installer option used.
|
;Shutdown ${APPLICATION_NAME} in case Add/Remove re-installer option used.
|
||||||
Call EnsureOwncloudShutdown
|
Call EnsureOwncloudShutdown
|
||||||
|
|
||||||
|
ReadRegStr $R0 ${MEMENTO_REGISTRY_ROOT} "${MEMENTO_REGISTRY_KEY}" "InstallLocation"
|
||||||
|
${If} ${Silent}
|
||||||
|
${AndIf} $R0 != ""
|
||||||
|
ExecWait '"$R0\Uninstall.exe" /S _?=$R0'
|
||||||
|
${EndIf}
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
Function .onInstSuccess
|
Function .onInstSuccess
|
||||||
@@ -766,6 +774,11 @@ Function .onInstSuccess
|
|||||||
WriteRegDWORD HKLM "Software\${APPLICATION_VENDOR}\${APPLICATION_NAME}" "skipUpdateCheck" "1"
|
WriteRegDWORD HKLM "Software\${APPLICATION_VENDOR}\${APPLICATION_NAME}" "skipUpdateCheck" "1"
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
|
; TODO: Only needed to when updating from 2.1.{0,1}. Remove in due time.
|
||||||
|
Delete /REBOOTOK $INSTDIR\bearer\qgenericbearer.dll
|
||||||
|
Delete /REBOOTOK $INSTDIR\bearer\qnativewifibearer.dll
|
||||||
|
RMDir /REBOOTOK $INSTDIR\bearer
|
||||||
|
|
||||||
${If} ${Silent}
|
${If} ${Silent}
|
||||||
${AndIf} $InstallRunIfSilent == "yes"
|
${AndIf} $InstallRunIfSilent == "yes"
|
||||||
Call LaunchApplication
|
Call LaunchApplication
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# (c) 2014 Copyright ownCloud, Inc.
|
# (c) 2014 Copyright ownCloud GmbH
|
||||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
# For details see the accompanying COPYING* file.
|
# For details see the accompanying COPYING* file.
|
||||||
|
|
||||||
@@ -18,11 +18,12 @@ if( Qt5Core_FOUND )
|
|||||||
find_package(Qt5Network REQUIRED)
|
find_package(Qt5Network REQUIRED)
|
||||||
find_package(Qt5Xml REQUIRED)
|
find_package(Qt5Xml REQUIRED)
|
||||||
find_package(Qt5Concurrent REQUIRED)
|
find_package(Qt5Concurrent REQUIRED)
|
||||||
|
if(UNIT_TESTING)
|
||||||
|
find_package(Qt5Test REQUIRED)
|
||||||
|
endif()
|
||||||
if(NOT TOKEN_AUTH_ONLY)
|
if(NOT TOKEN_AUTH_ONLY)
|
||||||
find_package(Qt5WebKitWidgets REQUIRED)
|
find_package(Qt5WebKitWidgets REQUIRED)
|
||||||
find_package(Qt5WebKit REQUIRED)
|
find_package(Qt5WebKit REQUIRED)
|
||||||
find_package(Qt5PrintSupport REQUIRED)
|
|
||||||
find_package(Qt5Quick REQUIRED)
|
|
||||||
find_package(Qt5Widgets REQUIRED)
|
find_package(Qt5Widgets REQUIRED)
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
find_package(Qt5MacExtras REQUIRED)
|
find_package(Qt5MacExtras REQUIRED)
|
||||||
@@ -31,7 +32,9 @@ if( Qt5Core_FOUND )
|
|||||||
|
|
||||||
else( Qt5Core_FOUND )
|
else( Qt5Core_FOUND )
|
||||||
if(WIN32 OR APPLE)
|
if(WIN32 OR APPLE)
|
||||||
|
if (NOT BUILD_WITH_QT4)
|
||||||
message(FATAL_ERROR "Qt 5 not found, but application depends on Qt5 on Windows and Mac OS X")
|
message(FATAL_ERROR "Qt 5 not found, but application depends on Qt5 on Windows and Mac OS X")
|
||||||
|
endif ()
|
||||||
endif(WIN32 OR APPLE)
|
endif(WIN32 OR APPLE)
|
||||||
endif( Qt5Core_FOUND )
|
endif( Qt5Core_FOUND )
|
||||||
|
|
||||||
@@ -72,11 +75,16 @@ endif()
|
|||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
if(NOT TOKEN_AUTH_ONLY)
|
if(NOT TOKEN_AUTH_ONLY)
|
||||||
find_package(Qt5LinguistTools REQUIRED)
|
find_package(Qt5LinguistTools)
|
||||||
macro(qt_add_translation)
|
if(Qt5LinguistTools_FOUND)
|
||||||
qt5_add_translation(${ARGN})
|
macro(qt_add_translation)
|
||||||
endmacro()
|
qt5_add_translation(${ARGN})
|
||||||
else()
|
endmacro()
|
||||||
|
else()
|
||||||
|
macro(qt_add_translation)
|
||||||
|
endmacro()
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
macro(qt_add_translation)
|
macro(qt_add_translation)
|
||||||
endmacro()
|
endmacro()
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# (c) 2014 Copyright ownCloud, Inc.
|
# (c) 2014 Copyright ownCloud GmbH
|
||||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
# For details see the accompanying COPYING* file.
|
# For details see the accompanying COPYING* file.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# (c) 2014 Copyright ownCloud, Inc.
|
# (c) 2014 Copyright ownCloud GmbH
|
||||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
# For details see the accompanying COPYING* file.
|
# For details see the accompanying COPYING* file.
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,4 @@
|
|||||||
#cmakedefine SYSCONFDIR "@SYSCONFDIR@"
|
#cmakedefine SYSCONFDIR "@SYSCONFDIR@"
|
||||||
#cmakedefine SHAREDIR "@SHAREDIR@"
|
#cmakedefine SHAREDIR "@SHAREDIR@"
|
||||||
|
|
||||||
#ifndef NEON_WITH_LFS
|
|
||||||
#cmakedefine NEON_WITH_LFS "@NEON_WITH_LFS@"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ set(PACKAGE ${APPLICATION_NAME})
|
|||||||
set(VERSION ${APPLICATION_VERSION})
|
set(VERSION ${APPLICATION_VERSION})
|
||||||
set(DATADIR ${DATA_INSTALL_DIR})
|
set(DATADIR ${DATA_INSTALL_DIR})
|
||||||
set(LIBDIR ${LIB_INSTALL_DIR})
|
set(LIBDIR ${LIB_INSTALL_DIR})
|
||||||
set(PLUGINDIR "${PLUGIN_INSTALL_DIR}-${LIBRARY_SOVERSION}")
|
|
||||||
set(SYSCONFDIR ${SYSCONF_INSTALL_DIR})
|
set(SYSCONFDIR ${SYSCONF_INSTALL_DIR})
|
||||||
|
|
||||||
set(BINARYDIR ${CMAKE_CURRENT_BINARY_DIR})
|
set(BINARYDIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
#cmakedefine VERSION "${APPLICATION_VERSION}"
|
#cmakedefine VERSION "${APPLICATION_VERSION}"
|
||||||
#cmakedefine LOCALEDIR "${LOCALE_INSTALL_DIR}"
|
#cmakedefine LOCALEDIR "${LOCALE_INSTALL_DIR}"
|
||||||
#cmakedefine LIBDIR "${LIBDIR}"
|
#cmakedefine LIBDIR "${LIBDIR}"
|
||||||
#cmakedefine PLUGINDIR "${PLUGINDIR}"
|
|
||||||
#cmakedefine SYSCONFDIR "${SYSCONFDIR}"
|
#cmakedefine SYSCONFDIR "${SYSCONFDIR}"
|
||||||
#cmakedefine BINARYDIR "${BINARYDIR}"
|
#cmakedefine BINARYDIR "${BINARYDIR}"
|
||||||
#cmakedefine SOURCEDIR "${SOURCEDIR}"
|
#cmakedefine SOURCEDIR "${SOURCEDIR}"
|
||||||
@@ -24,10 +23,6 @@
|
|||||||
#cmakedefine HAVE_ICONV 1
|
#cmakedefine HAVE_ICONV 1
|
||||||
#cmakedefine HAVE_ICONV_CONST 1
|
#cmakedefine HAVE_ICONV_CONST 1
|
||||||
|
|
||||||
#ifndef NEON_WITH_LFS
|
|
||||||
#cmakedefine NEON_WITH_LFS 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#cmakedefine HAVE___MINGW_ASPRINTF 1
|
#cmakedefine HAVE___MINGW_ASPRINTF 1
|
||||||
#cmakedefine HAVE_ASPRINTF 1
|
#cmakedefine HAVE_ASPRINTF 1
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
project(libcsync)
|
project(libcsync)
|
||||||
|
|
||||||
add_subdirectory(std)
|
add_subdirectory(std)
|
||||||
if(USE_NEON)
|
|
||||||
add_subdirectory(httpbf)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Statically include sqlite
|
# Statically include sqlite
|
||||||
|
|
||||||
@@ -71,19 +68,6 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
if(USE_NEON)
|
|
||||||
list(APPEND csync_SRCS
|
|
||||||
csync_owncloud.c
|
|
||||||
csync_owncloud_util.c
|
|
||||||
)
|
|
||||||
list(APPEND CSYNC_LINK_LIBRARIES
|
|
||||||
${NEON_LIBRARIES}
|
|
||||||
)
|
|
||||||
include_directories(${NEON_INCLUDE_DIRS})
|
|
||||||
add_definitions(-DUSE_NEON)
|
|
||||||
endif(USE_NEON)
|
|
||||||
|
|
||||||
|
|
||||||
configure_file(csync_version.h.in ${CMAKE_CURRENT_BINARY_DIR}/csync_version.h)
|
configure_file(csync_version.h.in ${CMAKE_CURRENT_BINARY_DIR}/csync_version.h)
|
||||||
|
|
||||||
set(csync_HDRS
|
set(csync_HDRS
|
||||||
@@ -144,10 +128,4 @@ else()
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# INSTALL(
|
|
||||||
# FILES
|
|
||||||
# ${csync_HDRS}
|
|
||||||
# DESTINATION
|
|
||||||
# ${INCLUDE_INSTALL_DIR}/${APPLICATION_NAME}
|
|
||||||
# )
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -58,12 +59,6 @@
|
|||||||
#include "csync_rename.h"
|
#include "csync_rename.h"
|
||||||
#include "c_jhash.h"
|
#include "c_jhash.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_NEON
|
|
||||||
// Breaking the abstraction for fun and profit.
|
|
||||||
#include "csync_owncloud.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int _key_cmp(const void *key, const void *data) {
|
static int _key_cmp(const void *key, const void *data) {
|
||||||
uint64_t a;
|
uint64_t a;
|
||||||
csync_file_stat_t *b;
|
csync_file_stat_t *b;
|
||||||
@@ -95,14 +90,11 @@ static int _data_cmp(const void *key, const void *data) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int csync_create(CSYNC **csync, const char *local, const char *remote) {
|
void csync_create(CSYNC **csync, const char *local, const char *remote) {
|
||||||
CSYNC *ctx;
|
CSYNC *ctx;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
ctx = c_malloc(sizeof(CSYNC));
|
ctx = c_malloc(sizeof(CSYNC));
|
||||||
if (ctx == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->status_code = CSYNC_STATUS_OK;
|
ctx->status_code = CSYNC_STATUS_OK;
|
||||||
|
|
||||||
@@ -127,49 +119,21 @@ int csync_create(CSYNC **csync, const char *local, const char *remote) {
|
|||||||
ctx->ignore_hidden_files = true;
|
ctx->ignore_hidden_files = true;
|
||||||
|
|
||||||
*csync = ctx;
|
*csync = ctx;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int csync_init(CSYNC *ctx) {
|
void csync_init(CSYNC *ctx) {
|
||||||
int rc;
|
assert(ctx);
|
||||||
|
|
||||||
if (ctx == NULL) {
|
|
||||||
errno = EBADF;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->status_code = CSYNC_STATUS_OK;
|
|
||||||
|
|
||||||
/* Do not initialize twice */
|
/* Do not initialize twice */
|
||||||
if (ctx->status & CSYNC_STATUS_INIT) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check for uri */
|
assert(!(ctx->status & CSYNC_STATUS_INIT));
|
||||||
if (csync_fnmatch("owncloud://*", ctx->remote.uri, 0) == 0 && csync_fnmatch("ownclouds://*", ctx->remote.uri, 0) == 0) {
|
ctx->status_code = CSYNC_STATUS_OK;
|
||||||
ctx->status_code = CSYNC_STATUS_NO_MODULE;
|
|
||||||
rc = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->local.type = LOCAL_REPLICA;
|
ctx->local.type = LOCAL_REPLICA;
|
||||||
|
|
||||||
#ifdef USE_NEON
|
|
||||||
owncloud_init(ctx);
|
|
||||||
#endif
|
|
||||||
ctx->remote.type = REMOTE_REPLICA;
|
ctx->remote.type = REMOTE_REPLICA;
|
||||||
|
|
||||||
if (c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp) < 0) {
|
c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp);
|
||||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
c_rbtree_create(&ctx->remote.tree, _key_cmp, _data_cmp);
|
||||||
rc = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c_rbtree_create(&ctx->remote.tree, _key_cmp, _data_cmp) < 0) {
|
|
||||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
|
||||||
rc = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->remote.root_perms = 0;
|
ctx->remote.root_perms = 0;
|
||||||
|
|
||||||
@@ -177,11 +141,6 @@ int csync_init(CSYNC *ctx) {
|
|||||||
|
|
||||||
/* initialize random generator */
|
/* initialize random generator */
|
||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
|
|
||||||
rc = 0;
|
|
||||||
|
|
||||||
out:
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int csync_update(CSYNC *ctx) {
|
int csync_update(CSYNC *ctx) {
|
||||||
@@ -216,14 +175,6 @@ int csync_update(CSYNC *ctx) {
|
|||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "No exclude file loaded or defined!");
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "No exclude file loaded or defined!");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_NEON
|
|
||||||
/* This is not actually connecting, just setting the info for neon. The legacy propagator can use it.. */
|
|
||||||
if (dav_connect( ctx, ctx->remote.uri ) < 0) {
|
|
||||||
ctx->status_code = CSYNC_STATUS_CONNECT_ERROR;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* update detection for local replica */
|
/* update detection for local replica */
|
||||||
csync_gettime(&start);
|
csync_gettime(&start);
|
||||||
ctx->current = LOCAL_REPLICA;
|
ctx->current = LOCAL_REPLICA;
|
||||||
@@ -438,6 +389,8 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
|
|||||||
trav.error_status = cur->error_status;
|
trav.error_status = cur->error_status;
|
||||||
trav.should_update_metadata = cur->should_update_metadata;
|
trav.should_update_metadata = cur->should_update_metadata;
|
||||||
trav.has_ignored_files = cur->has_ignored_files;
|
trav.has_ignored_files = cur->has_ignored_files;
|
||||||
|
trav.checksum = cur->checksum;
|
||||||
|
trav.checksumTypeId = cur->checksumTypeId;
|
||||||
|
|
||||||
if( other_node ) {
|
if( other_node ) {
|
||||||
csync_file_stat_t *other_stat = (csync_file_stat_t*)other_node->data;
|
csync_file_stat_t *other_stat = (csync_file_stat_t*)other_node->data;
|
||||||
@@ -595,29 +548,17 @@ int csync_commit(CSYNC *ctx) {
|
|||||||
ctx->remote.read_from_db = 0;
|
ctx->remote.read_from_db = 0;
|
||||||
ctx->read_remote_from_db = true;
|
ctx->read_remote_from_db = true;
|
||||||
ctx->db_is_empty = false;
|
ctx->db_is_empty = false;
|
||||||
ctx->ignore_hidden_files = true; // do NOT sync hidden files by default.
|
|
||||||
|
|
||||||
|
|
||||||
/* Create new trees */
|
/* Create new trees */
|
||||||
rc = c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp);
|
c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp);
|
||||||
if (rc < 0) {
|
c_rbtree_create(&ctx->remote.tree, _key_cmp, _data_cmp);
|
||||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = c_rbtree_create(&ctx->remote.tree, _key_cmp, _data_cmp);
|
|
||||||
if (rc < 0) {
|
|
||||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ctx->status = CSYNC_STATUS_INIT;
|
ctx->status = CSYNC_STATUS_INIT;
|
||||||
SAFE_FREE(ctx->error_string);
|
SAFE_FREE(ctx->error_string);
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
|
||||||
out:
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,19 +578,12 @@ int csync_destroy(CSYNC *ctx) {
|
|||||||
}
|
}
|
||||||
ctx->statedb.db = NULL;
|
ctx->statedb.db = NULL;
|
||||||
|
|
||||||
/* destroy exclude list */
|
|
||||||
csync_exclude_destroy(ctx);
|
|
||||||
|
|
||||||
_csync_clean_ctx(ctx);
|
_csync_clean_ctx(ctx);
|
||||||
|
|
||||||
SAFE_FREE(ctx->local.uri);
|
SAFE_FREE(ctx->local.uri);
|
||||||
SAFE_FREE(ctx->remote.uri);
|
SAFE_FREE(ctx->remote.uri);
|
||||||
SAFE_FREE(ctx->error_string);
|
SAFE_FREE(ctx->error_string);
|
||||||
|
|
||||||
#ifdef USE_NEON
|
|
||||||
owncloud_destroy(ctx);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WITH_ICONV
|
#ifdef WITH_ICONV
|
||||||
c_close_iconv();
|
c_close_iconv();
|
||||||
#endif
|
#endif
|
||||||
@@ -659,34 +593,6 @@ int csync_destroy(CSYNC *ctx) {
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int csync_add_exclude_list(CSYNC *ctx, const char *path) {
|
|
||||||
if (ctx == NULL || path == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return csync_exclude_load(path, &ctx->excludes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void csync_clear_exclude_list(CSYNC *ctx)
|
|
||||||
{
|
|
||||||
csync_exclude_clear(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
int csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb) {
|
|
||||||
if (ctx == NULL || cb == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx->status & CSYNC_STATUS_INIT) {
|
|
||||||
ctx->status_code = CSYNC_STATUS_CSYNC_STATUS_ERROR;
|
|
||||||
fprintf(stderr, "This function must be called before initialization.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
ctx->callbacks.auth_function = cb;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *csync_get_userdata(CSYNC *ctx) {
|
void *csync_get_userdata(CSYNC *ctx) {
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -778,17 +684,7 @@ void csync_file_stat_free(csync_file_stat_t *st)
|
|||||||
SAFE_FREE(st->directDownloadCookies);
|
SAFE_FREE(st->directDownloadCookies);
|
||||||
SAFE_FREE(st->etag);
|
SAFE_FREE(st->etag);
|
||||||
SAFE_FREE(st->destpath);
|
SAFE_FREE(st->destpath);
|
||||||
|
SAFE_FREE(st->checksum);
|
||||||
SAFE_FREE(st);
|
SAFE_FREE(st);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int csync_set_module_property(CSYNC* ctx, const char* key, void* value)
|
|
||||||
{
|
|
||||||
#ifdef USE_NEON
|
|
||||||
return owncloud_set_property(ctx, key, value);
|
|
||||||
#else
|
|
||||||
(void)ctx, (void)key, (void)value;
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,8 @@ enum csync_status_codes_e {
|
|||||||
CYSNC_STATUS_FILE_LOCKED_OR_OPEN,
|
CYSNC_STATUS_FILE_LOCKED_OR_OPEN,
|
||||||
CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN,
|
CSYNC_STATUS_INDIVIDUAL_EXCLUDE_HIDDEN,
|
||||||
CSYNC_STATUS_INVALID_CHARACTERS,
|
CSYNC_STATUS_INVALID_CHARACTERS,
|
||||||
CSYNC_STATUS_INDIVIDUAL_STAT_FAILED
|
CSYNC_STATUS_INDIVIDUAL_STAT_FAILED,
|
||||||
|
CSYNC_STATUS_FORBIDDEN
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum csync_status_codes_e CSYNC_STATUS;
|
typedef enum csync_status_codes_e CSYNC_STATUS;
|
||||||
@@ -133,7 +134,10 @@ enum csync_instructions_e {
|
|||||||
CSYNC_INSTRUCTION_IGNORE = 0x00000020, /* The file is ignored (UPDATE|RECONCILE) */
|
CSYNC_INSTRUCTION_IGNORE = 0x00000020, /* The file is ignored (UPDATE|RECONCILE) */
|
||||||
CSYNC_INSTRUCTION_SYNC = 0x00000040, /* The file need to be pushed to the other remote (RECONCILE) */
|
CSYNC_INSTRUCTION_SYNC = 0x00000040, /* The file need to be pushed to the other remote (RECONCILE) */
|
||||||
CSYNC_INSTRUCTION_STAT_ERROR = 0x00000080,
|
CSYNC_INSTRUCTION_STAT_ERROR = 0x00000080,
|
||||||
CSYNC_INSTRUCTION_ERROR = 0x00000100
|
CSYNC_INSTRUCTION_ERROR = 0x00000100,
|
||||||
|
CSYNC_INSTRUCTION_TYPE_CHANGE = 0x0000200, /* Like NEW, but deletes the old entity first (RECONCILE)
|
||||||
|
Used when the type of something changes from directory to file
|
||||||
|
or back. */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum csync_ftw_type_e {
|
enum csync_ftw_type_e {
|
||||||
@@ -173,7 +177,7 @@ enum csync_vio_file_stat_fields_e {
|
|||||||
CSYNC_VIO_FILE_STAT_FIELDS_TYPE = 1 << 0,
|
CSYNC_VIO_FILE_STAT_FIELDS_TYPE = 1 << 0,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_MODE = 1 << 1, // local POSIX mode
|
CSYNC_VIO_FILE_STAT_FIELDS_MODE = 1 << 1, // local POSIX mode
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_FLAGS = 1 << 2,
|
CSYNC_VIO_FILE_STAT_FIELDS_FLAGS = 1 << 2,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_DEVICE = 1 << 3,
|
// CSYNC_VIO_FILE_STAT_FIELDS_DEVICE = 1 << 3,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_INODE = 1 << 4,
|
CSYNC_VIO_FILE_STAT_FIELDS_INODE = 1 << 4,
|
||||||
// CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT = 1 << 5,
|
// CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT = 1 << 5,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_SIZE = 1 << 6,
|
CSYNC_VIO_FILE_STAT_FIELDS_SIZE = 1 << 6,
|
||||||
@@ -212,7 +216,6 @@ struct csync_vio_file_stat_s {
|
|||||||
|
|
||||||
mode_t mode;
|
mode_t mode;
|
||||||
|
|
||||||
dev_t device;
|
|
||||||
uint64_t inode;
|
uint64_t inode;
|
||||||
|
|
||||||
int fields; // actually enum csync_vio_file_stat_fields_e fields;
|
int fields; // actually enum csync_vio_file_stat_fields_e fields;
|
||||||
@@ -262,6 +265,10 @@ struct csync_tree_walk_file_s {
|
|||||||
const char *remotePerm;
|
const char *remotePerm;
|
||||||
char *directDownloadUrl;
|
char *directDownloadUrl;
|
||||||
char *directDownloadCookies;
|
char *directDownloadCookies;
|
||||||
|
|
||||||
|
const char *checksum;
|
||||||
|
uint32_t checksumTypeId;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int64_t size;
|
int64_t size;
|
||||||
time_t modtime;
|
time_t modtime;
|
||||||
@@ -301,14 +308,16 @@ typedef void (*csync_vio_closedir_hook) (csync_vio_handle_t *dhhandle,
|
|||||||
typedef int (*csync_vio_stat_hook) (csync_vio_handle_t *dhhandle,
|
typedef int (*csync_vio_stat_hook) (csync_vio_handle_t *dhhandle,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
|
||||||
|
/* Compute the checksum of the given \a checksumTypeId for \a path. */
|
||||||
|
typedef const char* (*csync_checksum_hook) (
|
||||||
|
const char *path, uint32_t checksumTypeId, void *userdata);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Allocate a csync context.
|
* @brief Allocate a csync context.
|
||||||
*
|
*
|
||||||
* @param csync The context variable to allocate.
|
* @param csync The context variable to allocate.
|
||||||
*
|
|
||||||
* @return 0 on success, less than 0 if an error occured.
|
|
||||||
*/
|
*/
|
||||||
int csync_create(CSYNC **csync, const char *local, const char *remote);
|
void csync_create(CSYNC **csync, const char *local, const char *remote);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize the file synchronizer.
|
* @brief Initialize the file synchronizer.
|
||||||
@@ -316,17 +325,15 @@ int csync_create(CSYNC **csync, const char *local, const char *remote);
|
|||||||
* This function loads the configuration
|
* This function loads the configuration
|
||||||
*
|
*
|
||||||
* @param ctx The context to initialize.
|
* @param ctx The context to initialize.
|
||||||
*
|
|
||||||
* @return 0 on success, less than 0 if an error occured.
|
|
||||||
*/
|
*/
|
||||||
int csync_init(CSYNC *ctx);
|
void csync_init(CSYNC *ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Update detection
|
* @brief Update detection
|
||||||
*
|
*
|
||||||
* @param ctx The context to run the update detection on.
|
* @param ctx The context to run the update detection on.
|
||||||
*
|
*
|
||||||
* @return 0 on success, less than 0 if an error occured.
|
* @return 0 on success, less than 0 if an error occurred.
|
||||||
*/
|
*/
|
||||||
int csync_update(CSYNC *ctx);
|
int csync_update(CSYNC *ctx);
|
||||||
|
|
||||||
@@ -335,7 +342,7 @@ int csync_update(CSYNC *ctx);
|
|||||||
*
|
*
|
||||||
* @param ctx The context to run the reconciliation on.
|
* @param ctx The context to run the reconciliation on.
|
||||||
*
|
*
|
||||||
* @return 0 on success, less than 0 if an error occured.
|
* @return 0 on success, less than 0 if an error occurred.
|
||||||
*/
|
*/
|
||||||
int csync_reconcile(CSYNC *ctx);
|
int csync_reconcile(CSYNC *ctx);
|
||||||
|
|
||||||
@@ -344,7 +351,7 @@ int csync_reconcile(CSYNC *ctx);
|
|||||||
*
|
*
|
||||||
* @param ctx The context to commit.
|
* @param ctx The context to commit.
|
||||||
*
|
*
|
||||||
* @return 0 on success, less than 0 if an error occured.
|
* @return 0 on success, less than 0 if an error occurred.
|
||||||
*/
|
*/
|
||||||
int csync_commit(CSYNC *ctx);
|
int csync_commit(CSYNC *ctx);
|
||||||
|
|
||||||
@@ -355,35 +362,17 @@ int csync_commit(CSYNC *ctx);
|
|||||||
*
|
*
|
||||||
* @param ctx The context to destroy.
|
* @param ctx The context to destroy.
|
||||||
*
|
*
|
||||||
* @return 0 on success, less than 0 if an error occured.
|
* @return 0 on success, less than 0 if an error occurred.
|
||||||
*/
|
*/
|
||||||
int csync_destroy(CSYNC *ctx);
|
int csync_destroy(CSYNC *ctx);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Add an additional exclude list.
|
|
||||||
*
|
|
||||||
* @param ctx The context to add the exclude list.
|
|
||||||
*
|
|
||||||
* @param path The path pointing to the file.
|
|
||||||
*
|
|
||||||
* @return 0 on success, less than 0 if an error occured.
|
|
||||||
*/
|
|
||||||
int csync_add_exclude_list(CSYNC *ctx, const char *path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Removes all items imported from exclude lists.
|
|
||||||
*
|
|
||||||
* @param ctx The context to add the exclude list.
|
|
||||||
*/
|
|
||||||
void csync_clear_exclude_list(CSYNC *ctx);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the userdata saved in the context.
|
* @brief Get the userdata saved in the context.
|
||||||
*
|
*
|
||||||
* @param ctx The csync context.
|
* @param ctx The csync context.
|
||||||
*
|
*
|
||||||
* @return The userdata saved in the context, NULL if an error
|
* @return The userdata saved in the context, NULL if an error
|
||||||
* occured.
|
* occurred.
|
||||||
*/
|
*/
|
||||||
void *csync_get_userdata(CSYNC *ctx);
|
void *csync_get_userdata(CSYNC *ctx);
|
||||||
|
|
||||||
@@ -395,7 +384,7 @@ void *csync_get_userdata(CSYNC *ctx);
|
|||||||
*
|
*
|
||||||
* @param userdata The userdata to be stored in the context.
|
* @param userdata The userdata to be stored in the context.
|
||||||
*
|
*
|
||||||
* @return 0 on success, less than 0 if an error occured.
|
* @return 0 on success, less than 0 if an error occurred.
|
||||||
*/
|
*/
|
||||||
int csync_set_userdata(CSYNC *ctx, void *userdata);
|
int csync_set_userdata(CSYNC *ctx, void *userdata);
|
||||||
|
|
||||||
@@ -405,7 +394,7 @@ int csync_set_userdata(CSYNC *ctx, void *userdata);
|
|||||||
* @param ctx The csync context.
|
* @param ctx The csync context.
|
||||||
*
|
*
|
||||||
* @return The authentication callback set or NULL if an error
|
* @return The authentication callback set or NULL if an error
|
||||||
* occured.
|
* occurred.
|
||||||
*/
|
*/
|
||||||
csync_auth_callback csync_get_auth_callback(CSYNC *ctx);
|
csync_auth_callback csync_get_auth_callback(CSYNC *ctx);
|
||||||
|
|
||||||
@@ -416,7 +405,7 @@ csync_auth_callback csync_get_auth_callback(CSYNC *ctx);
|
|||||||
*
|
*
|
||||||
* @param cb The authentication callback.
|
* @param cb The authentication callback.
|
||||||
*
|
*
|
||||||
* @return 0 on success, less than 0 if an error occured.
|
* @return 0 on success, less than 0 if an error occurred.
|
||||||
*/
|
*/
|
||||||
int csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb);
|
int csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb);
|
||||||
|
|
||||||
@@ -425,7 +414,7 @@ int csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb);
|
|||||||
*
|
*
|
||||||
* @param[in] level The log verbosity.
|
* @param[in] level The log verbosity.
|
||||||
*
|
*
|
||||||
* @return 0 on success, < 0 if an error occured.
|
* @return 0 on success, < 0 if an error occurred.
|
||||||
*/
|
*/
|
||||||
int csync_set_log_level(int level);
|
int csync_set_log_level(int level);
|
||||||
|
|
||||||
@@ -440,7 +429,7 @@ int csync_get_log_level(void);
|
|||||||
* @brief Get the logging callback set.
|
* @brief Get the logging callback set.
|
||||||
*
|
*
|
||||||
* @return The logging callback set or NULL if an error
|
* @return The logging callback set or NULL if an error
|
||||||
* occured.
|
* occurred.
|
||||||
*/
|
*/
|
||||||
csync_log_callback csync_get_log_callback(void);
|
csync_log_callback csync_get_log_callback(void);
|
||||||
|
|
||||||
@@ -449,7 +438,7 @@ csync_log_callback csync_get_log_callback(void);
|
|||||||
*
|
*
|
||||||
* @param cb The logging callback.
|
* @param cb The logging callback.
|
||||||
*
|
*
|
||||||
* @return 0 on success, less than 0 if an error occured.
|
* @return 0 on success, less than 0 if an error occurred.
|
||||||
*/
|
*/
|
||||||
int csync_set_log_callback(csync_log_callback cb);
|
int csync_set_log_callback(csync_log_callback cb);
|
||||||
|
|
||||||
@@ -465,7 +454,7 @@ void *csync_get_log_userdata(void);
|
|||||||
*
|
*
|
||||||
* @param[in] data The userdata to set.
|
* @param[in] data The userdata to set.
|
||||||
*
|
*
|
||||||
* @return 0 on success, less than 0 if an error occured.
|
* @return 0 on success, less than 0 if an error occurred.
|
||||||
*/
|
*/
|
||||||
int csync_set_log_userdata(void *data);
|
int csync_set_log_userdata(void *data);
|
||||||
|
|
||||||
@@ -484,7 +473,7 @@ typedef int csync_treewalk_visit_func(TREE_WALK_FILE* ,void*);
|
|||||||
* @param visitor A callback function to handle the file info.
|
* @param visitor A callback function to handle the file info.
|
||||||
* @param filter A filter, built from or'ed csync_instructions_e
|
* @param filter A filter, built from or'ed csync_instructions_e
|
||||||
*
|
*
|
||||||
* @return 0 on success, less than 0 if an error occured.
|
* @return 0 on success, less than 0 if an error occurred.
|
||||||
*/
|
*/
|
||||||
int csync_walk_local_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter);
|
int csync_walk_local_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter);
|
||||||
|
|
||||||
@@ -495,7 +484,7 @@ int csync_walk_local_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int fi
|
|||||||
* @param visitor A callback function to handle the file info.
|
* @param visitor A callback function to handle the file info.
|
||||||
* @param filter A filter, built from and'ed csync_instructions_e
|
* @param filter A filter, built from and'ed csync_instructions_e
|
||||||
*
|
*
|
||||||
* @return 0 on success, less than 0 if an error occured.
|
* @return 0 on success, less than 0 if an error occurred.
|
||||||
*/
|
*/
|
||||||
int csync_walk_remote_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter);
|
int csync_walk_remote_tree(CSYNC *ctx, csync_treewalk_visit_func *visitor, int filter);
|
||||||
|
|
||||||
@@ -519,19 +508,6 @@ const char *csync_get_status_string(CSYNC *ctx);
|
|||||||
int csync_set_iconv_codec(const char *from);
|
int csync_set_iconv_codec(const char *from);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set a property to module
|
|
||||||
*
|
|
||||||
* @param ctx The csync context.
|
|
||||||
*
|
|
||||||
* @param key The property key
|
|
||||||
*
|
|
||||||
* @param value An opaque pointer to the data.
|
|
||||||
*
|
|
||||||
* @return 0 on success, less than 0 if an error occured.
|
|
||||||
*/
|
|
||||||
int csync_set_module_property(CSYNC *ctx, const char *key, void *value);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Aborts the current sync run as soon as possible. Can be called from another thread.
|
* @brief Aborts the current sync run as soon as possible. Can be called from another thread.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -44,9 +44,60 @@
|
|||||||
static
|
static
|
||||||
#endif
|
#endif
|
||||||
int _csync_exclude_add(c_strlist_t **inList, const char *string) {
|
int _csync_exclude_add(c_strlist_t **inList, const char *string) {
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
// We never want duplicates, so check whether the string is already
|
||||||
|
// in the list first.
|
||||||
|
if (*inList) {
|
||||||
|
for (i = 0; i < (*inList)->count; ++i) {
|
||||||
|
char *pattern = (*inList)->vector[i];
|
||||||
|
if (c_streq(pattern, string)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return c_strlist_add_grow(inList, string);
|
return c_strlist_add_grow(inList, string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Expands C-like escape sequences.
|
||||||
|
*
|
||||||
|
* The returned string is heap-allocated and owned by the caller.
|
||||||
|
*/
|
||||||
|
static const char *csync_exclude_expand_escapes(const char * input)
|
||||||
|
{
|
||||||
|
size_t i_len = strlen(input) + 1;
|
||||||
|
char *out = c_malloc(i_len); // out can only be shorter
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
size_t o = 0;
|
||||||
|
for (; i < i_len; ++i) {
|
||||||
|
if (input[i] == '\\') {
|
||||||
|
// at worst input[i+1] is \0
|
||||||
|
switch (input[i+1]) {
|
||||||
|
case '\'': out[o++] = '\''; break;
|
||||||
|
case '"': out[o++] = '"'; break;
|
||||||
|
case '?': out[o++] = '?'; break;
|
||||||
|
case '\\': out[o++] = '\\'; break;
|
||||||
|
case 'a': out[o++] = '\a'; break;
|
||||||
|
case 'b': out[o++] = '\b'; break;
|
||||||
|
case 'f': out[o++] = '\f'; break;
|
||||||
|
case 'n': out[o++] = '\n'; break;
|
||||||
|
case 'r': out[o++] = '\r'; break;
|
||||||
|
case 't': out[o++] = '\t'; break;
|
||||||
|
case 'v': out[o++] = '\v'; break;
|
||||||
|
default:
|
||||||
|
out[o++] = input[i];
|
||||||
|
out[o++] = input[i+1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
} else {
|
||||||
|
out[o++] = input[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
int csync_exclude_load(const char *fname, c_strlist_t **list) {
|
int csync_exclude_load(const char *fname, c_strlist_t **list) {
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -99,8 +150,12 @@ int csync_exclude_load(const char *fname, c_strlist_t **list) {
|
|||||||
if (entry != buf + i) {
|
if (entry != buf + i) {
|
||||||
buf[i] = '\0';
|
buf[i] = '\0';
|
||||||
if (*entry != '#') {
|
if (*entry != '#') {
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Adding entry: %s", entry);
|
const char *unescaped = csync_exclude_expand_escapes(entry);
|
||||||
rc = _csync_exclude_add(list, entry);
|
rc = _csync_exclude_add(list, unescaped);
|
||||||
|
if( rc == 0 ) {
|
||||||
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Adding entry: %s", unescaped);
|
||||||
|
}
|
||||||
|
SAFE_FREE(unescaped);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -117,23 +172,6 @@ out:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void csync_exclude_clear(CSYNC *ctx) {
|
|
||||||
c_strlist_clear(ctx->excludes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void csync_exclude_destroy(CSYNC *ctx) {
|
|
||||||
c_strlist_destroy(ctx->excludes);
|
|
||||||
}
|
|
||||||
|
|
||||||
CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype) {
|
|
||||||
|
|
||||||
CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED;
|
|
||||||
|
|
||||||
match = csync_excluded_no_ctx( ctx->excludes, path, filetype );
|
|
||||||
|
|
||||||
return match;
|
|
||||||
}
|
|
||||||
|
|
||||||
// See http://support.microsoft.com/kb/74496 and
|
// See http://support.microsoft.com/kb/74496 and
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
|
||||||
// Additionally, we ignore '$Recycle.Bin', see https://github.com/owncloud/client/issues/2955
|
// Additionally, we ignore '$Recycle.Bin', see https://github.com/owncloud/client/issues/2955
|
||||||
@@ -171,7 +209,6 @@ bool csync_is_windows_reserved_word(const char* filename) {
|
|||||||
|
|
||||||
static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const char *path, int filetype, bool check_leading_dirs) {
|
static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const char *path, int filetype, bool check_leading_dirs) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
const char *p = NULL;
|
|
||||||
const char *bname = NULL;
|
const char *bname = NULL;
|
||||||
size_t blen = 0;
|
size_t blen = 0;
|
||||||
char *conflict = NULL;
|
char *conflict = NULL;
|
||||||
@@ -179,22 +216,6 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
|
|||||||
CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED;
|
CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED;
|
||||||
CSYNC_EXCLUDE_TYPE type = CSYNC_NOT_EXCLUDED;
|
CSYNC_EXCLUDE_TYPE type = CSYNC_NOT_EXCLUDED;
|
||||||
|
|
||||||
for (p = path; *p; p++) {
|
|
||||||
switch (*p) {
|
|
||||||
case '\\':
|
|
||||||
case ':':
|
|
||||||
case '?':
|
|
||||||
case '*':
|
|
||||||
case '"':
|
|
||||||
case '>':
|
|
||||||
case '<':
|
|
||||||
case '|':
|
|
||||||
return CSYNC_FILE_EXCLUDE_INVALID_CHAR;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* split up the path */
|
/* split up the path */
|
||||||
bname = strrchr(path, '/');
|
bname = strrchr(path, '/');
|
||||||
if (bname) {
|
if (bname) {
|
||||||
@@ -217,7 +238,7 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Windows cannot sync files ending in spaces (#2176). It also cannot
|
// Windows cannot sync files ending in spaces (#2176). It also cannot
|
||||||
// distinguish files ending in '.' from files without an ending,
|
// distinguish files ending in '.' from files without an ending,
|
||||||
// as '.' is a separator that is not stored internally, so let's
|
// as '.' is a separator that is not stored internally, so let's
|
||||||
@@ -231,7 +252,26 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
|
|||||||
match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
|
match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
// Filter out characters not allowed in a filename on windows
|
||||||
|
const char *p = NULL;
|
||||||
|
for (p = path; *p; p++) {
|
||||||
|
switch (*p) {
|
||||||
|
case '\\':
|
||||||
|
case ':':
|
||||||
|
case '?':
|
||||||
|
case '*':
|
||||||
|
case '"':
|
||||||
|
case '>':
|
||||||
|
case '<':
|
||||||
|
case '|':
|
||||||
|
match = CSYNC_FILE_EXCLUDE_INVALID_CHAR;
|
||||||
|
goto out;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
rc = csync_fnmatch(".owncloudsync.log*", bname, 0);
|
rc = csync_fnmatch(".owncloudsync.log*", bname, 0);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
@@ -264,40 +304,41 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build a list of path components to check. */
|
c_strlist_t *path_components = NULL;
|
||||||
c_strlist_t *path_components = c_strlist_new(32);
|
if (check_leading_dirs) {
|
||||||
char *path_split = strdup(path);
|
/* Build a list of path components to check. */
|
||||||
size_t len = strlen(path_split);
|
path_components = c_strlist_new(32);
|
||||||
for (i = len; ; --i) {
|
char *path_split = strdup(path);
|
||||||
// read backwards until a path separator is found
|
size_t len = strlen(path_split);
|
||||||
if (i != 0 && path_split[i-1] != '/') {
|
for (i = len; ; --i) {
|
||||||
continue;
|
// read backwards until a path separator is found
|
||||||
}
|
if (i != 0 && path_split[i-1] != '/') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// check 'basename', i.e. for "/foo/bar/fi" we'd check 'fi', 'bar', 'foo'
|
// check 'basename', i.e. for "/foo/bar/fi" we'd check 'fi', 'bar', 'foo'
|
||||||
if (path_split[i] != 0) {
|
if (path_split[i] != 0) {
|
||||||
c_strlist_add_grow(&path_components, path_split + i);
|
c_strlist_add_grow(&path_components, path_split + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == 0 || !check_leading_dirs) {
|
if (i == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check 'dirname', i.e. for "/foo/bar/fi" we'd check '/foo/bar', '/foo'
|
// check 'dirname', i.e. for "/foo/bar/fi" we'd check '/foo/bar', '/foo'
|
||||||
path_split[i-1] = '\0';
|
path_split[i-1] = '\0';
|
||||||
c_strlist_add_grow(&path_components, path_split);
|
c_strlist_add_grow(&path_components, path_split);
|
||||||
|
}
|
||||||
|
SAFE_FREE(path_split);
|
||||||
}
|
}
|
||||||
SAFE_FREE(path_split);
|
|
||||||
|
|
||||||
/* Loop over all exclude patterns and evaluate the given path */
|
/* Loop over all exclude patterns and evaluate the given path */
|
||||||
for (i = 0; match == CSYNC_NOT_EXCLUDED && i < excludes->count; i++) {
|
for (i = 0; match == CSYNC_NOT_EXCLUDED && i < excludes->count; i++) {
|
||||||
bool match_dirs_only = false;
|
bool match_dirs_only = false;
|
||||||
char *pattern_stored = c_strdup(excludes->vector[i]);
|
char *pattern = excludes->vector[i];
|
||||||
char* pattern = pattern_stored;
|
|
||||||
|
|
||||||
type = CSYNC_FILE_EXCLUDE_LIST;
|
type = CSYNC_FILE_EXCLUDE_LIST;
|
||||||
if (strlen(pattern) < 1) {
|
if (!pattern[0]) { /* empty pattern */
|
||||||
SAFE_FREE(pattern_stored);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Excludes starting with ']' means it can be cleanup */
|
/* Excludes starting with ']' means it can be cleanup */
|
||||||
@@ -309,6 +350,9 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
|
|||||||
}
|
}
|
||||||
/* Check if the pattern applies to pathes only. */
|
/* Check if the pattern applies to pathes only. */
|
||||||
if (pattern[strlen(pattern)-1] == '/') {
|
if (pattern[strlen(pattern)-1] == '/') {
|
||||||
|
if (!check_leading_dirs && filetype == CSYNC_FTW_TYPE_FILE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
match_dirs_only = true;
|
match_dirs_only = true;
|
||||||
pattern[strlen(pattern)-1] = '\0'; /* Cut off the slash */
|
pattern[strlen(pattern)-1] = '\0'; /* Cut off the slash */
|
||||||
}
|
}
|
||||||
@@ -326,7 +370,7 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* if still not excluded, check each component and leading directory of the path */
|
/* if still not excluded, check each component and leading directory of the path */
|
||||||
if (match == CSYNC_NOT_EXCLUDED) {
|
if (match == CSYNC_NOT_EXCLUDED && check_leading_dirs) {
|
||||||
size_t j = 0;
|
size_t j = 0;
|
||||||
if (match_dirs_only && filetype == CSYNC_FTW_TYPE_FILE) {
|
if (match_dirs_only && filetype == CSYNC_FTW_TYPE_FILE) {
|
||||||
j = 1; // skip the first entry, which is bname
|
j = 1; // skip the first entry, which is bname
|
||||||
@@ -338,8 +382,16 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (match == CSYNC_NOT_EXCLUDED && !check_leading_dirs) {
|
||||||
|
rc = csync_fnmatch(pattern, bname, 0);
|
||||||
|
if (rc == 0) {
|
||||||
|
match = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (match_dirs_only) {
|
||||||
|
/* restore the '/' */
|
||||||
|
pattern[strlen(pattern)] = '/';
|
||||||
}
|
}
|
||||||
SAFE_FREE(pattern_stored);
|
|
||||||
}
|
}
|
||||||
c_strlist_destroy(path_components);
|
c_strlist_destroy(path_components);
|
||||||
|
|
||||||
|
|||||||
@@ -43,41 +43,10 @@ int _csync_exclude_add(c_strlist_t **inList, const char *string);
|
|||||||
* @param ctx The context of the synchronizer.
|
* @param ctx The context of the synchronizer.
|
||||||
* @param fname The filename to load.
|
* @param fname The filename to load.
|
||||||
*
|
*
|
||||||
* @return 0 on success, -1 if an error occured with errno set.
|
* @return 0 on success, -1 if an error occurred with errno set.
|
||||||
*/
|
*/
|
||||||
int csync_exclude_load(const char *fname, c_strlist_t **list);
|
int csync_exclude_load(const char *fname, c_strlist_t **list);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Clear the exclude list in memory.
|
|
||||||
*
|
|
||||||
* @param ctx The synchronizer context.
|
|
||||||
*/
|
|
||||||
void csync_exclude_clear(CSYNC *ctx);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Destroy the exclude list in memory.
|
|
||||||
*
|
|
||||||
* @param ctx The synchronizer context.
|
|
||||||
*/
|
|
||||||
void csync_exclude_destroy(CSYNC *ctx);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Check if the given path should be excluded.
|
|
||||||
*
|
|
||||||
* This excludes also paths which can't be used without unix extensions.
|
|
||||||
*
|
|
||||||
* The exclude list is checked against the full path, each component of
|
|
||||||
* the path and all leading directory strings, e.g.
|
|
||||||
* '/foo/bar/file' checks ('/foo/bar/file', 'foo', 'bar', 'file',
|
|
||||||
* '/foo/bar', '/foo').
|
|
||||||
*
|
|
||||||
* @param ctx The synchronizer context.
|
|
||||||
* @param path The patch to check.
|
|
||||||
*
|
|
||||||
* @return 2 if excluded and needs cleanup, 1 if excluded, 0 if not.
|
|
||||||
*/
|
|
||||||
CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if the given path should be excluded in a traversal situation.
|
* @brief Check if the given path should be excluded in a traversal situation.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
#define ERRNO_SERVICE_UNAVAILABLE CSYNC_CUSTOM_ERRNO_BASE+14
|
#define ERRNO_SERVICE_UNAVAILABLE CSYNC_CUSTOM_ERRNO_BASE+14
|
||||||
#define ERRNO_USER_ABORT CSYNC_CUSTOM_ERRNO_BASE+16
|
#define ERRNO_USER_ABORT CSYNC_CUSTOM_ERRNO_BASE+16
|
||||||
#define ERRNO_STORAGE_UNAVAILABLE CSYNC_CUSTOM_ERRNO_BASE+17
|
#define ERRNO_STORAGE_UNAVAILABLE CSYNC_CUSTOM_ERRNO_BASE+17
|
||||||
|
#define ERRNO_FORBIDDEN CSYNC_CUSTOM_ERRNO_BASE+18
|
||||||
|
|
||||||
#endif /* _CSYNC_MACROS_H */
|
#endif /* _CSYNC_MACROS_H */
|
||||||
/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */
|
/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */
|
||||||
|
|||||||
@@ -57,20 +57,13 @@ int csync_fnmatch(__const char *__pattern, __const char *__name, int __flags) {
|
|||||||
#else /* HAVE_FNMATCH */
|
#else /* HAVE_FNMATCH */
|
||||||
|
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
int csync_fnmatch(__const char *__pattern, __const char *__name, int __flags) {
|
int csync_fnmatch(const char *pattern, const char *name, int flags) {
|
||||||
wchar_t *pat = NULL;
|
|
||||||
wchar_t *name = NULL;
|
|
||||||
BOOL match;
|
BOOL match;
|
||||||
|
|
||||||
(void) __flags;
|
(void) flags;
|
||||||
|
|
||||||
name = c_utf8_string_to_locale(__name);
|
match = PathMatchSpecA(name, pattern);
|
||||||
pat = c_utf8_string_to_locale(__pattern);
|
|
||||||
|
|
||||||
match = PathMatchSpecW(name, pat);
|
|
||||||
|
|
||||||
c_free_locale_string(pat);
|
|
||||||
c_free_locale_string(name);
|
|
||||||
if(match)
|
if(match)
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
* than fmmatch anyway, which does not care for flags.
|
* than fmmatch anyway, which does not care for flags.
|
||||||
**/
|
**/
|
||||||
#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
|
#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
|
||||||
|
#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int csync_fnmatch(__const char *__pattern, __const char *__name, int __flags);
|
int csync_fnmatch(__const char *__pattern, __const char *__name, int __flags);
|
||||||
|
|||||||
@@ -1,617 +0,0 @@
|
|||||||
/*
|
|
||||||
* libcsync -- a library to sync a directory with another
|
|
||||||
*
|
|
||||||
* Copyright (c) 2011 by Andreas Schneider <asn@cryptomilk.org>
|
|
||||||
* Copyright (c) 2012 by Klaas Freitag <freitag@owncloud.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "csync_owncloud.h"
|
|
||||||
#include "csync_owncloud_private.h"
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#include "csync_private.h"
|
|
||||||
|
|
||||||
#include "csync_version.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* helper method to build up a user text for SSL problems, called from the
|
|
||||||
* verify_sslcert callback.
|
|
||||||
*/
|
|
||||||
static void addSSLWarning( char *ptr, const char *warn, int len )
|
|
||||||
{
|
|
||||||
char *concatHere = ptr;
|
|
||||||
int remainingLen = 0;
|
|
||||||
|
|
||||||
if( ! (warn && ptr )) return;
|
|
||||||
remainingLen = len - strlen(ptr);
|
|
||||||
if( remainingLen <= 0 ) return;
|
|
||||||
concatHere = ptr + strlen(ptr); /* put the write pointer to the end. */
|
|
||||||
strncpy( concatHere, warn, remainingLen );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Callback to verify the SSL certificate, called from libneon.
|
|
||||||
* It analyzes the SSL problem, creates a user information text and passes
|
|
||||||
* it to the csync callback to ask the user.
|
|
||||||
*/
|
|
||||||
#define LEN 4096
|
|
||||||
static int ssl_callback_by_neon(void *userdata, int failures,
|
|
||||||
const ne_ssl_certificate *certificate)
|
|
||||||
{
|
|
||||||
char problem[LEN];
|
|
||||||
char buf[MAX(NE_SSL_DIGESTLEN, NE_ABUFSIZ)];
|
|
||||||
int ret = -1;
|
|
||||||
const ne_ssl_certificate *cert = certificate;
|
|
||||||
csync_auth_callback authcb = NULL;
|
|
||||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
|
||||||
|
|
||||||
memset( problem, 0, LEN );
|
|
||||||
|
|
||||||
while( cert ) {
|
|
||||||
|
|
||||||
addSSLWarning( problem, "There are problems with the SSL certificate:\n", LEN );
|
|
||||||
if( failures & NE_SSL_NOTYETVALID ) {
|
|
||||||
addSSLWarning( problem, " * The certificate is not yet valid.\n", LEN );
|
|
||||||
}
|
|
||||||
if( failures & NE_SSL_EXPIRED ) {
|
|
||||||
addSSLWarning( problem, " * The certificate has expired.\n", LEN );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( failures & NE_SSL_UNTRUSTED ) {
|
|
||||||
addSSLWarning( problem, " * The certificate is not trusted!\n", LEN );
|
|
||||||
}
|
|
||||||
if( failures & NE_SSL_IDMISMATCH ) {
|
|
||||||
addSSLWarning( problem, " * The hostname for which the certificate was "
|
|
||||||
"issued does not match the hostname of the server\n", LEN );
|
|
||||||
}
|
|
||||||
if( failures & NE_SSL_BADCHAIN ) {
|
|
||||||
addSSLWarning( problem, " * The certificate chain contained a certificate other than the server cert\n", LEN );
|
|
||||||
}
|
|
||||||
if( failures & NE_SSL_REVOKED ) {
|
|
||||||
addSSLWarning( problem, " * The server certificate has been revoked by the issuing authority.\n", LEN );
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ne_ssl_cert_digest(cert, buf) == 0) {
|
|
||||||
addSSLWarning( problem, "Certificate fingerprint: ", LEN );
|
|
||||||
addSSLWarning( problem, buf, LEN );
|
|
||||||
addSSLWarning( problem, "\n", LEN );
|
|
||||||
}
|
|
||||||
cert = ne_ssl_cert_signedby( cert );
|
|
||||||
}
|
|
||||||
addSSLWarning( problem, "Do you want to accept the certificate chain anyway?\nAnswer yes to do so and take the risk: ", LEN );
|
|
||||||
|
|
||||||
if( ctx->csync_ctx ) {
|
|
||||||
authcb = csync_get_auth_callback( ctx->csync_ctx );
|
|
||||||
}
|
|
||||||
if( authcb ){
|
|
||||||
/* call the csync callback */
|
|
||||||
DEBUG_WEBDAV("Call the csync callback for SSL problems");
|
|
||||||
memset( buf, 0, NE_ABUFSIZ );
|
|
||||||
(*authcb) ( problem, buf, NE_ABUFSIZ-1, 1, 0, csync_get_userdata(ctx->csync_ctx) );
|
|
||||||
if( buf[0] == 'y' || buf[0] == 'Y') {
|
|
||||||
ret = 0;
|
|
||||||
} else {
|
|
||||||
DEBUG_WEBDAV("Authentication callback replied %s", buf );
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DEBUG_WEBDAV("## VERIFY_SSL CERT: %d", ret );
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Authentication callback. Is set by ne_set_server_auth to be called
|
|
||||||
* from the neon lib to authenticate a request.
|
|
||||||
*/
|
|
||||||
static int authentication_callback_by_neon( void *userdata, const char *realm, int attempt,
|
|
||||||
char *username, char *password)
|
|
||||||
{
|
|
||||||
char buf[NE_ABUFSIZ];
|
|
||||||
csync_auth_callback authcb = NULL;
|
|
||||||
int re = attempt;
|
|
||||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
|
||||||
|
|
||||||
(void) realm;
|
|
||||||
|
|
||||||
/* DEBUG_WEBDAV( "Authentication required %s", realm ); */
|
|
||||||
if( username && password ) {
|
|
||||||
DEBUG_WEBDAV( "Authentication required %s", username );
|
|
||||||
if( ctx->dav_session.user ) {
|
|
||||||
/* allow user without password */
|
|
||||||
if( strlen( ctx->dav_session.user ) < NE_ABUFSIZ ) {
|
|
||||||
strcpy( username, ctx->dav_session.user );
|
|
||||||
}
|
|
||||||
if( ctx->dav_session.pwd && strlen( ctx->dav_session.pwd ) < NE_ABUFSIZ ) {
|
|
||||||
strcpy( password, ctx->dav_session.pwd );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
authcb = csync_get_auth_callback( ctx->csync_ctx );
|
|
||||||
if( authcb != NULL ){
|
|
||||||
/* call the csync callback */
|
|
||||||
DEBUG_WEBDAV("Call the csync callback for %s", realm );
|
|
||||||
memset( buf, 0, NE_ABUFSIZ );
|
|
||||||
(*authcb) ("Enter your username: ", buf, NE_ABUFSIZ-1, 1, 0, csync_get_userdata(ctx->csync_ctx) );
|
|
||||||
if( strlen(buf) < NE_ABUFSIZ ) {
|
|
||||||
strcpy( username, buf );
|
|
||||||
}
|
|
||||||
memset( buf, 0, NE_ABUFSIZ );
|
|
||||||
(*authcb) ("Enter your password: ", buf, NE_ABUFSIZ-1, 0, 0, csync_get_userdata(ctx->csync_ctx) );
|
|
||||||
if( strlen(buf) < NE_ABUFSIZ) {
|
|
||||||
strcpy( password, buf );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
re = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return re;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Authentication callback. Is set by ne_set_proxy_auth to be called
|
|
||||||
* from the neon lib to authenticate against a proxy. The data to authenticate
|
|
||||||
* against comes from mirall throught vio_module_init function.
|
|
||||||
*/
|
|
||||||
static int proxy_authentication_callback_by_neon( void *userdata, const char *realm, int attempt,
|
|
||||||
char *username, char *password)
|
|
||||||
{
|
|
||||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
|
||||||
(void) realm;
|
|
||||||
if( ctx->dav_session.proxy_user && strlen( ctx->dav_session.proxy_user ) < NE_ABUFSIZ) {
|
|
||||||
strcpy( username, ctx->dav_session.proxy_user );
|
|
||||||
if( ctx->dav_session.proxy_pwd && strlen( ctx->dav_session.proxy_pwd ) < NE_ABUFSIZ) {
|
|
||||||
strcpy( password, ctx->dav_session.proxy_pwd );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* NTLM needs several attempts */
|
|
||||||
return (attempt < 3) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Configure the proxy depending on the variables */
|
|
||||||
static int configureProxy( csync_owncloud_ctx_t *ctx, ne_session *session )
|
|
||||||
{
|
|
||||||
int port = 8080;
|
|
||||||
int re = -1;
|
|
||||||
|
|
||||||
if( ! session ) return -1;
|
|
||||||
if( ! ctx->dav_session.proxy_type ) return 0; /* Go by NoProxy per default */
|
|
||||||
|
|
||||||
if( ctx->dav_session.proxy_port > 0 ) {
|
|
||||||
port = ctx->dav_session.proxy_port;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( c_streq(ctx->dav_session.proxy_type, "NoProxy" )) {
|
|
||||||
DEBUG_WEBDAV("No proxy configured.");
|
|
||||||
re = 0;
|
|
||||||
} else if( c_streq(ctx->dav_session.proxy_type, "DefaultProxy") ||
|
|
||||||
c_streq(ctx->dav_session.proxy_type, "HttpProxy") ||
|
|
||||||
c_streq(ctx->dav_session.proxy_type, "HttpCachingProxy") ||
|
|
||||||
c_streq(ctx->dav_session.proxy_type, "Socks5Proxy")) {
|
|
||||||
|
|
||||||
if( ctx->dav_session.proxy_host ) {
|
|
||||||
DEBUG_WEBDAV("%s at %s:%d", ctx->dav_session.proxy_type, ctx->dav_session.proxy_host, port );
|
|
||||||
if (c_streq(ctx->dav_session.proxy_type, "Socks5Proxy")) {
|
|
||||||
ne_session_socks_proxy(session, NE_SOCK_SOCKSV5, ctx->dav_session.proxy_host, port,
|
|
||||||
ctx->dav_session.proxy_user, ctx->dav_session.proxy_pwd);
|
|
||||||
} else {
|
|
||||||
ne_session_proxy(session, ctx->dav_session.proxy_host, port );
|
|
||||||
}
|
|
||||||
re = 2;
|
|
||||||
} else {
|
|
||||||
DEBUG_WEBDAV("%s requested but no proxy host defined.", ctx->dav_session.proxy_type );
|
|
||||||
/* we used to try ne_system_session_proxy here, but we should rather err out
|
|
||||||
to behave exactly like the caller. */
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DEBUG_WEBDAV( "Unsupported Proxy: %s", ctx->dav_session.proxy_type );
|
|
||||||
}
|
|
||||||
|
|
||||||
return re;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This hook is called for with the response of a request. Here its checked
|
|
||||||
* if a Set-Cookie header is there for the PHPSESSID. The key is stored into
|
|
||||||
* the webdav session to be added to subsequent requests.
|
|
||||||
*/
|
|
||||||
static void post_request_hook(ne_request *req, void *userdata, const ne_status *status)
|
|
||||||
{
|
|
||||||
const char *set_cookie_header = NULL;
|
|
||||||
const char *sc = NULL;
|
|
||||||
char *key = NULL;
|
|
||||||
|
|
||||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
|
||||||
|
|
||||||
if (ctx->dav_session.session_key)
|
|
||||||
return; /* We already have a session cookie, and we should ignore other ones */
|
|
||||||
|
|
||||||
if(!(status && req)) return;
|
|
||||||
if( status->klass == 2 || status->code == 401 ) {
|
|
||||||
/* successful request */
|
|
||||||
set_cookie_header = ne_get_response_header( req, "Set-Cookie" );
|
|
||||||
if( set_cookie_header ) {
|
|
||||||
DEBUG_WEBDAV(" Set-Cookie found: %s", set_cookie_header);
|
|
||||||
/* try to find a ', ' sequence which is the separator of neon if multiple Set-Cookie
|
|
||||||
* headers are there.
|
|
||||||
* The following code parses a string like this:
|
|
||||||
* Set-Cookie: 50ace6bd8a669=p537brtt048jh8srlp2tuep7em95nh9u98mj992fbqc47d1aecp1;
|
|
||||||
*/
|
|
||||||
sc = set_cookie_header;
|
|
||||||
while(sc) {
|
|
||||||
const char *sc_val = sc;
|
|
||||||
const char *sc_end = sc_val;
|
|
||||||
int cnt = 0;
|
|
||||||
int len = strlen(sc_val); /* The length of the rest of the header string. */
|
|
||||||
|
|
||||||
while( cnt < len && *sc_end != ';' && *sc_end != ',') {
|
|
||||||
cnt++;
|
|
||||||
sc_end++;
|
|
||||||
}
|
|
||||||
if( cnt == len ) {
|
|
||||||
/* exit: We are at the end. */
|
|
||||||
sc = NULL;
|
|
||||||
} else if( *sc_end == ';' ) {
|
|
||||||
/* We are at the end of the session key. */
|
|
||||||
int keylen = sc_end-sc_val;
|
|
||||||
if( key ) {
|
|
||||||
int oldlen = strlen(key);
|
|
||||||
key = c_realloc(key, oldlen + 2 + keylen+1);
|
|
||||||
strcpy(key + oldlen, "; ");
|
|
||||||
strncpy(key + oldlen + 2, sc_val, keylen);
|
|
||||||
key[oldlen + 2 + keylen] = '\0';
|
|
||||||
} else {
|
|
||||||
key = c_malloc(keylen+1);
|
|
||||||
strncpy( key, sc_val, keylen );
|
|
||||||
key[keylen] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now search for a ',' to find a potential other header entry */
|
|
||||||
while(cnt < len && *sc_end != ',') {
|
|
||||||
cnt++;
|
|
||||||
sc_end++;
|
|
||||||
}
|
|
||||||
if( cnt < len )
|
|
||||||
sc = sc_end+2; /* mind the space after the comma */
|
|
||||||
else
|
|
||||||
sc = NULL;
|
|
||||||
} else if( *sc_end == ',' ) {
|
|
||||||
/* A new entry is to check. */
|
|
||||||
if( *(sc_end + 1) == ' ') {
|
|
||||||
sc = sc_end+2;
|
|
||||||
} else {
|
|
||||||
/* error condition */
|
|
||||||
sc = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DEBUG_WEBDAV("Request failed, don't take session header.");
|
|
||||||
}
|
|
||||||
if( key ) {
|
|
||||||
DEBUG_WEBDAV("----> Session-key: %s", key);
|
|
||||||
SAFE_FREE(ctx->dav_session.session_key);
|
|
||||||
ctx->dav_session.session_key = key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* this hook is called just after a request has been created, before its sent.
|
|
||||||
* Here it is used to set the proxy connection header if available.
|
|
||||||
*/
|
|
||||||
static void request_created_hook(ne_request *req, void *userdata,
|
|
||||||
const char *method, const char *requri)
|
|
||||||
{
|
|
||||||
// FIXME Can possibly be merged with pre_send_hook
|
|
||||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
|
|
||||||
(void) method;
|
|
||||||
(void) requri;
|
|
||||||
|
|
||||||
if( !req ) return;
|
|
||||||
|
|
||||||
if(ctx->dav_session.proxy_type) {
|
|
||||||
/* required for NTLM */
|
|
||||||
ne_add_request_header(req, "Proxy-Connection", "Keep-Alive");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* this hook is called just before a request has been sent.
|
|
||||||
* Here it is used to set the session cookie if available.
|
|
||||||
*/
|
|
||||||
static void pre_send_hook(ne_request *req, void *userdata,
|
|
||||||
ne_buffer *header)
|
|
||||||
{
|
|
||||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
|
|
||||||
|
|
||||||
if( !req ) return;
|
|
||||||
|
|
||||||
if(ctx->dav_session.session_key) {
|
|
||||||
ne_buffer_concat(header, "Cookie: ", ctx->dav_session.session_key, "\r\n", NULL);
|
|
||||||
} else {
|
|
||||||
DEBUG_WEBDAV("csync pre_send_hook We don't have a Auth Cookie (session_key), this is wrong!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int post_send_hook(ne_request *req, void *userdata,
|
|
||||||
const ne_status *status)
|
|
||||||
{
|
|
||||||
const char *location;
|
|
||||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t *) userdata;
|
|
||||||
(void) status;
|
|
||||||
|
|
||||||
location = ne_get_response_header(req, "Location");
|
|
||||||
|
|
||||||
if( !location ) return NE_OK;
|
|
||||||
|
|
||||||
if( ctx->dav_session.redir_callback ) {
|
|
||||||
if( ctx->dav_session.redir_callback( ctx->csync_ctx, location ) ) {
|
|
||||||
return NE_REDIRECT;
|
|
||||||
} else {
|
|
||||||
return NE_RETRY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NE_REDIRECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Connect to a DAV server
|
|
||||||
* This function sets the flag _connected if the connection is established
|
|
||||||
* and returns if the flag is set, so calling it frequently is save.
|
|
||||||
*/
|
|
||||||
int dav_connect(CSYNC *csyncCtx, const char *base_url) {
|
|
||||||
int useSSL = 0;
|
|
||||||
int rc;
|
|
||||||
char protocol[6] = {'\0'};
|
|
||||||
char uaBuf[256];
|
|
||||||
char *path = NULL;
|
|
||||||
char *scheme = NULL;
|
|
||||||
char *host = NULL;
|
|
||||||
unsigned int port = 0;
|
|
||||||
int proxystate = -1;
|
|
||||||
csync_owncloud_ctx_t *ctx = csyncCtx->owncloud_context;
|
|
||||||
struct csync_client_certs_s* clientCerts = csyncCtx->clientCerts;
|
|
||||||
|
|
||||||
if (ctx->_connected) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = c_parse_uri( base_url, &scheme,
|
|
||||||
&ctx->dav_session.user,
|
|
||||||
&ctx->dav_session.pwd,
|
|
||||||
&host, &port, &path );
|
|
||||||
if( rc < 0 ) {
|
|
||||||
DEBUG_WEBDAV("Failed to parse uri %s", base_url );
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_WEBDAV("* scheme %s", scheme );
|
|
||||||
DEBUG_WEBDAV("* host %s", host );
|
|
||||||
DEBUG_WEBDAV("* port %u", port );
|
|
||||||
DEBUG_WEBDAV("* path %s", path );
|
|
||||||
|
|
||||||
if( strcmp( scheme, "owncloud" ) == 0 || strcmp( scheme, "http" ) == 0 ) {
|
|
||||||
strcpy( protocol, "http");
|
|
||||||
} else if( strcmp( scheme, "ownclouds" ) == 0 || strcmp( scheme, "https") == 0 ) {
|
|
||||||
strcpy( protocol, "https");
|
|
||||||
useSSL = 1;
|
|
||||||
} else {
|
|
||||||
DEBUG_WEBDAV("Invalid scheme %s, go out here!", scheme );
|
|
||||||
rc = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_WEBDAV("* user %s", ctx->dav_session.user ? ctx->dav_session.user : "");
|
|
||||||
|
|
||||||
if (port == 0) {
|
|
||||||
port = ne_uri_defaultport(protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->dav_session.ctx = ne_session_create( protocol, host, port);
|
|
||||||
|
|
||||||
if (ctx->dav_session.ctx == NULL) {
|
|
||||||
DEBUG_WEBDAV("Session create with protocol %s failed", protocol );
|
|
||||||
rc = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx->dav_session.read_timeout != 0) {
|
|
||||||
ne_set_read_timeout(ctx->dav_session.ctx, ctx->dav_session.read_timeout);
|
|
||||||
DEBUG_WEBDAV("Timeout set to %u seconds", ctx->dav_session.read_timeout );
|
|
||||||
}
|
|
||||||
// Should never take more than some seconds, 30 is really a max.
|
|
||||||
ne_set_connect_timeout(ctx->dav_session.ctx, 30);
|
|
||||||
|
|
||||||
snprintf( uaBuf, sizeof(uaBuf), "Mozilla/5.0 (%s) mirall/%s (csyncoC)",
|
|
||||||
CSYNC_STRINGIFY( MIRALL_VERSION ), csync_owncloud_get_platform() );
|
|
||||||
ne_set_useragent( ctx->dav_session.ctx, uaBuf);
|
|
||||||
ne_set_server_auth(ctx->dav_session.ctx, authentication_callback_by_neon, ctx);
|
|
||||||
|
|
||||||
if( useSSL ) {
|
|
||||||
if (!ne_has_support(NE_FEATURE_SSL)) {
|
|
||||||
DEBUG_WEBDAV("Error: SSL is not enabled.");
|
|
||||||
rc = -1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(clientCerts != NULL) {
|
|
||||||
ne_ssl_client_cert *clicert;
|
|
||||||
|
|
||||||
DEBUG_WEBDAV("dav_connect: certificatePath and certificatePasswd are set, so we use it" );
|
|
||||||
DEBUG_WEBDAV(" with certificatePath: %s", clientCerts->certificatePath );
|
|
||||||
DEBUG_WEBDAV(" with certificatePasswd: %s", clientCerts->certificatePasswd );
|
|
||||||
clicert = ne_ssl_clicert_read ( clientCerts->certificatePath );
|
|
||||||
if ( clicert == NULL ) {
|
|
||||||
DEBUG_WEBDAV ( "Error read certificate : %s", ne_get_error ( ctx->dav_session.ctx ) );
|
|
||||||
} else {
|
|
||||||
if ( ne_ssl_clicert_encrypted ( clicert ) ) {
|
|
||||||
int rtn = ne_ssl_clicert_decrypt ( clicert, clientCerts->certificatePasswd );
|
|
||||||
if ( !rtn ) {
|
|
||||||
DEBUG_WEBDAV ( "Certificate was deciphered successfully." );
|
|
||||||
ne_ssl_set_clicert ( ctx->dav_session.ctx, clicert );
|
|
||||||
} else {
|
|
||||||
DEBUG_WEBDAV ( "Errors while deciphering certificate: %s", ne_get_error ( ctx->dav_session.ctx ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DEBUG_WEBDAV("dav_connect: error with csync_client_certs_s* clientCerts");
|
|
||||||
}
|
|
||||||
ne_ssl_trust_default_ca( ctx->dav_session.ctx );
|
|
||||||
ne_ssl_set_verify( ctx->dav_session.ctx, ssl_callback_by_neon, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hook called when a request is created. It sets the proxy connection header. */
|
|
||||||
ne_hook_create_request( ctx->dav_session.ctx, request_created_hook, ctx );
|
|
||||||
/* Hook called after response headers are read. It gets the Session ID. */
|
|
||||||
ne_hook_post_headers( ctx->dav_session.ctx, post_request_hook, ctx );
|
|
||||||
/* Hook called before a request is sent. It sets the cookies. */
|
|
||||||
ne_hook_pre_send( ctx->dav_session.ctx, pre_send_hook, ctx );
|
|
||||||
/* Hook called after request is dispatched. Used for handling possible redirections. */
|
|
||||||
ne_hook_post_send( ctx->dav_session.ctx, post_send_hook, ctx );
|
|
||||||
|
|
||||||
/* Proxy support */
|
|
||||||
proxystate = configureProxy( ctx, ctx->dav_session.ctx );
|
|
||||||
if( proxystate < 0 ) {
|
|
||||||
DEBUG_WEBDAV("Error: Proxy-Configuration failed.");
|
|
||||||
} else if( proxystate > 0 ) {
|
|
||||||
ne_set_proxy_auth( ctx->dav_session.ctx, proxy_authentication_callback_by_neon, ctx );
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->_connected = 1;
|
|
||||||
rc = 0;
|
|
||||||
out:
|
|
||||||
SAFE_FREE(path);
|
|
||||||
SAFE_FREE(host);
|
|
||||||
SAFE_FREE(scheme);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char *owncloud_error_string(CSYNC* ctx)
|
|
||||||
{
|
|
||||||
return ctx->owncloud_context->dav_session.error_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
int owncloud_commit(CSYNC* ctx) {
|
|
||||||
if (!ctx->owncloud_context) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ctx->owncloud_context->dav_session.ctx ) {
|
|
||||||
ne_forget_auth(ctx->owncloud_context->dav_session.ctx);
|
|
||||||
ne_session_destroy(ctx->owncloud_context->dav_session.ctx );
|
|
||||||
ctx->owncloud_context->dav_session.ctx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* DEBUG_WEBDAV( "********** vio_module_shutdown" ); */
|
|
||||||
|
|
||||||
ctx->owncloud_context->dav_session.ctx = 0;
|
|
||||||
|
|
||||||
// ne_sock_exit();
|
|
||||||
ctx->owncloud_context->_connected = 0; /* triggers dav_connect to go through the whole neon setup */
|
|
||||||
|
|
||||||
SAFE_FREE( ctx->owncloud_context->dav_session.user );
|
|
||||||
SAFE_FREE( ctx->owncloud_context->dav_session.pwd );
|
|
||||||
SAFE_FREE( ctx->owncloud_context->dav_session.session_key);
|
|
||||||
SAFE_FREE( ctx->owncloud_context->dav_session.error_string );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void owncloud_destroy(CSYNC* ctx)
|
|
||||||
{
|
|
||||||
owncloud_commit(ctx);
|
|
||||||
SAFE_FREE(ctx->owncloud_context);
|
|
||||||
|
|
||||||
if (ctx->clientCerts) {
|
|
||||||
SAFE_FREE(ctx->clientCerts->certificatePasswd);
|
|
||||||
SAFE_FREE(ctx->clientCerts->certificatePath);
|
|
||||||
SAFE_FREE(ctx->clientCerts);
|
|
||||||
}
|
|
||||||
ne_sock_exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
int owncloud_set_property(CSYNC* ctx, const char *key, void *data) {
|
|
||||||
#define READ_STRING_PROPERTY(P) \
|
|
||||||
if (c_streq(key, #P)) { \
|
|
||||||
SAFE_FREE(ctx->owncloud_context->dav_session.P); \
|
|
||||||
ctx->owncloud_context->dav_session.P = c_strdup((const char*)data); \
|
|
||||||
return 0; \
|
|
||||||
}
|
|
||||||
READ_STRING_PROPERTY(session_key)
|
|
||||||
READ_STRING_PROPERTY(proxy_type)
|
|
||||||
READ_STRING_PROPERTY(proxy_host)
|
|
||||||
READ_STRING_PROPERTY(proxy_user)
|
|
||||||
READ_STRING_PROPERTY(proxy_pwd)
|
|
||||||
#undef READ_STRING_PROPERTY
|
|
||||||
|
|
||||||
if (c_streq(key, "proxy_port")) {
|
|
||||||
ctx->owncloud_context->dav_session.proxy_port = *(int*)(data);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (c_streq(key, "read_timeout") || c_streq(key, "timeout")) {
|
|
||||||
ctx->owncloud_context->dav_session.read_timeout = *(int*)(data);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if( c_streq(key, "get_dav_session")) {
|
|
||||||
/* Give the ne_session to the caller */
|
|
||||||
*(ne_session**)data = ctx->owncloud_context->dav_session.ctx;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if( c_streq(key, "redirect_callback")) {
|
|
||||||
if (data) {
|
|
||||||
csync_owncloud_redirect_callback_t* cb_wrapper = data;
|
|
||||||
ctx->owncloud_context->dav_session.redir_callback = *cb_wrapper;
|
|
||||||
} else {
|
|
||||||
ctx->owncloud_context->dav_session.redir_callback = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( c_streq(key, "SSLClientCerts")) {
|
|
||||||
if(ctx->clientCerts != NULL) {
|
|
||||||
SAFE_FREE(ctx->clientCerts->certificatePasswd);
|
|
||||||
SAFE_FREE(ctx->clientCerts->certificatePath);
|
|
||||||
SAFE_FREE(ctx->clientCerts);
|
|
||||||
ctx->clientCerts = NULL;
|
|
||||||
}
|
|
||||||
if (data) {
|
|
||||||
struct csync_client_certs_s* clientCerts = (struct csync_client_certs_s*) data;
|
|
||||||
struct csync_client_certs_s* newCerts = c_malloc(sizeof(struct csync_client_certs_s));
|
|
||||||
newCerts->certificatePath = c_strdup(clientCerts->certificatePath);
|
|
||||||
newCerts->certificatePasswd = c_strdup(clientCerts->certificatePasswd);
|
|
||||||
ctx->clientCerts = newCerts;
|
|
||||||
} else {
|
|
||||||
DEBUG_WEBDAV("error: in owncloud_set_property for 'SSLClientCerts'" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void owncloud_init(CSYNC* ctx) {
|
|
||||||
|
|
||||||
ne_sock_init();
|
|
||||||
|
|
||||||
ctx->owncloud_context = c_malloc( sizeof( struct csync_owncloud_ctx_s ));
|
|
||||||
ctx->owncloud_context->csync_ctx = ctx; // back reference
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vim: set ts=4 sw=4 et cindent: */
|
|
||||||
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* libcsync -- a library to sync a directory with another
|
|
||||||
*
|
|
||||||
* Copyright (c) 2011 by Andreas Schneider <asn@cryptomilk.org>
|
|
||||||
* Copyright (c) 2012 by Klaas Freitag <freitag@owncloud.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
#ifndef CSYNC_OWNCLOUD_H
|
|
||||||
#define CSYNC_OWNCLOUD_H
|
|
||||||
|
|
||||||
#include "csync.h"
|
|
||||||
#include "vio/csync_vio.h"
|
|
||||||
|
|
||||||
// Public API used by csync
|
|
||||||
int owncloud_commit(CSYNC* ctx);
|
|
||||||
void owncloud_destroy(CSYNC* ctx);
|
|
||||||
char *owncloud_error_string(CSYNC* ctx);
|
|
||||||
int owncloud_set_property(CSYNC* ctx, const char *key, void *data);
|
|
||||||
void owncloud_init(CSYNC* ctx);
|
|
||||||
|
|
||||||
int dav_connect(CSYNC* ctx, const char *base_url);
|
|
||||||
|
|
||||||
#endif /* CSYNC_OWNCLOUD_H */
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
/*
|
|
||||||
* libcsync -- a library to sync a directory with another
|
|
||||||
*
|
|
||||||
* Copyright (c) 2011 by Andreas Schneider <asn@cryptomilk.org>
|
|
||||||
* Copyright (c) 2012 by Klaas Freitag <freitag@owncloud.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CSYNC_OWNCLOUD_PRIVATE_H
|
|
||||||
#define CSYNC_OWNCLOUD_PRIVATE_H
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#include "config_csync.h"
|
|
||||||
#ifdef NEON_WITH_LFS /* Switch on LFS in libneon. Never remove the NE_LFS! */
|
|
||||||
#define NE_LFS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <neon/ne_basic.h>
|
|
||||||
#include <neon/ne_socket.h>
|
|
||||||
#include <neon/ne_session.h>
|
|
||||||
#include <neon/ne_request.h>
|
|
||||||
#include <neon/ne_props.h>
|
|
||||||
#include <neon/ne_auth.h>
|
|
||||||
#include <neon/ne_dates.h>
|
|
||||||
#include <neon/ne_compress.h>
|
|
||||||
#include <neon/ne_redirect.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include "c_rbtree.h"
|
|
||||||
|
|
||||||
#include "c_lib.h"
|
|
||||||
#include "csync.h"
|
|
||||||
#include "csync_misc.h"
|
|
||||||
#include "csync_macros.h"
|
|
||||||
#include "c_private.h"
|
|
||||||
|
|
||||||
#include "vio/csync_vio.h"
|
|
||||||
|
|
||||||
#include "csync_log.h"
|
|
||||||
|
|
||||||
#include "csync_owncloud.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define DEBUG_WEBDAV(...) csync_log( 9, "oc_module", __VA_ARGS__);
|
|
||||||
|
|
||||||
typedef int (*csync_owncloud_redirect_callback_t)(CSYNC* ctx, const char* uri);
|
|
||||||
|
|
||||||
/* Struct with the WebDAV session */
|
|
||||||
struct dav_session_s {
|
|
||||||
ne_session *ctx;
|
|
||||||
char *user;
|
|
||||||
char *pwd;
|
|
||||||
|
|
||||||
char *proxy_type;
|
|
||||||
char *proxy_host;
|
|
||||||
int proxy_port;
|
|
||||||
char *proxy_user;
|
|
||||||
char *proxy_pwd;
|
|
||||||
|
|
||||||
char *session_key;
|
|
||||||
|
|
||||||
char *error_string;
|
|
||||||
|
|
||||||
int read_timeout;
|
|
||||||
|
|
||||||
csync_owncloud_redirect_callback_t redir_callback;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct csync_owncloud_ctx_s {
|
|
||||||
CSYNC *csync_ctx;
|
|
||||||
|
|
||||||
// For the WebDAV connection
|
|
||||||
struct dav_session_s dav_session; /* The DAV Session, initialised in dav_connect */
|
|
||||||
int _connected; /* flag to indicate if a connection exists, ie.
|
|
||||||
the dav_session is valid */
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct csync_owncloud_ctx_s csync_owncloud_ctx_t;
|
|
||||||
//typedef csync_owncloud_ctx_t* csync_owncloud_ctx_p;
|
|
||||||
|
|
||||||
void set_errno_from_http_errcode( int err );
|
|
||||||
void set_error_message( csync_owncloud_ctx_t *ctx, const char *msg );
|
|
||||||
void set_errno_from_neon_errcode(csync_owncloud_ctx_t *ctx, int neon_code );
|
|
||||||
int http_result_code_from_session(csync_owncloud_ctx_t *ctx);
|
|
||||||
void set_errno_from_session(csync_owncloud_ctx_t *ctx);
|
|
||||||
|
|
||||||
time_t oc_httpdate_parse( const char *date );
|
|
||||||
|
|
||||||
const char* csync_owncloud_get_platform(void);
|
|
||||||
|
|
||||||
char *_cleanPath( const char* uri );
|
|
||||||
|
|
||||||
#endif // CSYNC_OWNCLOUD_PRIVATE_H
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
/*
|
|
||||||
* libcsync -- a library to sync a directory with another
|
|
||||||
*
|
|
||||||
* Copyright (c) 2011 by Andreas Schneider <asn@cryptomilk.org>
|
|
||||||
* Copyright (c) 2012 by Klaas Freitag <freitag@owncloud.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "csync_owncloud.h"
|
|
||||||
#include "csync_owncloud_private.h"
|
|
||||||
|
|
||||||
#include "csync_misc.h"
|
|
||||||
|
|
||||||
void set_errno_from_http_errcode( int err ) {
|
|
||||||
int new_errno = 0;
|
|
||||||
|
|
||||||
switch(err) {
|
|
||||||
case 200: /* OK */
|
|
||||||
case 201: /* Created */
|
|
||||||
case 202: /* Accepted */
|
|
||||||
case 203: /* Non-Authoritative Information */
|
|
||||||
case 204: /* No Content */
|
|
||||||
case 205: /* Reset Content */
|
|
||||||
case 207: /* Multi-Status */
|
|
||||||
case 304: /* Not Modified */
|
|
||||||
new_errno = 0;
|
|
||||||
break;
|
|
||||||
case 401: /* Unauthorized */
|
|
||||||
case 402: /* Payment Required */
|
|
||||||
case 407: /* Proxy Authentication Required */
|
|
||||||
case 405:
|
|
||||||
new_errno = EPERM;
|
|
||||||
break;
|
|
||||||
case 301: /* Moved Permanently */
|
|
||||||
case 303: /* See Other */
|
|
||||||
case 404: /* Not Found */
|
|
||||||
case 410: /* Gone */
|
|
||||||
new_errno = ENOENT;
|
|
||||||
break;
|
|
||||||
case 408: /* Request Timeout */
|
|
||||||
case 504: /* Gateway Timeout */
|
|
||||||
new_errno = EAGAIN;
|
|
||||||
break;
|
|
||||||
case 423: /* Locked */
|
|
||||||
new_errno = EACCES;
|
|
||||||
break;
|
|
||||||
case 400: /* Bad Request */
|
|
||||||
case 403: /* Forbidden */
|
|
||||||
case 409: /* Conflict */
|
|
||||||
case 411: /* Length Required */
|
|
||||||
case 412: /* Precondition Failed */
|
|
||||||
case 414: /* Request-URI Too Long */
|
|
||||||
case 415: /* Unsupported Media Type */
|
|
||||||
case 424: /* Failed Dependency */
|
|
||||||
case 501: /* Not Implemented */
|
|
||||||
new_errno = EINVAL;
|
|
||||||
break;
|
|
||||||
case 507: /* Insufficient Storage */
|
|
||||||
new_errno = ENOSPC;
|
|
||||||
break;
|
|
||||||
case 206: /* Partial Content */
|
|
||||||
case 300: /* Multiple Choices */
|
|
||||||
case 302: /* Found */
|
|
||||||
case 305: /* Use Proxy */
|
|
||||||
case 306: /* (Unused) */
|
|
||||||
case 307: /* Temporary Redirect */
|
|
||||||
case 406: /* Not Acceptable */
|
|
||||||
case 416: /* Requested Range Not Satisfiable */
|
|
||||||
case 417: /* Expectation Failed */
|
|
||||||
case 422: /* Unprocessable Entity */
|
|
||||||
case 500: /* Internal Server Error */
|
|
||||||
case 502: /* Bad Gateway */
|
|
||||||
case 505: /* HTTP Version Not Supported */
|
|
||||||
new_errno = EIO;
|
|
||||||
break;
|
|
||||||
case 503: /* Service Unavailable */
|
|
||||||
new_errno = ERRNO_SERVICE_UNAVAILABLE;
|
|
||||||
break;
|
|
||||||
case 413: /* Request Entity too Large */
|
|
||||||
new_errno = EFBIG;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
new_errno = EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
errno = new_errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
// as per http://sourceforge.net/p/predef/wiki/OperatingSystems/
|
|
||||||
// extend as required
|
|
||||||
const char* csync_owncloud_get_platform() {
|
|
||||||
#if defined (_WIN32)
|
|
||||||
return "Windows";
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
return "Macintosh";
|
|
||||||
#elif defined(__gnu_linux__)
|
|
||||||
return "Linux";
|
|
||||||
#elif defined(__DragonFly__)
|
|
||||||
/* might also define __FreeBSD__ */
|
|
||||||
return "DragonFlyBSD";
|
|
||||||
#elif defined(__FreeBSD__)
|
|
||||||
return "FreeBSD";
|
|
||||||
#elif defined(__NetBSD__)
|
|
||||||
return "NetBSD";
|
|
||||||
#elif defined(__OpenBSD__)
|
|
||||||
return "OpenBSD";
|
|
||||||
#elif defined(sun) || defined(__sun)
|
|
||||||
return "Solaris";
|
|
||||||
#else
|
|
||||||
return "Unknown OS";
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
@@ -77,9 +77,6 @@ enum csync_replica_e {
|
|||||||
|
|
||||||
typedef struct csync_file_stat_s csync_file_stat_t;
|
typedef struct csync_file_stat_s csync_file_stat_t;
|
||||||
|
|
||||||
struct csync_owncloud_ctx_s; // csync_owncloud.c
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief csync public structure
|
* @brief csync public structure
|
||||||
*/
|
*/
|
||||||
@@ -99,6 +96,11 @@ struct csync_s {
|
|||||||
csync_vio_readdir_hook remote_readdir_hook;
|
csync_vio_readdir_hook remote_readdir_hook;
|
||||||
csync_vio_closedir_hook remote_closedir_hook;
|
csync_vio_closedir_hook remote_closedir_hook;
|
||||||
void *vio_userdata;
|
void *vio_userdata;
|
||||||
|
|
||||||
|
/* hook for comparing checksums of files during discovery */
|
||||||
|
csync_checksum_hook checksum_hook;
|
||||||
|
void *checksum_userdata;
|
||||||
|
|
||||||
} callbacks;
|
} callbacks;
|
||||||
c_strlist_t *excludes;
|
c_strlist_t *excludes;
|
||||||
|
|
||||||
@@ -169,9 +171,6 @@ struct csync_s {
|
|||||||
bool db_is_empty;
|
bool db_is_empty;
|
||||||
|
|
||||||
bool ignore_hidden_files;
|
bool ignore_hidden_files;
|
||||||
|
|
||||||
struct csync_owncloud_ctx_s *owncloud_context;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -193,11 +192,14 @@ struct csync_file_stat_s {
|
|||||||
|
|
||||||
char *destpath; /* for renames */
|
char *destpath; /* for renames */
|
||||||
const char *etag;
|
const char *etag;
|
||||||
char file_id[FILE_ID_BUF_SIZE+1]; /* the ownCloud file id is fixed width of 21 byte. */
|
char file_id[FILE_ID_BUF_SIZE+1]; /* the ownCloud file id is fixed width in ownCloud. */
|
||||||
char *directDownloadUrl;
|
char *directDownloadUrl;
|
||||||
char *directDownloadCookies;
|
char *directDownloadCookies;
|
||||||
char remotePerm[REMOTE_PERM_BUF_SIZE+1];
|
char remotePerm[REMOTE_PERM_BUF_SIZE+1];
|
||||||
|
|
||||||
|
const char *checksum;
|
||||||
|
uint32_t checksumTypeId;
|
||||||
|
|
||||||
CSYNC_STATUS error_status;
|
CSYNC_STATUS error_status;
|
||||||
|
|
||||||
enum csync_instructions_e instruction; /* u32 */
|
enum csync_instructions_e instruction; /* u32 */
|
||||||
|
|||||||
@@ -283,7 +283,13 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
|||||||
break;
|
break;
|
||||||
/* file on the other replica has not been modified */
|
/* file on the other replica has not been modified */
|
||||||
case CSYNC_INSTRUCTION_NONE:
|
case CSYNC_INSTRUCTION_NONE:
|
||||||
cur->instruction = CSYNC_INSTRUCTION_SYNC;
|
if (cur->type != other->type) {
|
||||||
|
// If the type of the entity changed, it's like NEW, but
|
||||||
|
// needs to delete the other entity first.
|
||||||
|
cur->instruction = CSYNC_INSTRUCTION_TYPE_CHANGE;
|
||||||
|
} else {
|
||||||
|
cur->instruction = CSYNC_INSTRUCTION_SYNC;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CSYNC_INSTRUCTION_IGNORE:
|
case CSYNC_INSTRUCTION_IGNORE:
|
||||||
cur->instruction = CSYNC_INSTRUCTION_IGNORE;
|
cur->instruction = CSYNC_INSTRUCTION_IGNORE;
|
||||||
|
|||||||
@@ -226,6 +226,8 @@ int csync_statedb_close(CSYNC *ctx) {
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define METADATA_COLUMNS "phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize, ignoredChildrenRemote, contentChecksum, contentChecksumTypeId"
|
||||||
|
|
||||||
// This funciton parses a line from the metadata table into the given csync_file_stat
|
// This funciton parses a line from the metadata table into the given csync_file_stat
|
||||||
// structure which it is also allocating.
|
// structure which it is also allocating.
|
||||||
// Note that this function calls laso sqlite3_step to actually get the info from db and
|
// Note that this function calls laso sqlite3_step to actually get the info from db and
|
||||||
@@ -286,6 +288,11 @@ static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3
|
|||||||
if(column_count > 13) {
|
if(column_count > 13) {
|
||||||
(*st)->has_ignored_files = sqlite3_column_int(stmt, 13);
|
(*st)->has_ignored_files = sqlite3_column_int(stmt, 13);
|
||||||
}
|
}
|
||||||
|
if(column_count > 15 && sqlite3_column_int(stmt, 15)) {
|
||||||
|
(*st)->checksum = c_strdup( (char*) sqlite3_column_text(stmt, 14));
|
||||||
|
(*st)->checksumTypeId = sqlite3_column_int(stmt, 15);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if( rc != SQLITE_DONE ) {
|
if( rc != SQLITE_DONE ) {
|
||||||
@@ -307,7 +314,7 @@ csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( ctx->statedb.by_hash_stmt == NULL ) {
|
if( ctx->statedb.by_hash_stmt == NULL ) {
|
||||||
const char *hash_query = "SELECT * FROM metadata WHERE phash=?1";
|
const char *hash_query = "SELECT " METADATA_COLUMNS " FROM metadata WHERE phash=?1";
|
||||||
|
|
||||||
SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, hash_query, strlen(hash_query), &ctx->statedb.by_hash_stmt, NULL));
|
SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, hash_query, strlen(hash_query), &ctx->statedb.by_hash_stmt, NULL));
|
||||||
ctx->statedb.lastReturnValue = rc;
|
ctx->statedb.lastReturnValue = rc;
|
||||||
@@ -350,7 +357,7 @@ csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( ctx->statedb.by_fileid_stmt == NULL ) {
|
if( ctx->statedb.by_fileid_stmt == NULL ) {
|
||||||
const char *query = "SELECT * FROM metadata WHERE fileid=?1";
|
const char *query = "SELECT " METADATA_COLUMNS " FROM metadata WHERE fileid=?1";
|
||||||
|
|
||||||
SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, query, strlen(query), &ctx->statedb.by_fileid_stmt, NULL));
|
SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, query, strlen(query), &ctx->statedb.by_fileid_stmt, NULL));
|
||||||
ctx->statedb.lastReturnValue = rc;
|
ctx->statedb.lastReturnValue = rc;
|
||||||
@@ -390,7 +397,7 @@ csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( ctx->statedb.by_inode_stmt == NULL ) {
|
if( ctx->statedb.by_inode_stmt == NULL ) {
|
||||||
const char *inode_query = "SELECT * FROM metadata WHERE inode=?1";
|
const char *inode_query = "SELECT " METADATA_COLUMNS " FROM metadata WHERE inode=?1";
|
||||||
|
|
||||||
SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, inode_query, strlen(inode_query), &ctx->statedb.by_inode_stmt, NULL));
|
SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, inode_query, strlen(inode_query), &ctx->statedb.by_inode_stmt, NULL));
|
||||||
ctx->statedb.lastReturnValue = rc;
|
ctx->statedb.lastReturnValue = rc;
|
||||||
@@ -416,37 +423,10 @@ csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx,
|
|||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the etag. */
|
|
||||||
char *csync_statedb_get_etag( CSYNC *ctx, uint64_t jHash ) {
|
|
||||||
char *ret = NULL;
|
|
||||||
csync_file_stat_t *fs = NULL;
|
|
||||||
|
|
||||||
if( !ctx ) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ! csync_get_statedb_exists(ctx)) return ret;
|
|
||||||
|
|
||||||
fs = csync_statedb_get_stat_by_hash(ctx, jHash );
|
|
||||||
if( fs ) {
|
|
||||||
if( fs->etag ) {
|
|
||||||
ret = c_strdup(fs->etag);
|
|
||||||
}
|
|
||||||
csync_file_stat_free(fs);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define BELOW_PATH_QUERY "SELECT phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize, ignoredChildrenRemote FROM metadata WHERE pathlen>? AND path LIKE(?)"
|
|
||||||
|
|
||||||
int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
||||||
int rc;
|
int rc;
|
||||||
sqlite3_stmt *stmt = NULL;
|
sqlite3_stmt *stmt = NULL;
|
||||||
int64_t cnt = 0;
|
int64_t cnt = 0;
|
||||||
char *likepath;
|
|
||||||
int asp;
|
|
||||||
int min_path_len;
|
|
||||||
|
|
||||||
if( !path ) {
|
if( !path ) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -456,7 +436,12 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, BELOW_PATH_QUERY, -1, &stmt, NULL));
|
/* Select the entries for anything that starts with (path+'/')
|
||||||
|
* In other words, anything that is between path+'/' and path+'0',
|
||||||
|
* (because '0' follows '/' in ascii)
|
||||||
|
*/
|
||||||
|
const char *below_path_query = "SELECT " METADATA_COLUMNS " FROM metadata WHERE path > (?||'/') AND path < (?||'0')";
|
||||||
|
SQLITE_BUSY_HANDLED(sqlite3_prepare_v2(ctx->statedb.db, below_path_query, -1, &stmt, NULL));
|
||||||
ctx->statedb.lastReturnValue = rc;
|
ctx->statedb.lastReturnValue = rc;
|
||||||
if( rc != SQLITE_OK ) {
|
if( rc != SQLITE_OK ) {
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for below path query.");
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for below path query.");
|
||||||
@@ -467,15 +452,8 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
asp = asprintf( &likepath, "%s/%%%%", path);
|
sqlite3_bind_text(stmt, 1, path, -1, SQLITE_STATIC);
|
||||||
if (asp < 0) {
|
sqlite3_bind_text(stmt, 2, path, -1, SQLITE_STATIC);
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
min_path_len = strlen(path);
|
|
||||||
sqlite3_bind_int(stmt, 1, min_path_len);
|
|
||||||
sqlite3_bind_text(stmt, 2, likepath, -1, SQLITE_STATIC);
|
|
||||||
|
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
|
|
||||||
@@ -494,7 +472,7 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
|||||||
|
|
||||||
if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE
|
if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE
|
||||||
|| excluded == CSYNC_FILE_SILENTLY_EXCLUDED) {
|
|| excluded == CSYNC_FILE_SILENTLY_EXCLUDED) {
|
||||||
SAFE_FREE(st);
|
csync_file_stat_free(st);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,7 +481,7 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
|||||||
|
|
||||||
/* store into result list. */
|
/* store into result list. */
|
||||||
if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) {
|
if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) {
|
||||||
SAFE_FREE(st);
|
csync_file_stat_free(st);
|
||||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -518,7 +496,6 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
|||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "%" PRId64 " entries read below path %s from db.", cnt, path);
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "%" PRId64 " entries read below path %s from db.", cnt, path);
|
||||||
}
|
}
|
||||||
sqlite3_finalize(stmt);
|
sqlite3_finalize(stmt);
|
||||||
SAFE_FREE(likepath);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ int csync_get_statedb_exists(CSYNC *ctx);
|
|||||||
* @param ctx The csync context.
|
* @param ctx The csync context.
|
||||||
* @param statedb Path to the statedb file (sqlite3 db).
|
* @param statedb Path to the statedb file (sqlite3 db).
|
||||||
*
|
*
|
||||||
* @return 0 on success, less than 0 if an error occured with errno set.
|
* @return 0 on success, less than 0 if an error occurred with errno set.
|
||||||
*/
|
*/
|
||||||
int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb);
|
int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb);
|
||||||
|
|
||||||
|
|||||||
@@ -106,6 +106,42 @@ static bool _last_db_return_error(CSYNC* ctx) {
|
|||||||
return ctx->statedb.lastReturnValue != SQLITE_OK && ctx->statedb.lastReturnValue != SQLITE_DONE && ctx->statedb.lastReturnValue != SQLITE_ROW;
|
return ctx->statedb.lastReturnValue != SQLITE_OK && ctx->statedb.lastReturnValue != SQLITE_DONE && ctx->statedb.lastReturnValue != SQLITE_ROW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This static method is needed because the type members of the two structs use
|
||||||
|
* different enum values. A direct comparion is not neccessarily correct.
|
||||||
|
*
|
||||||
|
* tmp is csync_file_stat_t
|
||||||
|
* fs is csync_vio_file_stat_t with this vio type:
|
||||||
|
* enum csync_vio_file_type_e {
|
||||||
|
* CSYNC_VIO_FILE_TYPE_UNKNOWN,
|
||||||
|
* CSYNC_VIO_FILE_TYPE_REGULAR,
|
||||||
|
* CSYNC_VIO_FILE_TYPE_DIRECTORY,
|
||||||
|
* CSYNC_VIO_FILE_TYPE_FIFO,
|
||||||
|
* CSYNC_VIO_FILE_TYPE_SOCKET,
|
||||||
|
* CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE,
|
||||||
|
* CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE,
|
||||||
|
* CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* csync_file_stat_t can be:
|
||||||
|
* CSYNC_FTW_TYPE_SKIP, CSYNC_FTW_TYPE_FILE
|
||||||
|
* CSYNC_FTW_TYPE_DIR, CSYNC_FTW_TYPE_SLINK
|
||||||
|
*/
|
||||||
|
static bool _csync_filetype_different( const csync_file_stat_t *tmp, const csync_vio_file_stat_t *fs)
|
||||||
|
{
|
||||||
|
if( !(tmp && fs)) return false;
|
||||||
|
|
||||||
|
if( tmp->type == CSYNC_FTW_TYPE_SKIP ) return true;
|
||||||
|
|
||||||
|
if( tmp->type == CSYNC_FTW_TYPE_DIR && fs->type != CSYNC_VIO_FILE_TYPE_DIRECTORY )
|
||||||
|
return true;
|
||||||
|
if( tmp->type == CSYNC_FTW_TYPE_FILE && fs->type != CSYNC_VIO_FILE_TYPE_REGULAR )
|
||||||
|
return true;
|
||||||
|
if( tmp->type == CSYNC_FTW_TYPE_SLINK && fs->type != CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false; // both are NOT different.
|
||||||
|
}
|
||||||
|
|
||||||
/* Return true if two mtime are considered equal
|
/* Return true if two mtime are considered equal
|
||||||
* We consider mtime that are one hour difference to be equal if they are one hour appart
|
* We consider mtime that are one hour difference to be equal if they are one hour appart
|
||||||
@@ -209,33 +245,9 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
|||||||
st->etag = NULL;
|
st->etag = NULL;
|
||||||
st->child_modified = 0;
|
st->child_modified = 0;
|
||||||
st->has_ignored_files = 0;
|
st->has_ignored_files = 0;
|
||||||
|
|
||||||
/* FIXME: Under which conditions are the following two ifs true and the code
|
|
||||||
* is executed? */
|
|
||||||
if (type == CSYNC_FTW_TYPE_FILE ) {
|
if (type == CSYNC_FTW_TYPE_FILE ) {
|
||||||
if (fs->mtime == 0) {
|
if (fs->mtime == 0) {
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - mtime is zero!", path);
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - mtime is zero!", path);
|
||||||
|
|
||||||
tmp = csync_statedb_get_stat_by_hash(ctx, h);
|
|
||||||
if(_last_db_return_error(ctx)) {
|
|
||||||
SAFE_FREE(st);
|
|
||||||
SAFE_FREE(tmp);
|
|
||||||
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tmp == NULL) {
|
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - not found in db, IGNORE!", path);
|
|
||||||
st->instruction = CSYNC_INSTRUCTION_IGNORE;
|
|
||||||
} else {
|
|
||||||
SAFE_FREE(st);
|
|
||||||
st = tmp;
|
|
||||||
st->instruction = CSYNC_INSTRUCTION_NONE;
|
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s - tmp non zero, mtime %lu", path, st->modtime );
|
|
||||||
tmp = NULL;
|
|
||||||
}
|
|
||||||
goto fastout; /* Skip copying of the etag. That's an important difference to upstream
|
|
||||||
* without etags. */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +269,8 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
|||||||
tmp = csync_statedb_get_stat_by_hash(ctx, h);
|
tmp = csync_statedb_get_stat_by_hash(ctx, h);
|
||||||
|
|
||||||
if(_last_db_return_error(ctx)) {
|
if(_last_db_return_error(ctx)) {
|
||||||
SAFE_FREE(st);
|
csync_file_stat_free(st);
|
||||||
|
csync_file_stat_free(tmp);
|
||||||
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -270,29 +283,48 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
|||||||
((int64_t) fs->mtime), ((int64_t) tmp->modtime),
|
((int64_t) fs->mtime), ((int64_t) tmp->modtime),
|
||||||
fs->etag, tmp->etag, (uint64_t) fs->inode, (uint64_t) tmp->inode,
|
fs->etag, tmp->etag, (uint64_t) fs->inode, (uint64_t) tmp->inode,
|
||||||
(uint64_t) fs->size, (uint64_t) tmp->size, fs->remotePerm, tmp->remotePerm, tmp->has_ignored_files );
|
(uint64_t) fs->size, (uint64_t) tmp->size, fs->remotePerm, tmp->remotePerm, tmp->has_ignored_files );
|
||||||
if( !fs->etag) {
|
if (ctx->current == REMOTE_REPLICA && !c_streq(fs->etag, tmp->etag)) {
|
||||||
st->instruction = CSYNC_INSTRUCTION_EVAL;
|
st->instruction = CSYNC_INSTRUCTION_EVAL;
|
||||||
|
|
||||||
|
// Preserve the EVAL flag later on if the type has changed.
|
||||||
|
if (_csync_filetype_different(tmp, fs)) {
|
||||||
|
st->child_modified = 1;
|
||||||
|
}
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if((ctx->current == REMOTE_REPLICA && !c_streq(fs->etag, tmp->etag ))
|
if (ctx->current == LOCAL_REPLICA &&
|
||||||
|| (ctx->current == LOCAL_REPLICA && (!_csync_mtime_equal(fs->mtime, tmp->modtime)
|
(!_csync_mtime_equal(fs->mtime, tmp->modtime)
|
||||||
// zero size in statedb can happen during migration
|
// zero size in statedb can happen during migration
|
||||||
|| (tmp->size != 0 && fs->size != tmp->size)
|
|| (tmp->size != 0 && fs->size != tmp->size))) {
|
||||||
#if 0
|
|
||||||
|| fs->inode != tmp->inode
|
// Checksum comparison at this stage is only enabled for .eml files,
|
||||||
#endif
|
// check #4754 #4755
|
||||||
))) {
|
bool isEmlFile = csync_fnmatch("*.eml", file, FNM_CASEFOLD) == 0;
|
||||||
/* Comparison of the local inode is disabled because people reported problems
|
if (isEmlFile && fs->size == tmp->size && tmp->checksumTypeId) {
|
||||||
* on windows with flacky inode values, see github bug #779
|
if (ctx->callbacks.checksum_hook) {
|
||||||
*
|
st->checksum = ctx->callbacks.checksum_hook(
|
||||||
* The inode needs to be observed because:
|
file, tmp->checksumTypeId,
|
||||||
* $> echo a > a.txt ; echo b > b.txt
|
ctx->callbacks.checksum_userdata);
|
||||||
* both files have the same mtime
|
}
|
||||||
* sync them.
|
bool checksumIdentical = false;
|
||||||
* $> rm a.txt && mv b.txt a.txt
|
if (st->checksum) {
|
||||||
* makes b.txt appearing as a.txt yet a sync is not performed because
|
st->checksumTypeId = tmp->checksumTypeId;
|
||||||
* both have the same modtime as mv does not change that.
|
checksumIdentical = strncmp(st->checksum, tmp->checksum, 1000) == 0;
|
||||||
*/
|
}
|
||||||
|
if (checksumIdentical) {
|
||||||
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "NOTE: Checksums are identical, file did not actually change: %s", path);
|
||||||
|
st->instruction = CSYNC_INSTRUCTION_NONE;
|
||||||
|
st->should_update_metadata = true;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preserve the EVAL flag later on if the type has changed.
|
||||||
|
if (_csync_filetype_different(tmp, fs)) {
|
||||||
|
st->child_modified = 1;
|
||||||
|
}
|
||||||
|
|
||||||
st->instruction = CSYNC_INSTRUCTION_EVAL;
|
st->instruction = CSYNC_INSTRUCTION_EVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -325,7 +357,7 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
|||||||
enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
|
enum csync_vio_file_type_e tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
|
||||||
|
|
||||||
/* tmp might point to malloc mem, so free it here before reusing tmp */
|
/* tmp might point to malloc mem, so free it here before reusing tmp */
|
||||||
SAFE_FREE(tmp);
|
csync_file_stat_free(tmp);
|
||||||
|
|
||||||
/* check if it's a file and has been renamed */
|
/* check if it's a file and has been renamed */
|
||||||
if (ctx->current == LOCAL_REPLICA) {
|
if (ctx->current == LOCAL_REPLICA) {
|
||||||
@@ -334,50 +366,68 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
|||||||
tmp = csync_statedb_get_stat_by_inode(ctx, fs->inode);
|
tmp = csync_statedb_get_stat_by_inode(ctx, fs->inode);
|
||||||
|
|
||||||
if(_last_db_return_error(ctx)) {
|
if(_last_db_return_error(ctx)) {
|
||||||
SAFE_FREE(st);
|
csync_file_stat_free(st);
|
||||||
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* translate the file type between the two stat types csync has. */
|
/* translate the file type between the two stat types csync has. */
|
||||||
if( tmp && tmp->type == 0 ) {
|
if( tmp && tmp->type == CSYNC_FTW_TYPE_FILE ) {
|
||||||
tmp_vio_type = CSYNC_VIO_FILE_TYPE_REGULAR;
|
tmp_vio_type = CSYNC_VIO_FILE_TYPE_REGULAR;
|
||||||
} else if( tmp && tmp->type == 2 ) {
|
} else if( tmp && tmp->type == CSYNC_FTW_TYPE_DIR) {
|
||||||
tmp_vio_type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
|
tmp_vio_type = CSYNC_VIO_FILE_TYPE_DIRECTORY;
|
||||||
|
} else if( tmp && tmp->type == CSYNC_FTW_TYPE_SLINK ) {
|
||||||
|
tmp_vio_type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK;
|
||||||
} else {
|
} else {
|
||||||
tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
|
tmp_vio_type = CSYNC_VIO_FILE_TYPE_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmp && tmp->inode == fs->inode && tmp_vio_type == fs->type
|
// Default to NEW unless we're sure it's a rename.
|
||||||
|
st->instruction = CSYNC_INSTRUCTION_NEW;
|
||||||
|
|
||||||
|
bool isRename =
|
||||||
|
tmp && tmp->inode == fs->inode && tmp_vio_type == fs->type
|
||||||
&& (tmp->modtime == fs->mtime || fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY)
|
&& (tmp->modtime == fs->mtime || fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY)
|
||||||
#ifdef NO_RENAME_EXTENSION
|
#ifdef NO_RENAME_EXTENSION
|
||||||
&& _csync_sameextension(tmp->path, path)
|
&& _csync_sameextension(tmp->path, path)
|
||||||
#endif
|
#endif
|
||||||
) {
|
;
|
||||||
|
|
||||||
|
|
||||||
|
// Verify the checksum where possible
|
||||||
|
if (isRename && tmp->checksumTypeId && ctx->callbacks.checksum_hook
|
||||||
|
&& fs->type == CSYNC_VIO_FILE_TYPE_REGULAR) {
|
||||||
|
st->checksum = ctx->callbacks.checksum_hook(
|
||||||
|
file, tmp->checksumTypeId,
|
||||||
|
ctx->callbacks.checksum_userdata);
|
||||||
|
if (st->checksum) {
|
||||||
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "checking checksum of potential rename %s %s <-> %s", path, st->checksum, tmp->checksum);
|
||||||
|
st->checksumTypeId = tmp->checksumTypeId;
|
||||||
|
isRename = strncmp(st->checksum, tmp->checksum, 1000) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRename) {
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "pot rename detected based on inode # %" PRId64 "", (uint64_t) fs->inode);
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "pot rename detected based on inode # %" PRId64 "", (uint64_t) fs->inode);
|
||||||
/* inode found so the file has been renamed */
|
/* inode found so the file has been renamed */
|
||||||
st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
|
st->instruction = CSYNC_INSTRUCTION_EVAL_RENAME;
|
||||||
if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
|
if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY) {
|
||||||
csync_rename_record(ctx, tmp->path, path);
|
csync_rename_record(ctx, tmp->path, path);
|
||||||
}
|
}
|
||||||
goto out;
|
|
||||||
} else {
|
|
||||||
/* file not found in statedb */
|
|
||||||
st->instruction = CSYNC_INSTRUCTION_NEW;
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
goto out;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* Remote Replica Rename check */
|
/* Remote Replica Rename check */
|
||||||
tmp = csync_statedb_get_stat_by_file_id(ctx, fs->file_id);
|
tmp = csync_statedb_get_stat_by_file_id(ctx, fs->file_id);
|
||||||
|
|
||||||
if(_last_db_return_error(ctx)) {
|
if(_last_db_return_error(ctx)) {
|
||||||
SAFE_FREE(st);
|
csync_file_stat_free(st);
|
||||||
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(tmp ) { /* tmp existing at all */
|
if(tmp ) { /* tmp existing at all */
|
||||||
if ((tmp->type == CSYNC_FTW_TYPE_DIR && fs->type != CSYNC_VIO_FILE_TYPE_DIRECTORY) ||
|
if ( _csync_filetype_different(tmp, fs)) {
|
||||||
(tmp->type == CSYNC_FTW_TYPE_FILE && fs->type != CSYNC_VIO_FILE_TYPE_REGULAR)) {
|
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "WARN: file types different is not!");
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "WARN: file types different is not!");
|
||||||
st->instruction = CSYNC_INSTRUCTION_NEW;
|
st->instruction = CSYNC_INSTRUCTION_NEW;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -401,7 +451,7 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
|||||||
|
|
||||||
if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY && ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncNewFolderHook) {
|
if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY && ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncNewFolderHook) {
|
||||||
if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path)) {
|
if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path)) {
|
||||||
SAFE_FREE(st);
|
csync_file_stat_free(st);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -411,7 +461,7 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Unable to open statedb" );
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Unable to open statedb" );
|
||||||
SAFE_FREE(st);
|
csync_file_stat_free(st);
|
||||||
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -466,7 +516,6 @@ out:
|
|||||||
strncpy(st->remotePerm, fs->remotePerm, REMOTE_PERM_BUF_SIZE);
|
strncpy(st->remotePerm, fs->remotePerm, REMOTE_PERM_BUF_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
fastout: /* target if the file information is read from database into st */
|
|
||||||
st->phash = h;
|
st->phash = h;
|
||||||
st->pathlen = len;
|
st->pathlen = len;
|
||||||
memcpy(st->path, (len ? path : ""), len + 1);
|
memcpy(st->path, (len ? path : ""), len + 1);
|
||||||
@@ -474,14 +523,14 @@ fastout: /* target if the file information is read from database into st */
|
|||||||
switch (ctx->current) {
|
switch (ctx->current) {
|
||||||
case LOCAL_REPLICA:
|
case LOCAL_REPLICA:
|
||||||
if (c_rbtree_insert(ctx->local.tree, (void *) st) < 0) {
|
if (c_rbtree_insert(ctx->local.tree, (void *) st) < 0) {
|
||||||
SAFE_FREE(st);
|
csync_file_stat_free(st);
|
||||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case REMOTE_REPLICA:
|
case REMOTE_REPLICA:
|
||||||
if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) {
|
if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) {
|
||||||
SAFE_FREE(st);
|
csync_file_stat_free(st);
|
||||||
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -511,7 +560,11 @@ int csync_walker(CSYNC *ctx, const char *file, const csync_vio_file_stat_t *fs,
|
|||||||
switch (flag) {
|
switch (flag) {
|
||||||
case CSYNC_FTW_FLAG_FILE:
|
case CSYNC_FTW_FLAG_FILE:
|
||||||
if (ctx->current == REMOTE_REPLICA) {
|
if (ctx->current == REMOTE_REPLICA) {
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=%" PRIu64 "]", file, fs->file_id, fs->size);
|
if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_SIZE) {
|
||||||
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=%" PRIu64 "]", file, fs->file_id, fs->size);
|
||||||
|
} else {
|
||||||
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [file_id=%s size=UNKNOWN]", file, fs->file_id);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [inode=%" PRIu64 " size=%" PRIu64 "]", file, fs->inode, fs->size);
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "file: %s [inode=%" PRIu64 " size=%" PRIu64 "]", file, fs->inode, fs->size);
|
||||||
}
|
}
|
||||||
@@ -577,6 +630,26 @@ static bool fill_tree_from_db(CSYNC *ctx, const char *uri)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set the current item to an ignored state.
|
||||||
|
* If the item is set to ignored, the update phase continues, ie. its not a hard error */
|
||||||
|
static bool mark_current_item_ignored( CSYNC *ctx, csync_file_stat_t *previous_fs, CSYNC_STATUS status )
|
||||||
|
{
|
||||||
|
if(!ctx) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->current_fs) {
|
||||||
|
ctx->current_fs->instruction = CSYNC_INSTRUCTION_IGNORE;
|
||||||
|
ctx->current_fs->error_status = status;
|
||||||
|
/* If a directory has ignored files, put the flag on the parent directory as well */
|
||||||
|
if( previous_fs ) {
|
||||||
|
previous_fs->has_ignored_files = true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* File tree walker */
|
/* File tree walker */
|
||||||
int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||||
unsigned int depth) {
|
unsigned int depth) {
|
||||||
@@ -584,7 +657,6 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
|||||||
char *d_name = NULL;
|
char *d_name = NULL;
|
||||||
csync_vio_handle_t *dh = NULL;
|
csync_vio_handle_t *dh = NULL;
|
||||||
csync_vio_file_stat_t *dirent = NULL;
|
csync_vio_file_stat_t *dirent = NULL;
|
||||||
csync_vio_file_stat_t *fs = NULL;
|
|
||||||
csync_file_stat_t *previous_fs = NULL;
|
csync_file_stat_t *previous_fs = NULL;
|
||||||
int read_from_db = 0;
|
int read_from_db = 0;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
@@ -630,13 +702,8 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
|||||||
/* permission denied */
|
/* permission denied */
|
||||||
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_OPENDIR_ERROR);
|
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_OPENDIR_ERROR);
|
||||||
if (errno == EACCES) {
|
if (errno == EACCES) {
|
||||||
if (ctx->current_fs) {
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Permission denied.");
|
||||||
ctx->current_fs->instruction = CSYNC_INSTRUCTION_IGNORE;
|
if (mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_PERMISSION_DENIED)) {
|
||||||
ctx->current_fs->error_status = CSYNC_STATUS_PERMISSION_DENIED;
|
|
||||||
/* If a directory has ignored files, put the flag on the parent directory as well */
|
|
||||||
if( previous_fs ) {
|
|
||||||
previous_fs->has_ignored_files = true;
|
|
||||||
}
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
} else if(errno == ENOENT) {
|
} else if(errno == ENOENT) {
|
||||||
@@ -645,19 +712,22 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
|||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!");
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 403 Forbidden can be sent by the server if the file firewall is active.
|
||||||
|
// A file or directory should be ignored and sync must continue. See #3490
|
||||||
|
else if(errno == ERRNO_FORBIDDEN) {
|
||||||
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Directory access Forbidden (File Firewall?)");
|
||||||
|
if( mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_FORBIDDEN) ) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* if current_fs is not defined here, better throw an error */
|
||||||
|
}
|
||||||
// The server usually replies with the custom "503 Storage not available"
|
// The server usually replies with the custom "503 Storage not available"
|
||||||
// if some path is temporarily unavailable. But in some cases a standard 503
|
// if some path is temporarily unavailable. But in some cases a standard 503
|
||||||
// is returned too. Thus we can't distinguish the two and will treat any
|
// is returned too. Thus we can't distinguish the two and will treat any
|
||||||
// 503 as request to ignore the folder. See #3113 #2884.
|
// 503 as request to ignore the folder. See #3113 #2884.
|
||||||
else if(errno == ERRNO_STORAGE_UNAVAILABLE || errno == ERRNO_SERVICE_UNAVAILABLE) {
|
else if(errno == ERRNO_STORAGE_UNAVAILABLE || errno == ERRNO_SERVICE_UNAVAILABLE) {
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Storage was not available!");
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Storage was not available!");
|
||||||
if (ctx->current_fs) {
|
if( mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_STORAGE_UNAVAILABLE ) ) {
|
||||||
ctx->current_fs->instruction = CSYNC_INSTRUCTION_IGNORE;
|
|
||||||
ctx->current_fs->error_status = CSYNC_STATUS_STORAGE_UNAVAILABLE;
|
|
||||||
/* If a directory has ignored files, put the flag on the parent directory as well */
|
|
||||||
if( previous_fs ) {
|
|
||||||
previous_fs->has_ignored_files = true;
|
|
||||||
}
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* if current_fs is not defined here, better throw an error */
|
/* if current_fs is not defined here, better throw an error */
|
||||||
@@ -688,8 +758,8 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* skip "." and ".." */
|
/* skip "." and ".." */
|
||||||
if (d_name[0] == '.' && (d_name[1] == '\0'
|
if ( (d_name[0] == '.' && d_name[1] == '\0')
|
||||||
|| (d_name[1] == '.' && d_name[2] == '\0'))) {
|
|| (d_name[0] == '.' && d_name[1] == '.' && d_name[2] == '\0')) {
|
||||||
csync_vio_file_stat_destroy(dirent);
|
csync_vio_file_stat_destroy(dirent);
|
||||||
dirent = NULL;
|
dirent = NULL;
|
||||||
continue;
|
continue;
|
||||||
@@ -741,15 +811,23 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
|||||||
|
|
||||||
/* Only for the local replica we have to stat(), for the remote one we have all data already */
|
/* Only for the local replica we have to stat(), for the remote one we have all data already */
|
||||||
if (ctx->replica == LOCAL_REPLICA) {
|
if (ctx->replica == LOCAL_REPLICA) {
|
||||||
fs = csync_vio_file_stat_new();
|
res = csync_vio_stat(ctx, filename, dirent);
|
||||||
res = csync_vio_stat(ctx, filename, fs);
|
|
||||||
} else {
|
} else {
|
||||||
fs = dirent;
|
|
||||||
res = 0;
|
res = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* if the filename starts with a . we consider it a hidden file
|
||||||
|
* For windows, the hidden state is also discovered within the vio
|
||||||
|
* local stat function.
|
||||||
|
*/
|
||||||
|
if( d_name[0] == '.' ) {
|
||||||
|
if (strcmp(".sys.admin#recall#", d_name) != 0) { /* recall file shall not be ignored (#4420) */
|
||||||
|
dirent->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( res == 0) {
|
if( res == 0) {
|
||||||
switch (fs->type) {
|
switch (dirent->type) {
|
||||||
case CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK:
|
case CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK:
|
||||||
flag = CSYNC_FTW_FLAG_SLINK;
|
flag = CSYNC_FTW_FLAG_SLINK;
|
||||||
break;
|
break;
|
||||||
@@ -772,42 +850,12 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
|||||||
flag = CSYNC_FTW_FLAG_NSTAT;
|
flag = CSYNC_FTW_FLAG_NSTAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ctx->current == LOCAL_REPLICA ) {
|
|
||||||
char *etag = NULL;
|
|
||||||
int len = strlen( path );
|
|
||||||
uint64_t h = c_jhash64((uint8_t *) path, len, 0);
|
|
||||||
etag = csync_statedb_get_etag( ctx, h );
|
|
||||||
|
|
||||||
if(_last_db_return_error(ctx)) {
|
|
||||||
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
|
||||||
SAFE_FREE(etag);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( etag ) {
|
|
||||||
SAFE_FREE(fs->etag);
|
|
||||||
fs->etag = etag;
|
|
||||||
fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG;
|
|
||||||
|
|
||||||
if( c_streq(etag, "")) {
|
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Uniq ID from Database is EMPTY: %s", path);
|
|
||||||
} else {
|
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Uniq ID from Database: %s -> %s", path, fs->etag ? fs->etag : "<NULL>" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
previous_fs = ctx->current_fs;
|
previous_fs = ctx->current_fs;
|
||||||
|
|
||||||
/* Call walker function for each file */
|
/* Call walker function for each file */
|
||||||
rc = fn(ctx, filename, fs, flag);
|
rc = fn(ctx, filename, dirent, flag);
|
||||||
/* this function may update ctx->current and ctx->read_from_db */
|
/* this function may update ctx->current and ctx->read_from_db */
|
||||||
|
|
||||||
/* Only for the local replica we have to destroy stat(), for the remote one it is a pointer to dirent */
|
|
||||||
if (ctx->replica == LOCAL_REPLICA) {
|
|
||||||
csync_vio_file_stat_destroy(fs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
if (CSYNC_STATUS_IS_OK(ctx->status_code)) {
|
if (CSYNC_STATUS_IS_OK(ctx->status_code)) {
|
||||||
ctx->status_code = CSYNC_STATUS_UPDATE_ERROR;
|
ctx->status_code = CSYNC_STATUS_UPDATE_ERROR;
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ static const _instr_code_struct _instr[] =
|
|||||||
{ "INSTRUCTION_SYNC", CSYNC_INSTRUCTION_SYNC },
|
{ "INSTRUCTION_SYNC", CSYNC_INSTRUCTION_SYNC },
|
||||||
{ "INSTRUCTION_STAT_ERR", CSYNC_INSTRUCTION_STAT_ERROR },
|
{ "INSTRUCTION_STAT_ERR", CSYNC_INSTRUCTION_STAT_ERROR },
|
||||||
{ "INSTRUCTION_ERROR", CSYNC_INSTRUCTION_ERROR },
|
{ "INSTRUCTION_ERROR", CSYNC_INSTRUCTION_ERROR },
|
||||||
|
{ "INSTRUCTION_TYPE_CHANGE", CSYNC_INSTRUCTION_TYPE_CHANGE },
|
||||||
{ NULL, CSYNC_INSTRUCTION_ERROR }
|
{ NULL, CSYNC_INSTRUCTION_ERROR }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
project(httpbflib C)
|
|
||||||
|
|
||||||
find_package(Neon)
|
|
||||||
|
|
||||||
|
|
||||||
set(HTTPBF_PUBLIC_INCLUDE_DIRS
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
|
||||||
${NEON_INCLUDE_DIRS}
|
|
||||||
CACHE INTERNAL "httpbflib public include directories"
|
|
||||||
)
|
|
||||||
|
|
||||||
set(HTTPBF_LIBRARY
|
|
||||||
httpbf
|
|
||||||
CACHE INTERNAL "httpbf library"
|
|
||||||
)
|
|
||||||
|
|
||||||
set(HTTPBF_LINK_LIBRARIES
|
|
||||||
${HTTPBF_LIBRARY}
|
|
||||||
)
|
|
||||||
|
|
||||||
set(httpbf_SRCS
|
|
||||||
src/httpbf.c
|
|
||||||
)
|
|
||||||
set(httpbf_HEADERS
|
|
||||||
src/httpbf.h
|
|
||||||
)
|
|
||||||
|
|
||||||
include_directories(
|
|
||||||
${HTTPBF_PUBLIC_INCLUDE_DIRS}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library(${HTTPBF_LIBRARY} STATIC ${httpbf_SRCS})
|
|
||||||
target_link_libraries(${HTTPBF_LIBRARY} ${NEON_LIBRARIES})
|
|
||||||
|
|
||||||
if(NOT WIN32)
|
|
||||||
add_definitions( -fPIC )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
INSTALL(
|
|
||||||
TARGETS
|
|
||||||
${HTTPBF_LIBRARY}
|
|
||||||
LIBRARY DESTINATION
|
|
||||||
${LIB_INSTALL_DIR}
|
|
||||||
ARCHIVE DESTINATION
|
|
||||||
${LIB_INSTALL_DIR}
|
|
||||||
RUNTIME DESTINATION
|
|
||||||
${BIN_INSTALL_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (NOT APPLE)
|
|
||||||
INSTALL(
|
|
||||||
FILES
|
|
||||||
${httpbf_HEADERS}
|
|
||||||
DESTINATION
|
|
||||||
${CMAKE_INSTALL_INCLUDEDIR}
|
|
||||||
)
|
|
||||||
endif (NOT APPLE)
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user