1
0
mirror of https://github.com/chylex/Nextcloud-Desktop.git synced 2026-04-03 09:11:33 +02:00

Compare commits

..

23 Commits

Author SHA1 Message Date
Klaas Freitag
0f37484b8a Bumped the release number to 1.6.2, Changelog additions. 2014-07-28 11:44:10 +02:00
Olivier Goffart
3d0c009719 propagator_qnam: Limit the HTTP buffer size when downloading
Otherwise the buffer might fill up too quickly and get too large and consume
too much memory which could lead to crash in extreme cases

Should fix issue #1974
2014-07-24 15:43:28 +02:00
Olivier Goffart
208011f6ab propagator_qnam: add debug output in cae the file changed localy
In order to debug https://github.com/owncloud/core/issues/9781
2014-07-24 11:17:59 +02:00
Daniel Molkentin
f84e0010ee NSIS: ICU rebumped to 5.3 as per build service change 2014-07-24 10:07:46 +02:00
Klaas Freitag
c97f46d403 Bump version to 1.6.2 rc2 plus Changelog 2014-07-24 09:58:23 +02:00
Klaas Freitag
1fb52f0d8b HTTPCreds: Do delete the WritePasswordJob to not leak memory. 2014-07-23 17:59:02 +02:00
Klaas Freitag
d4de024f15 Propagator: Fix local file name clash detection.
Need to normalize the output of QFileInfo::canonicalFilePath() before
comparing to a server side path.
See https://bugreports.qt-project.org/browse/QTBUG-39622

This fixes #1998 and #1999
2014-07-23 17:56:46 +02:00
Olivier Goffart
1d9d88ca85 Always use the dummy crendential while trying to determine the credentials
Otherwise the SHibbolethCredential may be set and it has hook to intercept 401

This should fix issue #1908
2014-07-23 14:38:50 +02:00
Olivier Goffart
beb9300b4e network limit: Never wait more than 10 seconds
When using the "Limit automatically" limit, we wait for 25% of the time
it took to upload something.
However, if we go to sleep while uploading, the time it took to upload may take
days. And waiting for 25% of a day is too long.
So never wait for more than 10 seconds

This may be related to issue #1880
2014-07-18 12:27:02 +02:00
Olivier Goffart
c35880d4f1 Fix corruption while trying to resume and the server don't suport it
Issue #1982
2014-07-18 12:03:45 +02:00
Klaas Freitag
d8ebebaf12 WinInstaller: No hardcoded www in front of the url on final page. 2014-07-16 18:39:51 +02:00
Klaas Freitag
af3fae9c28 Bumped to 1.6.2 rc1 2014-07-16 14:32:58 +02:00
Klaas Freitag
d3b72940fd Updated Changelog for 1.6.2 2014-07-16 11:56:17 +02:00
Daniel Molkentin
e8de3e855a 1.6.2 2014-07-16 11:43:13 +02:00
Klaas Freitag
71338000a4 SetupWizard: Keep initial local folder to compare later for changes.
If the local folder changes, the sync has to be reinitialized as
well. Until now we did not detect that, which led to the case that
the sync folder was not reinitialized in case only the local folder
changed in the setup dialog.
2014-07-16 11:37:46 +02:00
Olivier Goffart
d697969f36 Use another way to detect that the server was reconfigured
Before, we would only detect it if all the files were removed, and no
file where added or changed. This may not be enough because there might
be a welcome.txt file. Now, we check that none of the file stays the same,
and some files are removed.

Relates issue #1948
2014-07-15 18:09:08 +02:00
Olivier Goffart
51e9c5fd96 propagator_qnam Fix signal slot connection
Fix the signature so it can be connected

This was hapenning if the derver does not support X-OC-MTime

issue #1963
2014-07-15 18:08:26 +02:00
Markus Goetz
0202351a27 Propagator: Fix crash when logging out during upload
Fixes #1957
2014-07-14 19:53:42 +02:00
Olivier Goffart
63cd5ef563 ProtocolWidget: limit the number of items
That should save memory instead of letting the number of items grow
to infinity
2014-07-09 15:48:03 +02:00
Olivier Goffart
82c254fecf propagator_qnam: Avoid using too much memory
The idea here was that the buffer would be maximum 8KiB, not minimum.
2014-07-08 15:30:53 +02:00
Olivier Goffart
86bea9a9af shibboleth: Fix the waiting curser that would not disapear
Fix #1915
2014-07-07 14:08:13 +02:00
Klaas Freitag
88f26fb548 HTTP Creds: In case of Keychain error, open the interact password dialog
But in case the user clicks cancel in the interactive dialog, invalidate
the credentials. Emit fechted() also in error case.
2014-07-04 13:27:35 +02:00
Klaas Freitag
a9f1de84f0 HTTP Credentials: Read the password from the old location if not found.
Earlier clients used QtKeychain without a QSettings object, which made
QtKeychain to write the password encrypted into a settings default
location, ie. the registry under windows.

If we can not find a password at the new location it is tried to read
the password from the old default location once. That makes people
happy in migration scenarios.
2014-07-04 13:27:22 +02:00
19 changed files with 227 additions and 66 deletions

View File

@@ -1,5 +1,20 @@
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 )
* Fix 'precondition failed' bug with broken upload
* Fix openSSL problems for windows deployment

View File

@@ -1,6 +1,6 @@
set( MIRALL_VERSION_MAJOR 1 )
set( MIRALL_VERSION_MINOR 6 )
set( MIRALL_VERSION_PATCH 1 )
set( MIRALL_VERSION_PATCH 2 )
set( MIRALL_SOVERSION 0 )
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )

View File

@@ -111,8 +111,8 @@ ReserveFile "${NSISDIR}\Plugins\InstallOptions.dll"
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_BITMAP ${WIN_SETUP_BITMAP_PATH}/page_header.bmp
!define MUI_COMPONENTSPAGE_SMALLDESC
!define MUI_FINISHPAGE_LINK "www.${APPLICATION_DOMAIN}"
!define MUI_FINISHPAGE_LINK_LOCATION "http://www.${APPLICATION_DOMAIN}"
!define MUI_FINISHPAGE_LINK "${APPLICATION_DOMAIN}"
!define MUI_FINISHPAGE_LINK_LOCATION "http://${APPLICATION_DOMAIN}"
!define MUI_FINISHPAGE_NOREBOOTSUPPORT
!ifdef OPTION_FINISHPAGE_RELEASE_NOTES
!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED
@@ -414,9 +414,9 @@ Section "${APPLICATION_NAME}" SEC_APPLICATION
;Qt deps
File "${MING_BIN}\libpng16-16.dll"
File "${MING_BIN}\icudata51.dll"
File "${MING_BIN}\icui18n51.dll"
File "${MING_BIN}\icuuc51.dll"
File "${MING_BIN}\icudata53.dll"
File "${MING_BIN}\icui18n53.dll"
File "${MING_BIN}\icuuc53.dll"
File "${MING_BIN}\libEGL.dll"
File "${MING_BIN}\libGLESv2.dll"
File "${MING_BIN}\libjpeg-8.dll"

View File

@@ -101,7 +101,8 @@ HttpCredentials::HttpCredentials()
: _user(),
_password(),
_ready(false),
_fetchJobInProgress(false)
_fetchJobInProgress(false),
_readPwdFromDeprecatedPlace(false)
{
}
@@ -230,6 +231,7 @@ void HttpCredentials::fetch(Account *account)
job->setProperty("account", QVariant::fromValue(account));
job->start();
_fetchJobInProgress = true;
_readPwdFromDeprecatedPlace = true;
}
}
bool HttpCredentials::stillValid(QNetworkReply *reply)
@@ -261,18 +263,40 @@ void HttpCredentials::slotReadJobDone(QKeychain::Job *job)
_ready = true;
emit fetched();
} else {
if( error != NoError ) {
qDebug() << "Error while reading password" << job->errorString();
// we come here if the password is empty or any other keychain
// 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:
qDebug() << "Error while writing password" << job->errorString();
}
WritePasswordJob *wjob = qobject_cast<WritePasswordJob*>(job);
wjob->deleteLater();
}
void HttpCredentials::slotAuthentication(QNetworkReply* reply, QAuthenticator* authenticator)

View File

@@ -63,6 +63,7 @@ private:
QString _password;
bool _ready;
bool _fetchJobInProgress; //True if the keychain job is in progress or the input dialog visible
bool _readPwdFromDeprecatedPlace;
};
} // ns Mirall

View File

@@ -34,6 +34,7 @@ ShibbolethWebView::ShibbolethWebView(Account* account, QWidget* parent)
: QWebView(parent)
, _account(account)
, _accepted(false)
, _cursorOverriden(false)
{
// no minimize
setWindowFlags(Qt::Dialog);
@@ -79,6 +80,10 @@ void ShibbolethWebView::onNewCookiesForUrl (const QList<QNetworkCookie>& cookieL
void ShibbolethWebView::closeEvent(QCloseEvent *event)
{
if (_cursorOverriden) {
QApplication::restoreOverrideCursor();
}
if (!_accepted) {
Q_EMIT rejected();
}
@@ -87,12 +92,17 @@ void ShibbolethWebView::closeEvent(QCloseEvent *event)
void ShibbolethWebView::slotLoadStarted()
{
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
if (!_cursorOverriden) {
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
_cursorOverriden = true;
}
}
void ShibbolethWebView::slotLoadFinished(bool success)
{
QApplication::restoreOverrideCursor();
if (_cursorOverriden) {
QApplication::restoreOverrideCursor();
}
if (!title().isNull()) {
setWindowTitle(tr("%1 - %2").arg(Theme::instance()->appNameGUI(), title()));

View File

@@ -55,6 +55,7 @@ private:
void setup(Account *account, ShibbolethCookieJar* jar);
QPointer<Account> _account;
bool _accepted;
bool _cursorOverriden;
};
} // ns Mirall

View File

@@ -704,10 +704,7 @@ void Folder::slotTransmissionProgress(const Progress::Info &pi)
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel)
{
#ifndef TOKEN_AUTH_ONLY
QString msg = direction == SyncFileItem::Down ?
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\".") :
QString msg =
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 "
"the file were manually removed.\n"

View File

@@ -337,8 +337,15 @@ bool OwncloudPropagator::localFileNameClash( const QString& relFile )
QFileInfo fileInfo(file);
if (!fileInfo.exists()) {
re = false;
qDebug() << Q_FUNC_INFO << "No valid fileinfo";
} 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)
const QString file( _localDir + relFile );

View File

@@ -111,6 +111,15 @@ void OwncloudSetupWizard::startWizard()
}
_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->setStartId(WizardCommon::Page_ServerSetup);
@@ -135,6 +144,8 @@ void OwncloudSetupWizard::slotDetermineAuthType(const QString &urlString)
}
Account *account = _ocWizard->account();
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);
job->setIgnoreCredentialFailure(true);
connect(job, SIGNAL(instanceFound(QUrl,QVariantMap)), SLOT(slotOwnCloudFoundAuth(QUrl,QVariantMap)));
@@ -392,10 +403,17 @@ void OwncloudSetupWizard::slotAssistantFinished( int result )
Account *newAccount = _ocWizard->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 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();
// This distinguishes three possibilities:

View File

@@ -94,6 +94,7 @@ private:
Account* _account;
OwncloudWizard* _ocWizard;
QString _initLocalFolder;
QString _remoteFolder;
};

View File

