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"
|
2012-07-20 19:13:23 +04:00
|
|
|
|
2011-02-17 02:21:45 +03:00
|
|
|
#include "mirall/folder.h"
|
|
|
|
#include "mirall/folderwatcher.h"
|
2012-03-28 14:23:34 +04:00
|
|
|
#include "mirall/mirallconfigfile.h"
|
2012-03-31 14:44:22 +04:00
|
|
|
#include "mirall/syncresult.h"
|
2013-07-22 22:27:42 +04:00
|
|
|
#include "mirall/logger.h"
|
|
|
|
#include "mirall/owncloudinfo.h"
|
2013-08-05 22:14:22 +04:00
|
|
|
#include "mirall/utility.h"
|
2013-07-30 13:19:22 +04:00
|
|
|
#include "creds/abstractcredentials.h"
|
2011-02-17 02:21:45 +03:00
|
|
|
|
2012-05-21 18:48:49 +04:00
|
|
|
#include <QDebug>
|
|
|
|
#include <QTimer>
|
|
|
|
#include <QUrl>
|
2012-06-25 17:31:13 +04:00
|
|
|
#include <QFileSystemWatcher>
|
|
|
|
#include <QDir>
|
2013-07-22 22:27:42 +04:00
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QPushButton>
|
2012-05-21 18:48:49 +04:00
|
|
|
|
2011-02-17 02:21:45 +03:00
|
|
|
namespace Mirall {
|
|
|
|
|
2013-07-30 16:37:46 +04:00
|
|
|
void csyncLogCatcher(CSYNC */*ctx*/,
|
|
|
|
int /*verbosity*/,
|
|
|
|
const char */*function*/,
|
2013-07-22 22:27:42 +04:00
|
|
|
const char *buffer,
|
2013-07-30 16:37:46 +04:00
|
|
|
void */*userdata*/)
|
2013-07-22 22:27:42 +04:00
|
|
|
{
|
|
|
|
Logger::instance()->csyncLog( QString::fromUtf8(buffer) );
|
|
|
|
}
|
|
|
|
|
2012-03-26 15:20:15 +04:00
|
|
|
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)
|
|
|
|
, _secondPath(secondPath)
|
|
|
|
, _alias(alias)
|
|
|
|
, _enabled(true)
|
|
|
|
, _thread(0)
|
|
|
|
, _csync(0)
|
|
|
|
, _csyncError(false)
|
|
|
|
, _csyncUnavail(false)
|
|
|
|
, _csync_ctx(0)
|
2011-02-17 02:21:45 +03:00
|
|
|
{
|
2012-03-13 18:42:29 +04:00
|
|
|
qsrand(QTime::currentTime().msec());
|
2012-03-08 14:39:31 +04:00
|
|
|
|
2013-08-05 15:34:36 +04:00
|
|
|
_watcher = new FolderWatcher(path, this);
|
2012-03-28 14:23:34 +04:00
|
|
|
|
|
|
|
MirallConfigFile cfg;
|
2013-07-05 18:54:11 +04:00
|
|
|
_watcher->addIgnoreListFile( cfg.excludeFile(MirallConfigFile::SystemScope) );
|
|
|
|
_watcher->addIgnoreListFile( cfg.excludeFile(MirallConfigFile::UserScope) );
|
2012-03-28 14:23:34 +04:00
|
|
|
|
2011-03-23 01:03:43 +03:00
|
|
|
QObject::connect(_watcher, SIGNAL(folderChanged(const QStringList &)),
|
|
|
|
SLOT(slotChanged(const QStringList &)));
|
2011-03-28 01:29:45 +04:00
|
|
|
|
2012-04-20 16:31:06 +04:00
|
|
|
_syncResult.setStatus( SyncResult::NotYetStarted );
|
2012-02-20 19:45:27 +04:00
|
|
|
|
2013-07-22 22:27:42 +04:00
|
|
|
ServerActionNotifier *notifier = new ServerActionNotifier(this);
|
|
|
|
connect(notifier, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(optionalGuiLog(QString,QString)));
|
2013-08-05 16:35:01 +04:00
|
|
|
connect(this, SIGNAL(syncFinished(SyncResult)), this, SLOT(slotSyncFinished(SyncResult)));
|
2013-07-22 22:27:42 +04:00
|
|
|
connect(this, SIGNAL(syncFinished(SyncResult)), notifier, SLOT(slotSyncFinished(SyncResult)));
|
|
|
|
|
2012-10-30 15:42:17 +04:00
|
|
|
// check if the local path exists
|
|
|
|
checkLocalPath();
|
2013-08-05 19:01:08 +04:00
|
|
|
|
|
|
|
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();
|
|
|
|
|
2013-08-06 20:04:42 +04:00
|
|
|
_syncResult.setFolder(alias);
|
2011-02-17 02:21:45 +03:00
|
|
|
}
|
|
|
|
|
2013-07-22 22:27:42 +04:00
|
|
|
bool Folder::init()
|
|
|
|
{
|
2013-08-05 21:45:16 +04:00
|
|
|
QString url = Utility::toCSyncScheme(ownCloudInfo::instance()->webdavUrl() + secondPath());
|
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!";
|
|
|
|
slotCSyncError(tr("Unable to create csync-context"));
|
|
|
|
_csync_ctx = 0;
|
|
|
|
} else {
|
|
|
|
csync_set_log_callback( _csync_ctx, csyncLogCatcher );
|
|
|
|
csync_set_log_verbosity(_csync_ctx, 11);
|
|
|
|
|
|
|
|
MirallConfigFile cfgFile;
|
|
|
|
csync_set_config_dir( _csync_ctx, cfgFile.configPath().toUtf8() );
|
|
|
|
|
|
|
|
csync_enable_conflictcopys(_csync_ctx);
|
|
|
|
setIgnoredFiles();
|
2013-07-29 16:44:54 +04:00
|
|
|
cfgFile.getCredentials()->syncContextPreInit(_csync_ctx);
|
2013-07-22 22:27:42 +04:00
|
|
|
|
|
|
|
if( csync_init( _csync_ctx ) < 0 ) {
|
|
|
|
qDebug() << "Could not initialize csync!" << csync_get_error(_csync_ctx) << csync_get_error_string(_csync_ctx);
|
|
|
|
slotCSyncError(CSyncThread::csyncErrorToString(csync_get_error(_csync_ctx), csync_get_error_string(_csync_ctx)));
|
|
|
|
csync_destroy(_csync_ctx);
|
|
|
|
_csync_ctx = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return _csync_ctx;
|
|
|
|
}
|
2011-02-17 02:21:45 +03:00
|
|
|
Folder::~Folder()
|
|
|
|
{
|
2013-07-22 22:27:42 +04:00
|
|
|
if( _thread ) {
|
|
|
|
_thread->quit();
|
|
|
|
csync_request_abort(_csync_ctx);
|
|
|
|
_thread->wait();
|
|
|
|
}
|
|
|
|
delete _csync;
|
|
|
|
// Destroy csync here.
|
|
|
|
csync_destroy(_csync_ctx);
|
2011-02-17 02:21:45 +03:00
|
|
|
}
|
|
|
|
|
2012-10-30 15:42:17 +04:00
|
|
|
void Folder::checkLocalPath()
|
|
|
|
{
|
|
|
|
QFileInfo fi(_path);
|
|
|
|
|
|
|
|
if( fi.isDir() && fi.isReadable() ) {
|
|
|
|
qDebug() << "Checked local path ok";
|
|
|
|
} else {
|
|
|
|
if( !fi.exists() ) {
|
2012-10-30 17:37:15 +04:00
|
|
|
// try to create the local dir
|
|
|
|
QDir d(_path);
|
|
|
|
if( d.mkpath(_path) ) {
|
|
|
|
qDebug() << "Successfully created the local dir " << _path;
|
2012-10-30 15:42:17 +04:00
|
|
|
}
|
|
|
|
}
|
2012-10-30 17:37:15 +04:00
|
|
|
// 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 );
|
|
|
|
}
|
2012-10-30 15:42:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// if all is fine, connect a FileSystemWatcher
|
|
|
|
if( _syncResult.status() != SyncResult::SetupError ) {
|
|
|
|
_pathWatcher = new QFileSystemWatcher(this);
|
|
|
|
_pathWatcher->addPath( _path );
|
|
|
|
connect(_pathWatcher, SIGNAL(directoryChanged(QString)),
|
|
|
|
SLOT(slotLocalPathChanged(QString)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-06 11:52:02 +04:00
|
|
|
QString Folder::alias() const
|
|
|
|
{
|
|
|
|
return _alias;
|
|
|
|
}
|
|
|
|
|
2011-02-17 17:10:06 +03:00
|
|
|
QString Folder::path() const
|
|
|
|
{
|
2012-10-29 14:22:02 +04:00
|
|
|
QString p(_path);
|
|
|
|
if( ! p.endsWith(QLatin1Char('/')) ) {
|
|
|
|
p.append(QLatin1Char('/'));
|
|
|
|
}
|
|
|
|
return p;
|
2011-02-17 17:10:06 +03:00
|
|
|
}
|
|
|
|
|
2013-07-22 22:27:42 +04:00
|
|
|
bool Folder::isBusy() const
|
|
|
|
{
|
|
|
|
return ( _thread && _thread->isRunning() );
|
|
|
|
}
|
|
|
|
|
2012-03-26 15:20:15 +04:00
|
|
|
QString Folder::secondPath() const
|
|
|
|
{
|
|
|
|
return _secondPath;
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:16:44 +04:00
|
|
|
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;
|
2011-11-04 14:41:49 +04:00
|
|
|
_watcher->setEventsEnabled( doit );
|
2012-03-26 15:20:15 +04:00
|
|
|
|
2012-03-31 14:44:22 +04:00
|
|
|
qDebug() << "setSyncEnabled - ############################ " << doit;
|
2012-03-26 15:20:15 +04:00
|
|
|
if( doit ) {
|
|
|
|
// undefined until next sync
|
2012-03-31 14:44:22 +04:00
|
|
|
_syncResult.setStatus( SyncResult::NotYetStarted);
|
2012-04-17 15:16:48 +04:00
|
|
|
_syncResult.clearErrors();
|
2012-03-26 15:20:15 +04:00
|
|
|
evaluateSync( QStringList() );
|
|
|
|
} else {
|
2012-04-30 10:56:56 +04:00
|
|
|
// disable folder. Done through the _enabled-flag set above
|
2012-03-26 15:20:15 +04:00
|
|
|
}
|
2011-10-13 18:41:24 +04:00
|
|
|
}
|
|
|
|
|
2013-02-18 17:56:21 +04:00
|
|
|
void Folder::setSyncState(SyncResult::Status state)
|
|
|
|
{
|
|
|
|
_syncResult.setStatus(state);
|
|
|
|
}
|
|
|
|
|
2012-02-20 19:45:27 +04:00
|
|
|
SyncResult Folder::syncResult() const
|
2011-10-13 18:41:24 +04:00
|
|
|
{
|
2012-02-20 19:45:27 +04:00
|
|
|
return _syncResult;
|
2011-10-13 18:41:24 +04:00
|
|
|
}
|
|
|
|
|
2013-07-30 16:37:46 +04:00
|
|
|
void Folder::evaluateSync(const QStringList &/*pathList*/)
|
2011-04-06 17:57:18 +04:00
|
|
|
{
|
2011-10-13 18:41:24 +04:00
|
|
|
if( !_enabled ) {
|
|
|
|
qDebug() << "*" << alias() << "sync skipped, disabled!";
|
|
|
|
return;
|
|
|
|
}
|
2012-02-28 19:49:13 +04:00
|
|
|
|
2012-03-31 14:44:22 +04:00
|
|
|
_syncResult.setStatus( SyncResult::NotYetStarted );
|
2012-03-29 12:13:19 +04:00
|
|
|
emit scheduleToSync( alias() );
|
2012-03-31 14:44:22 +04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-04-05 14:16:24 +04:00
|
|
|
void Folder::slotPollTimerTimeout()
|
|
|
|
{
|
2011-04-06 12:40:15 +04:00
|
|
|
qDebug() << "* Polling" << alias() << "for changes. Ignoring all pending events until now";
|
2011-04-05 14:16:24 +04:00
|
|
|
_watcher->clearPendingEvents();
|
2013-08-05 21:53:58 +04:00
|
|
|
|
|
|
|
QObject::connect(new RequestEtagJob(secondPath(), this), SIGNAL(etagRetreived(QString)),
|
|
|
|
this, SLOT(etagRetreived(QString)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Folder::etagRetreived(const QString& etag)
|
|
|
|
{
|
|
|
|
qDebug() << "* Compare etag " << etag << " with previous etag " << _lastEtag;
|
|
|
|
if (_lastEtag != etag) {
|
|
|
|
_lastEtag = etag;
|
|
|
|
evaluateSync(QStringList());
|
|
|
|
}
|
2011-04-06 17:57:18 +04:00
|
|
|
}
|
|
|
|
|
2013-08-05 21:53:58 +04:00
|
|
|
|
2011-03-23 01:03:43 +03:00
|
|
|
void Folder::slotChanged(const QStringList &pathList)
|
2011-02-17 02:21:45 +03:00
|
|
|
{
|
2012-02-16 01:36:52 +04:00
|
|
|
qDebug() << "** Changed was notified on " << pathList;
|
2011-04-06 17:57:18 +04:00
|
|
|
evaluateSync(pathList);
|
2011-02-17 02:21:45 +03:00
|
|
|
}
|
|
|
|
|
2011-04-08 13:36:53 +04:00
|
|
|
void Folder::slotSyncFinished(const SyncResult &result)
|
2011-02-17 17:10:06 +03:00
|
|
|
{
|
2012-12-06 21:38:45 +04:00
|
|
|
_watcher->setEventsEnabledDelayed(2000);
|
2013-08-05 19:01:08 +04:00
|
|
|
_pollTimer.start();
|
2011-12-12 20:47:30 +04:00
|
|
|
|
2013-05-04 17:16:53 +04:00
|
|
|
qDebug() << "OO folder slotSyncFinished: result: " << int(result.status());
|
2012-02-29 18:25:16 +04:00
|
|
|
emit syncStateChange();
|
2011-02-17 17:10:06 +03:00
|
|
|
}
|
2011-02-17 02:21:45 +03:00
|
|
|
|
2012-06-25 17:31:13 +04:00
|
|
|
void Folder::slotLocalPathChanged( const QString& dir )
|
|
|
|
{
|
|
|
|
QDir notifiedDir(dir);
|
2013-07-22 22:27:42 +04:00
|
|
|
QDir localPath( path() );
|
2012-06-25 17:31:13 +04:00
|
|
|
|
2013-07-22 22:27:42 +04:00
|
|
|
if( notifiedDir.absolutePath() == localPath.absolutePath() ) {
|
2012-06-25 17:31:13 +04:00
|
|
|
if( !localPath.exists() ) {
|
2013-07-22 22:27:42 +04:00
|
|
|
qDebug() << "XXXXXXX The sync folder root was removed!!";
|
|
|
|
if( _thread && _thread->isRunning() ) {
|
|
|
|
qDebug() << "CSync currently running, set wipe flag!!";
|
|
|
|
} else {
|
|
|
|
qDebug() << "CSync not running, wipe it now!!";
|
|
|
|
wipe();
|
|
|
|
}
|
|
|
|
|
2012-06-25 17:31:13 +04:00
|
|
|
qDebug() << "ALARM: The local path was DELETED!";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-22 15:29:50 +04:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2013-07-22 22:27:42 +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!";
|
|
|
|
MirallConfigFile cfg;
|
|
|
|
QString configDir = cfg.configPath();
|
|
|
|
qDebug() << "csync's Config Dir: " << configDir;
|
|
|
|
|
|
|
|
if( _thread && _csync ) {
|
|
|
|
csync_request_abort(_csync_ctx);
|
|
|
|
_thread->quit();
|
|
|
|
_thread->wait();
|
|
|
|
_csync->deleteLater();
|
|
|
|
delete _thread;
|
|
|
|
_csync = 0;
|
|
|
|
_thread = 0;
|
|
|
|
csync_resume(_csync_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ! configDir.isEmpty() ) {
|
|
|
|
QFile file( configDir + QLatin1String("/lock"));
|
|
|
|
if( file.exists() ) {
|
|
|
|
qDebug() << "After termination, lock file exists and gets removed.";
|
|
|
|
file.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_errors.append( tr("The CSync thread terminated.") );
|
|
|
|
_csyncError = true;
|
|
|
|
qDebug() << "-> CSync Terminated!";
|
|
|
|
slotCSyncFinished();
|
2011-10-18 12:22:24 +04:00
|
|
|
}
|
|
|
|
|
2013-07-22 22:27:42 +04:00
|
|
|
// This removes the csync File database if the sync folder definition is removed
|
|
|
|
// permanentely. This is needed to provide a clean startup again in case another
|
|
|
|
// local folder is synced to the same ownCloud.
|
|
|
|
// See http://bugs.owncloud.org/thebuggenie/owncloud/issues/oc-788
|
2012-06-11 12:10:07 +04:00
|
|
|
void Folder::wipe()
|
|
|
|
{
|
2013-07-22 22:27:42 +04:00
|
|
|
QString stateDbFile = path()+QLatin1String(".csync_journal.db");
|
|
|
|
|
|
|
|
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::setProxy()
|
|
|
|
{
|
|
|
|
if( _csync_ctx ) {
|
|
|
|
/* Store proxy */
|
|
|
|
QUrl proxyUrl(ownCloudInfo::instance()->webdavUrl());
|
|
|
|
QList<QNetworkProxy> proxies = QNetworkProxyFactory::proxyForQuery(proxyUrl);
|
|
|
|
// We set at least one in Application
|
|
|
|
Q_ASSERT(proxies.count() > 0);
|
|
|
|
QNetworkProxy proxy = proxies.first();
|
|
|
|
if (proxy.type() == QNetworkProxy::NoProxy) {
|
|
|
|
qDebug() << "Passing NO proxy to csync for" << proxyUrl;
|
|
|
|
} else {
|
|
|
|
qDebug() << "Passing" << proxy.hostName() << "of proxy type " << proxy.type()
|
|
|
|
<< " to csync for" << proxyUrl;
|
|
|
|
}
|
|
|
|
int proxyPort = proxy.port();
|
|
|
|
|
|
|
|
csync_set_module_property(_csync_ctx, "proxy_type", (char*) proxyTypeToCStr(proxy.type()) );
|
|
|
|
csync_set_module_property(_csync_ctx, "proxy_host", proxy.hostName().toUtf8().data() );
|
|
|
|
csync_set_module_property(_csync_ctx, "proxy_port", &proxyPort );
|
|
|
|
csync_set_module_property(_csync_ctx, "proxy_user", proxy.user().toUtf8().data() );
|
|
|
|
csync_set_module_property(_csync_ctx, "proxy_pwd" , proxy.password().toUtf8().data() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const char* Folder::proxyTypeToCStr(QNetworkProxy::ProxyType type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case QNetworkProxy::NoProxy:
|
|
|
|
return "NoProxy";
|
|
|
|
case QNetworkProxy::DefaultProxy:
|
|
|
|
return "DefaultProxy";
|
|
|
|
case QNetworkProxy::Socks5Proxy:
|
|
|
|
return "Socks5Proxy";
|
|
|
|
case QNetworkProxy::HttpProxy:
|
|
|
|
return "HttpProxy";
|
|
|
|
case QNetworkProxy::HttpCachingProxy:
|
|
|
|
return "HttpCachingProxy";
|
|
|
|
case QNetworkProxy::FtpCachingProxy:
|
|
|
|
return "FtpCachingProxy";
|
|
|
|
default:
|
|
|
|
return "NoProxy";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_thread && _thread->isRunning()) {
|
|
|
|
qCritical() << "* ERROR csync is still running and new sync requested.";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (_thread)
|
|
|
|
_thread->quit();
|
|
|
|
delete _csync;
|
|
|
|
delete _thread;
|
|
|
|
_errors.clear();
|
|
|
|
_csyncError = false;
|
|
|
|
_csyncUnavail = false;
|
|
|
|
|
|
|
|
_syncResult.clearErrors();
|
|
|
|
_syncResult.setStatus( SyncResult::SyncPrepare );
|
|
|
|
emit syncStateChange();
|
|
|
|
|
|
|
|
|
|
|
|
qDebug() << "*** Start syncing";
|
|
|
|
_thread = new QThread(this);
|
|
|
|
_thread->setPriority(QThread::LowPriority);
|
|
|
|
setIgnoredFiles();
|
|
|
|
_csync = new CSyncThread( _csync_ctx );
|
|
|
|
_csync->moveToThread(_thread);
|
2012-06-11 12:10:07 +04:00
|
|
|
|
2013-07-22 22:27:42 +04:00
|
|
|
|
|
|
|
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
|
|
|
|
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
|
|
|
|
|
|
|
|
connect( _csync, SIGNAL(treeWalkResult(const SyncFileItemVector&)),
|
|
|
|
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection);
|
|
|
|
|
|
|
|
connect(_csync, SIGNAL(started()), SLOT(slotCSyncStarted()), Qt::QueuedConnection);
|
|
|
|
connect(_csync, SIGNAL(finished()), SLOT(slotCSyncFinished()), Qt::QueuedConnection);
|
|
|
|
connect(_csync, SIGNAL(csyncError(QString)), SLOT(slotCSyncError(QString)), Qt::QueuedConnection);
|
|
|
|
connect(_csync, SIGNAL(csyncUnavailable()), SLOT(slotCsyncUnavailable()), Qt::QueuedConnection);
|
|
|
|
|
|
|
|
//blocking connection so the message box happens in this thread, but block the csync thread.
|
|
|
|
connect(_csync, SIGNAL(aboutToRemoveAllFiles(SyncFileItem::Direction,bool*)),
|
|
|
|
SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*)), Qt::BlockingQueuedConnection);
|
2013-07-26 15:44:38 +04:00
|
|
|
connect(_csync, SIGNAL(transmissionProgress(Progress::Info)), this, SLOT(slotTransmissionProgress(Progress::Info)));
|
|
|
|
|
2013-07-22 22:27:42 +04:00
|
|
|
_thread->start();
|
|
|
|
QMetaObject::invokeMethod(_csync, "startSync", Qt::QueuedConnection);
|
2013-08-05 16:35:01 +04:00
|
|
|
|
|
|
|
// disable events until syncing is done
|
|
|
|
_watcher->setEventsEnabled(false);
|
2013-08-05 19:01:08 +04:00
|
|
|
_pollTimer.stop();
|
2013-07-22 22:27:42 +04:00
|
|
|
emit syncStarted();
|
2012-06-11 12:10:07 +04:00
|
|
|
}
|
|
|
|
|
2013-07-22 22:27:42 +04:00
|
|
|
void Folder::slotCSyncError(const QString& err)
|
|
|
|
{
|
|
|
|
_errors.append( err );
|
|
|
|
_csyncError = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Folder::slotCSyncStarted()
|
|
|
|
{
|
|
|
|
qDebug() << " * csync thread started";
|
|
|
|
_syncResult.setStatus(SyncResult::SyncRunning);
|
|
|
|
emit syncStateChange();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Folder::slotCsyncUnavailable()
|
|
|
|
{
|
|
|
|
_csyncUnavail = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Folder::slotCSyncFinished()
|
|
|
|
{
|
|
|
|
qDebug() << "-> CSync Finished slot with error " << _csyncError;
|
|
|
|
|
|
|
|
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);
|
2013-08-02 16:22:01 +04:00
|
|
|
} 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( _thread && _thread->isRunning() ) {
|
|
|
|
_thread->quit();
|
|
|
|
}
|
|
|
|
ownCloudInfo::instance()->getQuotaRequest("/");
|
|
|
|
emit syncFinished( _syncResult );
|
|
|
|
}
|
|
|
|
|
2013-07-31 00:22:04 +04:00
|
|
|
void Folder::slotTransmissionProgress(const Progress::Info& progress)
|
2013-07-22 22:27:42 +04:00
|
|
|
{
|
2013-07-31 00:22:43 +04:00
|
|
|
Progress::Info newInfo = progress;
|
|
|
|
newInfo.folder = alias();
|
|
|
|
|
|
|
|
if(newInfo.current_file.startsWith(QLatin1String("ownclouds://")) ||
|
|
|
|
newInfo.current_file.startsWith(QLatin1String("owncloud://")) ) {
|
|
|
|
// rip off the whole ownCloud URL.
|
2013-08-05 21:45:16 +04:00
|
|
|
QString remotePathUrl = ownCloudInfo::instance()->webdavUrl() + secondPath();
|
|
|
|
newInfo.current_file.remove(Utility::toCSyncScheme(remotePathUrl));
|
2013-07-31 00:22:43 +04:00
|
|
|
}
|
2013-08-02 14:16:21 +04:00
|
|
|
QString localPath = path();
|
|
|
|
if( newInfo.current_file.startsWith(localPath) ) {
|
|
|
|
// remove the local dir.
|
|
|
|
newInfo.current_file = newInfo.current_file.right( newInfo.current_file.length() - localPath.length());
|
|
|
|
}
|
2013-07-31 00:22:43 +04:00
|
|
|
|
2013-08-02 16:22:01 +04:00
|
|
|
// remember problems happening to set the correct Sync status in slot slotCSyncFinished.
|
|
|
|
if( newInfo.kind == Progress::StartSync ) {
|
|
|
|
_syncResult.setWarnCount(0);
|
|
|
|
}
|
|
|
|
if( newInfo.kind == Progress::Error ) {
|
|
|
|
_syncResult.setWarnCount( _syncResult.warnCount()+1 );
|
|
|
|
}
|
|
|
|
|
2013-07-31 00:22:43 +04:00
|
|
|
ProgressDispatcher::instance()->setProgressInfo(alias(), newInfo);
|
2013-07-22 22:27:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
ServerActionNotifier::ServerActionNotifier(QObject *parent)
|
|
|
|
: QObject(parent)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void ServerActionNotifier::slotSyncFinished(const SyncResult &result)
|
|
|
|
{
|
|
|
|
SyncFileItemVector items = result.syncFileItemVector();
|
|
|
|
if (items.count() == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int newItems = 0;
|
|
|
|
int removedItems = 0;
|
|
|
|
int updatedItems = 0;
|
|
|
|
SyncFileItem firstItemNew;
|
|
|
|
SyncFileItem firstItemDeleted;
|
|
|
|
SyncFileItem firstItemUpdated;
|
|
|
|
foreach (const SyncFileItem &item, items) {
|
|
|
|
if (item._dir == SyncFileItem::Down) {
|
|
|
|
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_UPDATED:
|
|
|
|
updatedItems++;
|
|
|
|
if (firstItemUpdated.isEmpty())
|
|
|
|
firstItemUpdated = item;
|
2013-07-31 00:22:43 +04:00
|
|
|
break;
|
|
|
|
case CSYNC_INSTRUCTION_ERROR:
|
|
|
|
qDebug() << "Got Instruction ERROR. " << result.errorString();
|
|
|
|
break;
|
2013-07-22 22:27:42 +04:00
|
|
|
default:
|
|
|
|
// nothing.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newItems > 0) {
|
|
|
|
QString file = QDir::toNativeSeparators(firstItemNew._file);
|
|
|
|
if (newItems == 1)
|
|
|
|
emit guiLog(tr("New file available"), tr("'%1' has been synced to this machine.").arg(file));
|
|
|
|
else
|
|
|
|
emit guiLog(tr("New files available"), tr("'%1' and %n other file(s) have been synced to this machine.",
|
|
|
|
"", newItems-1).arg(file));
|
|
|
|
}
|
|
|
|
if (removedItems > 0) {
|
|
|
|
QString file = QDir::toNativeSeparators(firstItemDeleted._file);
|
|
|
|
if (removedItems == 1)
|
|
|
|
emit guiLog(tr("File removed"), tr("'%1' has been removed.").arg(file));
|
|
|
|
else
|
|
|
|
emit guiLog(tr("Files removed"), tr("'%1' and %n other file(s) have been removed.",
|
|
|
|
"", removedItems-1).arg(file));
|
|
|
|
}
|
|
|
|
if (updatedItems > 0) {
|
|
|
|
QString file = QDir::toNativeSeparators(firstItemUpdated._file);
|
|
|
|
if (updatedItems == 1)
|
|
|
|
emit guiLog(tr("File updated"), tr("'%1' has been updated.").arg(file));
|
|
|
|
else
|
|
|
|
emit guiLog(tr("Files updated"), tr("'%1' and %n other file(s) have been updated.",
|
|
|
|
"", updatedItems-1).arg(file));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel)
|
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-17 02:21:45 +03:00
|
|
|
} // namespace Mirall
|
|
|
|
|