nextcloud-desktop/src/mirall/folder.cpp

784 lines
24 KiB
C++
Raw Normal View History

2011-04-06 13:48:02 +04:00
/*
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
2013-07-22 22:27:42 +04:00
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
2011-04-06 13:48:02 +04:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
2013-02-25 12:54:19 +04:00
#include "config.h"
2013-10-21 23:42:52 +04:00
#include "mirall/account.h"
2011-02-17 02:21:45 +03:00
#include "mirall/folder.h"
2013-10-21 23:42:52 +04:00
#include "mirall/folderman.h"
#include "mirall/logger.h"
#include "mirall/mirallconfigfile.h"
2013-10-21 23:42:52 +04:00
#include "mirall/networkjobs.h"
#include "mirall/syncjournalfilerecord.h"
#include "mirall/syncresult.h"
2013-08-05 22:14:22 +04:00
#include "mirall/utility.h"
#include "mirall/clientproxy.h"
#include "mirall/syncengine.h"
2014-03-26 21:10:59 +04:00
#include "mirall/syncrunfilelog.h"
2013-10-21 23:42:52 +04:00
#include "creds/abstractcredentials.h"
2013-10-21 23:42:52 +04:00
extern "C" {
enum csync_exclude_type_e {
CSYNC_NOT_EXCLUDED = 0,
CSYNC_FILE_SILENTLY_EXCLUDED,
CSYNC_FILE_EXCLUDE_AND_REMOVE,
CSYNC_FILE_EXCLUDE_LIST,
CSYNC_FILE_EXCLUDE_INVALID_CHAR
};
typedef enum csync_exclude_type_e CSYNC_EXCLUDE_TYPE;
CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype);
}
2011-02-17 02:21:45 +03:00
2012-05-21 18:48:49 +04:00
#include <QDebug>
#include <QTimer>
#include <QUrl>
#include <QDir>
2014-04-06 21:34:56 +04:00
#ifndef TOKEN_AUTH_ONLY
2013-07-22 22:27:42 +04:00
#include <QMessageBox>
#include <QPushButton>
2014-04-06 21:34:56 +04:00
#endif
2012-05-21 18:48:49 +04:00
2011-02-17 02:21:45 +03:00
namespace Mirall {
Folder::Folder(const QString &alias, const QString &path, const QString& secondPath, QObject *parent)
2013-07-22 22:27:42 +04:00
: QObject(parent)
, _path(path)
2013-10-21 23:42:52 +04:00
, _remotePath(secondPath)
2013-07-22 22:27:42 +04:00
, _alias(alias)
, _enabled(true)
, _csyncError(false)
, _csyncUnavail(false)
, _wipeDb(false)
, _proxyDirty(true)
, _journal(path)
2013-07-22 22:27:42 +04:00
, _csync_ctx(0)
2011-02-17 02:21:45 +03:00
{
qsrand(QTime::currentTime().msec());
2013-08-08 16:30:45 +04:00
_timeSinceLastSync.start();
MirallConfigFile cfg;
2012-04-20 16:31:06 +04:00
_syncResult.setStatus( SyncResult::NotYetStarted );
// check if the local path exists
checkLocalPath();
int polltime = cfg.remotePollInterval();
qDebug() << "setting remote poll timer interval to" << polltime << "msec";
_pollTimer.setInterval( polltime );
QObject::connect(&_pollTimer, SIGNAL(timeout()), this, SLOT(slotPollTimerTimeout()));
_pollTimer.start();
_syncResult.setFolder(alias);
2011-02-17 02:21:45 +03:00
}
2013-07-22 22:27:42 +04:00
bool Folder::init()
{
Account *account = AccountManager::instance()->account();
if (!account) {
// Normaly this should not happen, but it could be that there is something
// wrong with the config and it is better not to crash.
qWarning() << "WRN: No account configured, can't sync";
return false;
}
2013-10-21 23:42:52 +04:00
QString url = Utility::toCSyncScheme(remoteUrl().toString());
2013-07-22 22:27:42 +04:00
QString localpath = path();
if( csync_create( &_csync_ctx, localpath.toUtf8().data(), url.toUtf8().data() ) < 0 ) {
qDebug() << "Unable to create csync-context!";
slotSyncError(tr("Unable to create csync-context"));
2013-07-22 22:27:42 +04:00
_csync_ctx = 0;
} else {
csync_set_log_callback( csyncLogCatcher );
csync_set_log_level( 11 );
2013-07-22 22:27:42 +04:00
MirallConfigFile cfgFile;
csync_set_config_dir( _csync_ctx, cfgFile.configPath().toUtf8() );
setIgnoredFiles();
if (Account *account = AccountManager::instance()->account()) {
account->credentials()->syncContextPreInit(_csync_ctx);
} else {
qDebug() << Q_FUNC_INFO << "No default Account object, huh?";
}
2013-07-22 22:27:42 +04:00
if( csync_init( _csync_ctx ) < 0 ) {
qDebug() << "Could not initialize csync!" << csync_get_status(_csync_ctx) << csync_get_status_string(_csync_ctx);
QString errStr = SyncEngine::csyncErrorToString(CSYNC_STATUS(csync_get_status(_csync_ctx)));
const char *errMsg = csync_get_status_string(_csync_ctx);
2013-08-14 17:36:34 +04:00
if( errMsg ) {
errStr += QLatin1String("<br/>");
errStr += QString::fromUtf8(errMsg);
}
slotSyncError(errStr);
2013-07-22 22:27:42 +04:00
csync_destroy(_csync_ctx);
_csync_ctx = 0;
}
}
return _csync_ctx;
}
2011-02-17 02:21:45 +03:00
Folder::~Folder()
{
if( _engine ) {
_engine->abort();
_engine.reset(0);
2013-07-22 22:27:42 +04:00
}
// Destroy csync here.
csync_destroy(_csync_ctx);
2011-02-17 02:21:45 +03:00
}
void Folder::checkLocalPath()
{
QFileInfo fi(_path);
if( fi.isDir() && fi.isReadable() ) {
qDebug() << "Checked local path ok";
} else {
if( !fi.exists() ) {
// try to create the local dir
QDir d(_path);
if( d.mkpath(_path) ) {
qDebug() << "Successfully created the local dir " << _path;
}
}
// Check directory again
if( !fi.exists() ) {
_syncResult.setErrorString(tr("Local folder %1 does not exist.").arg(_path));
_syncResult.setStatus( SyncResult::SetupError );
} else if( !fi.isDir() ) {
_syncResult.setErrorString(tr("%1 should be a directory but is not.").arg(_path));
_syncResult.setStatus( SyncResult::SetupError );
} else if( !fi.isReadable() ) {
_syncResult.setErrorString(tr("%1 is not readable.").arg(_path));
_syncResult.setStatus( SyncResult::SetupError );
}
}
}
2011-04-06 11:52:02 +04:00
QString Folder::alias() const
{
return _alias;
}
QString Folder::path() const
{
QString p(_path);
if( ! p.endsWith(QLatin1Char('/')) ) {
p.append(QLatin1Char('/'));
}
return p;
}
2013-07-22 22:27:42 +04:00
bool Folder::isBusy() const
{
return !_engine.isNull();
2013-07-22 22:27:42 +04:00
}
2013-10-21 23:42:52 +04:00
QString Folder::remotePath() const
{
return _remotePath;
}
QUrl Folder::remoteUrl() const
{
2013-10-21 23:42:52 +04:00
Account *account = AccountManager::instance()->account();
2013-10-23 16:48:44 +04:00
QUrl url = account->davUrl();
2013-10-21 23:42:52 +04:00
QString path = url.path();
2013-11-05 21:15:47 +04:00
if (!path.endsWith('/')) {
2013-10-21 23:42:52 +04:00
path.append('/');
}
path.append(_remotePath);
url.setPath(path);
return url;
}
QString Folder::nativePath() const
{
return QDir::toNativeSeparators(_path);
}
2011-10-13 18:41:24 +04:00
bool Folder::syncEnabled() const
{
return _enabled;
}
void Folder::setSyncEnabled( bool doit )
{
_enabled = doit;
if( doit ) {
// qDebug() << "Syncing enabled on folder " << name();
} else {
// do not stop or start the watcher here, that is done internally by
// folder class. Even if the watcher fires, the folder does not
// schedule itself because it checks the var. _enabled before.
_pollTimer.stop();
setSyncState(SyncResult::Paused);
}
2011-10-13 18:41:24 +04:00
}
void Folder::setSyncState(SyncResult::Status state)
{
_syncResult.setStatus(state);
}
SyncResult Folder::syncResult() const
2011-10-13 18:41:24 +04:00
{
return _syncResult;
2011-10-13 18:41:24 +04:00
}
void Folder::prepareToSync()
2011-04-06 17:57:18 +04:00
{
_syncResult.setStatus( SyncResult::NotYetStarted );
_syncResult.clearErrors();
}
void Folder::slotPollTimerTimeout()
{
2013-11-05 21:15:47 +04:00
qDebug() << "* Polling" << alias() << "for changes. (time since last sync:" << (_timeSinceLastSync.elapsed() / 1000) << "s)";
if (quint64(_timeSinceLastSync.elapsed()) > MirallConfigFile().forceSyncInterval() ||
!(_syncResult.status() == SyncResult::Success ||_syncResult.status() == SyncResult::Problem)) {
qDebug() << "** Force Sync now, state is " << _syncResult.statusString();
emit scheduleToSync(alias());
2013-08-08 16:30:45 +04:00
} else {
2013-10-23 16:48:44 +04:00
RequestEtagJob* job = new RequestEtagJob(AccountManager::instance()->account(), remotePath(), this);
2013-08-08 16:30:45 +04:00
// check if the etag is different
QObject::connect(job, SIGNAL(etagRetreived(QString)), this, SLOT(etagRetreived(QString)));
2013-11-11 13:57:33 +04:00
QObject::connect(job, SIGNAL(networkError(QNetworkReply*)), this, SLOT(slotNetworkUnavailable()));
2013-11-14 22:20:09 +04:00
job->start();
2013-08-08 16:30:45 +04:00
}
}
void Folder::etagRetreived(const QString& etag)
{
2013-08-14 13:59:35 +04:00
qDebug() << "* Compare etag with previous etag: " << (_lastEtag != etag);
// re-enable sync if it was disabled because network was down
FolderMan::instance()->setSyncEnabled(true);
if (_lastEtag != etag) {
_lastEtag = etag;
emit scheduleToSync(alias());
}
2011-04-06 17:57:18 +04:00
}
void Folder::slotNetworkUnavailable()
{
Account *account = AccountManager::instance()->account();
if (account && account->state() == Account::Connected) {
account->setState(Account::Disconnected);
}
_syncResult.setStatus(SyncResult::Unavailable);
emit syncStateChange();
}
void Folder::bubbleUpSyncResult()
{
// count new, removed and updated items
int newItems = 0;
int removedItems = 0;
int updatedItems = 0;
int ignoredItems = 0;
int renamedItems = 0;
SyncFileItem firstItemNew;
SyncFileItem firstItemDeleted;
SyncFileItem firstItemUpdated;
SyncFileItem firstItemRenamed;
Logger *logger = Logger::instance();
2014-03-26 21:10:59 +04:00
SyncRunFileLog syncFileLog;
syncFileLog.start(path(), _engine ? _engine->stopWatch() : Utility::StopWatch() );
2014-03-26 21:10:59 +04:00
QElapsedTimer timer;
timer.start();
foreach (const SyncFileItem &item, _syncResult.syncFileItemVector() ) {
2014-03-26 21:10:59 +04:00
// Log the item
syncFileLog.logItem( item );
// and process the item to the gui
if( item._status == SyncFileItem::FatalError || item._status == SyncFileItem::NormalError ) {
slotSyncError( tr("%1: %2").arg(item._file, item._errorString) );
2014-02-18 21:42:49 +04:00
logger->postOptionalGuiLog(item._file, item._errorString);
2013-08-15 10:15:30 +04:00
} else {
// add new directories or remove gone away dirs to the watcher
if (item._isDirectory && item._instruction == CSYNC_INSTRUCTION_NEW ) {
FolderMan::instance()->addMonitorPath( alias(), path()+item._file );
}
if (item._isDirectory && item._instruction == CSYNC_INSTRUCTION_REMOVE ) {
FolderMan::instance()->removeMonitorPath( alias(), path()+item._file );
}
if (item._direction == SyncFileItem::Down) {
2013-08-15 10:15:30 +04:00
switch (item._instruction) {
case CSYNC_INSTRUCTION_NEW:
newItems++;
if (firstItemNew.isEmpty())
firstItemNew = item;
break;
case CSYNC_INSTRUCTION_REMOVE:
removedItems++;
if (firstItemDeleted.isEmpty())
firstItemDeleted = item;
break;
case CSYNC_INSTRUCTION_CONFLICT:
case CSYNC_INSTRUCTION_SYNC:
2013-08-15 10:15:30 +04:00
updatedItems++;
if (firstItemUpdated.isEmpty())
firstItemUpdated = item;
break;
case CSYNC_INSTRUCTION_ERROR:
qDebug() << "Got Instruction ERROR. " << _syncResult.errorString();
break;
case CSYNC_INSTRUCTION_RENAME:
if (firstItemRenamed.isEmpty()) {
firstItemRenamed = item;
}
renamedItems++;
break;
2013-08-15 10:15:30 +04:00
default:
// nothing.
break;
}
} else if( item._direction == SyncFileItem::None ) { // ignored files counting.
2013-08-15 10:15:30 +04:00
if( item._instruction == CSYNC_INSTRUCTION_IGNORE ) {
ignoredItems++;
}
}
}
}
2014-03-26 21:10:59 +04:00
syncFileLog.close();
2014-03-26 21:10:59 +04:00
qDebug() << "Processing result list and logging took " << timer.elapsed() << " Milliseconds.";
_syncResult.setWarnCount(ignoredItems);
createGuiLog( firstItemNew._file, FILE_STATUS_NEW, newItems );
createGuiLog( firstItemDeleted._file, FILE_STATUS_REMOVE, removedItems );
createGuiLog( firstItemUpdated._file, FILE_STATUS_UPDATED, updatedItems );
if( !firstItemRenamed.isEmpty() ) {
SyncFileStatus status = FILE_STATUS_RENAME;
// if the path changes it's rather a move
QDir renTarget = QFileInfo(firstItemRenamed._renameTarget).dir();
QDir renSource = QFileInfo(firstItemRenamed._file).dir();
if(renTarget != renSource) {
status = FILE_STATUS_MOVE;
}
createGuiLog( firstItemRenamed._file, status, renamedItems, firstItemRenamed._renameTarget );
}
qDebug() << "OO folder slotSyncFinished: result: " << int(_syncResult.status());
}
void Folder::createGuiLog( const QString& filename, SyncFileStatus status, int count,
const QString& renameTarget )
{
if(count > 0) {
Logger *logger = Logger::instance();
QString file = QDir::toNativeSeparators(filename);
QString text;
// not all possible values of status are evaluated here because the others
// are not used in the calling function. Please check there.
switch (status) {
case FILE_STATUS_REMOVE:
if( count > 1 ) {
text = tr("%1 and %2 other files have been removed.", "%1 names a file.").arg(file).arg(count-1);
} else {
text = tr("%1 has been removed.", "%1 names a file.").arg(file);
}
break;
case FILE_STATUS_NEW:
if( count > 1 ) {
text = tr("%1 and %2 other files have been downloaded.", "%1 names a file.").arg(file).arg(count-1);
} else {
text = tr("%1 has been downloaded.", "%1 names a file.").arg(file);
}
break;
case FILE_STATUS_UPDATED:
if( count > 1 ) {
text = tr("%1 and %2 other files have been updated.").arg(file).arg(count-1);
} else {
text = tr("%1 has been updated.", "%1 names a file.").arg(file);
}
break;
case FILE_STATUS_RENAME:
if( count > 1 ) {
text = tr("%1 has been renamed to %2 and %3 other files have been renamed.").arg(file).arg(renameTarget).arg(count-1);
} else {
text = tr("%1 has been renamed to %2.", "%1 and %2 name files.").arg(file).arg(renameTarget);
}
break;
case FILE_STATUS_MOVE:
if( count > 1 ) {
text = tr("%1 has been moved to %2 and %3 other files have been moved.").arg(file).arg(renameTarget).arg(count-1);
} else {
text = tr("%1 has been moved to %2.").arg(file).arg(renameTarget);
}
break;
default:
break;
}
if( !text.isEmpty() ) {
logger->postOptionalGuiLog( tr("Sync Activity"), text );
}
}
}
2011-02-17 02:21:45 +03:00
2013-12-03 17:47:32 +04:00
int Folder::blackListEntryCount()
{
return _journal.blackListEntryCount();
}
int Folder::slotWipeBlacklist()
{
return _journal.wipeBlacklist();
}
void Folder::setConfigFile( const QString& file )
{
_configFile = file;
}
QString Folder::configFile()
{
return _configFile;
}
2013-07-22 22:27:42 +04:00
void Folder::slotThreadTreeWalkResult(const SyncFileItemVector& items)
2011-10-18 12:22:24 +04:00
{
2013-07-22 22:27:42 +04:00
_syncResult.setSyncFileItemVector(items);
2011-10-18 12:22:24 +04:00
}
void Folder::slotTerminateSync()
2011-10-18 12:22:24 +04:00
{
2013-07-22 22:27:42 +04:00
qDebug() << "folder " << alias() << " Terminating!";
if( _engine ) {
_engine->abort();
// Do not display an error message, user knows his own actions.
// _errors.append( tr("The CSync thread terminated.") );
// _csyncError = true;
setSyncEnabled(false);
setSyncState(SyncResult::SyncAbortRequested);
return;
2013-07-22 22:27:42 +04:00
}
2011-10-18 12:22:24 +04:00
}
// This removes the csync File database
// This is needed to provide a clean startup again in case another
2013-07-22 22:27:42 +04:00
// local folder is synced to the same ownCloud.
void Folder::wipe()
{
2013-07-22 22:27:42 +04:00
QString stateDbFile = path()+QLatin1String(".csync_journal.db");
_journal.close(); // close the sync journal
2013-07-22 22:27:42 +04:00
QFile file(stateDbFile);
if( file.exists() ) {
if( !file.remove()) {
qDebug() << "WRN: Failed to remove existing csync StateDB " << stateDbFile;
} else {
qDebug() << "wipe: Removed csync StateDB " << stateDbFile;
}
} else {
qDebug() << "WRN: statedb is empty, can not remove.";
}
// Check if the tmp database file also exists
QString ctmpName = path() + QLatin1String(".csync_journal.db.ctmp");
QFile ctmpFile( ctmpName );
if( ctmpFile.exists() ) {
ctmpFile.remove();
}
}
void Folder::setIgnoredFiles()
{
MirallConfigFile cfgFile;
csync_clear_exclude_list( _csync_ctx );
QString excludeList = cfgFile.excludeFile( MirallConfigFile::SystemScope );
if( !excludeList.isEmpty() ) {
qDebug() << "==== added system ignore list to csync:" << excludeList.toUtf8();
csync_add_exclude_list( _csync_ctx, excludeList.toUtf8() );
}
excludeList = cfgFile.excludeFile( MirallConfigFile::UserScope );
if( !excludeList.isEmpty() ) {
qDebug() << "==== added user defined ignore list to csync:" << excludeList.toUtf8();
csync_add_exclude_list( _csync_ctx, excludeList.toUtf8() );
}
}
void Folder::setProxyDirty(bool value)
{
_proxyDirty = value;
}
bool Folder::proxyDirty()
{
return _proxyDirty;
}
2013-07-22 22:27:42 +04:00
void Folder::startSync(const QStringList &pathList)
{
Q_UNUSED(pathList)
if (!_csync_ctx) {
// no _csync_ctx yet, initialize it.
init();
if (!_csync_ctx) {
qDebug() << Q_FUNC_INFO << "init failed.";
// the error should already be set
QMetaObject::invokeMethod(this, "slotCSyncFinished", Qt::QueuedConnection);
return;
}
_clientProxy.setCSyncProxy(AccountManager::instance()->account()->url(), _csync_ctx);
} else if (proxyDirty()) {
_clientProxy.setCSyncProxy(AccountManager::instance()->account()->url(), _csync_ctx);
setProxyDirty(false);
2013-07-22 22:27:42 +04:00
}
if (isBusy()) {
2013-07-22 22:27:42 +04:00
qCritical() << "* ERROR csync is still running and new sync requested.";
return;
}
_errors.clear();
_csyncError = false;
_csyncUnavail = false;
_syncResult.clearErrors();
_syncResult.setStatus( SyncResult::SyncPrepare );
emit syncStateChange();
qDebug() << "*** Start syncing";
setIgnoredFiles();
_engine.reset(new SyncEngine( _csync_ctx, path(), remoteUrl().path(), _remotePath, &_journal));
2013-07-22 22:27:42 +04:00
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
connect( _engine.data(), SIGNAL(treeWalkResult(const SyncFileItemVector&)),
2013-07-22 22:27:42 +04:00
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection);
connect(_engine.data(), SIGNAL(started()), SLOT(slotSyncStarted()), Qt::QueuedConnection);
connect(_engine.data(), SIGNAL(finished()), SLOT(slotSyncFinished()), Qt::QueuedConnection);
connect(_engine.data(), SIGNAL(csyncError(QString)), SLOT(slotSyncError(QString)), Qt::QueuedConnection);
connect(_engine.data(), SIGNAL(csyncUnavailable()), SLOT(slotCsyncUnavailable()), Qt::QueuedConnection);
2013-07-22 22:27:42 +04:00
//direct connection so the message box is blocking the sync.
connect(_engine.data(), SIGNAL(aboutToRemoveAllFiles(SyncFileItem::Direction,bool*)),
SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*)));
connect(_engine.data(), SIGNAL(transmissionProgress(Progress::Info)), this, SLOT(slotTransmissionProgress(Progress::Info)));
QMetaObject::invokeMethod(_engine.data(), "startSync", Qt::QueuedConnection);
// disable events until syncing is done
// _watcher->setEventsEnabled(false);
_pollTimer.stop();
2013-07-22 22:27:42 +04:00
emit syncStarted();
}
void Folder::setDirtyNetworkLimits()
{
if (_engine) {
_engine->setNetworkLimits();
}
}
void Folder::slotSyncError(const QString& err)
2013-07-22 22:27:42 +04:00
{
_errors.append( err );
_csyncError = true;
}
void Folder::slotSyncStarted()
2013-07-22 22:27:42 +04:00
{
qDebug() << " * csync thread started";
_syncResult.setStatus(SyncResult::SyncRunning);
emit syncStateChange();
}
void Folder::slotCsyncUnavailable()
{
_csyncUnavail = true;
}
void Folder::slotSyncFinished()
2013-07-22 22:27:42 +04:00
{
qDebug() << "-> CSync Finished slot with error " << _csyncError << "warn count" << _syncResult.warnCount();
2014-03-26 21:10:59 +04:00
bubbleUpSyncResult();
_engine.reset(0);
// _watcher->setEventsEnabledDelayed(2000);
_pollTimer.start();
_timeSinceLastSync.restart();
2013-07-22 22:27:42 +04:00
if (_csyncError) {
_syncResult.setStatus(SyncResult::Error);
qDebug() << " ** error Strings: " << _errors;
_syncResult.setErrorStrings( _errors );
qDebug() << " * owncloud csync thread finished with error";
} else if (_csyncUnavail) {
_syncResult.setStatus(SyncResult::Unavailable);
} else if( _syncResult.warnCount() > 0 ) {
// there have been warnings on the way.
_syncResult.setStatus(SyncResult::Problem);
2013-07-22 22:27:42 +04:00
} else {
_syncResult.setStatus(SyncResult::Success);
}
emit syncStateChange();
// The syncFinished result that is to be triggered here makes the folderman
// clearing the current running sync folder marker.
// Lets wait a bit to do that because, as long as this marker is not cleared,
// file system change notifications are ignored for that folder. And it takes
// some time under certain conditions to make the file system notifications
// all come in.
QTimer::singleShot(200, this, SLOT(slotEmitFinishedDelayed() ));
}
void Folder::slotEmitFinishedDelayed()
{
2013-07-22 22:27:42 +04:00
emit syncFinished( _syncResult );
}
// the progress comes without a folder and the valid path set. Add that here
// and hand the result over to the progress dispatcher.
void Folder::slotTransmissionProgress(const Progress::Info &pi)
2013-07-22 22:27:42 +04:00
{
if (!pi._lastCompletedItem.isEmpty()
&& Progress::isWarningKind(pi._lastCompletedItem._status)) {
// Count all error conditions.
_syncResult.setWarnCount(_syncResult.warnCount()+1);
}
// remember problems happening to set the correct Sync status in slot slotCSyncFinished.
if( pi._completedFileCount ) {
_syncResult.setWarnCount(0);
}
ProgressDispatcher::instance()->setProgressInfo(alias(), pi);
2013-07-22 22:27:42 +04:00
}
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel)
{
2014-04-06 21:34:56 +04:00
#ifndef TOKEN_AUTH_ONLY
2013-07-22 22:27:42 +04:00
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\".") :
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"
"Are you sure you want to perform this operation?");
QMessageBox msgBox(QMessageBox::Warning, tr("Remove All Files?"),
msg.arg(alias()));
msgBox.addButton(tr("Remove all files"), QMessageBox::DestructiveRole);
QPushButton* keepBtn = msgBox.addButton(tr("Keep files"), QMessageBox::ActionRole);
if (msgBox.exec() == -1) {
*cancel = true;
return;
}
*cancel = msgBox.clickedButton() == keepBtn;
if (*cancel) {
wipe();
// speed up next sync
_lastEtag = QString();
QTimer::singleShot(50, this, SLOT(slotPollTimerTimeout()));
2013-07-22 22:27:42 +04:00
}
2014-04-06 21:34:56 +04:00
#endif
2013-07-22 22:27:42 +04:00
}
SyncFileStatus Folder::fileStatus( const QString& fileName )
{
/*
STATUS_NONE,
+ STATUS_EVAL,
STATUS_REMOVE, (invalid for this case because it asks for local files)
STATUS_RENAME,
+ STATUS_NEW,
STATUS_CONFLICT,(probably also invalid as we know the conflict only with server involvement)
+ STATUS_IGNORE,
+ STATUS_SYNC,
+ STATUS_STAT_ERROR,
STATUS_ERROR,
STATUS_UPDATED
*/
// FIXME: Find a way for STATUS_ERROR
2013-10-03 18:12:50 +04:00
SyncFileStatus stat = FILE_STATUS_NONE;
QString file = path() + fileName;
QFileInfo fi(file);
if( !fi.exists() ) {
2013-10-03 18:12:50 +04:00
stat = FILE_STATUS_STAT_ERROR; // not really possible.
}
// file is ignored?
if( fi.isSymLink() ) {
2013-10-03 18:12:50 +04:00
stat = FILE_STATUS_IGNORE;
}
int type = CSYNC_FTW_TYPE_FILE;
if( fi.isDir() ) {
type = CSYNC_FTW_TYPE_DIR;
}
2013-10-03 18:12:50 +04:00
if( stat == FILE_STATUS_NONE ) {
CSYNC_EXCLUDE_TYPE excl = csync_excluded(_csync_ctx, file.toUtf8(), type);
if( excl != CSYNC_NOT_EXCLUDED ) {
stat = FILE_STATUS_IGNORE;
}
}
SyncJournalFileRecord rec = _journal.getFileRecord(fileName);
if( stat == FILE_STATUS_NONE && !rec.isValid() ) {
stat = FILE_STATUS_NEW;
}
// file was locally modified.
if( stat == FILE_STATUS_NONE && fi.lastModified() != rec._modtime ) {
stat = FILE_STATUS_EVAL;
}
2013-10-03 18:12:50 +04:00
if( stat == FILE_STATUS_NONE ) {
stat = FILE_STATUS_SYNC;
}
return stat;
}
2013-07-22 22:27:42 +04:00
2011-02-17 02:21:45 +03:00
} // namespace Mirall