Compare commits
89 Commits
v2.6.0-fix
...
v2.6.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5adbc01ef1 | ||
|
|
c4a04bfd05 | ||
|
|
03711429f4 | ||
|
|
e3cb040c3c | ||
|
|
83a21179fa | ||
|
|
829da85aa5 | ||
|
|
3b1ac89312 | ||
|
|
57df29e7c9 | ||
|
|
d774067004 | ||
|
|
728154386c | ||
|
|
bc31182c63 | ||
|
|
a6bb84080a | ||
|
|
576ba7c011 | ||
|
|
b6893aad16 | ||
|
|
59d1624ce5 | ||
|
|
a0faf1f54d | ||
|
|
caa7c845c2 | ||
|
|
e43a80d0be | ||
|
|
f060a92563 | ||
|
|
483696261d | ||
|
|
610e35ec64 | ||
|
|
5fa5526ea2 | ||
|
|
42d9d99a92 | ||
|
|
c3ff9ca917 | ||
|
|
875f123d5b | ||
|
|
a5f053afe4 | ||
|
|
63a6992f97 | ||
|
|
54740378f0 | ||
|
|
1dc443bc06 | ||
|
|
e541109d7c | ||
|
|
993f124120 | ||
|
|
0a373ea708 | ||
|
|
0fae01495e | ||
|
|
97867384b1 | ||
|
|
c54f6e83ed | ||
|
|
a9a731dfc0 | ||
|
|
d0f469bd90 | ||
|
|
374375ce3f | ||
|
|
89ef03412e | ||
|
|
07d3fe3a79 | ||
|
|
24107040cc | ||
|
|
9d9fc6d0bf | ||
|
|
51f5991f1e | ||
|
|
a8b93516cc | ||
|
|
a85c228e59 | ||
|
|
04a75eaca2 | ||
|
|
2f46601396 | ||
|
|
18fc6a9e0e | ||
|
|
34675e03a8 | ||
|
|
4b5cf94a29 | ||
|
|
1729e1a94c | ||
|
|
60859714ae | ||
|
|
b5fcfd918b | ||
|
|
44176be964 | ||
|
|
3935866052 | ||
|
|
1e9c45222c | ||
|
|
adc3b1a25c | ||
|
|
9ae0417cad | ||
|
|
03453d6800 | ||
|
|
1ac9c4ea8d | ||
|
|
986bb49a88 | ||
|
|
8f39c4140e | ||
|
|
9c7903868f | ||
|
|
8ee1adf058 | ||
|
|
27fb1fcd53 | ||
|
|
29cc5c1e7f | ||
|
|
29bb76019f | ||
|
|
bf6d57f327 | ||
|
|
eb5ec05ef8 | ||
|
|
c723028eae | ||
|
|
5d024fdf33 | ||
|
|
ed99cb297b | ||
|
|
a0e794a7f1 | ||
|
|
0761342840 | ||
|
|
4da9123b67 | ||
|
|
c7158e2c7c | ||
|
|
4adc45483a | ||
|
|
ae0ff6b3e3 | ||
|
|
dc6d2e6a6d | ||
|
|
5127f50d1e | ||
|
|
a26f2a7359 | ||
|
|
42f1f445a9 | ||
|
|
51304485c3 | ||
|
|
63cc6edddd | ||
|
|
58abebe9ac | ||
|
|
1182ae9e26 | ||
|
|
3407174c2f | ||
|
|
913894eaa5 | ||
|
|
db91552578 |
@@ -198,7 +198,7 @@ X-GNOME-Autostart-Delay=3
|
|||||||
|
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
Icon[de]=@APPLICATION_ICON_NAME@
|
Icon[de_DE]=@APPLICATION_ICON_NAME@
|
||||||
Name[de]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
|
Name[de_DE]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
|
||||||
Comment[de]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
|
Comment[de_DE]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
|
||||||
GenericName[de]=Synchronisationsordner
|
GenericName[de_DE]=Synchronisationsordner
|
||||||
|
|||||||
@@ -203,8 +203,16 @@ if( WIN32 )
|
|||||||
add_definitions( -D__USE_MINGW_ANSI_STDIO=1 )
|
add_definitions( -D__USE_MINGW_ANSI_STDIO=1 )
|
||||||
add_definitions( -DNOMINMAX )
|
add_definitions( -DNOMINMAX )
|
||||||
# Get APIs from from Vista onwards.
|
# Get APIs from from Vista onwards.
|
||||||
add_definitions( -D_WIN32_WINNT=0x0600)
|
add_definitions( -D_WIN32_WINNT=0x0601 )
|
||||||
add_definitions( -DWINVER=0x0600)
|
add_definitions( -DWINVER=0x0601 )
|
||||||
|
if( MSVC )
|
||||||
|
# Use automatic overload for suitable CRT safe-functions
|
||||||
|
# See https://docs.microsoft.com/de-de/cpp/c-runtime-library/security-features-in-the-crt?view=vs-2019
|
||||||
|
add_definitions( -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1 )
|
||||||
|
# Also: Disable compiler warnings because we don't use Windows CRT safe-functions explicitly and don't intend to
|
||||||
|
# as this is a pure cross-platform source the only alternative would be a ton of ifdefs with calls to the _s version
|
||||||
|
add_definitions( -D_CRT_SECURE_NO_WARNINGS )
|
||||||
|
endif( MSVC )
|
||||||
endif( WIN32 )
|
endif( WIN32 )
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
set( MIRALL_VERSION_MAJOR 2 )
|
set( MIRALL_VERSION_MAJOR 2 )
|
||||||
set( MIRALL_VERSION_MINOR 6 )
|
set( MIRALL_VERSION_MINOR 6 )
|
||||||
set( MIRALL_VERSION_PATCH 0 )
|
set( MIRALL_VERSION_PATCH 1 )
|
||||||
set( MIRALL_VERSION_YEAR 2019 )
|
set( MIRALL_VERSION_YEAR 2019 )
|
||||||
set( MIRALL_SOVERSION 0 )
|
set( MIRALL_SOVERSION 0 )
|
||||||
|
|
||||||
|
|||||||
@@ -32,11 +32,12 @@ FRAMEWORK_SEARCH_PATH=[
|
|||||||
os.path.join(os.environ['HOME'], 'Library/Frameworks')
|
os.path.join(os.environ['HOME'], 'Library/Frameworks')
|
||||||
]
|
]
|
||||||
|
|
||||||
LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/Qt-5.6.2/lib', '.']
|
LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/Qt-5.12.5/lib', '.']
|
||||||
|
|
||||||
QT_PLUGINS = [
|
QT_PLUGINS = [
|
||||||
'sqldrivers/libqsqlite.dylib',
|
'sqldrivers/libqsqlite.dylib',
|
||||||
'platforms/libqcocoa.dylib',
|
'platforms/libqcocoa.dylib',
|
||||||
|
'styles/libqmacstyle.dylib',
|
||||||
'imageformats/libqgif.dylib',
|
'imageformats/libqgif.dylib',
|
||||||
'imageformats/libqico.dylib',
|
'imageformats/libqico.dylib',
|
||||||
'imageformats/libqjpeg.dylib',
|
'imageformats/libqjpeg.dylib',
|
||||||
@@ -46,7 +47,7 @@ QT_PLUGINS = [
|
|||||||
QT_PLUGINS_SEARCH_PATH=[
|
QT_PLUGINS_SEARCH_PATH=[
|
||||||
# os.path.join(os.environ['QTDIR'], 'plugins'),
|
# os.path.join(os.environ['QTDIR'], 'plugins'),
|
||||||
# '/usr/local/Cellar/qt/5.2.1/plugins',
|
# '/usr/local/Cellar/qt/5.2.1/plugins',
|
||||||
'/usr/local/Qt-5.6.2/plugins',
|
'/usr/local/Qt-5.12.5/plugins',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 254 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 151 KiB |
2
binary
@@ -3,7 +3,11 @@
|
|||||||
# For details see the accompanying COPYING* file.
|
# For details see the accompanying COPYING* file.
|
||||||
|
|
||||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long -Wno-gnu-zero-variadic-macro-arguments")
|
|
||||||
|
# Use this only for Clang
|
||||||
|
if (CMAKE_CXX_COMPILER MATCHES "Clang")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long -Wno-gnu-zero-variadic-macro-arguments")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Fix sqlite compilation on macOS
|
# Fix sqlite compilation on macOS
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-incompatible-pointer-types-discards-qualifiers")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-incompatible-pointer-types-discards-qualifiers")
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ IFACEMETHODIMP OCContextMenu::Initialize(
|
|||||||
HDROP hDrop = static_cast<HDROP>(GlobalLock(stm.hGlobal));
|
HDROP hDrop = static_cast<HDROP>(GlobalLock(stm.hGlobal));
|
||||||
if (hDrop) {
|
if (hDrop) {
|
||||||
UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
|
UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
|
||||||
for (int i = 0; i < nFiles; ++i) {
|
for (UINT i = 0; i < nFiles; ++i) {
|
||||||
// Get the path of the file.
|
// Get the path of the file.
|
||||||
wchar_t buffer[MAX_PATH];
|
wchar_t buffer[MAX_PATH];
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
|
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
|
||||||
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
|
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
|
||||||
|
|
||||||
#define WINVER 0x0501
|
// Note: Here was a #define for windows target version
|
||||||
#define _WIN32_WINNT 0x0501
|
// e.g. WINVER / _WIN32_WINNT, see https://devblogs.microsoft.com/oldnewthing/20070411-00/?p=27283
|
||||||
|
// Unnecessary because we define both in desktop/CMakeLists.txt
|
||||||
|
|
||||||
#include <SDKDDKVer.h>
|
#include <SDKDDKVer.h>
|
||||||
|
|||||||
@@ -13,8 +13,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#define WINVER 0x0501
|
|
||||||
#define _WIN32_WINNT 0x0501
|
// Note: Here was a #define for windows target version
|
||||||
|
// e.g. WINVER / _WIN32_WINNT, see https://devblogs.microsoft.com/oldnewthing/20070411-00/?p=27283
|
||||||
|
// Unnecessary because we define both in desktop/CMakeLists.txt
|
||||||
|
|
||||||
#include "CommunicationSocket.h"
|
#include "CommunicationSocket.h"
|
||||||
#include "RegistryUtil.h"
|
#include "RegistryUtil.h"
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#define WINVER 0x0501
|
|
||||||
#define _WIN32_WINNT 0x0501
|
// Note: Here was a #define for windows target version
|
||||||
|
// e.g. WINVER / _WIN32_WINNT, see https://devblogs.microsoft.com/oldnewthing/20070411-00/?p=27283
|
||||||
|
// Unnecessary because we define both in desktop/CMakeLists.txt
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|||||||
2
src/3rdparty/libcrashreporter-qt
vendored
2
src/3rdparty/qtmacgoodies
vendored
@@ -33,8 +33,8 @@ endif()
|
|||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
# Enable DEP & ASLR
|
# Enable DEP & ASLR
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--nxcompat -Wl,--dynamicbase")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /nxcompat /dynamicbase")
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--nxcompat -Wl,--dynamicbase")
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /nxcompat /dynamicbase")
|
||||||
elseif(UNIX AND NOT APPLE)
|
elseif(UNIX AND NOT APPLE)
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now")
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now")
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now")
|
||||||
|
|||||||
@@ -11,43 +11,50 @@
|
|||||||
|
|
||||||
// For overloading macros by argument count
|
// For overloading macros by argument count
|
||||||
// See stackoverflow.com/questions/16683146/can-macros-be-overloaded-by-number-of-arguments
|
// See stackoverflow.com/questions/16683146/can-macros-be-overloaded-by-number-of-arguments
|
||||||
#define OC_ASSERT_CAT(A, B) A##B
|
// Bugfix 08/09/2019: Broken arg expansion led to always collapsing to 1 arg (XXXX_1 overload result)
|
||||||
#define OC_ASSERT_SELECT(NAME, NUM) OC_ASSERT_CAT(NAME##_, NUM)
|
// See also: https://stackoverflow.com/questions/9183993/msvc-variadic-macro-expansion
|
||||||
#define OC_ASSERT_GET_COUNT(_1, _2, _3, COUNT, ...) COUNT
|
#define OC_ASSERT_GLUE(x, y) x y
|
||||||
#define OC_ASSERT_VA_SIZE(...) OC_ASSERT_GET_COUNT(__VA_ARGS__, 3, 2, 1, 0)
|
|
||||||
|
|
||||||
#define OC_ASSERT_OVERLOAD(NAME, ...) OC_ASSERT_SELECT(NAME, OC_ASSERT_VA_SIZE(__VA_ARGS__)) \
|
#define OC_ASSERT_GET_COUNT(_1, _2, _3, COUNT, ...) COUNT
|
||||||
(__VA_ARGS__)
|
#define OC_ASSERT_EXPAND_ARGS(args) OC_ASSERT_GET_COUNT args
|
||||||
|
#define OC_ASSERT_VA_SIZE(...) OC_ASSERT_EXPAND_ARGS((__VA_ARGS__, 3, 2, 1, 0))
|
||||||
|
|
||||||
|
#define OC_ASSERT_SELECT2(NAME, COUNT) NAME##COUNT
|
||||||
|
#define OC_ASSERT_SELECT1(NAME, COUNT) OC_ASSERT_SELECT2(NAME, COUNT)
|
||||||
|
#define OC_ASSERT_SELECT(NAME, COUNT) OC_ASSERT_SELECT1(NAME, COUNT)
|
||||||
|
|
||||||
|
#define OC_ASSERT_OVERLOAD(NAME, ...) OC_ASSERT_GLUE(OC_ASSERT_SELECT(NAME, OC_ASSERT_VA_SIZE(__VA_ARGS__)), \
|
||||||
|
(__VA_ARGS__))
|
||||||
|
|
||||||
// Default assert: If the condition is false in debug builds, terminate.
|
// Default assert: If the condition is false in debug builds, terminate.
|
||||||
//
|
//
|
||||||
// Prints a message on failure, even in release builds.
|
// Prints a message on failure, even in release builds.
|
||||||
#define ASSERT(...) OC_ASSERT_OVERLOAD(ASSERT, __VA_ARGS__)
|
#define ASSERT1(cond) \
|
||||||
#define ASSERT_1(cond) \
|
|
||||||
if (!(cond)) { \
|
if (!(cond)) { \
|
||||||
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
||||||
} else { \
|
} else { \
|
||||||
}
|
}
|
||||||
#define ASSERT_2(cond, message) \
|
#define ASSERT2(cond, message) \
|
||||||
if (!(cond)) { \
|
if (!(cond)) { \
|
||||||
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
||||||
} else { \
|
} else { \
|
||||||
}
|
}
|
||||||
|
#define ASSERT(...) OC_ASSERT_OVERLOAD(ASSERT, __VA_ARGS__)
|
||||||
|
|
||||||
// Enforce condition to be true, even in release builds.
|
// Enforce condition to be true, even in release builds.
|
||||||
//
|
//
|
||||||
// Prints 'message' and aborts execution if 'cond' is false.
|
// Prints 'message' and aborts execution if 'cond' is false.
|
||||||
#define ENFORCE(...) OC_ASSERT_OVERLOAD(ENFORCE, __VA_ARGS__)
|
#define ENFORCE1(cond) \
|
||||||
#define ENFORCE_1(cond) \
|
|
||||||
if (!(cond)) { \
|
if (!(cond)) { \
|
||||||
qFatal("ENFORCE: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
qFatal("ENFORCE: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
||||||
} else { \
|
} else { \
|
||||||
}
|
}
|
||||||
#define ENFORCE_2(cond, message) \
|
#define ENFORCE2(cond, message) \
|
||||||
if (!(cond)) { \
|
if (!(cond)) { \
|
||||||
qFatal("ENFORCE: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
qFatal("ENFORCE: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
||||||
} else { \
|
} else { \
|
||||||
}
|
}
|
||||||
|
#define ENFORCE(...) OC_ASSERT_OVERLOAD(ENFORCE, __VA_ARGS__)
|
||||||
|
|
||||||
// An assert that is only present in debug builds: typically used for
|
// An assert that is only present in debug builds: typically used for
|
||||||
// asserts that are too expensive for release mode.
|
// asserts that are too expensive for release mode.
|
||||||
|
|||||||
@@ -207,7 +207,10 @@ static inline uint64_t c_jhash64(const uint8_t *k, uint64_t length, uint64_t int
|
|||||||
/* handle the last 23 bytes */
|
/* handle the last 23 bytes */
|
||||||
c += length;
|
c += length;
|
||||||
switch(len) {
|
switch(len) {
|
||||||
|
// pragma only for GCC (and clang continues to pretend to be it by defining __GNUC__)
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||||
|
#endif
|
||||||
case 23: c+=((uint64_t)k[22]<<56);
|
case 23: c+=((uint64_t)k[22]<<56);
|
||||||
case 22: c+=((uint64_t)k[21]<<48);
|
case 22: c+=((uint64_t)k[21]<<48);
|
||||||
case 21: c+=((uint64_t)k[20]<<40);
|
case 21: c+=((uint64_t)k[20]<<40);
|
||||||
|
|||||||
@@ -281,8 +281,8 @@ int SqlQuery::prepare(const QByteArray &sql, bool allow_failure)
|
|||||||
*/
|
*/
|
||||||
static bool startsWithInsensitive(const QByteArray &a, const char *b)
|
static bool startsWithInsensitive(const QByteArray &a, const char *b)
|
||||||
{
|
{
|
||||||
int len = strlen(b);
|
size_t len = strlen(b);
|
||||||
return a.size() >= len && qstrnicmp(a.constData(), b, len) == 0;
|
return a.size() >= len && qstrnicmp(a.constData(), b, Utility::convertSizeToUint(len)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SqlQuery::isSelect()
|
bool SqlQuery::isSelect()
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ public:
|
|||||||
: _chunk(0)
|
: _chunk(0)
|
||||||
, _transferid(0)
|
, _transferid(0)
|
||||||
, _size(0)
|
, _size(0)
|
||||||
|
, _modtime(0)
|
||||||
, _errorCount(0)
|
, _errorCount(0)
|
||||||
, _valid(false)
|
, _valid(false)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -396,6 +396,26 @@ void Utility::crash()
|
|||||||
*a = 1;
|
*a = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use this functions to retrieve uint/int (often required by Qt and WIN32) from size_t
|
||||||
|
// without compiler warnings about possible truncation
|
||||||
|
uint Utility::convertSizeToUint(size_t &convertVar)
|
||||||
|
{
|
||||||
|
if( convertVar > UINT_MAX ) {
|
||||||
|
//throw std::bad_cast();
|
||||||
|
convertVar = UINT_MAX; // intentionally default to wrong value here to not crash: exception handling TBD
|
||||||
|
}
|
||||||
|
return static_cast<uint>(convertVar);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint Utility::convertSizeToInt(size_t &convertVar)
|
||||||
|
{
|
||||||
|
if( convertVar > INT_MAX ) {
|
||||||
|
//throw std::bad_cast();
|
||||||
|
convertVar = INT_MAX; // intentionally default to wrong value here to not crash: exception handling TBD
|
||||||
|
}
|
||||||
|
return static_cast<int>(convertVar);
|
||||||
|
}
|
||||||
|
|
||||||
// read the output of the owncloud --version command from the owncloud
|
// read the output of the owncloud --version command from the owncloud
|
||||||
// version that is on disk. This works for most versions of the client,
|
// version that is on disk. This works for most versions of the client,
|
||||||
// because clients that do not yet know the --version flag return the
|
// because clients that do not yet know the --version flag return the
|
||||||
|
|||||||
@@ -55,6 +55,12 @@ namespace Utility {
|
|||||||
OCSYNC_EXPORT QByteArray userAgentString();
|
OCSYNC_EXPORT QByteArray userAgentString();
|
||||||
OCSYNC_EXPORT bool hasLaunchOnStartup(const QString &appName);
|
OCSYNC_EXPORT bool hasLaunchOnStartup(const QString &appName);
|
||||||
OCSYNC_EXPORT void setLaunchOnStartup(const QString &appName, const QString &guiName, bool launch);
|
OCSYNC_EXPORT void setLaunchOnStartup(const QString &appName, const QString &guiName, bool launch);
|
||||||
|
OCSYNC_EXPORT uint convertSizeToUint(size_t &convertVar);
|
||||||
|
OCSYNC_EXPORT uint convertSizeToInt(size_t &convertVar);
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
OCSYNC_EXPORT DWORD convertSizeToDWORD(size_t &convertVar);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the amount of free space available.
|
* Return the amount of free space available.
|
||||||
|
|||||||
@@ -90,32 +90,13 @@ void setLaunchOnStartup_private(const QString &appName, const QString &guiName,
|
|||||||
// TODO: Right now only detection on toggle/startup, not when windows theme is switched while nextcloud is running
|
// TODO: Right now only detection on toggle/startup, not when windows theme is switched while nextcloud is running
|
||||||
static inline bool hasDarkSystray_private()
|
static inline bool hasDarkSystray_private()
|
||||||
{
|
{
|
||||||
bool hasDarkSystray = true;
|
if(Utility::registryGetKeyValue( HKEY_CURRENT_USER,
|
||||||
// Open registry key first, continue only on success (may be legitimately absent in earlier windows versions)
|
"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||||
HKEY hKey;
|
"SystemUsesLightTheme" ) == 1) {
|
||||||
LONG lRes = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_READ, &hKey);
|
return false;
|
||||||
|
}
|
||||||
// classical windows function - preserve buff size for DWORD, call ExW version, store regkey value in nResult
|
else {
|
||||||
if (lRes == ERROR_SUCCESS) {
|
return true;
|
||||||
DWORD dwBufferSize(sizeof(DWORD));
|
|
||||||
DWORD nResult(0);
|
|
||||||
|
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexw
|
|
||||||
LONG nError = ::RegQueryValueExW(hKey,
|
|
||||||
L"SystemUsesLightTheme",
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
reinterpret_cast<LPBYTE>(&nResult),
|
|
||||||
&dwBufferSize);
|
|
||||||
|
|
||||||
// if RegQuery returned no error and light theme was found, change systray return value
|
|
||||||
if (nError == ERROR_SUCCESS && nResult == 1)
|
|
||||||
hasDarkSystray = false;
|
|
||||||
|
|
||||||
return hasDarkSystray;
|
|
||||||
} else {
|
|
||||||
// fallback to true if regkey could not be determined
|
|
||||||
return hasDarkSystray;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,4 +264,13 @@ bool Utility::registryWalkSubKeys(HKEY hRootKey, const QString &subKey, const st
|
|||||||
return retCode != ERROR_NO_MORE_ITEMS;
|
return retCode != ERROR_NO_MORE_ITEMS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DWORD Utility::convertSizeToDWORD(size_t &convertVar)
|
||||||
|
{
|
||||||
|
if( convertVar > UINT_MAX ) {
|
||||||
|
//throw std::bad_cast();
|
||||||
|
convertVar = UINT_MAX; // intentionally default to wrong value here to not crash: exception handling TBD
|
||||||
|
}
|
||||||
|
return static_cast<DWORD>(convertVar);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ static void csync_exclude_expand_escapes(QByteArray &input)
|
|||||||
line[o++] = line[i];
|
line[o++] = line[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
input.resize(o);
|
input.resize(OCC::Utility::convertSizeToUint(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
// See http://support.microsoft.com/kb/74496 and
|
// See http://support.microsoft.com/kb/74496 and
|
||||||
@@ -322,7 +322,11 @@ bool ExcludedFiles::loadExcludeFile(const QByteArray & basePath, const QString &
|
|||||||
csync_exclude_expand_escapes(line);
|
csync_exclude_expand_escapes(line);
|
||||||
_allExcludes[basePath].append(line);
|
_allExcludes[basePath].append(line);
|
||||||
}
|
}
|
||||||
prepare(basePath);
|
|
||||||
|
// nothing to prepare if the user decided to not exclude anything
|
||||||
|
if(_allExcludes.size())
|
||||||
|
prepare(basePath);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,8 +342,8 @@ bool ExcludedFiles::reloadExcludeFiles()
|
|||||||
_fullRegexDir.clear();
|
_fullRegexDir.clear();
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
for (auto basePath : _excludeFiles.keys()) {
|
for (const auto& basePath : _excludeFiles.keys()) {
|
||||||
for (auto file : _excludeFiles.value(basePath)) {
|
for (const auto& file : _excludeFiles.value(basePath)) {
|
||||||
success = loadExcludeFile(basePath, file);
|
success = loadExcludeFile(basePath, file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -724,7 +724,8 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
|||||||
if (ctx->current == LOCAL_REPLICA) {
|
if (ctx->current == LOCAL_REPLICA) {
|
||||||
ASSERT(dirent->path.startsWith(ctx->local.uri)); // path is relative to uri
|
ASSERT(dirent->path.startsWith(ctx->local.uri)); // path is relative to uri
|
||||||
// "len + 1" to include the slash in-between.
|
// "len + 1" to include the slash in-between.
|
||||||
dirent->path = dirent->path.mid(strlen(ctx->local.uri) + 1);
|
size_t uriLength = strlen(ctx->local.uri);
|
||||||
|
dirent->path = dirent->path.mid(OCC::Utility::convertSizeToInt(uriLength) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
previous_fs = ctx->current_fs;
|
previous_fs = ctx->current_fs;
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
#include "c_alloc.h"
|
#include "c_alloc.h"
|
||||||
#include "c_string.h"
|
#include "c_string.h"
|
||||||
#include "common/filesystembase.h"
|
#include "common/filesystembase.h"
|
||||||
|
#include "common/utility.h"
|
||||||
|
|
||||||
/* Convert a locale String to UTF8 */
|
/* Convert a locale String to UTF8 */
|
||||||
QByteArray c_utf8_from_locale(const mbchar_t *wstr)
|
QByteArray c_utf8_from_locale(const mbchar_t *wstr)
|
||||||
@@ -52,10 +53,10 @@ QByteArray c_utf8_from_locale(const mbchar_t *wstr)
|
|||||||
size_t len;
|
size_t len;
|
||||||
len = wcslen(wstr);
|
len = wcslen(wstr);
|
||||||
/* Call once to get the required size. */
|
/* Call once to get the required size. */
|
||||||
size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, len, NULL, 0, NULL, NULL);
|
size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, OCC::Utility::convertSizeToInt(len), NULL, 0, NULL, NULL);
|
||||||
if (size_needed > 0) {
|
if (size_needed > 0) {
|
||||||
dst.resize(size_needed);
|
dst.resize(size_needed);
|
||||||
WideCharToMultiByte(CP_UTF8, 0, wstr, len, dst.data(), size_needed, NULL, NULL);
|
WideCharToMultiByte(CP_UTF8, 0, wstr, OCC::Utility::convertSizeToInt(len), dst.data(), size_needed, NULL, NULL);
|
||||||
}
|
}
|
||||||
return dst;
|
return dst;
|
||||||
#else
|
#else
|
||||||
@@ -95,7 +96,7 @@ mbchar_t* c_utf8_string_to_locale(const char *str)
|
|||||||
int size_needed;
|
int size_needed;
|
||||||
|
|
||||||
len = strlen(str);
|
len = strlen(str);
|
||||||
size_needed = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
|
size_needed = MultiByteToWideChar(CP_UTF8, 0, str, OCC::Utility::convertSizeToInt(len), NULL, 0);
|
||||||
if (size_needed > 0) {
|
if (size_needed > 0) {
|
||||||
int size_char = (size_needed + 1) * sizeof(mbchar_t);
|
int size_char = (size_needed + 1) * sizeof(mbchar_t);
|
||||||
dst = (mbchar_t*)c_malloc(size_char);
|
dst = (mbchar_t*)c_malloc(size_char);
|
||||||
@@ -114,7 +115,8 @@ mbchar_t* c_utf8_string_to_locale(const char *str)
|
|||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
QByteArray unc_str = OCC::FileSystem::pathtoUNC(QByteArray::fromRawData(str, strlen(str)));
|
size_t strLength = strlen(str);
|
||||||
|
QByteArray unc_str = OCC::FileSystem::pathtoUNC(QByteArray::fromRawData(str, OCC::Utility::convertSizeToInt(strLength)));
|
||||||
mbchar_t *dst = c_utf8_string_to_locale(unc_str);
|
mbchar_t *dst = c_utf8_string_to_locale(unc_str);
|
||||||
return dst;
|
return dst;
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ csync_vio_handle_t *csync_vio_local_opendir(const char *name) {
|
|||||||
handle = (dhandle_t*)c_malloc(sizeof(dhandle_t));
|
handle = (dhandle_t*)c_malloc(sizeof(dhandle_t));
|
||||||
|
|
||||||
// the file wildcard has to be attached
|
// the file wildcard has to be attached
|
||||||
int len_name = strlen(name);
|
size_t len_name = strlen(name);
|
||||||
if( len_name ) {
|
if( len_name ) {
|
||||||
char *h = NULL;
|
char *h = NULL;
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ set(client_SRCS
|
|||||||
guiutility.cpp
|
guiutility.cpp
|
||||||
elidedlabel.cpp
|
elidedlabel.cpp
|
||||||
iconjob.cpp
|
iconjob.cpp
|
||||||
|
remotewipe.cpp
|
||||||
creds/credentialsfactory.cpp
|
creds/credentialsfactory.cpp
|
||||||
creds/httpcredentialsgui.cpp
|
creds/httpcredentialsgui.cpp
|
||||||
creds/oauth.cpp
|
creds/oauth.cpp
|
||||||
@@ -181,6 +182,9 @@ if (APPLE)
|
|||||||
../3rdparty/qtmacgoodies/src/macstandardicon.mm
|
../3rdparty/qtmacgoodies/src/macstandardicon.mm
|
||||||
../3rdparty/qtmacgoodies/src/macwindow.mm
|
../3rdparty/qtmacgoodies/src/macwindow.mm
|
||||||
)
|
)
|
||||||
|
# We want to access Cocoa specific structures in the code above
|
||||||
|
# and need the platform plugin interface for that - which is private.
|
||||||
|
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
|
|||||||
@@ -368,6 +368,7 @@ void AccountManager::shutdown()
|
|||||||
_accounts.clear();
|
_accounts.clear();
|
||||||
foreach (const auto &acc, accountsCopy) {
|
foreach (const auto &acc, accountsCopy) {
|
||||||
emit accountRemoved(acc.data());
|
emit accountRemoved(acc.data());
|
||||||
|
emit removeAccountFolders(acc.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void deleteAccount(AccountState *account);
|
void deleteAccount(AccountState *account);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an account and sets up some basic handlers.
|
* Creates an account and sets up some basic handlers.
|
||||||
* Does *not* add the account to the account manager just yet.
|
* Does *not* add the account to the account manager just yet.
|
||||||
@@ -104,6 +103,7 @@ public slots:
|
|||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void accountAdded(AccountState *account);
|
void accountAdded(AccountState *account);
|
||||||
void accountRemoved(AccountState *account);
|
void accountRemoved(AccountState *account);
|
||||||
|
void removeAccountFolders(AccountState *account);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AccountManager() {}
|
AccountManager() {}
|
||||||
|
|||||||
@@ -147,6 +147,8 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
|
|||||||
createAccountToolbox();
|
createAccountToolbox();
|
||||||
connect(AccountManager::instance(), &AccountManager::accountAdded,
|
connect(AccountManager::instance(), &AccountManager::accountAdded,
|
||||||
this, &AccountSettings::slotAccountAdded);
|
this, &AccountSettings::slotAccountAdded);
|
||||||
|
connect(this, &AccountSettings::removeAccountFolders,
|
||||||
|
AccountManager::instance(), &AccountManager::removeAccountFolders);
|
||||||
connect(ui->_folderList, &QWidget::customContextMenuRequested,
|
connect(ui->_folderList, &QWidget::customContextMenuRequested,
|
||||||
this, &AccountSettings::slotCustomContextMenuRequested);
|
this, &AccountSettings::slotCustomContextMenuRequested);
|
||||||
connect(ui->_folderList, &QAbstractItemView::clicked,
|
connect(ui->_folderList, &QAbstractItemView::clicked,
|
||||||
@@ -334,9 +336,9 @@ void AccountSettings::slotEncryptionFlagError(const QByteArray& fileId, int http
|
|||||||
|
|
||||||
void AccountSettings::slotLockForEncryptionSuccess(const QByteArray& fileId, const QByteArray &token)
|
void AccountSettings::slotLockForEncryptionSuccess(const QByteArray& fileId, const QByteArray &token)
|
||||||
{
|
{
|
||||||
accountsState()->account()->e2e()->setTokenForFolder(fileId, token);
|
accountsState()->account()->e2e()->setTokenForFolder(fileId, token);
|
||||||
|
|
||||||
FolderMetadata emptyMetadata(accountsState()->account());
|
FolderMetadata emptyMetadata(accountsState()->account());
|
||||||
auto encryptedMetadata = emptyMetadata.encryptedMetadata();
|
auto encryptedMetadata = emptyMetadata.encryptedMetadata();
|
||||||
if (encryptedMetadata.isEmpty()) {
|
if (encryptedMetadata.isEmpty()) {
|
||||||
//TODO: Mark the folder as unencrypted as the metadata generation failed.
|
//TODO: Mark the folder as unencrypted as the metadata generation failed.
|
||||||
@@ -348,36 +350,36 @@ void AccountSettings::slotLockForEncryptionSuccess(const QByteArray& fileId, con
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto storeMetadataJob = new StoreMetaDataApiJob(accountsState()->account(), fileId, emptyMetadata.encryptedMetadata());
|
auto storeMetadataJob = new StoreMetaDataApiJob(accountsState()->account(), fileId, emptyMetadata.encryptedMetadata());
|
||||||
connect(storeMetadataJob, &StoreMetaDataApiJob::success,
|
connect(storeMetadataJob, &StoreMetaDataApiJob::success,
|
||||||
this, &AccountSettings::slotUploadMetadataSuccess);
|
this, &AccountSettings::slotUploadMetadataSuccess);
|
||||||
connect(storeMetadataJob, &StoreMetaDataApiJob::error,
|
connect(storeMetadataJob, &StoreMetaDataApiJob::error,
|
||||||
this, &AccountSettings::slotUpdateMetadataError);
|
this, &AccountSettings::slotUpdateMetadataError);
|
||||||
|
|
||||||
storeMetadataJob->start();
|
storeMetadataJob->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountSettings::slotUploadMetadataSuccess(const QByteArray& folderId)
|
void AccountSettings::slotUploadMetadataSuccess(const QByteArray& folderId)
|
||||||
{
|
{
|
||||||
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
|
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
|
||||||
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
|
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
|
||||||
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
|
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
|
||||||
this, &AccountSettings::slotUnlockFolderSuccess);
|
this, &AccountSettings::slotUnlockFolderSuccess);
|
||||||
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
|
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
|
||||||
this, &AccountSettings::slotUnlockFolderError);
|
this, &AccountSettings::slotUnlockFolderError);
|
||||||
unlockJob->start();
|
unlockJob->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountSettings::slotUpdateMetadataError(const QByteArray& folderId, int httpReturnCode)
|
void AccountSettings::slotUpdateMetadataError(const QByteArray& folderId, int httpReturnCode)
|
||||||
{
|
{
|
||||||
Q_UNUSED(httpReturnCode);
|
Q_UNUSED(httpReturnCode);
|
||||||
|
|
||||||
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
|
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
|
||||||
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
|
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
|
||||||
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
|
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
|
||||||
this, &AccountSettings::slotUnlockFolderSuccess);
|
this, &AccountSettings::slotUnlockFolderSuccess);
|
||||||
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
|
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
|
||||||
this, &AccountSettings::slotUnlockFolderError);
|
this, &AccountSettings::slotUnlockFolderError);
|
||||||
unlockJob->start();
|
unlockJob->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountSettings::slotLockForEncryptionError(const QByteArray& fileId, int httpErrorCode)
|
void AccountSettings::slotLockForEncryptionError(const QByteArray& fileId, int httpErrorCode)
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ signals:
|
|||||||
void openFolderAlias(const QString &);
|
void openFolderAlias(const QString &);
|
||||||
void showIssuesList(AccountState *account);
|
void showIssuesList(AccountState *account);
|
||||||
void requesetMnemonic();
|
void requesetMnemonic();
|
||||||
|
void removeAccountFolders(AccountState *account);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void slotOpenOC();
|
void slotOpenOC();
|
||||||
|
|||||||
@@ -187,7 +187,7 @@
|
|||||||
<item row="0" column="2">
|
<item row="0" column="2">
|
||||||
<widget class="QToolButton" name="_accountToolbox">
|
<widget class="QToolButton" name="_accountToolbox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>...</string>
|
<string notr="true">...</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "accountstate.h"
|
#include "accountstate.h"
|
||||||
#include "accountmanager.h"
|
#include "accountmanager.h"
|
||||||
|
#include "remotewipe.h"
|
||||||
#include "account.h"
|
#include "account.h"
|
||||||
#include "creds/abstractcredentials.h"
|
#include "creds/abstractcredentials.h"
|
||||||
#include "creds/httpcredentials.h"
|
#include "creds/httpcredentials.h"
|
||||||
@@ -24,6 +25,11 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <qfontmetrics.h>
|
#include <qfontmetrics.h>
|
||||||
|
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QBuffer>
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(lcAccountState, "nextcloud.gui.account.state", QtInfoMsg)
|
Q_LOGGING_CATEGORY(lcAccountState, "nextcloud.gui.account.state", QtInfoMsg)
|
||||||
@@ -36,11 +42,12 @@ AccountState::AccountState(AccountPtr account)
|
|||||||
, _waitingForNewCredentials(false)
|
, _waitingForNewCredentials(false)
|
||||||
, _notificationsEtagResponseHeader("*")
|
, _notificationsEtagResponseHeader("*")
|
||||||
, _maintenanceToConnectedDelay(60000 + (qrand() % (4 * 60000))) // 1-5min delay
|
, _maintenanceToConnectedDelay(60000 + (qrand() % (4 * 60000))) // 1-5min delay
|
||||||
|
, _remoteWipe(new RemoteWipe(_account))
|
||||||
{
|
{
|
||||||
qRegisterMetaType<AccountState *>("AccountState*");
|
qRegisterMetaType<AccountState *>("AccountState*");
|
||||||
|
|
||||||
connect(account.data(), &Account::invalidCredentials,
|
connect(account.data(), &Account::invalidCredentials,
|
||||||
this, &AccountState::slotInvalidCredentials);
|
this, &AccountState::slotHandleRemoteWipeCheck);
|
||||||
connect(account.data(), &Account::credentialsFetched,
|
connect(account.data(), &Account::credentialsFetched,
|
||||||
this, &AccountState::slotCredentialsFetched);
|
this, &AccountState::slotCredentialsFetched);
|
||||||
connect(account.data(), &Account::credentialsAsked,
|
connect(account.data(), &Account::credentialsAsked,
|
||||||
@@ -303,7 +310,7 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
|
|||||||
break;
|
break;
|
||||||
case ConnectionValidator::CredentialsWrong:
|
case ConnectionValidator::CredentialsWrong:
|
||||||
case ConnectionValidator::CredentialsNotReady:
|
case ConnectionValidator::CredentialsNotReady:
|
||||||
slotInvalidCredentials();
|
handleInvalidCredentials();
|
||||||
break;
|
break;
|
||||||
case ConnectionValidator::SslError:
|
case ConnectionValidator::SslError:
|
||||||
setState(SignedOut);
|
setState(SignedOut);
|
||||||
@@ -322,7 +329,20 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountState::slotInvalidCredentials()
|
void AccountState::slotHandleRemoteWipeCheck()
|
||||||
|
{
|
||||||
|
// make sure it changes account state and icons
|
||||||
|
signOutByUi();
|
||||||
|
|
||||||
|
qCInfo(lcAccountState) << "Invalid credentials for" << _account->url().toString()
|
||||||
|
<< "checking for remote wipe request";
|
||||||
|
|
||||||
|
_waitingForNewCredentials = false;
|
||||||
|
setState(SignedOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AccountState::handleInvalidCredentials()
|
||||||
{
|
{
|
||||||
if (isSignedOut() || _waitingForNewCredentials)
|
if (isSignedOut() || _waitingForNewCredentials)
|
||||||
return;
|
return;
|
||||||
@@ -343,6 +363,7 @@ void AccountState::slotInvalidCredentials()
|
|||||||
account()->credentials()->askFromUser();
|
account()->credentials()->askFromUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AccountState::slotCredentialsFetched(AbstractCredentials *)
|
void AccountState::slotCredentialsFetched(AbstractCredentials *)
|
||||||
{
|
{
|
||||||
// Make a connection attempt, no matter whether the credentials are
|
// Make a connection attempt, no matter whether the credentials are
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ namespace OCC {
|
|||||||
|
|
||||||
class AccountState;
|
class AccountState;
|
||||||
class Account;
|
class Account;
|
||||||
|
class RemoteWipe;
|
||||||
|
|
||||||
typedef QExplicitlySharedDataPointer<AccountState> AccountStatePtr;
|
typedef QExplicitlySharedDataPointer<AccountState> AccountStatePtr;
|
||||||
|
|
||||||
@@ -150,6 +151,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
void setNavigationAppsEtagResponseHeader(const QByteArray &value);
|
void setNavigationAppsEtagResponseHeader(const QByteArray &value);
|
||||||
|
|
||||||
|
///Asks for user credentials
|
||||||
|
void handleInvalidCredentials();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
/// Triggers a ping to the server to update state and
|
/// Triggers a ping to the server to update state and
|
||||||
/// connection status and errors.
|
/// connection status and errors.
|
||||||
@@ -164,7 +168,11 @@ signals:
|
|||||||
|
|
||||||
protected Q_SLOTS:
|
protected Q_SLOTS:
|
||||||
void slotConnectionValidatorResult(ConnectionValidator::Status status, const QStringList &errors);
|
void slotConnectionValidatorResult(ConnectionValidator::Status status, const QStringList &errors);
|
||||||
void slotInvalidCredentials();
|
|
||||||
|
/// When client gets a 401 or 403 checks if server requested remote wipe
|
||||||
|
/// before asking for user credentials again
|
||||||
|
void slotHandleRemoteWipeCheck();
|
||||||
|
|
||||||
void slotCredentialsFetched(AbstractCredentials *creds);
|
void slotCredentialsFetched(AbstractCredentials *creds);
|
||||||
void slotCredentialsAsked(AbstractCredentials *creds);
|
void slotCredentialsAsked(AbstractCredentials *creds);
|
||||||
|
|
||||||
@@ -190,6 +198,13 @@ private:
|
|||||||
* Milliseconds for which to delay reconnection after 503/maintenance.
|
* Milliseconds for which to delay reconnection after 503/maintenance.
|
||||||
*/
|
*/
|
||||||
int _maintenanceToConnectedDelay;
|
int _maintenanceToConnectedDelay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects remote wipe check with the account
|
||||||
|
* the log out triggers the check (loads app password -> create request)
|
||||||
|
*/
|
||||||
|
RemoteWipe *_remoteWipe;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
||||||
|
#define HASQT5_11 (QT_VERSION >= QT_VERSION_CHECK(5,11,0))
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
int ActivityItemDelegate::_iconHeight = 0;
|
int ActivityItemDelegate::_iconHeight = 0;
|
||||||
@@ -106,7 +108,11 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
|
|
||||||
// subject text rect
|
// subject text rect
|
||||||
QRect actionTextBox = actionIconRect;
|
QRect actionTextBox = actionIconRect;
|
||||||
|
#if (HASQT5_11)
|
||||||
|
int actionTextBoxWidth = fm.horizontalAdvance(actionText);
|
||||||
|
#else
|
||||||
int actionTextBoxWidth = fm.width(actionText);
|
int actionTextBoxWidth = fm.width(actionText);
|
||||||
|
#endif
|
||||||
actionTextBox.setTop(option.rect.top() + margin + offset/2);
|
actionTextBox.setTop(option.rect.top() + margin + offset/2);
|
||||||
actionTextBox.setHeight(fm.height());
|
actionTextBox.setHeight(fm.height());
|
||||||
actionTextBox.setLeft(actionIconRect.right() + margin);
|
actionTextBox.setLeft(actionIconRect.right() + margin);
|
||||||
@@ -114,7 +120,11 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
|
|
||||||
// message text rect
|
// message text rect
|
||||||
QRect messageTextBox = actionTextBox;
|
QRect messageTextBox = actionTextBox;
|
||||||
|
#if (HASQT5_11)
|
||||||
|
int messageTextWidth = fm.horizontalAdvance(messageText);
|
||||||
|
#else
|
||||||
int messageTextWidth = fm.width(messageText);
|
int messageTextWidth = fm.width(messageText);
|
||||||
|
#endif
|
||||||
int messageTextTop = option.rect.top() + fm.height() + margin;
|
int messageTextTop = option.rect.top() + fm.height() + margin;
|
||||||
if(actionText.isEmpty()) messageTextTop = option.rect.top() + margin + offset/2;
|
if(actionText.isEmpty()) messageTextTop = option.rect.top() + margin + offset/2;
|
||||||
messageTextBox.setTop(messageTextTop);
|
messageTextBox.setTop(messageTextTop);
|
||||||
@@ -129,7 +139,11 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
// time box rect
|
// time box rect
|
||||||
QRect timeBox = messageTextBox;
|
QRect timeBox = messageTextBox;
|
||||||
QString timeStr = tr("%1").arg(timeText);
|
QString timeStr = tr("%1").arg(timeText);
|
||||||
|
#if (HASQT5_11)
|
||||||
|
int timeTextWidth = fm.horizontalAdvance(timeStr);
|
||||||
|
#else
|
||||||
int timeTextWidth = fm.width(timeStr);
|
int timeTextWidth = fm.width(timeStr);
|
||||||
|
#endif
|
||||||
int timeTop = option.rect.top() + fm.height() + fm.height() + margin + offset/2;
|
int timeTop = option.rect.top() + fm.height() + fm.height() + margin + offset/2;
|
||||||
if(messageText.isEmpty() || actionText.isEmpty())
|
if(messageText.isEmpty() || actionText.isEmpty())
|
||||||
timeTop = option.rect.top() + fm.height() + margin;
|
timeTop = option.rect.top() + fm.height() + margin;
|
||||||
@@ -180,7 +194,11 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
if(objectType == _remote_share) primaryButton.text = tr("Accept");
|
if(objectType == _remote_share) primaryButton.text = tr("Accept");
|
||||||
if(objectType == _call) primaryButton.text = tr("Join");
|
if(objectType == _call) primaryButton.text = tr("Join");
|
||||||
|
|
||||||
|
#if (HASQT5_11)
|
||||||
|
primaryButton.rect.setLeft(left - margin * 2 - fm.horizontalAdvance(primaryButton.text));
|
||||||
|
#else
|
||||||
primaryButton.rect.setLeft(left - margin * 2 - fm.width(primaryButton.text));
|
primaryButton.rect.setLeft(left - margin * 2 - fm.width(primaryButton.text));
|
||||||
|
#endif
|
||||||
|
|
||||||
// save info to be able to filter mouse clicks
|
// save info to be able to filter mouse clicks
|
||||||
_buttonHeight = buttonSize;
|
_buttonHeight = buttonSize;
|
||||||
@@ -196,7 +214,12 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
|
|
||||||
// Primary button will be 'open browser'
|
// Primary button will be 'open browser'
|
||||||
primaryButton.text = tr("Open Browser");
|
primaryButton.text = tr("Open Browser");
|
||||||
|
|
||||||
|
#if (HASQT5_11)
|
||||||
|
primaryButton.rect.setLeft(left - margin * 2 - fm.horizontalAdvance(primaryButton.text));
|
||||||
|
#else
|
||||||
primaryButton.rect.setLeft(left - margin * 2 - fm.width(primaryButton.text));
|
primaryButton.rect.setLeft(left - margin * 2 - fm.width(primaryButton.text));
|
||||||
|
#endif
|
||||||
|
|
||||||
// save info to be able to filter mouse clicks
|
// save info to be able to filter mouse clicks
|
||||||
_buttonHeight = buttonSize;
|
_buttonHeight = buttonSize;
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ Application::Application(int &argc, char **argv)
|
|||||||
, _userTriggeredConnect(false)
|
, _userTriggeredConnect(false)
|
||||||
, _debugMode(false)
|
, _debugMode(false)
|
||||||
, _backgroundMode(false)
|
, _backgroundMode(false)
|
||||||
|
, _isQuitting(false)
|
||||||
{
|
{
|
||||||
_startedAt.start();
|
_startedAt.start();
|
||||||
|
|
||||||
@@ -264,6 +265,8 @@ Application::~Application()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove the account from the account manager so it can be deleted.
|
// Remove the account from the account manager so it can be deleted.
|
||||||
|
disconnect(AccountManager::instance(), &AccountManager::accountRemoved,
|
||||||
|
this, &Application::slotAccountStateRemoved);
|
||||||
AccountManager::instance()->shutdown();
|
AccountManager::instance()->shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,7 +286,7 @@ void Application::slotAccountStateRemoved(AccountState *accountState)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if there is no more account, show the wizard.
|
// if there is no more account, show the wizard.
|
||||||
if (AccountManager::instance()->accounts().isEmpty()) {
|
if (!_isQuitting && AccountManager::instance()->accounts().isEmpty()) {
|
||||||
// allow to add a new account if there is non any more. Always think
|
// allow to add a new account if there is non any more. Always think
|
||||||
// about single account theming!
|
// about single account theming!
|
||||||
OwncloudSetupWizard::runWizard(this, SLOT(slotownCloudWizardDone(int)));
|
OwncloudSetupWizard::runWizard(this, SLOT(slotownCloudWizardDone(int)));
|
||||||
@@ -306,6 +309,8 @@ void Application::slotAccountStateAdded(AccountState *accountState)
|
|||||||
|
|
||||||
void Application::slotCleanup()
|
void Application::slotCleanup()
|
||||||
{
|
{
|
||||||
|
_isQuitting = true;
|
||||||
|
|
||||||
AccountManager::instance()->save();
|
AccountManager::instance()->save();
|
||||||
FolderMan::instance()->unloadAndDeleteAllFolders();
|
FolderMan::instance()->unloadAndDeleteAllFolders();
|
||||||
|
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ private:
|
|||||||
bool _userTriggeredConnect;
|
bool _userTriggeredConnect;
|
||||||
bool _debugMode;
|
bool _debugMode;
|
||||||
bool _backgroundMode;
|
bool _backgroundMode;
|
||||||
|
bool _isQuitting;
|
||||||
|
|
||||||
ClientProxy _proxy;
|
ClientProxy _proxy;
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,11 @@ void Flow2Auth::openBrowser()
|
|||||||
// Step 1: Initiate a login, do an anonymous POST request
|
// Step 1: Initiate a login, do an anonymous POST request
|
||||||
QUrl url = Utility::concatUrlPath(_account->url().toString(), QLatin1String("/index.php/login/v2"));
|
QUrl url = Utility::concatUrlPath(_account->url().toString(), QLatin1String("/index.php/login/v2"));
|
||||||
|
|
||||||
auto job = _account->sendRequest("POST", url);
|
// add 'Content-Length: 0' header (see https://github.com/nextcloud/desktop/issues/1473)
|
||||||
|
QNetworkRequest req;
|
||||||
|
req.setHeader(QNetworkRequest::ContentLengthHeader, "0");
|
||||||
|
|
||||||
|
auto job = _account->sendRequest("POST", url, req);
|
||||||
job->setTimeout(qMin(30 * 1000ll, job->timeoutMsec()));
|
job->setTimeout(qMin(30 * 1000ll, job->timeoutMsec()));
|
||||||
|
|
||||||
QObject::connect(job, &SimpleNetworkJob::finishedSignal, this, [this](QNetworkReply *reply) {
|
QObject::connect(job, &SimpleNetworkJob::finishedSignal, this, [this](QNetworkReply *reply) {
|
||||||
|
|||||||
@@ -358,6 +358,8 @@ void WebFlowCredentials::forgetSensitiveData() {
|
|||||||
|
|
||||||
fetchUser();
|
fetchUser();
|
||||||
|
|
||||||
|
_account->deleteAppPassword();
|
||||||
|
|
||||||
const QString kck = keychainKey(_account->url().toString(), _user, _account->id());
|
const QString kck = keychainKey(_account->url().toString(), _user, _account->id());
|
||||||
if (kck.isEmpty()) {
|
if (kck.isEmpty()) {
|
||||||
qCDebug(lcWebFlowCredentials()) << "InvalidateToken: User is empty, bailing out!";
|
qCDebug(lcWebFlowCredentials()) << "InvalidateToken: User is empty, bailing out!";
|
||||||
@@ -372,7 +374,7 @@ void WebFlowCredentials::forgetSensitiveData() {
|
|||||||
invalidateToken();
|
invalidateToken();
|
||||||
|
|
||||||
/* IMPORTANT
|
/* IMPORTANT
|
||||||
/* TODO: For "Log out" & "Remove account": Remove client CA certs and KEY!
|
* TODO: For "Log out" & "Remove account": Remove client CA certs and KEY!
|
||||||
*
|
*
|
||||||
* Disabled as long as selecting another cert is not supported by the UI.
|
* Disabled as long as selecting another cert is not supported by the UI.
|
||||||
*
|
*
|
||||||
@@ -416,6 +418,9 @@ void WebFlowCredentials::slotFinished(QNetworkReply *reply) {
|
|||||||
|
|
||||||
if (reply->error() == QNetworkReply::NoError) {
|
if (reply->error() == QNetworkReply::NoError) {
|
||||||
_credentialsValid = true;
|
_credentialsValid = true;
|
||||||
|
|
||||||
|
/// Used later for remote wipe
|
||||||
|
_account->setAppPassword(_password);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,7 +544,7 @@ void WebFlowCredentials::slotReadClientCaCertsPEMJobDone(QKeychain::Job *incomin
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (readJob->error() != QKeychain::Error::EntryNotFound ||
|
if (readJob->error() != QKeychain::Error::EntryNotFound ||
|
||||||
(readJob->error() == QKeychain::Error::EntryNotFound) && _clientSslCaCertificates.count() == 0) {
|
((readJob->error() == QKeychain::Error::EntryNotFound) && _clientSslCaCertificates.count() == 0)) {
|
||||||
qCWarning(lcWebFlowCredentials) << "Unable to read client CA cert slot " << QString::number(_clientSslCaCertificates.count()) << readJob->errorString();
|
qCWarning(lcWebFlowCredentials) << "Unable to read client CA cert slot " << QString::number(_clientSslCaCertificates.count()) << readJob->errorString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -417,6 +417,13 @@ void Folder::createGuiLog(const QString &filename, LogStatus status, int count,
|
|||||||
text = tr("%1 could not be synced due to an error. See the log for details.").arg(file);
|
text = tr("%1 could not be synced due to an error. See the log for details.").arg(file);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case LogStatusFileLocked:
|
||||||
|
if (count > 1) {
|
||||||
|
text = tr("%1 and %n other file(s) are currently locked.", "", count -1).arg(file);
|
||||||
|
} else {
|
||||||
|
text = tr("%1 is currently locked.").arg(file);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!text.isEmpty()) {
|
if (!text.isEmpty()) {
|
||||||
@@ -895,13 +902,19 @@ void Folder::slotItemCompleted(const SyncFileItemPtr &item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add new directories or remove gone away dirs to the watcher
|
// add new directories or remove gone away dirs to the watcher
|
||||||
if (item->isDirectory() && item->_instruction == CSYNC_INSTRUCTION_NEW) {
|
if (_folderWatcher && item->isDirectory()) {
|
||||||
if (_folderWatcher)
|
switch (item->_instruction) {
|
||||||
_folderWatcher->addPath(path() + item->_file);
|
case CSYNC_INSTRUCTION_NEW:
|
||||||
}
|
_folderWatcher->addPath(path() + item->_file);
|
||||||
if (item->isDirectory() && item->_instruction == CSYNC_INSTRUCTION_REMOVE) {
|
break;
|
||||||
if (_folderWatcher)
|
case CSYNC_INSTRUCTION_REMOVE:
|
||||||
_folderWatcher->removePath(path() + item->_file);
|
_folderWatcher->removePath(path() + item->_file);
|
||||||
|
break;
|
||||||
|
case CSYNC_INSTRUCTION_RENAME:
|
||||||
|
_folderWatcher->removePath(path() + item->_file);
|
||||||
|
_folderWatcher->addPath(path() + item->destination());
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Success and failure of sync items adjust what the next sync is
|
// Success and failure of sync items adjust what the next sync is
|
||||||
@@ -1072,7 +1085,7 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction dir, bool *cancel
|
|||||||
if (!cfgFile.promptDeleteFiles())
|
if (!cfgFile.promptDeleteFiles())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QString msg = dir == SyncFileItem::Down ? tr("All files in the sync folder '%1' folder were deleted on the server.\n"
|
QString msg = dir == SyncFileItem::Down ? tr("All files in the sync folder '%1' were deleted on the server.\n"
|
||||||
"These deletes will be synchronized to your local sync folder, making such files "
|
"These deletes will be synchronized to your local sync folder, making such files "
|
||||||
"unavailable unless you have a right to restore. \n"
|
"unavailable unless you have a right to restore. \n"
|
||||||
"If you decide to restore the files, they will be re-synced with the server if you have rights to do so.\n"
|
"If you decide to restore the files, they will be re-synced with the server if you have rights to do so.\n"
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ FolderMan::FolderMan(QObject *parent)
|
|||||||
this, &FolderMan::slotScheduleFolderByTime);
|
this, &FolderMan::slotScheduleFolderByTime);
|
||||||
_timeScheduler.start();
|
_timeScheduler.start();
|
||||||
|
|
||||||
connect(AccountManager::instance(), &AccountManager::accountRemoved,
|
connect(AccountManager::instance(), &AccountManager::removeAccountFolders,
|
||||||
this, &FolderMan::slotRemoveFoldersForAccount);
|
this, &FolderMan::slotRemoveFoldersForAccount);
|
||||||
|
|
||||||
connect(_lockWatcher.data(), &LockWatcher::fileUnlocked,
|
connect(_lockWatcher.data(), &LockWatcher::fileUnlocked,
|
||||||
@@ -443,7 +443,7 @@ void FolderMan::slotFolderSyncPaused(Folder *f, bool paused)
|
|||||||
void FolderMan::slotFolderCanSyncChanged()
|
void FolderMan::slotFolderCanSyncChanged()
|
||||||
{
|
{
|
||||||
Folder *f = qobject_cast<Folder *>(sender());
|
Folder *f = qobject_cast<Folder *>(sender());
|
||||||
ASSERT(f);
|
ASSERT(f);
|
||||||
if (f->canSync()) {
|
if (f->canSync()) {
|
||||||
_socketApi->slotRegisterPath(f->alias());
|
_socketApi->slotRegisterPath(f->alias());
|
||||||
} else {
|
} else {
|
||||||
@@ -562,7 +562,7 @@ void FolderMan::slotEtagJobDestroyed(QObject * /*o*/)
|
|||||||
void FolderMan::slotRunOneEtagJob()
|
void FolderMan::slotRunOneEtagJob()
|
||||||
{
|
{
|
||||||
if (_currentEtagJob.isNull()) {
|
if (_currentEtagJob.isNull()) {
|
||||||
Folder *folder;
|
Folder *folder = nullptr;
|
||||||
foreach (Folder *f, _folderMap) {
|
foreach (Folder *f, _folderMap) {
|
||||||
if (f->etagJob()) {
|
if (f->etagJob()) {
|
||||||
// Caveat: always grabs the first folder with a job, but we think this is Ok for now and avoids us having a seperate queue.
|
// Caveat: always grabs the first folder with a job, but we think this is Ok for now and avoids us having a seperate queue.
|
||||||
@@ -1084,6 +1084,73 @@ bool FolderMan::startFromScratch(const QString &localFolder)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FolderMan::slotWipeFolderForAccount(AccountState *accountState)
|
||||||
|
{
|
||||||
|
QVarLengthArray<Folder *, 16> foldersToRemove;
|
||||||
|
Folder::MapIterator i(_folderMap);
|
||||||
|
while (i.hasNext()) {
|
||||||
|
i.next();
|
||||||
|
Folder *folder = i.value();
|
||||||
|
if (folder->accountState() == accountState) {
|
||||||
|
foldersToRemove.append(folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
foreach (const auto &f, foldersToRemove) {
|
||||||
|
if (!f) {
|
||||||
|
qCCritical(lcFolderMan) << "Can not remove null folder";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qCInfo(lcFolderMan) << "Removing " << f->alias();
|
||||||
|
|
||||||
|
const bool currentlyRunning = (_currentSyncFolder == f);
|
||||||
|
if (currentlyRunning) {
|
||||||
|
// abort the sync now
|
||||||
|
terminateSyncProcess();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_scheduledFolders.removeAll(f) > 0) {
|
||||||
|
emit scheduleQueueChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
// wipe database
|
||||||
|
f->wipe();
|
||||||
|
|
||||||
|
// wipe data
|
||||||
|
QDir userFolder(f->path());
|
||||||
|
if (userFolder.exists()) {
|
||||||
|
success = userFolder.removeRecursively();
|
||||||
|
if (!success) {
|
||||||
|
qCWarning(lcFolderMan) << "Failed to remove existing folder " << f->path();
|
||||||
|
} else {
|
||||||
|
qCInfo(lcFolderMan) << "wipe: Removed file " << f->path();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
success = true;
|
||||||
|
qCWarning(lcFolderMan) << "folder does not exist, can not remove.";
|
||||||
|
}
|
||||||
|
|
||||||
|
f->setSyncPaused(true);
|
||||||
|
|
||||||
|
// remove the folder configuration
|
||||||
|
f->removeFromSettings();
|
||||||
|
|
||||||
|
unloadFolder(f);
|
||||||
|
if (currentlyRunning) {
|
||||||
|
delete f;
|
||||||
|
}
|
||||||
|
|
||||||
|
_navigationPaneHelper.scheduleUpdateCloudStorageRegistry();
|
||||||
|
}
|
||||||
|
|
||||||
|
emit folderListChanged(_folderMap);
|
||||||
|
emit wipeDone(accountState, success);
|
||||||
|
}
|
||||||
|
|
||||||
void FolderMan::setDirtyProxy()
|
void FolderMan::setDirtyProxy()
|
||||||
{
|
{
|
||||||
foreach (Folder *f, _folderMap.values()) {
|
foreach (Folder *f, _folderMap.values()) {
|
||||||
|
|||||||
@@ -207,6 +207,11 @@ signals:
|
|||||||
*/
|
*/
|
||||||
void folderListChanged(const Folder::Map &);
|
void folderListChanged(const Folder::Map &);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted once slotRemoveFoldersForAccount is done wiping
|
||||||
|
*/
|
||||||
|
void wipeDone(AccountState *account, bool success);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -231,6 +236,9 @@ public slots:
|
|||||||
// slot to schedule an ETag job (from Folder only)
|
// slot to schedule an ETag job (from Folder only)
|
||||||
void slotScheduleETagJob(const QString &alias, RequestEtagJob *job);
|
void slotScheduleETagJob(const QString &alias, RequestEtagJob *job);
|
||||||
|
|
||||||
|
/** Wipe folder */
|
||||||
|
void slotWipeFolderForAccount(AccountState *accountState);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void slotFolderSyncPaused(Folder *, bool paused);
|
void slotFolderSyncPaused(Folder *, bool paused);
|
||||||
void slotFolderCanSyncChanged();
|
void slotFolderCanSyncChanged();
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
QString itemString = qvariant_cast<QString>(index.data(SyncProgressItemString));
|
QString itemString = qvariant_cast<QString>(index.data(SyncProgressItemString));
|
||||||
int warningCount = qvariant_cast<int>(index.data(WarningCount));
|
int warningCount = qvariant_cast<int>(index.data(WarningCount));
|
||||||
bool syncOngoing = qvariant_cast<bool>(index.data(SyncRunning));
|
bool syncOngoing = qvariant_cast<bool>(index.data(SyncRunning));
|
||||||
|
QDateTime syncDate = qvariant_cast<QDateTime>(index.data(SyncDate));
|
||||||
bool syncEnabled = qvariant_cast<bool>(index.data(FolderAccountConnected));
|
bool syncEnabled = qvariant_cast<bool>(index.data(FolderAccountConnected));
|
||||||
|
|
||||||
QRect iconRect = option.rect;
|
QRect iconRect = option.rect;
|
||||||
@@ -252,7 +253,7 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
if (!showProgess) {
|
if (!showProgess) {
|
||||||
painter->setFont(subFont);
|
painter->setFont(subFont);
|
||||||
QString elidedRemotePathText = subFm.elidedText(
|
QString elidedRemotePathText = subFm.elidedText(
|
||||||
tr("Synchronized with local folder"),
|
tr("Synchronized with local folder (%1)").arg(syncDate.toTimeSpec(Qt::LocalTime).toString(Qt::SystemLocaleShortDate)),
|
||||||
Qt::ElideRight, remotePathRect.width());
|
Qt::ElideRight, remotePathRect.width());
|
||||||
painter->drawText(QStyle::visualRect(option.direction, option.rect, remotePathRect),
|
painter->drawText(QStyle::visualRect(option.direction, option.rect, remotePathRect),
|
||||||
textAlign, elidedRemotePathText);
|
textAlign, elidedRemotePathText);
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ public:
|
|||||||
SyncProgressItemString,
|
SyncProgressItemString,
|
||||||
WarningCount,
|
WarningCount,
|
||||||
SyncRunning,
|
SyncRunning,
|
||||||
|
SyncDate,
|
||||||
|
|
||||||
AddButton // 1 = enabled; 2 = disabled
|
AddButton // 1 = enabled; 2 = disabled
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -218,6 +218,8 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
|
|||||||
return f->syncResult().errorStrings();
|
return f->syncResult().errorStrings();
|
||||||
case FolderStatusDelegate::SyncRunning:
|
case FolderStatusDelegate::SyncRunning:
|
||||||
return f->syncResult().status() == SyncResult::SyncRunning;
|
return f->syncResult().status() == SyncResult::SyncRunning;
|
||||||
|
case FolderStatusDelegate::SyncDate:
|
||||||
|
return f->syncResult().syncTime();
|
||||||
case FolderStatusDelegate::HeaderRole:
|
case FolderStatusDelegate::HeaderRole:
|
||||||
return f->shortGuiRemotePathOrAppName();
|
return f->shortGuiRemotePathOrAppName();
|
||||||
case FolderStatusDelegate::FolderAliasRole:
|
case FolderStatusDelegate::FolderAliasRole:
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
#include "folderwatcher.h"
|
#include "folderwatcher.h"
|
||||||
#include "folderwatcher_win.h"
|
#include "folderwatcher_win.h"
|
||||||
|
|
||||||
|
#include "common/utility.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
@@ -52,7 +54,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
|||||||
|
|
||||||
// QVarLengthArray ensures the stack-buffer is aligned like double and qint64.
|
// QVarLengthArray ensures the stack-buffer is aligned like double and qint64.
|
||||||
QVarLengthArray<char, 4096 * 10> fileNotifyBuffer;
|
QVarLengthArray<char, 4096 * 10> fileNotifyBuffer;
|
||||||
fileNotifyBuffer.resize(fileNotifyBufferSize);
|
fileNotifyBuffer.resize(OCC::Utility::convertSizeToInt(fileNotifyBufferSize));
|
||||||
|
|
||||||
const size_t fileNameBufferSize = 4096;
|
const size_t fileNameBufferSize = 4096;
|
||||||
TCHAR fileNameBuffer[fileNameBufferSize];
|
TCHAR fileNameBuffer[fileNameBufferSize];
|
||||||
@@ -66,7 +68,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
|||||||
DWORD dwBytesReturned = 0;
|
DWORD dwBytesReturned = 0;
|
||||||
SecureZeroMemory(pFileNotifyBuffer, fileNotifyBufferSize);
|
SecureZeroMemory(pFileNotifyBuffer, fileNotifyBufferSize);
|
||||||
if (!ReadDirectoryChangesW(_directory, (LPVOID)pFileNotifyBuffer,
|
if (!ReadDirectoryChangesW(_directory, (LPVOID)pFileNotifyBuffer,
|
||||||
fileNotifyBufferSize, true,
|
OCC::Utility::convertSizeToDWORD(fileNotifyBufferSize), true,
|
||||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
|
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
|
||||||
&dwBytesReturned,
|
&dwBytesReturned,
|
||||||
&overlapped,
|
&overlapped,
|
||||||
@@ -113,7 +115,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
|||||||
FILE_NOTIFY_INFORMATION *curEntry = pFileNotifyBuffer;
|
FILE_NOTIFY_INFORMATION *curEntry = pFileNotifyBuffer;
|
||||||
forever {
|
forever {
|
||||||
size_t len = curEntry->FileNameLength / 2;
|
size_t len = curEntry->FileNameLength / 2;
|
||||||
QString file = _path + "\\" + QString::fromWCharArray(curEntry->FileName, len);
|
QString file = _path + "\\" + QString::fromWCharArray(curEntry->FileName, OCC::Utility::convertSizeToInt(len));
|
||||||
|
|
||||||
// Unless the file was removed or renamed, get its full long name
|
// Unless the file was removed or renamed, get its full long name
|
||||||
// TODO: We could still try expanding the path in the tricky cases...
|
// TODO: We could still try expanding the path in the tricky cases...
|
||||||
@@ -122,7 +124,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
|||||||
&& curEntry->Action != FILE_ACTION_RENAMED_OLD_NAME) {
|
&& curEntry->Action != FILE_ACTION_RENAMED_OLD_NAME) {
|
||||||
size_t longNameSize = GetLongPathNameW(reinterpret_cast<LPCWSTR>(file.utf16()), fileNameBuffer, fileNameBufferSize);
|
size_t longNameSize = GetLongPathNameW(reinterpret_cast<LPCWSTR>(file.utf16()), fileNameBuffer, fileNameBufferSize);
|
||||||
if (longNameSize > 0) {
|
if (longNameSize > 0) {
|
||||||
longfile = QString::fromUtf16(reinterpret_cast<const ushort *>(fileNameBuffer), longNameSize);
|
longfile = QString::fromUtf16(reinterpret_cast<const ushort *>(fileNameBuffer), OCC::Utility::convertSizeToInt(longNameSize));
|
||||||
} else {
|
} else {
|
||||||
qCWarning(lcFolderWatcher) << "Error converting file name to full length, keeping original name.";
|
qCWarning(lcFolderWatcher) << "Error converting file name to full length, keeping original name.";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,7 +107,7 @@
|
|||||||
<enum>QFrame::Plain</enum>
|
<enum>QFrame::Plain</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>TextLabel</string>
|
<string notr="true">TextLabel</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="textFormat">
|
<property name="textFormat">
|
||||||
<enum>Qt::RichText</enum>
|
<enum>Qt::RichText</enum>
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "updater/updater.h"
|
#include "updater/updater.h"
|
||||||
#include "updater/ocupdater.h"
|
#include "updater/ocupdater.h"
|
||||||
#include "ignorelisteditor.h"
|
#include "ignorelisteditor.h"
|
||||||
|
#include "common/utility.h"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@@ -35,6 +36,12 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QScopedValueRollback>
|
#include <QScopedValueRollback>
|
||||||
|
|
||||||
|
#define QTLEGACY (QT_VERSION < QT_VERSION_CHECK(5,9,0))
|
||||||
|
|
||||||
|
#if !(QTLEGACY)
|
||||||
|
#include <QOperatingSystemVersion>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
GeneralSettings::GeneralSettings(QWidget *parent)
|
GeneralSettings::GeneralSettings(QWidget *parent)
|
||||||
@@ -79,9 +86,13 @@ GeneralSettings::GeneralSettings(QWidget *parent)
|
|||||||
// Hide on non-Windows, or WindowsVersion < 10.
|
// Hide on non-Windows, or WindowsVersion < 10.
|
||||||
// The condition should match the default value of ConfigFile::showInExplorerNavigationPane.
|
// The condition should match the default value of ConfigFile::showInExplorerNavigationPane.
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS10)
|
#if QTLEGACY
|
||||||
|
if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS10)
|
||||||
|
#else
|
||||||
|
if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows10)
|
||||||
|
#endif
|
||||||
|
_ui->showInExplorerNavigationPaneCheckBox->setVisible(false);
|
||||||
#endif
|
#endif
|
||||||
_ui->showInExplorerNavigationPaneCheckBox->setVisible(false);
|
|
||||||
|
|
||||||
/* Set the left contents margin of the layout to zero to make the checkboxes
|
/* Set the left contents margin of the layout to zero to make the checkboxes
|
||||||
* align properly vertically , fixes bug #3758
|
* align properly vertically , fixes bug #3758
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>IgnoreListTableWidget</string>
|
<string notr="true">IgnoreListTableWidget</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<item row="0" column="0" rowspan="4">
|
<item row="0" column="0" rowspan="4">
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Label</string>
|
<string notr="true">Label</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>542</width>
|
<width>563</width>
|
||||||
<height>396</height>
|
<height>444</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -228,7 +228,7 @@
|
|||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>9999</number>
|
<number>999999</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="value">
|
<property name="value">
|
||||||
<number>80</number>
|
<number>80</number>
|
||||||
@@ -307,7 +307,7 @@
|
|||||||
<number>1</number>
|
<number>1</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>9999</number>
|
<number>999999</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="value">
|
<property name="value">
|
||||||
<number>10</number>
|
<number>10</number>
|
||||||
|
|||||||
@@ -22,6 +22,12 @@
|
|||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
||||||
|
#define QTLEGACY (QT_VERSION < QT_VERSION_CHECK(5,9,0))
|
||||||
|
|
||||||
|
#if !(QTLEGACY)
|
||||||
|
#include <QOperatingSystemVersion>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
// according to the QStandardDir impl from Qt5
|
// according to the QStandardDir impl from Qt5
|
||||||
@@ -89,10 +95,14 @@ void showInFileManager(const QString &localPath)
|
|||||||
{
|
{
|
||||||
if (Utility::isWindows()) {
|
if (Utility::isWindows()) {
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
if (QSysInfo::windowsVersion() <= QSysInfo::WV_2003) {
|
#if QTLEGACY
|
||||||
return;
|
if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS10)
|
||||||
}
|
#else
|
||||||
|
if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows7)
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QString explorer = "explorer.exe "; // FIXME: we trust it's in PATH
|
QString explorer = "explorer.exe "; // FIXME: we trust it's in PATH
|
||||||
QFileInfo fi(localPath);
|
QFileInfo fi(localPath);
|
||||||
|
|
||||||
|
|||||||
@@ -675,6 +675,12 @@ void ownCloudGui::updateContextMenu()
|
|||||||
|
|
||||||
_contextMenu->addSeparator();
|
_contextMenu->addSeparator();
|
||||||
|
|
||||||
|
if (_navLinksMenu) {
|
||||||
|
_contextMenu->addMenu(_navLinksMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
_contextMenu->addSeparator();
|
||||||
|
|
||||||
if (accountList.isEmpty()) {
|
if (accountList.isEmpty()) {
|
||||||
_contextMenu->addAction(_actionNewAccountWizard);
|
_contextMenu->addAction(_actionNewAccountWizard);
|
||||||
}
|
}
|
||||||
@@ -688,6 +694,7 @@ void ownCloudGui::updateContextMenu()
|
|||||||
}
|
}
|
||||||
|
|
||||||
_contextMenu->addSeparator();
|
_contextMenu->addSeparator();
|
||||||
|
|
||||||
if (atLeastOnePaused) {
|
if (atLeastOnePaused) {
|
||||||
QString text;
|
QString text;
|
||||||
if (accountList.count() > 1) {
|
if (accountList.count() > 1) {
|
||||||
@@ -777,6 +784,8 @@ void ownCloudGui::setupActions()
|
|||||||
{
|
{
|
||||||
_actionStatus = new QAction(tr("Unknown status"), this);
|
_actionStatus = new QAction(tr("Unknown status"), this);
|
||||||
_actionStatus->setEnabled(false);
|
_actionStatus->setEnabled(false);
|
||||||
|
_navLinksMenu = new QMenu(tr("Apps"));
|
||||||
|
_navLinksMenu->setEnabled(false);
|
||||||
_actionSettings = new QAction(tr("Settings..."), this);
|
_actionSettings = new QAction(tr("Settings..."), this);
|
||||||
_actionNewAccountWizard = new QAction(tr("New account..."), this);
|
_actionNewAccountWizard = new QAction(tr("New account..."), this);
|
||||||
_actionRecent = new QAction(tr("View more activity..."), this);
|
_actionRecent = new QAction(tr("View more activity..."), this);
|
||||||
@@ -818,8 +827,11 @@ void ownCloudGui::fetchNavigationApps(AccountStatePtr account){
|
|||||||
|
|
||||||
void ownCloudGui::buildNavigationAppsMenu(AccountStatePtr account, QMenu *accountMenu){
|
void ownCloudGui::buildNavigationAppsMenu(AccountStatePtr account, QMenu *accountMenu){
|
||||||
auto navLinks = _navApps.value(account);
|
auto navLinks = _navApps.value(account);
|
||||||
if(navLinks.size() > 0){
|
|
||||||
|
|
||||||
|
_navLinksMenu->clear();
|
||||||
|
_navLinksMenu->setEnabled(navLinks.size() > 0);
|
||||||
|
|
||||||
|
if(navLinks.size() > 0){
|
||||||
// when there is only one account add the nav links above the settings
|
// when there is only one account add the nav links above the settings
|
||||||
QAction *actionBefore = _actionSettings;
|
QAction *actionBefore = _actionSettings;
|
||||||
|
|
||||||
@@ -838,17 +850,13 @@ void ownCloudGui::buildNavigationAppsMenu(AccountStatePtr account, QMenu *accoun
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create submenu with links
|
// Create submenu with links
|
||||||
QMenu *navLinksMenu = new QMenu(tr("Apps"));
|
|
||||||
accountMenu->insertSeparator(actionBefore);
|
|
||||||
accountMenu->insertMenu(actionBefore, navLinksMenu);
|
|
||||||
foreach (const QJsonValue &value, navLinks) {
|
foreach (const QJsonValue &value, navLinks) {
|
||||||
auto navLink = value.toObject();
|
auto navLink = value.toObject();
|
||||||
QAction *action = new QAction(navLink.value("name").toString(), this);
|
QAction *action = new QAction(navLink.value("name").toString(), this);
|
||||||
QUrl href(navLink.value("href").toString());
|
QUrl href(navLink.value("href").toString());
|
||||||
connect(action, &QAction::triggered, this, [href] { QDesktopServices::openUrl(href); });
|
connect(action, &QAction::triggered, this, [href] { QDesktopServices::openUrl(href); });
|
||||||
navLinksMenu->addAction(action);
|
_navLinksMenu->addAction(action);
|
||||||
}
|
}
|
||||||
accountMenu->insertSeparator(actionBefore);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ private:
|
|||||||
QAction *_actionQuit;
|
QAction *_actionQuit;
|
||||||
QAction *_actionCrash;
|
QAction *_actionCrash;
|
||||||
|
|
||||||
|
QMenu *_navLinksMenu;
|
||||||
QMap<AccountStatePtr, QJsonArray> _navApps;
|
QMap<AccountStatePtr, QJsonArray> _navApps;
|
||||||
|
|
||||||
QList<QAction *> _recentItemsActions;
|
QList<QAction *> _recentItemsActions;
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QLabel" name="proxyAddress">
|
<widget class="QLabel" name="proxyAddress">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>TextLabel</string>
|
<string notr="true">TextLabel</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="textFormat">
|
<property name="textFormat">
|
||||||
<enum>Qt::PlainText</enum>
|
<enum>Qt::PlainText</enum>
|
||||||
|
|||||||
161
src/gui/remotewipe.cpp
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) by Camila Ayres <hello@camila.codes>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "remotewipe.h"
|
||||||
|
#include "folderman.h"
|
||||||
|
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QBuffer>
|
||||||
|
|
||||||
|
namespace OCC {
|
||||||
|
|
||||||
|
Q_LOGGING_CATEGORY(lcRemoteWipe, "nextcloud.gui.remotewipe", QtInfoMsg)
|
||||||
|
|
||||||
|
RemoteWipe::RemoteWipe(AccountPtr account, QObject *parent)
|
||||||
|
: _account(account),
|
||||||
|
_appPassword(QString()),
|
||||||
|
_accountRemoved(false),
|
||||||
|
_networkManager(nullptr),
|
||||||
|
_networkReplyCheck(nullptr),
|
||||||
|
_networkReplySuccess(nullptr)
|
||||||
|
{
|
||||||
|
QObject::connect(AccountManager::instance(), &AccountManager::accountRemoved,
|
||||||
|
this, [=](AccountState *) {
|
||||||
|
_accountRemoved = true;
|
||||||
|
});
|
||||||
|
QObject::connect(this, &RemoteWipe::authorized, FolderMan::instance(),
|
||||||
|
&FolderMan::slotWipeFolderForAccount);
|
||||||
|
QObject::connect(FolderMan::instance(), &FolderMan::wipeDone, this,
|
||||||
|
&RemoteWipe::notifyServerSuccessJob);
|
||||||
|
QObject::connect(_account.data(), &Account::appPasswordRetrieved, this,
|
||||||
|
&RemoteWipe::startCheckJobWithAppPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteWipe::startCheckJobWithAppPassword(QString pwd){
|
||||||
|
if(pwd.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
_appPassword = pwd;
|
||||||
|
QUrl requestUrl = Utility::concatUrlPath(_account->url().toString(),
|
||||||
|
QLatin1String("/index.php/core/wipe/check"));
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setHeader(QNetworkRequest::ContentTypeHeader,
|
||||||
|
"application/x-www-form-urlencoded");
|
||||||
|
request.setUrl(requestUrl);
|
||||||
|
request.setSslConfiguration(_account->getOrCreateSslConfig());
|
||||||
|
auto requestBody = new QBuffer;
|
||||||
|
QUrlQuery arguments(QString("token=%1").arg(_appPassword));
|
||||||
|
requestBody->setData(arguments.query(QUrl::FullyEncoded).toLatin1());
|
||||||
|
_networkReplyCheck = _networkManager.post(request, requestBody);
|
||||||
|
QObject::connect(&_networkManager, SIGNAL(sslErrors(QNetworkReply *, QList<QSslError>)),
|
||||||
|
_account.data(), SLOT(slotHandleSslErrors(QNetworkReply *, QList<QSslError>)));
|
||||||
|
QObject::connect(_networkReplyCheck, &QNetworkReply::finished, this,
|
||||||
|
&RemoteWipe::checkJobSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteWipe::checkJobSlot()
|
||||||
|
{
|
||||||
|
auto jsonData = _networkReplyCheck->readAll();
|
||||||
|
QJsonParseError jsonParseError;
|
||||||
|
QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object();
|
||||||
|
bool wipe = false;
|
||||||
|
|
||||||
|
//check for errors
|
||||||
|
if (_networkReplyCheck->error() != QNetworkReply::NoError ||
|
||||||
|
jsonParseError.error != QJsonParseError::NoError) {
|
||||||
|
QString errorReason;
|
||||||
|
QString errorFromJson = json["error"].toString();
|
||||||
|
if (!errorFromJson.isEmpty()) {
|
||||||
|
qCWarning(lcRemoteWipe) << QString("Error returned from the server: <em>%1<em>")
|
||||||
|
.arg(errorFromJson.toHtmlEscaped());
|
||||||
|
} else if (_networkReplyCheck->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(lcRemoteWipe) << QString("There was an error accessing the 'token' endpoint: <br><em>%1</em>")
|
||||||
|
.arg(_networkReplyCheck->errorString().toHtmlEscaped());
|
||||||
|
} else if (jsonParseError.error != QJsonParseError::NoError) {
|
||||||
|
qCWarning(lcRemoteWipe) << QString("Could not parse the JSON returned from the server: <br><em>%1</em>")
|
||||||
|
.arg(jsonParseError.errorString());
|
||||||
|
} else {
|
||||||
|
qCWarning(lcRemoteWipe) << QString("The reply from the server did not contain all expected fields");
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for wipe request
|
||||||
|
} else if(!json.value("wipe").isUndefined()){
|
||||||
|
wipe = json["wipe"].toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto manager = AccountManager::instance();
|
||||||
|
auto accountState = manager->account(_account->displayName()).data();
|
||||||
|
|
||||||
|
if(wipe){
|
||||||
|
// delete account
|
||||||
|
manager->deleteAccount(accountState);
|
||||||
|
manager->save();
|
||||||
|
|
||||||
|
// delete data
|
||||||
|
emit authorized(accountState);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// ask user for his credentials again
|
||||||
|
accountState->handleInvalidCredentials();
|
||||||
|
}
|
||||||
|
|
||||||
|
_networkReplyCheck->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteWipe::notifyServerSuccessJob(AccountState *accountState, bool dataWiped){
|
||||||
|
if(_accountRemoved && dataWiped && _account == accountState->account()){
|
||||||
|
QUrl requestUrl = Utility::concatUrlPath(_account->url().toString(),
|
||||||
|
QLatin1String("/index.php/core/wipe/success"));
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setHeader(QNetworkRequest::ContentTypeHeader,
|
||||||
|
"application/x-www-form-urlencoded");
|
||||||
|
request.setUrl(requestUrl);
|
||||||
|
request.setSslConfiguration(_account->getOrCreateSslConfig());
|
||||||
|
auto requestBody = new QBuffer;
|
||||||
|
QUrlQuery arguments(QString("token=%1").arg(_appPassword));
|
||||||
|
requestBody->setData(arguments.query(QUrl::FullyEncoded).toLatin1());
|
||||||
|
_networkReplySuccess = _networkManager.post(request, requestBody);
|
||||||
|
QObject::connect(_networkReplySuccess, &QNetworkReply::finished, this,
|
||||||
|
&RemoteWipe::notifyServerSuccessJobSlot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteWipe::notifyServerSuccessJobSlot()
|
||||||
|
{
|
||||||
|
auto jsonData = _networkReplySuccess->readAll();
|
||||||
|
QJsonParseError jsonParseError;
|
||||||
|
QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object();
|
||||||
|
if (_networkReplySuccess->error() != QNetworkReply::NoError ||
|
||||||
|
jsonParseError.error != QJsonParseError::NoError) {
|
||||||
|
QString errorReason;
|
||||||
|
QString errorFromJson = json["error"].toString();
|
||||||
|
if (!errorFromJson.isEmpty()) {
|
||||||
|
qCWarning(lcRemoteWipe) << QString("Error returned from the server: <em>%1</em>")
|
||||||
|
.arg(errorFromJson.toHtmlEscaped());
|
||||||
|
} else if (_networkReplySuccess->error() != QNetworkReply::NoError) {
|
||||||
|
qCWarning(lcRemoteWipe) << QString("There was an error accessing the 'success' endpoint: <br><em>%1</em>")
|
||||||
|
.arg(_networkReplySuccess->errorString().toHtmlEscaped());
|
||||||
|
} else if (jsonParseError.error != QJsonParseError::NoError) {
|
||||||
|
qCWarning(lcRemoteWipe) << QString("Could not parse the JSON returned from the server: <br><em>%1</em>")
|
||||||
|
.arg(jsonParseError.errorString());
|
||||||
|
} else {
|
||||||
|
qCWarning(lcRemoteWipe) << QString("The reply from the server did not contain all expected fields.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_networkReplySuccess->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
61
src/gui/remotewipe.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#ifndef REMOTEWIPE_H
|
||||||
|
#define REMOTEWIPE_H
|
||||||
|
|
||||||
|
#include "accountmanager.h"
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
|
||||||
|
class QJsonDocument;
|
||||||
|
class TestRemoteWipe;
|
||||||
|
|
||||||
|
namespace OCC {
|
||||||
|
|
||||||
|
class RemoteWipe : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit RemoteWipe(AccountPtr account, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* Notify if wipe was requested
|
||||||
|
*/
|
||||||
|
void authorized(AccountState*);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify if user only needs to login again
|
||||||
|
*/
|
||||||
|
void askUserCredentials();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
/**
|
||||||
|
* Once receives a 401 or 403 status response it will do a fetch to
|
||||||
|
* <server>/index.php/core/wipe/check
|
||||||
|
*/
|
||||||
|
void startCheckJobWithAppPassword(QString);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
/**
|
||||||
|
* If wipe is requested, delete account and data, if not continue by asking
|
||||||
|
* the user to login again
|
||||||
|
*/
|
||||||
|
void checkJobSlot();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Once the client has wiped all the required data a POST to
|
||||||
|
* <server>/index.php/core/wipe/success
|
||||||
|
*/
|
||||||
|
void notifyServerSuccessJob(AccountState *accountState, bool);
|
||||||
|
void notifyServerSuccessJobSlot();
|
||||||
|
|
||||||
|
private:
|
||||||
|
AccountPtr _account;
|
||||||
|
QString _appPassword;
|
||||||
|
bool _accountRemoved;
|
||||||
|
QNetworkAccessManager _networkManager;
|
||||||
|
QNetworkReply *_networkReplyCheck;
|
||||||
|
QNetworkReply *_networkReplySuccess;
|
||||||
|
|
||||||
|
friend class ::TestRemoteWipe;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif // REMOTEWIPE_H
|
||||||
@@ -48,7 +48,7 @@ const char TOOLBAR_CSS[] =
|
|||||||
"QToolBar QToolBarExtension { padding:0; } "
|
"QToolBar QToolBarExtension { padding:0; } "
|
||||||
"QToolBar QToolButton:checked { background: %3; color: %4; }";
|
"QToolBar QToolButton:checked { background: %3; color: %4; }";
|
||||||
|
|
||||||
static const float buttonSizeRatio = 1.618; // golden ratio
|
static const float buttonSizeRatio = 1.618f; // golden ratio
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>share label</string>
|
<string notr="true">share label</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="textFormat">
|
<property name="textFormat">
|
||||||
<enum>Qt::PlainText</enum>
|
<enum>Qt::PlainText</enum>
|
||||||
@@ -120,7 +120,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Icon</string>
|
<string notr="true">Icon</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -151,8 +151,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>352</width>
|
<width>367</width>
|
||||||
<height>68</height>
|
<height>85</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="scrollAreaVerticalLayout"/>
|
<layout class="QVBoxLayout" name="scrollAreaVerticalLayout"/>
|
||||||
|
|||||||
@@ -277,6 +277,7 @@ void ShareLinkWidget::slotCreatePassword()
|
|||||||
|
|
||||||
void ShareLinkWidget::slotCreateShareLink(bool clicked)
|
void ShareLinkWidget::slotCreateShareLink(bool clicked)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(clicked);
|
||||||
slotToggleAnimation(true);
|
slotToggleAnimation(true);
|
||||||
emit createLinkShare();
|
emit createLinkShare();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,7 @@
|
|||||||
</palette>
|
</palette>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>TextLabel</string>
|
<string notr="true">TextLabel</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="textFormat">
|
<property name="textFormat">
|
||||||
<enum>Qt::PlainText</enum>
|
<enum>Qt::PlainText</enum>
|
||||||
|
|||||||
@@ -628,7 +628,7 @@ void SocketApi::command_GET_STRINGS(const QString &argument, SocketListener *lis
|
|||||||
{ "EMAIL_PRIVATE_LINK_MENU_TITLE", tr("Send private link by email...") },
|
{ "EMAIL_PRIVATE_LINK_MENU_TITLE", tr("Send private link by email...") },
|
||||||
} };
|
} };
|
||||||
listener->sendMessage(QString("GET_STRINGS:BEGIN"));
|
listener->sendMessage(QString("GET_STRINGS:BEGIN"));
|
||||||
for (auto key_value : strings) {
|
for (const auto& key_value : strings) {
|
||||||
if (argument.isEmpty() || argument == QLatin1String(key_value.first)) {
|
if (argument.isEmpty() || argument == QLatin1String(key_value.first)) {
|
||||||
listener->sendMessage(QString("STRING:%1:%2").arg(key_value.first, key_value.second));
|
listener->sendMessage(QString("STRING:%1:%2").arg(key_value.first, key_value.second));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ SslButton::SslButton(QWidget *parent)
|
|||||||
_menu = new QMenu(this);
|
_menu = new QMenu(this);
|
||||||
QObject::connect(_menu, &QMenu::aboutToShow,
|
QObject::connect(_menu, &QMenu::aboutToShow,
|
||||||
this, &SslButton::slotUpdateMenu);
|
this, &SslButton::slotUpdateMenu);
|
||||||
|
setMenu(_menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString addCertDetailsField(const QString &key, const QString &value)
|
static QString addCertDetailsField(const QString &key, const QString &value)
|
||||||
@@ -171,11 +172,9 @@ void SslButton::updateAccountState(AccountState *accountState)
|
|||||||
setIcon(QIcon(QLatin1String(":/client/resources/lock-https.png")));
|
setIcon(QIcon(QLatin1String(":/client/resources/lock-https.png")));
|
||||||
QSslCipher cipher = account->_sessionCipher;
|
QSslCipher cipher = account->_sessionCipher;
|
||||||
setToolTip(tr("This connection is encrypted using %1 bit %2.\n").arg(cipher.usedBits()).arg(cipher.name()));
|
setToolTip(tr("This connection is encrypted using %1 bit %2.\n").arg(cipher.usedBits()).arg(cipher.name()));
|
||||||
setMenu(_menu);
|
|
||||||
} else {
|
} else {
|
||||||
setIcon(QIcon(QLatin1String(":/client/resources/lock-http.png")));
|
setIcon(QIcon(QLatin1String(":/client/resources/lock-http.png")));
|
||||||
setToolTip(tr("This connection is NOT secure as it is not encrypted.\n"));
|
setToolTip(tr("This connection is NOT secure as it is not encrypted.\n"));
|
||||||
setMenu(nullptr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +188,8 @@ void SslButton::slotUpdateMenu()
|
|||||||
|
|
||||||
AccountPtr account = _accountState->account();
|
AccountPtr account = _accountState->account();
|
||||||
|
|
||||||
|
_menu->addAction(tr("Server version: %1").arg(account->serverVersion()))->setEnabled(false);
|
||||||
|
|
||||||
if (account->isHttp2Supported()) {
|
if (account->isHttp2Supported()) {
|
||||||
_menu->addAction("HTTP/2")->setEnabled(false);
|
_menu->addAction("HTTP/2")->setEnabled(false);
|
||||||
}
|
}
|
||||||
@@ -239,6 +240,8 @@ void SslButton::slotUpdateMenu()
|
|||||||
_menu->addMenu(buildCertMenu(_menu, it.previous(), account->approvedCerts(), i, systemCerts));
|
_menu->addMenu(buildCertMenu(_menu, it.previous(), account->approvedCerts(), i, systemCerts));
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
_menu->addAction(tr("The connection is not secure"))->setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ QString OCUpdater::statusString() const
|
|||||||
case DownloadTimedOut:
|
case DownloadTimedOut:
|
||||||
return tr("Could not check for new updates.");
|
return tr("Could not check for new updates.");
|
||||||
case UpdateOnlyAvailableThroughSystem:
|
case UpdateOnlyAvailableThroughSystem:
|
||||||
return tr("New %1 version %2 available. Please use the system's update tool to install it.").arg(Theme::instance()->appNameGUI(), updateVersion);
|
return tr("New %1 version %2 is available. Please click <a href='%3'>here</a> to download the update.").arg(Theme::instance()->appNameGUI(), updateVersion, _updateInfo.web());
|
||||||
case CheckingServer:
|
case CheckingServer:
|
||||||
return tr("Checking update server...");
|
return tr("Checking update server...");
|
||||||
case Unknown:
|
case Unknown:
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ void Flow2AuthCredsPage::asyncAuthResult(Flow2Auth::Result r, const QString &use
|
|||||||
_appPassword = appPassword;
|
_appPassword = appPassword;
|
||||||
OwncloudWizard *ocWizard = qobject_cast<OwncloudWizard *>(wizard());
|
OwncloudWizard *ocWizard = qobject_cast<OwncloudWizard *>(wizard());
|
||||||
Q_ASSERT(ocWizard);
|
Q_ASSERT(ocWizard);
|
||||||
|
|
||||||
emit connectToOCUrl(ocWizard->account()->url().toString());
|
emit connectToOCUrl(ocWizard->account()->url().toString());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Form</string>
|
<string>Browser Authentication</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
@@ -61,6 +61,7 @@
|
|||||||
<widget class="QCommandLinkButton" name="copyLinkButton">
|
<widget class="QCommandLinkButton" name="copyLinkButton">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
<font>
|
<font>
|
||||||
|
<family>Segoe UI</family>
|
||||||
<weight>50</weight>
|
<weight>50</weight>
|
||||||
<bold>false</bold>
|
<bold>false</bold>
|
||||||
</font>
|
</font>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Form</string>
|
<string>Browser Authentication</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
@@ -73,6 +73,7 @@
|
|||||||
<widget class="QCommandLinkButton" name="copyLinkButton">
|
<widget class="QCommandLinkButton" name="copyLinkButton">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
<font>
|
<font>
|
||||||
|
<family>Segoe UI</family>
|
||||||
<weight>50</weight>
|
<weight>50</weight>
|
||||||
<bold>false</bold>
|
<bold>false</bold>
|
||||||
</font>
|
</font>
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ OwncloudAdvancedSetupPage::OwncloudAdvancedSetupPage()
|
|||||||
, _localFolderValid(false)
|
, _localFolderValid(false)
|
||||||
, _progressIndi(new QProgressIndicator(this))
|
, _progressIndi(new QProgressIndicator(this))
|
||||||
, _remoteFolder()
|
, _remoteFolder()
|
||||||
|
, _rSize(-1)
|
||||||
|
, _rSelectedSize(-1)
|
||||||
{
|
{
|
||||||
_ui.setupUi(this);
|
_ui.setupUi(this);
|
||||||
|
|
||||||
@@ -368,6 +370,8 @@ void OwncloudAdvancedSetupPage::slotQuotaRetrieved(const QVariantMap &result)
|
|||||||
{
|
{
|
||||||
_rSize = result["size"].toDouble();
|
_rSize = result["size"].toDouble();
|
||||||
_ui.lSyncEverythingSizeLabel->setText(tr("(%1)").arg(Utility::octetsToString(_rSize)));
|
_ui.lSyncEverythingSizeLabel->setText(tr("(%1)").arg(Utility::octetsToString(_rSize)));
|
||||||
|
|
||||||
|
updateStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 OwncloudAdvancedSetupPage::availableLocalSpace() const
|
qint64 OwncloudAdvancedSetupPage::availableLocalSpace() const
|
||||||
|
|||||||
@@ -399,7 +399,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="syncModeLabel">
|
<widget class="QLabel" name="syncModeLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Status message</string>
|
<string notr="true">Status message</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="textFormat">
|
<property name="textFormat">
|
||||||
<enum>Qt::RichText</enum>
|
<enum>Qt::RichText</enum>
|
||||||
|
|||||||
@@ -25,67 +25,24 @@
|
|||||||
<property name="styleSheet">
|
<property name="styleSheet">
|
||||||
<string notr="true"/>
|
<string notr="true"/>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<item row="16" column="0">
|
<item>
|
||||||
<widget class="QLabel" name="bottomLabel">
|
<spacer name="verticalSpacer_5">
|
||||||
<property name="minimumSize">
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
<width>0</width>
|
<width>20</width>
|
||||||
<height>0</height>
|
<height>20</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
</spacer>
|
||||||
<string notr="true">TextLabel</string>
|
|
||||||
</property>
|
|
||||||
<property name="textFormat">
|
|
||||||
<enum>Qt::RichText</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="14" column="0">
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_6">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="installLink">
|
|
||||||
<property name="text">
|
|
||||||
<string><a href="https://docs.nextcloud.com/server/15/admin_manual/installation/index.html#installation"><span style=" text-decoration: underline; color:#0000ff;">Host your own server</span></a></string>
|
|
||||||
</property>
|
|
||||||
<property name="openExternalLinks">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_5">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
|
||||||
<widget class="QLabel" name="topLabel">
|
<widget class="QLabel" name="topLabel">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
@@ -107,117 +64,66 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="11" column="0" rowspan="2">
|
<item>
|
||||||
<layout class="QHBoxLayout" name="buttons" stretch="0,0,0,0">
|
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||||
<property name="spacing">
|
|
||||||
<number>6</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>20</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_3">
|
<widget class="QPushButton" name="prevButton">
|
||||||
<property name="orientation">
|
<property name="minimumSize">
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
<size>
|
||||||
<width>40</width>
|
<width>40</width>
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="createAccountButton">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>150</width>
|
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="autoFillBackground">
|
<property name="maximumSize">
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Register with a provider</string>
|
|
||||||
</property>
|
|
||||||
<property name="default">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="loginButton">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
<size>
|
||||||
<width>150</width>
|
<width>40</width>
|
||||||
<height>0</height>
|
<height>16777215</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Log in</string>
|
<string/>
|
||||||
</property>
|
|
||||||
<property name="autoDefault">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="default">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
</property>
|
||||||
<property name="flat">
|
<property name="flat">
|
||||||
<bool>false</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_4">
|
<widget class="OCC::SlideShow" name="slideShow" native="true">
|
||||||
<property name="orientation">
|
<property name="font">
|
||||||
<enum>Qt::Horizontal</enum>
|
<font>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="nextButton">
|
||||||
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>40</width>
|
<width>40</width>
|
||||||
<height>20</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0">
|
<item>
|
||||||
<spacer name="verticalSpacer_4">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeType">
|
|
||||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="OCC::SlideShow" name="slideShow">
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<pointsize>12</pointsize>
|
|
||||||
<weight>75</weight>
|
|
||||||
<bold>true</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="0">
|
|
||||||
<widget class="QWidget" name="login" native="true">
|
<widget class="QWidget" name="login" native="true">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||||
@@ -301,7 +207,7 @@
|
|||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="placeholderText">
|
<property name="placeholderText">
|
||||||
<string>https://...</string>
|
<string notr="true">https://...</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -336,7 +242,7 @@
|
|||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Error Label</string>
|
<string notr="true">Error Label</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="textFormat">
|
<property name="textFormat">
|
||||||
<enum>Qt::RichText</enum>
|
<enum>Qt::RichText</enum>
|
||||||
@@ -385,8 +291,8 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item>
|
||||||
<spacer name="verticalSpacer_5">
|
<spacer name="verticalSpacer_4">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
@@ -401,6 +307,157 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="buttons" stretch="0,0,0,0">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>20</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="createAccountButton">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>150</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="autoFillBackground">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Register with a provider</string>
|
||||||
|
</property>
|
||||||
|
<property name="default">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="loginButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>150</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Log in</string>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="default">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_6">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="widget" native="true">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="installLink">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"><a href="https://docs.nextcloud.com/server/latest/admin_manual/installation/#installation"><span style=" text-decoration: underline; color:#7a7a7a;">Host your own server</span></a></string>
|
||||||
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_5">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="bottomLabel">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">TextLabel</string>
|
||||||
|
</property>
|
||||||
|
<property name="textFormat">
|
||||||
|
<enum>Qt::RichText</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
|
|||||||
@@ -84,7 +84,22 @@ OwncloudSetupPage::OwncloudSetupPage(QWidget *parent)
|
|||||||
_ui.slideShow->addSlide(Theme::hidpiFileName(":/client/theme/colored/wizard-files.png"), tr("Secure collaboration & file exchange"));
|
_ui.slideShow->addSlide(Theme::hidpiFileName(":/client/theme/colored/wizard-files.png"), tr("Secure collaboration & file exchange"));
|
||||||
_ui.slideShow->addSlide(Theme::hidpiFileName(":/client/theme/colored/wizard-groupware.png"), tr("Easy-to-use web mail, calendaring & contacts"));
|
_ui.slideShow->addSlide(Theme::hidpiFileName(":/client/theme/colored/wizard-groupware.png"), tr("Easy-to-use web mail, calendaring & contacts"));
|
||||||
_ui.slideShow->addSlide(Theme::hidpiFileName(":/client/theme/colored/wizard-talk.png"), tr("Screensharing, online meetings & web conferences"));
|
_ui.slideShow->addSlide(Theme::hidpiFileName(":/client/theme/colored/wizard-talk.png"), tr("Screensharing, online meetings & web conferences"));
|
||||||
connect(_ui.slideShow, &SlideShow::clicked, _ui.slideShow, &SlideShow::nextSlide);
|
connect(_ui.slideShow, &SlideShow::clicked, _ui.slideShow, &SlideShow::stopShow);
|
||||||
|
connect(_ui.nextButton, &QPushButton::clicked, _ui.slideShow, &SlideShow::nextSlide);
|
||||||
|
connect(_ui.prevButton, &QPushButton::clicked, _ui.slideShow, &SlideShow::prevSlide);
|
||||||
|
|
||||||
|
auto widgetBgLightness = OwncloudSetupPage::palette().color(OwncloudSetupPage::backgroundRole()).lightness();
|
||||||
|
bool widgetHasDarkBg =
|
||||||
|
(widgetBgLightness >= 125)
|
||||||
|
? false
|
||||||
|
: true;
|
||||||
|
_ui.nextButton->setIcon(theme->uiThemeIcon(QString("control-next.svg"), widgetHasDarkBg));
|
||||||
|
_ui.prevButton->setIcon(theme->uiThemeIcon(QString("control-prev.svg"), widgetHasDarkBg));
|
||||||
|
|
||||||
|
// QPushButtons are a mess when it comes to consistent background coloring without stylesheets,
|
||||||
|
// so we do it here even though this is an exceptional styling method here
|
||||||
|
_ui.createAccountButton->setStyleSheet("QPushButton {background-color: #0082C9; color: white}");
|
||||||
|
|
||||||
_ui.slideShow->startShow();
|
_ui.slideShow->startShow();
|
||||||
|
|
||||||
QPalette pal = _ui.slideShow->palette();
|
QPalette pal = _ui.slideShow->palette();
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
#include <QStyleHints>
|
#include <QStyleHints>
|
||||||
|
|
||||||
|
#define HASQT5_11 (QT_VERSION >= QT_VERSION_CHECK(5,11,0))
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
static const int Spacing = 6;
|
static const int Spacing = 6;
|
||||||
@@ -88,7 +90,11 @@ QSize SlideShow::sizeHint() const
|
|||||||
QFontMetrics fm = fontMetrics();
|
QFontMetrics fm = fontMetrics();
|
||||||
QSize labelSize(0, fm.height());
|
QSize labelSize(0, fm.height());
|
||||||
for (const QString &label : _labels) {
|
for (const QString &label : _labels) {
|
||||||
|
#if (HASQT5_11)
|
||||||
|
labelSize.setWidth(std::max(fm.horizontalAdvance(label), labelSize.width()));
|
||||||
|
#else
|
||||||
labelSize.setWidth(std::max(fm.width(label), labelSize.width()));
|
labelSize.setWidth(std::max(fm.width(label), labelSize.width()));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
QSize pixmapSize;
|
QSize pixmapSize;
|
||||||
for (const QPixmap &pixmap : _pixmaps) {
|
for (const QPixmap &pixmap : _pixmaps) {
|
||||||
@@ -116,7 +122,7 @@ void SlideShow::nextSlide()
|
|||||||
_reverse = false;
|
_reverse = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SlideShow::previousSlide()
|
void SlideShow::prevSlide()
|
||||||
{
|
{
|
||||||
setCurrentSlide((_currentIndex > 0 ? _currentIndex : _labels.count()) - 1);
|
setCurrentSlide((_currentIndex > 0 ? _currentIndex : _labels.count()) - 1);
|
||||||
_reverse = true;
|
_reverse = true;
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public slots:
|
|||||||
void startShow(int interval = 0);
|
void startShow(int interval = 0);
|
||||||
void stopShow();
|
void stopShow();
|
||||||
void nextSlide();
|
void nextSlide();
|
||||||
void previousSlide();
|
void prevSlide();
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
#include <QWebEngineProfile>
|
#include <QWebEngineProfile>
|
||||||
#include <QWebEngineUrlRequestInterceptor>
|
#include <QWebEngineUrlRequestInterceptor>
|
||||||
#include <QWebEngineUrlRequestJob>
|
#include <QWebEngineUrlRequestJob>
|
||||||
|
#if QT_VERSION >= 0x051200
|
||||||
|
#include <QWebEngineUrlScheme>
|
||||||
|
#endif
|
||||||
#include <QWebEngineUrlSchemeHandler>
|
#include <QWebEngineUrlSchemeHandler>
|
||||||
#include <QWebEngineView>
|
#include <QWebEngineView>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
@@ -65,7 +68,10 @@ WebView::WebView(QWidget *parent)
|
|||||||
_ui()
|
_ui()
|
||||||
{
|
{
|
||||||
_ui.setupUi(this);
|
_ui.setupUi(this);
|
||||||
|
#if QT_VERSION >= 0x051200
|
||||||
|
QWebEngineUrlScheme _ncsheme("nc");
|
||||||
|
QWebEngineUrlScheme::registerScheme(_ncsheme);
|
||||||
|
#endif
|
||||||
_webview = new QWebEngineView(this);
|
_webview = new QWebEngineView(this);
|
||||||
_profile = new QWebEngineProfile(this);
|
_profile = new QWebEngineProfile(this);
|
||||||
_page = new WebEnginePage(_profile);
|
_page = new WebEnginePage(_profile);
|
||||||
@@ -175,6 +181,7 @@ WebEnginePage::WebEnginePage(QWebEngineProfile *profile, QObject* parent) : QWeb
|
|||||||
}
|
}
|
||||||
|
|
||||||
QWebEnginePage * WebEnginePage::createWindow(QWebEnginePage::WebWindowType type) {
|
QWebEnginePage * WebEnginePage::createWindow(QWebEnginePage::WebWindowType type) {
|
||||||
|
Q_UNUSED(type);
|
||||||
ExternalWebEnginePage *view = new ExternalWebEnginePage(this->profile());
|
ExternalWebEnginePage *view = new ExternalWebEnginePage(this->profile());
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
@@ -216,6 +223,8 @@ ExternalWebEnginePage::ExternalWebEnginePage(QWebEngineProfile *profile, QObject
|
|||||||
|
|
||||||
bool ExternalWebEnginePage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame)
|
bool ExternalWebEnginePage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(type);
|
||||||
|
Q_UNUSED(isMainFrame);
|
||||||
QDesktopServices::openUrl(url);
|
QDesktopServices::openUrl(url);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,6 +160,37 @@ void AbstractNetworkJob::slotFinished()
|
|||||||
qCWarning(lcNetworkJob) << "SslHandshakeFailedError: " << errorString() << " : can be caused by a webserver wanting SSL client certificates";
|
qCWarning(lcNetworkJob) << "SslHandshakeFailedError: " << errorString() << " : can be caused by a webserver wanting SSL client certificates";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Qt doesn't yet transparently resend HTTP2 requests, do so here
|
||||||
|
const auto maxHttp2Resends = 5;
|
||||||
|
QByteArray verb = requestVerb(*reply());
|
||||||
|
if (_reply->error() == QNetworkReply::ContentReSendError
|
||||||
|
&& _reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute).toBool()) {
|
||||||
|
|
||||||
|
if ((_requestBody && !_requestBody->isSequential()) || verb.isEmpty()) {
|
||||||
|
qCWarning(lcNetworkJob) << "Can't resend HTTP2 request, verb or body not suitable"
|
||||||
|
<< _reply->request().url() << verb << _requestBody;
|
||||||
|
} else if (_http2ResendCount >= maxHttp2Resends) {
|
||||||
|
qCWarning(lcNetworkJob) << "Not resending HTTP2 request, number of resends exhausted"
|
||||||
|
<< _reply->request().url() << _http2ResendCount;
|
||||||
|
} else {
|
||||||
|
qCInfo(lcNetworkJob) << "HTTP2 resending" << _reply->request().url();
|
||||||
|
_http2ResendCount++;
|
||||||
|
|
||||||
|
resetTimeout();
|
||||||
|
if (_requestBody) {
|
||||||
|
if(!_requestBody->isOpen())
|
||||||
|
_requestBody->open(QIODevice::ReadOnly);
|
||||||
|
_requestBody->seek(0);
|
||||||
|
}
|
||||||
|
sendRequest(
|
||||||
|
verb,
|
||||||
|
_reply->request().url(),
|
||||||
|
_reply->request(),
|
||||||
|
_requestBody);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_reply->error() != QNetworkReply::NoError) {
|
if (_reply->error() != QNetworkReply::NoError) {
|
||||||
if (!_ignoreCredentialFailure || _reply->error() != QNetworkReply::AuthenticationRequiredError) {
|
if (!_ignoreCredentialFailure || _reply->error() != QNetworkReply::AuthenticationRequiredError) {
|
||||||
qCWarning(lcNetworkJob) << _reply->error() << errorString()
|
qCWarning(lcNetworkJob) << _reply->error() << errorString()
|
||||||
|
|||||||
@@ -188,7 +188,8 @@ private:
|
|||||||
QPointer<QNetworkReply> _reply; // (QPointer because the NetworkManager may be destroyed before the jobs at exit)
|
QPointer<QNetworkReply> _reply; // (QPointer because the NetworkManager may be destroyed before the jobs at exit)
|
||||||
QString _path;
|
QString _path;
|
||||||
QTimer _timer;
|
QTimer _timer;
|
||||||
int _redirectCount;
|
int _redirectCount = 0;
|
||||||
|
int _http2ResendCount = 0;
|
||||||
|
|
||||||
// Set by the xyzRequest() functions and needed to be able to redirect
|
// Set by the xyzRequest() functions and needed to be able to redirect
|
||||||
// requests, should it be required.
|
// requests, should it be required.
|
||||||
|
|||||||
@@ -36,9 +36,15 @@
|
|||||||
#include <QAuthenticator>
|
#include <QAuthenticator>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
|
||||||
|
#include <keychain.h>
|
||||||
|
#include "creds/abstractcredentials.h"
|
||||||
|
|
||||||
|
using namespace QKeychain;
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(lcAccount, "nextcloud.sync.account", QtInfoMsg)
|
Q_LOGGING_CATEGORY(lcAccount, "nextcloud.sync.account", QtInfoMsg)
|
||||||
|
const char app_password[] = "_app-password";
|
||||||
|
|
||||||
Account::Account(QObject *parent)
|
Account::Account(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
@@ -53,16 +59,17 @@ AccountPtr Account::create()
|
|||||||
AccountPtr acc = AccountPtr(new Account);
|
AccountPtr acc = AccountPtr(new Account);
|
||||||
acc->setSharedThis(acc);
|
acc->setSharedThis(acc);
|
||||||
|
|
||||||
//TODO: This probably needs to have a better
|
//TODO: This probably needs to have a better
|
||||||
// coupling, but it should work for now.
|
// coupling, but it should work for now.
|
||||||
acc->e2e()->setAccount(acc);
|
acc->e2e()->setAccount(acc);
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientSideEncryption* Account::e2e()
|
ClientSideEncryption* Account::e2e()
|
||||||
{
|
{
|
||||||
// Qt expects everything in the connect to be a pointer, so return a pointer.
|
// Qt expects everything in the connect to be a pointer, so return a pointer.
|
||||||
return &_e2e;
|
return &_e2e;
|
||||||
}
|
}
|
||||||
|
|
||||||
Account::~Account()
|
Account::~Account()
|
||||||
@@ -432,6 +439,9 @@ void Account::slotCredentialsAsked()
|
|||||||
|
|
||||||
void Account::handleInvalidCredentials()
|
void Account::handleInvalidCredentials()
|
||||||
{
|
{
|
||||||
|
// Retrieving password will trigger remote wipe check job
|
||||||
|
retrieveAppPassword();
|
||||||
|
|
||||||
emit invalidCredentials();
|
emit invalidCredentials();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,4 +513,63 @@ void Account::setNonShib(bool nonShib)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Account::setAppPassword(QString appPassword){
|
||||||
|
const QString kck = AbstractCredentials::keychainKey(
|
||||||
|
url().toString(),
|
||||||
|
davUser() + app_password,
|
||||||
|
id()
|
||||||
|
);
|
||||||
|
|
||||||
|
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
|
||||||
|
job->setInsecureFallback(false);
|
||||||
|
job->setKey(kck);
|
||||||
|
job->setBinaryData(appPassword.toLatin1());
|
||||||
|
connect(job, &WritePasswordJob::finished, [](Job *) {
|
||||||
|
qCInfo(lcAccount) << "appPassword stored in keychain";
|
||||||
|
});
|
||||||
|
job->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Account::retrieveAppPassword(){
|
||||||
|
const QString kck = AbstractCredentials::keychainKey(
|
||||||
|
url().toString(),
|
||||||
|
credentials()->user() + app_password,
|
||||||
|
id()
|
||||||
|
);
|
||||||
|
|
||||||
|
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
|
||||||
|
job->setInsecureFallback(false);
|
||||||
|
job->setKey(kck);
|
||||||
|
connect(job, &WritePasswordJob::finished, [this](Job *incoming) {
|
||||||
|
ReadPasswordJob *readJob = static_cast<ReadPasswordJob *>(incoming);
|
||||||
|
QString pwd("");
|
||||||
|
// Error or no valid public key error out
|
||||||
|
if (readJob->error() == NoError &&
|
||||||
|
readJob->binaryData().length() > 0) {
|
||||||
|
pwd = readJob->binaryData();
|
||||||
|
}
|
||||||
|
|
||||||
|
emit appPasswordRetrieved(pwd);
|
||||||
|
});
|
||||||
|
job->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Account::deleteAppPassword(){
|
||||||
|
const QString kck = AbstractCredentials::keychainKey(
|
||||||
|
url().toString(),
|
||||||
|
credentials()->user() + app_password,
|
||||||
|
id()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (kck.isEmpty()) {
|
||||||
|
qCDebug(lcAccount) << "appPassword is empty";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
||||||
|
job->setInsecureFallback(false);
|
||||||
|
job->setKey(kck);
|
||||||
|
job->start();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|||||||
@@ -41,6 +41,12 @@ class QNetworkReply;
|
|||||||
class QUrl;
|
class QUrl;
|
||||||
class QNetworkAccessManager;
|
class QNetworkAccessManager;
|
||||||
|
|
||||||
|
namespace QKeychain {
|
||||||
|
class Job;
|
||||||
|
class WritePasswordJob;
|
||||||
|
class ReadPasswordJob;
|
||||||
|
}
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
class AbstractCredentials;
|
class AbstractCredentials;
|
||||||
@@ -50,7 +56,6 @@ class QuotaInfo;
|
|||||||
class AccessManager;
|
class AccessManager;
|
||||||
class SimpleNetworkJob;
|
class SimpleNetworkJob;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reimplement this to handle SSL errors from libsync
|
* @brief Reimplement this to handle SSL errors from libsync
|
||||||
* @ingroup libsync
|
* @ingroup libsync
|
||||||
@@ -236,6 +241,11 @@ public:
|
|||||||
|
|
||||||
ClientSideEncryption* e2e();
|
ClientSideEncryption* e2e();
|
||||||
|
|
||||||
|
/// Used in RemoteWipe
|
||||||
|
void retrieveAppPassword();
|
||||||
|
void setAppPassword(QString appPassword);
|
||||||
|
void deleteAppPassword();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
/// Used when forgetting credentials
|
/// Used when forgetting credentials
|
||||||
void clearQNAMCache();
|
void clearQNAMCache();
|
||||||
@@ -262,6 +272,9 @@ signals:
|
|||||||
void accountChangedAvatar();
|
void accountChangedAvatar();
|
||||||
void accountChangedDisplayName();
|
void accountChangedDisplayName();
|
||||||
|
|
||||||
|
/// Used in RemoteWipe
|
||||||
|
void appPasswordRetrieved(QString);
|
||||||
|
|
||||||
protected Q_SLOTS:
|
protected Q_SLOTS:
|
||||||
void slotCredentialsFetched();
|
void slotCredentialsFetched();
|
||||||
void slotCredentialsAsked();
|
void slotCredentialsAsked();
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
|
||||||
#include <keychain.h>
|
#include <keychain.h>
|
||||||
|
#include "common/utility.h"
|
||||||
|
|
||||||
#include "wordlist.h"
|
#include "wordlist.h"
|
||||||
|
|
||||||
@@ -62,11 +63,11 @@ namespace {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
QByteArray BIO2ByteArray(BIO *b) {
|
QByteArray BIO2ByteArray(BIO *b) {
|
||||||
int pending = BIO_ctrl_pending(b);
|
size_t pending = BIO_ctrl_pending(b);
|
||||||
char *tmp = (char *)calloc(pending+1, sizeof(char));
|
char *tmp = (char *)calloc(pending+1, sizeof(char));
|
||||||
BIO_read(b, tmp, pending);
|
BIO_read(b, tmp, OCC::Utility::convertSizeToInt(pending));
|
||||||
|
|
||||||
QByteArray res(tmp, pending);
|
QByteArray res(tmp, OCC::Utility::convertSizeToInt(pending));
|
||||||
free(tmp);
|
free(tmp);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -549,7 +550,7 @@ QByteArray decryptStringAsymmetric(EVP_PKEY *privateKey, const QByteArray& data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto ret = std::string((char*) out, outlen);
|
const auto ret = std::string((char*) out, outlen);
|
||||||
QByteArray raw((const char*) out, outlen);
|
QByteArray raw((const char*) out, OCC::Utility::convertSizeToInt(outlen));
|
||||||
qCInfo(lcCse()) << raw;
|
qCInfo(lcCse()) << raw;
|
||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
@@ -603,7 +604,7 @@ QByteArray encryptStringAsymmetric(EVP_PKEY *publicKey, const QByteArray& data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Transform the encrypted data into base64.
|
// Transform the encrypted data into base64.
|
||||||
QByteArray raw((const char*) out, outLen);
|
QByteArray raw((const char*) out, OCC::Utility::convertSizeToInt(outLen));
|
||||||
qCInfo(lcCse()) << raw.toBase64();
|
qCInfo(lcCse()) << raw.toBase64();
|
||||||
return raw.toBase64();
|
return raw.toBase64();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -432,6 +432,7 @@ void SignPublicKeyApiJob::start()
|
|||||||
{
|
{
|
||||||
QNetworkRequest req;
|
QNetworkRequest req;
|
||||||
req.setRawHeader("OCS-APIREQUEST", "true");
|
req.setRawHeader("OCS-APIREQUEST", "true");
|
||||||
|
req.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/x-www-form-urlencoded"));
|
||||||
QUrlQuery query;
|
QUrlQuery query;
|
||||||
query.addQueryItem(QLatin1String("format"), QLatin1String("json"));
|
query.addQueryItem(QLatin1String("format"), QLatin1String("json"));
|
||||||
QUrl url = Utility::concatUrlPath(account()->url(), path());
|
QUrl url = Utility::concatUrlPath(account()->url(), path());
|
||||||
|
|||||||
@@ -37,6 +37,12 @@
|
|||||||
#include <QNetworkProxy>
|
#include <QNetworkProxy>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
|
||||||
|
#define QTLEGACY (QT_VERSION < QT_VERSION_CHECK(5,9,0))
|
||||||
|
|
||||||
|
#if !(QTLEGACY)
|
||||||
|
#include <QOperatingSystemVersion>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DEFAULT_REMOTE_POLL_INTERVAL 5000 // default remote poll time in milliseconds
|
#define DEFAULT_REMOTE_POLL_INTERVAL 5000 // default remote poll time in milliseconds
|
||||||
#define DEFAULT_MAX_LOG_LINES 20000
|
#define DEFAULT_MAX_LOG_LINES 20000
|
||||||
|
|
||||||
@@ -174,7 +180,11 @@ bool ConfigFile::showInExplorerNavigationPane() const
|
|||||||
{
|
{
|
||||||
const bool defaultValue =
|
const bool defaultValue =
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS10
|
#if QTLEGACY
|
||||||
|
(QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS10);
|
||||||
|
#else
|
||||||
|
QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10;
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
false
|
false
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -798,7 +798,11 @@ namespace { // Anonymous namespace for the recall feature
|
|||||||
static void preserveGroupOwnership(const QString &fileName, const QFileInfo &fi)
|
static void preserveGroupOwnership(const QString &fileName, const QFileInfo &fi)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
chown(fileName.toLocal8Bit().constData(), -1, fi.groupId());
|
int chownErr = chown(fileName.toLocal8Bit().constData(), -1, fi.groupId());
|
||||||
|
if (chownErr) {
|
||||||
|
// TODO: Consider further error handling!
|
||||||
|
qCWarning(lcPropagateDownload) << QString("preserveGroupOwnership: chown error %1: setting group %2 failed on file %3").arg(chownErr).arg(fi.groupId()).arg(fileName);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
Q_UNUSED(fileName);
|
Q_UNUSED(fileName);
|
||||||
Q_UNUSED(fi);
|
Q_UNUSED(fi);
|
||||||
|
|||||||
@@ -177,6 +177,14 @@ QIcon Theme::themeIcon(const QString &name, bool sysTray, bool sysTrayMenuVisibl
|
|||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QIcon Theme::uiThemeIcon(const QString &iconName, bool uiHasDarkBg) const
|
||||||
|
{
|
||||||
|
QString themeResBasePath = ":/client/theme/";
|
||||||
|
QString iconPath = themeResBasePath + (uiHasDarkBg?"white/":"black/") + iconName;
|
||||||
|
std::string icnPath = iconPath.toUtf8().constData();
|
||||||
|
return QIcon(QPixmap(iconPath));
|
||||||
|
}
|
||||||
|
|
||||||
QString Theme::hidpiFileName(const QString &fileName, QPaintDevice *dev)
|
QString Theme::hidpiFileName(const QString &fileName, QPaintDevice *dev)
|
||||||
{
|
{
|
||||||
qreal devicePixelRatio = dev ? dev->devicePixelRatio() : qApp->primaryScreen()->devicePixelRatio();
|
qreal devicePixelRatio = dev ? dev->devicePixelRatio() : qApp->primaryScreen()->devicePixelRatio();
|
||||||
|
|||||||
@@ -347,6 +347,14 @@ public:
|
|||||||
* important dependency versions.
|
* important dependency versions.
|
||||||
*/
|
*/
|
||||||
virtual QString versionSwitchOutput() const;
|
virtual QString versionSwitchOutput() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Request suitable QIcon resource depending on the background colour of the parent widget.
|
||||||
|
*
|
||||||
|
* This should be replaced (TODO) by a real theming implementation for the client UI
|
||||||
|
* (actually 2019/09/13 only systray theming).
|
||||||
|
*/
|
||||||
|
virtual QIcon uiThemeIcon(const QString &iconName, bool uiHasDarkBg) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
#ifndef TOKEN_AUTH_ONLY
|
#ifndef TOKEN_AUTH_ONLY
|
||||||
|
|||||||
@@ -40,3 +40,5 @@ System Volume Information
|
|||||||
.nfs*
|
.nfs*
|
||||||
|
|
||||||
My Saved Places.
|
My Saved Places.
|
||||||
|
|
||||||
|
\#*#
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ include_directories(${CMAKE_SOURCE_DIR}/src
|
|||||||
${SQLITE3_INCLUDE_DIR}
|
${SQLITE3_INCLUDE_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
include(owncloud_add_test.cmake)
|
include(nextcloud_add_test.cmake)
|
||||||
|
|
||||||
owncloud_add_test(OwncloudPropagator "")
|
nextcloud_add_test(NextcloudPropagator "")
|
||||||
owncloud_add_test(Updater "")
|
nextcloud_add_test(Updater "")
|
||||||
|
|
||||||
SET(FolderWatcher_SRC ../src/gui/folderwatcher.cpp)
|
SET(FolderWatcher_SRC ../src/gui/folderwatcher.cpp)
|
||||||
|
|
||||||
@@ -29,49 +29,64 @@ IF( APPLE )
|
|||||||
list(APPEND FolderWatcher_SRC ../src/gui/folderwatcher_mac.cpp)
|
list(APPEND FolderWatcher_SRC ../src/gui/folderwatcher_mac.cpp)
|
||||||
list(APPEND FolderWatcher_SRC ../src/gui/socketapisocket_mac.mm)
|
list(APPEND FolderWatcher_SRC ../src/gui/socketapisocket_mac.mm)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
owncloud_add_test(NetrcParser ../src/cmd/netrcparser.cpp)
|
nextcloud_add_test(NetrcParser ../src/cmd/netrcparser.cpp)
|
||||||
owncloud_add_test(OwnSql "")
|
nextcloud_add_test(OwnSql "")
|
||||||
owncloud_add_test(SyncJournalDB "")
|
nextcloud_add_test(SyncJournalDB "")
|
||||||
owncloud_add_test(SyncFileItem "")
|
nextcloud_add_test(SyncFileItem "")
|
||||||
owncloud_add_test(ConcatUrl "")
|
nextcloud_add_test(ConcatUrl "")
|
||||||
owncloud_add_test(XmlParse "")
|
nextcloud_add_test(XmlParse "")
|
||||||
owncloud_add_test(ChecksumValidator "")
|
nextcloud_add_test(ChecksumValidator "")
|
||||||
|
|
||||||
owncloud_add_test(ExcludedFiles "")
|
nextcloud_add_test(ExcludedFiles "")
|
||||||
|
|
||||||
owncloud_add_test(FileSystem "")
|
nextcloud_add_test(FileSystem "")
|
||||||
owncloud_add_test(Utility "")
|
nextcloud_add_test(Utility "")
|
||||||
owncloud_add_test(SyncEngine "syncenginetestutils.h")
|
nextcloud_add_test(SyncEngine "syncenginetestutils.h")
|
||||||
owncloud_add_test(SyncMove "syncenginetestutils.h")
|
nextcloud_add_test(SyncMove "syncenginetestutils.h")
|
||||||
owncloud_add_test(SyncConflict "syncenginetestutils.h")
|
nextcloud_add_test(SyncConflict "syncenginetestutils.h")
|
||||||
owncloud_add_test(SyncFileStatusTracker "syncenginetestutils.h")
|
nextcloud_add_test(SyncFileStatusTracker "syncenginetestutils.h")
|
||||||
owncloud_add_test(ChunkingNg "syncenginetestutils.h")
|
nextcloud_add_test(ChunkingNg "syncenginetestutils.h")
|
||||||
owncloud_add_test(UploadReset "syncenginetestutils.h")
|
nextcloud_add_test(UploadReset "syncenginetestutils.h")
|
||||||
owncloud_add_test(AllFilesDeleted "syncenginetestutils.h")
|
nextcloud_add_test(AllFilesDeleted "syncenginetestutils.h")
|
||||||
owncloud_add_test(Blacklist "syncenginetestutils.h")
|
nextcloud_add_test(Blacklist "syncenginetestutils.h")
|
||||||
owncloud_add_test(FolderWatcher "${FolderWatcher_SRC}")
|
nextcloud_add_test(FolderWatcher "${FolderWatcher_SRC}")
|
||||||
|
|
||||||
if( UNIX AND NOT APPLE )
|
if( UNIX AND NOT APPLE )
|
||||||
owncloud_add_test(InotifyWatcher "${FolderWatcher_SRC}")
|
nextcloud_add_test(InotifyWatcher "${FolderWatcher_SRC}")
|
||||||
endif(UNIX AND NOT APPLE)
|
endif(UNIX AND NOT APPLE)
|
||||||
|
|
||||||
owncloud_add_benchmark(LargeSync "syncenginetestutils.h")
|
nextcloud_add_benchmark(LargeSync "syncenginetestutils.h")
|
||||||
|
|
||||||
SET(FolderMan_SRC ../src/gui/folderman.cpp)
|
SET(FolderMan_SRC ../src/gui/folderman.cpp)
|
||||||
list(APPEND FolderMan_SRC ../src/gui/folder.cpp )
|
list(APPEND FolderMan_SRC ../src/gui/folder.cpp )
|
||||||
list(APPEND FolderMan_SRC ../src/gui/socketapi.cpp )
|
list(APPEND FolderMan_SRC ../src/gui/socketapi.cpp )
|
||||||
list(APPEND FolderMan_SRC ../src/gui/accountstate.cpp )
|
|
||||||
list(APPEND FolderMan_SRC ../src/gui/syncrunfilelog.cpp )
|
list(APPEND FolderMan_SRC ../src/gui/syncrunfilelog.cpp )
|
||||||
list(APPEND FolderMan_SRC ../src/gui/lockwatcher.cpp )
|
list(APPEND FolderMan_SRC ../src/gui/lockwatcher.cpp )
|
||||||
list(APPEND FolderMan_SRC ../src/gui/guiutility.cpp )
|
list(APPEND FolderMan_SRC ../src/gui/guiutility.cpp )
|
||||||
list(APPEND FolderMan_SRC ../src/gui/navigationpanehelper.cpp )
|
list(APPEND FolderMan_SRC ../src/gui/navigationpanehelper.cpp )
|
||||||
list(APPEND FolderMan_SRC ../src/gui/connectionvalidator.cpp )
|
list(APPEND FolderMan_SRC ../src/gui/connectionvalidator.cpp )
|
||||||
list(APPEND FolderMan_SRC ../src/gui/clientproxy.cpp )
|
list(APPEND FolderMan_SRC ../src/gui/clientproxy.cpp )
|
||||||
|
list(APPEND FolderMan_SRC ../src/gui/accountstate.cpp )
|
||||||
|
list(APPEND FolderMan_SRC ../src/gui/remotewipe.cpp )
|
||||||
list(APPEND FolderMan_SRC ${FolderWatcher_SRC})
|
list(APPEND FolderMan_SRC ${FolderWatcher_SRC})
|
||||||
list(APPEND FolderMan_SRC stub.cpp )
|
list(APPEND FolderMan_SRC stubfolderman.cpp )
|
||||||
owncloud_add_test(FolderMan "${FolderMan_SRC}")
|
nextcloud_add_test(FolderMan "${FolderMan_SRC}")
|
||||||
|
|
||||||
owncloud_add_test(OAuth "syncenginetestutils.h;../src/gui/creds/oauth.cpp")
|
SET(RemoteWipe_SRC ../src/gui/remotewipe.cpp)
|
||||||
|
list(APPEND RemoteWipe_SRC ../src/gui/clientproxy.cpp )
|
||||||
|
list(APPEND RemoteWipe_SRC ../src/gui/guiutility.cpp )
|
||||||
|
list(APPEND RemoteWipe_SRC ../src/gui/connectionvalidator.cpp )
|
||||||
|
list(APPEND RemoteWipe_SRC ../src/gui/accountstate.cpp )
|
||||||
|
list(APPEND RemoteWipe_SRC ../src/gui/socketapi.cpp )
|
||||||
|
list(APPEND RemoteWipe_SRC ../src/gui/folder.cpp )
|
||||||
|
list(APPEND RemoteWipe_SRC ../src/gui/syncrunfilelog.cpp )
|
||||||
|
list(APPEND RemoteWipe_SRC ../src/gui/folderwatcher_linux.cpp )
|
||||||
|
list(APPEND RemoteWipe_SRC ../src/gui/folderwatcher.cpp )
|
||||||
|
list(APPEND RemoteWipe_SRC ${RemoteWipe_SRC})
|
||||||
|
list(APPEND RemoteWipe_SRC stubremotewipe.cpp )
|
||||||
|
nextcloud_add_test(RemoteWipe "${RemoteWipe_SRC}")
|
||||||
|
|
||||||
|
nextcloud_add_test(OAuth "syncenginetestutils.h;../src/gui/creds/oauth.cpp")
|
||||||
|
|
||||||
configure_file(test_journal.db "${PROJECT_BINARY_DIR}/bin/test_journal.db" COPYONLY)
|
configure_file(test_journal.db "${PROJECT_BINARY_DIR}/bin/test_journal.db" COPYONLY)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
find_package(Qt5 COMPONENTS Core Test Xml Network REQUIRED)
|
find_package(Qt5 COMPONENTS Core Test Xml Network REQUIRED)
|
||||||
|
|
||||||
macro(owncloud_add_test test_class additional_cpp)
|
macro(nextcloud_add_test test_class additional_cpp)
|
||||||
set(CMAKE_AUTOMOC TRUE)
|
set(CMAKE_AUTOMOC TRUE)
|
||||||
set(OWNCLOUD_TEST_CLASS ${test_class})
|
set(OWNCLOUD_TEST_CLASS ${test_class})
|
||||||
string(TOLOWER "${OWNCLOUD_TEST_CLASS}" OWNCLOUD_TEST_CLASS_LOWERCASE)
|
string(TOLOWER "${OWNCLOUD_TEST_CLASS}" OWNCLOUD_TEST_CLASS_LOWERCASE)
|
||||||
@@ -19,7 +19,7 @@ macro(owncloud_add_test test_class additional_cpp)
|
|||||||
add_test(NAME ${OWNCLOUD_TEST_CLASS}Test COMMAND ${OWNCLOUD_TEST_CLASS}Test)
|
add_test(NAME ${OWNCLOUD_TEST_CLASS}Test COMMAND ${OWNCLOUD_TEST_CLASS}Test)
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
macro(owncloud_add_benchmark test_class additional_cpp)
|
macro(nextcloud_add_benchmark test_class additional_cpp)
|
||||||
set(CMAKE_AUTOMOC TRUE)
|
set(CMAKE_AUTOMOC TRUE)
|
||||||
set(OWNCLOUD_TEST_CLASS ${test_class})
|
set(OWNCLOUD_TEST_CLASS ${test_class})
|
||||||
string(TOLOWER "${OWNCLOUD_TEST_CLASS}" OWNCLOUD_TEST_CLASS_LOWERCASE)
|
string(TOLOWER "${OWNCLOUD_TEST_CLASS}" OWNCLOUD_TEST_CLASS_LOWERCASE)
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
// stub to prevent linker error
|
// stub to prevent linker error
|
||||||
#include "accountmanager.h"
|
#include "accountmanager.h"
|
||||||
|
|
||||||
OCC::AccountManager *OCC::AccountManager::instance() { return static_cast<AccountManager *>(new QObject); }
|
OCC::AccountManager *OCC::AccountManager::instance() { return static_cast<AccountManager *>(new QObject); }
|
||||||
|
void OCC::AccountManager::save(bool) { }
|
||||||
void OCC::AccountManager::saveAccountState(AccountState *) { }
|
void OCC::AccountManager::saveAccountState(AccountState *) { }
|
||||||
void OCC::AccountManager::save(bool saveCredentials) { Q_UNUSED(saveCredentials); }
|
void OCC::AccountManager::deleteAccount(AccountState *) { }
|
||||||
void OCC::AccountManager::accountRemoved(OCC::AccountState*) { }
|
void OCC::AccountManager::accountRemoved(OCC::AccountState*) { }
|
||||||
|
OCC::AccountStatePtr OCC::AccountManager::account(const QString &){ return AccountStatePtr(); }
|
||||||
|
void OCC::AccountManager::removeAccountFolders(OCC::AccountState*) { }
|
||||||
const QMetaObject OCC::AccountManager::staticMetaObject = QObject::staticMetaObject;
|
const QMetaObject OCC::AccountManager::staticMetaObject = QObject::staticMetaObject;
|
||||||
30
test/stubremotewipe.cpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// stub to prevent linker error
|
||||||
|
#include "accountmanager.h"
|
||||||
|
#include "accountstate.h"
|
||||||
|
#include "socketapi.h"
|
||||||
|
#include "folderman.h"
|
||||||
|
|
||||||
|
OCC::AccountManager *OCC::AccountManager::instance() { return static_cast<AccountManager *>(new QObject); }
|
||||||
|
void OCC::AccountManager::save(bool) { }
|
||||||
|
OCC::AccountState *OCC::AccountManager::addAccount(const AccountPtr& ac) { return new OCC::AccountState(ac); }
|
||||||
|
void OCC::AccountManager::deleteAccount(AccountState *) { }
|
||||||
|
void OCC::AccountManager::accountRemoved(OCC::AccountState*) { }
|
||||||
|
OCC::AccountStatePtr OCC::AccountManager::account(const QString &){ return AccountStatePtr(); }
|
||||||
|
const QMetaObject OCC::AccountManager::staticMetaObject = QObject::staticMetaObject;
|
||||||
|
|
||||||
|
OCC::FolderMan *OCC::FolderMan::instance() { return static_cast<FolderMan *>(new QObject); }
|
||||||
|
void OCC::FolderMan::wipeDone(OCC::AccountState*, bool) { }
|
||||||
|
OCC::Folder* OCC::FolderMan::addFolder(OCC::AccountState* as, OCC::FolderDefinition const &f) { return nullptr; }
|
||||||
|
void OCC::FolderMan::slotWipeFolderForAccount(OCC::AccountState*) { }
|
||||||
|
QString OCC::FolderMan::unescapeAlias(QString const&){ return QString(); }
|
||||||
|
QString OCC::FolderMan::escapeAlias(QString const&){ return QString(); }
|
||||||
|
void OCC::FolderMan::scheduleFolder(OCC::Folder*){ }
|
||||||
|
OCC::SocketApi *OCC::FolderMan::socketApi(){ return new SocketApi; }
|
||||||
|
OCC::Folder::Map OCC::FolderMan::map() { return OCC::Folder::Map(); }
|
||||||
|
void OCC::FolderMan::setSyncEnabled(bool) { }
|
||||||
|
void OCC::FolderMan::slotSyncOnceFileUnlocks(QString const&) { }
|
||||||
|
void OCC::FolderMan::slotScheduleETagJob(QString const&, OCC::RequestEtagJob*){ }
|
||||||
|
OCC::Folder *OCC::FolderMan::folderForPath(QString const&) { return nullptr; }
|
||||||
|
OCC::Folder* OCC::FolderMan::folder(QString const&) { return nullptr; }
|
||||||
|
void OCC::FolderMan::folderSyncStateChange(OCC::Folder*) { }
|
||||||
|
const QMetaObject OCC::FolderMan::staticMetaObject = QObject::staticMetaObject;
|
||||||
@@ -39,6 +39,8 @@ private slots:
|
|||||||
QVERIFY(excluded.isExcluded("/a/foo_conflict-bar", "/a", keepHidden));
|
QVERIFY(excluded.isExcluded("/a/foo_conflict-bar", "/a", keepHidden));
|
||||||
QVERIFY(excluded.isExcluded("/a/foo (conflicted copy bar)", "/a", keepHidden));
|
QVERIFY(excluded.isExcluded("/a/foo (conflicted copy bar)", "/a", keepHidden));
|
||||||
QVERIFY(excluded.isExcluded("/a/.b", "/a", excludeHidden));
|
QVERIFY(excluded.isExcluded("/a/.b", "/a", excludeHidden));
|
||||||
|
|
||||||
|
QVERIFY(excluded.isExcluded("/a/#b#", "/a", keepHidden));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -14,29 +14,10 @@
|
|||||||
#include "account.h"
|
#include "account.h"
|
||||||
#include "accountstate.h"
|
#include "accountstate.h"
|
||||||
#include "configfile.h"
|
#include "configfile.h"
|
||||||
#include "creds/httpcredentials.h"
|
#include "testhelper.h"
|
||||||
|
|
||||||
using namespace OCC;
|
using namespace OCC;
|
||||||
|
class HttpCredentials;
|
||||||
class HttpCredentialsTest : public HttpCredentials {
|
|
||||||
public:
|
|
||||||
HttpCredentialsTest(const QString& user, const QString& password)
|
|
||||||
: HttpCredentials(user, password)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void askFromUser() Q_DECL_OVERRIDE {
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static FolderDefinition folderDefinition(const QString &path) {
|
|
||||||
FolderDefinition d;
|
|
||||||
d.localPath = path;
|
|
||||||
d.targetPath = path;
|
|
||||||
d.alias = path;
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class TestFolderMan: public QObject
|
class TestFolderMan: public QObject
|
||||||
{
|
{
|
||||||
|
|||||||
28
test/testhelper.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef TESTHELPER_H
|
||||||
|
#define TESTHELPER_H
|
||||||
|
|
||||||
|
#include "folder.h"
|
||||||
|
#include "creds/httpcredentials.h"
|
||||||
|
|
||||||
|
using namespace OCC;
|
||||||
|
|
||||||
|
class HttpCredentialsTest : public HttpCredentials {
|
||||||
|
public:
|
||||||
|
HttpCredentialsTest(const QString& user, const QString& password)
|
||||||
|
: HttpCredentials(user, password)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void askFromUser() Q_DECL_OVERRIDE {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static FolderDefinition folderDefinition(const QString &path) {
|
||||||
|
FolderDefinition d;
|
||||||
|
d.localPath = path;
|
||||||
|
d.targetPath = path;
|
||||||
|
d.alias = path;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // TESTHELPER_H
|
||||||
@@ -8,21 +8,21 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "propagatedownload.h"
|
#include "propagatedownload.h"
|
||||||
#include "owncloudpropagator_p.h"
|
#include "nextcloudpropagator_p.h"
|
||||||
|
|
||||||
using namespace OCC;
|
using namespace OCC;
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
QString OWNCLOUDSYNC_EXPORT createDownloadTmpFileName(const QString &previous);
|
QString OWNCLOUDSYNC_EXPORT createDownloadTmpFileName(const QString &previous);
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestOwncloudPropagator : public QObject
|
class TestNextcloudPropagator : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void testUpdateErrorFromSession()
|
void testUpdateErrorFromSession()
|
||||||
{
|
{
|
||||||
// OwncloudPropagator propagator( NULL, QLatin1String("test1"), QLatin1String("test2"), new ProgressDatabase);
|
// NextcloudPropagator propagator( NULL, QLatin1String("test1"), QLatin1String("test2"), new ProgressDatabase);
|
||||||
QVERIFY( true );
|
QVERIFY( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,5 +78,5 @@ private slots:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
QTEST_APPLESS_MAIN(TestOwncloudPropagator)
|
QTEST_APPLESS_MAIN(TestNextcloudPropagator)
|
||||||
#include "testowncloudpropagator.moc"
|
#include "testnextcloudpropagator.moc"
|
||||||
83
test/testremotewipe.cpp
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* This software is in the public domain, furnished "as is", without technical
|
||||||
|
* support, and with no warranty, express or implied, as to its usefulness for
|
||||||
|
* any purpose.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <qglobal.h>
|
||||||
|
#include <QTemporaryDir>
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
#include "remotewipe.h"
|
||||||
|
|
||||||
|
#include "common/utility.h"
|
||||||
|
#include "folderman.h"
|
||||||
|
#include "account.h"
|
||||||
|
#include "accountstate.h"
|
||||||
|
#include "configfile.h"
|
||||||
|
|
||||||
|
#include "testhelper.h"
|
||||||
|
|
||||||
|
using namespace OCC;
|
||||||
|
|
||||||
|
class TestRemoteWipe: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
// TODO
|
||||||
|
void testWipe(){
|
||||||
|
// QTemporaryDir dir;
|
||||||
|
// ConfigFile::setConfDir(dir.path()); // we don't want to pollute the user's config file
|
||||||
|
// QVERIFY(dir.isValid());
|
||||||
|
|
||||||
|
// QDir dirToRemove(dir.path());
|
||||||
|
// QVERIFY(dirToRemove.mkpath("nextcloud"));
|
||||||
|
|
||||||
|
// QString dirPath = dirToRemove.canonicalPath();
|
||||||
|
|
||||||
|
// AccountPtr account = Account::create();
|
||||||
|
// QVERIFY(account);
|
||||||
|
|
||||||
|
// auto manager = AccountManager::instance();
|
||||||
|
// QVERIFY(manager);
|
||||||
|
|
||||||
|
// AccountState *newAccountState = manager->addAccount(account);
|
||||||
|
// manager->save();
|
||||||
|
// QVERIFY(newAccountState);
|
||||||
|
|
||||||
|
// QUrl url("http://example.de");
|
||||||
|
// HttpCredentialsTest *cred = new HttpCredentialsTest("testuser", "secret");
|
||||||
|
// account->setCredentials(cred);
|
||||||
|
// account->setUrl( url );
|
||||||
|
|
||||||
|
// FolderMan *folderman = FolderMan::instance();
|
||||||
|
// folderman->addFolder(newAccountState, folderDefinition(dirPath + "/sub/nextcloud/"));
|
||||||
|
|
||||||
|
// // check if account exists
|
||||||
|
// qDebug() << "Does account exists?!";
|
||||||
|
// QVERIFY(!account->id().isEmpty());
|
||||||
|
|
||||||
|
// manager->deleteAccount(newAccountState);
|
||||||
|
// manager->save();
|
||||||
|
|
||||||
|
// // check if account exists
|
||||||
|
// qDebug() << "Does account exists yet?!";
|
||||||
|
// QVERIFY(account);
|
||||||
|
|
||||||
|
// // check if folder exists
|
||||||
|
// QVERIFY(dirToRemove.exists());
|
||||||
|
|
||||||
|
// // remote folders
|
||||||
|
// qDebug() << "Removing folder for account " << newAccountState->account()->url();
|
||||||
|
|
||||||
|
// folderman->slotWipeFolderForAccount(newAccountState);
|
||||||
|
|
||||||
|
// // check if folders dont exist anymore
|
||||||
|
// QCOMPARE(dirToRemove.exists(), false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QTEST_APPLESS_MAIN(TestRemoteWipe)
|
||||||
|
#include "testremotewipe.moc"
|
||||||
@@ -543,7 +543,7 @@ private slots:
|
|||||||
QVERIFY(conflicts.size() == 2);
|
QVERIFY(conflicts.size() == 2);
|
||||||
QVERIFY(conflicts[0].contains("A (conflicted copy"));
|
QVERIFY(conflicts[0].contains("A (conflicted copy"));
|
||||||
QVERIFY(conflicts[1].contains("B (conflicted copy"));
|
QVERIFY(conflicts[1].contains("B (conflicted copy"));
|
||||||
for (auto conflict : conflicts)
|
for (const auto& conflict : conflicts)
|
||||||
QDir(fakeFolder.localPath() + conflict).removeRecursively();
|
QDir(fakeFolder.localPath() + conflict).removeRecursively();
|
||||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||||
|
|
||||||
@@ -581,7 +581,7 @@ private slots:
|
|||||||
auto conflicts = findConflicts(fakeFolder.currentLocalState());
|
auto conflicts = findConflicts(fakeFolder.currentLocalState());
|
||||||
QVERIFY(conflicts.size() == 1);
|
QVERIFY(conflicts.size() == 1);
|
||||||
QVERIFY(conflicts[0].contains("A (conflicted copy"));
|
QVERIFY(conflicts[0].contains("A (conflicted copy"));
|
||||||
for (auto conflict : conflicts)
|
for (const auto& conflict : conflicts)
|
||||||
QDir(fakeFolder.localPath() + conflict).removeRecursively();
|
QDir(fakeFolder.localPath() + conflict).removeRecursively();
|
||||||
|
|
||||||
QVERIFY(fakeFolder.syncEngine().isAnotherSyncNeeded() == ImmediateFollowUp);
|
QVERIFY(fakeFolder.syncEngine().isAnotherSyncNeeded() == ImmediateFollowUp);
|
||||||
|
|||||||
@@ -289,12 +289,12 @@ private slots:
|
|||||||
<< "foo bla bar/file"
|
<< "foo bla bar/file"
|
||||||
<< "fo_"
|
<< "fo_"
|
||||||
<< "fo_/file";
|
<< "fo_/file";
|
||||||
for (auto elem : elements)
|
for (const auto& elem : elements)
|
||||||
makeEntry(elem);
|
makeEntry(elem);
|
||||||
|
|
||||||
auto checkElements = [&]() {
|
auto checkElements = [&]() {
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
for (auto elem : elements) {
|
for (const auto& elem : elements) {
|
||||||
SyncJournalFileRecord record;
|
SyncJournalFileRecord record;
|
||||||
_db.getFileRecord(elem, &record);
|
_db.getFileRecord(elem, &record);
|
||||||
if (!record.isValid()) {
|
if (!record.isValid()) {
|
||||||
|
|||||||
@@ -523,13 +523,13 @@ private slots:
|
|||||||
auto currentLocal = fakeFolder.currentLocalState();
|
auto currentLocal = fakeFolder.currentLocalState();
|
||||||
auto conflicts = findConflicts(currentLocal.children["A4"]);
|
auto conflicts = findConflicts(currentLocal.children["A4"]);
|
||||||
QCOMPARE(conflicts.size(), 1);
|
QCOMPARE(conflicts.size(), 1);
|
||||||
for (auto c : conflicts) {
|
for (const auto& c : conflicts) {
|
||||||
QCOMPARE(currentLocal.find(c)->contentChar, 'L');
|
QCOMPARE(currentLocal.find(c)->contentChar, 'L');
|
||||||
local.remove(c);
|
local.remove(c);
|
||||||
}
|
}
|
||||||
conflicts = findConflicts(currentLocal.children["B4"]);
|
conflicts = findConflicts(currentLocal.children["B4"]);
|
||||||
QCOMPARE(conflicts.size(), 1);
|
QCOMPARE(conflicts.size(), 1);
|
||||||
for (auto c : conflicts) {
|
for (const auto& c : conflicts) {
|
||||||
QCOMPARE(currentLocal.find(c)->contentChar, 'L');
|
QCOMPARE(currentLocal.find(c)->contentChar, 'L');
|
||||||
local.remove(c);
|
local.remove(c);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
<file>theme/white/state-sync-64.png</file>
|
<file>theme/white/state-sync-64.png</file>
|
||||||
<file>theme/white/state-sync-128.png</file>
|
<file>theme/white/state-sync-128.png</file>
|
||||||
<file>theme/white/state-sync-256.png</file>
|
<file>theme/white/state-sync-256.png</file>
|
||||||
<file>theme/black/state-error-32.png</file>
|
<file>theme/black/state-error-32.png</file>
|
||||||
<file>theme/black/state-error-64.png</file>
|
<file>theme/black/state-error-64.png</file>
|
||||||
<file>theme/black/state-error-128.png</file>
|
<file>theme/black/state-error-128.png</file>
|
||||||
<file>theme/black/state-error-256.png</file>
|
<file>theme/black/state-error-256.png</file>
|
||||||
@@ -79,6 +79,8 @@
|
|||||||
<file>theme/colored/state-warning-64.png</file>
|
<file>theme/colored/state-warning-64.png</file>
|
||||||
<file>theme/colored/state-warning-128.png</file>
|
<file>theme/colored/state-warning-128.png</file>
|
||||||
<file>theme/colored/state-warning-256.png</file>
|
<file>theme/colored/state-warning-256.png</file>
|
||||||
|
<file>theme/black/control-next.svg</file>
|
||||||
|
<file>theme/black/control-prev.svg</file>
|
||||||
<file>theme/black/state-error.svg</file>
|
<file>theme/black/state-error.svg</file>
|
||||||
<file>theme/black/state-error-16.png</file>
|
<file>theme/black/state-error-16.png</file>
|
||||||
<file>theme/black/state-offline.svg</file>
|
<file>theme/black/state-offline.svg</file>
|
||||||
@@ -99,6 +101,8 @@
|
|||||||
<file>theme/black/state-warning-64.png</file>
|
<file>theme/black/state-warning-64.png</file>
|
||||||
<file>theme/black/state-warning-128.png</file>
|
<file>theme/black/state-warning-128.png</file>
|
||||||
<file>theme/black/state-warning-256.png</file>
|
<file>theme/black/state-warning-256.png</file>
|
||||||
|
<file>theme/white/control-next.svg</file>
|
||||||
|
<file>theme/white/control-prev.svg</file>
|
||||||
<file>theme/white/state-error.svg</file>
|
<file>theme/white/state-error.svg</file>
|
||||||
<file>theme/white/state-error-16.png</file>
|
<file>theme/white/state-error-16.png</file>
|
||||||
<file>theme/white/state-offline.svg</file>
|
<file>theme/white/state-offline.svg</file>
|
||||||
|
|||||||
9
theme/black/control-next.svg
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 18 29" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<g transform="matrix(1,0,0,1,-7.28829,-1.57657)">
|
||||||
|
<g transform="matrix(1,0,0,1,-5.71171,-3.55271e-15)">
|
||||||
|
<path d="M13.424,5.001C13.19,4.767 13.19,4.387 13.424,4.152C13.995,3.581 15.005,2.572 15.576,2.001C15.81,1.767 16.19,1.767 16.424,2.001C18.491,4.068 27.501,13.078 29.858,15.434C30.008,15.584 30.092,15.788 30.092,16C30.092,16.212 30.008,16.416 29.858,16.566C27.501,18.922 18.491,27.932 16.424,29.999C16.19,30.233 15.81,30.233 15.576,29.999C15.005,29.428 13.995,28.419 13.424,27.848C13.19,27.613 13.19,27.233 13.424,26.999C15.493,24.93 24.423,16 24.423,16C24.423,16 15.493,7.07 13.424,5.001Z" style="fill-opacity:0.6;"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |