Comparar commits
56 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 17cc8156a4 | |||
| 2b09655ea4 | |||
| 80a526d0e7 | |||
| 76fde49282 | |||
| 4ef7d0410d | |||
| a1b4984d14 | |||
| adbe5ecf55 | |||
| ba32571039 | |||
| 084146756b | |||
| e1f5a49c21 | |||
| 143320341e | |||
| e286bb1b64 | |||
| d433f0e08e | |||
| 107149d601 | |||
| fa9b36f829 | |||
| 6775292d63 | |||
| 6835429a28 | |||
| 22135f9f57 | |||
| 0fd06a225c | |||
| 473dcb0947 | |||
| e306f4611c | |||
| c6f4f44619 | |||
| 0865c63745 | |||
| b81c3a6a67 | |||
| cc56e5639d | |||
| 3ce5b358ae | |||
| e968284618 | |||
| c7723179d8 | |||
| 1872f3f94a | |||
| 3b7887ca35 | |||
| d781e63fab | |||
| d1237cdda3 | |||
| 030e3a5d4a | |||
| 4fa4a6a5ed | |||
| 23fb07240b | |||
| 3912dba33a | |||
| d8c479ab1e | |||
| bec67455c1 | |||
| ba6a37a601 | |||
| 03f5091e73 | |||
| 6b6ff08821 | |||
| 35a0ee4893 | |||
| 3519391119 | |||
| 775a1c9ad8 | |||
| ac95844ebd | |||
| c5b90d9507 | |||
| d631f2e070 | |||
| 5bae2ed5ef | |||
| 5af2a657ca | |||
| 71231026a0 | |||
| dfca67b63a | |||
| 7dc6a3b89f | |||
| f985111b62 | |||
| e8d734b1c2 | |||
| a38864fcb4 | |||
| 47bab51474 |
+4
-1
@@ -58,6 +58,9 @@ if( UNIX AND NOT APPLE )
|
||||
endif()
|
||||
####
|
||||
|
||||
# Enable Q_ASSERT etc. in all builds
|
||||
add_definitions( -DQT_FORCE_ASSERTS )
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(DefineInstallationPaths)
|
||||
include(GenerateExportHeader)
|
||||
@@ -69,7 +72,7 @@ get_git_head_revision(GIT_REFSPEC GIT_SHA1)
|
||||
# if we cannot get it from git, directly try .tag (packages)
|
||||
# this will work if the tar balls have been properly created
|
||||
# via git-archive.
|
||||
if (${GIT_SHA1} STREQUAL "GITDIR-NOTFOUND")
|
||||
if ("${GIT_SHA1}" STREQUAL "GITDIR-NOTFOUND")
|
||||
file(READ ${CMAKE_SOURCE_DIR}/.tag sha1_candidate)
|
||||
string(REPLACE "\n" "" sha1_candidate ${sha1_candidate})
|
||||
if (NOT ${sha1_candidate} STREQUAL "$Format:%H$")
|
||||
|
||||
+39
@@ -1,6 +1,45 @@
|
||||
ChangeLog
|
||||
=========
|
||||
|
||||
version 2.3.0 (2017-0x-xx)
|
||||
* WiP!
|
||||
* WiP Switch Windows and OS X build to 5.6.2
|
||||
* WiP Performance improvements for exclude detection
|
||||
* Switch to new ownCloud server WebDAV endpoint
|
||||
* Chunking NG: New file upload chunking algorithmn for ownCloud server 9.2
|
||||
* Allow to sync a folder to multiple different servers (Filename change from .csync_journal.db to _sync_$HASH.db)
|
||||
* Conflicts: Use the local mtime for the conflict file name (#5273)
|
||||
* "Sync now" menu item
|
||||
* SSL Client certificate support improved (Show UI, Store keys in keychain)
|
||||
* Propagator: Upload more small files in parallel
|
||||
* Sync Engine: Read data-fingerprint property to detect backups (#2325)
|
||||
* GUI: Show link to ceate an app password/token for syncing
|
||||
* Share dialog: Add 'Mail link' button
|
||||
* Caja file manager plugin
|
||||
* Make "backup detected" message to not trigger in wrong cases
|
||||
* SyncEngine: Fix renaming of folder when file are changed (#5192)
|
||||
* Fix reconnect bug if status.php intermittently returns wrong data (#5188)
|
||||
* Improve sync scheduling (#5317)
|
||||
* Overlay icons: Improvements in correctnes
|
||||
* Tray menu: Only update on demand to fix Linux desktop integration glitches
|
||||
* Progress: Better time/bandwidth estimations
|
||||
* Network: Follow certain HTTP redirects (#2791)
|
||||
* Network: Remove all cookies (including load balancers etc) when logging out
|
||||
* Discovery thread: Low priority
|
||||
* owncloudsync.log: Write during propagation
|
||||
* Better error message for files with trailing spaces on Windows
|
||||
* Excludes: Consider files in hidden folders excluded (#5163)
|
||||
* Allow sync directory to be a symlinked directory
|
||||
* Add manifest file on Windows to make the application UAC aware
|
||||
* macOS: Improve monochrome tray icons
|
||||
* Don't blacklist 507 Insufficent Storage #5346 (#5424)
|
||||
* Shibboleth bugfixes
|
||||
* Fixes with regards to low disk space
|
||||
* A ton of other bugfixes
|
||||
* Refactorings
|
||||
* Improved documentation
|
||||
* Crash fixes
|
||||
|
||||
version 2.2.4 (release 2016-09-27)
|
||||
* Dolphin Plugin: Use the Application name for the socket path (#5172)
|
||||
* SyncEngine: Fix renaming of folder when file are changed (#5195)
|
||||
|
||||
@@ -418,10 +418,8 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
File "${QT_DLL_PATH}\Qt5Core.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Gui.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Network.dll"
|
||||
File "${QT_DLL_PATH}\Qt5OpenGL.dll"
|
||||
File "${QT_DLL_PATH}\Qt5PrintSupport.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Qml.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Quick.dll"
|
||||
File "${QT_DLL_PATH}\Qt5Sql.dll"
|
||||
File "${QT_DLL_PATH}\Qt5WebKit.dll"
|
||||
File "${QT_DLL_PATH}\Qt5WebKitWidgets.dll"
|
||||
@@ -435,9 +433,9 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
|
||||
;Qt deps
|
||||
File "${MING_BIN}\libpng16-16.dll"
|
||||
File "${MING_BIN}\icudata53.dll"
|
||||
File "${MING_BIN}\icui18n53.dll"
|
||||
File "${MING_BIN}\icuuc53.dll"
|
||||
File "${MING_BIN}\icudata56.dll"
|
||||
File "${MING_BIN}\icui18n56.dll"
|
||||
File "${MING_BIN}\icuuc56.dll"
|
||||
File "${MING_BIN}\libEGL.dll"
|
||||
File "${MING_BIN}\libGLESv2.dll"
|
||||
File "${MING_BIN}\libjpeg-8.dll"
|
||||
@@ -446,11 +444,14 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
||||
File "${MING_BIN}\libcrypto-10.dll"
|
||||
File "${MING_BIN}\libssl-10.dll"
|
||||
File "${MING_BIN}\libstdc++-6.dll"
|
||||
File "${MING_BIN}\libwebp-4.dll"
|
||||
File "${MING_BIN}\libwebp-5.dll"
|
||||
File "${MING_BIN}\libxslt-1.dll"
|
||||
File "${MING_BIN}\libxml2-2.dll"
|
||||
File "${MING_BIN}\zlib1.dll"
|
||||
File "${MING_BIN}\libsqlite3-0.dll"
|
||||
File "${MING_BIN}\libharfbuzz-0.dll"
|
||||
File "${MING_BIN}\libfreetype-6.dll"
|
||||
File "${MING_BIN}\libglib-2.0-0.dll"
|
||||
File "${MING_BIN}\libintl-8.dll"
|
||||
|
||||
;QtKeyChain stuff
|
||||
File "${MING_BIN}\libqt5keychain.dll"
|
||||
|
||||
@@ -44,11 +44,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct csync_client_certs_s {
|
||||
char *certificatePath;
|
||||
char *certificatePasswd;
|
||||
};
|
||||
|
||||
enum csync_status_codes_e {
|
||||
CSYNC_STATUS_OK = 0,
|
||||
|
||||
|
||||
@@ -103,9 +103,6 @@ struct csync_s {
|
||||
|
||||
} callbacks;
|
||||
c_strlist_t *excludes;
|
||||
|
||||
// needed for SSL client certificate support
|
||||
struct csync_client_certs_s *clientCerts;
|
||||
|
||||
struct {
|
||||
char *file;
|
||||
|
||||
+1
-9
@@ -68,17 +68,9 @@ To set up your build environment for development using HomeBrew_:
|
||||
|
||||
1. Install Xcode
|
||||
2. Install Xcode command line tools::
|
||||
<<<<<<< HEAD
|
||||
xcode-select --install
|
||||
|
||||
3. Install homebrew::
|
||||
=======
|
||||
|
||||
xcode-select --install
|
||||
|
||||
3. Install homebrew::
|
||||
|
||||
>>>>>>> ca9ec4625391ae23940b3a62aaa0afe89f3d98e8
|
||||
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||
|
||||
4. Add the ownCloud repository using the following command::
|
||||
@@ -91,7 +83,7 @@ To set up your build environment for development using HomeBrew_:
|
||||
|
||||
3. Add Qt from brew to the path::
|
||||
|
||||
export PATH=/usr/local/Cellar/qt5/5.x.y/bin/qmake
|
||||
export PATH=/usr/local/Cellar/qt5/5.x.y/bin:$PATH
|
||||
|
||||
Where ``x.z`` is the current version of Qt 5 that brew has installed
|
||||
on your machine.
|
||||
|
||||
@@ -65,7 +65,7 @@ If no client is configured, or if you choose to use a different user to synchron
|
||||
you can specify the user
|
||||
password setting with the usual URL pattern. For example::
|
||||
|
||||
$ owncloudcmd / https://carla:secret@server/owncloud/remote.php/webdav/
|
||||
$ owncloudcmd /home/user/my_sync_folder https://carla:secret@server/owncloud/remote.php/webdav/
|
||||
|
||||
To synchronize the ownCloud directory ``Music`` to the local directory
|
||||
``media/music``, through a proxy listening on port ``8080``, and on a gateway
|
||||
|
||||
@@ -553,6 +553,72 @@ X-GNOME-Autostart-Delay=3
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
Comment[oc]=@APPLICATION_NAME@ sincronizacion del client
|
||||
GenericName[oc]=Dorsièr de Sincronizacion
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <KIOCore/kfileitem.h>
|
||||
#include <KIOCore/KFileItemListProperties>
|
||||
#include <QtWidgets/QAction>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QTimer>
|
||||
#include "ownclouddolphinpluginhelper.h"
|
||||
|
||||
@@ -43,7 +44,8 @@ public:
|
||||
auto url = urls.first();
|
||||
if (!url.isLocalFile())
|
||||
return {};
|
||||
auto localFile = url.toLocalFile();
|
||||
QDir localPath(url.toLocalFile());
|
||||
auto localFile = localPath.canonicalPath();
|
||||
|
||||
const auto paths = helper->paths();
|
||||
if (!std::any_of(paths.begin(), paths.end(), [&](const QString &s) {
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <KPluginFactory>
|
||||
#include <QtNetwork/QLocalSocket>
|
||||
#include <KIOCore/kfileitem.h>
|
||||
#include <QDir>
|
||||
#include <QTimer>
|
||||
#include "ownclouddolphinpluginhelper.h"
|
||||
|
||||
@@ -46,7 +47,8 @@ public:
|
||||
return QStringList();
|
||||
if (!url.isLocalFile())
|
||||
return QStringList();
|
||||
const QByteArray localFile = url.toLocalFile().toUtf8();
|
||||
QDir localPath(url.toLocalFile());
|
||||
const QByteArray localFile = localPath.canonicalPath().toUtf8();
|
||||
|
||||
helper->sendCommand(QByteArray("RETRIEVE_FILE_STATUS:" + localFile + "\n"));
|
||||
|
||||
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) by Pierre MOREAU <p.moreau@agim.idshost.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file p12topem.cpp
|
||||
* \brief Static library to convert p12 to pem
|
||||
* \author Pierre MOREAU <p.moreau@agim.idshost.fr>
|
||||
* \version 1.0.0
|
||||
* \date 09 January 2014
|
||||
*/
|
||||
|
||||
#include "p12topem.h"
|
||||
|
||||
/**
|
||||
* \fn string x509ToString (BIO)
|
||||
* \brief Return string from BIO SSL
|
||||
* \param BIO o PEM_write_BIO_...
|
||||
* \return string PEM
|
||||
*/
|
||||
string x509ToString(BIO *o) {
|
||||
BUF_MEM *bptr;
|
||||
BIO_get_mem_ptr(o, &bptr);
|
||||
int len = bptr->length;
|
||||
void* data = calloc(len+10, sizeof(char));
|
||||
BIO_read(o, data, len);
|
||||
string ret = std::string(static_cast<char*>(data));
|
||||
free(data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn resultP12ToPem p12ToPem (string, string)
|
||||
* \brief Convert P12 to PEM
|
||||
* \param string p12File Path to P12 file
|
||||
* \param string p12Passwd Password to open P12 file
|
||||
* \return result (bool ReturnCode, Int ErrorCode, String Comment, String PrivateKey, String Certificate)
|
||||
*/
|
||||
resultP12ToPem p12ToPem(string p12File, string p12Passwd) {
|
||||
FILE *fp;
|
||||
PKCS12 *p12 = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
X509 *cert = NULL;
|
||||
STACK_OF(X509) *ca = NULL;
|
||||
|
||||
BIO *o = BIO_new(BIO_s_mem());
|
||||
|
||||
string privateKey = "";
|
||||
string certificate = "";
|
||||
|
||||
resultP12ToPem ret;
|
||||
ret.ReturnCode = false;
|
||||
ret.ErrorCode = 0;
|
||||
ret.Comment = "";
|
||||
ret.PrivateKey = "";
|
||||
ret.Certificate = "";
|
||||
|
||||
SSLeay_add_all_algorithms();
|
||||
ERR_load_crypto_strings();
|
||||
if(!(fp = fopen(p12File.c_str(), "rb"))) {
|
||||
ret.ErrorCode = 1;
|
||||
ret.Comment = strerror(errno);
|
||||
return ret;
|
||||
}
|
||||
|
||||
p12 = d2i_PKCS12_fp(fp, &p12);
|
||||
fclose (fp);
|
||||
|
||||
if (!p12) {
|
||||
ret.ErrorCode = 2;
|
||||
ret.Comment = "Unable to open PKCS#12 file";
|
||||
return ret;
|
||||
}
|
||||
if (!PKCS12_parse(p12, p12Passwd.c_str(), &pkey, &cert, &ca)) {
|
||||
ret.ErrorCode = 3;
|
||||
ret.Comment = "Unable to parse PKCS#12 file (wrong password ?)";
|
||||
return ret;
|
||||
}
|
||||
PKCS12_free(p12);
|
||||
|
||||
if (!(pkey && cert)) {
|
||||
ret.ErrorCode = 4;
|
||||
ret.Comment = "Certificate and/or key file doesn't exists";
|
||||
} else {
|
||||
PEM_write_bio_PrivateKey(o, pkey, 0, 0, 0, NULL, 0);
|
||||
privateKey = x509ToString(o);
|
||||
|
||||
PEM_write_bio_X509(o, cert);
|
||||
certificate = x509ToString(o);
|
||||
|
||||
BIO_free(o);
|
||||
|
||||
ret.ReturnCode = true;
|
||||
ret.ErrorCode = 0;
|
||||
ret.Comment = "All is fine";
|
||||
ret.PrivateKey = privateKey;
|
||||
ret.Certificate = certificate;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
-62
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) by Pierre MOREAU <p.moreau@agim.idshost.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef P12TOPEM_H
|
||||
#define P12TOPEM_H
|
||||
|
||||
/**
|
||||
* \file p12topem.h
|
||||
* \brief Static library to convert p12 to pem
|
||||
* \author Pierre MOREAU <p.moreau@agim.idshost.fr>
|
||||
* \version 1.0.0
|
||||
* \date 09 January 2014
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pkcs12.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* \struct resultP12ToPem p12topem.h
|
||||
*/
|
||||
struct resultP12ToPem {
|
||||
bool ReturnCode;
|
||||
int ErrorCode;
|
||||
string Comment;
|
||||
string PrivateKey;
|
||||
string Certificate;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Return string from BIO SSL
|
||||
* \param BIO o PEM_write_BIO_...
|
||||
* \return string PEM
|
||||
*/
|
||||
string x509ToString(BIO *o);
|
||||
|
||||
/**
|
||||
* \brief Convert P12 to PEM
|
||||
* \param string p12File Path to P12 file
|
||||
* \param string p12Passwd Password to open P12 file
|
||||
* \return result (bool ReturnCode, Int ErrorCode, String Comment, String PrivateKey, String Certificate)
|
||||
*/
|
||||
resultP12ToPem p12ToPem(string p12File, string p12Passwd);
|
||||
|
||||
#endif /* P12TOPEM_H */
|
||||
|
||||
externo
+6941
-4159
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
externo
+125
-29
@@ -108,7 +108,8 @@ extern "C" {
|
||||
** be held constant and Z will be incremented or else Y will be incremented
|
||||
** and Z will be reset to zero.
|
||||
**
|
||||
** Since version 3.6.18, SQLite source code has been stored in the
|
||||
** Since [version 3.6.18] ([dateof:3.6.18]),
|
||||
** SQLite source code has been stored in the
|
||||
** <a href="http://www.fossil-scm.org/">Fossil configuration management
|
||||
** system</a>. ^The SQLITE_SOURCE_ID macro evaluates to
|
||||
** a string which identifies a particular check-in of SQLite
|
||||
@@ -120,13 +121,13 @@ extern "C" {
|
||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.14.2"
|
||||
#define SQLITE_VERSION_NUMBER 3014002
|
||||
#define SQLITE_SOURCE_ID "2016-09-12 18:50:49 29dbef4b8585f753861a36d6dd102ca634197bd6"
|
||||
#define SQLITE_VERSION "3.16.1"
|
||||
#define SQLITE_VERSION_NUMBER 3016001
|
||||
#define SQLITE_SOURCE_ID "2017-01-03 18:27:03 979f04392853b8053817a3eea2fc679947b437fd"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
** KEYWORDS: sqlite3_version, sqlite3_sourceid
|
||||
** KEYWORDS: sqlite3_version sqlite3_sourceid
|
||||
**
|
||||
** These interfaces provide the same information as the [SQLITE_VERSION],
|
||||
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
|
||||
@@ -452,7 +453,8 @@ SQLITE_API int sqlite3_exec(
|
||||
** [result codes]. However, experience has shown that many of
|
||||
** these result codes are too coarse-grained. They do not provide as
|
||||
** much information about problems as programmers might like. In an effort to
|
||||
** address this, newer versions of SQLite (version 3.3.8 and later) include
|
||||
** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8]
|
||||
** and later) include
|
||||
** support for additional result codes that provide more detailed information
|
||||
** about errors. These [extended result codes] are enabled or disabled
|
||||
** on a per database connection basis using the
|
||||
@@ -976,6 +978,12 @@ struct sqlite3_io_methods {
|
||||
** on whether or not the file has been renamed, moved, or deleted since it
|
||||
** was first opened.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_WIN32_GET_HANDLE]]
|
||||
** The [SQLITE_FCNTL_WIN32_GET_HANDLE] opcode can be used to obtain the
|
||||
** underlying native file handle associated with a file handle. This file
|
||||
** control interprets its argument as a pointer to a native file handle and
|
||||
** writes the resulting value there.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_WIN32_SET_HANDLE]]
|
||||
** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This
|
||||
** opcode causes the xFileControl method to swap the file handle with the one
|
||||
@@ -1026,6 +1034,8 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_RBU 26
|
||||
#define SQLITE_FCNTL_VFS_POINTER 27
|
||||
#define SQLITE_FCNTL_JOURNAL_POINTER 28
|
||||
#define SQLITE_FCNTL_WIN32_GET_HANDLE 29
|
||||
#define SQLITE_FCNTL_PDB 30
|
||||
|
||||
/* deprecated names */
|
||||
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
||||
@@ -1969,13 +1979,36 @@ struct sqlite3_mem_methods {
|
||||
** be a NULL pointer, in which case the new setting is not reported back.
|
||||
** </dd>
|
||||
**
|
||||
** <dt>SQLITE_DBCONFIG_MAINDBNAME</dt>
|
||||
** <dd> ^This option is used to change the name of the "main" database
|
||||
** schema. ^The sole argument is a pointer to a constant UTF8 string
|
||||
** which will become the new schema name in place of "main". ^SQLite
|
||||
** does not make a copy of the new main schema name string, so the application
|
||||
** must ensure that the argument passed into this DBCONFIG option is unchanged
|
||||
** until after the database connection closes.
|
||||
** </dd>
|
||||
**
|
||||
** <dt>SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE</dt>
|
||||
** <dd> Usually, when a database in wal mode is closed or detached from a
|
||||
** database handle, SQLite checks if this will mean that there are now no
|
||||
** connections at all to the database. If so, it performs a checkpoint
|
||||
** operation before closing the connection. This option may be used to
|
||||
** override this behaviour. The first parameter passed to this operation
|
||||
** is an integer - non-zero to disable checkpoints-on-close, or zero (the
|
||||
** default) to enable them. The second parameter is a pointer to an integer
|
||||
** into which is written 0 or 1 to indicate whether checkpoints-on-close
|
||||
** have been disabled - 0 if they are not disabled, 1 if they are.
|
||||
** </dd>
|
||||
**
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
|
||||
#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
|
||||
#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
|
||||
#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
|
||||
#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */
|
||||
#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
|
||||
#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */
|
||||
|
||||
|
||||
/*
|
||||
@@ -3577,6 +3610,10 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
|
||||
** sqlite3_stmt_readonly() to return true since, while those statements
|
||||
** change the configuration of a database connection, they do not make
|
||||
** changes to the content of the database files on disk.
|
||||
** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since
|
||||
** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and
|
||||
** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so
|
||||
** sqlite3_stmt_readonly() returns false for those commands.
|
||||
*/
|
||||
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
|
||||
|
||||
@@ -4041,7 +4078,8 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
|
||||
** other than [SQLITE_ROW] before any subsequent invocation of
|
||||
** sqlite3_step(). Failure to reset the prepared statement using
|
||||
** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
|
||||
** sqlite3_step(). But after version 3.6.23.1, sqlite3_step() began
|
||||
** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1],
|
||||
** sqlite3_step() began
|
||||
** calling [sqlite3_reset()] automatically in this circumstance rather
|
||||
** than returning [SQLITE_MISUSE]. This is not considered a compatibility
|
||||
** break because any application that ever receives an SQLITE_MISUSE error
|
||||
@@ -5404,7 +5442,8 @@ SQLITE_API void *sqlite3_update_hook(
|
||||
** and disabled if the argument is false.)^
|
||||
**
|
||||
** ^Cache sharing is enabled and disabled for an entire process.
|
||||
** This is a change as of SQLite version 3.5.0. In prior versions of SQLite,
|
||||
** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
|
||||
** In prior versions of SQLite,
|
||||
** sharing was enabled or disabled for each thread separately.
|
||||
**
|
||||
** ^(The cache sharing mode set by this interface effects all subsequent
|
||||
@@ -5498,7 +5537,8 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
|
||||
** from the heap.
|
||||
** </ul>)^
|
||||
**
|
||||
** Beginning with SQLite version 3.7.3, the soft heap limit is enforced
|
||||
** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]),
|
||||
** the soft heap limit is enforced
|
||||
** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
|
||||
** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
|
||||
** the soft heap limit is enforced on every memory allocation. Without
|
||||
@@ -5892,13 +5932,15 @@ struct sqlite3_module {
|
||||
** the xUpdate method are automatically rolled back by SQLite.
|
||||
**
|
||||
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
|
||||
** structure for SQLite version 3.8.2. If a virtual table extension is
|
||||
** structure for SQLite [version 3.8.2] ([dateof:3.8.2]).
|
||||
** If a virtual table extension is
|
||||
** used with an SQLite version earlier than 3.8.2, the results of attempting
|
||||
** to read or write the estimatedRows field are undefined (but are likely
|
||||
** to included crashing the application). The estimatedRows field should
|
||||
** therefore only be used if [sqlite3_libversion_number()] returns a
|
||||
** value greater than or equal to 3008002. Similarly, the idxFlags field
|
||||
** was added for version 3.9.0. It may therefore only be used if
|
||||
** was added for [version 3.9.0] ([dateof:3.9.0]).
|
||||
** It may therefore only be used if
|
||||
** sqlite3_libversion_number() returns a value greater than or equal to
|
||||
** 3009000.
|
||||
*/
|
||||
@@ -6596,7 +6638,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
|
||||
#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */
|
||||
#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */
|
||||
#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
|
||||
#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */
|
||||
#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_randomness() */
|
||||
#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
|
||||
#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
|
||||
#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
|
||||
@@ -6700,6 +6742,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
|
||||
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
|
||||
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
|
||||
#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
|
||||
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
|
||||
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
|
||||
#define SQLITE_TESTCTRL_BYTEORDER 22
|
||||
@@ -8186,7 +8229,8 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
|
||||
**
|
||||
** See also: [sqlite3_update_hook()]
|
||||
*/
|
||||
SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_preupdate_hook(
|
||||
#if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
|
||||
SQLITE_API void *sqlite3_preupdate_hook(
|
||||
sqlite3 *db,
|
||||
void(*xPreUpdate)(
|
||||
void *pCtx, /* Copy of third arg to preupdate_hook() */
|
||||
@@ -8199,10 +8243,11 @@ SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_preupdate_hook(
|
||||
),
|
||||
void*
|
||||
);
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_count(sqlite3 *);
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_depth(sqlite3 *);
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
|
||||
SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
|
||||
SQLITE_API int sqlite3_preupdate_count(sqlite3 *);
|
||||
SQLITE_API int sqlite3_preupdate_depth(sqlite3 *);
|
||||
SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
|
||||
#endif
|
||||
|
||||
/*
|
||||
** CAPI3REF: Low-level system error code
|
||||
@@ -8218,7 +8263,7 @@ SQLITE_API int sqlite3_system_errno(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Database Snapshot
|
||||
** KEYWORDS: {snapshot}
|
||||
** KEYWORDS: {snapshot} {sqlite3_snapshot}
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** An instance of the snapshot object records the state of a [WAL mode]
|
||||
@@ -8242,7 +8287,9 @@ SQLITE_API int sqlite3_system_errno(sqlite3*);
|
||||
** to an historical snapshot (if possible). The destructor for
|
||||
** sqlite3_snapshot objects is [sqlite3_snapshot_free()].
|
||||
*/
|
||||
typedef struct sqlite3_snapshot sqlite3_snapshot;
|
||||
typedef struct sqlite3_snapshot {
|
||||
unsigned char hidden[48];
|
||||
} sqlite3_snapshot;
|
||||
|
||||
/*
|
||||
** CAPI3REF: Record A Database Snapshot
|
||||
@@ -8253,9 +8300,32 @@ typedef struct sqlite3_snapshot sqlite3_snapshot;
|
||||
** schema S in database connection D. ^On success, the
|
||||
** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
|
||||
** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
|
||||
** ^If schema S of [database connection] D is not a [WAL mode] database
|
||||
** that is in a read transaction, then [sqlite3_snapshot_get(D,S,P)]
|
||||
** leaves the *P value unchanged and returns an appropriate [error code].
|
||||
** If there is not already a read-transaction open on schema S when
|
||||
** this function is called, one is opened automatically.
|
||||
**
|
||||
** The following must be true for this function to succeed. If any of
|
||||
** the following statements are false when sqlite3_snapshot_get() is
|
||||
** called, SQLITE_ERROR is returned. The final value of *P is undefined
|
||||
** in this case.
|
||||
**
|
||||
** <ul>
|
||||
** <li> The database handle must be in [autocommit mode].
|
||||
**
|
||||
** <li> Schema S of [database connection] D must be a [WAL mode] database.
|
||||
**
|
||||
** <li> There must not be a write transaction open on schema S of database
|
||||
** connection D.
|
||||
**
|
||||
** <li> One or more transactions must have been written to the current wal
|
||||
** file since it was created on disk (by any connection). This means
|
||||
** that a snapshot cannot be taken on a wal mode database with no wal
|
||||
** file immediately after it is first opened. At least one transaction
|
||||
** must be written to it first.
|
||||
** </ul>
|
||||
**
|
||||
** This function may also return SQLITE_NOMEM. If it is called with the
|
||||
** database handle in autocommit mode but fails for some other reason,
|
||||
** whether or not a read transaction is opened on schema S is undefined.
|
||||
**
|
||||
** The [sqlite3_snapshot] object returned from a successful call to
|
||||
** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()]
|
||||
@@ -8348,6 +8418,28 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
|
||||
sqlite3_snapshot *p2
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Recover snapshots from a wal file
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** If all connections disconnect from a database file but do not perform
|
||||
** a checkpoint, the existing wal file is opened along with the database
|
||||
** file the next time the database is opened. At this point it is only
|
||||
** possible to successfully call sqlite3_snapshot_open() to open the most
|
||||
** recent snapshot of the database (the one at the head of the wal file),
|
||||
** even though the wal file may contain other valid snapshots for which
|
||||
** clients have sqlite3_snapshot handles.
|
||||
**
|
||||
** This function attempts to scan the wal file associated with database zDb
|
||||
** of database handle db and make all valid snapshots available to
|
||||
** sqlite3_snapshot_open(). It is an error if there is already a read
|
||||
** transaction open on the database, or if the database is not a wal mode
|
||||
** database.
|
||||
**
|
||||
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
|
||||
*/
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
|
||||
|
||||
/*
|
||||
** Undo the hack that converts floating point types to integer for
|
||||
** builds on processors without floating point support.
|
||||
@@ -8639,7 +8731,7 @@ int sqlite3session_attach(
|
||||
** CAPI3REF: Set a table filter on a Session Object.
|
||||
**
|
||||
** The second argument (xFilter) is the "filter callback". For changes to rows
|
||||
** in tables that are not attached to the Session oject, the filter is called
|
||||
** in tables that are not attached to the Session object, the filter is called
|
||||
** to determine whether changes to the table's rows should be tracked or not.
|
||||
** If xFilter returns 0, changes is not tracked. Note that once a table is
|
||||
** attached, xFilter will not be called again.
|
||||
@@ -8905,7 +8997,7 @@ int sqlite3session_isempty(sqlite3_session *pSession);
|
||||
** [sqlite3changeset_invert()] functions, all changes within the changeset
|
||||
** that apply to a single table are grouped together. This means that when
|
||||
** an application iterates through a changeset using an iterator created by
|
||||
** this function, all changes that relate to a single table are visted
|
||||
** this function, all changes that relate to a single table are visited
|
||||
** consecutively. There is no chance that the iterator will visit a change
|
||||
** the applies to table X, then one for table Y, and then later on visit
|
||||
** another change for table X.
|
||||
@@ -8992,7 +9084,7 @@ int sqlite3changeset_op(
|
||||
** 0x01 if the corresponding column is part of the tables primary key, or
|
||||
** 0x00 if it is not.
|
||||
**
|
||||
** If argumet pnCol is not NULL, then *pnCol is set to the number of columns
|
||||
** If argument pnCol is not NULL, then *pnCol is set to the number of columns
|
||||
** in the table.
|
||||
**
|
||||
** If this function is called when the iterator does not point to a valid
|
||||
@@ -9209,12 +9301,12 @@ int sqlite3changeset_concat(
|
||||
|
||||
|
||||
/*
|
||||
** Changegroup handle.
|
||||
** CAPI3REF: Changegroup Handle
|
||||
*/
|
||||
typedef struct sqlite3_changegroup sqlite3_changegroup;
|
||||
|
||||
/*
|
||||
** CAPI3REF: Combine two or more changesets into a single changeset.
|
||||
** CAPI3REF: Create A New Changegroup Object
|
||||
**
|
||||
** An sqlite3_changegroup object is used to combine two or more changesets
|
||||
** (or patchsets) into a single changeset (or patchset). A single changegroup
|
||||
@@ -9251,6 +9343,8 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
|
||||
int sqlite3changegroup_new(sqlite3_changegroup **pp);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Add A Changeset To A Changegroup
|
||||
**
|
||||
** Add all changes within the changeset (or patchset) in buffer pData (size
|
||||
** nData bytes) to the changegroup.
|
||||
**
|
||||
@@ -9265,7 +9359,7 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp);
|
||||
** apply to the same row as a change already present in the changegroup if
|
||||
** the two rows have the same primary key.
|
||||
**
|
||||
** Changes to rows that that do not already appear in the changegroup are
|
||||
** Changes to rows that do not already appear in the changegroup are
|
||||
** simply copied into it. Or, if both the new changeset and the changegroup
|
||||
** contain changes that apply to a single row, the final contents of the
|
||||
** changegroup depends on the type of each change, as follows:
|
||||
@@ -9326,6 +9420,8 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp);
|
||||
int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Obtain A Composite Changeset From A Changegroup
|
||||
**
|
||||
** Obtain a buffer containing a changeset (or patchset) representing the
|
||||
** current contents of the changegroup. If the inputs to the changegroup
|
||||
** were themselves changesets, the output is a changeset. Or, if the
|
||||
@@ -9354,7 +9450,7 @@ int sqlite3changegroup_output(
|
||||
);
|
||||
|
||||
/*
|
||||
** Delete a changegroup object.
|
||||
** CAPI3REF: Delete A Changegroup Object
|
||||
*/
|
||||
void sqlite3changegroup_delete(sqlite3_changegroup*);
|
||||
|
||||
|
||||
+2
-2
@@ -121,7 +121,7 @@ QString queryPassword(const QString &user)
|
||||
class HttpCredentialsText : public HttpCredentials {
|
||||
public:
|
||||
HttpCredentialsText(const QString& user, const QString& password)
|
||||
: HttpCredentials(user, password, "", ""), // FIXME: not working with client certs yet (qknight)
|
||||
: HttpCredentials(user, password), // FIXME: not working with client certs yet (qknight)
|
||||
_sslTrusted(false)
|
||||
{}
|
||||
|
||||
@@ -507,7 +507,7 @@ restart_sync:
|
||||
|
||||
app.exec();
|
||||
|
||||
if (engine.isAnotherSyncNeeded()) {
|
||||
if (engine.isAnotherSyncNeeded() != NoFollowUpSync) {
|
||||
if (restartCount < options.restartTimes) {
|
||||
restartCount++;
|
||||
qDebug() << "Restarting Sync, because another sync is needed" << restartCount;
|
||||
|
||||
@@ -151,7 +151,6 @@ set(3rdparty_SRC
|
||||
../3rdparty/qtsingleapplication/qtlocalpeer.cpp
|
||||
../3rdparty/qtsingleapplication/qtsingleapplication.cpp
|
||||
../3rdparty/qtsingleapplication/qtsinglecoreapplication.cpp
|
||||
../3rdparty/certificates/p12topem.cpp
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
|
||||
@@ -214,6 +214,17 @@ AccountPtr AccountManager::loadAccountHelper(QSettings& settings)
|
||||
auto acc = createAccount();
|
||||
|
||||
QString authType = settings.value(QLatin1String(authTypeC)).toString();
|
||||
|
||||
// There was an account-type saving bug when 'skip folder config' was used
|
||||
// See #5408. This attempts to fix up the "dummy" authType
|
||||
if (authType == QLatin1String("dummy")) {
|
||||
if (settings.contains(QLatin1String("http_user"))) {
|
||||
authType = "http";
|
||||
} else if (settings.contains(QLatin1String("shibboleth_shib_user"))) {
|
||||
authType = "shibboleth";
|
||||
}
|
||||
}
|
||||
|
||||
QString overrideUrl = Theme::instance()->overrideServerUrl();
|
||||
QString forceAuth = Theme::instance()->forceConfigAuthType();
|
||||
if(!forceAuth.isEmpty() && !overrideUrl.isEmpty() ) {
|
||||
@@ -237,7 +248,7 @@ AccountPtr AccountManager::loadAccountHelper(QSettings& settings)
|
||||
|
||||
acc->setCredentials(CredentialsFactory::create(authType));
|
||||
|
||||
// now the cert, it is in the general group
|
||||
// now the server cert, it is in the general group
|
||||
settings.beginGroup(QLatin1String("General"));
|
||||
acc->setApprovedCerts(QSslCertificate::fromData(settings.value(caCertsKeyC).toByteArray()));
|
||||
settings.endGroup();
|
||||
|
||||
@@ -214,8 +214,10 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
|
||||
}
|
||||
|
||||
tv->setCurrentIndex(index);
|
||||
QString alias = _model->data( index, FolderStatusDelegate::FolderAliasRole ).toString();
|
||||
bool folderPaused = _model->data( index, FolderStatusDelegate::FolderSyncPaused).toBool();
|
||||
bool folderConnected = _model->data( index, FolderStatusDelegate::FolderAccountConnected ).toBool();
|
||||
auto folderMan = FolderMan::instance();
|
||||
|
||||
QMenu *menu = new QMenu(tv);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
@@ -231,6 +233,10 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
|
||||
|
||||
if (!folderPaused) {
|
||||
ac = menu->addAction(tr("Force sync now"));
|
||||
if (folderMan->currentSyncFolder() == folderMan->folder(alias)) {
|
||||
ac->setText(tr("Restart sync"));
|
||||
}
|
||||
ac->setEnabled(folderConnected);
|
||||
connect(ac, SIGNAL(triggered(bool)), this, SLOT(slotForceSyncCurrentFolder()));
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>462</width>
|
||||
<height>186</height>
|
||||
<height>188</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -32,7 +32,7 @@
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelCertificateFile">
|
||||
<property name="text">
|
||||
<string>Certificate :</string>
|
||||
<string>Certificate & Key (pkcs12) :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -347,14 +347,6 @@ void Application::slotownCloudWizardDone( int res )
|
||||
}
|
||||
}
|
||||
|
||||
static void csyncLogCatcher(int /*verbosity*/,
|
||||
const char */*function*/,
|
||||
const char *buffer,
|
||||
void */*userdata*/)
|
||||
{
|
||||
Logger::instance()->csyncLog( QString::fromUtf8(buffer) );
|
||||
}
|
||||
|
||||
void Application::setupLogging()
|
||||
{
|
||||
// might be called from second instance
|
||||
@@ -370,10 +362,6 @@ void Application::setupLogging()
|
||||
.arg(property("ui_lang").toString())
|
||||
.arg(_theme->version())
|
||||
.arg(Utility::platformName());
|
||||
|
||||
// Setup CSYNC logging to forward to our own logger
|
||||
csync_set_log_callback( csyncLogCatcher );
|
||||
csync_set_log_level( Logger::instance()->isNoop() ? 0 : 11 );
|
||||
}
|
||||
|
||||
void Application::slotUseMonoIconsChanged(bool)
|
||||
|
||||
@@ -27,7 +27,7 @@ class HttpCredentialsGui : public HttpCredentials {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit HttpCredentialsGui() : HttpCredentials() {}
|
||||
HttpCredentialsGui(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd) : HttpCredentials(user, password, certificatePath, certificatePasswd) {}
|
||||
HttpCredentialsGui(const QString& user, const QString& password, const QSslCertificate& certificate, const QSslKey& key) : HttpCredentials(user, password, certificate, key) {}
|
||||
void askFromUser() Q_DECL_OVERRIDE;
|
||||
Q_INVOKABLE void askFromUserAsync();
|
||||
|
||||
|
||||
@@ -65,9 +65,6 @@ Folder::Folder(const FolderDefinition& definition,
|
||||
, _fileLog(new SyncRunFileLog)
|
||||
, _saveBackwardsCompatible(false)
|
||||
{
|
||||
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
|
||||
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
|
||||
|
||||
qsrand(QTime::currentTime().msec());
|
||||
_timeSinceLastSyncStart.start();
|
||||
_timeSinceLastSyncDone.start();
|
||||
@@ -826,7 +823,7 @@ void Folder::slotSyncFinished(bool success)
|
||||
_fileLog->finish();
|
||||
bubbleUpSyncResult();
|
||||
|
||||
bool anotherSyncNeeded = _engine->isAnotherSyncNeeded();
|
||||
auto anotherSyncNeeded = _engine->isAnotherSyncNeeded();
|
||||
|
||||
if (_csyncError) {
|
||||
_syncResult.setStatus(SyncResult::Error);
|
||||
@@ -877,7 +874,7 @@ void Folder::slotSyncFinished(bool success)
|
||||
_timeSinceLastSyncDone.restart();
|
||||
|
||||
// Increment the follow-up sync counter if necessary.
|
||||
if (anotherSyncNeeded) {
|
||||
if (anotherSyncNeeded == ImmediateFollowUp) {
|
||||
_consecutiveFollowUpSyncs++;
|
||||
qDebug() << "another sync was requested by the finished sync, this has"
|
||||
<< "happened" << _consecutiveFollowUpSyncs << "times";
|
||||
@@ -886,7 +883,7 @@ void Folder::slotSyncFinished(bool success)
|
||||
}
|
||||
|
||||
// Maybe force a follow-up sync to take place, but only a couple of times.
|
||||
if (anotherSyncNeeded && _consecutiveFollowUpSyncs <= 3)
|
||||
if (anotherSyncNeeded == ImmediateFollowUp && _consecutiveFollowUpSyncs <= 3)
|
||||
{
|
||||
// Sometimes another sync is requested because a local file is still
|
||||
// changing, so wait at least a small amount of time before syncing
|
||||
|
||||
+17
-10
@@ -148,6 +148,7 @@ int FolderMan::unloadAndDeleteAllFolders()
|
||||
void FolderMan::registerFolderMonitor( Folder *folder )
|
||||
{
|
||||
if( !folder ) return;
|
||||
if( !QDir(folder->path()).exists() ) return;
|
||||
|
||||
if( !_folderWatchers.contains(folder->alias() ) ) {
|
||||
FolderWatcher *fw = new FolderWatcher(folder->path(), folder);
|
||||
@@ -730,6 +731,10 @@ void FolderMan::slotStartScheduledFolderSync()
|
||||
|
||||
// Start syncing this folder!
|
||||
if( folder ) {
|
||||
// Safe to call several times, and necessary to try again if
|
||||
// the folder path didn't exist previously.
|
||||
registerFolderMonitor(folder);
|
||||
|
||||
_currentSyncFolder = folder;
|
||||
folder->startSync( QStringList() );
|
||||
}
|
||||
@@ -833,18 +838,20 @@ void FolderMan::slotScheduleFolderByTime()
|
||||
continue;
|
||||
}
|
||||
|
||||
// Retry a couple of times after failure
|
||||
bool syncAgainAfterFail = f->consecutiveFailingSyncs() > 0 && f->consecutiveFailingSyncs() < 3;
|
||||
qint64 syncAgainAfterFailDelay = 10 * 1000; // 10s for the first retry-after-fail
|
||||
// Retry a couple of times after failure; or regularly if requested
|
||||
bool syncAgain =
|
||||
(f->consecutiveFailingSyncs() > 0 && f->consecutiveFailingSyncs() < 3)
|
||||
|| f->syncEngine().isAnotherSyncNeeded() == DelayedFollowUp;
|
||||
qint64 syncAgainDelay = 10 * 1000; // 10s for the first retry-after-fail
|
||||
if (f->consecutiveFailingSyncs() > 1)
|
||||
syncAgainAfterFailDelay = 60 * 1000; // 60s for each further attempt
|
||||
if (syncAgainAfterFail
|
||||
&& msecsSinceSync > syncAgainAfterFailDelay) {
|
||||
syncAgainDelay = 60 * 1000; // 60s for each further attempt
|
||||
if (syncAgain
|
||||
&& msecsSinceSync > syncAgainDelay) {
|
||||
qDebug() << "** scheduling folder" << f->alias()
|
||||
<< "because the last"
|
||||
<< f->consecutiveFailingSyncs() << "syncs failed, last status:"
|
||||
<< f->syncResult().statusString()
|
||||
<< "time since last sync:" << msecsSinceSync;
|
||||
<< ", the last" << f->consecutiveFailingSyncs() << "syncs failed"
|
||||
<< ", anotherSyncNeeded" << f->syncEngine().isAnotherSyncNeeded()
|
||||
<< ", last status:" << f->syncResult().statusString()
|
||||
<< ", time since last sync:" << msecsSinceSync;
|
||||
|
||||
scheduleFolder(f);
|
||||
continue;
|
||||
|
||||
@@ -527,10 +527,8 @@ void FolderStatusModel::fetchMore(const QModelIndex& parent)
|
||||
|
||||
if (!info || info->_fetched || info->_fetching)
|
||||
return;
|
||||
|
||||
info->_hasError = false;
|
||||
info->resetSubs(this, parent);
|
||||
info->_fetching = true;
|
||||
info->_fetchingLabel = false;
|
||||
QString path = info->_folder->remotePath();
|
||||
if (info->_path != QLatin1String("/")) {
|
||||
if (!path.endsWith(QLatin1Char('/'))) {
|
||||
@@ -698,17 +696,16 @@ void FolderStatusModel::slotLscolFinishedWithError(QNetworkReply* r)
|
||||
qDebug() << r->errorString();
|
||||
parentInfo->_lastErrorString = r->errorString();
|
||||
|
||||
parentInfo->resetSubs(this, idx);
|
||||
|
||||
if (r->error() == QNetworkReply::ContentNotFoundError) {
|
||||
parentInfo->_fetched = true;
|
||||
} else {
|
||||
if (!parentInfo->hasLabel()) {
|
||||
beginInsertRows(idx, 0, 0);
|
||||
endInsertRows();
|
||||
}
|
||||
Q_ASSERT(!parentInfo->hasLabel());
|
||||
beginInsertRows(idx, 0, 0);
|
||||
parentInfo->_hasError = true;
|
||||
endInsertRows();
|
||||
}
|
||||
parentInfo->_fetching = false;
|
||||
parentInfo->_fetchingLabel = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -110,8 +110,9 @@ LogBrowser::LogBrowser(QWidget *parent) :
|
||||
|
||||
setModal(false);
|
||||
|
||||
Logger::instance()->setLogWindowActivated(true);
|
||||
// Direct connection for log coming from this thread, and queued for the one in a different thread
|
||||
connect(Logger::instance(), SIGNAL(newLog(QString)),this,SLOT(slotNewLog(QString)), Qt::AutoConnection);
|
||||
connect(Logger::instance(), SIGNAL(logWindowLog(QString)),this,SLOT(slotNewLog(QString)), Qt::AutoConnection);
|
||||
|
||||
QAction *showLogWindow = new QAction(this);
|
||||
showLogWindow->setShortcut(QKeySequence("F12"));
|
||||
|
||||
@@ -207,10 +207,15 @@ void OwncloudSetupWizard::slotNoOwnCloudFoundAuth(QNetworkReply *reply)
|
||||
QString contentType = reply->header(QNetworkRequest::ContentTypeHeader).toString();
|
||||
|
||||
// Do this early because reply might be deleted in message box event loop
|
||||
QString msg = tr("Failed to connect to %1 at %2:<br/>%3")
|
||||
QString msg;
|
||||
if (!_ocWizard->account()->url().isValid()) {
|
||||
msg = tr("Invalid URL");
|
||||
} else {
|
||||
msg = tr("Failed to connect to %1 at %2:<br/>%3")
|
||||
.arg(Theme::instance()->appNameGUI(),
|
||||
reply->url().toString(),
|
||||
reply->errorString());
|
||||
}
|
||||
bool isDowngradeAdvised = checkDowngradeAdvised(reply);
|
||||
|
||||
// If a client cert is needed, nginx sends:
|
||||
@@ -553,6 +558,13 @@ void OwncloudSetupWizard::slotSkipFolderConfiguration()
|
||||
AccountState *OwncloudSetupWizard::applyAccountChanges()
|
||||
{
|
||||
AccountPtr newAccount = _ocWizard->account();
|
||||
|
||||
// Detach the account that is going to be saved from the
|
||||
// wizard to ensure it doesn't accidentally get modified
|
||||
// later (such as from running cleanup such as
|
||||
// AbstractCredentialsWizardPage::cleanupPage())
|
||||
_ocWizard->setAccount(AccountManager::createAccount());
|
||||
|
||||
auto manager = AccountManager::instance();
|
||||
|
||||
auto newState = manager->addAccount(newAccount);
|
||||
|
||||
@@ -29,8 +29,11 @@ OwncloudConnectionMethodDialog::OwncloudConnectionMethodDialog(QWidget *parent)
|
||||
connect(ui->btnClientSideTLS, SIGNAL(clicked(bool)), this, SLOT(returnClientSideTLS()));
|
||||
connect(ui->btnBack, SIGNAL(clicked(bool)), this, SLOT(returnBack()));
|
||||
|
||||
// DM: TLS Client Cert GUI support disabled for now
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 4, 0)
|
||||
// We support only from Qt 5.4.x because of https://doc.qt.io/qt-5/qsslcertificate.html#importPkcs12
|
||||
ui->btnClientSideTLS->hide();
|
||||
#endif
|
||||
}
|
||||
|
||||
void OwncloudConnectionMethodDialog::setUrl(const QUrl &url)
|
||||
|
||||
@@ -192,7 +192,7 @@ void OwncloudHttpCredsPage::setErrorString(const QString& err)
|
||||
|
||||
AbstractCredentials* OwncloudHttpCredsPage::getCredentials() const
|
||||
{
|
||||
return new HttpCredentialsGui(_ui.leUsername->text(), _ui.lePassword->text(), _ocWizard->ownCloudCertificatePath, _ocWizard->ownCloudCertificatePasswd);
|
||||
return new HttpCredentialsGui(_ui.leUsername->text(), _ui.lePassword->text(), _ocWizard->_clientSslCertificate, _ocWizard->_clientSslKey);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
#include <QMessageBox>
|
||||
#include <QSsl>
|
||||
#include <QSslCertificate>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
#include "QProgressIndicator.h"
|
||||
|
||||
#include "wizard/owncloudwizardcommon.h"
|
||||
#include "wizard/owncloudsetuppage.h"
|
||||
#include "wizard/owncloudconnectionmethoddialog.h"
|
||||
#include "../3rdparty/certificates/p12topem.h"
|
||||
#include "theme.h"
|
||||
#include "account.h"
|
||||
|
||||
@@ -71,7 +71,6 @@ OwncloudSetupPage::OwncloudSetupPage(QWidget *parent)
|
||||
connect(_ui.leUrl, SIGNAL(editingFinished()), SLOT(slotUrlEditFinished()));
|
||||
|
||||
addCertDial = new AddCertificateDialog(this);
|
||||
connect(_ocWizard,SIGNAL(needCertificate()),this,SLOT(slotAskSSLClientCertificate()));
|
||||
}
|
||||
|
||||
void OwncloudSetupPage::setServerUrl( const QString& newUrl )
|
||||
@@ -139,7 +138,7 @@ void OwncloudSetupPage::slotUrlChanged(const QString& url)
|
||||
void OwncloudSetupPage::slotUrlEditFinished()
|
||||
{
|
||||
QString url = _ui.leUrl->fullText();
|
||||
if (QUrl(url).isRelative()) {
|
||||
if (QUrl(url).isRelative() && !url.isEmpty()) {
|
||||
// no scheme defined, set one
|
||||
url.prepend("https://");
|
||||
}
|
||||
@@ -269,7 +268,10 @@ void OwncloudSetupPage::setErrorString( const QString& err, bool retryHTTPonly )
|
||||
}
|
||||
break;
|
||||
case OwncloudConnectionMethodDialog::Client_Side_TLS:
|
||||
slotAskSSLClientCertificate();
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
|
||||
addCertDial->show();
|
||||
connect(addCertDial, SIGNAL(accepted()),this,SLOT(slotCertificateAccepted()));
|
||||
#endif
|
||||
break;
|
||||
case OwncloudConnectionMethodDialog::Closed:
|
||||
case OwncloudConnectionMethodDialog::Back:
|
||||
@@ -302,12 +304,6 @@ void OwncloudSetupPage::stopSpinner()
|
||||
_progressIndi->stopAnimation();
|
||||
}
|
||||
|
||||
void OwncloudSetupPage::slotAskSSLClientCertificate()
|
||||
{
|
||||
addCertDial->show();
|
||||
connect(addCertDial, SIGNAL(accepted()),this,SLOT(slotCertificateAccepted()));
|
||||
}
|
||||
|
||||
QString subjectInfoHelper(const QSslCertificate& cert, const QByteArray &qa)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||
@@ -320,36 +316,40 @@ QString subjectInfoHelper(const QSslCertificate& cert, const QByteArray &qa)
|
||||
//called during the validation of the client certificate.
|
||||
void OwncloudSetupPage::slotCertificateAccepted()
|
||||
{
|
||||
QSslCertificate sslCertificate;
|
||||
|
||||
resultP12ToPem certif = p12ToPem(addCertDial->getCertificatePath().toStdString() , addCertDial->getCertificatePasswd().toStdString());
|
||||
if(certif.ReturnCode){
|
||||
QString s = QString::fromStdString(certif.Certificate);
|
||||
QByteArray ba = s.toLocal8Bit();
|
||||
|
||||
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(ba, QSsl::Pem);
|
||||
sslCertificate = sslCertificateList.takeAt(0);
|
||||
|
||||
_ocWizard->ownCloudCertificate = ba;
|
||||
_ocWizard->ownCloudPrivateKey = certif.PrivateKey.c_str();
|
||||
_ocWizard->ownCloudCertificatePath = addCertDial->getCertificatePath();
|
||||
_ocWizard->ownCloudCertificatePasswd = addCertDial->getCertificatePasswd();
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
|
||||
QList<QSslCertificate> clientCaCertificates;
|
||||
QFile certFile(addCertDial->getCertificatePath());
|
||||
certFile.open(QFile::ReadOnly);
|
||||
if(QSslCertificate::importPkcs12(&certFile,
|
||||
&_ocWizard->_clientSslKey, &_ocWizard->_clientSslCertificate,
|
||||
&clientCaCertificates,
|
||||
addCertDial->getCertificatePasswd().toLocal8Bit())){
|
||||
AccountPtr acc = _ocWizard->account();
|
||||
acc->setCertificate(_ocWizard->ownCloudCertificate, _ocWizard->ownCloudPrivateKey);
|
||||
addCertDial->reinit();
|
||||
|
||||
// to re-create the session ticket because we added a key/cert
|
||||
acc->setSslConfiguration(QSslConfiguration());
|
||||
QSslConfiguration sslConfiguration = acc->getOrCreateSslConfig();
|
||||
|
||||
// We're stuffing the certificate into the configuration form here. Later the
|
||||
// cert will come via the HttpCredentials
|
||||
sslConfiguration.setLocalCertificate(_ocWizard->_clientSslCertificate);
|
||||
sslConfiguration.setPrivateKey(_ocWizard->_clientSslKey);
|
||||
acc->setSslConfiguration(sslConfiguration);
|
||||
|
||||
// Make sure TCP connections get re-established
|
||||
acc->networkAccessManager()->clearAccessCache();
|
||||
|
||||
addCertDial->reinit(); // FIXME: Why not just have this only created on use?
|
||||
validatePage();
|
||||
} else {
|
||||
QString message;
|
||||
message = certif.Comment.c_str();
|
||||
addCertDial->showErrorMessage(message);
|
||||
addCertDial->showErrorMessage("Could not load certificate");
|
||||
addCertDial->show();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
OwncloudSetupPage::~OwncloudSetupPage()
|
||||
{
|
||||
delete addCertDial;
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
@@ -59,7 +59,6 @@ public slots:
|
||||
void setErrorString( const QString&, bool retryHTTPonly );
|
||||
void startSpinner();
|
||||
void stopSpinner();
|
||||
void slotAskSSLClientCertificate();
|
||||
void slotCertificateAccepted();
|
||||
|
||||
protected slots:
|
||||
|
||||
@@ -224,11 +224,4 @@ AbstractCredentials* OwncloudWizard::getCredentials() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
// outputs the signal needed to authenticate a certificate
|
||||
void OwncloudWizard::raiseCertificatePopup()
|
||||
{
|
||||
emit needCertificate();
|
||||
}
|
||||
|
||||
|
||||
} // end namespace
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#define MIRALL_OWNCLOUD_WIZARD_H
|
||||
|
||||
#include <QWizard>
|
||||
#include <QSslKey>
|
||||
#include <QSslCertificate>
|
||||
|
||||
#include "wizard/owncloudwizardcommon.h"
|
||||
#include "accountfwd.h"
|
||||
@@ -63,11 +65,10 @@ public:
|
||||
void displayError( const QString&, bool retryHTTPonly);
|
||||
AbstractCredentials* getCredentials() const;
|
||||
|
||||
void raiseCertificatePopup();
|
||||
QByteArray ownCloudCertificate;
|
||||
QString ownCloudPrivateKey;
|
||||
QString ownCloudCertificatePath;
|
||||
QString ownCloudCertificatePasswd;
|
||||
// FIXME: Can those be local variables?
|
||||
// Set from the OwncloudSetupPage, later used from OwncloudHttpCredsPage
|
||||
QSslKey _clientSslKey;
|
||||
QSslCertificate _clientSslCertificate;
|
||||
|
||||
public slots:
|
||||
void setAuthType(WizardCommon::AuthType type);
|
||||
|
||||
@@ -70,7 +70,6 @@ set(libsync_SRCS
|
||||
creds/abstractcredentials.cpp
|
||||
creds/credentialscommon.cpp
|
||||
../3rdparty/qjson/json.cpp
|
||||
../3rdparty/certificates/p12topem.cpp
|
||||
)
|
||||
|
||||
if(TOKEN_AUTH_ONLY)
|
||||
|
||||
+11
-33
@@ -18,7 +18,6 @@
|
||||
#include "configfile.h"
|
||||
#include "accessmanager.h"
|
||||
#include "creds/abstractcredentials.h"
|
||||
#include "../3rdparty/certificates/p12topem.h"
|
||||
#include "capabilities.h"
|
||||
#include "theme.h"
|
||||
|
||||
@@ -93,7 +92,7 @@ void Account::setDavUser(const QString &newDavUser)
|
||||
|
||||
QString Account::displayName() const
|
||||
{
|
||||
QString dn = QString("%1@%2").arg(davUser(), _url.host());
|
||||
QString dn = QString("%1@%2").arg(_credentials->user(), _url.host());
|
||||
int port = url().port();
|
||||
if (port > 0 && port != 80 && port != 443) {
|
||||
dn.append(QLatin1Char(':'));
|
||||
@@ -149,10 +148,14 @@ QUrl Account::davUrl() const
|
||||
return Utility::concatUrlPath(url(), davPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* clear all cookies. (Session cookies or not)
|
||||
*/
|
||||
void Account::clearCookieJar()
|
||||
{
|
||||
Q_ASSERT(qobject_cast<CookieJar*>(_am->cookieJar()));
|
||||
static_cast<CookieJar*>(_am->cookieJar())->clearSessionCookies();
|
||||
static_cast<CookieJar*>(_am->cookieJar())->setAllCookies(QList<QNetworkCookie>());
|
||||
emit wantsAccountSaved(this);
|
||||
}
|
||||
|
||||
/*! This shares our official cookie jar (containing all the tasty
|
||||
@@ -242,12 +245,6 @@ QNetworkReply *Account::davRequest(const QByteArray &verb, const QUrl &url, QNet
|
||||
return _am->sendCustomRequest(req, verb, data);
|
||||
}
|
||||
|
||||
void Account::setCertificate(const QByteArray certficate, const QString privateKey)
|
||||
{
|
||||
_pemCertificate=certficate;
|
||||
_pemPrivateKey=privateKey;
|
||||
}
|
||||
|
||||
void Account::setSslConfiguration(const QSslConfiguration &config)
|
||||
{
|
||||
_sslConfiguration = config;
|
||||
@@ -264,31 +261,7 @@ QSslConfiguration Account::getOrCreateSslConfig()
|
||||
// if setting the client certificate fails, you will probably get an error similar to this:
|
||||
// "An internal error number 1060 happened. SSL handshake failed, client certificate was requested: SSL error: sslv3 alert handshake failure"
|
||||
QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
|
||||
QSslCertificate sslClientCertificate;
|
||||
|
||||
ConfigFile cfgFile;
|
||||
if(!cfgFile.certificatePath().isEmpty() && !cfgFile.certificatePasswd().isEmpty()) {
|
||||
resultP12ToPem certif = p12ToPem(cfgFile.certificatePath().toStdString(), cfgFile.certificatePasswd().toStdString());
|
||||
QString s = QString::fromStdString(certif.Certificate);
|
||||
QByteArray ba = s.toLocal8Bit();
|
||||
this->setCertificate(ba, QString::fromStdString(certif.PrivateKey));
|
||||
}
|
||||
if((!_pemCertificate.isEmpty())&&(!_pemPrivateKey.isEmpty())) {
|
||||
// Read certificates
|
||||
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(_pemCertificate, QSsl::Pem);
|
||||
if(sslCertificateList.length() != 0) {
|
||||
sslClientCertificate = sslCertificateList.takeAt(0);
|
||||
}
|
||||
// Read key from file
|
||||
QSslKey privateKey(_pemPrivateKey.toLocal8Bit(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey , "");
|
||||
|
||||
// SSL configuration
|
||||
sslConfig.setCaCertificates(QSslSocket::systemCaCertificates());
|
||||
sslConfig.setLocalCertificate(sslClientCertificate);
|
||||
sslConfig.setPrivateKey(privateKey);
|
||||
qDebug() << "Added SSL client certificate to the query";
|
||||
}
|
||||
|
||||
#if QT_VERSION > QT_VERSION_CHECK(5, 2, 0)
|
||||
// Try hard to re-use session for different requests
|
||||
sslConfig.setSslOption(QSsl::SslOptionDisableSessionTickets, false);
|
||||
@@ -379,8 +352,11 @@ void Account::slotHandleSslErrors(QNetworkReply *reply , QList<QSslError> errors
|
||||
// Keep a ref here on our stackframe to make sure that it doesn't get deleted before
|
||||
// handleErrors returns.
|
||||
QSharedPointer<QNetworkAccessManager> qnamLock = _am;
|
||||
QPointer<QObject> guard = reply;
|
||||
|
||||
if (_sslErrorHandler->handleErrors(errors, reply->sslConfiguration(), &approvedCerts, sharedFromThis())) {
|
||||
if (!guard) return;
|
||||
|
||||
QSslSocket::addDefaultCaCertificates(approvedCerts);
|
||||
addApprovedCerts(approvedCerts);
|
||||
emit wantsAccountSaved(this);
|
||||
@@ -392,6 +368,8 @@ void Account::slotHandleSslErrors(QNetworkReply *reply , QList<QSslError> errors
|
||||
// certificate changes.
|
||||
reply->ignoreSslErrors(errors);
|
||||
} else {
|
||||
if (!guard) return;
|
||||
|
||||
// Mark all involved certificates as rejected, so we don't ask the user again.
|
||||
foreach (const QSslError &error, errors) {
|
||||
if (!_rejectedCertificates.contains(error.certificate())) {
|
||||
|
||||
@@ -224,8 +224,7 @@ private:
|
||||
QList<QSslCertificate> _rejectedCertificates;
|
||||
|
||||
static QString _configFileName;
|
||||
QByteArray _pemCertificate;
|
||||
QString _pemPrivateKey;
|
||||
|
||||
QString _davPath; // defaults to value from theme, might be overwritten in brandings
|
||||
friend class AccountManager;
|
||||
};
|
||||
|
||||
@@ -116,5 +116,9 @@ bool Capabilities::chunkingNg() const
|
||||
return _capabilities["dav"].toMap()["chunking"].toByteArray() >= "1.0";
|
||||
}
|
||||
|
||||
bool Capabilities::chunkingParallelUploadDisabled() const
|
||||
{
|
||||
return _capabilities["dav"].toMap()["chunkingParallelUploadDisabled"].toBool();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,6 +42,9 @@ public:
|
||||
bool shareResharing() const;
|
||||
bool chunkingNg() const;
|
||||
|
||||
/// disable parallel upload in chunking
|
||||
bool chunkingParallelUploadDisabled() const;
|
||||
|
||||
/// returns true if the capabilities report notifications
|
||||
bool notificationsAvailable() const;
|
||||
|
||||
|
||||
@@ -144,7 +144,12 @@ void ConnectionValidator::slotStatusFound(const QUrl&url, const QVariantMap &inf
|
||||
// status.php could not be loaded (network or server issue!).
|
||||
void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << reply->error() << reply->errorString();
|
||||
qDebug() << Q_FUNC_INFO << reply->error() << reply->errorString() << reply->peek(1024);
|
||||
if (reply && !_account->credentials()->ready()) {
|
||||
// This could be needed for SSL client certificates
|
||||
// We need to load them from keychain and try
|
||||
reportResult( CredentialsMissingOrWrong );
|
||||
} else
|
||||
if( reply && ! _account->credentials()->stillValid(reply)) {
|
||||
_errors.append(tr("Authentication error: Either username or password are wrong."));
|
||||
} else {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <QDebug>
|
||||
#include <QNetworkReply>
|
||||
#include <QSettings>
|
||||
#include <QSslKey>
|
||||
|
||||
#include <keychain.h>
|
||||
|
||||
@@ -36,8 +37,8 @@ namespace OCC
|
||||
namespace
|
||||
{
|
||||
const char userC[] = "user";
|
||||
const char certifPathC[] = "certificatePath";
|
||||
const char certifPasswdC[] = "certificatePasswd";
|
||||
const char clientCertificatePEMC[] = "_clientCertificatePEM";
|
||||
const char clientKeyPEMC[] = "_clientKeyPEM";
|
||||
const char authenticationFailedC[] = "owncloud-authentication-failed";
|
||||
} // ns
|
||||
|
||||
@@ -50,24 +51,47 @@ protected:
|
||||
QByteArray credHash = QByteArray(_cred->user().toUtf8()+":"+_cred->password().toUtf8()).toBase64();
|
||||
QNetworkRequest req(request);
|
||||
req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash);
|
||||
//qDebug() << "Request for " << req.url() << "with authorization" << QByteArray::fromBase64(credHash);
|
||||
//qDebug() << "Request for " << req.url() << "with authorization"
|
||||
// << QByteArray::fromBase64(credHash)
|
||||
// << _cred->_clientSslKey << _cred->_clientSslCertificate
|
||||
// << _cred->_clientSslKey.isNull() << _cred->_clientSslCertificate.isNull();
|
||||
|
||||
if (!_cred->_clientSslKey.isNull() && !_cred->_clientSslCertificate.isNull()) {
|
||||
// SSL configuration
|
||||
QSslConfiguration sslConfiguration = req.sslConfiguration();
|
||||
sslConfiguration.setLocalCertificate(_cred->_clientSslCertificate);
|
||||
sslConfiguration.setPrivateKey(_cred->_clientSslKey);
|
||||
req.setSslConfiguration(sslConfiguration);
|
||||
}
|
||||
|
||||
|
||||
return AccessManager::createRequest(op, req, outgoingData);
|
||||
}
|
||||
private:
|
||||
const HttpCredentials *_cred;
|
||||
};
|
||||
|
||||
|
||||
static void addSettingsToJob(Account *account, QKeychain::Job *job)
|
||||
{
|
||||
Q_UNUSED(account);
|
||||
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
|
||||
settings->setParent(job); // make the job parent to make setting deleted properly
|
||||
job->setSettings(settings.release());
|
||||
}
|
||||
|
||||
HttpCredentials::HttpCredentials()
|
||||
: _ready(false)
|
||||
{
|
||||
}
|
||||
|
||||
HttpCredentials::HttpCredentials(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd)
|
||||
// From wizard
|
||||
HttpCredentials::HttpCredentials(const QString& user, const QString& password, const QSslCertificate& certificate, const QSslKey& key)
|
||||
: _user(user),
|
||||
_password(password),
|
||||
_ready(true),
|
||||
_certificatePath(certificatePath),
|
||||
_certificatePasswd(certificatePasswd)
|
||||
_clientSslKey(key),
|
||||
_clientSslCertificate(certificate)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -86,16 +110,6 @@ QString HttpCredentials::password() const
|
||||
return _password;
|
||||
}
|
||||
|
||||
QString HttpCredentials::certificatePath() const
|
||||
{
|
||||
return _certificatePath;
|
||||
}
|
||||
|
||||
QString HttpCredentials::certificatePasswd() const
|
||||
{
|
||||
return _certificatePasswd;
|
||||
}
|
||||
|
||||
void HttpCredentials::setAccount(Account* account)
|
||||
{
|
||||
AbstractCredentials::setAccount(account);
|
||||
@@ -129,35 +143,83 @@ void HttpCredentials::fetchFromKeychain()
|
||||
{
|
||||
// User must be fetched from config file
|
||||
fetchUser();
|
||||
_certificatePath = _account->credentialSetting(QLatin1String(certifPathC)).toString();
|
||||
_certificatePasswd = _account->credentialSetting(QLatin1String(certifPasswdC)).toString();
|
||||
|
||||
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
|
||||
const QString kck = keychainKey(_account->url().toString(), _user );
|
||||
|
||||
QString key = QString::fromLatin1( "%1/data" ).arg( kck );
|
||||
if( settings && settings->contains(key) ) {
|
||||
// Clean the password from the config file if it is in there.
|
||||
// we do not want a security problem.
|
||||
settings->remove(key);
|
||||
key = QString::fromLatin1( "%1/type" ).arg( kck );
|
||||
settings->remove(key);
|
||||
settings->sync();
|
||||
}
|
||||
|
||||
if (_ready) {
|
||||
Q_EMIT fetched();
|
||||
} else {
|
||||
// Read client cert from keychain
|
||||
const QString kck = keychainKey(_account->url().toString(), _user + clientCertificatePEMC);
|
||||
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
|
||||
settings->setParent(job); // make the job parent to make setting deleted properly
|
||||
job->setSettings(settings.release());
|
||||
|
||||
addSettingsToJob(_account, job);
|
||||
job->setInsecureFallback(false);
|
||||
job->setKey(kck);
|
||||
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
|
||||
qDebug() << "-------- ----->" << _clientSslCertificate << _clientSslKey;
|
||||
|
||||
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadClientCertPEMJobDone(QKeychain::Job*)));
|
||||
job->start();
|
||||
}
|
||||
}
|
||||
|
||||
void HttpCredentials::slotReadClientCertPEMJobDone(QKeychain::Job* incoming)
|
||||
{
|
||||
// Store PEM in memory
|
||||
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(incoming);
|
||||
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
|
||||
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(readJob->binaryData(), QSsl::Pem);
|
||||
if(sslCertificateList.length() >= 1) {
|
||||
_clientSslCertificate = sslCertificateList.at(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Load key too
|
||||
const QString kck = keychainKey(_account->url().toString(), _user + clientKeyPEMC);
|
||||
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
|
||||
addSettingsToJob(_account, job);
|
||||
job->setInsecureFallback(false);
|
||||
job->setKey(kck);
|
||||
|
||||
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadClientKeyPEMJobDone(QKeychain::Job*)));
|
||||
job->start();
|
||||
}
|
||||
|
||||
void HttpCredentials::slotReadClientKeyPEMJobDone(QKeychain::Job* incoming)
|
||||
{
|
||||
// Store key in memory
|
||||
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(incoming);
|
||||
|
||||
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
|
||||
QByteArray clientKeyPEM = readJob->binaryData();
|
||||
// FIXME Unfortunately Qt has a bug and we can't just use QSsl::Opaque to let it
|
||||
// load whatever we have. So we try until it works.
|
||||
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Rsa);
|
||||
if (_clientSslKey.isNull()) {
|
||||
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Dsa);
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
|
||||
// ec keys are Qt 5.5
|
||||
if (_clientSslKey.isNull()) {
|
||||
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Ec);
|
||||
}
|
||||
#endif
|
||||
if (_clientSslKey.isNull()) {
|
||||
qDebug() << "Warning: Could not load SSL key into Qt!";
|
||||
}
|
||||
}
|
||||
|
||||
// Now fetch the actual server password
|
||||
const QString kck = keychainKey(_account->url().toString(), _user );
|
||||
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
|
||||
addSettingsToJob(_account, job);
|
||||
job->setInsecureFallback(false);
|
||||
job->setKey(kck);
|
||||
|
||||
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
|
||||
job->start();
|
||||
}
|
||||
|
||||
|
||||
bool HttpCredentials::stillValid(QNetworkReply *reply)
|
||||
{
|
||||
return ((reply->error() != QNetworkReply::AuthenticationRequiredError)
|
||||
@@ -166,10 +228,10 @@ bool HttpCredentials::stillValid(QNetworkReply *reply)
|
||||
|| !reply->property(authenticationFailedC).toBool()));
|
||||
}
|
||||
|
||||
void HttpCredentials::slotReadJobDone(QKeychain::Job *job)
|
||||
void HttpCredentials::slotReadJobDone(QKeychain::Job *incomingJob)
|
||||
{
|
||||
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(job);
|
||||
_password = readJob->textData();
|
||||
QKeychain::ReadPasswordJob *job = static_cast<ReadPasswordJob*>(incomingJob);
|
||||
_password = job->textData();
|
||||
|
||||
if( _user.isEmpty()) {
|
||||
qDebug() << "Strange: User is empty!";
|
||||
@@ -178,7 +240,6 @@ void HttpCredentials::slotReadJobDone(QKeychain::Job *job)
|
||||
QKeychain::Error error = job->error();
|
||||
|
||||
if( !_password.isEmpty() && error == NoError ) {
|
||||
|
||||
// All cool, the keychain did not come back with error.
|
||||
// Still, the password can be empty which indicates a problem and
|
||||
// the password dialog has to be opened.
|
||||
@@ -214,9 +275,7 @@ void HttpCredentials::invalidateToken()
|
||||
}
|
||||
|
||||
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
||||
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
|
||||
settings->setParent(job); // make the job parent to make setting deleted properly
|
||||
job->setSettings(settings.release());
|
||||
addSettingsToJob(_account, job);
|
||||
job->setInsecureFallback(true);
|
||||
job->setKey(kck);
|
||||
job->start();
|
||||
@@ -261,14 +320,37 @@ void HttpCredentials::persist()
|
||||
// We never connected or fetched the user, there is nothing to save.
|
||||
return;
|
||||
}
|
||||
_account->setCredentialSetting(QLatin1String(userC), _user);
|
||||
_account->setCredentialSetting(QLatin1String(certifPathC), _certificatePath);
|
||||
_account->setCredentialSetting(QLatin1String(certifPasswdC), _certificatePasswd);
|
||||
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
|
||||
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
|
||||
settings->setParent(job); // make the job parent to make setting deleted properly
|
||||
job->setSettings(settings.release());
|
||||
|
||||
_account->setCredentialSetting(QLatin1String(userC), _user);
|
||||
|
||||
// write cert
|
||||
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
|
||||
addSettingsToJob(_account, job);
|
||||
job->setInsecureFallback(false);
|
||||
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteClientCertPEMJobDone(QKeychain::Job*)));
|
||||
job->setKey(keychainKey(_account->url().toString(), _user + clientCertificatePEMC));
|
||||
job->setBinaryData(_clientSslCertificate.toPem());
|
||||
job->start();
|
||||
}
|
||||
|
||||
void HttpCredentials::slotWriteClientCertPEMJobDone(Job *incomingJob)
|
||||
{
|
||||
Q_UNUSED(incomingJob);
|
||||
// write ssl key
|
||||
WritePasswordJob* job = new WritePasswordJob(Theme::instance()->appName());
|
||||
addSettingsToJob(_account, job);
|
||||
job->setInsecureFallback(false);
|
||||
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteClientKeyPEMJobDone(QKeychain::Job*)));
|
||||
job->setKey(keychainKey(_account->url().toString(), _user + clientKeyPEMC));
|
||||
job->setBinaryData(_clientSslKey.toPem());
|
||||
job->start();
|
||||
}
|
||||
|
||||
void HttpCredentials::slotWriteClientKeyPEMJobDone(Job *incomingJob)
|
||||
{
|
||||
Q_UNUSED(incomingJob);
|
||||
WritePasswordJob* job = new WritePasswordJob(Theme::instance()->appName());
|
||||
addSettingsToJob(_account, job);
|
||||
job->setInsecureFallback(false);
|
||||
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteJobDone(QKeychain::Job*)));
|
||||
job->setKey(keychainKey(_account->url().toString(), _user));
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
#define MIRALL_CREDS_HTTP_CREDENTIALS_H
|
||||
|
||||
#include <QMap>
|
||||
|
||||
#include <QSslCertificate>
|
||||
#include <QSslKey>
|
||||
#include "creds/abstractcredentials.h"
|
||||
|
||||
class QNetworkReply;
|
||||
@@ -25,6 +26,8 @@ class QAuthenticator;
|
||||
|
||||
namespace QKeychain {
|
||||
class Job;
|
||||
class WritePasswordJob;
|
||||
class ReadPasswordJob;
|
||||
}
|
||||
|
||||
namespace OCC
|
||||
@@ -33,10 +36,10 @@ namespace OCC
|
||||
class OWNCLOUDSYNC_EXPORT HttpCredentials : public AbstractCredentials
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class HttpCredentialsAccessManager;
|
||||
public:
|
||||
explicit HttpCredentials();
|
||||
HttpCredentials(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd);
|
||||
HttpCredentials(const QString& user, const QString& password, const QSslCertificate& certificate = QSslCertificate(), const QSslKey& key = QSslKey());
|
||||
|
||||
QString authType() const Q_DECL_OVERRIDE;
|
||||
QNetworkAccessManager* getQNAM() const Q_DECL_OVERRIDE;
|
||||
@@ -50,15 +53,19 @@ public:
|
||||
void forgetSensitiveData() Q_DECL_OVERRIDE;
|
||||
QString fetchUser();
|
||||
virtual bool sslIsTrusted() { return false; }
|
||||
QString certificatePath() const;
|
||||
QString certificatePasswd() const;
|
||||
|
||||
// To fetch the user name as early as possible
|
||||
void setAccount(Account* account) Q_DECL_OVERRIDE;
|
||||
|
||||
private Q_SLOTS:
|
||||
void slotAuthentication(QNetworkReply*, QAuthenticator*);
|
||||
|
||||
void slotReadClientCertPEMJobDone(QKeychain::Job*);
|
||||
void slotReadClientKeyPEMJobDone(QKeychain::Job*);
|
||||
void slotReadJobDone(QKeychain::Job*);
|
||||
|
||||
void slotWriteClientCertPEMJobDone(QKeychain::Job*);
|
||||
void slotWriteClientKeyPEMJobDone(QKeychain::Job*);
|
||||
void slotWriteJobDone(QKeychain::Job*);
|
||||
void clearQNAMCache();
|
||||
|
||||
@@ -66,12 +73,11 @@ protected:
|
||||
QString _user;
|
||||
QString _password;
|
||||
QString _previousPassword;
|
||||
|
||||
QString _fetchErrorString;
|
||||
bool _ready;
|
||||
|
||||
private:
|
||||
QString _certificatePath;
|
||||
QString _certificatePasswd;
|
||||
QSslKey _clientSslKey;
|
||||
QSslCertificate _clientSslCertificate;
|
||||
};
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <QThread>
|
||||
#include <qmetaobject.h>
|
||||
|
||||
#include "csync.h"
|
||||
|
||||
namespace OCC {
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
@@ -48,6 +50,14 @@ static void mirallLogCatcher(QtMsgType type, const QMessageLogContext &ctx, cons
|
||||
}
|
||||
#endif
|
||||
|
||||
static void csyncLogCatcher(int /*verbosity*/,
|
||||
const char * /*function*/,
|
||||
const char *buffer,
|
||||
void * /*userdata*/)
|
||||
{
|
||||
Logger::instance()->csyncLog( QString::fromUtf8(buffer) );
|
||||
}
|
||||
|
||||
Logger *Logger::instance()
|
||||
{
|
||||
static Logger log;
|
||||
@@ -55,7 +65,7 @@ Logger *Logger::instance()
|
||||
}
|
||||
|
||||
Logger::Logger( QObject* parent) : QObject(parent),
|
||||
_showTime(true), _doLogging(false), _doFileFlush(false), _logExpire(0)
|
||||
_showTime(true), _logWindowActivated(false), _doFileFlush(false), _logExpire(0)
|
||||
{
|
||||
#ifndef NO_MSG_HANDLER
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
|
||||
@@ -117,12 +127,8 @@ bool Logger::isNoop() const
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
return false;
|
||||
#else
|
||||
static auto signal = QMetaMethod::fromSignal(&Logger::newLog);
|
||||
if (isSignalConnected(signal)) {
|
||||
return false;
|
||||
}
|
||||
QMutexLocker lock(const_cast<QMutex *>(&_mutex));
|
||||
return !_logstream;
|
||||
return !_logstream && !_logWindowActivated;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -136,7 +142,7 @@ void Logger::doLog(const QString& msg)
|
||||
if( _doFileFlush ) _logstream->flush();
|
||||
}
|
||||
}
|
||||
emit newLog(msg);
|
||||
emit logWindowLog(msg);
|
||||
}
|
||||
|
||||
void Logger::csyncLog( const QString& message )
|
||||
@@ -164,10 +170,25 @@ void Logger::mirallLog( const QString& message )
|
||||
Logger::instance()->log( log_ );
|
||||
}
|
||||
|
||||
void Logger::setLogWindowActivated(bool activated)
|
||||
{
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
||||
// Setup CSYNC logging to forward to our own logger
|
||||
csync_set_log_callback(csyncLogCatcher);
|
||||
csync_set_log_level(11);
|
||||
|
||||
_logWindowActivated = activated;
|
||||
}
|
||||
|
||||
void Logger::setLogFile(const QString & name)
|
||||
{
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
||||
// Setup CSYNC logging to forward to our own logger
|
||||
csync_set_log_callback(csyncLogCatcher);
|
||||
csync_set_log_level(11);
|
||||
|
||||
if( _logstream ) {
|
||||
_logstream.reset(0);
|
||||
_logFile.close();
|
||||
|
||||
@@ -61,13 +61,15 @@ public:
|
||||
void postOptionalGuiLog(const QString& title, const QString& message);
|
||||
void postGuiMessage(const QString& title, const QString& message);
|
||||
|
||||
void setLogWindowActivated(bool activated);
|
||||
void setLogFile( const QString & name );
|
||||
void setLogExpire( int expire );
|
||||
void setLogDir( const QString& dir );
|
||||
void setLogFlush( bool flush );
|
||||
|
||||
signals:
|
||||
void newLog(const QString&);
|
||||
void logWindowLog(const QString&);
|
||||
|
||||
void guiLog(const QString&, const QString&);
|
||||
void guiMessage(const QString&, const QString&);
|
||||
void optionalGuiLog(const QString&, const QString&);
|
||||
@@ -80,7 +82,7 @@ private:
|
||||
~Logger();
|
||||
QList<Log> _logs;
|
||||
bool _showTime;
|
||||
bool _doLogging;
|
||||
bool _logWindowActivated;
|
||||
QFile _logFile;
|
||||
bool _doFileFlush;
|
||||
int _logExpire;
|
||||
|
||||
@@ -472,7 +472,7 @@ bool CheckServerJob::finished()
|
||||
QVariantMap status = QtJson::parse(QString::fromUtf8(body), success).toMap();
|
||||
// empty or invalid response
|
||||
if (!success || status.isEmpty()) {
|
||||
qDebug() << "status.php from server is not valid JSON!";
|
||||
qDebug() << "status.php from server is not valid JSON!" << body << reply()->request().url();
|
||||
}
|
||||
|
||||
qDebug() << "status.php returns: " << status << " " << reply()->error() << " Reply: " << reply();
|
||||
|
||||
@@ -70,7 +70,9 @@ bool SqlDatabase::openHelper( const QString& filename, int sqliteFlags )
|
||||
|
||||
bool SqlDatabase::checkDb()
|
||||
{
|
||||
SqlQuery quick_check("PRAGMA quick_check;", *this);
|
||||
// quick_check can fail with a disk IO error when diskspace is low
|
||||
SqlQuery quick_check(*this);
|
||||
quick_check.prepare("PRAGMA quick_check;", /*allow_failure=*/true);
|
||||
if( !quick_check.exec() ) {
|
||||
qDebug() << "Error running quick_check on database";
|
||||
return false;
|
||||
@@ -97,6 +99,14 @@ bool SqlDatabase::openOrCreateReadWrite( const QString& filename )
|
||||
}
|
||||
|
||||
if( !checkDb() ) {
|
||||
// When disk space is low, checking the db may fail even though it's fine.
|
||||
qint64 freeSpace = Utility::freeDiskSpace(filename);
|
||||
if (freeSpace < 1000000) {
|
||||
qDebug() << "Consistency check failed, disk space is low, aborting" << freeSpace;
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << "Consistency check failed, removing broken db" << filename;
|
||||
close();
|
||||
QFile::remove(filename);
|
||||
@@ -191,7 +201,7 @@ SqlQuery::SqlQuery(const QString& sql, SqlDatabase& db)
|
||||
prepare(sql);
|
||||
}
|
||||
|
||||
int SqlQuery::prepare( const QString& sql)
|
||||
int SqlQuery::prepare( const QString& sql, bool allow_failure )
|
||||
{
|
||||
QString s(sql);
|
||||
_sql = s.trimmed();
|
||||
@@ -213,7 +223,11 @@ int SqlQuery::prepare( const QString& sql)
|
||||
if( _errId != SQLITE_OK ) {
|
||||
_error = QString::fromUtf8(sqlite3_errmsg(_db));
|
||||
qWarning() << "Sqlite prepare statement error:" << _error << "in" <<_sql;
|
||||
Q_ASSERT(!"SQLITE Prepare error");
|
||||
if (!allow_failure) {
|
||||
qFatal("SQLITE Prepare error: %s in %s",
|
||||
_error.toLocal8Bit().data(),
|
||||
sql.toLocal8Bit().data());
|
||||
}
|
||||
}
|
||||
}
|
||||
return _errId;
|
||||
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
bool isSelect();
|
||||
bool isPragma();
|
||||
bool exec();
|
||||
int prepare( const QString& sql );
|
||||
int prepare( const QString& sql, bool allow_failure = false );
|
||||
bool next();
|
||||
void bindValue(int pos, const QVariant& value);
|
||||
QString lastQuery() const;
|
||||
|
||||
@@ -145,8 +145,12 @@ void ProgressInfo::reset()
|
||||
_sizeProgress = Progress();
|
||||
_fileProgress = Progress();
|
||||
_totalSizeOfCompletedJobs = 0;
|
||||
_maxBytesPerSecond = 100000.0;
|
||||
_maxFilesPerSecond = 2.0;
|
||||
|
||||
// Historically, these starting estimates were way lower, but that lead
|
||||
// to gross overestimation of ETA when a good estimate wasn't available.
|
||||
_maxBytesPerSecond = 2000000.0; // 2 MB/s
|
||||
_maxFilesPerSecond = 10.0;
|
||||
|
||||
_updateEstimatesTimer.stop();
|
||||
_lastCompletedItem = SyncFileItem();
|
||||
}
|
||||
|
||||
@@ -401,7 +401,7 @@ void PropagateDownloadFile::start()
|
||||
// Normal job, download from oC instance
|
||||
_job = new GETFileJob(_propagator->account(),
|
||||
_propagator->_remoteFolder + _item->_file,
|
||||
&_tmpFile, headers, expectedEtagForResume, _resumeStart);
|
||||
&_tmpFile, headers, expectedEtagForResume, _resumeStart, this);
|
||||
} else {
|
||||
// We were provided a direct URL, use that one
|
||||
qDebug() << Q_FUNC_INFO << "directDownloadUrl given for " << _item->_file << _item->_directDownloadUrl;
|
||||
@@ -413,7 +413,7 @@ void PropagateDownloadFile::start()
|
||||
QUrl url = QUrl::fromUserInput(_item->_directDownloadUrl);
|
||||
_job = new GETFileJob(_propagator->account(),
|
||||
url,
|
||||
&_tmpFile, headers, expectedEtagForResume, _resumeStart);
|
||||
&_tmpFile, headers, expectedEtagForResume, _resumeStart, this);
|
||||
}
|
||||
_job->setBandwidthManager(&_propagator->_bandwidthManager);
|
||||
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
|
||||
|
||||
@@ -315,7 +315,7 @@ void PropagateUploadFileNG::startNextChunk()
|
||||
QUrl url = chunkUrl(_currentChunk);
|
||||
|
||||
// job takes ownership of device via a QScopedPointer. Job deletes itself when finishing
|
||||
PUTFileJob* job = new PUTFileJob(_propagator->account(), url, device, headers, _currentChunk);
|
||||
PUTFileJob* job = new PUTFileJob(_propagator->account(), url, device, headers, _currentChunk, this);
|
||||
_jobs.append(job);
|
||||
connect(job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
|
||||
connect(job, SIGNAL(uploadProgress(qint64,qint64)),
|
||||
|
||||
@@ -123,7 +123,7 @@ void PropagateUploadFileV1::startNextChunk()
|
||||
}
|
||||
|
||||
// job takes ownership of device via a QScopedPointer. Job deletes itself when finishing
|
||||
PUTFileJob* job = new PUTFileJob(_propagator->account(), _propagator->_remoteFolder + path, device, headers, _currentChunk);
|
||||
PUTFileJob* job = new PUTFileJob(_propagator->account(), _propagator->_remoteFolder + path, device, headers, _currentChunk, this);
|
||||
_jobs.append(job);
|
||||
connect(job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
|
||||
connect(job, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(slotUploadProgress(qint64,qint64)));
|
||||
@@ -134,18 +134,25 @@ void PropagateUploadFileV1::startNextChunk()
|
||||
_currentChunk++;
|
||||
|
||||
bool parallelChunkUpload = true;
|
||||
QByteArray env = qgetenv("OWNCLOUD_PARALLEL_CHUNK");
|
||||
if (!env.isEmpty()) {
|
||||
parallelChunkUpload = env != "false" && env != "0";
|
||||
|
||||
if (_propagator->account()->capabilities().chunkingParallelUploadDisabled()) {
|
||||
// Server may also disable parallel chunked upload for any higher version
|
||||
parallelChunkUpload = false;
|
||||
} else {
|
||||
int versionNum = _propagator->account()->serverVersionInt();
|
||||
if (versionNum < 0x080003) {
|
||||
// Disable parallel chunk upload severs older than 8.0.3 to avoid too many
|
||||
// internal sever errors (#2743, #2938)
|
||||
parallelChunkUpload = false;
|
||||
QByteArray env = qgetenv("OWNCLOUD_PARALLEL_CHUNK");
|
||||
if (!env.isEmpty()) {
|
||||
parallelChunkUpload = env != "false" && env != "0";
|
||||
} else {
|
||||
int versionNum = _propagator->account()->serverVersionInt();
|
||||
if (versionNum < 0x080003) {
|
||||
// Disable parallel chunk upload severs older than 8.0.3 to avoid too many
|
||||
// internal sever errors (#2743, #2938)
|
||||
parallelChunkUpload = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_currentChunk + _startChunk >= _chunkCount - 1) {
|
||||
// Don't do parallel upload of chunk if this might be the last chunk because the server cannot handle that
|
||||
// https://github.com/owncloud/core/issues/11106
|
||||
|
||||
@@ -73,11 +73,13 @@ SyncEngine::SyncEngine(AccountPtr account, const QString& localPath,
|
||||
, _downloadLimit(0)
|
||||
, _newBigFolderSizeLimit(-1)
|
||||
, _checksum_hook(journal)
|
||||
, _anotherSyncNeeded(false)
|
||||
, _anotherSyncNeeded(NoFollowUpSync)
|
||||
{
|
||||
qRegisterMetaType<SyncFileItem>("SyncFileItem");
|
||||
qRegisterMetaType<SyncFileItem::Status>("SyncFileItem::Status");
|
||||
qRegisterMetaType<SyncFileStatus>("SyncFileStatus");
|
||||
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
|
||||
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
|
||||
|
||||
// Everything in the SyncEngine expects a trailing slash for the localPath.
|
||||
Q_ASSERT(localPath.endsWith(QLatin1Char('/')));
|
||||
@@ -693,12 +695,13 @@ void SyncEngine::startSync()
|
||||
Q_ASSERT(!_syncRunning);
|
||||
s_anySyncRunning = true;
|
||||
_syncRunning = true;
|
||||
_anotherSyncNeeded = false;
|
||||
_anotherSyncNeeded = NoFollowUpSync;
|
||||
_clearTouchedFilesTimer.stop();
|
||||
|
||||
_progressInfo->reset();
|
||||
|
||||
if (!QDir(_localPath).exists()) {
|
||||
_anotherSyncNeeded = DelayedFollowUp;
|
||||
// No _tr, it should only occur in non-mirall
|
||||
emit csyncError("Unable to find local sync folder.");
|
||||
finalize(false);
|
||||
@@ -712,6 +715,7 @@ void SyncEngine::startSync()
|
||||
qDebug() << "There are" << freeBytes << "bytes available at" << _localPath
|
||||
<< "and at least" << minFree << "are required";
|
||||
if (freeBytes < minFree) {
|
||||
_anotherSyncNeeded = DelayedFollowUp;
|
||||
emit csyncError(tr("Only %1 are available, need at least %2 to start",
|
||||
"Placeholders are postfixed with file sizes using Utility::octetsToString()").arg(
|
||||
Utility::octetsToString(freeBytes),
|
||||
@@ -1048,7 +1052,9 @@ void SyncEngine::slotItemCompleted(const SyncFileItem &item, const PropagatorJob
|
||||
|
||||
void SyncEngine::slotFinished(bool success)
|
||||
{
|
||||
_anotherSyncNeeded = _anotherSyncNeeded || _propagator->_anotherSyncNeeded;
|
||||
if (_propagator->_anotherSyncNeeded && _anotherSyncNeeded == NoFollowUpSync) {
|
||||
_anotherSyncNeeded = ImmediateFollowUp;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
_journal->setDataFingerprint(_discoveryMainThread->_dataFingerprint);
|
||||
@@ -1171,7 +1177,7 @@ void SyncEngine::checkForPermission()
|
||||
// be restored. Do that in the next sync by not considering as a rename
|
||||
// but delete and upload. It will then be restored if needed.
|
||||
_journal->avoidRenamesOnNextSync((*it)->_file);
|
||||
_anotherSyncNeeded = true;
|
||||
_anotherSyncNeeded = ImmediateFollowUp;
|
||||
qDebug() << "Moving of " << (*it)->_file << " canceled because no permission to add parent folder";
|
||||
}
|
||||
(*it)->_instruction = CSYNC_INSTRUCTION_ERROR;
|
||||
@@ -1328,7 +1334,7 @@ void SyncEngine::checkForPermission()
|
||||
// At this point we would need to go back to the propagate phase on both remote to take
|
||||
// the decision.
|
||||
_journal->avoidRenamesOnNextSync((*it)->_file);
|
||||
_anotherSyncNeeded = true;
|
||||
_anotherSyncNeeded = ImmediateFollowUp;
|
||||
|
||||
|
||||
if ((*it)->_isDirectory) {
|
||||
|
||||
@@ -49,6 +49,13 @@ class SyncJournalDb;
|
||||
class OwncloudPropagator;
|
||||
class PropagatorJob;
|
||||
|
||||
enum AnotherSyncNeeded
|
||||
{
|
||||
NoFollowUpSync,
|
||||
ImmediateFollowUp, // schedule this again immediately (limited amount of times)
|
||||
DelayedFollowUp // regularly schedule this folder again (around 1/minute, unlimited)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The SyncEngine class
|
||||
* @ingroup libsync
|
||||
@@ -82,8 +89,8 @@ public:
|
||||
Utility::StopWatch &stopWatch() { return _stopWatch; }
|
||||
SyncFileStatusTracker &syncFileStatusTracker() { return *_syncFileStatusTracker; }
|
||||
|
||||
/* Return true if we detected that another sync is needed to complete the sync */
|
||||
bool isAnotherSyncNeeded() { return _anotherSyncNeeded; }
|
||||
/* Returns whether another sync is needed to complete the sync */
|
||||
AnotherSyncNeeded isAnotherSyncNeeded() { return _anotherSyncNeeded; }
|
||||
|
||||
/** Get the ms since a file was touched, or -1 if it wasn't.
|
||||
*
|
||||
@@ -259,7 +266,7 @@ private:
|
||||
/// Hook for computing checksums from csync_update
|
||||
CSyncChecksumHook _checksum_hook;
|
||||
|
||||
bool _anotherSyncNeeded;
|
||||
AnotherSyncNeeded _anotherSyncNeeded;
|
||||
|
||||
/** Stores the time since a job touched a file. */
|
||||
QHash<QString, QElapsedTimer> _touchedFiles;
|
||||
|
||||
@@ -138,7 +138,7 @@ public:
|
||||
QString _file;
|
||||
QString _renameTarget;
|
||||
Type _type BITFIELD(3);
|
||||
Direction _direction BITFIELD(2);
|
||||
Direction _direction BITFIELD(3);
|
||||
bool _isDirectory BITFIELD(1);
|
||||
bool _serverHasIgnoredFiles BITFIELD(1);
|
||||
|
||||
|
||||
@@ -131,6 +131,7 @@ SyncJournalErrorBlacklistRecord SyncJournalErrorBlacklistRecord::update(
|
||||
bool mayBlacklist =
|
||||
item._errorMayBeBlacklisted // explicitly flagged for blacklisting
|
||||
|| (item._httpErrorCode != 0 // or non-local error
|
||||
&& item._httpErrorCode != 507 // Don't blacklist "Insufficient Storage"
|
||||
#ifdef OWNCLOUD_5XX_NO_BLACKLIST
|
||||
&& item._httpErrorCode / 100 != 5 // In this configuration, never blacklist error 5xx
|
||||
#endif
|
||||
|
||||
@@ -23,7 +23,7 @@ using namespace OCC;
|
||||
class HttpCredentialsTest : public HttpCredentials {
|
||||
public:
|
||||
HttpCredentialsTest(const QString& user, const QString& password)
|
||||
: HttpCredentials(user, password, "", "")
|
||||
: HttpCredentials(user, password)
|
||||
{}
|
||||
|
||||
void askFromUser() Q_DECL_OVERRIDE {
|
||||
|
||||
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+218
-208
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+215
-205
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+218
-208
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+215
-205
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+237
-225
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+218
-208
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+218
-208
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+219
-209
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+223
-213
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+218
-208
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+218
-208
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+220
-210
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+218
-208
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+216
-206
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
Referência em uma Nova Issue
Bloquear um usuário