mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2026-04-03 09:11:33 +02:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0b32c19e4 |
@@ -344,9 +344,10 @@ steps:
|
||||
from_secret: DEBIAN_SECRET_IV
|
||||
trigger:
|
||||
branch:
|
||||
- stable-2.6
|
||||
- master
|
||||
event:
|
||||
- tag
|
||||
- pull_request
|
||||
- push
|
||||
---
|
||||
kind: pipeline
|
||||
name: Documentation
|
||||
|
||||
@@ -198,7 +198,7 @@ X-GNOME-Autostart-Delay=3
|
||||
|
||||
|
||||
# Translations
|
||||
Icon[de_DE]=@APPLICATION_ICON_NAME@
|
||||
Name[de_DE]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
|
||||
Comment[de_DE]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
|
||||
GenericName[de_DE]=Synchronisationsordner
|
||||
Icon[de]=@APPLICATION_ICON_NAME@
|
||||
Name[de]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
|
||||
Comment[de]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
|
||||
GenericName[de]=Synchronisationsordner
|
||||
|
||||
@@ -203,16 +203,8 @@ if( WIN32 )
|
||||
add_definitions( -D__USE_MINGW_ANSI_STDIO=1 )
|
||||
add_definitions( -DNOMINMAX )
|
||||
# Get APIs from from Vista onwards.
|
||||
add_definitions( -D_WIN32_WINNT=0x0601 )
|
||||
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 )
|
||||
add_definitions( -D_WIN32_WINNT=0x0600)
|
||||
add_definitions( -DWINVER=0x0600)
|
||||
endif( WIN32 )
|
||||
|
||||
if (APPLE)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
set( MIRALL_VERSION_MAJOR 2 )
|
||||
set( MIRALL_VERSION_MINOR 6 )
|
||||
set( MIRALL_VERSION_PATCH 1 )
|
||||
set( MIRALL_VERSION_PATCH 0 )
|
||||
set( MIRALL_VERSION_YEAR 2019 )
|
||||
set( MIRALL_SOVERSION 0 )
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ Build-Depends: cmake,
|
||||
cdbs,
|
||||
dh-python,
|
||||
extra-cmake-modules (>= 5.16),
|
||||
kdelibs5-dev,
|
||||
libkf5kio-dev,
|
||||
libcmocka-dev,
|
||||
libhttp-dav-perl,
|
||||
|
||||
@@ -32,12 +32,11 @@ FRAMEWORK_SEARCH_PATH=[
|
||||
os.path.join(os.environ['HOME'], 'Library/Frameworks')
|
||||
]
|
||||
|
||||
LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/Qt-5.12.5/lib', '.']
|
||||
LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/Qt-5.6.2/lib', '.']
|
||||
|
||||
QT_PLUGINS = [
|
||||
'sqldrivers/libqsqlite.dylib',
|
||||
'platforms/libqcocoa.dylib',
|
||||
'styles/libqmacstyle.dylib',
|
||||
'imageformats/libqgif.dylib',
|
||||
'imageformats/libqico.dylib',
|
||||
'imageformats/libqjpeg.dylib',
|
||||
@@ -47,7 +46,7 @@ QT_PLUGINS = [
|
||||
QT_PLUGINS_SEARCH_PATH=[
|
||||
# os.path.join(os.environ['QTDIR'], 'plugins'),
|
||||
# '/usr/local/Cellar/qt/5.2.1/plugins',
|
||||
'/usr/local/Qt-5.12.5/plugins',
|
||||
'/usr/local/Qt-5.6.2/plugins',
|
||||
]
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 254 KiB After Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 9.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 151 KiB |
2
binary
2
binary
Submodule binary updated: 09f12de312...3425fab2c6
@@ -3,11 +3,7 @@
|
||||
# For details see the accompanying COPYING* file.
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
|
||||
# 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()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long -Wno-gnu-zero-variadic-macro-arguments")
|
||||
|
||||
# Fix sqlite compilation on macOS
|
||||
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));
|
||||
if (hDrop) {
|
||||
UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
|
||||
for (UINT i = 0; i < nFiles; ++i) {
|
||||
for (int i = 0; i < nFiles; ++i) {
|
||||
// Get the path of the file.
|
||||
wchar_t buffer[MAX_PATH];
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
// 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.
|
||||
|
||||
// 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
|
||||
|
||||
#define WINVER 0x0501
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#include <SDKDDKVer.h>
|
||||
|
||||
@@ -13,10 +13,8 @@
|
||||
*/
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
// 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
|
||||
#define WINVER 0x0501
|
||||
#define _WIN32_WINNT 0x0501
|
||||
|
||||
#include "CommunicationSocket.h"
|
||||
#include "RegistryUtil.h"
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
// 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
|
||||
#define WINVER 0x0501
|
||||
#define _WIN32_WINNT 0x0501
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
2
src/3rdparty/libcrashreporter-qt
vendored
2
src/3rdparty/libcrashreporter-qt
vendored
Submodule src/3rdparty/libcrashreporter-qt updated: a4409c5c1b...7df66f72aa
2
src/3rdparty/qtmacgoodies
vendored
2
src/3rdparty/qtmacgoodies
vendored
Submodule src/3rdparty/qtmacgoodies updated: b59d091b3e...ebc7ec6f68
@@ -33,8 +33,8 @@ endif()
|
||||
|
||||
if(WIN32)
|
||||
# Enable DEP & ASLR
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /nxcompat /dynamicbase")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /nxcompat /dynamicbase")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--nxcompat -Wl,--dynamicbase")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--nxcompat -Wl,--dynamicbase")
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
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")
|
||||
|
||||
@@ -11,50 +11,43 @@
|
||||
|
||||
// For overloading macros by argument count
|
||||
// See stackoverflow.com/questions/16683146/can-macros-be-overloaded-by-number-of-arguments
|
||||
// Bugfix 08/09/2019: Broken arg expansion led to always collapsing to 1 arg (XXXX_1 overload result)
|
||||
// See also: https://stackoverflow.com/questions/9183993/msvc-variadic-macro-expansion
|
||||
#define OC_ASSERT_GLUE(x, y) x y
|
||||
|
||||
#define OC_ASSERT_CAT(A, B) A##B
|
||||
#define OC_ASSERT_SELECT(NAME, NUM) OC_ASSERT_CAT(NAME##_, NUM)
|
||||
#define OC_ASSERT_GET_COUNT(_1, _2, _3, COUNT, ...) COUNT
|
||||
#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_VA_SIZE(...) OC_ASSERT_GET_COUNT(__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__))
|
||||
#define OC_ASSERT_OVERLOAD(NAME, ...) OC_ASSERT_SELECT(NAME, OC_ASSERT_VA_SIZE(__VA_ARGS__)) \
|
||||
(__VA_ARGS__)
|
||||
|
||||
// Default assert: If the condition is false in debug builds, terminate.
|
||||
//
|
||||
// Prints a message on failure, even in release builds.
|
||||
#define ASSERT1(cond) \
|
||||
#define ASSERT(...) OC_ASSERT_OVERLOAD(ASSERT, __VA_ARGS__)
|
||||
#define ASSERT_1(cond) \
|
||||
if (!(cond)) { \
|
||||
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
||||
} else { \
|
||||
}
|
||||
#define ASSERT2(cond, message) \
|
||||
#define ASSERT_2(cond, message) \
|
||||
if (!(cond)) { \
|
||||
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
||||
} else { \
|
||||
}
|
||||
#define ASSERT(...) OC_ASSERT_OVERLOAD(ASSERT, __VA_ARGS__)
|
||||
|
||||
// Enforce condition to be true, even in release builds.
|
||||
//
|
||||
// Prints 'message' and aborts execution if 'cond' is false.
|
||||
#define ENFORCE1(cond) \
|
||||
#define ENFORCE(...) OC_ASSERT_OVERLOAD(ENFORCE, __VA_ARGS__)
|
||||
#define ENFORCE_1(cond) \
|
||||
if (!(cond)) { \
|
||||
qFatal("ENFORCE: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
||||
} else { \
|
||||
}
|
||||
#define ENFORCE2(cond, message) \
|
||||
#define ENFORCE_2(cond, message) \
|
||||
if (!(cond)) { \
|
||||
qFatal("ENFORCE: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
||||
} else { \
|
||||
}
|
||||
#define ENFORCE(...) OC_ASSERT_OVERLOAD(ENFORCE, __VA_ARGS__)
|
||||
|
||||
// An assert that is only present in debug builds: typically used for
|
||||
// asserts that are too expensive for release mode.
|
||||
|
||||
@@ -207,10 +207,7 @@ static inline uint64_t c_jhash64(const uint8_t *k, uint64_t length, uint64_t int
|
||||
/* handle the last 23 bytes */
|
||||
c += length;
|
||||
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"
|
||||
#endif
|
||||
case 23: c+=((uint64_t)k[22]<<56);
|
||||
case 22: c+=((uint64_t)k[21]<<48);
|
||||
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)
|
||||
{
|
||||
size_t len = strlen(b);
|
||||
return a.size() >= len && qstrnicmp(a.constData(), b, Utility::convertSizeToUint(len)) == 0;
|
||||
int len = strlen(b);
|
||||
return a.size() >= len && qstrnicmp(a.constData(), b, len) == 0;
|
||||
}
|
||||
|
||||
bool SqlQuery::isSelect()
|
||||
|
||||
@@ -103,7 +103,6 @@ public:
|
||||
: _chunk(0)
|
||||
, _transferid(0)
|
||||
, _size(0)
|
||||
, _modtime(0)
|
||||
, _errorCount(0)
|
||||
, _valid(false)
|
||||
{
|
||||
|
||||
@@ -396,26 +396,6 @@ void Utility::crash()
|
||||
*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
|
||||
// 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
|
||||
|
||||
@@ -55,12 +55,6 @@ namespace Utility {
|
||||
OCSYNC_EXPORT QByteArray userAgentString();
|
||||
OCSYNC_EXPORT bool hasLaunchOnStartup(const QString &appName);
|
||||
OCSYNC_EXPORT void setLaunchOnStartup(const QString &appName, const QString &guiName, bool launch);
|
||||
OCSYNC_EXPORT uint convertSizeToUint(size_t &convertVar);
|
||||
OCSYNC_EXPORT uint convertSizeToInt(size_t &convertVar);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
OCSYNC_EXPORT DWORD convertSizeToDWORD(size_t &convertVar);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Return the amount of free space available.
|
||||
|
||||
@@ -90,13 +90,32 @@ 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
|
||||
static inline bool hasDarkSystray_private()
|
||||
{
|
||||
if(Utility::registryGetKeyValue( HKEY_CURRENT_USER,
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||
"SystemUsesLightTheme" ) == 1) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
bool hasDarkSystray = true;
|
||||
// Open registry key first, continue only on success (may be legitimately absent in earlier windows versions)
|
||||
HKEY hKey;
|
||||
LONG lRes = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_READ, &hKey);
|
||||
|
||||
// classical windows function - preserve buff size for DWORD, call ExW version, store regkey value in nResult
|
||||
if (lRes == ERROR_SUCCESS) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,13 +283,4 @@ bool Utility::registryWalkSubKeys(HKEY hRootKey, const QString &subKey, const st
|
||||
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
|
||||
|
||||
@@ -73,7 +73,7 @@ static void csync_exclude_expand_escapes(QByteArray &input)
|
||||
line[o++] = line[i];
|
||||
}
|
||||
}
|
||||
input.resize(OCC::Utility::convertSizeToUint(o));
|
||||
input.resize(o);
|
||||
}
|
||||
|
||||
// See http://support.microsoft.com/kb/74496 and
|
||||
@@ -322,11 +322,7 @@ bool ExcludedFiles::loadExcludeFile(const QByteArray & basePath, const QString &
|
||||
csync_exclude_expand_escapes(line);
|
||||
_allExcludes[basePath].append(line);
|
||||
}
|
||||
|
||||
// nothing to prepare if the user decided to not exclude anything
|
||||
if(_allExcludes.size())
|
||||
prepare(basePath);
|
||||
|
||||
prepare(basePath);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -342,8 +338,8 @@ bool ExcludedFiles::reloadExcludeFiles()
|
||||
_fullRegexDir.clear();
|
||||
|
||||
bool success = true;
|
||||
for (const auto& basePath : _excludeFiles.keys()) {
|
||||
for (const auto& file : _excludeFiles.value(basePath)) {
|
||||
for (auto basePath : _excludeFiles.keys()) {
|
||||
for (auto file : _excludeFiles.value(basePath)) {
|
||||
success = loadExcludeFile(basePath, file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -724,8 +724,7 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||
if (ctx->current == LOCAL_REPLICA) {
|
||||
ASSERT(dirent->path.startsWith(ctx->local.uri)); // path is relative to uri
|
||||
// "len + 1" to include the slash in-between.
|
||||
size_t uriLength = strlen(ctx->local.uri);
|
||||
dirent->path = dirent->path.mid(OCC::Utility::convertSizeToInt(uriLength) + 1);
|
||||
dirent->path = dirent->path.mid(strlen(ctx->local.uri) + 1);
|
||||
}
|
||||
|
||||
previous_fs = ctx->current_fs;
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
#include "c_alloc.h"
|
||||
#include "c_string.h"
|
||||
#include "common/filesystembase.h"
|
||||
#include "common/utility.h"
|
||||
|
||||
/* Convert a locale String to UTF8 */
|
||||
QByteArray c_utf8_from_locale(const mbchar_t *wstr)
|
||||
@@ -53,10 +52,10 @@ QByteArray c_utf8_from_locale(const mbchar_t *wstr)
|
||||
size_t len;
|
||||
len = wcslen(wstr);
|
||||
/* Call once to get the required size. */
|
||||
size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, OCC::Utility::convertSizeToInt(len), NULL, 0, NULL, NULL);
|
||||
size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, len, NULL, 0, NULL, NULL);
|
||||
if (size_needed > 0) {
|
||||
dst.resize(size_needed);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr, OCC::Utility::convertSizeToInt(len), dst.data(), size_needed, NULL, NULL);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr, len, dst.data(), size_needed, NULL, NULL);
|
||||
}
|
||||
return dst;
|
||||
#else
|
||||
@@ -96,7 +95,7 @@ mbchar_t* c_utf8_string_to_locale(const char *str)
|
||||
int size_needed;
|
||||
|
||||
len = strlen(str);
|
||||
size_needed = MultiByteToWideChar(CP_UTF8, 0, str, OCC::Utility::convertSizeToInt(len), NULL, 0);
|
||||
size_needed = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
|
||||
if (size_needed > 0) {
|
||||
int size_char = (size_needed + 1) * sizeof(mbchar_t);
|
||||
dst = (mbchar_t*)c_malloc(size_char);
|
||||
@@ -115,8 +114,7 @@ mbchar_t* c_utf8_string_to_locale(const char *str)
|
||||
return NULL;
|
||||
} else {
|
||||
#ifdef _WIN32
|
||||
size_t strLength = strlen(str);
|
||||
QByteArray unc_str = OCC::FileSystem::pathtoUNC(QByteArray::fromRawData(str, OCC::Utility::convertSizeToInt(strLength)));
|
||||
QByteArray unc_str = OCC::FileSystem::pathtoUNC(QByteArray::fromRawData(str, strlen(str)));
|
||||
mbchar_t *dst = c_utf8_string_to_locale(unc_str);
|
||||
return dst;
|
||||
#else
|
||||
|
||||
@@ -57,7 +57,7 @@ csync_vio_handle_t *csync_vio_local_opendir(const char *name) {
|
||||
handle = (dhandle_t*)c_malloc(sizeof(dhandle_t));
|
||||
|
||||
// the file wildcard has to be attached
|
||||
size_t len_name = strlen(name);
|
||||
int len_name = strlen(name);
|
||||
if( len_name ) {
|
||||
char *h = NULL;
|
||||
|
||||
|
||||
@@ -104,7 +104,6 @@ set(client_SRCS
|
||||
guiutility.cpp
|
||||
elidedlabel.cpp
|
||||
iconjob.cpp
|
||||
remotewipe.cpp
|
||||
creds/credentialsfactory.cpp
|
||||
creds/httpcredentialsgui.cpp
|
||||
creds/oauth.cpp
|
||||
@@ -182,9 +181,6 @@ if (APPLE)
|
||||
../3rdparty/qtmacgoodies/src/macstandardicon.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()
|
||||
|
||||
if(NOT WIN32)
|
||||
|
||||
@@ -368,7 +368,6 @@ void AccountManager::shutdown()
|
||||
_accounts.clear();
|
||||
foreach (const auto &acc, accountsCopy) {
|
||||
emit accountRemoved(acc.data());
|
||||
emit removeAccountFolders(acc.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ public:
|
||||
*/
|
||||
void deleteAccount(AccountState *account);
|
||||
|
||||
|
||||
/**
|
||||
* Creates an account and sets up some basic handlers.
|
||||
* Does *not* add the account to the account manager just yet.
|
||||
@@ -103,7 +104,6 @@ public slots:
|
||||
Q_SIGNALS:
|
||||
void accountAdded(AccountState *account);
|
||||
void accountRemoved(AccountState *account);
|
||||
void removeAccountFolders(AccountState *account);
|
||||
|
||||
private:
|
||||
AccountManager() {}
|
||||
|
||||
@@ -147,8 +147,6 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
|
||||
createAccountToolbox();
|
||||
connect(AccountManager::instance(), &AccountManager::accountAdded,
|
||||
this, &AccountSettings::slotAccountAdded);
|
||||
connect(this, &AccountSettings::removeAccountFolders,
|
||||
AccountManager::instance(), &AccountManager::removeAccountFolders);
|
||||
connect(ui->_folderList, &QWidget::customContextMenuRequested,
|
||||
this, &AccountSettings::slotCustomContextMenuRequested);
|
||||
connect(ui->_folderList, &QAbstractItemView::clicked,
|
||||
@@ -336,9 +334,9 @@ void AccountSettings::slotEncryptionFlagError(const QByteArray& fileId, int http
|
||||
|
||||
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();
|
||||
if (encryptedMetadata.isEmpty()) {
|
||||
//TODO: Mark the folder as unencrypted as the metadata generation failed.
|
||||
@@ -350,36 +348,36 @@ void AccountSettings::slotLockForEncryptionSuccess(const QByteArray& fileId, con
|
||||
return;
|
||||
}
|
||||
auto storeMetadataJob = new StoreMetaDataApiJob(accountsState()->account(), fileId, emptyMetadata.encryptedMetadata());
|
||||
connect(storeMetadataJob, &StoreMetaDataApiJob::success,
|
||||
this, &AccountSettings::slotUploadMetadataSuccess);
|
||||
connect(storeMetadataJob, &StoreMetaDataApiJob::error,
|
||||
this, &AccountSettings::slotUpdateMetadataError);
|
||||
connect(storeMetadataJob, &StoreMetaDataApiJob::success,
|
||||
this, &AccountSettings::slotUploadMetadataSuccess);
|
||||
connect(storeMetadataJob, &StoreMetaDataApiJob::error,
|
||||
this, &AccountSettings::slotUpdateMetadataError);
|
||||
|
||||
storeMetadataJob->start();
|
||||
storeMetadataJob->start();
|
||||
}
|
||||
|
||||
void AccountSettings::slotUploadMetadataSuccess(const QByteArray& folderId)
|
||||
{
|
||||
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
|
||||
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
|
||||
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
|
||||
this, &AccountSettings::slotUnlockFolderSuccess);
|
||||
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
|
||||
this, &AccountSettings::slotUnlockFolderError);
|
||||
unlockJob->start();
|
||||
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
|
||||
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
|
||||
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
|
||||
this, &AccountSettings::slotUnlockFolderSuccess);
|
||||
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
|
||||
this, &AccountSettings::slotUnlockFolderError);
|
||||
unlockJob->start();
|
||||
}
|
||||
|
||||
void AccountSettings::slotUpdateMetadataError(const QByteArray& folderId, int httpReturnCode)
|
||||
{
|
||||
Q_UNUSED(httpReturnCode);
|
||||
|
||||
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
|
||||
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
|
||||
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
|
||||
this, &AccountSettings::slotUnlockFolderSuccess);
|
||||
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
|
||||
this, &AccountSettings::slotUnlockFolderError);
|
||||
unlockJob->start();
|
||||
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
|
||||
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
|
||||
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
|
||||
this, &AccountSettings::slotUnlockFolderSuccess);
|
||||
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
|
||||
this, &AccountSettings::slotUnlockFolderError);
|
||||
unlockJob->start();
|
||||
}
|
||||
|
||||
void AccountSettings::slotLockForEncryptionError(const QByteArray& fileId, int httpErrorCode)
|
||||
|
||||
@@ -63,7 +63,6 @@ signals:
|
||||
void openFolderAlias(const QString &);
|
||||
void showIssuesList(AccountState *account);
|
||||
void requesetMnemonic();
|
||||
void removeAccountFolders(AccountState *account);
|
||||
|
||||
public slots:
|
||||
void slotOpenOC();
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
<item row="0" column="2">
|
||||
<widget class="QToolButton" name="_accountToolbox">
|
||||
<property name="text">
|
||||
<string notr="true">...</string>
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
#include "accountstate.h"
|
||||
#include "accountmanager.h"
|
||||
#include "remotewipe.h"
|
||||
#include "account.h"
|
||||
#include "creds/abstractcredentials.h"
|
||||
#include "creds/httpcredentials.h"
|
||||
@@ -25,11 +24,6 @@
|
||||
#include <QTimer>
|
||||
#include <qfontmetrics.h>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkRequest>
|
||||
#include <QBuffer>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
Q_LOGGING_CATEGORY(lcAccountState, "nextcloud.gui.account.state", QtInfoMsg)
|
||||
@@ -42,12 +36,11 @@ AccountState::AccountState(AccountPtr account)
|
||||
, _waitingForNewCredentials(false)
|
||||
, _notificationsEtagResponseHeader("*")
|
||||
, _maintenanceToConnectedDelay(60000 + (qrand() % (4 * 60000))) // 1-5min delay
|
||||
, _remoteWipe(new RemoteWipe(_account))
|
||||
{
|
||||
qRegisterMetaType<AccountState *>("AccountState*");
|
||||
|
||||
connect(account.data(), &Account::invalidCredentials,
|
||||
this, &AccountState::slotHandleRemoteWipeCheck);
|
||||
this, &AccountState::slotInvalidCredentials);
|
||||
connect(account.data(), &Account::credentialsFetched,
|
||||
this, &AccountState::slotCredentialsFetched);
|
||||
connect(account.data(), &Account::credentialsAsked,
|
||||
@@ -310,7 +303,7 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
|
||||
break;
|
||||
case ConnectionValidator::CredentialsWrong:
|
||||
case ConnectionValidator::CredentialsNotReady:
|
||||
handleInvalidCredentials();
|
||||
slotInvalidCredentials();
|
||||
break;
|
||||
case ConnectionValidator::SslError:
|
||||
setState(SignedOut);
|
||||
@@ -329,20 +322,7 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
void AccountState::slotInvalidCredentials()
|
||||
{
|
||||
if (isSignedOut() || _waitingForNewCredentials)
|
||||
return;
|
||||
@@ -363,7 +343,6 @@ void AccountState::handleInvalidCredentials()
|
||||
account()->credentials()->askFromUser();
|
||||
}
|
||||
|
||||
|
||||
void AccountState::slotCredentialsFetched(AbstractCredentials *)
|
||||
{
|
||||
// Make a connection attempt, no matter whether the credentials are
|
||||
|
||||
@@ -29,7 +29,6 @@ namespace OCC {
|
||||
|
||||
class AccountState;
|
||||
class Account;
|
||||
class RemoteWipe;
|
||||
|
||||
typedef QExplicitlySharedDataPointer<AccountState> AccountStatePtr;
|
||||
|
||||
@@ -151,9 +150,6 @@ public:
|
||||
*/
|
||||
void setNavigationAppsEtagResponseHeader(const QByteArray &value);
|
||||
|
||||
///Asks for user credentials
|
||||
void handleInvalidCredentials();
|
||||
|
||||
public slots:
|
||||
/// Triggers a ping to the server to update state and
|
||||
/// connection status and errors.
|
||||
@@ -168,11 +164,7 @@ signals:
|
||||
|
||||
protected Q_SLOTS:
|
||||
void slotConnectionValidatorResult(ConnectionValidator::Status status, const QStringList &errors);
|
||||
|
||||
/// When client gets a 401 or 403 checks if server requested remote wipe
|
||||
/// before asking for user credentials again
|
||||
void slotHandleRemoteWipeCheck();
|
||||
|
||||
void slotInvalidCredentials();
|
||||
void slotCredentialsFetched(AbstractCredentials *creds);
|
||||
void slotCredentialsAsked(AbstractCredentials *creds);
|
||||
|
||||
@@ -198,13 +190,6 @@ private:
|
||||
* Milliseconds for which to delay reconnection after 503/maintenance.
|
||||
*/
|
||||
int _maintenanceToConnectedDelay;
|
||||
|
||||
/**
|
||||
* Connects remote wipe check with the account
|
||||
* the log out triggers the check (loads app password -> create request)
|
||||
*/
|
||||
RemoteWipe *_remoteWipe;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
#include <QPainter>
|
||||
#include <QApplication>
|
||||
|
||||
#define HASQT5_11 (QT_VERSION >= QT_VERSION_CHECK(5,11,0))
|
||||
|
||||
namespace OCC {
|
||||
|
||||
int ActivityItemDelegate::_iconHeight = 0;
|
||||
@@ -108,11 +106,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
||||
|
||||
// subject text rect
|
||||
QRect actionTextBox = actionIconRect;
|
||||
#if (HASQT5_11)
|
||||
int actionTextBoxWidth = fm.horizontalAdvance(actionText);
|
||||
#else
|
||||
int actionTextBoxWidth = fm.width(actionText);
|
||||
#endif
|
||||
actionTextBox.setTop(option.rect.top() + margin + offset/2);
|
||||
actionTextBox.setHeight(fm.height());
|
||||
actionTextBox.setLeft(actionIconRect.right() + margin);
|
||||
@@ -120,11 +114,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
||||
|
||||
// message text rect
|
||||
QRect messageTextBox = actionTextBox;
|
||||
#if (HASQT5_11)
|
||||
int messageTextWidth = fm.horizontalAdvance(messageText);
|
||||
#else
|
||||
int messageTextWidth = fm.width(messageText);
|
||||
#endif
|
||||
int messageTextTop = option.rect.top() + fm.height() + margin;
|
||||
if(actionText.isEmpty()) messageTextTop = option.rect.top() + margin + offset/2;
|
||||
messageTextBox.setTop(messageTextTop);
|
||||
@@ -139,11 +129,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
||||
// time box rect
|
||||
QRect timeBox = messageTextBox;
|
||||
QString timeStr = tr("%1").arg(timeText);
|
||||
#if (HASQT5_11)
|
||||
int timeTextWidth = fm.horizontalAdvance(timeStr);
|
||||
#else
|
||||
int timeTextWidth = fm.width(timeStr);
|
||||
#endif
|
||||
int timeTop = option.rect.top() + fm.height() + fm.height() + margin + offset/2;
|
||||
if(messageText.isEmpty() || actionText.isEmpty())
|
||||
timeTop = option.rect.top() + fm.height() + margin;
|
||||
@@ -194,11 +180,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
||||
if(objectType == _remote_share) primaryButton.text = tr("Accept");
|
||||
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));
|
||||
#endif
|
||||
|
||||
// save info to be able to filter mouse clicks
|
||||
_buttonHeight = buttonSize;
|
||||
@@ -214,12 +196,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
||||
|
||||
// Primary button will be '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));
|
||||
#endif
|
||||
|
||||
// save info to be able to filter mouse clicks
|
||||
_buttonHeight = buttonSize;
|
||||
|
||||
@@ -108,7 +108,6 @@ Application::Application(int &argc, char **argv)
|
||||
, _userTriggeredConnect(false)
|
||||
, _debugMode(false)
|
||||
, _backgroundMode(false)
|
||||
, _isQuitting(false)
|
||||
{
|
||||
_startedAt.start();
|
||||
|
||||
@@ -265,8 +264,6 @@ Application::~Application()
|
||||
}
|
||||
|
||||
// Remove the account from the account manager so it can be deleted.
|
||||
disconnect(AccountManager::instance(), &AccountManager::accountRemoved,
|
||||
this, &Application::slotAccountStateRemoved);
|
||||
AccountManager::instance()->shutdown();
|
||||
}
|
||||
|
||||
@@ -286,7 +283,7 @@ void Application::slotAccountStateRemoved(AccountState *accountState)
|
||||
}
|
||||
|
||||
// if there is no more account, show the wizard.
|
||||
if (!_isQuitting && AccountManager::instance()->accounts().isEmpty()) {
|
||||
if (AccountManager::instance()->accounts().isEmpty()) {
|
||||
// allow to add a new account if there is non any more. Always think
|
||||
// about single account theming!
|
||||
OwncloudSetupWizard::runWizard(this, SLOT(slotownCloudWizardDone(int)));
|
||||
@@ -309,8 +306,6 @@ void Application::slotAccountStateAdded(AccountState *accountState)
|
||||
|
||||
void Application::slotCleanup()
|
||||
{
|
||||
_isQuitting = true;
|
||||
|
||||
AccountManager::instance()->save();
|
||||
FolderMan::instance()->unloadAndDeleteAllFolders();
|
||||
|
||||
|
||||
@@ -114,7 +114,6 @@ private:
|
||||
bool _userTriggeredConnect;
|
||||
bool _debugMode;
|
||||
bool _backgroundMode;
|
||||
bool _isQuitting;
|
||||
|
||||
ClientProxy _proxy;
|
||||
|
||||
|
||||
@@ -52,11 +52,7 @@ void Flow2Auth::openBrowser()
|
||||
// Step 1: Initiate a login, do an anonymous POST request
|
||||
QUrl url = Utility::concatUrlPath(_account->url().toString(), QLatin1String("/index.php/login/v2"));
|
||||
|
||||
// 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);
|
||||
auto job = _account->sendRequest("POST", url);
|
||||
job->setTimeout(qMin(30 * 1000ll, job->timeoutMsec()));
|
||||
|
||||
QObject::connect(job, &SimpleNetworkJob::finishedSignal, this, [this](QNetworkReply *reply) {
|
||||
|
||||
@@ -358,8 +358,6 @@ void WebFlowCredentials::forgetSensitiveData() {
|
||||
|
||||
fetchUser();
|
||||
|
||||
_account->deleteAppPassword();
|
||||
|
||||
const QString kck = keychainKey(_account->url().toString(), _user, _account->id());
|
||||
if (kck.isEmpty()) {
|
||||
qCDebug(lcWebFlowCredentials()) << "InvalidateToken: User is empty, bailing out!";
|
||||
@@ -374,7 +372,7 @@ void WebFlowCredentials::forgetSensitiveData() {
|
||||
invalidateToken();
|
||||
|
||||
/* 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.
|
||||
*
|
||||
@@ -418,9 +416,6 @@ void WebFlowCredentials::slotFinished(QNetworkReply *reply) {
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
_credentialsValid = true;
|
||||
|
||||
/// Used later for remote wipe
|
||||
_account->setAppPassword(_password);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,7 +539,7 @@ void WebFlowCredentials::slotReadClientCaCertsPEMJobDone(QKeychain::Job *incomin
|
||||
return;
|
||||
} else {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,13 +417,6 @@ 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);
|
||||
}
|
||||
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()) {
|
||||
@@ -902,19 +895,13 @@ void Folder::slotItemCompleted(const SyncFileItemPtr &item)
|
||||
}
|
||||
|
||||
// add new directories or remove gone away dirs to the watcher
|
||||
if (_folderWatcher && item->isDirectory()) {
|
||||
switch (item->_instruction) {
|
||||
case CSYNC_INSTRUCTION_NEW:
|
||||
_folderWatcher->addPath(path() + item->_file);
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_REMOVE:
|
||||
_folderWatcher->removePath(path() + item->_file);
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_RENAME:
|
||||
_folderWatcher->removePath(path() + item->_file);
|
||||
_folderWatcher->addPath(path() + item->destination());
|
||||
break;
|
||||
}
|
||||
if (item->isDirectory() && item->_instruction == CSYNC_INSTRUCTION_NEW) {
|
||||
if (_folderWatcher)
|
||||
_folderWatcher->addPath(path() + item->_file);
|
||||
}
|
||||
if (item->isDirectory() && item->_instruction == CSYNC_INSTRUCTION_REMOVE) {
|
||||
if (_folderWatcher)
|
||||
_folderWatcher->removePath(path() + item->_file);
|
||||
}
|
||||
|
||||
// Success and failure of sync items adjust what the next sync is
|
||||
@@ -1085,7 +1072,7 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction dir, bool *cancel
|
||||
if (!cfgFile.promptDeleteFiles())
|
||||
return;
|
||||
|
||||
QString msg = dir == SyncFileItem::Down ? tr("All files in the sync folder '%1' were deleted on the server.\n"
|
||||
QString msg = dir == SyncFileItem::Down ? tr("All files in the sync folder '%1' folder were deleted on the server.\n"
|
||||
"These deletes will be synchronized to your local sync folder, making such files "
|
||||
"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"
|
||||
|
||||
@@ -75,7 +75,7 @@ FolderMan::FolderMan(QObject *parent)
|
||||
this, &FolderMan::slotScheduleFolderByTime);
|
||||
_timeScheduler.start();
|
||||
|
||||
connect(AccountManager::instance(), &AccountManager::removeAccountFolders,
|
||||
connect(AccountManager::instance(), &AccountManager::accountRemoved,
|
||||
this, &FolderMan::slotRemoveFoldersForAccount);
|
||||
|
||||
connect(_lockWatcher.data(), &LockWatcher::fileUnlocked,
|
||||
@@ -443,7 +443,7 @@ void FolderMan::slotFolderSyncPaused(Folder *f, bool paused)
|
||||
void FolderMan::slotFolderCanSyncChanged()
|
||||
{
|
||||
Folder *f = qobject_cast<Folder *>(sender());
|
||||
ASSERT(f);
|
||||
ASSERT(f);
|
||||
if (f->canSync()) {
|
||||
_socketApi->slotRegisterPath(f->alias());
|
||||
} else {
|
||||
@@ -562,7 +562,7 @@ void FolderMan::slotEtagJobDestroyed(QObject * /*o*/)
|
||||
void FolderMan::slotRunOneEtagJob()
|
||||
{
|
||||
if (_currentEtagJob.isNull()) {
|
||||
Folder *folder = nullptr;
|
||||
Folder *folder;
|
||||
foreach (Folder *f, _folderMap) {
|
||||
if (f->etagJob()) {
|
||||
// Caveat: always grabs the first folder with a job, but we think this is Ok for now and avoids us having a seperate queue.
|
||||
@@ -1084,73 +1084,6 @@ bool FolderMan::startFromScratch(const QString &localFolder)
|
||||
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()
|
||||
{
|
||||
foreach (Folder *f, _folderMap.values()) {
|
||||
|
||||
@@ -207,11 +207,6 @@ signals:
|
||||
*/
|
||||
void folderListChanged(const Folder::Map &);
|
||||
|
||||
/**
|
||||
* Emitted once slotRemoveFoldersForAccount is done wiping
|
||||
*/
|
||||
void wipeDone(AccountState *account, bool success);
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
@@ -236,9 +231,6 @@ public slots:
|
||||
// slot to schedule an ETag job (from Folder only)
|
||||
void slotScheduleETagJob(const QString &alias, RequestEtagJob *job);
|
||||
|
||||
/** Wipe folder */
|
||||
void slotWipeFolderForAccount(AccountState *accountState);
|
||||
|
||||
private slots:
|
||||
void slotFolderSyncPaused(Folder *, bool paused);
|
||||
void slotFolderCanSyncChanged();
|
||||
|
||||
@@ -168,7 +168,6 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
||||
QString itemString = qvariant_cast<QString>(index.data(SyncProgressItemString));
|
||||
int warningCount = qvariant_cast<int>(index.data(WarningCount));
|
||||
bool syncOngoing = qvariant_cast<bool>(index.data(SyncRunning));
|
||||
QDateTime syncDate = qvariant_cast<QDateTime>(index.data(SyncDate));
|
||||
bool syncEnabled = qvariant_cast<bool>(index.data(FolderAccountConnected));
|
||||
|
||||
QRect iconRect = option.rect;
|
||||
@@ -253,7 +252,7 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
||||
if (!showProgess) {
|
||||
painter->setFont(subFont);
|
||||
QString elidedRemotePathText = subFm.elidedText(
|
||||
tr("Synchronized with local folder (%1)").arg(syncDate.toTimeSpec(Qt::LocalTime).toString(Qt::SystemLocaleShortDate)),
|
||||
tr("Synchronized with local folder"),
|
||||
Qt::ElideRight, remotePathRect.width());
|
||||
painter->drawText(QStyle::visualRect(option.direction, option.rect, remotePathRect),
|
||||
textAlign, elidedRemotePathText);
|
||||
|
||||
@@ -44,7 +44,6 @@ public:
|
||||
SyncProgressItemString,
|
||||
WarningCount,
|
||||
SyncRunning,
|
||||
SyncDate,
|
||||
|
||||
AddButton // 1 = enabled; 2 = disabled
|
||||
};
|
||||
|
||||
@@ -218,8 +218,6 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
|
||||
return f->syncResult().errorStrings();
|
||||
case FolderStatusDelegate::SyncRunning:
|
||||
return f->syncResult().status() == SyncResult::SyncRunning;
|
||||
case FolderStatusDelegate::SyncDate:
|
||||
return f->syncResult().syncTime();
|
||||
case FolderStatusDelegate::HeaderRole:
|
||||
return f->shortGuiRemotePathOrAppName();
|
||||
case FolderStatusDelegate::FolderAliasRole:
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
#include "folderwatcher.h"
|
||||
#include "folderwatcher_win.h"
|
||||
|
||||
#include "common/utility.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
@@ -54,7 +52,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
||||
|
||||
// QVarLengthArray ensures the stack-buffer is aligned like double and qint64.
|
||||
QVarLengthArray<char, 4096 * 10> fileNotifyBuffer;
|
||||
fileNotifyBuffer.resize(OCC::Utility::convertSizeToInt(fileNotifyBufferSize));
|
||||
fileNotifyBuffer.resize(fileNotifyBufferSize);
|
||||
|
||||
const size_t fileNameBufferSize = 4096;
|
||||
TCHAR fileNameBuffer[fileNameBufferSize];
|
||||
@@ -68,7 +66,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
||||
DWORD dwBytesReturned = 0;
|
||||
SecureZeroMemory(pFileNotifyBuffer, fileNotifyBufferSize);
|
||||
if (!ReadDirectoryChangesW(_directory, (LPVOID)pFileNotifyBuffer,
|
||||
OCC::Utility::convertSizeToDWORD(fileNotifyBufferSize), true,
|
||||
fileNotifyBufferSize, true,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
|
||||
&dwBytesReturned,
|
||||
&overlapped,
|
||||
@@ -115,7 +113,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
||||
FILE_NOTIFY_INFORMATION *curEntry = pFileNotifyBuffer;
|
||||
forever {
|
||||
size_t len = curEntry->FileNameLength / 2;
|
||||
QString file = _path + "\\" + QString::fromWCharArray(curEntry->FileName, OCC::Utility::convertSizeToInt(len));
|
||||
QString file = _path + "\\" + QString::fromWCharArray(curEntry->FileName, len);
|
||||
|
||||
// Unless the file was removed or renamed, get its full long name
|
||||
// TODO: We could still try expanding the path in the tricky cases...
|
||||
@@ -124,7 +122,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
||||
&& curEntry->Action != FILE_ACTION_RENAMED_OLD_NAME) {
|
||||
size_t longNameSize = GetLongPathNameW(reinterpret_cast<LPCWSTR>(file.utf16()), fileNameBuffer, fileNameBufferSize);
|
||||
if (longNameSize > 0) {
|
||||
longfile = QString::fromUtf16(reinterpret_cast<const ushort *>(fileNameBuffer), OCC::Utility::convertSizeToInt(longNameSize));
|
||||
longfile = QString::fromUtf16(reinterpret_cast<const ushort *>(fileNameBuffer), longNameSize);
|
||||
} else {
|
||||
qCWarning(lcFolderWatcher) << "Error converting file name to full length, keeping original name.";
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">TextLabel</string>
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "updater/updater.h"
|
||||
#include "updater/ocupdater.h"
|
||||
#include "ignorelisteditor.h"
|
||||
#include "common/utility.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@@ -36,12 +35,6 @@
|
||||
#include <QDir>
|
||||
#include <QScopedValueRollback>
|
||||
|
||||
#define QTLEGACY (QT_VERSION < QT_VERSION_CHECK(5,9,0))
|
||||
|
||||
#if !(QTLEGACY)
|
||||
#include <QOperatingSystemVersion>
|
||||
#endif
|
||||
|
||||
namespace OCC {
|
||||
|
||||
GeneralSettings::GeneralSettings(QWidget *parent)
|
||||
@@ -86,13 +79,9 @@ GeneralSettings::GeneralSettings(QWidget *parent)
|
||||
// Hide on non-Windows, or WindowsVersion < 10.
|
||||
// The condition should match the default value of ConfigFile::showInExplorerNavigationPane.
|
||||
#ifdef Q_OS_WIN
|
||||
#if QTLEGACY
|
||||
if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS10)
|
||||
#else
|
||||
if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows10)
|
||||
#endif
|
||||
_ui->showInExplorerNavigationPaneCheckBox->setVisible(false);
|
||||
if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS10)
|
||||
#endif
|
||||
_ui->showInExplorerNavigationPaneCheckBox->setVisible(false);
|
||||
|
||||
/* Set the left contents margin of the layout to zero to make the checkboxes
|
||||
* align properly vertically , fixes bug #3758
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">IgnoreListTableWidget</string>
|
||||
<string>IgnoreListTableWidget</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0" rowspan="4">
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Label</string>
|
||||
<string>Label</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>563</width>
|
||||
<height>444</height>
|
||||
<width>542</width>
|
||||
<height>396</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -228,7 +228,7 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999999</number>
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>80</number>
|
||||
@@ -307,7 +307,7 @@
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999999</number>
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
|
||||
@@ -22,12 +22,6 @@
|
||||
#include <QDesktopServices>
|
||||
#include <QApplication>
|
||||
|
||||
#define QTLEGACY (QT_VERSION < QT_VERSION_CHECK(5,9,0))
|
||||
|
||||
#if !(QTLEGACY)
|
||||
#include <QOperatingSystemVersion>
|
||||
#endif
|
||||
|
||||
namespace OCC {
|
||||
|
||||
// according to the QStandardDir impl from Qt5
|
||||
@@ -95,14 +89,10 @@ void showInFileManager(const QString &localPath)
|
||||
{
|
||||
if (Utility::isWindows()) {
|
||||
#ifdef Q_OS_WIN
|
||||
#if QTLEGACY
|
||||
if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS10)
|
||||
#else
|
||||
if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows7)
|
||||
#endif
|
||||
return;
|
||||
if (QSysInfo::windowsVersion() <= QSysInfo::WV_2003) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
QString explorer = "explorer.exe "; // FIXME: we trust it's in PATH
|
||||
QFileInfo fi(localPath);
|
||||
|
||||
|
||||
@@ -675,12 +675,6 @@ void ownCloudGui::updateContextMenu()
|
||||
|
||||
_contextMenu->addSeparator();
|
||||
|
||||
if (_navLinksMenu) {
|
||||
_contextMenu->addMenu(_navLinksMenu);
|
||||
}
|
||||
|
||||
_contextMenu->addSeparator();
|
||||
|
||||
if (accountList.isEmpty()) {
|
||||
_contextMenu->addAction(_actionNewAccountWizard);
|
||||
}
|
||||
@@ -694,7 +688,6 @@ void ownCloudGui::updateContextMenu()
|
||||
}
|
||||
|
||||
_contextMenu->addSeparator();
|
||||
|
||||
if (atLeastOnePaused) {
|
||||
QString text;
|
||||
if (accountList.count() > 1) {
|
||||
@@ -784,8 +777,6 @@ void ownCloudGui::setupActions()
|
||||
{
|
||||
_actionStatus = new QAction(tr("Unknown status"), this);
|
||||
_actionStatus->setEnabled(false);
|
||||
_navLinksMenu = new QMenu(tr("Apps"));
|
||||
_navLinksMenu->setEnabled(false);
|
||||
_actionSettings = new QAction(tr("Settings..."), this);
|
||||
_actionNewAccountWizard = new QAction(tr("New account..."), this);
|
||||
_actionRecent = new QAction(tr("View more activity..."), this);
|
||||
@@ -827,11 +818,8 @@ void ownCloudGui::fetchNavigationApps(AccountStatePtr account){
|
||||
|
||||
void ownCloudGui::buildNavigationAppsMenu(AccountStatePtr account, QMenu *accountMenu){
|
||||
auto navLinks = _navApps.value(account);
|
||||
|
||||
_navLinksMenu->clear();
|
||||
_navLinksMenu->setEnabled(navLinks.size() > 0);
|
||||
|
||||
if(navLinks.size() > 0){
|
||||
|
||||
// when there is only one account add the nav links above the settings
|
||||
QAction *actionBefore = _actionSettings;
|
||||
|
||||
@@ -850,13 +838,17 @@ void ownCloudGui::buildNavigationAppsMenu(AccountStatePtr account, QMenu *accoun
|
||||
}
|
||||
|
||||
// Create submenu with links
|
||||
QMenu *navLinksMenu = new QMenu(tr("Apps"));
|
||||
accountMenu->insertSeparator(actionBefore);
|
||||
accountMenu->insertMenu(actionBefore, navLinksMenu);
|
||||
foreach (const QJsonValue &value, navLinks) {
|
||||
auto navLink = value.toObject();
|
||||
QAction *action = new QAction(navLink.value("name").toString(), this);
|
||||
QUrl href(navLink.value("href").toString());
|
||||
connect(action, &QAction::triggered, this, [href] { QDesktopServices::openUrl(href); });
|
||||
_navLinksMenu->addAction(action);
|
||||
navLinksMenu->addAction(action);
|
||||
}
|
||||
accountMenu->insertSeparator(actionBefore);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -168,7 +168,6 @@ private:
|
||||
QAction *_actionQuit;
|
||||
QAction *_actionCrash;
|
||||
|
||||
QMenu *_navLinksMenu;
|
||||
QMap<AccountStatePtr, QJsonArray> _navApps;
|
||||
|
||||
QList<QAction *> _recentItemsActions;
|
||||
|
||||
@@ -466,41 +466,7 @@ void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString &localFo
|
||||
_ocWizard->appendToConfigurationLog(res);
|
||||
}
|
||||
if (nextStep) {
|
||||
/*
|
||||
* BEGIN - Sanitize URL paths to eliminate double-slashes
|
||||
*
|
||||
* Purpose: Don't rely on unsafe paths, be extra careful.
|
||||
*
|
||||
* Example: https://cloud.example.com/remote.php/webdav//
|
||||
*
|
||||
*/
|
||||
qCInfo(lcWizard) << "Sanitize got URL path:" << QString(_ocWizard->account()->url().toString() + '/' + _ocWizard->account()->davPath() + remoteFolder);
|
||||
|
||||
QString newDavPath = _ocWizard->account()->davPath(),
|
||||
newRemoteFolder = remoteFolder;
|
||||
|
||||
while (newDavPath.startsWith('/')) {
|
||||
newDavPath.remove(0, 1);
|
||||
}
|
||||
while (newDavPath.endsWith('/')) {
|
||||
newDavPath.chop(1);
|
||||
}
|
||||
|
||||
while (newRemoteFolder.startsWith('/')) {
|
||||
newRemoteFolder.remove(0, 1);
|
||||
}
|
||||
while (newRemoteFolder.endsWith('/')) {
|
||||
newRemoteFolder.chop(1);
|
||||
}
|
||||
|
||||
QString newUrlPath = newDavPath + '/' + newRemoteFolder;
|
||||
|
||||
qCInfo(lcWizard) << "Sanitized to URL path:" << _ocWizard->account()->url().toString() + '/' + newUrlPath;
|
||||
/*
|
||||
* END - Sanitize URL paths to eliminate double-slashes
|
||||
*/
|
||||
|
||||
EntityExistsJob *job = new EntityExistsJob(_ocWizard->account(), newUrlPath, this);
|
||||
EntityExistsJob *job = new EntityExistsJob(_ocWizard->account(), _ocWizard->account()->davPath() + remoteFolder, this);
|
||||
connect(job, &EntityExistsJob::exists, this, &OwncloudSetupWizard::slotRemoteFolderExists);
|
||||
job->start();
|
||||
} else {
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="proxyAddress">
|
||||
<property name="text">
|
||||
<string notr="true">TextLabel</string>
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::PlainText</enum>
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#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 QToolButton:checked { background: %3; color: %4; }";
|
||||
|
||||
static const float buttonSizeRatio = 1.618f; // golden ratio
|
||||
static const float buttonSizeRatio = 1.618; // golden ratio
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">share label</string>
|
||||
<string>share label</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::PlainText</enum>
|
||||
@@ -120,7 +120,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Icon</string>
|
||||
<string>Icon</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -151,8 +151,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>367</width>
|
||||
<height>85</height>
|
||||
<width>352</width>
|
||||
<height>68</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="scrollAreaVerticalLayout"/>
|
||||
|
||||
@@ -277,7 +277,6 @@ void ShareLinkWidget::slotCreatePassword()
|
||||
|
||||
void ShareLinkWidget::slotCreateShareLink(bool clicked)
|
||||
{
|
||||
Q_UNUSED(clicked);
|
||||
slotToggleAnimation(true);
|
||||
emit createLinkShare();
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
</palette>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">TextLabel</string>
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<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...") },
|
||||
} };
|
||||
listener->sendMessage(QString("GET_STRINGS:BEGIN"));
|
||||
for (const auto& key_value : strings) {
|
||||
for (auto key_value : strings) {
|
||||
if (argument.isEmpty() || argument == QLatin1String(key_value.first)) {
|
||||
listener->sendMessage(QString("STRING:%1:%2").arg(key_value.first, key_value.second));
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ SslButton::SslButton(QWidget *parent)
|
||||
_menu = new QMenu(this);
|
||||
QObject::connect(_menu, &QMenu::aboutToShow,
|
||||
this, &SslButton::slotUpdateMenu);
|
||||
setMenu(_menu);
|
||||
}
|
||||
|
||||
static QString addCertDetailsField(const QString &key, const QString &value)
|
||||
@@ -172,9 +171,11 @@ void SslButton::updateAccountState(AccountState *accountState)
|
||||
setIcon(QIcon(QLatin1String(":/client/resources/lock-https.png")));
|
||||
QSslCipher cipher = account->_sessionCipher;
|
||||
setToolTip(tr("This connection is encrypted using %1 bit %2.\n").arg(cipher.usedBits()).arg(cipher.name()));
|
||||
setMenu(_menu);
|
||||
} else {
|
||||
setIcon(QIcon(QLatin1String(":/client/resources/lock-http.png")));
|
||||
setToolTip(tr("This connection is NOT secure as it is not encrypted.\n"));
|
||||
setMenu(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,8 +189,6 @@ void SslButton::slotUpdateMenu()
|
||||
|
||||
AccountPtr account = _accountState->account();
|
||||
|
||||
_menu->addAction(tr("Server version: %1").arg(account->serverVersion()))->setEnabled(false);
|
||||
|
||||
if (account->isHttp2Supported()) {
|
||||
_menu->addAction("HTTP/2")->setEnabled(false);
|
||||
}
|
||||
@@ -240,8 +239,6 @@ void SslButton::slotUpdateMenu()
|
||||
_menu->addMenu(buildCertMenu(_menu, it.previous(), account->approvedCerts(), i, systemCerts));
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
_menu->addAction(tr("The connection is not secure"))->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ QString OCUpdater::statusString() const
|
||||
case DownloadTimedOut:
|
||||
return tr("Could not check for new updates.");
|
||||
case UpdateOnlyAvailableThroughSystem:
|
||||
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());
|
||||
return tr("New %1 version %2 available. Please use the system's update tool to install it.").arg(Theme::instance()->appNameGUI(), updateVersion);
|
||||
case CheckingServer:
|
||||
return tr("Checking update server...");
|
||||
case Unknown:
|
||||
|
||||
@@ -99,7 +99,6 @@ void Flow2AuthCredsPage::asyncAuthResult(Flow2Auth::Result r, const QString &use
|
||||
_appPassword = appPassword;
|
||||
OwncloudWizard *ocWizard = qobject_cast<OwncloudWizard *>(wizard());
|
||||
Q_ASSERT(ocWizard);
|
||||
|
||||
emit connectToOCUrl(ocWizard->account()->url().toString());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Browser Authentication</string>
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
@@ -61,7 +61,6 @@
|
||||
<widget class="QCommandLinkButton" name="copyLinkButton">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Browser Authentication</string>
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
@@ -73,7 +73,6 @@
|
||||
<widget class="QCommandLinkButton" name="copyLinkButton">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
|
||||
@@ -42,8 +42,6 @@ OwncloudAdvancedSetupPage::OwncloudAdvancedSetupPage()
|
||||
, _localFolderValid(false)
|
||||
, _progressIndi(new QProgressIndicator(this))
|
||||
, _remoteFolder()
|
||||
, _rSize(-1)
|
||||
, _rSelectedSize(-1)
|
||||
{
|
||||
_ui.setupUi(this);
|
||||
|
||||
@@ -370,8 +368,6 @@ void OwncloudAdvancedSetupPage::slotQuotaRetrieved(const QVariantMap &result)
|
||||
{
|
||||
_rSize = result["size"].toDouble();
|
||||
_ui.lSyncEverythingSizeLabel->setText(tr("(%1)").arg(Utility::octetsToString(_rSize)));
|
||||
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
qint64 OwncloudAdvancedSetupPage::availableLocalSpace() const
|
||||
|
||||
@@ -399,7 +399,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="syncModeLabel">
|
||||
<property name="text">
|
||||
<string notr="true">Status message</string>
|
||||
<string>Status message</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
|
||||
@@ -25,24 +25,67 @@
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<spacer name="verticalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="16" column="0">
|
||||
<widget class="QLabel" name="bottomLabel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
<property name="text">
|
||||
<string notr="true">TextLabel</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="14" column="0">
|
||||
<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">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
@@ -64,66 +107,117 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item row="11" column="0" rowspan="2">
|
||||
<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>
|
||||
<widget class="QPushButton" name="prevButton">
|
||||
<property name="minimumSize">
|
||||
<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="maximumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
<string>Register with a provider</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
<property name="default">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="OCC::SlideShow" name="slideShow" native="true">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
<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>
|
||||
<widget class="QPushButton" name="nextButton">
|
||||
<property name="minimumSize">
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>0</height>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<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>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<item row="6" column="0">
|
||||
<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">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
@@ -207,7 +301,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string notr="true">https://...</string>
|
||||
<string>https://...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -242,7 +336,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Error Label</string>
|
||||
<string>Error Label</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
@@ -291,8 +385,8 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<item row="0" column="0">
|
||||
<spacer name="verticalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
@@ -307,157 +401,6 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</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>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
|
||||
@@ -84,22 +84,7 @@ 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-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"));
|
||||
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}");
|
||||
|
||||
connect(_ui.slideShow, &SlideShow::clicked, _ui.slideShow, &SlideShow::nextSlide);
|
||||
_ui.slideShow->startShow();
|
||||
|
||||
QPalette pal = _ui.slideShow->palette();
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
#include <QStyle>
|
||||
#include <QStyleHints>
|
||||
|
||||
#define HASQT5_11 (QT_VERSION >= QT_VERSION_CHECK(5,11,0))
|
||||
|
||||
namespace OCC {
|
||||
|
||||
static const int Spacing = 6;
|
||||
@@ -90,11 +88,7 @@ QSize SlideShow::sizeHint() const
|
||||
QFontMetrics fm = fontMetrics();
|
||||
QSize labelSize(0, fm.height());
|
||||
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()));
|
||||
#endif
|
||||
}
|
||||
QSize pixmapSize;
|
||||
for (const QPixmap &pixmap : _pixmaps) {
|
||||
@@ -122,7 +116,7 @@ void SlideShow::nextSlide()
|
||||
_reverse = false;
|
||||
}
|
||||
|
||||
void SlideShow::prevSlide()
|
||||
void SlideShow::previousSlide()
|
||||
{
|
||||
setCurrentSlide((_currentIndex > 0 ? _currentIndex : _labels.count()) - 1);
|
||||
_reverse = true;
|
||||
|
||||
@@ -51,7 +51,7 @@ public slots:
|
||||
void startShow(int interval = 0);
|
||||
void stopShow();
|
||||
void nextSlide();
|
||||
void prevSlide();
|
||||
void previousSlide();
|
||||
void reset();
|
||||
|
||||
signals:
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
#include <QWebEngineProfile>
|
||||
#include <QWebEngineUrlRequestInterceptor>
|
||||
#include <QWebEngineUrlRequestJob>
|
||||
#if QT_VERSION >= 0x051200
|
||||
#include <QWebEngineUrlScheme>
|
||||
#endif
|
||||
#include <QWebEngineUrlSchemeHandler>
|
||||
#include <QWebEngineView>
|
||||
#include <QDesktopServices>
|
||||
@@ -68,10 +65,7 @@ WebView::WebView(QWidget *parent)
|
||||
_ui()
|
||||
{
|
||||
_ui.setupUi(this);
|
||||
#if QT_VERSION >= 0x051200
|
||||
QWebEngineUrlScheme _ncsheme("nc");
|
||||
QWebEngineUrlScheme::registerScheme(_ncsheme);
|
||||
#endif
|
||||
|
||||
_webview = new QWebEngineView(this);
|
||||
_profile = new QWebEngineProfile(this);
|
||||
_page = new WebEnginePage(_profile);
|
||||
@@ -181,7 +175,6 @@ WebEnginePage::WebEnginePage(QWebEngineProfile *profile, QObject* parent) : QWeb
|
||||
}
|
||||
|
||||
QWebEnginePage * WebEnginePage::createWindow(QWebEnginePage::WebWindowType type) {
|
||||
Q_UNUSED(type);
|
||||
ExternalWebEnginePage *view = new ExternalWebEnginePage(this->profile());
|
||||
return view;
|
||||
}
|
||||
@@ -223,8 +216,6 @@ ExternalWebEnginePage::ExternalWebEnginePage(QWebEngineProfile *profile, QObject
|
||||
|
||||
bool ExternalWebEnginePage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame)
|
||||
{
|
||||
Q_UNUSED(type);
|
||||
Q_UNUSED(isMainFrame);
|
||||
QDesktopServices::openUrl(url);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -160,37 +160,6 @@ void AbstractNetworkJob::slotFinished()
|
||||
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 (!_ignoreCredentialFailure || _reply->error() != QNetworkReply::AuthenticationRequiredError) {
|
||||
qCWarning(lcNetworkJob) << _reply->error() << errorString()
|
||||
|
||||
@@ -188,8 +188,7 @@ private:
|
||||
QPointer<QNetworkReply> _reply; // (QPointer because the NetworkManager may be destroyed before the jobs at exit)
|
||||
QString _path;
|
||||
QTimer _timer;
|
||||
int _redirectCount = 0;
|
||||
int _http2ResendCount = 0;
|
||||
int _redirectCount;
|
||||
|
||||
// Set by the xyzRequest() functions and needed to be able to redirect
|
||||
// requests, should it be required.
|
||||
|
||||
@@ -36,15 +36,9 @@
|
||||
#include <QAuthenticator>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include <keychain.h>
|
||||
#include "creds/abstractcredentials.h"
|
||||
|
||||
using namespace QKeychain;
|
||||
|
||||
namespace OCC {
|
||||
|
||||
Q_LOGGING_CATEGORY(lcAccount, "nextcloud.sync.account", QtInfoMsg)
|
||||
const char app_password[] = "_app-password";
|
||||
|
||||
Account::Account(QObject *parent)
|
||||
: QObject(parent)
|
||||
@@ -59,17 +53,16 @@ AccountPtr Account::create()
|
||||
AccountPtr acc = AccountPtr(new Account);
|
||||
acc->setSharedThis(acc);
|
||||
|
||||
//TODO: This probably needs to have a better
|
||||
// coupling, but it should work for now.
|
||||
acc->e2e()->setAccount(acc);
|
||||
|
||||
//TODO: This probably needs to have a better
|
||||
// coupling, but it should work for now.
|
||||
acc->e2e()->setAccount(acc);
|
||||
return acc;
|
||||
}
|
||||
|
||||
ClientSideEncryption* Account::e2e()
|
||||
{
|
||||
// Qt expects everything in the connect to be a pointer, so return a pointer.
|
||||
return &_e2e;
|
||||
// Qt expects everything in the connect to be a pointer, so return a pointer.
|
||||
return &_e2e;
|
||||
}
|
||||
|
||||
Account::~Account()
|
||||
@@ -439,9 +432,6 @@ void Account::slotCredentialsAsked()
|
||||
|
||||
void Account::handleInvalidCredentials()
|
||||
{
|
||||
// Retrieving password will trigger remote wipe check job
|
||||
retrieveAppPassword();
|
||||
|
||||
emit invalidCredentials();
|
||||
}
|
||||
|
||||
@@ -513,63 +503,4 @@ 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
|
||||
|
||||
@@ -41,12 +41,6 @@ class QNetworkReply;
|
||||
class QUrl;
|
||||
class QNetworkAccessManager;
|
||||
|
||||
namespace QKeychain {
|
||||
class Job;
|
||||
class WritePasswordJob;
|
||||
class ReadPasswordJob;
|
||||
}
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class AbstractCredentials;
|
||||
@@ -56,6 +50,7 @@ class QuotaInfo;
|
||||
class AccessManager;
|
||||
class SimpleNetworkJob;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Reimplement this to handle SSL errors from libsync
|
||||
* @ingroup libsync
|
||||
@@ -241,11 +236,6 @@ public:
|
||||
|
||||
ClientSideEncryption* e2e();
|
||||
|
||||
/// Used in RemoteWipe
|
||||
void retrieveAppPassword();
|
||||
void setAppPassword(QString appPassword);
|
||||
void deleteAppPassword();
|
||||
|
||||
public slots:
|
||||
/// Used when forgetting credentials
|
||||
void clearQNAMCache();
|
||||
@@ -272,9 +262,6 @@ signals:
|
||||
void accountChangedAvatar();
|
||||
void accountChangedDisplayName();
|
||||
|
||||
/// Used in RemoteWipe
|
||||
void appPasswordRetrieved(QString);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void slotCredentialsFetched();
|
||||
void slotCredentialsAsked();
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include <QUuid>
|
||||
|
||||
#include <keychain.h>
|
||||
#include "common/utility.h"
|
||||
|
||||
#include "wordlist.h"
|
||||
|
||||
@@ -63,11 +62,11 @@ namespace {
|
||||
|
||||
namespace {
|
||||
QByteArray BIO2ByteArray(BIO *b) {
|
||||
size_t pending = BIO_ctrl_pending(b);
|
||||
int pending = BIO_ctrl_pending(b);
|
||||
char *tmp = (char *)calloc(pending+1, sizeof(char));
|
||||
BIO_read(b, tmp, OCC::Utility::convertSizeToInt(pending));
|
||||
BIO_read(b, tmp, pending);
|
||||
|
||||
QByteArray res(tmp, OCC::Utility::convertSizeToInt(pending));
|
||||
QByteArray res(tmp, pending);
|
||||
free(tmp);
|
||||
|
||||
return res;
|
||||
@@ -550,7 +549,7 @@ QByteArray decryptStringAsymmetric(EVP_PKEY *privateKey, const QByteArray& data)
|
||||
}
|
||||
|
||||
const auto ret = std::string((char*) out, outlen);
|
||||
QByteArray raw((const char*) out, OCC::Utility::convertSizeToInt(outlen));
|
||||
QByteArray raw((const char*) out, outlen);
|
||||
qCInfo(lcCse()) << raw;
|
||||
return raw;
|
||||
}
|
||||
@@ -604,7 +603,7 @@ QByteArray encryptStringAsymmetric(EVP_PKEY *publicKey, const QByteArray& data)
|
||||
}
|
||||
|
||||
// Transform the encrypted data into base64.
|
||||
QByteArray raw((const char*) out, OCC::Utility::convertSizeToInt(outLen));
|
||||
QByteArray raw((const char*) out, outLen);
|
||||
qCInfo(lcCse()) << raw.toBase64();
|
||||
return raw.toBase64();
|
||||
}
|
||||
|
||||
@@ -432,7 +432,6 @@ void SignPublicKeyApiJob::start()
|
||||
{
|
||||
QNetworkRequest req;
|
||||
req.setRawHeader("OCS-APIREQUEST", "true");
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/x-www-form-urlencoded"));
|
||||
QUrlQuery query;
|
||||
query.addQueryItem(QLatin1String("format"), QLatin1String("json"));
|
||||
QUrl url = Utility::concatUrlPath(account()->url(), path());
|
||||
|
||||
@@ -37,12 +37,6 @@
|
||||
#include <QNetworkProxy>
|
||||
#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_MAX_LOG_LINES 20000
|
||||
|
||||
@@ -180,11 +174,7 @@ bool ConfigFile::showInExplorerNavigationPane() const
|
||||
{
|
||||
const bool defaultValue =
|
||||
#ifdef Q_OS_WIN
|
||||
#if QTLEGACY
|
||||
(QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS10);
|
||||
#else
|
||||
QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10;
|
||||
#endif
|
||||
QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS10
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
|
||||
@@ -798,11 +798,7 @@ namespace { // Anonymous namespace for the recall feature
|
||||
static void preserveGroupOwnership(const QString &fileName, const QFileInfo &fi)
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
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);
|
||||
}
|
||||
chown(fileName.toLocal8Bit().constData(), -1, fi.groupId());
|
||||
#else
|
||||
Q_UNUSED(fileName);
|
||||
Q_UNUSED(fi);
|
||||
|
||||
@@ -177,14 +177,6 @@ QIcon Theme::themeIcon(const QString &name, bool sysTray, bool sysTrayMenuVisibl
|
||||
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)
|
||||
{
|
||||
qreal devicePixelRatio = dev ? dev->devicePixelRatio() : qApp->primaryScreen()->devicePixelRatio();
|
||||
|
||||
@@ -347,14 +347,6 @@ public:
|
||||
* important dependency versions.
|
||||
*/
|
||||
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:
|
||||
#ifndef TOKEN_AUTH_ONLY
|
||||
|
||||
@@ -40,5 +40,3 @@ System Volume Information
|
||||
.nfs*
|
||||
|
||||
My Saved Places.
|
||||
|
||||
\#*#
|
||||
|
||||
@@ -12,10 +12,10 @@ include_directories(${CMAKE_SOURCE_DIR}/src
|
||||
${SQLITE3_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
include(nextcloud_add_test.cmake)
|
||||
include(owncloud_add_test.cmake)
|
||||
|
||||
nextcloud_add_test(NextcloudPropagator "")
|
||||
nextcloud_add_test(Updater "")
|
||||
owncloud_add_test(OwncloudPropagator "")
|
||||
owncloud_add_test(Updater "")
|
||||
|
||||
SET(FolderWatcher_SRC ../src/gui/folderwatcher.cpp)
|
||||
|
||||
@@ -29,64 +29,49 @@ IF( APPLE )
|
||||
list(APPEND FolderWatcher_SRC ../src/gui/folderwatcher_mac.cpp)
|
||||
list(APPEND FolderWatcher_SRC ../src/gui/socketapisocket_mac.mm)
|
||||
ENDIF()
|
||||
nextcloud_add_test(NetrcParser ../src/cmd/netrcparser.cpp)
|
||||
nextcloud_add_test(OwnSql "")
|
||||
nextcloud_add_test(SyncJournalDB "")
|
||||
nextcloud_add_test(SyncFileItem "")
|
||||
nextcloud_add_test(ConcatUrl "")
|
||||
nextcloud_add_test(XmlParse "")
|
||||
nextcloud_add_test(ChecksumValidator "")
|
||||
owncloud_add_test(NetrcParser ../src/cmd/netrcparser.cpp)
|
||||
owncloud_add_test(OwnSql "")
|
||||
owncloud_add_test(SyncJournalDB "")
|
||||
owncloud_add_test(SyncFileItem "")
|
||||
owncloud_add_test(ConcatUrl "")
|
||||
owncloud_add_test(XmlParse "")
|
||||
owncloud_add_test(ChecksumValidator "")
|
||||
|
||||
nextcloud_add_test(ExcludedFiles "")
|
||||
owncloud_add_test(ExcludedFiles "")
|
||||
|
||||
nextcloud_add_test(FileSystem "")
|
||||
nextcloud_add_test(Utility "")
|
||||
nextcloud_add_test(SyncEngine "syncenginetestutils.h")
|
||||
nextcloud_add_test(SyncMove "syncenginetestutils.h")
|
||||
nextcloud_add_test(SyncConflict "syncenginetestutils.h")
|
||||
nextcloud_add_test(SyncFileStatusTracker "syncenginetestutils.h")
|
||||
nextcloud_add_test(ChunkingNg "syncenginetestutils.h")
|
||||
nextcloud_add_test(UploadReset "syncenginetestutils.h")
|
||||
nextcloud_add_test(AllFilesDeleted "syncenginetestutils.h")
|
||||
nextcloud_add_test(Blacklist "syncenginetestutils.h")
|
||||
nextcloud_add_test(FolderWatcher "${FolderWatcher_SRC}")
|
||||
owncloud_add_test(FileSystem "")
|
||||
owncloud_add_test(Utility "")
|
||||
owncloud_add_test(SyncEngine "syncenginetestutils.h")
|
||||
owncloud_add_test(SyncMove "syncenginetestutils.h")
|
||||
owncloud_add_test(SyncConflict "syncenginetestutils.h")
|
||||
owncloud_add_test(SyncFileStatusTracker "syncenginetestutils.h")
|
||||
owncloud_add_test(ChunkingNg "syncenginetestutils.h")
|
||||
owncloud_add_test(UploadReset "syncenginetestutils.h")
|
||||
owncloud_add_test(AllFilesDeleted "syncenginetestutils.h")
|
||||
owncloud_add_test(Blacklist "syncenginetestutils.h")
|
||||
owncloud_add_test(FolderWatcher "${FolderWatcher_SRC}")
|
||||
|
||||
if( UNIX AND NOT APPLE )
|
||||
nextcloud_add_test(InotifyWatcher "${FolderWatcher_SRC}")
|
||||
owncloud_add_test(InotifyWatcher "${FolderWatcher_SRC}")
|
||||
endif(UNIX AND NOT APPLE)
|
||||
|
||||
nextcloud_add_benchmark(LargeSync "syncenginetestutils.h")
|
||||
owncloud_add_benchmark(LargeSync "syncenginetestutils.h")
|
||||
|
||||
SET(FolderMan_SRC ../src/gui/folderman.cpp)
|
||||
list(APPEND FolderMan_SRC ../src/gui/folder.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/lockwatcher.cpp )
|
||||
list(APPEND FolderMan_SRC ../src/gui/guiutility.cpp )
|
||||
list(APPEND FolderMan_SRC ../src/gui/navigationpanehelper.cpp )
|
||||
list(APPEND FolderMan_SRC ../src/gui/connectionvalidator.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 stubfolderman.cpp )
|
||||
nextcloud_add_test(FolderMan "${FolderMan_SRC}")
|
||||
list(APPEND FolderMan_SRC stub.cpp )
|
||||
owncloud_add_test(FolderMan "${FolderMan_SRC}")
|
||||
|
||||
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")
|
||||
owncloud_add_test(OAuth "syncenginetestutils.h;../src/gui/creds/oauth.cpp")
|
||||
|
||||
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)
|
||||
|
||||
macro(nextcloud_add_test test_class additional_cpp)
|
||||
macro(owncloud_add_test test_class additional_cpp)
|
||||
set(CMAKE_AUTOMOC TRUE)
|
||||
set(OWNCLOUD_TEST_CLASS ${test_class})
|
||||
string(TOLOWER "${OWNCLOUD_TEST_CLASS}" OWNCLOUD_TEST_CLASS_LOWERCASE)
|
||||
@@ -19,7 +19,7 @@ macro(nextcloud_add_test test_class additional_cpp)
|
||||
add_test(NAME ${OWNCLOUD_TEST_CLASS}Test COMMAND ${OWNCLOUD_TEST_CLASS}Test)
|
||||
endmacro()
|
||||
|
||||
macro(nextcloud_add_benchmark test_class additional_cpp)
|
||||
macro(owncloud_add_benchmark test_class additional_cpp)
|
||||
set(CMAKE_AUTOMOC TRUE)
|
||||
set(OWNCLOUD_TEST_CLASS ${test_class})
|
||||
string(TOLOWER "${OWNCLOUD_TEST_CLASS}" OWNCLOUD_TEST_CLASS_LOWERCASE)
|
||||
@@ -1,11 +1,7 @@
|
||||
// stub to prevent linker error
|
||||
#include "accountmanager.h"
|
||||
|
||||
OCC::AccountManager *OCC::AccountManager::instance() { return static_cast<AccountManager *>(new QObject); }
|
||||
void OCC::AccountManager::save(bool) { }
|
||||
void OCC::AccountManager::saveAccountState(AccountState *) { }
|
||||
void OCC::AccountManager::deleteAccount(AccountState *) { }
|
||||
void OCC::AccountManager::save(bool saveCredentials) { Q_UNUSED(saveCredentials); }
|
||||
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;
|
||||
@@ -1,30 +0,0 @@
|
||||
// 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,8 +39,6 @@ private slots:
|
||||
QVERIFY(excluded.isExcluded("/a/foo_conflict-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", keepHidden));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -14,10 +14,29 @@
|
||||
#include "account.h"
|
||||
#include "accountstate.h"
|
||||
#include "configfile.h"
|
||||
#include "testhelper.h"
|
||||
#include "creds/httpcredentials.h"
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#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 "propagatedownload.h"
|
||||
#include "nextcloudpropagator_p.h"
|
||||
#include "owncloudpropagator_p.h"
|
||||
|
||||
using namespace OCC;
|
||||
namespace OCC {
|
||||
QString OWNCLOUDSYNC_EXPORT createDownloadTmpFileName(const QString &previous);
|
||||
}
|
||||
|
||||
class TestNextcloudPropagator : public QObject
|
||||
class TestOwncloudPropagator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void testUpdateErrorFromSession()
|
||||
{
|
||||
// NextcloudPropagator propagator( NULL, QLatin1String("test1"), QLatin1String("test2"), new ProgressDatabase);
|
||||
// OwncloudPropagator propagator( NULL, QLatin1String("test1"), QLatin1String("test2"), new ProgressDatabase);
|
||||
QVERIFY( true );
|
||||
}
|
||||
|
||||
@@ -78,5 +78,5 @@ private slots:
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_APPLESS_MAIN(TestNextcloudPropagator)
|
||||
#include "testnextcloudpropagator.moc"
|
||||
QTEST_APPLESS_MAIN(TestOwncloudPropagator)
|
||||
#include "testowncloudpropagator.moc"
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* 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[0].contains("A (conflicted copy"));
|
||||
QVERIFY(conflicts[1].contains("B (conflicted copy"));
|
||||
for (const auto& conflict : conflicts)
|
||||
for (auto conflict : conflicts)
|
||||
QDir(fakeFolder.localPath() + conflict).removeRecursively();
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
@@ -581,7 +581,7 @@ private slots:
|
||||
auto conflicts = findConflicts(fakeFolder.currentLocalState());
|
||||
QVERIFY(conflicts.size() == 1);
|
||||
QVERIFY(conflicts[0].contains("A (conflicted copy"));
|
||||
for (const auto& conflict : conflicts)
|
||||
for (auto conflict : conflicts)
|
||||
QDir(fakeFolder.localPath() + conflict).removeRecursively();
|
||||
|
||||
QVERIFY(fakeFolder.syncEngine().isAnotherSyncNeeded() == ImmediateFollowUp);
|
||||
|
||||
@@ -289,12 +289,12 @@ private slots:
|
||||
<< "foo bla bar/file"
|
||||
<< "fo_"
|
||||
<< "fo_/file";
|
||||
for (const auto& elem : elements)
|
||||
for (auto elem : elements)
|
||||
makeEntry(elem);
|
||||
|
||||
auto checkElements = [&]() {
|
||||
bool ok = true;
|
||||
for (const auto& elem : elements) {
|
||||
for (auto elem : elements) {
|
||||
SyncJournalFileRecord record;
|
||||
_db.getFileRecord(elem, &record);
|
||||
if (!record.isValid()) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user