Comparar commits
314 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 7e63849fcb | |||
| de53732629 | |||
| dc3accacfc | |||
| 1b9c49e8f5 | |||
| ed15842eb9 | |||
| c24c3d559d | |||
| 6dcd79ded6 | |||
| 0905bcdaea | |||
| d6fdda8efa | |||
| faedaa5e09 | |||
| 661c7f0558 | |||
| a7efe144fc | |||
| b68a28de8d | |||
| 72a7b7ca42 | |||
| 166ef85a51 | |||
| 1f60c61f87 | |||
| 30ef794fa1 | |||
| 47fbfbc006 | |||
| e131c142ff | |||
| 1b99ff2e91 | |||
| 3e85d47a57 | |||
| e709d75d56 | |||
| cb5cfb8cf6 | |||
| ebd2a15711 | |||
| d3a0608bd5 | |||
| c25b599bbb | |||
| a5ff9e58e3 | |||
| 9b96899d75 | |||
| b046cca010 | |||
| edf0a99a8a | |||
| a4640b202f | |||
| 5ef2e88f00 | |||
| 352f168313 | |||
| 85d3de1589 | |||
| 588a88fb63 | |||
| cd9e88ad22 | |||
| 29b39acfbe | |||
| 7427be0062 | |||
| e7546903cc | |||
| 78e3a7e897 | |||
| 1a21b8698e | |||
| 280906eab9 | |||
| 9d7425b201 | |||
| 7eb43d7f7e | |||
| d76e0ec6d8 | |||
| 4a83f976e1 | |||
| 23572aaf77 | |||
| 48655ff1ec | |||
| ffbf34cb97 | |||
| fad690be11 | |||
| 355a644020 | |||
| 5e6e4e7464 | |||
| 76fde49282 | |||
| 4ef7d0410d | |||
| a1b4984d14 | |||
| adbe5ecf55 | |||
| ba32571039 | |||
| 084146756b | |||
| e1f5a49c21 | |||
| 143320341e | |||
| e286bb1b64 | |||
| d433f0e08e | |||
| 107149d601 | |||
| fa9b36f829 | |||
| 6775292d63 | |||
| 6835429a28 | |||
| 22135f9f57 | |||
| 0fd06a225c | |||
| 473dcb0947 | |||
| e306f4611c | |||
| c6f4f44619 | |||
| 0865c63745 | |||
| b81c3a6a67 | |||
| cc56e5639d | |||
| 3ce5b358ae | |||
| e968284618 | |||
| c7723179d8 | |||
| 1872f3f94a | |||
| 3b7887ca35 | |||
| d781e63fab | |||
| d1237cdda3 | |||
| 030e3a5d4a | |||
| 4fa4a6a5ed | |||
| 23fb07240b | |||
| 3912dba33a | |||
| d8c479ab1e | |||
| bec67455c1 | |||
| ba6a37a601 | |||
| 03f5091e73 | |||
| 6b6ff08821 | |||
| 35a0ee4893 | |||
| 3519391119 | |||
| 775a1c9ad8 | |||
| ac95844ebd | |||
| c5b90d9507 | |||
| d631f2e070 | |||
| 5bae2ed5ef | |||
| 5af2a657ca | |||
| 71231026a0 | |||
| dfca67b63a | |||
| 7dc6a3b89f | |||
| f985111b62 | |||
| e8d734b1c2 | |||
| a38864fcb4 | |||
| 47bab51474 | |||
| d0d5b2b4ee | |||
| 36967122db | |||
| 3fd67b9fb6 | |||
| 5bef1aa402 | |||
| de9ea19e7e | |||
| 4ac2b764a4 | |||
| 0614cda337 | |||
| 9e895b9b3e | |||
| f501211c63 | |||
| 77ac1b46dd | |||
| 745c21623c | |||
| b91c116518 | |||
| d090a3330a | |||
| d04e7841e2 | |||
| d7a4726544 | |||
| 19d2677db1 | |||
| a139d1a279 | |||
| 13e624c38f | |||
| acb155503b | |||
| 4cb80b08a2 | |||
| cd85b7c6d7 | |||
| 109056e676 | |||
| 51a1bea5de | |||
| 68f99bcc27 | |||
| 276985f6c3 | |||
| 7523db354d | |||
| 4919c9e7b1 | |||
| 045498c71a | |||
| 49f8143f00 | |||
| bea7241910 | |||
| 61b4da944c | |||
| 6fe1868693 | |||
| 9641c7a1e7 | |||
| 3e59a9b316 | |||
| 679ac0d26a | |||
| 2e3a3bcf84 | |||
| ad437a49f9 | |||
| 6b2282bf0d | |||
| 42aed56a5a | |||
| ca9ec46253 | |||
| a92eec160a | |||
| cc91c42dfa | |||
| d22d0e7e30 | |||
| 4998303c42 | |||
| ceef2f2d46 | |||
| 8b18600d7e | |||
| 6cc63462b3 | |||
| a1dc4069c9 | |||
| 86846af59d | |||
| 5bfa02602d | |||
| 9be23984eb | |||
| eb8de8e3c0 | |||
| ec7333a4bf | |||
| e485c5c008 | |||
| 6451eb3ade | |||
| 01528427b5 | |||
| cec4d7b9ff | |||
| efa7821dd2 | |||
| 89f55cf9df | |||
| 52552a4204 | |||
| 2f3db04e87 | |||
| 2d6e473a40 | |||
| 92027e8692 | |||
| 2723cd225e | |||
| acd151102c | |||
| 77e790d2ee | |||
| 899c675f0a | |||
| fb76487e76 | |||
| 0c0a3ca0a5 | |||
| 5377d1e283 | |||
| 676ad530e7 | |||
| fbcb01ed27 | |||
| c2b006e857 | |||
| 0e7ccea588 | |||
| c16deb3e44 | |||
| 019544fcfd | |||
| 5f0167b19e | |||
| 29d3c33eb2 | |||
| 469eca1f5f | |||
| 0864d67a9a | |||
| e9503664f5 | |||
| 58cee61624 | |||
| d23d07f99b | |||
| d70db810dd | |||
| 842129f99d | |||
| 36d61ef3a9 | |||
| f1f27221a7 | |||
| eb012d26ee | |||
| 9ee8187083 | |||
| b0c45cfc89 | |||
| 90cea69692 | |||
| 155bdfbffe | |||
| 0e2782d369 | |||
| 6b3d0e69aa | |||
| f30aee6d4e | |||
| 82f86eb019 | |||
| 9573c5e64d | |||
| 15f2b911d9 | |||
| f5aff70398 | |||
| e3a4c3989a | |||
| 3e954bc17f | |||
| 2527569bb8 | |||
| 1e197531cb | |||
| 8b876576eb | |||
| a2287c9657 | |||
| 34c59ba9ed | |||
| c8014a0afd | |||
| 456d82715e | |||
| 8ca3eb7883 | |||
| c110745330 | |||
| 19521863a0 | |||
| c256896165 | |||
| ef922f60fa | |||
| 733ea90e6b | |||
| a4e1fa9dcf | |||
| 1a1684ca2a | |||
| 9c8572e335 | |||
| e675a34fbb | |||
| 5f47c01346 | |||
| 10644d3568 | |||
| 9ee3144358 | |||
| cf48ea2e00 | |||
| db24f60ae3 | |||
| 6026148692 | |||
| a2222228c9 | |||
| 9e2d3f5bc7 | |||
| fe984b61d7 | |||
| ffac3f6213 | |||
| 4f1feab845 | |||
| f738cfd7fe | |||
| e6be670e49 | |||
| 46ce2f4722 | |||
| 166a0f60ca | |||
| a9019ccbad | |||
| 0a4806af44 | |||
| e33b89c222 | |||
| 6b899be895 | |||
| 641785298f | |||
| 092c935422 | |||
| 273590fdfc | |||
| 0960058842 | |||
| 1f78ea0fd1 | |||
| 72d8175032 | |||
| 2fd9767892 | |||
| 69a1e46d0c | |||
| e020a5327e | |||
| 1b04489887 | |||
| 36a19703db | |||
| f3a345a23b | |||
| 826459eae7 | |||
| c2c36b85cb | |||
| 7b2f8ae6f7 | |||
| d600fdc89b | |||
| 8c5ea8dc90 | |||
| 0eddcd6384 | |||
| 9f2ae5dd17 | |||
| 766d9ae1ac | |||
| 21128ed762 | |||
| 5000d40619 | |||
| 16e28567a6 | |||
| 3bef42db6b | |||
| 27d23edacc | |||
| 0d321050a6 | |||
| 089ecf8222 | |||
| e1a48e3c33 | |||
| d54f8adac5 | |||
| d35ecafa0b | |||
| 2ca807280a | |||
| 5d13f9290f | |||
| c84140d293 | |||
| e1a01c75d9 | |||
| 6a4adbc87e | |||
| 89974ab1d4 | |||
| 8d0c313486 | |||
| aab0cdf12a | |||
| a89520043e | |||
| 838c072ccc | |||
| 02c403e360 | |||
| ed6a708460 | |||
| 0c9dcdafc2 | |||
| da26e59770 | |||
| 3c24d5a148 | |||
| c222793525 | |||
| 28018e8590 | |||
| 4c79ce2ae6 | |||
| 7c75a39bc1 | |||
| f0dc3b2deb | |||
| 84ede3f01f | |||
| 2daf895e43 | |||
| 3b651b2da9 | |||
| 6fd930908c | |||
| 62125a442d | |||
| 2d54fb2ff9 | |||
| e46fad52bb | |||
| c41f6ed76b | |||
| 818b5854ce | |||
| 79abb8b4e3 | |||
| fad387b6b8 | |||
| a1558100b8 | |||
| 4f3f642da6 | |||
| f3cfd2b70b | |||
| 78caa1a712 | |||
| 0884ad6517 | |||
| 37fc4e4332 | |||
| 9cc90159f1 | |||
| 4ceee86c66 | |||
| b9ea7c3414 | |||
| 3033e693be | |||
| a1bc01d3b1 |
+4
-1
@@ -58,6 +58,9 @@ if( UNIX AND NOT APPLE )
|
||||
endif()
|
||||
####
|
||||
|
||||
# Enable Q_ASSERT etc. in all builds
|
||||
add_definitions( -DQT_FORCE_ASSERTS )
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(DefineInstallationPaths)
|
||||
include(GenerateExportHeader)
|
||||
@@ -69,7 +72,7 @@ get_git_head_revision(GIT_REFSPEC GIT_SHA1)
|
||||
# if we cannot get it from git, directly try .tag (packages)
|
||||
# this will work if the tar balls have been properly created
|
||||
# via git-archive.
|
||||
if (${GIT_SHA1} STREQUAL "GITDIR-NOTFOUND")
|
||||
if ("${GIT_SHA1}" STREQUAL "GITDIR-NOTFOUND")
|
||||
file(READ ${CMAKE_SOURCE_DIR}/.tag sha1_candidate)
|
||||
string(REPLACE "\n" "" sha1_candidate ${sha1_candidate})
|
||||
if (NOT ${sha1_candidate} STREQUAL "$Format:%H$")
|
||||
|
||||
+39
@@ -1,6 +1,45 @@
|
||||
ChangeLog
|
||||
=========
|
||||
|
||||
version 2.3.0 (2017-0x-xx)
|
||||
* WiP!
|
||||
* WiP Switch Windows and OS X build to 5.6.2
|
||||
* WiP Performance improvements for exclude detection
|
||||
* Switch to new ownCloud server WebDAV endpoint
|
||||
* Chunking NG: New file upload chunking algorithmn for ownCloud server 9.2
|
||||
* Allow to sync a folder to multiple different servers (Filename change from .csync_journal.db to _sync_$HASH.db)
|
||||
* Conflicts: Use the local mtime for the conflict file name (#5273)
|
||||
* "Sync now" menu item
|
||||
* SSL Client certificate support improved (Show UI, Store keys in keychain)
|
||||
* Propagator: Upload more small files in parallel
|
||||
* Sync Engine: Read data-fingerprint property to detect backups (#2325)
|
||||
* GUI: Show link to ceate an app password/token for syncing
|
||||
* Share dialog: Add 'Mail link' button
|
||||
* Caja file manager plugin
|
||||
* Make "backup detected" message to not trigger in wrong cases
|
||||
* SyncEngine: Fix renaming of folder when file are changed (#5192)
|
||||
* Fix reconnect bug if status.php intermittently returns wrong data (#5188)
|
||||
* Improve sync scheduling (#5317)
|
||||
* Overlay icons: Improvements in correctnes
|
||||
* Tray menu: Only update on demand to fix Linux desktop integration glitches
|
||||
* Progress: Better time/bandwidth estimations
|
||||
* Network: Follow certain HTTP redirects (#2791)
|
||||
* Network: Remove all cookies (including load balancers etc) when logging out
|
||||
* Discovery thread: Low priority
|
||||
* owncloudsync.log: Write during propagation
|
||||
* Better error message for files with trailing spaces on Windows
|
||||
* Excludes: Consider files in hidden folders excluded (#5163)
|
||||
* Allow sync directory to be a symlinked directory
|
||||
* Add manifest file on Windows to make the application UAC aware
|
||||
* macOS: Improve monochrome tray icons
|
||||
* Don't blacklist 507 Insufficent Storage #5346 (#5424)
|
||||
* Shibboleth bugfixes
|
||||
* Fixes with regards to low disk space
|
||||
* A ton of other bugfixes
|
||||
* Refactorings
|
||||
* Improved documentation
|
||||
* Crash fixes
|
||||
|
||||
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)
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ https://github.com/owncloud/client.
|
||||
|
||||
## Building the source code
|
||||
|
||||
[Building the Client](http://doc.owncloud.org/desktop/2.0/building.html)
|
||||
[Building the Client](http://doc.owncloud.org/desktop/2.2/building.html)
|
||||
in the ownCloud Desktop Client manual.
|
||||
|
||||
## Maintainers and Contributors
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
#
|
||||
# ownCloud is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; version 2 of the License.
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ownCLoud is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@@ -39,7 +40,6 @@ QT_PLUGINS = [
|
||||
'imageformats/libqico.dylib',
|
||||
'imageformats/libqjpeg.dylib',
|
||||
'imageformats/libqsvg.dylib',
|
||||
'imageformats/libqmng.dylib',
|
||||
]
|
||||
|
||||
QT_PLUGINS_SEARCH_PATH=[
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
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)
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
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)
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
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)
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,691 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,434 +0,0 @@
|
||||
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
|
||||
@@ -1,64 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
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
|
||||
@@ -1,113 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,233 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
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
|
||||
@@ -1,32 +0,0 @@
|
||||
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
|
||||
@@ -1,39 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,55 +1,20 @@
|
||||
## 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
|
||||
There are our patches on top of Qt 5.6.2, which we are currently
|
||||
using for our binary packages on Windows and macOS. 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
|
||||
All changes are designed to be 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.
|
||||
You can apply those patches on a git clone using:
|
||||
|
||||
### 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.
|
||||
```
|
||||
git am <client>/admin/qt/patches/qtbase/*.patch
|
||||
```
|
||||
|
||||
You can update them using:
|
||||
|
||||
```
|
||||
git format-patch -N --no-signature -o <client>/admin/qt/patches/qtbase/ <v5.x.y>
|
||||
```
|
||||
|
||||
+9
-12
@@ -1,30 +1,27 @@
|
||||
From f3cd07c11e0b7327ffc629f48a89c8c457cdba75 Mon Sep 17 00:00:00 2001
|
||||
From 96c34ce85136cbdc16ef83effa8a13137f7ae4c5 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
|
||||
Subject: [PATCH] [NOUPSTREAM] 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
|
||||
index e003b94..e9b3291 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}
|
||||
@@ -21,11 +21,13 @@ QMAKE_CFLAGS_PRECOMPILE = -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_
|
||||
QMAKE_CFLAGS_USE_PRECOMPILE = -Xclang -include-pch -Xclang ${QMAKE_PCH_OUTPUT}
|
||||
QMAKE_CFLAGS_LTCG = -flto
|
||||
QMAKE_CFLAGS_DISABLE_LTCG = -fno-lto
|
||||
+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_DISABLE_LTCG = $$QMAKE_CFLAGS_DISABLE_LTCG
|
||||
+QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
|
||||
|
||||
QMAKE_LFLAGS_CXX11 =
|
||||
QMAKE_LFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG
|
||||
--
|
||||
2.2.0
|
||||
|
||||
QMAKE_CXXFLAGS_CXX11 = -std=c++11
|
||||
QMAKE_CXXFLAGS_CXX14 = -std=c++1y
|
||||
QMAKE_CXXFLAGS_CXX1Z = -std=c++1z
|
||||
+17
-22
@@ -1,7 +1,7 @@
|
||||
From 06818f6d1c602aa3c4f9356324866432d2dd0195 Mon Sep 17 00:00:00 2001
|
||||
From e6bccb1f0d8ca59acb1ffdac74a823c06346e7f3 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
|
||||
Subject: [PATCH] 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.
|
||||
@@ -16,20 +16,18 @@ 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_openssl.cpp | 81 +++++++++++-----------------------
|
||||
src/network/ssl/qsslsocket_p.h | 6 +--
|
||||
2 files changed, 28 insertions(+), 61 deletions(-)
|
||||
2 files changed, 26 insertions(+), 61 deletions(-)
|
||||
|
||||
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
|
||||
index 13fc534..7d0fe00 100644
|
||||
index 82644c1..415f147 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
|
||||
@@ -76,14 +76,17 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
+#include <string.h>
|
||||
+
|
||||
+#ifdef Q_OS_DARWIN
|
||||
+# include <private/qcore_mac_p.h>
|
||||
+#endif
|
||||
@@ -50,7 +48,7 @@ index 13fc534..7d0fe00 100644
|
||||
PtrCertOpenSystemStoreW QSslSocketPrivate::ptrCertOpenSystemStoreW = 0;
|
||||
PtrCertFindCertificateInStore QSslSocketPrivate::ptrCertFindCertificateInStore = 0;
|
||||
PtrCertCloseStore QSslSocketPrivate::ptrCertCloseStore = 0;
|
||||
@@ -482,23 +487,7 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
|
||||
@@ -509,23 +512,7 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
|
||||
|
||||
#ifndef QT_NO_LIBRARY
|
||||
//load symbols needed to receive certificates from system store
|
||||
@@ -59,23 +57,23 @@ index 13fc534..7d0fe00 100644
|
||||
- if (securityLib.load()) {
|
||||
- ptrSecCertificateCopyData = (PtrSecCertificateCopyData) securityLib.resolve("SecCertificateCopyData");
|
||||
- if (!ptrSecCertificateCopyData)
|
||||
- qWarning("could not resolve symbols in security library"); // should never happen
|
||||
- qCWarning(lcSsl, "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
|
||||
- qCWarning(lcSsl, "could not resolve symbols in security library"); // should never happen
|
||||
- }
|
||||
- } else {
|
||||
- qWarning("could not load security library");
|
||||
- qCWarning(lcSsl, "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()
|
||||
@@ -693,40 +680,22 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
timer.start();
|
||||
#endif
|
||||
QList<QSslCertificate> systemCerts;
|
||||
@@ -101,7 +99,7 @@ index 13fc534..7d0fe00 100644
|
||||
- data = ptrSecCertificateCopyData(cfCert);
|
||||
-
|
||||
- if (data == NULL) {
|
||||
- qWarning("error retrieving a CA certificate from the system store");
|
||||
- qCWarning(lcSsl, "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));
|
||||
@@ -127,15 +125,15 @@ index 13fc534..7d0fe00 100644
|
||||
- }
|
||||
- else {
|
||||
- // no detailed error handling here
|
||||
- qWarning("could not retrieve system CA certificates");
|
||||
- qCWarning(lcSsl, "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
|
||||
index d651971..17cc7b4 100644
|
||||
--- a/src/network/ssl/qsslsocket_p.h
|
||||
+++ b/src/network/ssl/qsslsocket_p.h
|
||||
@@ -145,11 +145,7 @@ public:
|
||||
@@ -151,11 +151,7 @@ public:
|
||||
static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
|
||||
Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname);
|
||||
|
||||
@@ -148,6 +146,3 @@ index 6e7a2c5..c1a6f05 100644
|
||||
static PtrCertOpenSystemStoreW ptrCertOpenSystemStoreW;
|
||||
static PtrCertFindCertificateInStore ptrCertFindCertificateInStore;
|
||||
static PtrCertCloseStore ptrCertCloseStore;
|
||||
--
|
||||
1.9.1
|
||||
|
||||
+13
-16
@@ -1,7 +1,7 @@
|
||||
From 6b9366e7748857f14d5b0f92ced70c08ab5235b7 Mon Sep 17 00:00:00 2001
|
||||
From 9d1120db0973ea7741b13a6555b20ae61f6d037e 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
|
||||
Subject: [PATCH] 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
|
||||
@@ -15,7 +15,7 @@ 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)
|
||||
(Backport of fe3a84138e266c425f11353f7d8dc28a588af89e)
|
||||
|
||||
Task-number: QTBUG-32898
|
||||
Change-Id: Ia23083d5af74388eeee31ba07239735cbbe64368
|
||||
@@ -29,10 +29,10 @@ Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>
|
||||
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
|
||||
index 549906a..7b202b0 100644
|
||||
--- a/src/network/ssl/qsslsocket.cpp
|
||||
+++ b/src/network/ssl/qsslsocket.cpp
|
||||
@@ -1446,6 +1446,10 @@ QList<QSslCertificate> QSslSocket::defaultCaCertificates()
|
||||
@@ -1508,6 +1508,10 @@ QList<QSslCertificate> QSslSocket::defaultCaCertificates()
|
||||
returned by defaultCaCertificates(). You can replace that database
|
||||
with your own with setDefaultCaCertificates().
|
||||
|
||||
@@ -198,10 +198,10 @@ index 0000000..60fea4c
|
||||
+
|
||||
+QT_END_NAMESPACE
|
||||
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
|
||||
index 7d0fe00..7415e32 100644
|
||||
index 415f147..7a3cb42 100644
|
||||
--- a/src/network/ssl/qsslsocket_openssl.cpp
|
||||
+++ b/src/network/ssl/qsslsocket_openssl.cpp
|
||||
@@ -71,14 +71,6 @@
|
||||
@@ -76,14 +76,6 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -216,15 +216,15 @@ index 7d0fe00..7415e32 100644
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
@@ -616,6 +608,7 @@ void QSslSocketPrivate::resetDefaultCiphers()
|
||||
setDefaultCiphers(defaultCiphers);
|
||||
@@ -672,6 +664,7 @@ void QSslSocketPrivate::resetDefaultEllipticCurves()
|
||||
setDefaultSupportedEllipticCurves(curves);
|
||||
}
|
||||
|
||||
+#ifndef Q_OS_DARWIN // Apple implementation in qsslsocket_mac_shared.cpp
|
||||
QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
{
|
||||
ensureInitialized();
|
||||
@@ -624,25 +617,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
@@ -680,25 +673,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
timer.start();
|
||||
#endif
|
||||
QList<QSslCertificate> systemCerts;
|
||||
@@ -251,7 +251,7 @@ index 7d0fe00..7415e32 100644
|
||||
if (ptrCertOpenSystemStoreW && ptrCertFindCertificateInStore && ptrCertCloseStore) {
|
||||
HCERTSTORE hSystemStore;
|
||||
#if defined(Q_OS_WINCE)
|
||||
@@ -719,6 +694,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
@@ -775,6 +750,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
|
||||
return systemCerts;
|
||||
}
|
||||
@@ -260,10 +260,10 @@ index 7d0fe00..7415e32 100644
|
||||
void QSslSocketBackendPrivate::startClientEncryption()
|
||||
{
|
||||
diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri
|
||||
index 384e149..9546f18 100644
|
||||
index 29c47cd..8eb605b 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) {
|
||||
@@ -62,7 +62,9 @@ contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
|
||||
ssl/qsslsocket_openssl.cpp \
|
||||
ssl/qsslsocket_openssl_symbols.cpp
|
||||
|
||||
@@ -274,6 +274,3 @@ index 384e149..9546f18 100644
|
||||
|
||||
# Add optional SSL libs
|
||||
# Static linking of OpenSSL with msvc:
|
||||
--
|
||||
1.9.1
|
||||
|
||||
@@ -9,6 +9,7 @@ StrCpy $PageReinstall_NEW_Field_3 "No instal·lar"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Ja instal·lat"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Trieu la manera com voleu instal·lar ${APPLICATION_NAME}."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "Una versió més recent de ${APPLICATION_NAME} ja està instal.lada!! No es recomana instal.lar una versió més antiga. Si realment voleu instal.lar una versió més antiga, és millor primer desinstal.lar la versió actual. Seleccioni l'operació que desitjeu realitzar i feu clic a Següent per a continuar."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} ja està instal·lat.$\n$\nSeleccioneu la operació que voleu fer i feu clic a Següent per continuar."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Afegir/Reinstal.lar components"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "Desinstal.lar ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Desinstal.lar ${APPLICATION_NAME}"
|
||||
@@ -37,7 +38,6 @@ StrCpy $UAC_ERROR_ELEVATE "No es pot elevar, error:"
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "Aquest instal·lador requereix accés d'administrador, intenteu-ho de nou"
|
||||
StrCpy $INIT_INSTALLER_RUNNING "L'instal·lador ja s'està executant."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Aquest desinstal·lador requereix accés d'administrador, intenteu-ho de nou."
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "El servei de inici de sessió no s'està executant, s'està abortant!"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "El desinstal·lador ja s'està executant."
|
||||
StrCpy $SectionGroup_Shortcuts "Dreceres"
|
||||
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!"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Mostrar las notas de la versión"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "El/los proceso/s ${APPLICATION_EXECUTABLE} debe/n ser detenidos.$\n¿Quiere que el instalador lo haga por usted?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Deteniendo el/los proceso/s ${APPLICATION_EXECUTABLE}."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "¡Proceso para finalizar no encontrado!"
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "¡Proceso a finalizar no encontrado!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Una versión anterior de ${APPLICATION_NAME} se encuentra instalada en el sistema. Se recomienda de instalar la versión actual antes de instalar la nueva. Seleccione la operacion deseada y haga click en Siguiente para continuar."
|
||||
StrCpy $PageReinstall_NEW_Field_2 "Desinstalar antes de instalar"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "No desinstalar"
|
||||
|
||||
+1
-1
Submodule binary updated: 0d89ac7766...741b49156b
@@ -32,7 +32,7 @@ find_library(CMOCKA_LIBRARY
|
||||
NAMES
|
||||
cmocka
|
||||
PATHS
|
||||
${CMOCKA_ROOT_DIR}/include
|
||||
${CMOCKA_ROOT_DIR}/lib
|
||||
)
|
||||
|
||||
if (CMOCKA_LIBRARY)
|
||||
|
||||
@@ -418,10 +418,8 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
File "${QT_DLL_PATH}\Qt5Core.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Gui.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Network.dll"
|
||||
File "${QT_DLL_PATH}\Qt5OpenGL.dll"
|
||||
File "${QT_DLL_PATH}\Qt5PrintSupport.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Qml.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Quick.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Sql.dll"
|
||||
File "${QT_DLL_PATH}\Qt5WebKit.dll"
|
||||
File "${QT_DLL_PATH}\Qt5WebKitWidgets.dll"
|
||||
@@ -435,9 +433,9 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
|
||||
;Qt deps
|
||||
File "${MING_BIN}\libpng16-16.dll"
|
||||
File "${MING_BIN}\icudata53.dll"
|
||||
File "${MING_BIN}\icui18n53.dll"
|
||||
File "${MING_BIN}\icuuc53.dll"
|
||||
File "${MING_BIN}\icudata56.dll"
|
||||
File "${MING_BIN}\icui18n56.dll"
|
||||
File "${MING_BIN}\icuuc56.dll"
|
||||
File "${MING_BIN}\libEGL.dll"
|
||||
File "${MING_BIN}\libGLESv2.dll"
|
||||
File "${MING_BIN}\libjpeg-8.dll"
|
||||
@@ -446,11 +444,14 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
File "${MING_BIN}\libcrypto-10.dll"
|
||||
File "${MING_BIN}\libssl-10.dll"
|
||||
File "${MING_BIN}\libstdc++-6.dll"
|
||||
File "${MING_BIN}\libwebp-4.dll"
|
||||
File "${MING_BIN}\libwebp-5.dll"
|
||||
File "${MING_BIN}\libxslt-1.dll"
|
||||
File "${MING_BIN}\libxml2-2.dll"
|
||||
File "${MING_BIN}\zlib1.dll"
|
||||
File "${MING_BIN}\libsqlite3-0.dll"
|
||||
File "${MING_BIN}\libharfbuzz-0.dll"
|
||||
File "${MING_BIN}\libfreetype-6.dll"
|
||||
File "${MING_BIN}\libglib-2.0-0.dll"
|
||||
File "${MING_BIN}\libintl-8.dll"
|
||||
|
||||
;QtKeyChain stuff
|
||||
File "${MING_BIN}\libqt5keychain.dll"
|
||||
|
||||
+10
-22
@@ -89,7 +89,7 @@ static int _data_cmp(const void *key, const void *data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void csync_create(CSYNC **csync, const char *local, const char *remote) {
|
||||
void csync_create(CSYNC **csync, const char *local) {
|
||||
CSYNC *ctx;
|
||||
size_t len = 0;
|
||||
|
||||
@@ -103,12 +103,6 @@ void csync_create(CSYNC **csync, const char *local, const char *remote) {
|
||||
|
||||
ctx->local.uri = c_strndup(local, len);
|
||||
|
||||
/* remove trailing slashes */
|
||||
len = strlen(remote);
|
||||
while(len > 0 && remote[len - 1] == '/') --len;
|
||||
|
||||
ctx->remote.uri = c_strndup(remote, len);
|
||||
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
ctx->current_fs = NULL;
|
||||
@@ -120,7 +114,7 @@ void csync_create(CSYNC **csync, const char *local, const char *remote) {
|
||||
*csync = ctx;
|
||||
}
|
||||
|
||||
void csync_init(CSYNC *ctx) {
|
||||
void csync_init(CSYNC *ctx, const char *db_file) {
|
||||
assert(ctx);
|
||||
/* Do not initialize twice */
|
||||
|
||||
@@ -131,6 +125,9 @@ void csync_init(CSYNC *ctx) {
|
||||
|
||||
ctx->remote.type = REMOTE_REPLICA;
|
||||
|
||||
SAFE_FREE(ctx->statedb.file);
|
||||
ctx->statedb.file = c_strdup(db_file);
|
||||
|
||||
c_rbtree_create(&ctx->local.tree, _key_cmp, _data_cmp);
|
||||
c_rbtree_create(&ctx->remote.tree, _key_cmp, _data_cmp);
|
||||
|
||||
@@ -152,19 +149,11 @@ int csync_update(CSYNC *ctx) {
|
||||
}
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
/* create/load statedb */
|
||||
rc = asprintf(&ctx->statedb.file, "%s/.csync_journal.db",
|
||||
ctx->local.uri);
|
||||
if (rc < 0) {
|
||||
ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
|
||||
return rc;
|
||||
}
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Journal: %s", ctx->statedb.file);
|
||||
|
||||
if (csync_statedb_load(ctx, ctx->statedb.file, &ctx->statedb.db) < 0) {
|
||||
/* Path of database file is set in csync_init */
|
||||
if (csync_statedb_load(ctx, ctx->statedb.file, &ctx->statedb.db) < 0) {
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->status_code = CSYNC_STATUS_OK;
|
||||
|
||||
@@ -199,7 +188,7 @@ int csync_update(CSYNC *ctx) {
|
||||
ctx->current = REMOTE_REPLICA;
|
||||
ctx->replica = ctx->remote.type;
|
||||
|
||||
rc = csync_ftw(ctx, ctx->remote.uri, csync_walker, MAX_DEPTH);
|
||||
rc = csync_ftw(ctx, "", csync_walker, MAX_DEPTH);
|
||||
if (rc < 0) {
|
||||
if(ctx->status_code == CSYNC_STATUS_OK) {
|
||||
ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_UPDATE_ERROR);
|
||||
@@ -521,7 +510,6 @@ static void _csync_clean_ctx(CSYNC *ctx)
|
||||
c_rbtree_free(ctx->local.tree);
|
||||
c_rbtree_free(ctx->remote.tree);
|
||||
|
||||
SAFE_FREE(ctx->statedb.file);
|
||||
SAFE_FREE(ctx->remote.root_perms);
|
||||
}
|
||||
|
||||
@@ -578,8 +566,8 @@ int csync_destroy(CSYNC *ctx) {
|
||||
|
||||
_csync_clean_ctx(ctx);
|
||||
|
||||
SAFE_FREE(ctx->statedb.file);
|
||||
SAFE_FREE(ctx->local.uri);
|
||||
SAFE_FREE(ctx->remote.uri);
|
||||
SAFE_FREE(ctx->error_string);
|
||||
|
||||
#ifdef WITH_ICONV
|
||||
|
||||
+2
-7
@@ -44,11 +44,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct csync_client_certs_s {
|
||||
char *certificatePath;
|
||||
char *certificatePasswd;
|
||||
};
|
||||
|
||||
enum csync_status_codes_e {
|
||||
CSYNC_STATUS_OK = 0,
|
||||
|
||||
@@ -317,7 +312,7 @@ typedef const char* (*csync_checksum_hook) (
|
||||
*
|
||||
* @param csync The context variable to allocate.
|
||||
*/
|
||||
void OCSYNC_EXPORT csync_create(CSYNC **csync, const char *local, const char *remote);
|
||||
void OCSYNC_EXPORT csync_create(CSYNC **csync, const char *local);
|
||||
|
||||
/**
|
||||
* @brief Initialize the file synchronizer.
|
||||
@@ -326,7 +321,7 @@ void OCSYNC_EXPORT csync_create(CSYNC **csync, const char *local, const char *re
|
||||
*
|
||||
* @param ctx The context to initialize.
|
||||
*/
|
||||
void OCSYNC_EXPORT csync_init(CSYNC *ctx);
|
||||
void OCSYNC_EXPORT csync_init(CSYNC *ctx, const char *db_file);
|
||||
|
||||
/**
|
||||
* @brief Update detection
|
||||
|
||||
@@ -230,6 +230,11 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
|
||||
}
|
||||
blen = strlen(bname);
|
||||
|
||||
rc = csync_fnmatch("._sync_*.db*", bname, 0);
|
||||
if (rc == 0) {
|
||||
match = CSYNC_FILE_SILENTLY_EXCLUDED;
|
||||
goto out;
|
||||
}
|
||||
rc = csync_fnmatch(".csync_journal.db*", bname, 0);
|
||||
if (rc == 0) {
|
||||
match = CSYNC_FILE_SILENTLY_EXCLUDED;
|
||||
|
||||
@@ -89,7 +89,7 @@ struct csync_s {
|
||||
|
||||
/* hooks for checking the white list (uses the update_callback_userdata) */
|
||||
int (*checkSelectiveSyncBlackListHook)(void*, const char*);
|
||||
int (*checkSelectiveSyncNewFolderHook)(void*, const char*);
|
||||
int (*checkSelectiveSyncNewFolderHook)(void*, const char* /* path */, const char* /* remotePerm */);
|
||||
|
||||
|
||||
csync_vio_opendir_hook remote_opendir_hook;
|
||||
@@ -103,9 +103,6 @@ struct csync_s {
|
||||
|
||||
} callbacks;
|
||||
c_strlist_t *excludes;
|
||||
|
||||
// needed for SSL client certificate support
|
||||
struct csync_client_certs_s *clientCerts;
|
||||
|
||||
struct {
|
||||
char *file;
|
||||
@@ -126,7 +123,6 @@ struct csync_s {
|
||||
} local;
|
||||
|
||||
struct {
|
||||
char *uri;
|
||||
c_rbtree_t *tree;
|
||||
enum csync_replica_e type;
|
||||
int read_from_db;
|
||||
|
||||
@@ -65,7 +65,21 @@ static c_rbnode_t *_csync_check_ignored(c_rbtree_t *tree, const char *path, int
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* The main function in the reconcile pass.
|
||||
*
|
||||
* It's called for each entry in the local and remote rbtrees by
|
||||
* csync_reconcile()
|
||||
*
|
||||
* Before the reconcile phase the trees already know about changes
|
||||
* relative to the sync journal. This function's job is to spot conflicts
|
||||
* between local and remote changes and adjust the nodes accordingly.
|
||||
*
|
||||
* See doc/dev/sync-algorithm.md for an overview.
|
||||
*
|
||||
*
|
||||
* Older detail comment:
|
||||
*
|
||||
* We merge replicas at the file level. The merged replica contains the
|
||||
* superset of files that are on the local machine and server copies of
|
||||
* the replica. In the case where the same file is in both the local
|
||||
|
||||
+25
-96
@@ -56,26 +56,13 @@ static uint64_t _hash_of_file(CSYNC *ctx, const char *file) {
|
||||
|
||||
if( ctx && file ) {
|
||||
path = file;
|
||||
switch (ctx->current) {
|
||||
case LOCAL_REPLICA:
|
||||
if (ctx->current == LOCAL_REPLICA) {
|
||||
if (strlen(path) <= strlen(ctx->local.uri)) {
|
||||
return 0;
|
||||
}
|
||||
path += strlen(ctx->local.uri) + 1;
|
||||
break;
|
||||
case REMOTE_REPLICA:
|
||||
if (strlen(path) <= strlen(ctx->remote.uri)) {
|
||||
return 0;
|
||||
}
|
||||
path += strlen(ctx->remote.uri) + 1;
|
||||
break;
|
||||
default:
|
||||
path = NULL;
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
len = strlen(path);
|
||||
|
||||
h = c_jhash64((uint8_t *) path, len, 0);
|
||||
}
|
||||
return h;
|
||||
@@ -158,7 +145,19 @@ static bool _csync_mtime_equal(time_t a, time_t b)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The main function of the discovery/update pass.
|
||||
*
|
||||
* It's called (indirectly) by csync_update(), once for each entity in the
|
||||
* local filesystem and once for each entity in the server data.
|
||||
*
|
||||
* It has two main jobs:
|
||||
* - figure out whether anything happened compared to the sync journal
|
||||
* and set (primarily) the instruction flag accordingly
|
||||
* - build the ctx->local.tree / ctx->remote.tree
|
||||
*
|
||||
* See doc/dev/sync-algorithm.md for an overview.
|
||||
*/
|
||||
static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
const csync_vio_file_stat_t *fs, const int type) {
|
||||
uint64_t h = 0;
|
||||
@@ -176,25 +175,12 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
}
|
||||
|
||||
path = file;
|
||||
switch (ctx->current) {
|
||||
case LOCAL_REPLICA:
|
||||
if (ctx->current == LOCAL_REPLICA) {
|
||||
if (strlen(path) <= strlen(ctx->local.uri)) {
|
||||
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
|
||||
return -1;
|
||||
}
|
||||
path += strlen(ctx->local.uri) + 1;
|
||||
break;
|
||||
case REMOTE_REPLICA:
|
||||
if (strlen(path) <= strlen(ctx->remote.uri)) {
|
||||
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
|
||||
return -1;
|
||||
}
|
||||
path += strlen(ctx->remote.uri) + 1;
|
||||
break;
|
||||
default:
|
||||
path = NULL;
|
||||
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = strlen(path);
|
||||
@@ -450,7 +436,7 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
st->instruction = CSYNC_INSTRUCTION_NEW;
|
||||
|
||||
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, fs->remotePerm)) {
|
||||
csync_file_stat_free(st);
|
||||
return 1;
|
||||
}
|
||||
@@ -617,16 +603,7 @@ int csync_walker(CSYNC *ctx, const char *file, const csync_vio_file_stat_t *fs,
|
||||
|
||||
static bool fill_tree_from_db(CSYNC *ctx, const char *uri)
|
||||
{
|
||||
const char *path = NULL;
|
||||
|
||||
if( strlen(uri) < strlen(ctx->remote.uri)+1) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "name does not contain remote uri!");
|
||||
return false;
|
||||
}
|
||||
|
||||
path = uri + strlen(ctx->remote.uri)+1;
|
||||
|
||||
if( csync_statedb_get_below_path(ctx, path) < 0 ) {
|
||||
if( csync_statedb_get_below_path(ctx, uri) < 0 ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "StateDB could not be read!");
|
||||
return false;
|
||||
}
|
||||
@@ -668,12 +645,6 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
|
||||
bool do_read_from_db = (ctx->current == REMOTE_REPLICA && ctx->remote.read_from_db);
|
||||
|
||||
if (uri[0] == '\0') {
|
||||
errno = ENOENT;
|
||||
ctx->status_code = CSYNC_STATUS_PARAM_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
read_from_db = ctx->remote.read_from_db;
|
||||
|
||||
// if the etag of this dir is still the same, its content is restored from the
|
||||
@@ -687,16 +658,7 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
goto done;
|
||||
}
|
||||
|
||||
const char *uri_for_vio = uri;
|
||||
if (ctx->current == REMOTE_REPLICA) {
|
||||
uri_for_vio += strlen(ctx->remote.uri);
|
||||
if (strlen(uri_for_vio) > 0 && uri_for_vio[0] == '/') {
|
||||
uri_for_vio++; // cut leading slash
|
||||
}
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "URI without fuzz for %s is \"%s\"", uri, uri_for_vio);
|
||||
}
|
||||
|
||||
if ((dh = csync_vio_opendir(ctx, uri_for_vio)) == NULL) {
|
||||
if ((dh = csync_vio_opendir(ctx, uri)) == NULL) {
|
||||
if (ctx->abort) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "Aborted!");
|
||||
ctx->status_code = CSYNC_STATUS_ABORTED;
|
||||
@@ -742,8 +704,6 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
}
|
||||
|
||||
while ((dirent = csync_vio_readdir(ctx, dh))) {
|
||||
const char *path = NULL;
|
||||
size_t ulen = 0;
|
||||
int flen;
|
||||
int flag;
|
||||
|
||||
@@ -769,50 +729,19 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
continue;
|
||||
}
|
||||
|
||||
flen = asprintf(&filename, "%s/%s", uri, d_name);
|
||||
if (flen < 0) {
|
||||
if (uri[0] == '\0') {
|
||||
filename = c_strdup(d_name);
|
||||
flen = strlen(d_name);
|
||||
} else {
|
||||
flen = asprintf(&filename, "%s/%s", uri, d_name);
|
||||
}
|
||||
if (flen < 0 || !filename) {
|
||||
csync_vio_file_stat_destroy(dirent);
|
||||
dirent = NULL;
|
||||
ctx->status_code = CSYNC_STATUS_MEMORY_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Create relative path */
|
||||
switch (ctx->current) {
|
||||
case LOCAL_REPLICA:
|
||||
ulen = strlen(ctx->local.uri) + 1;
|
||||
break;
|
||||
case REMOTE_REPLICA:
|
||||
ulen = strlen(ctx->remote.uri) + 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (((size_t)flen) < ulen) {
|
||||
csync_vio_file_stat_destroy(dirent);
|
||||
dirent = NULL;
|
||||
ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
path = filename + ulen;
|
||||
|
||||
/* skip ".csync_journal.db" and ".csync_journal.db.ctmp" */
|
||||
/* Isn't this done via csync_exclude already? */
|
||||
if (c_streq(path, ".csync_journal.db")
|
||||
|| c_streq(path, ".csync_journal.db.ctmp")
|
||||
|| c_streq(path, ".csync_journal.db.ctmp-journal")
|
||||
|| c_streq(path, ".csync-progressdatabase")
|
||||
|| c_streq(path, ".csync_journal.db-shm")
|
||||
|| c_streq(path, ".csync_journal.db-wal")
|
||||
|| c_streq(path, ".csync_journal.db-journal")) {
|
||||
csync_vio_file_stat_destroy(dirent);
|
||||
dirent = NULL;
|
||||
SAFE_FREE(filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Only for the local replica we have to stat(), for the remote one we have all data already */
|
||||
if (ctx->replica == LOCAL_REPLICA) {
|
||||
res = csync_vio_stat(ctx, filename, dirent);
|
||||
|
||||
@@ -23,38 +23,36 @@
|
||||
|
||||
#include "csync_private.h"
|
||||
|
||||
static void setup(void **state) {
|
||||
static int setup(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
*state = csync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup_module(void **state) {
|
||||
static int setup_module(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "dummy://foo/bar");
|
||||
|
||||
csync_init(csync);
|
||||
csync_init(csync, "foo");
|
||||
*state = csync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void teardown(void **state) {
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
@@ -66,10 +64,9 @@ static void teardown(void **state) {
|
||||
rc = system("rm -rf /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("rm -rf /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_csync_commit(void **state)
|
||||
@@ -97,10 +94,10 @@ static void check_csync_commit_dummy(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(check_csync_commit, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_commit_dummy, setup_module, teardown),
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(check_csync_commit, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_commit_dummy, setup_module, teardown),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ static void check_csync_create(void **state)
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
csync_create(&csync, "/tmp/csync1", "/tmp/csync2");
|
||||
csync_create(&csync, "/tmp/csync1");
|
||||
|
||||
rc = csync_destroy(csync);
|
||||
assert_int_equal(rc, 0);
|
||||
@@ -50,11 +50,11 @@ static void check_csync_create(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test(check_csync_destroy_null),
|
||||
unit_test(check_csync_create),
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(check_csync_destroy_null),
|
||||
cmocka_unit_test(check_csync_create),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,19 +29,20 @@
|
||||
|
||||
#define EXCLUDE_LIST_FILE SOURCEDIR"/../sync-exclude.lst"
|
||||
|
||||
static void setup(void **state) {
|
||||
static int setup(void **state) {
|
||||
CSYNC *csync;
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
*state = csync;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup_init(void **state) {
|
||||
static int setup_init(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
rc = csync_exclude_load(EXCLUDE_LIST_FILE, &(csync->excludes));
|
||||
assert_int_equal(rc, 0);
|
||||
@@ -59,9 +60,10 @@ static void setup_init(void **state) {
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = csync;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void teardown(void **state) {
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
@@ -74,6 +76,8 @@ static void teardown(void **state) {
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_csync_exclude_add(void **state)
|
||||
@@ -143,6 +147,17 @@ static void check_csync_excluded(void **state)
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "subdir/.csync_journal.db", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
|
||||
/* also the new form of the database name */
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "._sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "._sync_5bdd60bdfcfa.db.ctmp", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "._sync_5bdd60bdfcfa.db-shm", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "subdir/._sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
|
||||
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
|
||||
|
||||
|
||||
/* pattern ]*.directory - ignore and remove */
|
||||
rc = csync_excluded_no_ctx(csync->excludes, "my.~directory", CSYNC_FTW_TYPE_FILE);
|
||||
@@ -380,16 +395,16 @@ static void check_csync_exclude_expand_escapes(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(check_csync_exclude_add, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_exclude_load, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_excluded, setup_init, teardown),
|
||||
unit_test_setup_teardown(check_csync_excluded_traversal, setup_init, teardown),
|
||||
unit_test_setup_teardown(check_csync_pathes, setup_init, teardown),
|
||||
unit_test_setup_teardown(check_csync_is_windows_reserved_word, setup_init, teardown),
|
||||
unit_test_setup_teardown(check_csync_excluded_performance, setup_init, teardown),
|
||||
unit_test(check_csync_exclude_expand_escapes),
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(check_csync_exclude_add, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_exclude_load, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_excluded, setup_init, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_excluded_traversal, setup_init, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_pathes, setup_init, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_is_windows_reserved_word, setup_init, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_excluded_performance, setup_init, teardown),
|
||||
cmocka_unit_test(check_csync_exclude_expand_escapes),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -23,37 +23,33 @@
|
||||
|
||||
#include "csync_private.h"
|
||||
|
||||
static void setup(void **state) {
|
||||
static int setup(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
*state = csync;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup_module(void **state) {
|
||||
static int setup_module(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "dummy://foo/bar");
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
*state = csync;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void teardown(void **state) {
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
@@ -65,28 +61,28 @@ static void teardown(void **state) {
|
||||
rc = system("rm -rf /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("rm -rf /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_csync_init(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
|
||||
csync_init(csync);
|
||||
csync_init(csync, "");
|
||||
|
||||
assert_int_equal(csync->status & CSYNC_STATUS_INIT, 1);
|
||||
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(check_csync_init, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_init, setup_module, teardown),
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(check_csync_init, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_init, setup_module, teardown),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,22 +26,21 @@
|
||||
#include "csync_log.c"
|
||||
#include "c_private.h"
|
||||
|
||||
static void setup(void **state) {
|
||||
static int setup(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("mkdir -p /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
*state = csync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void teardown(void **state) {
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
@@ -53,10 +52,9 @@ static void teardown(void **state) {
|
||||
rc = system("rm -rf /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = system("rm -rf /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_log_callback(int verbosity,
|
||||
@@ -140,11 +138,11 @@ static void check_logging(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test(check_set_log_level),
|
||||
unit_test(check_set_auth_callback),
|
||||
unit_test_setup_teardown(check_logging, setup, teardown),
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(check_set_log_level),
|
||||
cmocka_unit_test(check_set_auth_callback),
|
||||
cmocka_unit_test_setup_teardown(check_logging, setup, teardown),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -48,10 +48,10 @@ static void check_csync_normalize_etag(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test(check_csync_normalize_etag),
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(check_csync_normalize_etag),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#define TESTDB "/tmp/check_csync1/test.db"
|
||||
|
||||
static void setup(void **state) {
|
||||
static int setup(void **state) {
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
|
||||
@@ -36,7 +36,7 @@ static void setup(void **state) {
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
|
||||
csync->statedb.file = c_strdup( TESTDB );
|
||||
*state = csync;
|
||||
@@ -47,9 +47,11 @@ static void setup(void **state) {
|
||||
|
||||
rc = sqlite3_close(db);
|
||||
assert_int_equal(rc, SQLITE_OK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void teardown(void **state) {
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
|
||||
@@ -60,6 +62,8 @@ static void teardown(void **state) {
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_csync_statedb_load(void **state)
|
||||
@@ -116,11 +120,11 @@ static void check_csync_statedb_close(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(check_csync_statedb_load, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_statedb_close, setup, teardown),
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(check_csync_statedb_load, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_statedb_close, setup, teardown),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,23 +27,19 @@
|
||||
|
||||
|
||||
|
||||
static void setup(void **state)
|
||||
static int setup(void **state)
|
||||
{
|
||||
CSYNC *csync;
|
||||
int rc = 0;
|
||||
|
||||
rc = system("rm -rf /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("rm -rf /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("mkdir -p /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("mkdir -p /tmp/check_csync");
|
||||
assert_int_equal(rc, 0);
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
csync_init(csync);
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
csync_init(csync, TESTDB);
|
||||
|
||||
sqlite3 *db = NULL;
|
||||
rc = sqlite3_open_v2(TESTDB, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
|
||||
@@ -55,9 +51,11 @@ static void setup(void **state)
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = csync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup_db(void **state)
|
||||
static int setup_db(void **state)
|
||||
{
|
||||
char *errmsg;
|
||||
int rc = 0;
|
||||
@@ -93,10 +91,12 @@ static void setup_db(void **state)
|
||||
assert_int_equal(rc, SQLITE_OK);
|
||||
|
||||
sqlite3_close(db);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void teardown(void **state) {
|
||||
static int teardown(void **state) {
|
||||
CSYNC *csync = *state;
|
||||
int rc = 0;
|
||||
|
||||
@@ -106,10 +106,10 @@ static void teardown(void **state) {
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("rm -rf /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("rm -rf /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -210,15 +210,15 @@ static void check_csync_statedb_get_stat_by_inode_not_found(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(check_csync_statedb_query_statement, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_statedb_drop_tables, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_statedb_insert_metadata, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_statedb_write, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_statedb_get_stat_by_hash_not_found, setup_db, teardown),
|
||||
unit_test_setup_teardown(check_csync_statedb_get_stat_by_inode_not_found, setup_db, teardown),
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(check_csync_statedb_query_statement, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_statedb_drop_tables, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_statedb_insert_metadata, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_statedb_write, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_statedb_get_stat_by_hash_not_found, setup_db, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_statedb_get_stat_by_inode_not_found, setup_db, teardown),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ static void statedb_insert_metadata(sqlite3 *db)
|
||||
}
|
||||
}
|
||||
|
||||
static void setup(void **state)
|
||||
static int setup(void **state)
|
||||
{
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
@@ -91,10 +91,8 @@ static void setup(void **state)
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("mkdir -p /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
|
||||
csync_init(csync);
|
||||
csync_create(&csync, "/tmp/check_csync1");
|
||||
csync_init(csync, TESTDB);
|
||||
|
||||
/* Create a new db with metadata */
|
||||
sqlite3 *db;
|
||||
@@ -111,9 +109,11 @@ static void setup(void **state)
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = csync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup_ftw(void **state)
|
||||
static int setup_ftw(void **state)
|
||||
{
|
||||
CSYNC *csync;
|
||||
int rc;
|
||||
@@ -122,10 +122,8 @@ static void setup_ftw(void **state)
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("mkdir -p /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("mkdir -p /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
csync_create(&csync, "/tmp", "/tmp");
|
||||
csync_init(csync);
|
||||
csync_create(&csync, "/tmp");
|
||||
csync_init(csync, TESTDB);
|
||||
|
||||
sqlite3 *db = NULL;
|
||||
rc = sqlite3_open_v2(TESTDB, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
|
||||
@@ -139,9 +137,11 @@ static void setup_ftw(void **state)
|
||||
|
||||
csync->statedb.file = c_strdup( TESTDB );
|
||||
*state = csync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void teardown(void **state)
|
||||
static int teardown(void **state)
|
||||
{
|
||||
CSYNC *csync = *state;
|
||||
int rc;
|
||||
@@ -151,9 +151,11 @@ static void teardown(void **state)
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
*state = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void teardown_rm(void **state) {
|
||||
static int teardown_rm(void **state) {
|
||||
int rc;
|
||||
|
||||
teardown(state);
|
||||
@@ -162,8 +164,8 @@ static void teardown_rm(void **state) {
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("rm -rf /tmp/check_csync1");
|
||||
assert_int_equal(rc, 0);
|
||||
rc = system("rm -rf /tmp/check_csync2");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* create a file stat, caller must free memory */
|
||||
@@ -430,19 +432,19 @@ static void check_csync_ftw_failing_fn(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(check_csync_detect_update, setup, teardown_rm),
|
||||
unit_test_setup_teardown(check_csync_detect_update_db_none, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_detect_update_db_eval, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_detect_update_db_rename, setup, teardown),
|
||||
unit_test_setup_teardown(check_csync_detect_update_db_new, setup, teardown_rm),
|
||||
unit_test_setup_teardown(check_csync_detect_update_null, setup, teardown_rm),
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(check_csync_detect_update, setup, teardown_rm),
|
||||
cmocka_unit_test_setup_teardown(check_csync_detect_update_db_none, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_detect_update_db_eval, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_detect_update_db_rename, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(check_csync_detect_update_db_new, setup, teardown_rm),
|
||||
cmocka_unit_test_setup_teardown(check_csync_detect_update_null, setup, teardown_rm),
|
||||
|
||||
unit_test_setup_teardown(check_csync_ftw, setup_ftw, teardown_rm),
|
||||
unit_test_setup_teardown(check_csync_ftw_empty_uri, setup_ftw, teardown_rm),
|
||||
unit_test_setup_teardown(check_csync_ftw_failing_fn, setup_ftw, teardown_rm),
|
||||
cmocka_unit_test_setup_teardown(check_csync_ftw, setup_ftw, teardown_rm),
|
||||
cmocka_unit_test_setup_teardown(check_csync_ftw_empty_uri, setup_ftw, teardown_rm),
|
||||
cmocka_unit_test_setup_teardown(check_csync_ftw_failing_fn, setup_ftw, teardown_rm),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,11 +43,11 @@ static void check_csync_memstat(void **state)
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
const UnitTest tests[] = {
|
||||
unit_test(check_csync_instruction_str),
|
||||
unit_test(check_csync_memstat),
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(check_csync_instruction_str),
|
||||
cmocka_unit_test(check_csync_memstat),
|
||||
};
|
||||
|
||||
return run_tests(tests);
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -457,6 +457,7 @@ sub traverse( $$;$ )
|
||||
|
||||
$isHere = 1 if( $acceptConflicts && !$isHere && $f =~ /_conflict/ );
|
||||
$isHere = 1 if( $f =~ /\.csync/ );
|
||||
$isHere = 1 if( $f =~ /\._sync_/ );
|
||||
assert( $isHere, "Filename local, but not remote: $f" );
|
||||
}
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ assertLocalAndRemoteDir( 'remoteToLocal1', 1);
|
||||
|
||||
printInfo("simulate a owncloud 5 update by removing all the fileid");
|
||||
## simulate a owncloud 5 update by removing all the fileid
|
||||
system( "sqlite3 " . localDir() . ".csync_journal.db \"UPDATE metadata SET fileid='';\"");
|
||||
system( "sqlite3 " . localDir() . "._sync_*.db \"UPDATE metadata SET fileid='';\"");
|
||||
#refresh the ids
|
||||
csync();
|
||||
assertLocalAndRemoteDir( 'remoteToLocal1', 1);
|
||||
|
||||
@@ -61,7 +61,7 @@ sub getETagFromJournal($$)
|
||||
{
|
||||
my ($name,$num) = @_;
|
||||
|
||||
my $sql = "sqlite3 " . localDir() . ".csync_journal.db \"SELECT md5 FROM metadata WHERE path='$name';\"";
|
||||
my $sql = "sqlite3 " . localDir() . "._sync_*.db \"SELECT md5 FROM metadata WHERE path='$name';\"";
|
||||
open(my $fh, '-|', $sql) or die $!;
|
||||
my $etag = <$fh>;
|
||||
close $fh;
|
||||
|
||||
@@ -37,8 +37,8 @@ sub assertCsyncJournalOk {
|
||||
my $path = $_[0];
|
||||
|
||||
# FIXME: should test also remoteperm but it's not working with owncloud6
|
||||
# my $cmd = 'sqlite3 ' . $path . '.csync_journal.db "SELECT count(*) from metadata where length(remotePerm) == 0 or length(fileId) == 0"';
|
||||
my $cmd = 'sqlite3 ' . $path . '.csync_journal.db "SELECT count(*) from metadata where length(fileId) == 0"';
|
||||
# my $cmd = 'sqlite3 ' . $path . '._sync_*.db "SELECT count(*) from metadata where length(remotePerm) == 0 or length(fileId) == 0"';
|
||||
my $cmd = 'sqlite3 ' . $path . '._sync_*.db "SELECT count(*) from metadata where length(fileId) == 0"';
|
||||
my $result = `$cmd`;
|
||||
assert($result == "0");
|
||||
}
|
||||
@@ -170,14 +170,14 @@ assertLocalAndRemoteDir( '', 0);
|
||||
|
||||
#######################################################################
|
||||
printInfo( "move a directory in a outside read only folder" );
|
||||
system("sqlite3 " . localDir().'.csync_journal.db .dump');
|
||||
system("sqlite3 " . localDir().'._sync_*.db .dump');
|
||||
|
||||
#Missing directory should be restored
|
||||
#new directory should be uploaded
|
||||
system("mv " . localDir().'readonlyDirectory_PERM_M_/subdir_PERM_CK_ ' . localDir().'normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_' );
|
||||
|
||||
csync();
|
||||
system("sqlite3 " . localDir().'.csync_journal.db .dump');
|
||||
system("sqlite3 " . localDir().'._sync_*.db .dump');
|
||||
assertCsyncJournalOk(localDir());
|
||||
|
||||
# old name restored
|
||||
@@ -229,7 +229,38 @@ system("rm -r " . localDir(). "readonlyDirectory_PERM_M_/moved_PERM_CK_");
|
||||
|
||||
assertLocalAndRemoteDir( '', 0);
|
||||
|
||||
system("sqlite3 " . localDir().'.csync_journal.db .dump');
|
||||
system("sqlite3 " . localDir().'._sync_*.db .dump');
|
||||
|
||||
|
||||
#######################################################################
|
||||
printInfo( "multiple restores of a file create different conflict files" );
|
||||
|
||||
system("sleep 1"); #make sure changes have different mtime
|
||||
|
||||
system("echo 'modified_1' > ". localDir() . "readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN_.data");
|
||||
|
||||
#do the sync
|
||||
csync();
|
||||
assertCsyncJournalOk(localDir());
|
||||
|
||||
system("sleep 1"); #make sure changes have different mtime
|
||||
|
||||
system("echo 'modified_2' > ". localDir() . "readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN_.data");
|
||||
|
||||
#do the sync
|
||||
csync();
|
||||
assertCsyncJournalOk(localDir());
|
||||
|
||||
# there should be two conflict files
|
||||
# TODO check that the conflict file has the right content
|
||||
my @conflicts = glob(localDir().'readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN__conflict-*.data' );
|
||||
assert( scalar @conflicts == 2 );
|
||||
# remove the conflicts for the next assertLocalAndRemoteDir
|
||||
system("rm " . localDir().'readonlyDirectory_PERM_M_/canotBeModified_PERM_DVN__conflict-*.data' );
|
||||
|
||||
### Both side should still be the same
|
||||
assertLocalAndRemoteDir( '', 0);
|
||||
|
||||
|
||||
|
||||
cleanup();
|
||||
|
||||
@@ -48,7 +48,7 @@ static void setup(void **state)
|
||||
rc = system("rm -rf /tmp/csync_test");
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
csync_create(&csync, "/tmp/csync1", "/tmp/csync2");
|
||||
csync_create(&csync, "/tmp/csync1");
|
||||
|
||||
csync->replica = LOCAL_REPLICA;
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ static void setup_testenv(void **state) {
|
||||
statevar *mystate = malloc( sizeof(statevar) );
|
||||
mystate->result = NULL;
|
||||
|
||||
csync_create(&(mystate->csync), "/tmp/csync1", "/tmp/csync2");
|
||||
csync_create(&(mystate->csync), "/tmp/csync1");
|
||||
|
||||
mystate->csync->replica = LOCAL_REPLICA;
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ a synchronization process.
|
||||
|
||||
Before the 1.3.0 release of the Desktop Client, the synchronization process
|
||||
might create false conflict files if time deviates. Original and changed files
|
||||
conflict only in their timestamp, but not in their content. This behaviour was
|
||||
conflict only in their timestamp, but not in their content. This behavior was
|
||||
changed to employ a binary check if files differ.
|
||||
|
||||
Like files, directories also hold a unique ID that changes whenever one of the
|
||||
@@ -153,7 +153,8 @@ By default, the ownCloud Client ignores the following files:
|
||||
|
||||
* Files matched by one of the patterns defined in the Ignored Files Editor
|
||||
* Files containing characters that do not work on certain file systems ``(`\, /, :, ?, *, ", >, <, |`)``.
|
||||
* Files starting with ``.csync_journal.db``, as these files are reserved for journalling.
|
||||
* Files starting with ``._sync_xxxxxxx.db`` and the old format ``.csync_journal.db``,
|
||||
as these files are reserved for journalling.
|
||||
|
||||
If a pattern selected using a checkbox in the `ignoredFilesEditor-label` (or if
|
||||
a line in the exclude file starts with the character ``]`` directly followed by
|
||||
|
||||
+3
-20
@@ -3,7 +3,7 @@ The Automatic Updater
|
||||
=====================
|
||||
|
||||
The Automatic Updater ensures that you always have the
|
||||
latest features and bugfixes for your ownCloud synchronization client.
|
||||
latest features and bug fixes for your ownCloud synchronization client.
|
||||
|
||||
The Automatic Updater updates only on Mac OS X and Windows computers; Linux
|
||||
users only need to use their normal package managers. However, on Linux systems
|
||||
@@ -49,7 +49,6 @@ the Linux operating system do not perform any updates on their own. The client
|
||||
will inform you (``Settings -> General -> Updates``) when an update is
|
||||
available.
|
||||
|
||||
|
||||
Preventing Automatic Updates
|
||||
----------------------------
|
||||
|
||||
@@ -110,24 +109,8 @@ To prevent automatic updates and disallow manual overrides:
|
||||
Preventing Automatic Updates in Mac OS X Environments
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can disable the automatic update mechanism in Mac OS X operating systems
|
||||
using the system-wide ``.plist`` file. To access this file:
|
||||
|
||||
1. Go to this directory::
|
||||
|
||||
/Library/Preferences/
|
||||
|
||||
2. Locate and open the following file::
|
||||
|
||||
com.owncloud.desktopclient.plist
|
||||
|
||||
3. Add a new root level item of type ``bool``.
|
||||
|
||||
4. Name the item ``skipUpdateCheck``.
|
||||
|
||||
5. Set the item to ``true``.
|
||||
|
||||
Alternatively, you can copy the file
|
||||
You can disable the automatic update mechanism, in the Mac OS X operating system,
|
||||
by copying the file
|
||||
``owncloud.app/Contents/Resources/deny_autoupdate_com.owncloud.desktopclient.plist``
|
||||
to ``/Library/Preferences/com.owncloud.desktopclient.plist``.
|
||||
|
||||
|
||||
+34
-11
@@ -42,7 +42,8 @@ repositories`_ to see all the Linux client repos.
|
||||
echo 'deb-src
|
||||
http://download.opensuse.org/repositories/isv:/ownCloud:/desktop/Debian_8.0/ /' >> /etc/apt/sources.list.d/owncloud-client.list
|
||||
|
||||
2. Install the dependencies using the following commands for your specific Linux distribution:
|
||||
2. Install the dependencies using the following commands for your specific Linux
|
||||
distribution. Make sure the repositories for source packages are enabled.
|
||||
|
||||
* Debian/Ubuntu: ``apt-get update; apt-get build-dep owncloud-client``
|
||||
* openSUSE/SLES: ``zypper ref; zypper si -d owncloud-client``
|
||||
@@ -53,7 +54,7 @@ repositories`_ to see all the Linux client repos.
|
||||
Mac OS X
|
||||
--------
|
||||
|
||||
In additon to needing XCode (along with the command line tools), developing in
|
||||
In addition to needing XCode (along with the command line tools), developing in
|
||||
the Mac OS X environment requires extra dependencies. You can install these
|
||||
dependencies through MacPorts_ or Homebrew_. These dependencies are required
|
||||
only on the build machine, because non-standard libs are deployed in the app
|
||||
@@ -65,31 +66,45 @@ recipes.
|
||||
|
||||
To set up your build environment for development using HomeBrew_:
|
||||
|
||||
1. Add the ownCloud repository using the following command::
|
||||
1. Install Xcode
|
||||
2. Install Xcode command line tools::
|
||||
xcode-select --install
|
||||
|
||||
3. Install homebrew::
|
||||
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||
|
||||
4. Add the ownCloud repository using the following command::
|
||||
|
||||
brew tap owncloud/owncloud
|
||||
|
||||
2. Install any missing dependencies::
|
||||
5. Install a Qt5 version with qtwebkit support::
|
||||
|
||||
brew install qt5 --with-qtwebkit
|
||||
|
||||
6. Install any missing dependencies::
|
||||
|
||||
brew install $(brew deps owncloud-client)
|
||||
|
||||
3. Add Qt from brew to the path::
|
||||
7. Add Qt from brew to the path::
|
||||
|
||||
export PATH=/usr/local/Cellar/qt5/5.x.y/bin/qmake
|
||||
export PATH=/usr/local/Cellar/qt5/5.x.y/bin:$PATH
|
||||
|
||||
Where ``x.z`` is the current version of Qt 5 that brew has installed
|
||||
Where ``x.y`` is the current version of Qt 5 that brew has installed
|
||||
on your machine.
|
||||
8. Install qtkeychain from here: git clone https://github.com/frankosterfeld/qtkeychain.git
|
||||
make sure you make the same install prefix as later while building the client e.g. -
|
||||
``DCMAKE_INSTALL_PREFIX=/Path/to/client-install``
|
||||
|
||||
5. For compilation of the client, follow the :ref:`generic-build-instructions`.
|
||||
9. For compilation of the client, follow the :ref:`generic-build-instructions`.
|
||||
|
||||
6. Install the Packages_ package creation tool.
|
||||
10. Install the Packages_ package creation tool.
|
||||
|
||||
7. In the build directory, run ``admin/osx/create_mac.sh <build_dir>
|
||||
11. In the build directory, run ``admin/osx/create_mac.sh <build_dir>
|
||||
<install_dir>``. If you have a developer signing certificate, you can specify
|
||||
its Common Name as a third parameter (use quotes) to have the package
|
||||
signed automatically.
|
||||
|
||||
.. note:: Contrary to earlier versions, ownCloud 1.7 and later are packaged
|
||||
.. note:: Contrary to earlier versions, ownCloud 1.7 and later are packaged
|
||||
as a ``pkg`` installer. Do not call "make package" at any time when
|
||||
compiling for OS X, as this will build a disk image, and will not
|
||||
work correctly.
|
||||
@@ -233,6 +248,14 @@ To build the most up-to-date version of the client:
|
||||
.. note:: On Mac OS X, you need to specify ``-DCMAKE_INSTALL_PREFIX=target``,
|
||||
where ``target`` is a private location, i.e. in parallel to your build
|
||||
dir by specifying ``../install``.
|
||||
|
||||
..note:: qtkeychain must be compiled with the same prefix e.g CMAKE_INSTALL_PREFIX=/Users/path/to/client/install/
|
||||
|
||||
.. note:: Example:: cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5 -DCMAKE_INSTALL_PREFIX=/Users/path/to/client/install/ -D_OPENSSL_LIBDIR=/usr/local/opt/openssl/lib/ -D_OPENSSL_INCLUDEDIR=/usr/local/opt/openssl/include/ -DOPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include/ -DNO_SHIBBOLETH=1
|
||||
|
||||
.. note:: Example:: cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5 -DCMAKE_INSTALL_PREFIX=/Users/path/to/client/install/ -D_OPENSSL_LIBDIR=/usr/local/opt/openssl/lib/ -D_OPENSSL_INCLUDEDIR=/usr/local/opt/openssl/include/ -D_OPENSSL_VERSION=1.0.2a -DOPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include/ -DNO_SHIBBOLETH=1
|
||||
|
||||
qtkeychain must be compiled with the same prefix e.g CMAKE_INSTALL_PREFIX=/Users/path/to/client/install/ .
|
||||
|
||||
4. Call ``make``.
|
||||
|
||||
|
||||
+8
-3
@@ -16,15 +16,20 @@ format. You can overwrite changes using the ownCloud configuration dialog.
|
||||
.. note:: Use caution when making changes to the ownCloud Client configuration
|
||||
file. Incorrect settings can produce unintended results.
|
||||
|
||||
You can change the following configuration settings (must be under the ``[ownCloud]`` section)
|
||||
You can change the following configuration settings in the ``[ownCloud]`` section:
|
||||
|
||||
- ``remotePollInterval`` (default: ``30000``) -- Specifies the poll time for the remote repository in milliseconds.
|
||||
|
||||
- ``maxLogLines`` (default: ``20000``) -- Specifies the maximum number of log lines displayed in the log window.
|
||||
- ``forceSyncInterval`` (default: ``7200000``) -- The duration of no activity after which a synchronization run shall be triggered automatically.
|
||||
|
||||
- ``notificationRefreshInterval`` (default: ``300000``) -- Specifies the default interval of checking for new server notifications in milliseconds.
|
||||
|
||||
You can change the following configuration settings in the ``[General]`` section:
|
||||
|
||||
- ``chunkSize`` (default: ``5242880``) -- Specifies the chunk size of uploaded files in bytes.
|
||||
|
||||
- ``promptDeleteAllFiles`` (default: ``true``) -- If a UI prompt should ask for confirmation if it was detected that all files and folders were deleted.
|
||||
|
||||
- ``notificationRefreshInterval`` (default``300,000``) -- Specifies the default interval of checking for new server notifications in milliseconds.
|
||||
- ``maxLogLines`` (default: ``20000``) -- Specifies the maximum number of log lines displayed in the log window.
|
||||
|
||||
- ``timeout`` (default: ``300``) -- The timeout for network connections in seconds.
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
Sync Algorithm
|
||||
==============
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
This is a technical description of the synchronization (sync) algorithm used by the ownCloud client.
|
||||
|
||||
The sync algorithm is the thing that looks at the local and remote file system trees and the sync journal and decides which steps need to be taken to bring the two trees into synchronization. It's different from the propagator, whose job it is to actually execute these steps.
|
||||
|
||||
|
||||
Definitions
|
||||
-----------
|
||||
|
||||
- local tree: The files and directories on the local file system that shall be kept in sync with the remote tree.
|
||||
- remote tree: The files and directories on the ownCloud server that shall be kept in sync with the local tree.
|
||||
- sync journal (journal): A snapshot of file and directory metadata that the sync algorithm uses as a baseline to detect local or remote changes. Typically stored in a database.
|
||||
- file and directory metadata:
|
||||
- mtimes
|
||||
- sizes
|
||||
- inodes (journal and local only): Representation of filesystem object. Useful for rename detection.
|
||||
- etags (journal and remote only): The server assigns a new etag when a file or directory changes.
|
||||
- checksums (journal and remote only): Checksum algorithm applied to a file's contents.
|
||||
- permissions (journal and remote only)
|
||||
|
||||
|
||||
Phases
|
||||
------
|
||||
|
||||
### Discovery (aka Update)
|
||||
|
||||
The discovery phase collects file and directory metadata from the local and remote trees, detecting differences between each tree and the journal.
|
||||
|
||||
Afterwards, we have two trees that tell us what happened relative to the journal. But there may still be conflicts if something happened to an entity both locally and on the remote.
|
||||
|
||||
- Input: file system, server data, journal
|
||||
- Output: two c_rbtree_t*, representing the local and remote trees
|
||||
|
||||
- Note on remote discovery: Since a change to a file on the server causes the etags of all parent folders to change, folders with an unchanged etag can be read from the journal directly and don't need to be walked into.
|
||||
|
||||
- Details
|
||||
- csync_update() uses csync_ftw() on the local and remote trees, one after the other.
|
||||
- csync_ftw() iterates through the entities in a tree and calls csync_walker() for each.
|
||||
- csync_walker() calls _csync_detect_update() on each.
|
||||
- _csync_detect_update() compares the item to its journal entry (if any) to detect new, changed or renamed files. This is the main function of this pass.
|
||||
|
||||
|
||||
|
||||
### Reconcile
|
||||
|
||||
The reconcile phase compares and adjusts the local and remote trees (in both directions), detecting conflicts.
|
||||
|
||||
Afterwards, there are still two trees, but conflicts are marked in them.
|
||||
|
||||
- Input: c_rbtree_t* for the local and remote trees, journal (for some rename-related queries)
|
||||
- Output: changes c_rbtree_t* in-place
|
||||
|
||||
- Details
|
||||
- csync_reconcile() runs csync_reconcile_updates() for the local and remote trees, one after the other.
|
||||
- csync_reconcile_updates() uses c_rbtree_walk() to iterate through the entries, calling _csync_merge_algorithm_visitor() for each.
|
||||
- _csync_merge_algorithm_visitor() checks whether the other tree also has an entry for that node and merges the actions, detecting conflicts. This is the main function of this pass.
|
||||
|
||||
|
||||
### Post-Reconcile
|
||||
|
||||
The post-reconcile phase merges the two trees into one set of SyncFileItems.
|
||||
|
||||
Afterwards, there is a list of items that can tell the propagator what needs to be done.
|
||||
|
||||
- Input: c_rbtree_t* for the local and remote trees
|
||||
- Output: QMap<QString, SyncFileItemPtr>
|
||||
|
||||
- Note that some "propagations", specifically cheap metadata-only updates, are already done at this stage.
|
||||
|
||||
- Details
|
||||
- csync_walk_local_tree() and csync_walk_remote_tree() are called.
|
||||
- They use _csync_walk_tree() to run SyncEngine::treewalkFile() on each entry.
|
||||
- treewalkFile() creates and fills SyncFileItems for each entry, ensuring that each file only has a single instance. This is the main function of this pass.
|
||||
|
||||
|
||||
See Also
|
||||
--------
|
||||
|
||||
An overview of the propagation steps is still missing. The sync protocol is documented at https://github.com/cernbox/smashbox/blob/master/protocol/protocol.md.
|
||||
+9
-6
@@ -1,17 +1,20 @@
|
||||
FAQ
|
||||
===
|
||||
|
||||
**Issue:**
|
||||
|
||||
Some files are continuously uploaded to the server, even when they are not modified.
|
||||
|
||||
**Resolution:**
|
||||
------------------------------------------------------------------------------------
|
||||
|
||||
It is possible that another program is changing the modification date of the file.
|
||||
|
||||
If the file is uses the ``.eml`` extension, Windows automatically and
|
||||
continually changes all files, unless you remove
|
||||
``\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\PropertyHandlers``
|
||||
from the windows registry.
|
||||
|
||||
See http://petersteier.wordpress.com/2011/10/22/windows-indexer-changes-modification-dates-of-eml-files/ for more information.
|
||||
|
||||
Syncing breaks when attempting to sync deeper than 50 sub-directories, but the sync client does not report an error (RC=0)
|
||||
--------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
The sync client has been intentionally limited to sync no deeper than
|
||||
fifty sub-directories, to help prevent memory problems.
|
||||
Unfortunately, it, *currently*, does not report an error when this occurs.
|
||||
However, a UI notification is planned for a future release of ownCloud.
|
||||
|
||||
@@ -12,7 +12,7 @@ Desktop Sync client enables you to:
|
||||
Your files are always automatically synchronized between your ownCloud server
|
||||
and local PC.
|
||||
|
||||
Because of various technical issues, desktop sync clients older than 1.7 will
|
||||
Because of various technical issues, desktop sync clients older than 2.2.1 will
|
||||
not allowed to connect and sync with the ownCloud 8.1+ server. It is highly
|
||||
recommended to keep your client updated.
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ If no client is configured, or if you choose to use a different user to synchron
|
||||
you can specify the user
|
||||
password setting with the usual URL pattern. For example::
|
||||
|
||||
$ owncloudcmd / https://carla:secret@server/owncloud/remote.php/webdav/
|
||||
$ owncloudcmd /home/user/my_sync_folder https://carla:secret@server/owncloud/remote.php/webdav/
|
||||
|
||||
To synchronize the ownCloud directory ``Music`` to the local directory
|
||||
``media/music``, through a proxy listening on port ``8080``, and on a gateway
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; version 2 of the License.
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
|
||||
@@ -138,7 +138,7 @@ Network
|
||||
|
||||
.. index:: proxy settings, SOCKS, bandwith, throttling, limiting
|
||||
|
||||
This tab consollidates ``Proxy Settings`` and ``Bandwith Limiting``:
|
||||
This tab consolidates ``Proxy Settings`` and ``Bandwith Limiting``:
|
||||
|
||||
.. image:: images/settings_network.png
|
||||
:scale: 50 %
|
||||
@@ -152,7 +152,7 @@ Proxy Settings
|
||||
On Linux, this will only pick up the value of the variable ``http_proxy``.
|
||||
* ``Specify proxy manually as``: Allows to specify custom proxy settings.
|
||||
If you require to go through a HTTP(S) proxy server such as Squid or Microsoft
|
||||
Forefront TMG, pick ``HTTP(S)``. ``SOCKSv5`` on the other hand is particulary
|
||||
Forefront TMG, pick ``HTTP(S)``. ``SOCKSv5`` on the other hand is particularly
|
||||
useful in special company LAN setups, or in combination with the OpenSSH
|
||||
dynamic application level forwarding feature (see ``ssh -D``).
|
||||
* ``Host``: Enter the host name or IP address of your proxy server, followed
|
||||
|
||||
@@ -37,6 +37,10 @@ Operating system:
|
||||
|
||||
OS language:
|
||||
|
||||
Qt version used by client package (Linux only, see also Settings dialog):
|
||||
|
||||
Client package (From ownCloud or distro) (Linux only):
|
||||
|
||||
Installation path of client:
|
||||
|
||||
### Logs
|
||||
|
||||
+299
-4
@@ -355,6 +355,297 @@ X-GNOME-Autostart-Delay=3
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
Comment[oc]=@APPLICATION_NAME@ sincronizacion del client
|
||||
GenericName[oc]=Dorsièr de Sincronizacion
|
||||
@@ -445,10 +736,10 @@ Comment[cs_CZ]=@APPLICATION_NAME@ počítačový synchronizační klient
|
||||
GenericName[cs_CZ]=Synchronizace adresáře
|
||||
Name[cs_CZ]=@APPLICATION_NAME@ počítačový synchronizační klient
|
||||
Icon[cs_CZ]=@APPLICATION_EXECUTABLE@
|
||||
Comment[ru]=Настольный клиент синхронизации @НАЗВАНИЕ_ПРИЛОЖЕНИЯ@
|
||||
GenericName[ru]=Синхронизация папки
|
||||
Name[ru]=Настольный клиент синхронизации @НАЗВАНИЕ_ПРИЛОЖЕНИЯ@
|
||||
Icon[ru]=@ВЫПОЛНЯЕМОЕ_ПРИЛОЖЕНИЕ@
|
||||
Comment[ru]=Настольный клиент синхронизации @APPLICATION_NAME@
|
||||
GenericName[ru]=Синхронизация каталогов
|
||||
Name[ru]=Настольный клиент синхронизации @APPLICATION_NAME@
|
||||
Icon[ru]=@APPLICATION_EXECUTABLE@
|
||||
Comment[sl]=@APPLICATION_NAME@ ‒ Program za usklajevanje datotek z namizjem
|
||||
GenericName[sl]=Usklajevanje map
|
||||
Name[sl]=@APPLICATION_NAME@ ‒ Program za usklajevanje datotek z namizjem
|
||||
@@ -490,6 +781,10 @@ Comment[th_TH]=@APPLICATION_NAME@ ไคลเอนต์ประสานข
|
||||
GenericName[th_TH]=ประสานข้อมูลโฟลเดอร์
|
||||
Name[th_TH]= @APPLICATION_NAME@ ไคลเอนต์ประสานข้อมูลเดสก์ท็อป
|
||||
Icon[th_TH]=@APPLICATION_EXECUTABLE@
|
||||
Comment[es_MX]=Cliente de escritorio para sincronziación de @APPLICATION_NAME@
|
||||
GenericName[es_MX]=Sincronización de Carpetas
|
||||
Name[es_MX]=Cliente de escritorio para sincronziación de @APPLICATION_NAME@
|
||||
Icon[es_MX]=@APPLICATION_EXECUTABLE@
|
||||
Comment[nb_NO]=@APPLICATION_NAME@ skrivebordssynkroniseringsklient
|
||||
GenericName[nb_NO]=Mappesynkronisering
|
||||
Name[nb_NO]=@APPLICATION_NAME@ skrivebordssynkroniseringsklient
|
||||
|
||||
@@ -16,12 +16,13 @@ set(OC_OEM_SHARE_ICNS "${CMAKE_BINARY_DIR}/src/gui/ownCloud.icns")
|
||||
# those user-defined settings to build the plist.
|
||||
add_custom_target( mac_overlayplugin ALL
|
||||
xcodebuild -project ${CMAKE_SOURCE_DIR}/shell_integration/MacOSX/OwnCloudFinderSync/OwnCloudFinderSync.xcodeproj
|
||||
-target FinderSyncExt -configuration Release SYMROOT=${CMAKE_CURRENT_BINARY_DIR}
|
||||
OC_OEM_SHARE_ICNS=${OC_OEM_SHARE_ICNS}
|
||||
OC_APPLICATION_NAME="${APPLICATION_NAME}"
|
||||
OC_APPLICATION_REV_DOMAIN=${APPLICATION_REV_DOMAIN}
|
||||
OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX=${SOCKETAPI_TEAM_IDENTIFIER_PREFIX}
|
||||
COMMENT building Mac Overlay icons)
|
||||
-target FinderSyncExt -configuration Release "SYMROOT=${CMAKE_CURRENT_BINARY_DIR}"
|
||||
"OC_OEM_SHARE_ICNS=${OC_OEM_SHARE_ICNS}"
|
||||
"OC_APPLICATION_NAME=${APPLICATION_NAME}"
|
||||
"OC_APPLICATION_REV_DOMAIN=${APPLICATION_REV_DOMAIN}"
|
||||
"OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX=${SOCKETAPI_TEAM_IDENTIFIER_PREFIX}"
|
||||
COMMENT building Mac Overlay icons
|
||||
VERBATIM)
|
||||
add_dependencies(mac_overlayplugin ${APPLICATION_EXECUTABLE}) # for the ownCloud.icns to be generated
|
||||
|
||||
|
||||
|
||||
@@ -155,9 +155,13 @@
|
||||
{
|
||||
_shareMenuTitle = nil;
|
||||
|
||||
[_registeredDirectories removeAllObjects];
|
||||
// For some reason the FIFinderSync cache doesn't seem to be cleared for the root item when
|
||||
// we reset the directoryURLs (seen on macOS 10.12 at least).
|
||||
// First setting it to the FS root and then setting it to nil seems to work around the issue.
|
||||
[FIFinderSyncController defaultController].directoryURLs = [NSSet setWithObject:[NSURL fileURLWithPath:@"/"]];
|
||||
// This will tell Finder that this extension isn't attached to any directory
|
||||
// until we can reconnect to the sync client.
|
||||
[_registeredDirectories removeAllObjects];
|
||||
[FIFinderSyncController defaultController].directoryURLs = nil;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,5 +49,6 @@ target_link_libraries(${OWNCLOUDDOLPHINOVERLAYPLUGIN} KF5::CoreAddons KF5::KIOCo
|
||||
set(OWNCLOUDDOLPHINACTIONPLUGIN ${APPLICATION_EXECUTABLE}dolphinactionplugin)
|
||||
add_library(${OWNCLOUDDOLPHINACTIONPLUGIN} MODULE ownclouddolphinactionplugin.cpp)
|
||||
target_link_libraries(${OWNCLOUDDOLPHINACTIONPLUGIN} KF5::CoreAddons KF5::KIOCore KF5::KIOWidgets ${OWNCLOUDDOLPHINHELPER})
|
||||
install(FILES ownclouddolphinactionplugin.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} RENAME ${OWNCLOUDDOLPHINACTIONPLUGIN}.desktop)
|
||||
configure_file(ownclouddolphinactionplugin.desktop.in ${OWNCLOUDDOLPHINACTIONPLUGIN}.desktop ESCAPE_QUOTES @ONLY)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${OWNCLOUDDOLPHINACTIONPLUGIN}.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR})
|
||||
install(TARGETS ${OWNCLOUDDOLPHINACTIONPLUGIN} DESTINATION ${KDE_INSTALL_PLUGINDIR})
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <KIOCore/kfileitem.h>
|
||||
#include <KIOCore/KFileItemListProperties>
|
||||
#include <QtWidgets/QAction>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QTimer>
|
||||
#include "ownclouddolphinpluginhelper.h"
|
||||
|
||||
@@ -43,7 +44,8 @@ public:
|
||||
auto url = urls.first();
|
||||
if (!url.isLocalFile())
|
||||
return {};
|
||||
auto localFile = url.toLocalFile();
|
||||
QDir localPath(url.toLocalFile());
|
||||
auto localFile = localPath.canonicalPath();
|
||||
|
||||
const auto paths = helper->paths();
|
||||
if (!std::any_of(paths.begin(), paths.end(), [&](const QString &s) {
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
Name=OwncloudAction
|
||||
Name=@APPLICATION_NAME@Action
|
||||
ServiceTypes=KFileItemAction/Plugin
|
||||
MimeType=application/octet-stream;inode/directory;
|
||||
X-KDE-Library=ownclouddolphinactionplugin
|
||||
X-KDE-Library=@APPLICATION_EXECUTABLE@dolphinactionplugin
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <KPluginFactory>
|
||||
#include <QtNetwork/QLocalSocket>
|
||||
#include <KIOCore/kfileitem.h>
|
||||
#include <QDir>
|
||||
#include <QTimer>
|
||||
#include "ownclouddolphinpluginhelper.h"
|
||||
|
||||
@@ -46,7 +47,8 @@ public:
|
||||
return QStringList();
|
||||
if (!url.isLocalFile())
|
||||
return QStringList();
|
||||
const QByteArray localFile = url.toLocalFile().toUtf8();
|
||||
QDir localPath(url.toLocalFile());
|
||||
const QByteArray localFile = localPath.canonicalPath().toUtf8();
|
||||
|
||||
helper->sendCommand(QByteArray("RETRIEVE_FILE_STATUS:" + localFile + "\n"));
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ if( UNIX AND NOT APPLE )
|
||||
|
||||
configure_file(syncstate.py syncstate.py COPYONLY)
|
||||
configure_file(syncstate.py syncstate_nemo.py COPYONLY)
|
||||
configure_file(syncstate.py syncstate_caja.py COPYONLY)
|
||||
|
||||
# Call the setupappname.sh script to set the custom app name.
|
||||
set (cmd "${CMAKE_CURRENT_SOURCE_DIR}/setappname.sh")
|
||||
@@ -18,9 +19,17 @@ if( UNIX AND NOT APPLE )
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
ERROR_VARIABLE errors OUTPUT_VARIABLE out)
|
||||
|
||||
# Create a caja plugin script from the nautilus one.
|
||||
# cajacmd copies the syncstate.py and performs string replacement.
|
||||
set (cajacmd "${CMAKE_CURRENT_SOURCE_DIR}/createcajaplugin.sh")
|
||||
execute_process(COMMAND ${cajacmd}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
ERROR_VARIABLE errors OUTPUT_VARIABLE out)
|
||||
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/syncstate.py DESTINATION ${DATADIR}/nautilus-python/extensions RENAME syncstate-${APPLICATION_SHORTNAME}.py)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/syncstate_nemo.py DESTINATION ${DATADIR}/nemo-python/extensions RENAME syncstate-${APPLICATION_SHORTNAME}.py)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/syncstate_caja.py DESTINATION ${DATADIR}/caja-python/extensions RENAME syncstate-${APPLICATION_SHORTNAME}.py)
|
||||
|
||||
|
||||
|
||||
|
||||
Arquivo executável
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
# this script creates a plugin for caja, just by replacing
|
||||
# all occurences of Nautilus with Caja (case sensitive).
|
||||
|
||||
sed -i.org -e 's/Nautilus/Caja/g' syncstate_caja.py
|
||||
sed -i.org -e 's/nautilus/caja/g' syncstate_caja.py
|
||||
@@ -18,6 +18,7 @@
|
||||
import os
|
||||
import urllib
|
||||
import socket
|
||||
import tempfile
|
||||
|
||||
from gi.repository import GObject, Nautilus
|
||||
|
||||
@@ -43,7 +44,7 @@ def get_runtime_dir():
|
||||
try:
|
||||
return os.environ['XDG_RUNTIME_DIR']
|
||||
except KeyError:
|
||||
fallback = '/tmp/runtime-' + os.environ['USER']
|
||||
fallback = os.path.join(tempfile.gettempdir(), 'runtime-' + os.environ['USER'])
|
||||
return fallback
|
||||
|
||||
|
||||
@@ -86,22 +87,17 @@ class SocketConnect(GObject.GObject):
|
||||
def _connectToSocketServer(self):
|
||||
try:
|
||||
self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
postfix = "/" + appname + "/socket" # Should use os.path.join instead
|
||||
sock_file = get_runtime_dir() + postfix
|
||||
print ("Socket: " + sock_file + " <=> " + postfix)
|
||||
if sock_file != postfix:
|
||||
try:
|
||||
print("Socket File: " + sock_file)
|
||||
self._sock.connect(sock_file)
|
||||
self.connected = True
|
||||
print("Setting connected to %r." % self.connected )
|
||||
self._watch_id = GObject.io_add_watch(self._sock, GObject.IO_IN, self._handle_notify)
|
||||
print("Socket watch id: " + str(self._watch_id))
|
||||
return False # Don't run again
|
||||
except Exception as e:
|
||||
print("Could not connect to unix socket. " + str(e))
|
||||
else:
|
||||
print("Sock-File not valid: " + sock_file)
|
||||
sock_file = os.path.join(get_runtime_dir(), appname, "socket")
|
||||
try:
|
||||
print("Socket File: " + sock_file)
|
||||
self._sock.connect(sock_file) # fails if sock_file doesn't exist
|
||||
self.connected = True
|
||||
print("Setting connected to %r." % self.connected )
|
||||
self._watch_id = GObject.io_add_watch(self._sock, GObject.IO_IN, self._handle_notify)
|
||||
print("Socket watch id: " + str(self._watch_id))
|
||||
return False # Don't run again
|
||||
except Exception as e:
|
||||
print("Could not connect to unix socket. " + str(e))
|
||||
except Exception as e: # Bad habbit
|
||||
print("Connect could not be established, try again later.")
|
||||
self._sock.close()
|
||||
@@ -157,32 +153,65 @@ class MenuExtension(GObject.GObject, Nautilus.MenuProvider):
|
||||
def __init__(self):
|
||||
GObject.GObject.__init__(self)
|
||||
|
||||
def check_registered_paths(self, filename):
|
||||
topLevelFolder = False
|
||||
internalFile = False
|
||||
for reg_path in socketConnect.registered_paths:
|
||||
if filename == reg_path:
|
||||
topLevelFolder = True
|
||||
break
|
||||
if filename.startswith(reg_path):
|
||||
internalFile = True
|
||||
# you can't have a registered path below another so it is save to break here
|
||||
break
|
||||
return (topLevelFolder, internalFile)
|
||||
|
||||
def get_file_items(self, window, files):
|
||||
# Show the menu extension to share a file or folder
|
||||
#
|
||||
# Show if file is OK.
|
||||
# Ignore top level folders.
|
||||
# Also show extension for folders
|
||||
# if there is a OK or SYNC underneath.
|
||||
# This is only
|
||||
|
||||
if len(files) != 1:
|
||||
return
|
||||
file = files[0]
|
||||
items = []
|
||||
|
||||
# Internal or external file?!
|
||||
syncedFile = False
|
||||
for reg_path in socketConnect.registered_paths:
|
||||
topLevelFolder = False
|
||||
filename = get_local_path(file.get_uri())
|
||||
# Check if its a folder (ends with an /), if yes add a "/"
|
||||
# otherwise it will not find the entry in the table
|
||||
if os.path.isdir(filename + "/"):
|
||||
filename += "/"
|
||||
# Check if toplevel folder, we need to ignore those as they cannot be shared
|
||||
if filename == reg_path:
|
||||
topLevelFolder=True
|
||||
# Only show the menu extension if the file is synced and the sync
|
||||
# status is ok. Not for ignored files etc.
|
||||
# ignore top level folders
|
||||
if filename.startswith(reg_path) and topLevelFolder == False and socketConnect.nautilusVFSFile_table[filename]['state'].startswith('OK'):
|
||||
syncedFile = True
|
||||
filename = get_local_path(file.get_uri())
|
||||
# Check if its a folder (ends with an /), if yes add a "/"
|
||||
# otherwise it will not find the entry in the table
|
||||
isDir = os.path.isdir(filename + os.sep)
|
||||
if isDir:
|
||||
filename += os.sep
|
||||
|
||||
# If it is neither in a synced folder or is a directory
|
||||
if not syncedFile:
|
||||
# Check if toplevel folder, we need to ignore those as they cannot be shared
|
||||
topLevelFolder, internalFile = self.check_registered_paths(filename)
|
||||
if topLevelFolder or not internalFile:
|
||||
return items
|
||||
|
||||
entry = socketConnect.nautilusVFSFile_table.get(filename)
|
||||
if not entry:
|
||||
return items
|
||||
|
||||
shareable = False
|
||||
state = entry['state']
|
||||
state_ok = state.startswith('OK')
|
||||
state_sync = state.startswith('SYNC')
|
||||
if state_ok:
|
||||
shareable = True
|
||||
elif state_sync and isDir:
|
||||
# some file below is OK or SYNC
|
||||
for key, value in socketConnect.nautilusVFSFile_table.items():
|
||||
if key != filename and key.startswith(filename):
|
||||
state = value['state']
|
||||
if state.startswith('OK') or state.startswith('SYNC'):
|
||||
shareable = True
|
||||
break
|
||||
|
||||
if not shareable:
|
||||
return items
|
||||
|
||||
# Create a menu item
|
||||
@@ -303,7 +332,7 @@ class SyncStateExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.Info
|
||||
|
||||
filename = get_local_path(item.get_uri())
|
||||
if item.is_directory():
|
||||
filename += '/'
|
||||
filename += os.sep
|
||||
|
||||
inScope = False
|
||||
for reg_path in socketConnect.registered_paths:
|
||||
|
||||
@@ -36,54 +36,54 @@ using namespace std;
|
||||
|
||||
OCClientInterface::ContextMenuInfo OCClientInterface::FetchInfo()
|
||||
{
|
||||
auto pipename = CommunicationSocket::DefaultPipePath();
|
||||
auto pipename = CommunicationSocket::DefaultPipePath();
|
||||
|
||||
CommunicationSocket socket;
|
||||
if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) {
|
||||
return {};
|
||||
}
|
||||
if (!socket.Connect(pipename)) {
|
||||
return {};
|
||||
}
|
||||
socket.SendMsg(L"SHARE_MENU_TITLE\n");
|
||||
CommunicationSocket socket;
|
||||
if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) {
|
||||
return {};
|
||||
}
|
||||
if (!socket.Connect(pipename)) {
|
||||
return {};
|
||||
}
|
||||
socket.SendMsg(L"SHARE_MENU_TITLE\n");
|
||||
|
||||
ContextMenuInfo info;
|
||||
std::wstring response;
|
||||
int sleptCount = 0;
|
||||
while (sleptCount < 5) {
|
||||
if (socket.ReadLine(&response)) {
|
||||
if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) {
|
||||
wstring responsePath = response.substr(14); // length of REGISTER_PATH
|
||||
info.watchedDirectories.push_back(responsePath);
|
||||
}
|
||||
else if (StringUtil::begins_with(response, wstring(L"SHARE_MENU_TITLE:"))) {
|
||||
info.shareMenuTitle = response.substr(17); // length of SHARE_MENU_TITLE:
|
||||
break; // Stop once we received the last sent request
|
||||
}
|
||||
}
|
||||
else {
|
||||
Sleep(50);
|
||||
++sleptCount;
|
||||
}
|
||||
}
|
||||
return info;
|
||||
ContextMenuInfo info;
|
||||
std::wstring response;
|
||||
int sleptCount = 0;
|
||||
while (sleptCount < 5) {
|
||||
if (socket.ReadLine(&response)) {
|
||||
if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) {
|
||||
wstring responsePath = response.substr(14); // length of REGISTER_PATH
|
||||
info.watchedDirectories.push_back(responsePath);
|
||||
}
|
||||
else if (StringUtil::begins_with(response, wstring(L"SHARE_MENU_TITLE:"))) {
|
||||
info.shareMenuTitle = response.substr(17); // length of SHARE_MENU_TITLE:
|
||||
break; // Stop once we received the last sent request
|
||||
}
|
||||
}
|
||||
else {
|
||||
Sleep(50);
|
||||
++sleptCount;
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
void OCClientInterface::ShareObject(const std::wstring &path)
|
||||
{
|
||||
auto pipename = CommunicationSocket::DefaultPipePath();
|
||||
auto pipename = CommunicationSocket::DefaultPipePath();
|
||||
|
||||
CommunicationSocket socket;
|
||||
if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) {
|
||||
return;
|
||||
}
|
||||
if (!socket.Connect(pipename)) {
|
||||
return;
|
||||
}
|
||||
CommunicationSocket socket;
|
||||
if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) {
|
||||
return;
|
||||
}
|
||||
if (!socket.Connect(pipename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
wchar_t msg[SOCK_BUFFER] = { 0 };
|
||||
if (SUCCEEDED(StringCchPrintf(msg, SOCK_BUFFER, L"SHARE:%s\n", path.c_str())))
|
||||
{
|
||||
socket.SendMsg(msg);
|
||||
}
|
||||
wchar_t msg[SOCK_BUFFER] = { 0 };
|
||||
if (SUCCEEDED(StringCchPrintf(msg, SOCK_BUFFER, L"SHARE:%s\n", path.c_str())))
|
||||
{
|
||||
socket.SendMsg(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,12 +43,12 @@ class CommunicationSocket;
|
||||
class OCClientInterface
|
||||
{
|
||||
public:
|
||||
struct ContextMenuInfo {
|
||||
std::vector<std::wstring> watchedDirectories;
|
||||
std::wstring shareMenuTitle;
|
||||
};
|
||||
static ContextMenuInfo FetchInfo();
|
||||
static void ShareObject(const std::wstring &path);
|
||||
struct ContextMenuInfo {
|
||||
std::vector<std::wstring> watchedDirectories;
|
||||
std::wstring shareMenuTitle;
|
||||
};
|
||||
static ContextMenuInfo FetchInfo();
|
||||
static void ShareObject(const std::wstring &path);
|
||||
};
|
||||
|
||||
#endif //ABSTRACTSOCKETHANDLER_H
|
||||
|
||||
@@ -30,27 +30,27 @@ extern long g_cDllRef;
|
||||
|
||||
|
||||
OCContextMenu::OCContextMenu(void)
|
||||
: m_cRef(1)
|
||||
, m_pszMenuText(L"&Share")
|
||||
, m_pszVerb("ocshare")
|
||||
, m_pwszVerb(L"ocshare")
|
||||
, m_pszVerbCanonicalName("OCShareViaOC")
|
||||
, m_pwszVerbCanonicalName(L"OCShareViaOC")
|
||||
, m_pszVerbHelpText("Share via ownCloud")
|
||||
, m_pwszVerbHelpText(L"Share via ownCloud")
|
||||
: m_cRef(1)
|
||||
, m_pszMenuText(L"&Share")
|
||||
, m_pszVerb("ocshare")
|
||||
, m_pwszVerb(L"ocshare")
|
||||
, m_pszVerbCanonicalName("OCShareViaOC")
|
||||
, m_pwszVerbCanonicalName(L"OCShareViaOC")
|
||||
, m_pszVerbHelpText("Share via ownCloud")
|
||||
, m_pwszVerbHelpText(L"Share via ownCloud")
|
||||
{
|
||||
InterlockedIncrement(&g_cDllRef);
|
||||
InterlockedIncrement(&g_cDllRef);
|
||||
}
|
||||
|
||||
OCContextMenu::~OCContextMenu(void)
|
||||
{
|
||||
InterlockedDecrement(&g_cDllRef);
|
||||
InterlockedDecrement(&g_cDllRef);
|
||||
}
|
||||
|
||||
|
||||
void OCContextMenu::OnVerbDisplayFileName(HWND hWnd)
|
||||
{
|
||||
OCClientInterface::ShareObject(std::wstring(m_szSelectedFile));
|
||||
OCClientInterface::ShareObject(std::wstring(m_szSelectedFile));
|
||||
}
|
||||
|
||||
|
||||
@@ -59,30 +59,30 @@ void OCContextMenu::OnVerbDisplayFileName(HWND hWnd)
|
||||
// Query to the interface the component supported.
|
||||
IFACEMETHODIMP OCContextMenu::QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
static const QITAB qit[] =
|
||||
{
|
||||
QITABENT(OCContextMenu, IContextMenu),
|
||||
QITABENT(OCContextMenu, IShellExtInit),
|
||||
{ 0 },
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
static const QITAB qit[] =
|
||||
{
|
||||
QITABENT(OCContextMenu, IContextMenu),
|
||||
QITABENT(OCContextMenu, IShellExtInit),
|
||||
{ 0 },
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
// Increase the reference count for an interface on an object.
|
||||
IFACEMETHODIMP_(ULONG) OCContextMenu::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&m_cRef);
|
||||
return InterlockedIncrement(&m_cRef);
|
||||
}
|
||||
|
||||
// Decrease the reference count for an interface on an object.
|
||||
IFACEMETHODIMP_(ULONG) OCContextMenu::Release()
|
||||
{
|
||||
ULONG cRef = InterlockedDecrement(&m_cRef);
|
||||
if (0 == cRef) {
|
||||
delete this;
|
||||
}
|
||||
ULONG cRef = InterlockedDecrement(&m_cRef);
|
||||
if (0 == cRef) {
|
||||
delete this;
|
||||
}
|
||||
|
||||
return cRef;
|
||||
return cRef;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
@@ -92,40 +92,40 @@ IFACEMETHODIMP_(ULONG) OCContextMenu::Release()
|
||||
|
||||
// Initialize the context menu handler.
|
||||
IFACEMETHODIMP OCContextMenu::Initialize(
|
||||
LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID)
|
||||
LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID)
|
||||
{
|
||||
if (!pDataObj) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (!pDataObj) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT hr = E_FAIL;
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||||
STGMEDIUM stm;
|
||||
FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||||
STGMEDIUM stm;
|
||||
|
||||
if (SUCCEEDED(pDataObj->GetData(&fe, &stm))) {
|
||||
// Get an HDROP handle.
|
||||
HDROP hDrop = static_cast<HDROP>(GlobalLock(stm.hGlobal));
|
||||
if (hDrop) {
|
||||
// Ignore multi-selections
|
||||
UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
|
||||
if (nFiles == 1) {
|
||||
// Get the path of the file.
|
||||
if (0 != DragQueryFile(hDrop, 0, m_szSelectedFile, ARRAYSIZE(m_szSelectedFile)))
|
||||
{
|
||||
hr = S_OK;
|
||||
}
|
||||
}
|
||||
if (SUCCEEDED(pDataObj->GetData(&fe, &stm))) {
|
||||
// Get an HDROP handle.
|
||||
HDROP hDrop = static_cast<HDROP>(GlobalLock(stm.hGlobal));
|
||||
if (hDrop) {
|
||||
// Ignore multi-selections
|
||||
UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
|
||||
if (nFiles == 1) {
|
||||
// Get the path of the file.
|
||||
if (0 != DragQueryFile(hDrop, 0, m_szSelectedFile, ARRAYSIZE(m_szSelectedFile)))
|
||||
{
|
||||
hr = S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
GlobalUnlock(stm.hGlobal);
|
||||
}
|
||||
GlobalUnlock(stm.hGlobal);
|
||||
}
|
||||
|
||||
ReleaseStgMedium(&stm);
|
||||
}
|
||||
ReleaseStgMedium(&stm);
|
||||
}
|
||||
|
||||
// If any value other than S_OK is returned from the method, the context
|
||||
// menu item is not displayed.
|
||||
return hr;
|
||||
// If any value other than S_OK is returned from the method, the context
|
||||
// menu item is not displayed.
|
||||
return hr;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
@@ -135,135 +135,136 @@ IFACEMETHODIMP OCContextMenu::Initialize(
|
||||
|
||||
void InsertSeperator(HMENU hMenu, UINT indexMenu)
|
||||
{
|
||||
// Add a separator.
|
||||
MENUITEMINFO sep = { sizeof(sep) };
|
||||
sep.fMask = MIIM_TYPE;
|
||||
sep.fType = MFT_SEPARATOR;
|
||||
InsertMenuItem(hMenu, indexMenu, TRUE, &sep);
|
||||
// Add a separator.
|
||||
MENUITEMINFO sep = { sizeof(sep) };
|
||||
sep.fMask = MIIM_TYPE;
|
||||
sep.fType = MFT_SEPARATOR;
|
||||
InsertMenuItem(hMenu, indexMenu, TRUE, &sep);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
|
||||
{
|
||||
// If uFlags include CMF_DEFAULTONLY then we should not do anything.
|
||||
if (CMF_DEFAULTONLY & uFlags)
|
||||
{
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
||||
}
|
||||
// If uFlags include CMF_DEFAULTONLY then we should not do anything.
|
||||
if (CMF_DEFAULTONLY & uFlags)
|
||||
{
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
||||
}
|
||||
|
||||
OCClientInterface::ContextMenuInfo info = OCClientInterface::FetchInfo();
|
||||
bool skip = true;
|
||||
for (const std::wstring path : info.watchedDirectories) {
|
||||
if (StringUtil::begins_with(std::wstring(m_szSelectedFile), path)) {
|
||||
skip = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
OCClientInterface::ContextMenuInfo info = OCClientInterface::FetchInfo();
|
||||
bool skip = true;
|
||||
size_t selectedFileLength = wcslen(m_szSelectedFile);
|
||||
for (const std::wstring path : info.watchedDirectories) {
|
||||
if (StringUtil::isDescendantOf(m_szSelectedFile, selectedFileLength, path)) {
|
||||
skip = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
||||
}
|
||||
if (skip) {
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
||||
}
|
||||
|
||||
InsertSeperator(hMenu, indexMenu);
|
||||
indexMenu++;
|
||||
InsertSeperator(hMenu, indexMenu);
|
||||
indexMenu++;
|
||||
|
||||
assert(!info.shareMenuTitle.empty());
|
||||
MENUITEMINFO mii = { sizeof(mii) };
|
||||
mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE;
|
||||
mii.wID = idCmdFirst + IDM_SHARE;
|
||||
mii.fType = MFT_STRING;
|
||||
mii.dwTypeData = &info.shareMenuTitle[0];
|
||||
mii.fState = MFS_ENABLED;
|
||||
if (!InsertMenuItem(hMenu, indexMenu, TRUE, &mii))
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
assert(!info.shareMenuTitle.empty());
|
||||
MENUITEMINFO mii = { sizeof(mii) };
|
||||
mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE;
|
||||
mii.wID = idCmdFirst + IDM_SHARE;
|
||||
mii.fType = MFT_STRING;
|
||||
mii.dwTypeData = &info.shareMenuTitle[0];
|
||||
mii.fState = MFS_ENABLED;
|
||||
if (!InsertMenuItem(hMenu, indexMenu, TRUE, &mii))
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
indexMenu++;
|
||||
InsertSeperator(hMenu, indexMenu);
|
||||
indexMenu++;
|
||||
InsertSeperator(hMenu, indexMenu);
|
||||
|
||||
|
||||
// Return an HRESULT value with the severity set to SEVERITY_SUCCESS.
|
||||
// Set the code value to the offset of the largest command identifier
|
||||
// that was assigned, plus one (1).
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_SHARE + 1));
|
||||
// Return an HRESULT value with the severity set to SEVERITY_SUCCESS.
|
||||
// Set the code value to the offset of the largest command identifier
|
||||
// that was assigned, plus one (1).
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_SHARE + 1));
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
|
||||
{
|
||||
|
||||
// For the Unicode case, if the high-order word is not zero, the
|
||||
// command's verb string is in lpcmi->lpVerbW.
|
||||
if (HIWORD(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW))
|
||||
{
|
||||
// Is the verb supported by this context menu extension?
|
||||
if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, m_pwszVerb) == 0)
|
||||
{
|
||||
OnVerbDisplayFileName(pici->hwnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the verb is not recognized by the context menu handler, it
|
||||
// must return E_FAIL to allow it to be passed on to the other
|
||||
// context menu handlers that might implement that verb.
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
// For the Unicode case, if the high-order word is not zero, the
|
||||
// command's verb string is in lpcmi->lpVerbW.
|
||||
if (HIWORD(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW))
|
||||
{
|
||||
// Is the verb supported by this context menu extension?
|
||||
if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, m_pwszVerb) == 0)
|
||||
{
|
||||
OnVerbDisplayFileName(pici->hwnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the verb is not recognized by the context menu handler, it
|
||||
// must return E_FAIL to allow it to be passed on to the other
|
||||
// context menu handlers that might implement that verb.
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
// If the command cannot be identified through the verb string, then
|
||||
// check the identifier offset.
|
||||
else
|
||||
{
|
||||
// Is the command identifier offset supported by this context menu
|
||||
// extension?
|
||||
if (LOWORD(pici->lpVerb) == IDM_SHARE)
|
||||
{
|
||||
OnVerbDisplayFileName(pici->hwnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the verb is not recognized by the context menu handler, it
|
||||
// must return E_FAIL to allow it to be passed on to the other
|
||||
// context menu handlers that might implement that verb.
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
// If the command cannot be identified through the verb string, then
|
||||
// check the identifier offset.
|
||||
else
|
||||
{
|
||||
// Is the command identifier offset supported by this context menu
|
||||
// extension?
|
||||
if (LOWORD(pici->lpVerb) == IDM_SHARE)
|
||||
{
|
||||
OnVerbDisplayFileName(pici->hwnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the verb is not recognized by the context menu handler, it
|
||||
// must return E_FAIL to allow it to be passed on to the other
|
||||
// context menu handlers that might implement that verb.
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenu::GetCommandString(UINT_PTR idCommand,
|
||||
UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
|
||||
UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
|
||||
{
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
|
||||
if (idCommand == IDM_SHARE)
|
||||
{
|
||||
switch (uFlags)
|
||||
{
|
||||
case GCS_HELPTEXTW:
|
||||
// Only useful for pre-Vista versions of Windows that have a
|
||||
// Status bar.
|
||||
hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax,
|
||||
m_pwszVerbHelpText);
|
||||
break;
|
||||
if (idCommand == IDM_SHARE)
|
||||
{
|
||||
switch (uFlags)
|
||||
{
|
||||
case GCS_HELPTEXTW:
|
||||
// Only useful for pre-Vista versions of Windows that have a
|
||||
// Status bar.
|
||||
hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax,
|
||||
m_pwszVerbHelpText);
|
||||
break;
|
||||
|
||||
case GCS_VERBW:
|
||||
// GCS_VERBW is an optional feature that enables a caller to
|
||||
// discover the canonical name for the verb passed in through
|
||||
// idCommand.
|
||||
hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax,
|
||||
m_pwszVerbCanonicalName);
|
||||
break;
|
||||
case GCS_VERBW:
|
||||
// GCS_VERBW is an optional feature that enables a caller to
|
||||
// discover the canonical name for the verb passed in through
|
||||
// idCommand.
|
||||
hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax,
|
||||
m_pwszVerbCanonicalName);
|
||||
break;
|
||||
|
||||
default:
|
||||
hr = S_OK;
|
||||
}
|
||||
}
|
||||
default:
|
||||
hr = S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// If the command (idCommand) is not supported by this context menu
|
||||
// extension handler, return E_INVALIDARG.
|
||||
// If the command (idCommand) is not supported by this context menu
|
||||
// extension handler, return E_INVALIDARG.
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
@@ -26,12 +26,12 @@ extern long g_cDllRef;
|
||||
|
||||
OCContextMenuFactory::OCContextMenuFactory() : m_cRef(1)
|
||||
{
|
||||
InterlockedIncrement(&g_cDllRef);
|
||||
InterlockedIncrement(&g_cDllRef);
|
||||
}
|
||||
|
||||
OCContextMenuFactory::~OCContextMenuFactory()
|
||||
{
|
||||
InterlockedDecrement(&g_cDllRef);
|
||||
InterlockedDecrement(&g_cDllRef);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,22 +39,22 @@ OCContextMenuFactory::~OCContextMenuFactory()
|
||||
|
||||
IFACEMETHODIMP OCContextMenuFactory::QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
static const QITAB qit[] = { QITABENT(OCContextMenuFactory, IClassFactory), { 0 }, };
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
static const QITAB qit[] = { QITABENT(OCContextMenuFactory, IClassFactory), { 0 }, };
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) OCContextMenuFactory::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&m_cRef);
|
||||
return InterlockedIncrement(&m_cRef);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) OCContextMenuFactory::Release()
|
||||
{
|
||||
ULONG cRef = InterlockedDecrement(&m_cRef);
|
||||
if (0 == cRef) {
|
||||
delete this;
|
||||
}
|
||||
return cRef;
|
||||
ULONG cRef = InterlockedDecrement(&m_cRef);
|
||||
if (0 == cRef) {
|
||||
delete this;
|
||||
}
|
||||
return cRef;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,30 +62,30 @@ IFACEMETHODIMP_(ULONG) OCContextMenuFactory::Release()
|
||||
|
||||
IFACEMETHODIMP OCContextMenuFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv)
|
||||
{
|
||||
HRESULT hr = CLASS_E_NOAGGREGATION;
|
||||
HRESULT hr = CLASS_E_NOAGGREGATION;
|
||||
|
||||
// pUnkOuter is used for aggregation. We do not support it in the sample.
|
||||
if (pUnkOuter == NULL) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
// pUnkOuter is used for aggregation. We do not support it in the sample.
|
||||
if (pUnkOuter == NULL) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
|
||||
// Create the COM component.
|
||||
OCContextMenu *pExt = new (std::nothrow) OCContextMenu();
|
||||
if (pExt) {
|
||||
// Query the specified interface.
|
||||
hr = pExt->QueryInterface(riid, ppv);
|
||||
pExt->Release();
|
||||
}
|
||||
}
|
||||
// Create the COM component.
|
||||
OCContextMenu *pExt = new (std::nothrow) OCContextMenu();
|
||||
if (pExt) {
|
||||
// Query the specified interface.
|
||||
hr = pExt->QueryInterface(riid, ppv);
|
||||
pExt->Release();
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenuFactory::LockServer(BOOL fLock)
|
||||
{
|
||||
if (fLock) {
|
||||
InterlockedIncrement(&g_cDllRef);
|
||||
} else {
|
||||
InterlockedDecrement(&g_cDllRef);
|
||||
}
|
||||
return S_OK;
|
||||
if (fLock) {
|
||||
InterlockedIncrement(&g_cDllRef);
|
||||
} else {
|
||||
InterlockedDecrement(&g_cDllRef);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
@@ -23,20 +23,20 @@
|
||||
class OCContextMenuFactory : public IClassFactory
|
||||
{
|
||||
public:
|
||||
// IUnknown
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
// IUnknown
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
|
||||
// IClassFactory
|
||||
IFACEMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP LockServer(BOOL fLock);
|
||||
// IClassFactory
|
||||
IFACEMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP LockServer(BOOL fLock);
|
||||
|
||||
OCContextMenuFactory();
|
||||
OCContextMenuFactory();
|
||||
|
||||
private:
|
||||
~OCContextMenuFactory();
|
||||
long m_cRef;
|
||||
~OCContextMenuFactory();
|
||||
long m_cRef;
|
||||
};
|
||||
|
||||
#endif //OCCONTEXTMENUFACTORY_H
|
||||
@@ -23,196 +23,196 @@ namespace {
|
||||
|
||||
HRESULT SetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName, PCWSTR pszData)
|
||||
{
|
||||
HRESULT hr;
|
||||
HKEY hKey = NULL;
|
||||
HRESULT hr;
|
||||
HKEY hKey = NULL;
|
||||
|
||||
// Creates the specified registry key. If the key already exists, the
|
||||
// function opens it.
|
||||
hr = HRESULT_FROM_WIN32(RegCreateKeyEx(HKEY_CLASSES_ROOT, pszSubKey, 0,
|
||||
NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL));
|
||||
// Creates the specified registry key. If the key already exists, the
|
||||
// function opens it.
|
||||
hr = HRESULT_FROM_WIN32(RegCreateKeyEx(HKEY_CLASSES_ROOT, pszSubKey, 0,
|
||||
NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL));
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (pszData != NULL)
|
||||
{
|
||||
// Set the specified value of the key.
|
||||
DWORD cbData = lstrlen(pszData) * sizeof(*pszData);
|
||||
hr = HRESULT_FROM_WIN32(RegSetValueEx(hKey, pszValueName, 0,
|
||||
REG_SZ, reinterpret_cast<const BYTE *>(pszData), cbData));
|
||||
}
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (pszData != NULL)
|
||||
{
|
||||
// Set the specified value of the key.
|
||||
DWORD cbData = lstrlen(pszData) * sizeof(*pszData);
|
||||
hr = HRESULT_FROM_WIN32(RegSetValueEx(hKey, pszValueName, 0,
|
||||
REG_SZ, reinterpret_cast<const BYTE *>(pszData), cbData));
|
||||
}
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT GetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName, PWSTR pszData, DWORD cbData)
|
||||
{
|
||||
HRESULT hr;
|
||||
HKEY hKey = NULL;
|
||||
HRESULT hr;
|
||||
HKEY hKey = NULL;
|
||||
|
||||
// Try to open the specified registry key.
|
||||
hr = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, pszSubKey, 0,
|
||||
KEY_READ, &hKey));
|
||||
// Try to open the specified registry key.
|
||||
hr = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, pszSubKey, 0,
|
||||
KEY_READ, &hKey));
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Get the data for the specified value name.
|
||||
hr = HRESULT_FROM_WIN32(RegQueryValueEx(hKey, pszValueName, NULL,
|
||||
NULL, reinterpret_cast<LPBYTE>(pszData), &cbData));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Get the data for the specified value name.
|
||||
hr = HRESULT_FROM_WIN32(RegQueryValueEx(hKey, pszValueName, NULL,
|
||||
NULL, reinterpret_cast<LPBYTE>(pszData), &cbData));
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
HRESULT OCContextMenuRegHandler::RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid, PCWSTR pszFriendlyName, PCWSTR pszThreadModel)
|
||||
{
|
||||
if (pszModule == NULL || pszThreadModel == NULL)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (pszModule == NULL || pszThreadModel == NULL)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
HRESULT hr;
|
||||
|
||||
wchar_t szCLSID[MAX_PATH];
|
||||
StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
|
||||
wchar_t szCLSID[MAX_PATH];
|
||||
StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
|
||||
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
|
||||
// Create the HKCR\CLSID\{<CLSID>} key.
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), L"CLSID\\%s", szCLSID);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, pszFriendlyName);
|
||||
// Create the HKCR\CLSID\{<CLSID>} key.
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), L"CLSID\\%s", szCLSID);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, pszFriendlyName);
|
||||
|
||||
// Create the HKCR\CLSID\{<CLSID>}\InprocServer32 key.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
|
||||
L"CLSID\\%s\\InprocServer32", szCLSID);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Set the default value of the InprocServer32 key to the
|
||||
// path of the COM module.
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, pszModule);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Set the threading model of the component.
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey,
|
||||
L"ThreadingModel", pszThreadModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create the HKCR\CLSID\{<CLSID>}\InprocServer32 key.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
|
||||
L"CLSID\\%s\\InprocServer32", szCLSID);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Set the default value of the InprocServer32 key to the
|
||||
// path of the COM module.
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, pszModule);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Set the threading model of the component.
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey,
|
||||
L"ThreadingModel", pszThreadModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT OCContextMenuRegHandler::UnregisterInprocServer(const CLSID& clsid)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
wchar_t szCLSID[MAX_PATH];
|
||||
StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
|
||||
wchar_t szCLSID[MAX_PATH];
|
||||
StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
|
||||
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
|
||||
// Delete the HKCR\CLSID\{<CLSID>} key.
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), L"CLSID\\%s", szCLSID);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(RegDelnode(HKEY_CLASSES_ROOT, szSubkey));
|
||||
}
|
||||
// Delete the HKCR\CLSID\{<CLSID>} key.
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), L"CLSID\\%s", szCLSID);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(RegDelnode(HKEY_CLASSES_ROOT, szSubkey));
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
HRESULT OCContextMenuRegHandler::RegisterShellExtContextMenuHandler(
|
||||
PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName)
|
||||
PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName)
|
||||
{
|
||||
if (pszFileType == NULL)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (pszFileType == NULL)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
HRESULT hr;
|
||||
|
||||
wchar_t szCLSID[MAX_PATH];
|
||||
StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
|
||||
wchar_t szCLSID[MAX_PATH];
|
||||
StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
|
||||
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
|
||||
// If pszFileType starts with '.', try to read the default value of the
|
||||
// HKCR\<File Type> key which contains the ProgID to which the file type
|
||||
// is linked.
|
||||
if (*pszFileType == L'.')
|
||||
{
|
||||
wchar_t szDefaultVal[260];
|
||||
hr = GetHKCRRegistryKeyAndValue(pszFileType, NULL, szDefaultVal,
|
||||
sizeof(szDefaultVal));
|
||||
// If pszFileType starts with '.', try to read the default value of the
|
||||
// HKCR\<File Type> key which contains the ProgID to which the file type
|
||||
// is linked.
|
||||
if (*pszFileType == L'.')
|
||||
{
|
||||
wchar_t szDefaultVal[260];
|
||||
hr = GetHKCRRegistryKeyAndValue(pszFileType, NULL, szDefaultVal,
|
||||
sizeof(szDefaultVal));
|
||||
|
||||
// If the key exists and its default value is not empty, use the
|
||||
// ProgID as the file type.
|
||||
if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0')
|
||||
{
|
||||
pszFileType = szDefaultVal;
|
||||
}
|
||||
}
|
||||
// If the key exists and its default value is not empty, use the
|
||||
// ProgID as the file type.
|
||||
if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0')
|
||||
{
|
||||
pszFileType = szDefaultVal;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the key HKCR\<File Type>\shellex\ContextMenuHandlers\{friendlyName>}
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
|
||||
L"%s\\shellex\\ContextMenuHandlers\\%s", pszFileType, pszFriendlyName);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Set the default value of the key.
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, szCLSID);
|
||||
}
|
||||
// Create the key HKCR\<File Type>\shellex\ContextMenuHandlers\{friendlyName>}
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
|
||||
L"%s\\shellex\\ContextMenuHandlers\\%s", pszFileType, pszFriendlyName);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Set the default value of the key.
|
||||
hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, szCLSID);
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT OCContextMenuRegHandler::UnregisterShellExtContextMenuHandler(
|
||||
PCWSTR pszFileType, PCWSTR pszFriendlyName)
|
||||
PCWSTR pszFileType, PCWSTR pszFriendlyName)
|
||||
{
|
||||
if (pszFileType == NULL)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (pszFileType == NULL)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
HRESULT hr;
|
||||
|
||||
wchar_t szSubkey[MAX_PATH];
|
||||
|
||||
// If pszFileType starts with '.', try to read the default value of the
|
||||
// HKCR\<File Type> key which contains the ProgID to which the file type
|
||||
// is linked.
|
||||
if (*pszFileType == L'.')
|
||||
{
|
||||
wchar_t szDefaultVal[260];
|
||||
hr = GetHKCRRegistryKeyAndValue(pszFileType, NULL, szDefaultVal,
|
||||
sizeof(szDefaultVal));
|
||||
// If pszFileType starts with '.', try to read the default value of the
|
||||
// HKCR\<File Type> key which contains the ProgID to which the file type
|
||||
// is linked.
|
||||
if (*pszFileType == L'.')
|
||||
{
|
||||
wchar_t szDefaultVal[260];
|
||||
hr = GetHKCRRegistryKeyAndValue(pszFileType, NULL, szDefaultVal,
|
||||
sizeof(szDefaultVal));
|
||||
|
||||
// If the key exists and its default value is not empty, use the
|
||||
// ProgID as the file type.
|
||||
if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0')
|
||||
{
|
||||
pszFileType = szDefaultVal;
|
||||
}
|
||||
}
|
||||
// If the key exists and its default value is not empty, use the
|
||||
// ProgID as the file type.
|
||||
if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0')
|
||||
{
|
||||
pszFileType = szDefaultVal;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the HKCR\<File Type>\shellex\ContextMenuHandlers\{friendlyName} key.
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
|
||||
L"%s\\shellex\\ContextMenuHandlers\\%s", pszFileType, pszFriendlyName);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(RegDelnode(HKEY_CLASSES_ROOT, szSubkey));
|
||||
}
|
||||
// Remove the HKCR\<File Type>\shellex\ContextMenuHandlers\{friendlyName} key.
|
||||
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
|
||||
L"%s\\shellex\\ContextMenuHandlers\\%s", pszFileType, pszFriendlyName);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(RegDelnode(HKEY_CLASSES_ROOT, szSubkey));
|
||||
}
|
||||
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
@@ -23,16 +23,16 @@
|
||||
class __declspec(dllexport) OCContextMenuRegHandler
|
||||
{
|
||||
public:
|
||||
static HRESULT MakeRegistryEntries(const CLSID& clsid, PCWSTR fileType);
|
||||
static HRESULT RegisterCOMObject(PCWSTR modulePath, PCWSTR friendlyName, const CLSID& clsid);
|
||||
static HRESULT RemoveRegistryEntries(PCWSTR friendlyName);
|
||||
static HRESULT UnregisterCOMObject(const CLSID& clsid);
|
||||
static HRESULT MakeRegistryEntries(const CLSID& clsid, PCWSTR fileType);
|
||||
static HRESULT RegisterCOMObject(PCWSTR modulePath, PCWSTR friendlyName, const CLSID& clsid);
|
||||
static HRESULT RemoveRegistryEntries(PCWSTR friendlyName);
|
||||
static HRESULT UnregisterCOMObject(const CLSID& clsid);
|
||||
|
||||
static HRESULT RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid, PCWSTR pszFriendlyName, PCWSTR pszThreadModel);
|
||||
static HRESULT UnregisterInprocServer(const CLSID& clsid);
|
||||
static HRESULT RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid, PCWSTR pszFriendlyName, PCWSTR pszThreadModel);
|
||||
static HRESULT UnregisterInprocServer(const CLSID& clsid);
|
||||
|
||||
static HRESULT RegisterShellExtContextMenuHandler(PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName);
|
||||
static HRESULT UnregisterShellExtContextMenuHandler(PCWSTR pszFileType, PCWSTR pszFriendlyName);
|
||||
static HRESULT RegisterShellExtContextMenuHandler(PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName);
|
||||
static HRESULT UnregisterShellExtContextMenuHandler(PCWSTR pszFileType, PCWSTR pszFriendlyName);
|
||||
};
|
||||
|
||||
#endif //OCCONTEXTMENUREGHANDLER_H
|
||||
@@ -23,142 +23,142 @@ long dllReferenceCount = 0;
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
instanceHandle = hModule;
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
instanceHandle = hModule;
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HRESULT CreateFactory(REFIID riid, void **ppv, int state)
|
||||
{
|
||||
HRESULT hResult = E_OUTOFMEMORY;
|
||||
HRESULT hResult = E_OUTOFMEMORY;
|
||||
|
||||
OCOverlayFactory* ocOverlayFactory = new OCOverlayFactory(state);
|
||||
OCOverlayFactory* ocOverlayFactory = new OCOverlayFactory(state);
|
||||
|
||||
if (ocOverlayFactory) {
|
||||
hResult = ocOverlayFactory->QueryInterface(riid, ppv);
|
||||
ocOverlayFactory->Release();
|
||||
}
|
||||
return hResult;
|
||||
if (ocOverlayFactory) {
|
||||
hResult = ocOverlayFactory->QueryInterface(riid, ppv);
|
||||
ocOverlayFactory->Release();
|
||||
}
|
||||
return hResult;
|
||||
}
|
||||
|
||||
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
|
||||
{
|
||||
HRESULT hResult = CLASS_E_CLASSNOTAVAILABLE;
|
||||
GUID guid;
|
||||
GUID guid;
|
||||
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_ERROR, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Error); }
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_ERROR, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Error); }
|
||||
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_OK, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_OK); }
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_OK, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_OK); }
|
||||
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_OK_SHARED, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_OKShared); }
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_OK_SHARED, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_OKShared); }
|
||||
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_SYNC, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Sync); }
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_SYNC, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Sync); }
|
||||
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_WARNING, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Warning); }
|
||||
hResult = CLSIDFromString(OVERLAY_GUID_WARNING, (LPCLSID)&guid);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Warning); }
|
||||
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
}
|
||||
|
||||
STDAPI DllCanUnloadNow(void)
|
||||
{
|
||||
return dllReferenceCount > 0 ? S_FALSE : S_OK;
|
||||
|
||||
return S_FALSE;
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
HRESULT RegisterCLSID(LPCOLESTR guidStr, PCWSTR overlayStr, PCWSTR szModule)
|
||||
{
|
||||
HRESULT hResult = S_OK;
|
||||
HRESULT hResult = S_OK;
|
||||
|
||||
GUID guid;
|
||||
hResult = CLSIDFromString(guidStr, (LPCLSID)&guid);
|
||||
GUID guid;
|
||||
hResult = CLSIDFromString(guidStr, (LPCLSID)&guid);
|
||||
|
||||
if (hResult != S_OK) {
|
||||
return hResult;
|
||||
}
|
||||
if (hResult != S_OK) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = OCOverlayRegistrationHandler::RegisterCOMObject(szModule, OVERLAY_GENERIC_NAME, guid);
|
||||
hResult = OCOverlayRegistrationHandler::RegisterCOMObject(szModule, OVERLAY_GENERIC_NAME, guid);
|
||||
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = OCOverlayRegistrationHandler::MakeRegistryEntries(guid, overlayStr);
|
||||
hResult = OCOverlayRegistrationHandler::MakeRegistryEntries(guid, overlayStr);
|
||||
|
||||
return hResult;
|
||||
return hResult;
|
||||
}
|
||||
|
||||
HRESULT UnregisterCLSID(LPCOLESTR guidStr, PCWSTR overlayStr)
|
||||
{
|
||||
HRESULT hResult = S_OK;
|
||||
GUID guid;
|
||||
HRESULT hResult = S_OK;
|
||||
GUID guid;
|
||||
|
||||
hResult = CLSIDFromString(guidStr, (LPCLSID)&guid);
|
||||
hResult = CLSIDFromString(guidStr, (LPCLSID)&guid);
|
||||
|
||||
if (hResult != S_OK) {
|
||||
return hResult;
|
||||
}
|
||||
if (hResult != S_OK) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = OCOverlayRegistrationHandler::UnregisterCOMObject(guid);
|
||||
hResult = OCOverlayRegistrationHandler::UnregisterCOMObject(guid);
|
||||
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = OCOverlayRegistrationHandler::RemoveRegistryEntries(overlayStr);
|
||||
hResult = OCOverlayRegistrationHandler::RemoveRegistryEntries(overlayStr);
|
||||
|
||||
return hResult;
|
||||
return hResult;
|
||||
}
|
||||
|
||||
HRESULT _stdcall DllRegisterServer(void)
|
||||
{
|
||||
HRESULT hResult = S_OK;
|
||||
HRESULT hResult = S_OK;
|
||||
|
||||
wchar_t szModule[MAX_PATH];
|
||||
wchar_t szModule[MAX_PATH];
|
||||
|
||||
if (GetModuleFileName(instanceHandle, szModule, ARRAYSIZE(szModule)) == 0) {
|
||||
hResult = HRESULT_FROM_WIN32(GetLastError());
|
||||
return hResult;
|
||||
}
|
||||
if (GetModuleFileName(instanceHandle, szModule, ARRAYSIZE(szModule)) == 0) {
|
||||
hResult = HRESULT_FROM_WIN32(GetLastError());
|
||||
return hResult;
|
||||
}
|
||||
|
||||
// Unregister any obsolete CLSID when we register here
|
||||
// Those CLSID were removed in 2.1, but we need to make sure to prevent any previous version
|
||||
// of the extension on the system from loading at the same time as a new version to avoid crashing explorer.
|
||||
UnregisterCLSID(OVERLAY_GUID_ERROR_SHARED, OVERLAY_NAME_ERROR_SHARED);
|
||||
UnregisterCLSID(OVERLAY_GUID_SYNC_SHARED, OVERLAY_NAME_SYNC_SHARED);
|
||||
UnregisterCLSID(OVERLAY_GUID_WARNING_SHARED, OVERLAY_NAME_WARNING_SHARED);
|
||||
// Unregister any obsolete CLSID when we register here
|
||||
// Those CLSID were removed in 2.1, but we need to make sure to prevent any previous version
|
||||
// of the extension on the system from loading at the same time as a new version to avoid crashing explorer.
|
||||
UnregisterCLSID(OVERLAY_GUID_ERROR_SHARED, OVERLAY_NAME_ERROR_SHARED);
|
||||
UnregisterCLSID(OVERLAY_GUID_SYNC_SHARED, OVERLAY_NAME_SYNC_SHARED);
|
||||
UnregisterCLSID(OVERLAY_GUID_WARNING_SHARED, OVERLAY_NAME_WARNING_SHARED);
|
||||
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_ERROR, OVERLAY_NAME_ERROR, szModule);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_OK, OVERLAY_NAME_OK, szModule);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_OK_SHARED, OVERLAY_NAME_OK_SHARED, szModule);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_SYNC, OVERLAY_NAME_SYNC, szModule);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_WARNING, OVERLAY_NAME_WARNING, szModule);
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_ERROR, OVERLAY_NAME_ERROR, szModule);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_OK, OVERLAY_NAME_OK, szModule);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_OK_SHARED, OVERLAY_NAME_OK_SHARED, szModule);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_SYNC, OVERLAY_NAME_SYNC, szModule);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = RegisterCLSID(OVERLAY_GUID_WARNING, OVERLAY_NAME_WARNING, szModule);
|
||||
|
||||
return hResult;
|
||||
return hResult;
|
||||
}
|
||||
|
||||
STDAPI DllUnregisterServer(void)
|
||||
@@ -167,21 +167,21 @@ STDAPI DllUnregisterServer(void)
|
||||
|
||||
wchar_t szModule[MAX_PATH];
|
||||
|
||||
if (GetModuleFileNameW(instanceHandle, szModule, ARRAYSIZE(szModule)) == 0)
|
||||
if (GetModuleFileNameW(instanceHandle, szModule, ARRAYSIZE(szModule)) == 0)
|
||||
{
|
||||
hResult = HRESULT_FROM_WIN32(GetLastError());
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_ERROR, OVERLAY_NAME_ERROR);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_OK, OVERLAY_NAME_OK);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_OK_SHARED, OVERLAY_NAME_OK_SHARED);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_SYNC, OVERLAY_NAME_SYNC);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_WARNING, OVERLAY_NAME_WARNING);
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_ERROR, OVERLAY_NAME_ERROR);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_OK, OVERLAY_NAME_OK);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_OK_SHARED, OVERLAY_NAME_OK_SHARED);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_SYNC, OVERLAY_NAME_SYNC);
|
||||
if (!SUCCEEDED(hResult)) { return hResult; }
|
||||
hResult = UnregisterCLSID(OVERLAY_GUID_WARNING, OVERLAY_NAME_WARNING);
|
||||
|
||||
return hResult;
|
||||
}
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "OCContextMenu.h"
|
||||
#include "stdafx.h"
|
||||
|
||||
#define IDM_SHARE 0
|
||||
|
||||
OCContextMenu::OCContextMenu()
|
||||
: m_pwszVerb(0)
|
||||
, m_referenceCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
OCContextMenu::~OCContextMenu()
|
||||
{
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) OCContextMenu::AddRef()
|
||||
{
|
||||
return InterlockedIncrement(&m_referenceCount);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(ULONG) OCContextMenu::Release()
|
||||
{
|
||||
ULONG cRef = InterlockedDecrement(&m_referenceCount);
|
||||
if (0 == cRef)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
return cRef;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenu::QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (IsEqualIID(IID_IUnknown, riid) || IsEqualIID(IID_IContextMenu, riid))
|
||||
{
|
||||
*ppv = static_cast<IContextMenu *>(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = E_NOINTERFACE;
|
||||
*ppv = NULL;
|
||||
}
|
||||
|
||||
if (*ppv)
|
||||
{
|
||||
AddRef();
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenu::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
|
||||
{
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
|
||||
if (idCmd == IDM_SHARE)
|
||||
{
|
||||
switch (uFlags)
|
||||
{
|
||||
case GCS_HELPTEXTW:
|
||||
hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName), cchMax, L"Shares file or directory with ownCloud");
|
||||
break;
|
||||
|
||||
case GCS_VERBW:
|
||||
// GCS_VERBW is an optional feature that enables a caller
|
||||
// to discover the canonical name for the verb that is passed in
|
||||
// through idCommand.
|
||||
hr = StringCchCopyW(reinterpret_cast<PWSTR>(pszName), cchMax, L"ownCloudShare");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
|
||||
{
|
||||
if (pici->cbSize == sizeof(CMINVOKECOMMANDINFOEX) &&
|
||||
(pici->fMask & CMIC_MASK_UNICODE))
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
|
||||
if (HIWORD(((CMINVOKECOMMANDINFOEX *)pici)->lpVerbW))
|
||||
{
|
||||
if (StrCmpIW(((CMINVOKECOMMANDINFOEX *)pici)->lpVerbW, m_pwszVerb))
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (LOWORD(pici->lpVerb) != IDM_SHARE) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
MessageBox(pici->hwnd,
|
||||
L"ownCloud was here",
|
||||
L"ownCloud was here",
|
||||
MB_OK | MB_ICONINFORMATION);
|
||||
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (!(CMF_DEFAULTONLY & uFlags))
|
||||
{
|
||||
InsertMenu(hMenu, indexMenu, MF_STRING | MF_BYPOSITION, idCmdFirst + IDM_SHARE, L"&Share with ownCloud");
|
||||
}
|
||||
hr = StringCbCopyW(m_pwszVerb, sizeof(m_pwszVerb), L"ownCloudShare");
|
||||
|
||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_SHARE + 1));
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef OCCONTEXTMENU_H
|
||||
#define OCCONTEXTMENU_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ShObjIdl.h"
|
||||
#include "memory"
|
||||
|
||||
class OCContextMenu :public IContextMenu
|
||||
{
|
||||
public:
|
||||
OCContextMenu();
|
||||
~OCContextMenu();
|
||||
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
|
||||
|
||||
IFACEMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax);
|
||||
IFACEMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici);
|
||||
IFACEMETHODIMP QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
|
||||
private:
|
||||
TCHAR* m_pwszVerb;
|
||||
long m_referenceCount;
|
||||
|
||||
};
|
||||
|
||||
#endif //OCCONTEXTMENU_H
|
||||
@@ -45,19 +45,19 @@ unique_ptr<RemotePathChecker> s_instance;
|
||||
|
||||
RemotePathChecker *getGlobalChecker()
|
||||
{
|
||||
// On Vista we'll run into issue #2680 if we try to create the thread+pipe connection
|
||||
// on any DllGetClassObject of our registered classes.
|
||||
// Work around the issue by creating the static RemotePathChecker only once actually needed.
|
||||
static once_flag s_onceFlag;
|
||||
call_once(s_onceFlag, [] { s_instance.reset(new RemotePathChecker); });
|
||||
// On Vista we'll run into issue #2680 if we try to create the thread+pipe connection
|
||||
// on any DllGetClassObject of our registered classes.
|
||||
// Work around the issue by creating the static RemotePathChecker only once actually needed.
|
||||
static once_flag s_onceFlag;
|
||||
call_once(s_onceFlag, [] { s_instance.reset(new RemotePathChecker); });
|
||||
|
||||
return s_instance.get();
|
||||
return s_instance.get();
|
||||
}
|
||||
|
||||
}
|
||||
OCOverlay::OCOverlay(int state)
|
||||
: _referenceCount(1)
|
||||
, _state(state)
|
||||
: _referenceCount(1)
|
||||
, _state(state)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ IFACEMETHODIMP OCOverlay::QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
AddRef();
|
||||
}
|
||||
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
@@ -106,80 +106,65 @@ IFACEMETHODIMP_(ULONG) OCOverlay::Release()
|
||||
|
||||
IFACEMETHODIMP OCOverlay::GetPriority(int *pPriority)
|
||||
{
|
||||
// this defines which handler has prededence, so
|
||||
// we order this in terms of likelyhood
|
||||
switch (_state) {
|
||||
case State_OK:
|
||||
*pPriority = 0; break;
|
||||
case State_OKShared:
|
||||
*pPriority = 1; break;
|
||||
case State_Warning:
|
||||
*pPriority = 2; break;
|
||||
case State_Sync:
|
||||
*pPriority = 3; break;
|
||||
case State_Error:
|
||||
*pPriority = 4; break;
|
||||
default:
|
||||
*pPriority = 5; break;
|
||||
}
|
||||
// this defines which handler has prededence, so
|
||||
// we order this in terms of likelyhood
|
||||
switch (_state) {
|
||||
case State_OK:
|
||||
*pPriority = 0; break;
|
||||
case State_OKShared:
|
||||
*pPriority = 1; break;
|
||||
case State_Warning:
|
||||
*pPriority = 2; break;
|
||||
case State_Sync:
|
||||
*pPriority = 3; break;
|
||||
case State_Error:
|
||||
*pPriority = 4; break;
|
||||
default:
|
||||
*pPriority = 5; break;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCOverlay::IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib)
|
||||
IFACEMETHODIMP OCOverlay::IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib)
|
||||
{
|
||||
RemotePathChecker* checker = getGlobalChecker();
|
||||
auto watchedDirectories = checker->WatchedDirectories();
|
||||
RemotePathChecker* checker = getGlobalChecker();
|
||||
std::shared_ptr<const std::vector<std::wstring>> watchedDirectories = checker->WatchedDirectories();
|
||||
|
||||
wstring wpath(pwszPath);
|
||||
wpath.append(L"\\");
|
||||
vector<wstring>::iterator it;
|
||||
bool watched = false;
|
||||
for (it = watchedDirectories.begin(); it != watchedDirectories.end(); ++it) {
|
||||
if (StringUtil::begins_with(wpath, *it)) {
|
||||
watched = true;
|
||||
}
|
||||
}
|
||||
if (watchedDirectories->empty()) {
|
||||
return MAKE_HRESULT(S_FALSE, 0, 0);
|
||||
}
|
||||
|
||||
if (!watched) {
|
||||
return MAKE_HRESULT(S_FALSE, 0, 0);
|
||||
}
|
||||
bool watched = false;
|
||||
size_t pathLength = wcslen(pwszPath);
|
||||
for (auto it = watchedDirectories->begin(); it != watchedDirectories->end(); ++it) {
|
||||
if (StringUtil::isDescendantOf(pwszPath, pathLength, *it)) {
|
||||
watched = true;
|
||||
}
|
||||
}
|
||||
|
||||
int state = 0;
|
||||
if (!checker->IsMonitoredPath(pwszPath, &state)) {
|
||||
return MAKE_HRESULT(S_FALSE, 0, 0);
|
||||
}
|
||||
return MAKE_HRESULT(state == _state ? S_OK : S_FALSE, 0, 0);
|
||||
if (!watched) {
|
||||
return MAKE_HRESULT(S_FALSE, 0, 0);
|
||||
}
|
||||
|
||||
int state = 0;
|
||||
if (!checker->IsMonitoredPath(pwszPath, &state)) {
|
||||
return MAKE_HRESULT(S_FALSE, 0, 0);
|
||||
}
|
||||
return MAKE_HRESULT(state == _state ? S_OK : S_FALSE, 0, 0);
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCOverlay::GetOverlayInfo(PWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags)
|
||||
{
|
||||
*pIndex = 0;
|
||||
*pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX;
|
||||
*pIndex = _state;
|
||||
*pIndex = 0;
|
||||
*pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX;
|
||||
*pIndex = _state;
|
||||
|
||||
if (GetModuleFileName(instanceHandle, pwszIconFile, cchMax) == 0) {
|
||||
HRESULT hResult = HRESULT_FROM_WIN32(GetLastError());
|
||||
wcerr << L"IsOK? " << (hResult == S_OK) << L" with path " << pwszIconFile << L", index " << *pIndex << endl;
|
||||
return hResult;
|
||||
}
|
||||
if (GetModuleFileName(instanceHandle, pwszIconFile, cchMax) == 0) {
|
||||
HRESULT hResult = HRESULT_FROM_WIN32(GetLastError());
|
||||
wcerr << L"IsOK? " << (hResult == S_OK) << L" with path " << pwszIconFile << L", index " << *pIndex << endl;
|
||||
return hResult;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
bool OCOverlay::_IsOverlaysEnabled()
|
||||
{
|
||||
//int enable;
|
||||
bool success = false;
|
||||
|
||||
//if(RegistryUtil::ReadRegistry(REGISTRY_ROOT_KEY, REGISTRY_ENABLE_OVERLAY, &enable))
|
||||
//{
|
||||
// if(enable) {
|
||||
// success = true;
|
||||
// }
|
||||
//}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,22 +21,21 @@ class OCOverlay : public IShellIconOverlayIdentifier
|
||||
|
||||
{
|
||||
public:
|
||||
OCOverlay(int state);
|
||||
OCOverlay(int state);
|
||||
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP GetOverlayInfo(PWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags);
|
||||
IFACEMETHODIMP GetPriority(int *pPriority);
|
||||
IFACEMETHODIMP IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib);
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP GetOverlayInfo(PWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags);
|
||||
IFACEMETHODIMP GetPriority(int *pPriority);
|
||||
IFACEMETHODIMP IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib);
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
|
||||
protected:
|
||||
~OCOverlay();
|
||||
|
||||
private:
|
||||
bool _IsOverlaysEnabled();
|
||||
long _referenceCount;
|
||||
int _state;
|
||||
int _state;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -20,7 +20,7 @@
|
||||
extern long dllReferenceCount;
|
||||
|
||||
OCOverlayFactory::OCOverlayFactory(int state)
|
||||
: _referenceCount(1), _state(state)
|
||||
: _referenceCount(1), _state(state)
|
||||
{
|
||||
InterlockedIncrement(&dllReferenceCount);
|
||||
}
|
||||
@@ -32,7 +32,7 @@ OCOverlayFactory::~OCOverlayFactory()
|
||||
|
||||
IFACEMETHODIMP OCOverlayFactory::QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
HRESULT hResult = S_OK;
|
||||
HRESULT hResult = S_OK;
|
||||
|
||||
if (IsEqualIID(IID_IUnknown, riid) ||
|
||||
IsEqualIID(IID_IClassFactory, riid))
|
||||
@@ -66,20 +66,20 @@ IFACEMETHODIMP_(ULONG) OCOverlayFactory::Release()
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCOverlayFactory::CreateInstance(
|
||||
IUnknown *pUnkOuter, REFIID riid, void **ppv)
|
||||
IUnknown *pUnkOuter, REFIID riid, void **ppv)
|
||||
{
|
||||
HRESULT hResult = CLASS_E_NOAGGREGATION;
|
||||
HRESULT hResult = CLASS_E_NOAGGREGATION;
|
||||
|
||||
if (pUnkOuter != NULL) { return hResult; }
|
||||
|
||||
hResult = E_OUTOFMEMORY;
|
||||
hResult = E_OUTOFMEMORY;
|
||||
OCOverlay *lrOverlay = new (std::nothrow) OCOverlay(_state);
|
||||
if (!lrOverlay) { return hResult; }
|
||||
if (!lrOverlay) { return hResult; }
|
||||
|
||||
hResult = lrOverlay->QueryInterface(riid, ppv);
|
||||
lrOverlay->Release();
|
||||
lrOverlay->Release();
|
||||
|
||||
return hResult;
|
||||
return hResult;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP OCOverlayFactory::LockServer(BOOL fLock)
|
||||
|
||||
@@ -18,20 +18,20 @@
|
||||
#pragma once
|
||||
|
||||
enum State {
|
||||
State_Error = 0,
|
||||
State_OK, State_OKShared,
|
||||
State_Sync,
|
||||
State_Warning
|
||||
State_Error = 0,
|
||||
State_OK, State_OKShared,
|
||||
State_Sync,
|
||||
State_Warning
|
||||
};
|
||||
|
||||
class OCOverlayFactory : public IClassFactory
|
||||
{
|
||||
public:
|
||||
OCOverlayFactory(int state);
|
||||
OCOverlayFactory(int state);
|
||||
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP_(ULONG) AddRef();
|
||||
IFACEMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP LockServer(BOOL fLock);
|
||||
IFACEMETHODIMP LockServer(BOOL fLock);
|
||||
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||||
IFACEMETHODIMP_(ULONG) Release();
|
||||
|
||||
@@ -40,7 +40,7 @@ protected:
|
||||
|
||||
private:
|
||||
long _referenceCount;
|
||||
int _state;
|
||||
int _state;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -23,52 +23,52 @@ using namespace std;
|
||||
|
||||
HRESULT OCOverlayRegistrationHandler::MakeRegistryEntries(const CLSID& clsid, PCWSTR friendlyName)
|
||||
{
|
||||
HRESULT hResult;
|
||||
HKEY shellOverlayKey = NULL;
|
||||
// the key may not exist yet
|
||||
hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &shellOverlayKey, NULL));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
hResult = RegCreateKey(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, &shellOverlayKey);
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
}
|
||||
HRESULT hResult;
|
||||
HKEY shellOverlayKey = NULL;
|
||||
// the key may not exist yet
|
||||
hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &shellOverlayKey, NULL));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
hResult = RegCreateKey(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, &shellOverlayKey);
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
}
|
||||
|
||||
HKEY syncExOverlayKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(shellOverlayKey, friendlyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &syncExOverlayKey, NULL));
|
||||
HKEY syncExOverlayKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(shellOverlayKey, friendlyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &syncExOverlayKey, NULL));
|
||||
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
wchar_t stringCLSID[MAX_PATH];
|
||||
wchar_t stringCLSID[MAX_PATH];
|
||||
StringFromGUID2(clsid, stringCLSID, ARRAYSIZE(stringCLSID));
|
||||
LPCTSTR value = stringCLSID;
|
||||
hResult = RegSetValueEx(syncExOverlayKey, NULL, 0, REG_SZ, (LPBYTE)value, (DWORD)((wcslen(value)+1) * sizeof(TCHAR)));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
LPCTSTR value = stringCLSID;
|
||||
hResult = RegSetValueEx(syncExOverlayKey, NULL, 0, REG_SZ, (LPBYTE)value, (DWORD)((wcslen(value)+1) * sizeof(TCHAR)));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
return hResult;
|
||||
return hResult;
|
||||
}
|
||||
|
||||
HRESULT OCOverlayRegistrationHandler::RemoveRegistryEntries(PCWSTR friendlyName)
|
||||
{
|
||||
HRESULT hResult;
|
||||
HKEY shellOverlayKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, 0, KEY_WRITE, &shellOverlayKey));
|
||||
HRESULT hResult;
|
||||
HKEY shellOverlayKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, 0, KEY_WRITE, &shellOverlayKey));
|
||||
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
HKEY syncExOverlayKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegDeleteKey(shellOverlayKey, friendlyName));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
HKEY syncExOverlayKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegDeleteKey(shellOverlayKey, friendlyName));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
return hResult;
|
||||
return hResult;
|
||||
}
|
||||
|
||||
HRESULT OCOverlayRegistrationHandler::RegisterCOMObject(PCWSTR modulePath, PCWSTR friendlyName, const CLSID& clsid)
|
||||
@@ -79,45 +79,45 @@ HRESULT OCOverlayRegistrationHandler::RegisterCOMObject(PCWSTR modulePath, PCWST
|
||||
|
||||
wchar_t stringCLSID[MAX_PATH];
|
||||
StringFromGUID2(clsid, stringCLSID, ARRAYSIZE(stringCLSID));
|
||||
HRESULT hResult;
|
||||
HKEY hKey = NULL;
|
||||
HRESULT hResult;
|
||||
HKEY hKey = NULL;
|
||||
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, REGISTRY_CLSID, 0, KEY_WRITE, &hKey));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, REGISTRY_CLSID, 0, KEY_WRITE, &hKey));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
HKEY clsidKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(hKey, stringCLSID, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &clsidKey, NULL));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
HKEY clsidKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(hKey, stringCLSID, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &clsidKey, NULL));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = HRESULT_FROM_WIN32(RegSetValue(clsidKey, NULL, REG_SZ, friendlyName, (DWORD) wcslen(friendlyName)));
|
||||
hResult = HRESULT_FROM_WIN32(RegSetValue(clsidKey, NULL, REG_SZ, friendlyName, (DWORD) wcslen(friendlyName)));
|
||||
|
||||
HKEY inprocessKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(clsidKey, REGISTRY_IN_PROCESS, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &inprocessKey, NULL));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
HKEY inprocessKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(clsidKey, REGISTRY_IN_PROCESS, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &inprocessKey, NULL));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = HRESULT_FROM_WIN32(RegSetValue(inprocessKey, NULL, REG_SZ, modulePath, (DWORD) wcslen(modulePath)));
|
||||
hResult = HRESULT_FROM_WIN32(RegSetValue(inprocessKey, NULL, REG_SZ, modulePath, (DWORD) wcslen(modulePath)));
|
||||
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = HRESULT_FROM_WIN32(RegSetValueEx(inprocessKey, REGISTRY_THREADING, 0, REG_SZ, (LPBYTE)REGISTRY_APARTMENT, (DWORD)((wcslen(REGISTRY_APARTMENT)+1) * sizeof(TCHAR))));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = HRESULT_FROM_WIN32(RegSetValueEx(inprocessKey, REGISTRY_VERSION, 0, REG_SZ, (LPBYTE)REGISTRY_VERSION_NUMBER, (DWORD)(wcslen(REGISTRY_VERSION_NUMBER)+1) * sizeof(TCHAR)));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
hResult = HRESULT_FROM_WIN32(RegSetValueEx(inprocessKey, REGISTRY_VERSION, 0, REG_SZ, (LPBYTE)REGISTRY_VERSION_NUMBER, (DWORD)(wcslen(REGISTRY_VERSION_NUMBER)+1) * sizeof(TCHAR)));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT OCOverlayRegistrationHandler::UnregisterCOMObject(const CLSID& clsid)
|
||||
@@ -125,28 +125,28 @@ HRESULT OCOverlayRegistrationHandler::UnregisterCOMObject(const CLSID& clsid)
|
||||
wchar_t stringCLSID[MAX_PATH];
|
||||
|
||||
StringFromGUID2(clsid, stringCLSID, ARRAYSIZE(stringCLSID));
|
||||
HRESULT hResult;
|
||||
HKEY hKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, REGISTRY_CLSID, 0, DELETE, &hKey));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
HRESULT hResult;
|
||||
HKEY hKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, REGISTRY_CLSID, 0, DELETE, &hKey));
|
||||
if (!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
HKEY clsidKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(hKey, stringCLSID, 0, DELETE, &clsidKey));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
HKEY clsidKey = NULL;
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(hKey, stringCLSID, 0, DELETE, &clsidKey));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = HRESULT_FROM_WIN32(RegDeleteKey(clsidKey, REGISTRY_IN_PROCESS));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
hResult = HRESULT_FROM_WIN32(RegDeleteKey(clsidKey, REGISTRY_IN_PROCESS));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
hResult = HRESULT_FROM_WIN32(RegDeleteKey(hKey, stringCLSID));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
hResult = HRESULT_FROM_WIN32(RegDeleteKey(hKey, stringCLSID));
|
||||
if(!SUCCEEDED(hResult)) {
|
||||
return hResult;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
}
|
||||
@@ -19,11 +19,11 @@
|
||||
|
||||
class __declspec(dllexport) OCOverlayRegistrationHandler
|
||||
{
|
||||
public:
|
||||
static HRESULT MakeRegistryEntries(const CLSID& clsid, PCWSTR fileType);
|
||||
static HRESULT RegisterCOMObject(PCWSTR modulePath, PCWSTR friendlyName, const CLSID& clsid);
|
||||
static HRESULT RemoveRegistryEntries(PCWSTR friendlyName);
|
||||
static HRESULT UnregisterCOMObject(const CLSID& clsid);
|
||||
public:
|
||||
static HRESULT MakeRegistryEntries(const CLSID& clsid, PCWSTR fileType);
|
||||
static HRESULT RegisterCOMObject(PCWSTR modulePath, PCWSTR friendlyName, const CLSID& clsid);
|
||||
static HRESULT RemoveRegistryEntries(PCWSTR friendlyName);
|
||||
static HRESULT UnregisterCOMObject(const CLSID& clsid);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -13,38 +13,38 @@
|
||||
*/
|
||||
|
||||
|
||||
#define OVERLAY_GUID_ERROR L"{0960F090-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_ERROR_SHARED L"{0960F091-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_OK L"{0960F092-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_OK_SHARED L"{0960F093-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_SYNC L"{0960F094-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_SYNC_SHARED L"{0960F095-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_WARNING L"{0960F096-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_ERROR L"{0960F090-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_ERROR_SHARED L"{0960F091-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_OK L"{0960F092-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_OK_SHARED L"{0960F093-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_SYNC L"{0960F094-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_SYNC_SHARED L"{0960F095-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_WARNING L"{0960F096-F328-48A3-B746-276B1E3C3722}"
|
||||
#define OVERLAY_GUID_WARNING_SHARED L"{0960F097-F328-48A3-B746-276B1E3C3722}"
|
||||
|
||||
#define OVERLAY_GENERIC_NAME L"OC Overlay Handler"
|
||||
|
||||
// two spaces to put us ahead of the competition :/
|
||||
#define OVERLAY_NAME_ERROR L" OCError"
|
||||
#define OVERLAY_NAME_ERROR_SHARED L" OCErrorShared"
|
||||
#define OVERLAY_NAME_OK L" OCOK"
|
||||
#define OVERLAY_NAME_OK_SHARED L" OCOKShared"
|
||||
#define OVERLAY_NAME_SYNC L" OCSync"
|
||||
#define OVERLAY_NAME_SYNC_SHARED L" OCSyncShared"
|
||||
#define OVERLAY_NAME_WARNING L" OCWarning"
|
||||
#define OVERLAY_NAME_WARNING_SHARED L" OCWarningShared"
|
||||
#define OVERLAY_NAME_ERROR L" OCError"
|
||||
#define OVERLAY_NAME_ERROR_SHARED L" OCErrorShared"
|
||||
#define OVERLAY_NAME_OK L" OCOK"
|
||||
#define OVERLAY_NAME_OK_SHARED L" OCOKShared"
|
||||
#define OVERLAY_NAME_SYNC L" OCSync"
|
||||
#define OVERLAY_NAME_SYNC_SHARED L" OCSyncShared"
|
||||
#define OVERLAY_NAME_WARNING L" OCWarning"
|
||||
#define OVERLAY_NAME_WARNING_SHARED L" OCWarningShared"
|
||||
|
||||
#define REGISTRY_OVERLAY_KEY L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers"
|
||||
#define REGISTRY_CLSID L"CLSID"
|
||||
#define REGISTRY_IN_PROCESS L"InprocServer32"
|
||||
#define REGISTRY_THREADING L"ThreadingModel"
|
||||
#define REGISTRY_APARTMENT L"Apartment"
|
||||
#define REGISTRY_VERSION L"Version"
|
||||
#define REGISTRY_VERSION_NUMBER L"1.0"
|
||||
#define REGISTRY_OVERLAY_KEY L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers"
|
||||
#define REGISTRY_CLSID L"CLSID"
|
||||
#define REGISTRY_IN_PROCESS L"InprocServer32"
|
||||
#define REGISTRY_THREADING L"ThreadingModel"
|
||||
#define REGISTRY_APARTMENT L"Apartment"
|
||||
#define REGISTRY_VERSION L"Version"
|
||||
#define REGISTRY_VERSION_NUMBER L"1.0"
|
||||
|
||||
//Registry values for running
|
||||
#define REGISTRY_ENABLE_OVERLAY L"EnableOverlay"
|
||||
#define REGISTRY_ENABLE_OVERLAY L"EnableOverlay"
|
||||
|
||||
#define GET_FILE_OVERLAY_ID L"getFileIconId"
|
||||
#define GET_FILE_OVERLAY_ID L"getFileIconId"
|
||||
|
||||
#define PORT 34001
|
||||
#define PORT 34001
|
||||
@@ -31,23 +31,23 @@ using namespace std;
|
||||
namespace {
|
||||
|
||||
std::wstring getUserName() {
|
||||
DWORD len = DEFAULT_BUFLEN;
|
||||
TCHAR buf[DEFAULT_BUFLEN];
|
||||
if (GetUserName(buf, &len)) {
|
||||
return std::wstring(&buf[0], len);
|
||||
} else {
|
||||
return std::wstring();
|
||||
}
|
||||
DWORD len = DEFAULT_BUFLEN;
|
||||
TCHAR buf[DEFAULT_BUFLEN];
|
||||
if (GetUserName(buf, &len)) {
|
||||
return std::wstring(&buf[0], len);
|
||||
} else {
|
||||
return std::wstring();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::wstring CommunicationSocket::DefaultPipePath()
|
||||
{
|
||||
auto pipename = std::wstring(L"\\\\.\\pipe\\");
|
||||
pipename += L"ownCloud-";
|
||||
pipename += getUserName();
|
||||
return pipename;
|
||||
auto pipename = std::wstring(L"\\\\.\\pipe\\");
|
||||
pipename += L"ownCloud-";
|
||||
pipename += getUserName();
|
||||
return pipename;
|
||||
}
|
||||
|
||||
CommunicationSocket::CommunicationSocket()
|
||||
@@ -57,23 +57,23 @@ CommunicationSocket::CommunicationSocket()
|
||||
|
||||
CommunicationSocket::~CommunicationSocket()
|
||||
{
|
||||
Close();
|
||||
Close();
|
||||
}
|
||||
|
||||
bool CommunicationSocket::Close()
|
||||
{
|
||||
if (_pipe == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
CloseHandle(_pipe);
|
||||
_pipe = INVALID_HANDLE_VALUE;
|
||||
return true;
|
||||
if (_pipe == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
CloseHandle(_pipe);
|
||||
_pipe = INVALID_HANDLE_VALUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CommunicationSocket::Connect(const std::wstring &pipename)
|
||||
{
|
||||
_pipe = CreateFile(pipename.data(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
_pipe = CreateFile(pipename.data(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
if (_pipe == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
@@ -84,7 +84,7 @@ bool CommunicationSocket::Connect(const std::wstring &pipename)
|
||||
|
||||
bool CommunicationSocket::SendMsg(const wchar_t* message) const
|
||||
{
|
||||
auto utf8_msg = StringUtil::toUtf8(message);
|
||||
auto utf8_msg = StringUtil::toUtf8(message);
|
||||
|
||||
DWORD numBytesWritten = 0;
|
||||
auto result = WriteFile( _pipe, utf8_msg.c_str(), DWORD(utf8_msg.size()), &numBytesWritten, NULL);
|
||||
@@ -92,7 +92,7 @@ bool CommunicationSocket::SendMsg(const wchar_t* message) const
|
||||
if (result) {
|
||||
return true;
|
||||
} else {
|
||||
const_cast<CommunicationSocket*>(this)->Close();
|
||||
const_cast<CommunicationSocket*>(this)->Close();
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -100,9 +100,9 @@ bool CommunicationSocket::SendMsg(const wchar_t* message) const
|
||||
|
||||
bool CommunicationSocket::ReadLine(wstring* response)
|
||||
{
|
||||
if (!response) {
|
||||
return false;
|
||||
}
|
||||
if (!response) {
|
||||
return false;
|
||||
}
|
||||
|
||||
response->clear();
|
||||
|
||||
@@ -110,7 +110,7 @@ bool CommunicationSocket::ReadLine(wstring* response)
|
||||
return false;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
while (true) {
|
||||
int lbPos = 0;
|
||||
auto it = std::find(_buffer.begin() + lbPos, _buffer.end(), '\n');
|
||||
if (it != _buffer.end()) {
|
||||
@@ -121,24 +121,24 @@ bool CommunicationSocket::ReadLine(wstring* response)
|
||||
|
||||
std::array<char, 128> resp_utf8;
|
||||
DWORD numBytesRead = 0;
|
||||
DWORD totalBytesAvailable = 0;
|
||||
DWORD totalBytesAvailable = 0;
|
||||
|
||||
if (!PeekNamedPipe(_pipe, NULL, 0, 0, &totalBytesAvailable, 0)) {
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
if (totalBytesAvailable == 0) {
|
||||
return false;
|
||||
}
|
||||
if (!PeekNamedPipe(_pipe, NULL, 0, 0, &totalBytesAvailable, 0)) {
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
if (totalBytesAvailable == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ReadFile(_pipe, resp_utf8.data(), DWORD(resp_utf8.size()), &numBytesRead, NULL)) {
|
||||
if (!ReadFile(_pipe, resp_utf8.data(), DWORD(resp_utf8.size()), &numBytesRead, NULL)) {
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
if (numBytesRead <= 0) {
|
||||
return false;
|
||||
}
|
||||
_buffer.insert(_buffer.end(), resp_utf8.begin(), resp_utf8.begin()+numBytesRead);
|
||||
_buffer.insert(_buffer.end(), resp_utf8.begin(), resp_utf8.begin()+numBytesRead);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,22 +26,22 @@
|
||||
class __declspec(dllexport) CommunicationSocket
|
||||
{
|
||||
public:
|
||||
static std::wstring DefaultPipePath();
|
||||
static std::wstring DefaultPipePath();
|
||||
|
||||
CommunicationSocket();
|
||||
~CommunicationSocket();
|
||||
CommunicationSocket();
|
||||
~CommunicationSocket();
|
||||
|
||||
bool Connect(const std::wstring& pipename);
|
||||
bool Close();
|
||||
bool Connect(const std::wstring& pipename);
|
||||
bool Close();
|
||||
|
||||
bool SendMsg(const wchar_t*) const;
|
||||
bool ReadLine(std::wstring*);
|
||||
bool SendMsg(const wchar_t*) const;
|
||||
bool ReadLine(std::wstring*);
|
||||
|
||||
HANDLE Event() { return _pipe; }
|
||||
|
||||
private:
|
||||
HANDLE _pipe;
|
||||
std::vector<char> _buffer;
|
||||
private:
|
||||
HANDLE _pipe;
|
||||
std::vector<char> _buffer;
|
||||
bool _connected;
|
||||
};
|
||||
|
||||
|
||||
@@ -22,65 +22,65 @@ using namespace std;
|
||||
|
||||
bool FileUtil::IsChildFile(const wchar_t* rootFolder, vector<wstring>* files)
|
||||
{
|
||||
for(vector<wstring>::iterator it = files->begin(); it != files->end(); it++)
|
||||
{
|
||||
wstring file = *it;
|
||||
for(vector<wstring>::iterator it = files->begin(); it != files->end(); it++)
|
||||
{
|
||||
wstring file = *it;
|
||||
|
||||
size_t found = file.find(rootFolder);
|
||||
size_t found = file.find(rootFolder);
|
||||
|
||||
if(found != string::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(found != string::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileUtil::IsChildFile(const wchar_t* rootFolder, const wchar_t* file)
|
||||
{
|
||||
wstring* f = new wstring(file);
|
||||
wstring* f = new wstring(file);
|
||||
|
||||
size_t found = f->find(rootFolder);
|
||||
size_t found = f->find(rootFolder);
|
||||
|
||||
if(found != string::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
if(found != string::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileUtil::IsChildFileOfRoot(std::vector<std::wstring>* files)
|
||||
{
|
||||
wstring* rootFolder = new wstring();
|
||||
bool needed = false;
|
||||
wstring* rootFolder = new wstring();
|
||||
bool needed = false;
|
||||
|
||||
if(RegistryUtil::ReadRegistry(REGISTRY_ROOT_KEY, REGISTRY_FILTER_FOLDER, rootFolder))
|
||||
{
|
||||
if(IsChildFile(rootFolder->c_str(), files))
|
||||
{
|
||||
needed = true;
|
||||
}
|
||||
}
|
||||
if(RegistryUtil::ReadRegistry(REGISTRY_ROOT_KEY, REGISTRY_FILTER_FOLDER, rootFolder))
|
||||
{
|
||||
if(IsChildFile(rootFolder->c_str(), files))
|
||||
{
|
||||
needed = true;
|
||||
}
|
||||
}
|
||||
|
||||
delete rootFolder;
|
||||
return needed;
|
||||
delete rootFolder;
|
||||
return needed;
|
||||
}
|
||||
|
||||
bool FileUtil::IsChildFileOfRoot(const wchar_t* filePath)
|
||||
{
|
||||
wstring* rootFolder = new wstring();
|
||||
bool needed = false;
|
||||
|
||||
if(RegistryUtil::ReadRegistry(REGISTRY_ROOT_KEY, REGISTRY_FILTER_FOLDER, rootFolder))
|
||||
{
|
||||
if(FileUtil::IsChildFile(rootFolder->c_str(), filePath))
|
||||
{
|
||||
needed = true;
|
||||
}
|
||||
}
|
||||
wstring* rootFolder = new wstring();
|
||||
bool needed = false;
|
||||
|
||||
if(RegistryUtil::ReadRegistry(REGISTRY_ROOT_KEY, REGISTRY_FILTER_FOLDER, rootFolder))
|
||||
{
|
||||
if(FileUtil::IsChildFile(rootFolder->c_str(), filePath))
|
||||
{
|
||||
needed = true;
|
||||
}
|
||||
}
|
||||
|
||||
delete rootFolder;
|
||||
return needed;
|
||||
delete rootFolder;
|
||||
return needed;
|
||||
}
|
||||
@@ -25,16 +25,16 @@
|
||||
class __declspec(dllexport) FileUtil
|
||||
{
|
||||
public:
|
||||
FileUtil();
|
||||
FileUtil();
|
||||
|
||||
~FileUtil();
|
||||
~FileUtil();
|
||||
|
||||
static bool IsChildFile(const wchar_t*, std::vector<std::wstring>*);
|
||||
static bool IsChildFile(const wchar_t*, const wchar_t*);
|
||||
static bool IsChildFileOfRoot(std::vector<std::wstring>*);
|
||||
static bool IsChildFileOfRoot(const wchar_t*);
|
||||
static bool IsChildFile(const wchar_t*, std::vector<std::wstring>*);
|
||||
static bool IsChildFile(const wchar_t*, const wchar_t*);
|
||||
static bool IsChildFileOfRoot(std::vector<std::wstring>*);
|
||||
static bool IsChildFileOfRoot(const wchar_t*);
|
||||
|
||||
private:
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -25,8 +25,8 @@ using namespace std;
|
||||
|
||||
OCMessage::OCMessage(void)
|
||||
{
|
||||
_command = new wstring();
|
||||
_value = new wstring();
|
||||
_command = new wstring();
|
||||
_value = new wstring();
|
||||
}
|
||||
|
||||
OCMessage::~OCMessage(void)
|
||||
@@ -35,40 +35,40 @@ OCMessage::~OCMessage(void)
|
||||
|
||||
bool OCMessage::InitFromMessage(const wstring* message)
|
||||
{
|
||||
if(message->length() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ParserUtil::GetItem(COMMAND, message, _command))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(message->length() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ParserUtil::GetItem(COMMAND, message, _command))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ParserUtil::GetItem(VALUE, message, _value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!ParserUtil::GetItem(VALUE, message, _value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::wstring* OCMessage::GetCommand()
|
||||
{
|
||||
return _command;
|
||||
return _command;
|
||||
}
|
||||
|
||||
std::wstring* OCMessage::GetValue()
|
||||
{
|
||||
return _value;
|
||||
return _value;
|
||||
}
|
||||
|
||||
void OCMessage::SetCommand(std::wstring* command)
|
||||
{
|
||||
_command = command;
|
||||
_command = command;
|
||||
}
|
||||
|
||||
void OCMessage::SetValue(std::wstring* value)
|
||||
{
|
||||
_value = value;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
@@ -23,20 +23,20 @@ class __declspec(dllexport) OCMessage
|
||||
{
|
||||
public:
|
||||
OCMessage(void);
|
||||
~OCMessage(void);
|
||||
~OCMessage(void);
|
||||
|
||||
bool InitFromMessage(const std::wstring*);
|
||||
bool InitFromMessage(const std::wstring*);
|
||||
|
||||
std::wstring* GetCommand();
|
||||
std::wstring* GetValue();
|
||||
std::wstring* GetCommand();
|
||||
std::wstring* GetValue();
|
||||
|
||||
void SetCommand(std::wstring*);
|
||||
void SetValue(std::wstring*);
|
||||
void SetCommand(std::wstring*);
|
||||
void SetValue(std::wstring*);
|
||||
|
||||
private:
|
||||
|
||||
std::wstring* _command;
|
||||
std::wstring* _value;
|
||||
std::wstring* _value;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -21,369 +21,369 @@ using namespace std;
|
||||
|
||||
bool ParserUtil::GetItem(const wchar_t* item, const wstring* message, wstring* result)
|
||||
{
|
||||
size_t start = message->find(item, 0);
|
||||
size_t start = message->find(item, 0);
|
||||
|
||||
if(start == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(start == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t end = message->find(COLON, start);
|
||||
size_t end = message->find(COLON, start);
|
||||
|
||||
if(end == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(end == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//Move to next character after :
|
||||
end += 1;
|
||||
//Move to next character after :
|
||||
end += 1;
|
||||
|
||||
wchar_t c = message->at(end);
|
||||
wchar_t c = message->at(end);
|
||||
|
||||
//Move to the next character, which is the start of the value
|
||||
end += 1;
|
||||
|
||||
if(c == '[')
|
||||
{
|
||||
return GetList(end - 1, message, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetValue(end, message, result);
|
||||
}
|
||||
//Move to the next character, which is the start of the value
|
||||
end += 1;
|
||||
|
||||
if(c == '[')
|
||||
{
|
||||
return GetList(end - 1, message, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetValue(end, message, result);
|
||||
}
|
||||
}
|
||||
|
||||
bool ParserUtil::GetList(size_t start, const wstring* message, wstring* result)
|
||||
{
|
||||
size_t end = start + 1;
|
||||
size_t end = start + 1;
|
||||
|
||||
int openBraceCount = 1;
|
||||
int openBraceCount = 1;
|
||||
|
||||
while(openBraceCount > 0)
|
||||
{
|
||||
size_t closeBraceLocation = message->find(CLOSE_BRACE, end);
|
||||
size_t openBraceLocation = message->find(OPEN_BRACE, end);
|
||||
while(openBraceCount > 0)
|
||||
{
|
||||
size_t closeBraceLocation = message->find(CLOSE_BRACE, end);
|
||||
size_t openBraceLocation = message->find(OPEN_BRACE, end);
|
||||
|
||||
if(closeBraceLocation < openBraceLocation)
|
||||
{
|
||||
openBraceCount--;
|
||||
end = closeBraceLocation + 1;
|
||||
}
|
||||
else if(openBraceLocation < closeBraceLocation)
|
||||
{
|
||||
openBraceCount++;
|
||||
end = openBraceLocation + 1;
|
||||
}
|
||||
if(closeBraceLocation < openBraceLocation)
|
||||
{
|
||||
openBraceCount--;
|
||||
end = closeBraceLocation + 1;
|
||||
}
|
||||
else if(openBraceLocation < closeBraceLocation)
|
||||
{
|
||||
openBraceCount++;
|
||||
end = openBraceLocation + 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
size_t length = end - start;
|
||||
}
|
||||
|
||||
size_t length = end - start;
|
||||
|
||||
return GetString(start, end, message, result);
|
||||
return GetString(start, end, message, result);
|
||||
}
|
||||
|
||||
size_t ParserUtil::GetNextStringItemInList(const wstring* message, size_t start, wstring* result)
|
||||
{
|
||||
size_t end = string::npos;
|
||||
size_t commaLocation = message->find(COMMA, start);
|
||||
size_t end = string::npos;
|
||||
size_t commaLocation = message->find(COMMA, start);
|
||||
|
||||
if(commaLocation == string::npos)
|
||||
{
|
||||
end = message->find(CLOSE_BRACE, start);
|
||||
if(end == string::npos)
|
||||
{
|
||||
end = message->length();
|
||||
}
|
||||
else
|
||||
{
|
||||
end = end - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
end = commaLocation - 1;
|
||||
}
|
||||
if(commaLocation == string::npos)
|
||||
{
|
||||
end = message->find(CLOSE_BRACE, start);
|
||||
if(end == string::npos)
|
||||
{
|
||||
end = message->length();
|
||||
}
|
||||
else
|
||||
{
|
||||
end = end - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
end = commaLocation - 1;
|
||||
}
|
||||
|
||||
if(!GetString(start + 2, end, message, result))
|
||||
{
|
||||
return string::npos;
|
||||
}
|
||||
if(!GetString(start + 2, end, message, result))
|
||||
{
|
||||
return string::npos;
|
||||
}
|
||||
|
||||
return end + 2;
|
||||
return end + 2;
|
||||
}
|
||||
|
||||
size_t ParserUtil::GetNextOCItemInList(const wstring* message, size_t start, wstring* result)
|
||||
{
|
||||
size_t end = message->find(OPEN_CURLY_BRACE, start) + 1;
|
||||
size_t end = message->find(OPEN_CURLY_BRACE, start) + 1;
|
||||
|
||||
int openBraceCount = 1;
|
||||
int openBraceCount = 1;
|
||||
|
||||
while(openBraceCount > 0)
|
||||
{
|
||||
size_t closeBraceLocation = message->find(CLOSE_CURLY_BRACE, end);
|
||||
size_t openBraceLocation = message->find(OPEN_CURLY_BRACE, end);
|
||||
while(openBraceCount > 0)
|
||||
{
|
||||
size_t closeBraceLocation = message->find(CLOSE_CURLY_BRACE, end);
|
||||
size_t openBraceLocation = message->find(OPEN_CURLY_BRACE, end);
|
||||
|
||||
if(closeBraceLocation < openBraceLocation)
|
||||
{
|
||||
openBraceCount--;
|
||||
end = closeBraceLocation + 1;
|
||||
}
|
||||
else if(openBraceLocation < closeBraceLocation)
|
||||
{
|
||||
openBraceCount++;
|
||||
end = openBraceLocation + 1;
|
||||
}
|
||||
}
|
||||
if(closeBraceLocation < openBraceLocation)
|
||||
{
|
||||
openBraceCount--;
|
||||
end = closeBraceLocation + 1;
|
||||
}
|
||||
else if(openBraceLocation < closeBraceLocation)
|
||||
{
|
||||
openBraceCount++;
|
||||
end = openBraceLocation + 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t length = end - start;
|
||||
size_t length = end - start;
|
||||
|
||||
if(!GetString(start, end, message, result))
|
||||
{
|
||||
return string::npos;
|
||||
}
|
||||
if(!GetString(start, end, message, result))
|
||||
{
|
||||
return string::npos;
|
||||
}
|
||||
|
||||
return end;
|
||||
return end;
|
||||
}
|
||||
|
||||
bool ParserUtil::GetValue(size_t start, const wstring* message, wstring* result)
|
||||
{
|
||||
if(message->at(start - 1) == '\"')
|
||||
{
|
||||
size_t end = message->find(QUOTE, start);
|
||||
return GetString(start, end, message, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
start = start - 1;
|
||||
if(message->at(start - 1) == '\"')
|
||||
{
|
||||
size_t end = message->find(QUOTE, start);
|
||||
return GetString(start, end, message, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
start = start - 1;
|
||||
|
||||
size_t end = message->find(COMMA, start);
|
||||
|
||||
result->append(message->substr(start, end-start));
|
||||
}
|
||||
size_t end = message->find(COMMA, start);
|
||||
|
||||
result->append(message->substr(start, end-start));
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserUtil::GetString(size_t start, size_t end, const wstring* message, wstring* result)
|
||||
{
|
||||
if(end == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(end == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t length = end - start;
|
||||
size_t length = end - start;
|
||||
|
||||
if(length > 0)
|
||||
{
|
||||
result->append(message->substr(start, length));
|
||||
}
|
||||
else
|
||||
{
|
||||
result->append(L"");
|
||||
}
|
||||
if(length > 0)
|
||||
{
|
||||
result->append(message->substr(start, length));
|
||||
}
|
||||
else
|
||||
{
|
||||
result->append(L"");
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserUtil::IsList(wstring* message)
|
||||
{
|
||||
wchar_t c = message->at(0);
|
||||
|
||||
if(c == '[')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
wchar_t c = message->at(0);
|
||||
|
||||
if(c == '[')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ParserUtil::ParseJsonList(wstring* message, vector<wstring*>* items)
|
||||
{
|
||||
|
||||
size_t currentLocation = message->find(OPEN_BRACE, 0);
|
||||
size_t currentLocation = message->find(OPEN_BRACE, 0);
|
||||
|
||||
while(currentLocation < message->size())
|
||||
{
|
||||
wstring* item = new wstring();
|
||||
while(currentLocation < message->size())
|
||||
{
|
||||
wstring* item = new wstring();
|
||||
|
||||
currentLocation = ParserUtil::GetNextStringItemInList(message, currentLocation, item);
|
||||
currentLocation = ParserUtil::GetNextStringItemInList(message, currentLocation, item);
|
||||
|
||||
if(currentLocation == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(currentLocation == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
items->push_back(item);
|
||||
}
|
||||
items->push_back(item);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserUtil::ParseOCList(wstring* message, vector<wstring*>* items)
|
||||
{
|
||||
|
||||
size_t currentLocation = message->find(OPEN_CURLY_BRACE, 0);
|
||||
size_t currentLocation = message->find(OPEN_CURLY_BRACE, 0);
|
||||
|
||||
while(currentLocation < message->size())
|
||||
{
|
||||
wstring* item = new wstring();
|
||||
while(currentLocation < message->size())
|
||||
{
|
||||
wstring* item = new wstring();
|
||||
|
||||
currentLocation = ParserUtil::GetNextOCItemInList(message, currentLocation, item);
|
||||
currentLocation = ParserUtil::GetNextOCItemInList(message, currentLocation, item);
|
||||
|
||||
if(currentLocation == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(currentLocation == string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
items->push_back(item);
|
||||
}
|
||||
items->push_back(item);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserUtil::ParseOCMessageList(wstring* message, vector<OCMessage*>* messages)
|
||||
{
|
||||
vector<wstring*>* items = new vector<wstring*>();
|
||||
vector<wstring*>* items = new vector<wstring*>();
|
||||
|
||||
if(!ParseOCList(message, items))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!ParseOCList(message, items))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for(vector<wstring*>::iterator it = items->begin(); it != items->end(); it++)
|
||||
{
|
||||
wstring* temp = *it;
|
||||
for(vector<wstring*>::iterator it = items->begin(); it != items->end(); it++)
|
||||
{
|
||||
wstring* temp = *it;
|
||||
|
||||
OCMessage* message = new OCMessage();
|
||||
message->InitFromMessage(temp);
|
||||
OCMessage* message = new OCMessage();
|
||||
message->InitFromMessage(temp);
|
||||
|
||||
messages->push_back(message);
|
||||
}
|
||||
messages->push_back(message);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserUtil::SerializeList(std::vector<std::wstring>* list, std::wstring* result, bool escapeQuotes)
|
||||
{
|
||||
if(result == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(result == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result->append(OPEN_BRACE);
|
||||
result->append(OPEN_BRACE);
|
||||
|
||||
for(vector<wstring>::iterator it = list->begin(); it != list->end(); it++)
|
||||
{
|
||||
wstring value = *it;
|
||||
for(vector<wstring>::iterator it = list->begin(); it != list->end(); it++)
|
||||
{
|
||||
wstring value = *it;
|
||||
|
||||
if(escapeQuotes)
|
||||
{
|
||||
result->append(BACK_SLASH);
|
||||
}
|
||||
if(escapeQuotes)
|
||||
{
|
||||
result->append(BACK_SLASH);
|
||||
}
|
||||
|
||||
result->append(QUOTE);
|
||||
result->append(value.c_str());
|
||||
result->append(QUOTE);
|
||||
result->append(value.c_str());
|
||||
|
||||
if(escapeQuotes)
|
||||
{
|
||||
result->append(BACK_SLASH);
|
||||
}
|
||||
if(escapeQuotes)
|
||||
{
|
||||
result->append(BACK_SLASH);
|
||||
}
|
||||
|
||||
result->append(QUOTE);
|
||||
result->append(COMMA);
|
||||
}
|
||||
result->append(QUOTE);
|
||||
result->append(COMMA);
|
||||
}
|
||||
|
||||
//Erase last comma
|
||||
result->erase(result->size() - 1, 1);
|
||||
//Erase last comma
|
||||
result->erase(result->size() - 1, 1);
|
||||
|
||||
result->append(CLOSE_BRACE);
|
||||
result->append(CLOSE_BRACE);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserUtil::SerializeMessage(std::map<std::wstring*, std::wstring*>* arguments, std::wstring* result, bool escapeQuotes)
|
||||
{
|
||||
if(result == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(result == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result->append(OPEN_CURLY_BRACE);
|
||||
result->append(OPEN_CURLY_BRACE);
|
||||
|
||||
for(map<wstring*, wstring*>::iterator it = arguments->begin(); it != arguments->end(); it++)
|
||||
{
|
||||
wstring key = *it->first;
|
||||
wstring value = *it->second;
|
||||
for(map<wstring*, wstring*>::iterator it = arguments->begin(); it != arguments->end(); it++)
|
||||
{
|
||||
wstring key = *it->first;
|
||||
wstring value = *it->second;
|
||||
|
||||
if(escapeQuotes)
|
||||
{
|
||||
result->append(BACK_SLASH);
|
||||
}
|
||||
if(escapeQuotes)
|
||||
{
|
||||
result->append(BACK_SLASH);
|
||||
}
|
||||
|
||||
result->append(QUOTE);
|
||||
result->append(key.c_str());
|
||||
result->append(QUOTE);
|
||||
result->append(key.c_str());
|
||||
|
||||
if(escapeQuotes)
|
||||
{
|
||||
result->append(BACK_SLASH);
|
||||
}
|
||||
if(escapeQuotes)
|
||||
{
|
||||
result->append(BACK_SLASH);
|
||||
}
|
||||
|
||||
result->append(QUOTE);
|
||||
result->append(COLON);
|
||||
result->append(value.c_str());
|
||||
result->append(COMMA);
|
||||
}
|
||||
result->append(QUOTE);
|
||||
result->append(COLON);
|
||||
result->append(value.c_str());
|
||||
result->append(COMMA);
|
||||
}
|
||||
|
||||
//Erase last comma
|
||||
result->erase(result->size() - 1, 1);
|
||||
//Erase last comma
|
||||
result->erase(result->size() - 1, 1);
|
||||
|
||||
result->append(CLOSE_CURLY_BRACE);
|
||||
result->append(CLOSE_CURLY_BRACE);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParserUtil::SerializeMessage(OCMessage* OCMessage, std::wstring* result)
|
||||
{
|
||||
if(result == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(result == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result->append(OPEN_CURLY_BRACE);
|
||||
result->append(OPEN_CURLY_BRACE);
|
||||
|
||||
result->append(QUOTE);
|
||||
result->append(COMMAND);
|
||||
result->append(QUOTE);
|
||||
result->append(QUOTE);
|
||||
result->append(COMMAND);
|
||||
result->append(QUOTE);
|
||||
|
||||
result->append(COLON);
|
||||
result->append(COLON);
|
||||
|
||||
result->append(QUOTE);
|
||||
result->append(OCMessage->GetCommand()->c_str());
|
||||
result->append(QUOTE);
|
||||
result->append(QUOTE);
|
||||
result->append(OCMessage->GetCommand()->c_str());
|
||||
result->append(QUOTE);
|
||||
|
||||
result->append(COMMA);
|
||||
|
||||
result->append(QUOTE);
|
||||
result->append(VALUE);
|
||||
result->append(QUOTE);
|
||||
result->append(COMMA);
|
||||
|
||||
result->append(QUOTE);
|
||||
result->append(VALUE);
|
||||
result->append(QUOTE);
|
||||
|
||||
result->append(COLON);
|
||||
|
||||
if(!IsList(OCMessage->GetValue()))
|
||||
{
|
||||
result->append(QUOTE);
|
||||
}
|
||||
|
||||
result->append(OCMessage->GetValue()->c_str());
|
||||
|
||||
if(!IsList(OCMessage->GetValue()))
|
||||
{
|
||||
result->append(QUOTE);
|
||||
}
|
||||
result->append(COLON);
|
||||
|
||||
if(!IsList(OCMessage->GetValue()))
|
||||
{
|
||||
result->append(QUOTE);
|
||||
}
|
||||
|
||||
result->append(OCMessage->GetValue()->c_str());
|
||||
|
||||
if(!IsList(OCMessage->GetValue()))
|
||||
{
|
||||
result->append(QUOTE);
|
||||
}
|
||||
|
||||
result->append(CLOSE_CURLY_BRACE);
|
||||
result->append(CLOSE_CURLY_BRACE);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,49 +22,49 @@ using namespace std;
|
||||
|
||||
bool RegistryUtil::ReadRegistry(const wchar_t* key, const wchar_t* name, int* result)
|
||||
{
|
||||
wstring* strResult = new wstring();
|
||||
wstring* strResult = new wstring();
|
||||
|
||||
if(!ReadRegistry(key, name, strResult))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!ReadRegistry(key, name, strResult))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*result = stoi( strResult->c_str() );
|
||||
*result = stoi( strResult->c_str() );
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RegistryUtil::ReadRegistry(const wchar_t* key, const wchar_t* name, wstring* result)
|
||||
{
|
||||
HRESULT hResult;
|
||||
HRESULT hResult;
|
||||
|
||||
HKEY rootKey = NULL;
|
||||
HKEY rootKey = NULL;
|
||||
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CURRENT_USER, (LPCWSTR)key, NULL, KEY_READ, &rootKey));
|
||||
hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CURRENT_USER, (LPCWSTR)key, NULL, KEY_READ, &rootKey));
|
||||
|
||||
if(!SUCCEEDED(hResult))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!SUCCEEDED(hResult))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t value[SIZE];
|
||||
DWORD value_length = SIZE;
|
||||
|
||||
wchar_t value[SIZE];
|
||||
DWORD value_length = SIZE;
|
||||
|
||||
hResult = RegQueryValueEx(rootKey, (LPCWSTR)name, NULL, NULL, (LPBYTE)value, &value_length );
|
||||
|
||||
if(!SUCCEEDED(hResult))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!SUCCEEDED(hResult))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result->append(value);
|
||||
result->append(value);
|
||||
|
||||
HRESULT hResult2 = RegCloseKey(rootKey);
|
||||
HRESULT hResult2 = RegCloseKey(rootKey);
|
||||
|
||||
if (!SUCCEEDED(hResult2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!SUCCEEDED(hResult2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
class __declspec(dllexport) RegistryUtil
|
||||
{
|
||||
public:
|
||||
RegistryUtil();
|
||||
RegistryUtil();
|
||||
|
||||
~RegistryUtil();
|
||||
~RegistryUtil();
|
||||
|
||||
static bool ReadRegistry(const wchar_t*, const wchar_t*, int*);
|
||||
static bool ReadRegistry(const wchar_t*, const wchar_t*, std::wstring*);
|
||||
static bool ReadRegistry(const wchar_t*, const wchar_t*, int*);
|
||||
static bool ReadRegistry(const wchar_t*, const wchar_t*, std::wstring*);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -40,7 +40,7 @@ void RemotePathChecker::workerThreadLoop()
|
||||
std::unordered_set<std::wstring> asked;
|
||||
|
||||
while(!_stop) {
|
||||
Sleep(50);
|
||||
Sleep(50);
|
||||
|
||||
if (!connected) {
|
||||
asked.clear();
|
||||
@@ -72,33 +72,42 @@ void RemotePathChecker::workerThreadLoop()
|
||||
|
||||
std::wstring response;
|
||||
while (!_stop && socket.ReadLine(&response)) {
|
||||
if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) {
|
||||
wstring responsePath = response.substr(14); // length of REGISTER_PATH:
|
||||
if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) {
|
||||
wstring responsePath = response.substr(14); // length of REGISTER_PATH:
|
||||
|
||||
{ std::unique_lock<std::mutex> lock(_mutex);
|
||||
_watchedDirectories.push_back(responsePath);
|
||||
}
|
||||
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
|
||||
} else if (StringUtil::begins_with(response, wstring(L"UNREGISTER_PATH:"))) {
|
||||
auto sharedPtrCopy = atomic_load(&_watchedDirectories);
|
||||
auto vectorCopy = make_shared<vector<wstring>>(*sharedPtrCopy);
|
||||
vectorCopy->push_back(responsePath);
|
||||
atomic_store(&_watchedDirectories, shared_ptr<const vector<wstring>>(vectorCopy));
|
||||
|
||||
// We don't keep track of all files and can't know which file is currently visible
|
||||
// to the user, but at least reload the root dir so that any shortcut to the root
|
||||
// is updated without the user needing to refresh.
|
||||
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
|
||||
} else if (StringUtil::begins_with(response, wstring(L"UNREGISTER_PATH:"))) {
|
||||
wstring responsePath = response.substr(16); // length of UNREGISTER_PATH:
|
||||
|
||||
{ std::unique_lock<std::mutex> lock(_mutex);
|
||||
_watchedDirectories.erase(
|
||||
std::remove(_watchedDirectories.begin(), _watchedDirectories.end(), responsePath),
|
||||
_watchedDirectories.end());
|
||||
auto sharedPtrCopy = atomic_load(&_watchedDirectories);
|
||||
auto vectorCopy = make_shared<vector<wstring>>(*sharedPtrCopy);
|
||||
vectorCopy->erase(
|
||||
std::remove(vectorCopy->begin(), vectorCopy->end(), responsePath),
|
||||
vectorCopy->end());
|
||||
atomic_store(&_watchedDirectories, shared_ptr<const vector<wstring>>(vectorCopy));
|
||||
|
||||
vector<wstring> removedPaths;
|
||||
{ std::unique_lock<std::mutex> lock(_mutex);
|
||||
// Remove any item from the cache
|
||||
for (auto it = _cache.begin(); it != _cache.end() ; ) {
|
||||
if (StringUtil::begins_with(it->first, responsePath)) {
|
||||
if (StringUtil::isDescendantOf(it->first, responsePath)) {
|
||||
removedPaths.emplace_back(move(it->first));
|
||||
it = _cache.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
// Assume that we won't need this at this point, UNREGISTER_PATH is rare
|
||||
_oldCache.clear();
|
||||
}
|
||||
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
|
||||
for (auto& path : removedPaths)
|
||||
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, path.data(), NULL);
|
||||
} else if (StringUtil::begins_with(response, wstring(L"STATUS:")) ||
|
||||
StringUtil::begins_with(response, wstring(L"BROADCAST:"))) {
|
||||
|
||||
@@ -116,57 +125,57 @@ void RemotePathChecker::workerThreadLoop()
|
||||
auto state = _StrToFileState(responseStatus);
|
||||
bool wasAsked = asked.erase(responsePath) > 0;
|
||||
|
||||
bool changed = false;
|
||||
bool updateView = false;
|
||||
{ std::unique_lock<std::mutex> lock(_mutex);
|
||||
bool wasCached = _cache.find(responsePath) != _cache.end();
|
||||
if (wasAsked || wasCached) {
|
||||
auto &it = _cache[responsePath];
|
||||
changed = (it != state);
|
||||
it = state;
|
||||
auto it = _cache.find(responsePath);
|
||||
if (it == _cache.end()) {
|
||||
// The client only approximates requested files, if the bloom
|
||||
// filter becomes saturated after navigating multiple directories we'll start getting
|
||||
// status pushes that we never requested and fill our cache. Ignore those.
|
||||
if (!wasAsked) {
|
||||
continue;
|
||||
}
|
||||
it = _cache.insert(make_pair(responsePath, StateNone)).first;
|
||||
}
|
||||
|
||||
updateView = it->second != state;
|
||||
it->second = state;
|
||||
}
|
||||
if (changed) {
|
||||
if (updateView) {
|
||||
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), NULL);
|
||||
}
|
||||
}
|
||||
else if (StringUtil::begins_with(response, wstring(L"UPDATE_VIEW"))) {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
// Keep the old states to continue having something to display while the new state is
|
||||
// requested from the client, triggered by clearing _cache.
|
||||
_oldCache.insert(_cache.cbegin(), _cache.cend());
|
||||
|
||||
// Swap to make a copy of the cache under the mutex and clear the one stored.
|
||||
std::unordered_map<std::wstring, FileState> cache;
|
||||
swap(cache, _cache);
|
||||
lock.unlock();
|
||||
// Let explorer know about the invalidated cache entries, it will re-request the ones it needs.
|
||||
for (auto it = cache.begin(); it != cache.end(); ++it) {
|
||||
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, it->first.data(), NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (socket.Event() == INVALID_HANDLE_VALUE) {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_cache.clear();
|
||||
_oldCache.clear();
|
||||
_watchedDirectories.clear();
|
||||
_connected = connected = false;
|
||||
}
|
||||
if (socket.Event() == INVALID_HANDLE_VALUE) {
|
||||
atomic_store(&_watchedDirectories, make_shared<const vector<wstring>>());
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_connected = connected = false;
|
||||
|
||||
if (_stop) return;
|
||||
// Swap to make a copy of the cache under the mutex and clear the one stored.
|
||||
std::unordered_map<std::wstring, FileState> cache;
|
||||
swap(cache, _cache);
|
||||
lock.unlock();
|
||||
// Let explorer know about each invalidated cache entry that needs to get its icon removed.
|
||||
for (auto it = cache.begin(); it != cache.end(); ++it) {
|
||||
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, it->first.data(), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
HANDLE handles[2] = { _newQueries, socket.Event() };
|
||||
WaitForMultipleObjects(2, handles, false, 0);
|
||||
if (_stop) return;
|
||||
|
||||
HANDLE handles[2] = { _newQueries, socket.Event() };
|
||||
WaitForMultipleObjects(2, handles, false, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
RemotePathChecker::RemotePathChecker()
|
||||
: _connected(false)
|
||||
: _watchedDirectories(make_shared<const vector<wstring>>())
|
||||
, _connected(false)
|
||||
, _newQueries(CreateEvent(NULL, true, true, NULL))
|
||||
, _thread([this]{ this->workerThreadLoop(); })
|
||||
, _thread([this]{ this->workerThreadLoop(); })
|
||||
{
|
||||
}
|
||||
|
||||
@@ -179,10 +188,9 @@ RemotePathChecker::~RemotePathChecker()
|
||||
CloseHandle(_newQueries);
|
||||
}
|
||||
|
||||
vector<wstring> RemotePathChecker::WatchedDirectories()
|
||||
std::shared_ptr<const std::vector<std::wstring>> RemotePathChecker::WatchedDirectories() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
return _watchedDirectories;
|
||||
return atomic_load(&_watchedDirectories);
|
||||
}
|
||||
|
||||
bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state)
|
||||
@@ -198,44 +206,39 @@ bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state)
|
||||
|
||||
auto it = _cache.find(path);
|
||||
if (it != _cache.end()) {
|
||||
// The path is in our cache, and we'll get updates pushed if the status changes.
|
||||
*state = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Re-request the status while we display what we have in _oldCache
|
||||
_pending.push(filePath);
|
||||
|
||||
it = _oldCache.find(path);
|
||||
bool foundInOldCache = it != _oldCache.end();
|
||||
if (foundInOldCache)
|
||||
*state = it->second;
|
||||
|
||||
lock.unlock();
|
||||
SetEvent(_newQueries);
|
||||
return foundInOldCache;
|
||||
return false;
|
||||
}
|
||||
|
||||
RemotePathChecker::FileState RemotePathChecker::_StrToFileState(const std::wstring &str)
|
||||
{
|
||||
if (str == L"NOP" || str == L"NONE") {
|
||||
return StateNone;
|
||||
} else if (str == L"SYNC" || str == L"NEW") {
|
||||
return StateSync;
|
||||
} else if (str == L"SYNC+SWM" || str == L"NEW+SWM") {
|
||||
return StateSync;
|
||||
} else if (str == L"OK") {
|
||||
return StateOk;
|
||||
} else if (str == L"OK+SWM") {
|
||||
return StateOkSWM;
|
||||
} else if (str == L"IGNORE") {
|
||||
return StateWarning;
|
||||
} else if (str == L"IGNORE+SWM") {
|
||||
return StateWarning;
|
||||
} else if (str == L"ERROR") {
|
||||
return StateError;
|
||||
} else if (str == L"ERROR+SWM") {
|
||||
return StateError;
|
||||
}
|
||||
if (str == L"NOP" || str == L"NONE") {
|
||||
return StateNone;
|
||||
} else if (str == L"SYNC" || str == L"NEW") {
|
||||
return StateSync;
|
||||
} else if (str == L"SYNC+SWM" || str == L"NEW+SWM") {
|
||||
return StateSync;
|
||||
} else if (str == L"OK") {
|
||||
return StateOk;
|
||||
} else if (str == L"OK+SWM") {
|
||||
return StateOkSWM;
|
||||
} else if (str == L"IGNORE") {
|
||||
return StateWarning;
|
||||
} else if (str == L"IGNORE+SWM") {
|
||||
return StateWarning;
|
||||
} else if (str == L"ERROR") {
|
||||
return StateError;
|
||||
} else if (str == L"ERROR+SWM") {
|
||||
return StateError;
|
||||
}
|
||||
|
||||
return StateNone;
|
||||
return StateNone;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
@@ -27,21 +28,21 @@
|
||||
|
||||
class __declspec(dllexport) RemotePathChecker {
|
||||
public:
|
||||
enum FileState {
|
||||
// Order synced with OCOverlay
|
||||
StateError = 0,
|
||||
StateOk, StateOkSWM,
|
||||
StateSync,
|
||||
StateWarning,
|
||||
StateNone
|
||||
};
|
||||
RemotePathChecker();
|
||||
enum FileState {
|
||||
// Order synced with OCOverlay
|
||||
StateError = 0,
|
||||
StateOk, StateOkSWM,
|
||||
StateSync,
|
||||
StateWarning,
|
||||
StateNone
|
||||
};
|
||||
RemotePathChecker();
|
||||
~RemotePathChecker();
|
||||
std::vector<std::wstring> WatchedDirectories();
|
||||
bool IsMonitoredPath(const wchar_t* filePath, int* state);
|
||||
std::shared_ptr<const std::vector<std::wstring>> WatchedDirectories() const;
|
||||
bool IsMonitoredPath(const wchar_t* filePath, int* state);
|
||||
|
||||
private:
|
||||
FileState _StrToFileState(const std::wstring &str);
|
||||
FileState _StrToFileState(const std::wstring &str);
|
||||
std::mutex _mutex;
|
||||
std::atomic<bool> _stop;
|
||||
|
||||
@@ -52,8 +53,9 @@ private:
|
||||
std::queue<std::wstring> _pending;
|
||||
|
||||
std::unordered_map<std::wstring, FileState> _cache;
|
||||
std::unordered_map<std::wstring, FileState> _oldCache;
|
||||
std::vector<std::wstring> _watchedDirectories;
|
||||
// The vector is const since it will be accessed from multiple threads through OCOverlay::IsMemberOf.
|
||||
// Each modification needs to be made onto a copy and then atomically replaced in the shared_ptr.
|
||||
std::shared_ptr<const std::vector<std::wstring>> _watchedDirectories;
|
||||
bool _connected;
|
||||
|
||||
|
||||
@@ -61,7 +63,7 @@ private:
|
||||
//std::condition_variable _newQueries;
|
||||
HANDLE _newQueries;
|
||||
|
||||
std::thread _thread;
|
||||
std::thread _thread;
|
||||
void workerThreadLoop();
|
||||
};
|
||||
|
||||
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário