Comparar commits
50 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 5cabac73ad | |||
| 4900db0099 | |||
| 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$")
|
||||
|
||||
@@ -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,69 @@ 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
|
||||
Comment[oc]=@APPLICATION_NAME@ sincronizacion del client
|
||||
GenericName[oc]=Dorsièr de Sincronizacion
|
||||
|
||||
-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 */
|
||||
|
||||
+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,7 @@ 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");
|
||||
Q_ASSERT(allow_failure || !"SQLITE Prepare error");
|
||||
}
|
||||
}
|
||||
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()));
|
||||
@@ -739,10 +739,12 @@ void PropagateDownloadFile::downloadFinished()
|
||||
qDebug() << "Created conflict file" << fn << "->" << conflictFileName;
|
||||
}
|
||||
|
||||
qDebug() << "1 We need to fetch the time again" << _item->_modtime;
|
||||
FileSystem::setModTime(_tmpFile.fileName(), _item->_modtime);
|
||||
// We need to fetch the time again because some file systems such as FAT have worse than a second
|
||||
// Accuracy, and we really need the time from the file system. (#3103)
|
||||
_item->_modtime = FileSystem::getModTime(_tmpFile.fileName());
|
||||
qDebug() << "2 and we really need the time from the file system" << _item->_modtime;
|
||||
|
||||
if (FileSystem::fileExists(fn)) {
|
||||
// Preserve the existing file permissions.
|
||||
@@ -805,6 +807,14 @@ void PropagateDownloadFile::downloadFinished()
|
||||
}
|
||||
FileSystem::setFileHidden(fn, false);
|
||||
|
||||
qDebug() << "1 Set modification time of moved file again" << _item->_modtime;
|
||||
// Set modification time of moved file again (because we modified permissions above and that changes modification time, depending on filesystem)
|
||||
FileSystem::setModTime(fn, _item->_modtime);
|
||||
// We need to fetch the time again because some file systems such as FAT have worse than a second
|
||||
// Accuracy, and we really need the time from the file system. (#3103)
|
||||
_item->_modtime = FileSystem::getModTime(fn);
|
||||
qDebug() << "2 and we really need the time from the file system" << _item->_modtime;
|
||||
|
||||
// Maybe we downloaded a newer version of the file than we thought we would...
|
||||
// Get up to date information for the journal.
|
||||
_item->_size = FileSystem::getSize(fn);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+185
-180
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+182
-177
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+185
-180
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+182
-177
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+204
-197
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+185
-180
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+185
-180
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+185
-180
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+190
-185
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+185
-180
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+185
-180
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+187
-182
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+185
-180
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+183
-178
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
Referência em uma Nova Issue
Bloquear um usuário