mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2026-04-08 12:13:05 +02:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f37484b8a | ||
|
|
3d0c009719 | ||
|
|
208011f6ab | ||
|
|
f84e0010ee | ||
|
|
c97f46d403 | ||
|
|
1fb52f0d8b | ||
|
|
d4de024f15 | ||
|
|
1d9d88ca85 | ||
|
|
beb9300b4e | ||
|
|
c35880d4f1 | ||
|
|
d8ebebaf12 | ||
|
|
af3fae9c28 | ||
|
|
d3b72940fd | ||
|
|
e8de3e855a | ||
|
|
71338000a4 | ||
|
|
d697969f36 | ||
|
|
51e9c5fd96 | ||
|
|
0202351a27 | ||
|
|
63cd5ef563 | ||
|
|
82c254fecf | ||
|
|
86bea9a9af | ||
|
|
88f26fb548 | ||
|
|
a9f1de84f0 |
15
ChangeLog
15
ChangeLog
@@ -1,5 +1,20 @@
|
|||||||
ChangeLog
|
ChangeLog
|
||||||
=========
|
=========
|
||||||
|
version 1.6.2 (release 2014-07-28 )
|
||||||
|
* Limit the HTTP buffer size when downloading to limit memory consumption.
|
||||||
|
* Another small mem leak fixed in HTTP Credentials.
|
||||||
|
* Fix local file name clash detection for MacOSX.
|
||||||
|
* Limit maximum wait time to ten seconds in network limiting.
|
||||||
|
* Fix data corruption while trying to resume and the server does
|
||||||
|
not support it.
|
||||||
|
* HTTP Credentials: Read password from legacy place if not found.
|
||||||
|
* Shibboleth: Fix the waiting curser that would not disapear (#1915)
|
||||||
|
* Limit memory usage to avoid mem wasting and crashes
|
||||||
|
* Propagator: Fix crash when logging out during upload (#1957)
|
||||||
|
* Propagator_qnam: Fix signal slot connection (#1963)
|
||||||
|
* Use more elaborated way to detect that the server was reconfigured (#1948)
|
||||||
|
* Setup Wizard: Reconfigure Server also if local path was changed (#1948)
|
||||||
|
|
||||||
version 1.6.1 (release 2014-06-26 )
|
version 1.6.1 (release 2014-06-26 )
|
||||||
* Fix 'precondition failed' bug with broken upload
|
* Fix 'precondition failed' bug with broken upload
|
||||||
* Fix openSSL problems for windows deployment
|
* Fix openSSL problems for windows deployment
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
set( MIRALL_VERSION_MAJOR 1 )
|
set( MIRALL_VERSION_MAJOR 1 )
|
||||||
set( MIRALL_VERSION_MINOR 6 )
|
set( MIRALL_VERSION_MINOR 6 )
|
||||||
set( MIRALL_VERSION_PATCH 1 )
|
set( MIRALL_VERSION_PATCH 2 )
|
||||||
set( MIRALL_SOVERSION 0 )
|
set( MIRALL_SOVERSION 0 )
|
||||||
|
|
||||||
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||||
|
|||||||
@@ -111,8 +111,8 @@ ReserveFile "${NSISDIR}\Plugins\InstallOptions.dll"
|
|||||||
!define MUI_HEADERIMAGE
|
!define MUI_HEADERIMAGE
|
||||||
!define MUI_HEADERIMAGE_BITMAP ${WIN_SETUP_BITMAP_PATH}/page_header.bmp
|
!define MUI_HEADERIMAGE_BITMAP ${WIN_SETUP_BITMAP_PATH}/page_header.bmp
|
||||||
!define MUI_COMPONENTSPAGE_SMALLDESC
|
!define MUI_COMPONENTSPAGE_SMALLDESC
|
||||||
!define MUI_FINISHPAGE_LINK "www.${APPLICATION_DOMAIN}"
|
!define MUI_FINISHPAGE_LINK "${APPLICATION_DOMAIN}"
|
||||||
!define MUI_FINISHPAGE_LINK_LOCATION "http://www.${APPLICATION_DOMAIN}"
|
!define MUI_FINISHPAGE_LINK_LOCATION "http://${APPLICATION_DOMAIN}"
|
||||||
!define MUI_FINISHPAGE_NOREBOOTSUPPORT
|
!define MUI_FINISHPAGE_NOREBOOTSUPPORT
|
||||||
!ifdef OPTION_FINISHPAGE_RELEASE_NOTES
|
!ifdef OPTION_FINISHPAGE_RELEASE_NOTES
|
||||||
!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED
|
!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED
|
||||||
@@ -414,9 +414,9 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
|
|||||||
|
|
||||||
;Qt deps
|
;Qt deps
|
||||||
File "${MING_BIN}\libpng16-16.dll"
|
File "${MING_BIN}\libpng16-16.dll"
|
||||||
File "${MING_BIN}\icudata51.dll"
|
File "${MING_BIN}\icudata53.dll"
|
||||||
File "${MING_BIN}\icui18n51.dll"
|
File "${MING_BIN}\icui18n53.dll"
|
||||||
File "${MING_BIN}\icuuc51.dll"
|
File "${MING_BIN}\icuuc53.dll"
|
||||||
File "${MING_BIN}\libEGL.dll"
|
File "${MING_BIN}\libEGL.dll"
|
||||||
File "${MING_BIN}\libGLESv2.dll"
|
File "${MING_BIN}\libGLESv2.dll"
|
||||||
File "${MING_BIN}\libjpeg-8.dll"
|
File "${MING_BIN}\libjpeg-8.dll"
|
||||||
|
|||||||
Submodule doc/ocdoc updated: 2c3e584b23...c612df399e
@@ -101,7 +101,8 @@ HttpCredentials::HttpCredentials()
|
|||||||
: _user(),
|
: _user(),
|
||||||
_password(),
|
_password(),
|
||||||
_ready(false),
|
_ready(false),
|
||||||
_fetchJobInProgress(false)
|
_fetchJobInProgress(false),
|
||||||
|
_readPwdFromDeprecatedPlace(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,6 +231,7 @@ void HttpCredentials::fetch(Account *account)
|
|||||||
job->setProperty("account", QVariant::fromValue(account));
|
job->setProperty("account", QVariant::fromValue(account));
|
||||||
job->start();
|
job->start();
|
||||||
_fetchJobInProgress = true;
|
_fetchJobInProgress = true;
|
||||||
|
_readPwdFromDeprecatedPlace = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool HttpCredentials::stillValid(QNetworkReply *reply)
|
bool HttpCredentials::stillValid(QNetworkReply *reply)
|
||||||
@@ -261,18 +263,40 @@ void HttpCredentials::slotReadJobDone(QKeychain::Job *job)
|
|||||||
_ready = true;
|
_ready = true;
|
||||||
emit fetched();
|
emit fetched();
|
||||||
} else {
|
} else {
|
||||||
if( error != NoError ) {
|
// we come here if the password is empty or any other keychain
|
||||||
qDebug() << "Error while reading password" << job->errorString();
|
// error happend.
|
||||||
|
// In all error conditions it should
|
||||||
|
// ask the user for the password interactively now.
|
||||||
|
if( _readPwdFromDeprecatedPlace ) {
|
||||||
|
// there simply was not a password. Lets restart a read job without
|
||||||
|
// a settings object as we did it in older client releases.
|
||||||
|
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
|
||||||
|
|
||||||
|
const QString kck = keychainKey(account->url().toString(), _user);
|
||||||
|
job->setKey(kck);
|
||||||
|
|
||||||
|
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
|
||||||
|
job->setProperty("account", QVariant::fromValue(account));
|
||||||
|
job->start();
|
||||||
|
_readPwdFromDeprecatedPlace = false; // do try that only once.
|
||||||
|
_fetchJobInProgress = true;
|
||||||
|
// Note: if this read job succeeds, the value from the old place is still
|
||||||
|
// NOT persisted into the new account.
|
||||||
|
} else {
|
||||||
|
// interactive password dialog starts here
|
||||||
|
bool ok;
|
||||||
|
QString pwd = queryPassword(&ok);
|
||||||
|
_fetchJobInProgress = false;
|
||||||
|
if (ok) {
|
||||||
|
_password = pwd;
|
||||||
|
_ready = true;
|
||||||
|
persist(account);
|
||||||
|
} else {
|
||||||
|
_password = QString::null;
|
||||||
|
_ready = false;
|
||||||
|
}
|
||||||
|
emit fetched();
|
||||||
}
|
}
|
||||||
bool ok;
|
|
||||||
QString pwd = queryPassword(&ok);
|
|
||||||
_fetchJobInProgress = false;
|
|
||||||
if (ok) {
|
|
||||||
_password = pwd;
|
|
||||||
_ready = true;
|
|
||||||
persist(account);
|
|
||||||
}
|
|
||||||
emit fetched();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,6 +366,8 @@ void HttpCredentials::slotWriteJobDone(QKeychain::Job *job)
|
|||||||
default:
|
default:
|
||||||
qDebug() << "Error while writing password" << job->errorString();
|
qDebug() << "Error while writing password" << job->errorString();
|
||||||
}
|
}
|
||||||
|
WritePasswordJob *wjob = qobject_cast<WritePasswordJob*>(job);
|
||||||
|
wjob->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpCredentials::slotAuthentication(QNetworkReply* reply, QAuthenticator* authenticator)
|
void HttpCredentials::slotAuthentication(QNetworkReply* reply, QAuthenticator* authenticator)
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ private:
|
|||||||
QString _password;
|
QString _password;
|
||||||
bool _ready;
|
bool _ready;
|
||||||
bool _fetchJobInProgress; //True if the keychain job is in progress or the input dialog visible
|
bool _fetchJobInProgress; //True if the keychain job is in progress or the input dialog visible
|
||||||
|
bool _readPwdFromDeprecatedPlace;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // ns Mirall
|
} // ns Mirall
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ ShibbolethWebView::ShibbolethWebView(Account* account, QWidget* parent)
|
|||||||
: QWebView(parent)
|
: QWebView(parent)
|
||||||
, _account(account)
|
, _account(account)
|
||||||
, _accepted(false)
|
, _accepted(false)
|
||||||
|
, _cursorOverriden(false)
|
||||||
{
|
{
|
||||||
// no minimize
|
// no minimize
|
||||||
setWindowFlags(Qt::Dialog);
|
setWindowFlags(Qt::Dialog);
|
||||||
@@ -79,6 +80,10 @@ void ShibbolethWebView::onNewCookiesForUrl (const QList<QNetworkCookie>& cookieL
|
|||||||
|
|
||||||
void ShibbolethWebView::closeEvent(QCloseEvent *event)
|
void ShibbolethWebView::closeEvent(QCloseEvent *event)
|
||||||
{
|
{
|
||||||
|
if (_cursorOverriden) {
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
}
|
||||||
|
|
||||||
if (!_accepted) {
|
if (!_accepted) {
|
||||||
Q_EMIT rejected();
|
Q_EMIT rejected();
|
||||||
}
|
}
|
||||||
@@ -87,12 +92,17 @@ void ShibbolethWebView::closeEvent(QCloseEvent *event)
|
|||||||
|
|
||||||
void ShibbolethWebView::slotLoadStarted()
|
void ShibbolethWebView::slotLoadStarted()
|
||||||
{
|
{
|
||||||
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
if (!_cursorOverriden) {
|
||||||
|
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
||||||
|
_cursorOverriden = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShibbolethWebView::slotLoadFinished(bool success)
|
void ShibbolethWebView::slotLoadFinished(bool success)
|
||||||
{
|
{
|
||||||
QApplication::restoreOverrideCursor();
|
if (_cursorOverriden) {
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
}
|
||||||
|
|
||||||
if (!title().isNull()) {
|
if (!title().isNull()) {
|
||||||
setWindowTitle(tr("%1 - %2").arg(Theme::instance()->appNameGUI(), title()));
|
setWindowTitle(tr("%1 - %2").arg(Theme::instance()->appNameGUI(), title()));
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ private:
|
|||||||
void setup(Account *account, ShibbolethCookieJar* jar);
|
void setup(Account *account, ShibbolethCookieJar* jar);
|
||||||
QPointer<Account> _account;
|
QPointer<Account> _account;
|
||||||
bool _accepted;
|
bool _accepted;
|
||||||
|
bool _cursorOverriden;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // ns Mirall
|
} // ns Mirall
|
||||||
|
|||||||
@@ -704,10 +704,7 @@ void Folder::slotTransmissionProgress(const Progress::Info &pi)
|
|||||||
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel)
|
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel)
|
||||||
{
|
{
|
||||||
#ifndef TOKEN_AUTH_ONLY
|
#ifndef TOKEN_AUTH_ONLY
|
||||||
QString msg = direction == SyncFileItem::Down ?
|
QString msg =
|
||||||
tr("This sync would remove all the files in the local sync folder '%1'.\n"
|
|
||||||
"If you or your administrator have reset your account on the server, choose "
|
|
||||||
"\"Keep files\". If you want your data to be removed, choose \"Remove all files\".") :
|
|
||||||
tr("This sync would remove all the files in the sync folder '%1'.\n"
|
tr("This sync would remove all the files in the sync folder '%1'.\n"
|
||||||
"This might be because the folder was silently reconfigured, or that all "
|
"This might be because the folder was silently reconfigured, or that all "
|
||||||
"the file were manually removed.\n"
|
"the file were manually removed.\n"
|
||||||
|
|||||||
@@ -337,8 +337,15 @@ bool OwncloudPropagator::localFileNameClash( const QString& relFile )
|
|||||||
QFileInfo fileInfo(file);
|
QFileInfo fileInfo(file);
|
||||||
if (!fileInfo.exists()) {
|
if (!fileInfo.exists()) {
|
||||||
re = false;
|
re = false;
|
||||||
|
qDebug() << Q_FUNC_INFO << "No valid fileinfo";
|
||||||
} else {
|
} else {
|
||||||
re = ( ! fileInfo.canonicalFilePath().endsWith(relFile, Qt::CaseSensitive) );
|
// Need to normalize to composited form because of
|
||||||
|
// https://bugreports.qt-project.org/browse/QTBUG-39622
|
||||||
|
const QString cName = fileInfo.canonicalFilePath().normalized(QString::NormalizationForm_C);
|
||||||
|
// qDebug() << Q_FUNC_INFO << "comparing " << cName << " with " << file;
|
||||||
|
bool equal = (file == cName);
|
||||||
|
re = (!equal && ! cName.endsWith(relFile, Qt::CaseSensitive) );
|
||||||
|
// qDebug() << Q_FUNC_INFO << "Returning for localFileNameClash: " << re;
|
||||||
}
|
}
|
||||||
#elif defined(Q_OS_WIN)
|
#elif defined(Q_OS_WIN)
|
||||||
const QString file( _localDir + relFile );
|
const QString file( _localDir + relFile );
|
||||||
|
|||||||
@@ -111,6 +111,15 @@ void OwncloudSetupWizard::startWizard()
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ocWizard->setProperty("localFolder", localFolder);
|
_ocWizard->setProperty("localFolder", localFolder);
|
||||||
|
|
||||||
|
// remember the local folder to compare later if it changed, but clean first
|
||||||
|
QString lf = QDir::fromNativeSeparators(localFolder);
|
||||||
|
if( !lf.endsWith(QLatin1Char('/'))) {
|
||||||
|
lf.append(QLatin1Char('/'));
|
||||||
|
}
|
||||||
|
|
||||||
|
_initLocalFolder = lf;
|
||||||
|
|
||||||
_ocWizard->setRemoteFolder(_remoteFolder);
|
_ocWizard->setRemoteFolder(_remoteFolder);
|
||||||
|
|
||||||
_ocWizard->setStartId(WizardCommon::Page_ServerSetup);
|
_ocWizard->setStartId(WizardCommon::Page_ServerSetup);
|
||||||
@@ -135,6 +144,8 @@ void OwncloudSetupWizard::slotDetermineAuthType(const QString &urlString)
|
|||||||
}
|
}
|
||||||
Account *account = _ocWizard->account();
|
Account *account = _ocWizard->account();
|
||||||
account->setUrl(url);
|
account->setUrl(url);
|
||||||
|
// Set fake credentials beforfe we check what credidential it actually is.
|
||||||
|
account->setCredentials(CredentialsFactory::create("dummy"));
|
||||||
CheckServerJob *job = new CheckServerJob(_ocWizard->account(), false, this);
|
CheckServerJob *job = new CheckServerJob(_ocWizard->account(), false, this);
|
||||||
job->setIgnoreCredentialFailure(true);
|
job->setIgnoreCredentialFailure(true);
|
||||||
connect(job, SIGNAL(instanceFound(QUrl,QVariantMap)), SLOT(slotOwnCloudFoundAuth(QUrl,QVariantMap)));
|
connect(job, SIGNAL(instanceFound(QUrl,QVariantMap)), SLOT(slotOwnCloudFoundAuth(QUrl,QVariantMap)));
|
||||||
@@ -392,10 +403,17 @@ void OwncloudSetupWizard::slotAssistantFinished( int result )
|
|||||||
|
|
||||||
Account *newAccount = _ocWizard->account();
|
Account *newAccount = _ocWizard->account();
|
||||||
Account *origAccount = AccountManager::instance()->account();
|
Account *origAccount = AccountManager::instance()->account();
|
||||||
const QString localFolder = _ocWizard->localFolder();
|
|
||||||
|
QString localFolder = QDir::fromNativeSeparators(_ocWizard->localFolder());
|
||||||
|
if( !localFolder.endsWith(QLatin1Char('/'))) {
|
||||||
|
localFolder.append(QLatin1Char('/'));
|
||||||
|
}
|
||||||
|
|
||||||
bool isInitialSetup = (origAccount == 0);
|
bool isInitialSetup = (origAccount == 0);
|
||||||
bool reinitRequired = newAccount->changed(origAccount, true /* ignoreProtocol, allows http->https */);
|
|
||||||
|
// check if either the account or the local folder changed, than reinit
|
||||||
|
bool reinitRequired = _initLocalFolder != localFolder ||
|
||||||
|
newAccount->changed(origAccount, true /* ignoreProtocol, allows http->https */);
|
||||||
bool startFromScratch = _ocWizard->field("OCSyncFromScratch").toBool();
|
bool startFromScratch = _ocWizard->field("OCSyncFromScratch").toBool();
|
||||||
|
|
||||||
// This distinguishes three possibilities:
|
// This distinguishes three possibilities:
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ private:
|
|||||||
|
|
||||||
Account* _account;
|
Account* _account;
|
||||||
OwncloudWizard* _ocWizard;
|
OwncloudWizard* _ocWizard;
|
||||||
|
QString _initLocalFolder;
|
||||||
QString _remoteFolder;
|
QString _remoteFolder;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -328,8 +328,7 @@ void PropagateNeonJob::limitBandwidth(qint64 progress, qint64 bandwidth_limit)
|
|||||||
// -bandwidth_limit is the % of bandwidth
|
// -bandwidth_limit is the % of bandwidth
|
||||||
int64_t wait_time = -diff * (1 + 100.0 / bandwidth_limit);
|
int64_t wait_time = -diff * (1 + 100.0 / bandwidth_limit);
|
||||||
if (wait_time > 0) {
|
if (wait_time > 0) {
|
||||||
Mirall::Utility::usleep(wait_time);
|
Mirall::Utility::usleep(qMin(wait_time, int64_t(1000000*10)));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_lastTime.start();
|
_lastTime.start();
|
||||||
@@ -397,24 +396,39 @@ void PropagateDownloadFileLegacy::install_content_reader( ne_request *req, void
|
|||||||
|
|
||||||
if (etag.isEmpty()) {
|
if (etag.isEmpty()) {
|
||||||
qDebug() << Q_FUNC_INFO << "No E-Tag reply by server, considering it invalid" << ne_get_response_header(req, "etag");
|
qDebug() << Q_FUNC_INFO << "No E-Tag reply by server, considering it invalid" << ne_get_response_header(req, "etag");
|
||||||
that->errorString = tr("No E-Tag received from server, check Proxy/Gateway");
|
that->abortTransfer(req, tr("No E-Tag received from server, check Proxy/Gateway"));
|
||||||
ne_set_error(that->_propagator->_session, "%s", that->errorString.toUtf8().data());
|
|
||||||
ne_add_response_body_reader( req, do_not_accept,
|
|
||||||
do_not_download_content_reader,
|
|
||||||
(void*) that );
|
|
||||||
return;
|
return;
|
||||||
} else if (!that->_expectedEtagForResume.isEmpty() && that->_expectedEtagForResume != etag) {
|
} else if (!that->_expectedEtagForResume.isEmpty() && that->_expectedEtagForResume != etag) {
|
||||||
qDebug() << Q_FUNC_INFO << "We received a different E-Tag for resuming!"
|
qDebug() << Q_FUNC_INFO << "We received a different E-Tag for resuming!"
|
||||||
<< QString::fromLatin1(that->_expectedEtagForResume.data()) << "vs"
|
<< QString::fromLatin1(that->_expectedEtagForResume.data()) << "vs"
|
||||||
<< QString::fromLatin1(etag.data());
|
<< QString::fromLatin1(etag.data());
|
||||||
that->errorString = tr("We received a different E-Tag for resuming. Retrying next time.");
|
that->abortTransfer(req, tr("We received a different E-Tag for resuming. Retrying next time."));
|
||||||
ne_set_error(that->_propagator->_session, "%s", that->errorString.toUtf8().data());
|
|
||||||
ne_add_response_body_reader( req, do_not_accept,
|
|
||||||
do_not_download_content_reader,
|
|
||||||
(void*) that );
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quint64 start = 0;
|
||||||
|
QByteArray ranges = ne_get_response_header(req, "content-range");
|
||||||
|
if (!ranges.isEmpty()) {
|
||||||
|
QRegExp rx("bytes (\\d+)-");
|
||||||
|
if (rx.indexIn(ranges) >= 0) {
|
||||||
|
start = rx.cap(1).toULongLong();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (start != that->_resumeStart) {
|
||||||
|
qDebug() << Q_FUNC_INFO << "Wrong content-range: "<< ranges << " while expecting start was" << that->_resumeStart;
|
||||||
|
if (start == 0) {
|
||||||
|
// device don't support range, just stry again from scratch
|
||||||
|
that->_file->close();
|
||||||
|
if (!that->_file->open(QIODevice::WriteOnly)) {
|
||||||
|
that->abortTransfer(req, that->_file->errorString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
that->abortTransfer(req, tr("Server returned wrong content-range"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *enc = ne_get_response_header( req, "Content-Encoding" );
|
const char *enc = ne_get_response_header( req, "Content-Encoding" );
|
||||||
qDebug("Content encoding ist <%s> with status %d", enc ? enc : "empty",
|
qDebug("Content encoding ist <%s> with status %d", enc ? enc : "empty",
|
||||||
@@ -431,6 +445,16 @@ void PropagateDownloadFileLegacy::install_content_reader( ne_request *req, void
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PropagateDownloadFileLegacy::abortTransfer(ne_request* req, const QString& error)
|
||||||
|
{
|
||||||
|
errorString = error;
|
||||||
|
ne_set_error(_propagator->_session, "%s", errorString.toUtf8().data());
|
||||||
|
ne_add_response_body_reader( req, do_not_accept,
|
||||||
|
do_not_download_content_reader,
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PropagateDownloadFileLegacy::notify_status_cb(void* userdata, ne_session_status status,
|
void PropagateDownloadFileLegacy::notify_status_cb(void* userdata, ne_session_status status,
|
||||||
const ne_session_status_info* info)
|
const ne_session_status_info* info)
|
||||||
{
|
{
|
||||||
@@ -521,6 +545,7 @@ void PropagateDownloadFileLegacy::start()
|
|||||||
ne_add_request_header(req.data(), "Range", rangeRequest.constData());
|
ne_add_request_header(req.data(), "Range", rangeRequest.constData());
|
||||||
ne_add_request_header(req.data(), "Accept-Ranges", "bytes");
|
ne_add_request_header(req.data(), "Accept-Ranges", "bytes");
|
||||||
qDebug() << "Retry with range " << rangeRequest;
|
qDebug() << "Retry with range " << rangeRequest;
|
||||||
|
_resumeStart = done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* hook called before the content is parsed to set the correct reader,
|
/* hook called before the content is parsed to set the correct reader,
|
||||||
|
|||||||
@@ -53,13 +53,14 @@ class PropagateDownloadFileLegacy: public PropagateNeonJob {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit PropagateDownloadFileLegacy(OwncloudPropagator* propagator,const SyncFileItem& item)
|
explicit PropagateDownloadFileLegacy(OwncloudPropagator* propagator,const SyncFileItem& item)
|
||||||
: PropagateNeonJob(propagator, item), _file(0) {}
|
: PropagateNeonJob(propagator, item), _file(0), _resumeStart(0) {}
|
||||||
void start();
|
void start();
|
||||||
private:
|
private:
|
||||||
QFile *_file;
|
QFile *_file;
|
||||||
QScopedPointer<ne_decompress, ScopedPointerHelpers> _decompress;
|
QScopedPointer<ne_decompress, ScopedPointerHelpers> _decompress;
|
||||||
QString errorString;
|
QString errorString;
|
||||||
QByteArray _expectedEtagForResume;
|
QByteArray _expectedEtagForResume;
|
||||||
|
quint64 _resumeStart;
|
||||||
|
|
||||||
static int do_not_accept (void *userdata, ne_request *req, const ne_status *st)
|
static int do_not_accept (void *userdata, ne_request *req, const ne_status *st)
|
||||||
{
|
{
|
||||||
@@ -78,6 +79,9 @@ private:
|
|||||||
static void install_content_reader( ne_request *req, void *userdata, const ne_status *status );
|
static void install_content_reader( ne_request *req, void *userdata, const ne_status *status );
|
||||||
static void notify_status_cb(void* userdata, ne_session_status status,
|
static void notify_status_cb(void* userdata, ne_session_status status,
|
||||||
const ne_session_status_info* info);
|
const ne_session_status_info* info);
|
||||||
|
|
||||||
|
/** To be called from install_content_reader if we want to abort the transfer */
|
||||||
|
void abortTransfer(ne_request *req, const QString &error);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,14 +119,15 @@ void PropagateUploadFileQNAM::start()
|
|||||||
|
|
||||||
struct ChunkDevice : QIODevice {
|
struct ChunkDevice : QIODevice {
|
||||||
public:
|
public:
|
||||||
QIODevice *_file;
|
QPointer<QIODevice> _file;
|
||||||
qint64 _read;
|
qint64 _read;
|
||||||
qint64 _size;
|
qint64 _size;
|
||||||
qint64 _start;
|
qint64 _start;
|
||||||
|
|
||||||
ChunkDevice(QIODevice *file, qint64 start, qint64 size)
|
ChunkDevice(QIODevice *file, qint64 start, qint64 size)
|
||||||
: QIODevice(file), _file(file), _read(0), _size(size), _start(start) {
|
: QIODevice(file), _file(file), _read(0), _size(size), _start(start) {
|
||||||
_file->seek(start);
|
_file = QPointer<QIODevice>(file);
|
||||||
|
_file.data()->seek(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual qint64 writeData(const char* , qint64 ) {
|
virtual qint64 writeData(const char* , qint64 ) {
|
||||||
@@ -135,10 +136,15 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual qint64 readData(char* data, qint64 maxlen) {
|
virtual qint64 readData(char* data, qint64 maxlen) {
|
||||||
|
if (_file.isNull()) {
|
||||||
|
qDebug() << Q_FUNC_INFO << "Upload file object deleted during upload";
|
||||||
|
close();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
maxlen = qMin(maxlen, chunkSize() - _read);
|
maxlen = qMin(maxlen, chunkSize() - _read);
|
||||||
if (maxlen == 0)
|
if (maxlen == 0)
|
||||||
return 0;
|
return 0;
|
||||||
qint64 ret = _file->read(data, maxlen);
|
qint64 ret = _file.data()->read(data, maxlen);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return -1;
|
return -1;
|
||||||
_read += ret;
|
_read += ret;
|
||||||
@@ -146,7 +152,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual bool atEnd() const {
|
virtual bool atEnd() const {
|
||||||
return _read >= chunkSize() || _file->atEnd();
|
if (_file.isNull()) {
|
||||||
|
qDebug() << Q_FUNC_INFO << "Upload file object deleted during upload";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return _read >= chunkSize() || _file.data()->atEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual qint64 size() const{
|
virtual qint64 size() const{
|
||||||
@@ -164,8 +174,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual bool seek ( qint64 pos ) {
|
virtual bool seek ( qint64 pos ) {
|
||||||
|
if (_file.isNull()) {
|
||||||
|
qDebug() << Q_FUNC_INFO << "Upload file object deleted during upload";
|
||||||
|
close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
_read = pos;
|
_read = pos;
|
||||||
return _file->seek(pos + _start);
|
return _file.data()->seek(pos + _start);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -288,7 +303,7 @@ void PropagateUploadFileQNAM::slotPutFinished()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Utility::qDateTimeToTime_t(fi.lastModified()) != _item._modtime) {
|
if (Utility::qDateTimeToTime_t(fi.lastModified()) != _item._modtime) {
|
||||||
/* Uh oh: The local file has changed during upload */
|
qDebug() << "The local file has changed during upload:" << _item._modtime << "!=" << Utility::qDateTimeToTime_t(fi.lastModified()) << fi.lastModified();
|
||||||
_propagator->_activeJobs--;
|
_propagator->_activeJobs--;
|
||||||
done(SyncFileItem::SoftError, tr("Local file changed during sync."));
|
done(SyncFileItem::SoftError, tr("Local file changed during sync."));
|
||||||
// FIXME: the legacy code was retrying for a few seconds.
|
// FIXME: the legacy code was retrying for a few seconds.
|
||||||
@@ -387,6 +402,7 @@ void GETFileJob::start() {
|
|||||||
|
|
||||||
setReply(davRequest("GET", path(), req));
|
setReply(davRequest("GET", path(), req));
|
||||||
setupConnections(reply());
|
setupConnections(reply());
|
||||||
|
reply()->setReadBufferSize(128 * 1024);
|
||||||
|
|
||||||
if( reply()->error() != QNetworkReply::NoError ) {
|
if( reply()->error() != QNetworkReply::NoError ) {
|
||||||
qWarning() << Q_FUNC_INFO << " Network error: " << reply()->errorString();
|
qWarning() << Q_FUNC_INFO << " Network error: " << reply()->errorString();
|
||||||
@@ -423,11 +439,39 @@ void GETFileJob::slotMetaDataChanged()
|
|||||||
reply()->abort();
|
reply()->abort();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quint64 start = 0;
|
||||||
|
QByteArray ranges = parseEtag(reply()->rawHeader("Content-Range"));
|
||||||
|
if (!ranges.isEmpty()) {
|
||||||
|
QRegExp rx("bytes (\\d+)-");
|
||||||
|
if (rx.indexIn(ranges) >= 0) {
|
||||||
|
start = rx.cap(1).toULongLong();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (start != _resumeStart) {
|
||||||
|
qDebug() << Q_FUNC_INFO << "Wrong content-range: "<< ranges << " while expecting start was" << _resumeStart;
|
||||||
|
if (start == 0) {
|
||||||
|
// device don't support range, just stry again from scratch
|
||||||
|
_device->close();
|
||||||
|
if (!_device->open(QIODevice::WriteOnly)) {
|
||||||
|
_errorString = _device->errorString();
|
||||||
|
_errorStatus = SyncFileItem::NormalError;
|
||||||
|
reply()->abort();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_errorString = tr("Server returned wrong content-range");
|
||||||
|
_errorStatus = SyncFileItem::NormalError;
|
||||||
|
reply()->abort();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GETFileJob::slotReadyRead()
|
void GETFileJob::slotReadyRead()
|
||||||
{
|
{
|
||||||
int bufferSize = qMax(1024*8ll , reply()->bytesAvailable());
|
int bufferSize = qMin(1024*8ll , reply()->bytesAvailable());
|
||||||
QByteArray buffer(bufferSize, Qt::Uninitialized);
|
QByteArray buffer(bufferSize, Qt::Uninitialized);
|
||||||
|
|
||||||
while(reply()->bytesAvailable() > 0) {
|
while(reply()->bytesAvailable() > 0) {
|
||||||
@@ -529,7 +573,7 @@ void PropagateDownloadFileQNAM::start()
|
|||||||
|
|
||||||
_job = new GETFileJob(AccountManager::instance()->account(),
|
_job = new GETFileJob(AccountManager::instance()->account(),
|
||||||
_propagator->_remoteFolder + _item._file,
|
_propagator->_remoteFolder + _item._file,
|
||||||
&_tmpFile, headers, expectedEtagForResume);
|
&_tmpFile, headers, expectedEtagForResume, _startSize);
|
||||||
_job->setTimeout(_propagator->httpTimeout() * 1000);
|
_job->setTimeout(_propagator->httpTimeout() * 1000);
|
||||||
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
|
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
|
||||||
connect(_job, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slotDownloadProgress(qint64,qint64)));
|
connect(_job, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slotDownloadProgress(qint64,qint64)));
|
||||||
|
|||||||
@@ -99,26 +99,27 @@ private slots:
|
|||||||
void slotUploadProgress(qint64,qint64);
|
void slotUploadProgress(qint64,qint64);
|
||||||
void abort();
|
void abort();
|
||||||
void startNextChunk();
|
void startNextChunk();
|
||||||
void finalize(const Mirall::SyncFileItem&);
|
void finalize(const SyncFileItem&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class GETFileJob : public AbstractNetworkJob {
|
class GETFileJob : public AbstractNetworkJob {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QIODevice* _device;
|
QFile* _device;
|
||||||
QMap<QByteArray, QByteArray> _headers;
|
QMap<QByteArray, QByteArray> _headers;
|
||||||
QString _errorString;
|
QString _errorString;
|
||||||
QByteArray _expectedEtagForResume;
|
QByteArray _expectedEtagForResume;
|
||||||
|
quint64 _resumeStart;
|
||||||
SyncFileItem::Status _errorStatus;
|
SyncFileItem::Status _errorStatus;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// DOES NOT take owncership of the device.
|
// DOES NOT take owncership of the device.
|
||||||
explicit GETFileJob(Account* account, const QString& path, QIODevice *device,
|
explicit GETFileJob(Account* account, const QString& path, QFile *device,
|
||||||
const QMap<QByteArray, QByteArray> &headers, QByteArray expectedEtagForResume,
|
const QMap<QByteArray, QByteArray> &headers, QByteArray expectedEtagForResume,
|
||||||
QObject* parent = 0)
|
quint64 resumeStart, QObject* parent = 0)
|
||||||
: AbstractNetworkJob(account, path, parent),
|
: AbstractNetworkJob(account, path, parent),
|
||||||
_device(device), _headers(headers), _expectedEtagForResume(expectedEtagForResume),
|
_device(device), _headers(headers), _expectedEtagForResume(expectedEtagForResume),
|
||||||
_errorStatus(SyncFileItem::NoStatus) {}
|
_resumeStart(resumeStart), _errorStatus(SyncFileItem::NoStatus) {}
|
||||||
|
|
||||||
virtual void start();
|
virtual void start();
|
||||||
virtual bool finished() {
|
virtual bool finished() {
|
||||||
|
|||||||
@@ -131,6 +131,13 @@ void ProtocolWidget::slotClearBlacklist()
|
|||||||
void ProtocolWidget::cleanIgnoreItems(const QString& folder)
|
void ProtocolWidget::cleanIgnoreItems(const QString& folder)
|
||||||
{
|
{
|
||||||
int itemCnt = _ui->_treeWidget->topLevelItemCount();
|
int itemCnt = _ui->_treeWidget->topLevelItemCount();
|
||||||
|
|
||||||
|
// Limit the number of items
|
||||||
|
while(itemCnt > 2000) {
|
||||||
|
delete _ui->_treeWidget->takeTopLevelItem(itemCnt - 1);
|
||||||
|
itemCnt--;
|
||||||
|
}
|
||||||
|
|
||||||
for( int cnt = itemCnt-1; cnt >=0 ; cnt-- ) {
|
for( int cnt = itemCnt-1; cnt >=0 ; cnt-- ) {
|
||||||
QTreeWidgetItem *item = _ui->_treeWidget->topLevelItem(cnt);
|
QTreeWidgetItem *item = _ui->_treeWidget->topLevelItem(cnt);
|
||||||
bool isErrorItem = item->data(0, IgnoredIndicatorRole).toBool();
|
bool isErrorItem = item->data(0, IgnoredIndicatorRole).toBool();
|
||||||
|
|||||||
@@ -61,7 +61,8 @@ SyncEngine::SyncEngine(CSYNC *ctx, const QString& localPath, const QString& remo
|
|||||||
, _remoteUrl(remoteURL)
|
, _remoteUrl(remoteURL)
|
||||||
, _remotePath(remotePath)
|
, _remotePath(remotePath)
|
||||||
, _journal(journal)
|
, _journal(journal)
|
||||||
, _hasFiles(false)
|
, _hasNoneFiles(false)
|
||||||
|
, _hasRemoveFile(false)
|
||||||
, _downloadLimit(0)
|
, _downloadLimit(0)
|
||||||
, _uploadLimit(0)
|
, _uploadLimit(0)
|
||||||
|
|
||||||
@@ -330,7 +331,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
|||||||
dir = SyncFileItem::None;
|
dir = SyncFileItem::None;
|
||||||
} else {
|
} else {
|
||||||
// No need to do anything.
|
// No need to do anything.
|
||||||
_hasFiles = true;
|
_hasNoneFiles = true;
|
||||||
|
|
||||||
emit syncItemDiscovered(item);
|
emit syncItemDiscovered(item);
|
||||||
return re;
|
return re;
|
||||||
@@ -343,8 +344,9 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
|||||||
_renamedFolders.insert(item._file, item._renameTarget);
|
_renamedFolders.insert(item._file, item._renameTarget);
|
||||||
break;
|
break;
|
||||||
case CSYNC_INSTRUCTION_REMOVE:
|
case CSYNC_INSTRUCTION_REMOVE:
|
||||||
|
_hasRemoveFile = true;
|
||||||
dir = !remote ? SyncFileItem::Down : SyncFileItem::Up;
|
dir = !remote ? SyncFileItem::Down : SyncFileItem::Up;
|
||||||
break;
|
break;
|
||||||
case CSYNC_INSTRUCTION_CONFLICT:
|
case CSYNC_INSTRUCTION_CONFLICT:
|
||||||
case CSYNC_INSTRUCTION_IGNORE:
|
case CSYNC_INSTRUCTION_IGNORE:
|
||||||
case CSYNC_INSTRUCTION_ERROR:
|
case CSYNC_INSTRUCTION_ERROR:
|
||||||
@@ -356,6 +358,11 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
|||||||
case CSYNC_INSTRUCTION_STAT_ERROR:
|
case CSYNC_INSTRUCTION_STAT_ERROR:
|
||||||
default:
|
default:
|
||||||
dir = remote ? SyncFileItem::Down : SyncFileItem::Up;
|
dir = remote ? SyncFileItem::Down : SyncFileItem::Up;
|
||||||
|
if (!remote && file->instruction == CSYNC_INSTRUCTION_SYNC) {
|
||||||
|
// An upload of an existing file means that the file was left unchanged on the server
|
||||||
|
// This count as a NONE for detecting if all the file on the server were changed
|
||||||
|
_hasNoneFiles = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,11 +371,6 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
|||||||
// if the item is on blacklist, the instruction was set to IGNORE
|
// if the item is on blacklist, the instruction was set to IGNORE
|
||||||
checkBlacklisting( &item );
|
checkBlacklisting( &item );
|
||||||
|
|
||||||
if (file->instruction != CSYNC_INSTRUCTION_IGNORE
|
|
||||||
&& file->instruction != CSYNC_INSTRUCTION_REMOVE) {
|
|
||||||
_hasFiles = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!item._isDirectory) {
|
if (!item._isDirectory) {
|
||||||
_progressInfo._totalFileCount++;
|
_progressInfo._totalFileCount++;
|
||||||
if (Progress::isSizeDependent(file->instruction)) {
|
if (Progress::isSizeDependent(file->instruction)) {
|
||||||
@@ -526,7 +528,8 @@ void SyncEngine::slotUpdateFinished(int updateResult)
|
|||||||
|
|
||||||
_progressInfo = Progress::Info();
|
_progressInfo = Progress::Info();
|
||||||
|
|
||||||
_hasFiles = false;
|
_hasNoneFiles = false;
|
||||||
|
_hasRemoveFile = false;
|
||||||
bool walkOk = true;
|
bool walkOk = true;
|
||||||
_seenFiles.clear();
|
_seenFiles.clear();
|
||||||
|
|
||||||
@@ -556,8 +559,8 @@ void SyncEngine::slotUpdateFinished(int updateResult)
|
|||||||
emit aboutToPropagate(_syncedItems);
|
emit aboutToPropagate(_syncedItems);
|
||||||
emit transmissionProgress(_progressInfo);
|
emit transmissionProgress(_progressInfo);
|
||||||
|
|
||||||
if (!_hasFiles && !_syncedItems.isEmpty()) {
|
if (!_hasNoneFiles && _hasRemoveFile) {
|
||||||
qDebug() << Q_FUNC_INFO << "All the files are going to be removed, asking the user";
|
qDebug() << Q_FUNC_INFO << "All the files are going to be changed, asking the user";
|
||||||
bool cancel = false;
|
bool cancel = false;
|
||||||
emit aboutToRemoveAllFiles(_syncedItems.first()._direction, &cancel);
|
emit aboutToRemoveAllFiles(_syncedItems.first()._direction, &cancel);
|
||||||
if (cancel) {
|
if (cancel) {
|
||||||
|
|||||||
@@ -127,7 +127,8 @@ private:
|
|||||||
QHash<QString, QString> _renamedFolders;
|
QHash<QString, QString> _renamedFolders;
|
||||||
QString adjustRenamedPath(const QString &original);
|
QString adjustRenamedPath(const QString &original);
|
||||||
|
|
||||||
bool _hasFiles; // true if there is at least one file that is not ignored or removed
|
bool _hasNoneFiles; // true if there is at least one file with instruction NONE
|
||||||
|
bool _hasRemoveFile; // true if there is at leasr one file with instruction REMOVE
|
||||||
|
|
||||||
int _downloadLimit;
|
int _downloadLimit;
|
||||||
int _uploadLimit;
|
int _uploadLimit;
|
||||||
|
|||||||
Reference in New Issue
Block a user