@@ -328,8 +328,7 @@ void PropagateNeonJob::limitBandwidth(qint64 progress, qint64 bandwidth_limit)
// -bandwidth_limit is the % of bandwidth
int64_t wait_time = -diff * (1 + 100.0 / bandwidth_limit);
if (wait_time > 0) {
Mirall::Utility::usleep(wait_time);
Mirall::Utility::usleep(qMin(wait_time, int64_t(1000000*10)));
}
}
_lastTime.start();
@@ -397,24 +396,39 @@ void PropagateDownloadFileLegacy::install_content_reader( ne_request *req, void
if (etag.isEmpty()) {
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");
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 );
that->abortTransfer(req, tr("No E-Tag received from server, check Proxy/Gateway"));
return;
} else if (!that->_expectedEtagForResume.isEmpty() && that->_expectedEtagForResume != etag) {
qDebug() << Q_FUNC_INFO << "We received a different E-Tag for resuming!"
<< QString::fromLatin1(that->_expectedEtagForResume.data()) << "vs"
<< QString::fromLatin1(etag.data());
that->errorString = 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 );
that->abortTransfer(req, tr("We received a different E-Tag for resuming. Retrying next time."));
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" );
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,
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(), "Accept-Ranges", "bytes");
qDebug() << "Retry with range " << rangeRequest;
_resumeStart = done;
}
/* hook called before the content is parsed to set the correct reader,

View File

@@ -53,13 +53,14 @@ class PropagateDownloadFileLegacy: public PropagateNeonJob {
Q_OBJECT
public:
explicit PropagateDownloadFileLegacy(OwncloudPropagator* propagator,const SyncFileItem& item)
: PropagateNeonJob(propagator, item), _file(0) {}
: PropagateNeonJob(propagator, item), _file(0), _resumeStart(0) {}
void start();
private:
QFile *_file;
QScopedPointer<ne_decompress, ScopedPointerHelpers> _decompress;
QString errorString;
QByteArray _expectedEtagForResume;
quint64 _resumeStart;
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 notify_status_cb(void* userdata, ne_session_status status,
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);
};
}

View File

@@ -119,14 +119,15 @@ void PropagateUploadFileQNAM::start()
struct ChunkDevice : QIODevice {
public:
QIODevice *_file;
QPointer<QIODevice> _file;
qint64 _read;
qint64 _size;
qint64 _start;
ChunkDevice(QIODevice *file, qint64 start, qint64 size)
: 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 ) {
@@ -135,10 +136,15 @@ public:
}
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);
if (maxlen == 0)
return 0;
qint64 ret = _file->read(data, maxlen);
qint64 ret = _file.data()->read(data, maxlen);
if (ret < 0)
return -1;
_read += ret;
@@ -146,7 +152,11 @@ public:
}
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{
@@ -164,8 +174,13 @@ public:
}
virtual bool seek ( qint64 pos ) {
if (_file.isNull()) {
qDebug() << Q_FUNC_INFO << "Upload file object deleted during upload";
close();
return false;
}
_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) {
/* 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--;
done(SyncFileItem::SoftError, tr("Local file changed during sync."));
// FIXME: the legacy code was retrying for a few seconds.
@@ -387,6 +402,7 @@ void GETFileJob::start() {
setReply(davRequest("GET", path(), req));
setupConnections(reply());
reply()->setReadBufferSize(128 * 1024);
if( reply()->error() != QNetworkReply::NoError ) {
qWarning() << Q_FUNC_INFO << " Network error: " << reply()->errorString();
@@ -423,11 +439,39 @@ void GETFileJob::slotMetaDataChanged()
reply()->abort();
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()
{
int bufferSize = qMax(1024*8ll , reply()->bytesAvailable());
int bufferSize = qMin(1024*8ll , reply()->bytesAvailable());
QByteArray buffer(bufferSize, Qt::Uninitialized);
while(reply()->bytesAvailable() > 0) {
@@ -529,7 +573,7 @@ void PropagateDownloadFileQNAM::start()
_job = new GETFileJob(AccountManager::instance()->account(),
_propagator->_remoteFolder + _item._file,
&_tmpFile, headers, expectedEtagForResume);
&_tmpFile, headers, expectedEtagForResume, _startSize);
_job->setTimeout(_propagator->httpTimeout() * 1000);
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
connect(_job, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slotDownloadProgress(qint64,qint64)));

View File

@@ -99,26 +99,27 @@ private slots:
void slotUploadProgress(qint64,qint64);
void abort();
void startNextChunk();
void finalize(const Mirall::SyncFileItem&);
void finalize(const SyncFileItem&);
};
class GETFileJob : public AbstractNetworkJob {
Q_OBJECT
QIODevice* _device;
QFile* _device;
QMap<QByteArray, QByteArray> _headers;
QString _errorString;
QByteArray _expectedEtagForResume;
quint64 _resumeStart;
SyncFileItem::Status _errorStatus;
public:
// 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,
QObject* parent = 0)
quint64 resumeStart, QObject* parent = 0)
: AbstractNetworkJob(account, path, parent),
_device(device), _headers(headers), _expectedEtagForResume(expectedEtagForResume),
_errorStatus(SyncFileItem::NoStatus) {}
_resumeStart(resumeStart), _errorStatus(SyncFileItem::NoStatus) {}
virtual void start();
virtual bool finished() {

View File

@@ -131,6 +131,13 @@ void ProtocolWidget::slotClearBlacklist()
void ProtocolWidget::cleanIgnoreItems(const QString& folder)
{
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-- ) {
QTreeWidgetItem *item = _ui->_treeWidget->topLevelItem(cnt);
bool isErrorItem = item->data(0, IgnoredIndicatorRole).toBool();

View File

@@ -61,7 +61,8 @@ SyncEngine::SyncEngine(CSYNC *ctx, const QString& localPath, const QString& remo
, _remoteUrl(remoteURL)
, _remotePath(remotePath)
, _journal(journal)
, _hasFiles(false)
, _hasNoneFiles(false)
, _hasRemoveFile(false)
, _downloadLimit(0)
, _uploadLimit(0)
@@ -330,7 +331,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
dir = SyncFileItem::None;
} else {
// No need to do anything.
_hasFiles = true;
_hasNoneFiles = true;
emit syncItemDiscovered(item);
return re;
@@ -343,8 +344,9 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
_renamedFolders.insert(item._file, item._renameTarget);
break;
case CSYNC_INSTRUCTION_REMOVE:
_hasRemoveFile = true;
dir = !remote ? SyncFileItem::Down : SyncFileItem::Up;
break;
break;
case CSYNC_INSTRUCTION_CONFLICT:
case CSYNC_INSTRUCTION_IGNORE:
case CSYNC_INSTRUCTION_ERROR:
@@ -356,6 +358,11 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
case CSYNC_INSTRUCTION_STAT_ERROR:
default:
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;
}
@@ -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
checkBlacklisting( &item );
if (file->instruction != CSYNC_INSTRUCTION_IGNORE
&& file->instruction != CSYNC_INSTRUCTION_REMOVE) {
_hasFiles = true;
}
if (!item._isDirectory) {
_progressInfo._totalFileCount++;
if (Progress::isSizeDependent(file->instruction)) {
@@ -526,7 +528,8 @@ void SyncEngine::slotUpdateFinished(int updateResult)
_progressInfo = Progress::Info();
_hasFiles = false;
_hasNoneFiles = false;
_hasRemoveFile = false;
bool walkOk = true;
_seenFiles.clear();
@@ -556,8 +559,8 @@ void SyncEngine::slotUpdateFinished(int updateResult)
emit aboutToPropagate(_syncedItems);
emit transmissionProgress(_progressInfo);
if (!_hasFiles && !_syncedItems.isEmpty()) {
qDebug() << Q_FUNC_INFO << "All the files are going to be removed, asking the user";
if (!_hasNoneFiles && _hasRemoveFile) {
qDebug() << Q_FUNC_INFO << "All the files are going to be changed, asking the user";
bool cancel = false;
emit aboutToRemoveAllFiles(_syncedItems.first()._direction, &cancel);
if (cancel) {

View File

@@ -127,7 +127,8 @@ private:
QHash<QString, QString> _renamedFolders;
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 _uploadLimit;