mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-27 17:37:36 +03:00
parent
38db0eddab
commit
56e5627b6b
11 changed files with 642 additions and 923 deletions
|
@ -67,7 +67,6 @@ set(libsync_SRCS
|
|||
mirall/networklocation.cpp
|
||||
mirall/mirallconfigfile.cpp
|
||||
mirall/credentialstore.cpp
|
||||
mirall/owncloudfolder.cpp
|
||||
mirall/csyncthread.cpp
|
||||
mirall/fileutils.cpp
|
||||
mirall/theme.cpp
|
||||
|
@ -82,7 +81,6 @@ set(libsync_HEADERS
|
|||
mirall/folderman.h
|
||||
mirall/folder.h
|
||||
mirall/folderwatcher.h
|
||||
mirall/owncloudfolder.h
|
||||
mirall/csyncthread.h
|
||||
mirall/theme.h
|
||||
mirall/owncloudtheme.h
|
||||
|
|
|
@ -128,11 +128,10 @@ void AccountSettings::slotFolderWizardAccepted()
|
|||
QString alias = folderWizard->field(QLatin1String("alias")).toString();
|
||||
QString sourceFolder = folderWizard->field(QLatin1String("sourceFolder")).toString();
|
||||
QString targetPath = folderWizard->field(QLatin1String("OCFolderLineEdit")).toString();
|
||||
QString backend = QLatin1String("owncloud");
|
||||
|
||||
if (!FolderMan::ensureJournalGone( sourceFolder ))
|
||||
return;
|
||||
folderMan->addFolderDefinition( backend, alias, sourceFolder, targetPath, false );
|
||||
folderMan->addFolderDefinition(alias, sourceFolder, targetPath );
|
||||
Folder *f = folderMan->setupFolderFromConfigFile( alias );
|
||||
slotAddFolder( f );
|
||||
folderMan->setSyncEnabled(true);
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "mirall/folderwatcher.h"
|
||||
#include "mirall/folderwizard.h"
|
||||
#include "mirall/networklocation.h"
|
||||
#include "mirall/owncloudfolder.h"
|
||||
#include "mirall/folder.h"
|
||||
#include "mirall/owncloudsetupwizard.h"
|
||||
#include "mirall/owncloudinfo.h"
|
||||
#include "mirall/sslerrordialog.h"
|
||||
|
@ -332,8 +332,6 @@ void Application::setupContextMenu()
|
|||
if( folder ) {
|
||||
// if there is singleFolder mode, a generic open action is displayed.
|
||||
QAction *action = new QAction( tr("Open local folder '%1'").arg(_theme->appNameGUI()), this);
|
||||
action->setIcon( _theme->trayFolderIcon( folder->backend()) );
|
||||
|
||||
connect( action, SIGNAL(triggered()),_folderOpenActionMapper,SLOT(map()));
|
||||
_folderOpenActionMapper->setMapping( action, folder->alias() );
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
/*
|
||||
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
|
||||
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
|
||||
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
||||
*
|
||||
* 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
|
||||
|
@ -17,26 +19,55 @@
|
|||
#include "mirall/folderwatcher.h"
|
||||
#include "mirall/mirallconfigfile.h"
|
||||
#include "mirall/syncresult.h"
|
||||
#include "mirall/logger.h"
|
||||
#include "mirall/owncloudinfo.h"
|
||||
#include "mirall/credentialstore.h"
|
||||
#include "mirall/utility.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <QUrl>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
void csyncLogCatcher(CSYNC *ctx,
|
||||
int verbosity,
|
||||
const char *function,
|
||||
const char *buffer,
|
||||
void *userdata)
|
||||
{
|
||||
Logger::instance()->csyncLog( QString::fromUtf8(buffer) );
|
||||
}
|
||||
|
||||
static QString replaceScheme(const QString &urlStr)
|
||||
{
|
||||
|
||||
QUrl url( urlStr );
|
||||
if( url.scheme() == QLatin1String("http") ) {
|
||||
url.setScheme( QLatin1String("owncloud") );
|
||||
} else {
|
||||
// connect SSL!
|
||||
url.setScheme( QLatin1String("ownclouds") );
|
||||
}
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
Folder::Folder(const QString &alias, const QString &path, const QString& secondPath, QObject *parent)
|
||||
: QObject(parent),
|
||||
_errorCount(0),
|
||||
_path(path),
|
||||
_secondPath(secondPath),
|
||||
_pollTimer(new QTimer(this)),
|
||||
_alias(alias),
|
||||
_onlyOnlineEnabled(false),
|
||||
_onlyThisLANEnabled(false),
|
||||
_online(false),
|
||||
_enabled(true)
|
||||
: QObject(parent)
|
||||
, _path(path)
|
||||
, _secondPath(secondPath)
|
||||
, _pollTimer(new QTimer(this))
|
||||
, _alias(alias)
|
||||
, _enabled(true)
|
||||
, _thread(0)
|
||||
, _csync(0)
|
||||
, _csyncError(false)
|
||||
, _csyncUnavail(false)
|
||||
, _csync_ctx(0)
|
||||
{
|
||||
qsrand(QTime::currentTime().msec());
|
||||
MirallConfigFile cfgFile;
|
||||
|
@ -62,21 +93,55 @@ Folder::Folder(const QString &alias, const QString &path, const QString& secondP
|
|||
QObject::connect(this, SIGNAL(syncFinished(const SyncResult &)),
|
||||
SLOT(slotSyncFinished(const SyncResult &)));
|
||||
|
||||
#if QT_VERSION >= 0x040700
|
||||
_online = _networkMgr.isOnline();
|
||||
QObject::connect(&_networkMgr, SIGNAL(onlineStateChanged(bool)), SLOT(slotOnlineChanged(bool)));
|
||||
#else
|
||||
_online = true;
|
||||
#endif
|
||||
|
||||
_syncResult.setStatus( SyncResult::NotYetStarted );
|
||||
|
||||
ServerActionNotifier *notifier = new ServerActionNotifier(this);
|
||||
connect(notifier, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(optionalGuiLog(QString,QString)));
|
||||
connect(this, SIGNAL(syncFinished(SyncResult)), notifier, SLOT(slotSyncFinished(SyncResult)));
|
||||
|
||||
// check if the local path exists
|
||||
checkLocalPath();
|
||||
}
|
||||
|
||||
bool Folder::init()
|
||||
{
|
||||
QString url = replaceScheme(ownCloudInfo::instance()->webdavUrl() + secondPath());
|
||||
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();
|
||||
csync_set_auth_callback( _csync_ctx, getauth );
|
||||
|
||||
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;
|
||||
}
|
||||
Folder::~Folder()
|
||||
{
|
||||
if( _thread ) {
|
||||
_thread->quit();
|
||||
csync_request_abort(_csync_ctx);
|
||||
_thread->wait();
|
||||
}
|
||||
delete _csync;
|
||||
// Destroy csync here.
|
||||
csync_destroy(_csync_ctx);
|
||||
}
|
||||
|
||||
void Folder::checkLocalPath()
|
||||
|
@ -129,6 +194,11 @@ QString Folder::path() const
|
|||
return p;
|
||||
}
|
||||
|
||||
bool Folder::isBusy() const
|
||||
{
|
||||
return ( _thread && _thread->isRunning() );
|
||||
}
|
||||
|
||||
QString Folder::secondPath() const
|
||||
{
|
||||
return _secondPath;
|
||||
|
@ -163,26 +233,6 @@ void Folder::setSyncEnabled( bool doit )
|
|||
}
|
||||
}
|
||||
|
||||
bool Folder::onlyOnlineEnabled() const
|
||||
{
|
||||
return _onlyOnlineEnabled;
|
||||
}
|
||||
|
||||
void Folder::setOnlyOnlineEnabled(bool enabled)
|
||||
{
|
||||
_onlyOnlineEnabled = enabled;
|
||||
}
|
||||
|
||||
bool Folder::onlyThisLANEnabled() const
|
||||
{
|
||||
return _onlyThisLANEnabled;
|
||||
}
|
||||
|
||||
void Folder::setOnlyThisLANEnabled(bool enabled)
|
||||
{
|
||||
_onlyThisLANEnabled = enabled;
|
||||
}
|
||||
|
||||
int Folder::pollInterval() const
|
||||
{
|
||||
return _pollTimer->interval();
|
||||
|
@ -198,30 +248,6 @@ void Folder::setPollInterval(int milliseconds)
|
|||
_pollTimer->setInterval( milliseconds );
|
||||
}
|
||||
|
||||
int Folder::errorCount()
|
||||
{
|
||||
return _errorCount;
|
||||
}
|
||||
|
||||
void Folder::resetErrorCount()
|
||||
{
|
||||
_errorCount = 0;
|
||||
}
|
||||
|
||||
void Folder::incrementErrorCount()
|
||||
{
|
||||
// if the error count gets higher than three, the interval timer
|
||||
// of the watcher is doubled.
|
||||
_errorCount++;
|
||||
if( _errorCount > 1 ) {
|
||||
int interval = _watcher->eventInterval();
|
||||
int newInt = 2*interval;
|
||||
qDebug() << "Set new watcher interval to " << newInt;
|
||||
_watcher->setEventInterval( newInt );
|
||||
_errorCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
SyncResult Folder::syncResult() const
|
||||
{
|
||||
return _syncResult;
|
||||
|
@ -233,10 +259,6 @@ void Folder::evaluateSync(const QStringList &pathList)
|
|||
qDebug() << "*" << alias() << "sync skipped, disabled!";
|
||||
return;
|
||||
}
|
||||
if (!_online && onlyOnlineEnabled()) {
|
||||
qDebug() << "*" << alias() << "sync skipped, not online";
|
||||
return;
|
||||
}
|
||||
|
||||
// stop the poll timer here. Its started again in the slot of
|
||||
// sync finished.
|
||||
|
@ -255,12 +277,6 @@ void Folder::slotPollTimerTimeout()
|
|||
evaluateSync(QStringList());
|
||||
}
|
||||
|
||||
void Folder::slotOnlineChanged(bool online)
|
||||
{
|
||||
qDebug() << "* " << alias() << "is" << (online ? "now online" : "no longer online");
|
||||
_online = online;
|
||||
}
|
||||
|
||||
void Folder::slotChanged(const QStringList &pathList)
|
||||
{
|
||||
qDebug() << "** Changed was notified on " << pathList;
|
||||
|
@ -293,10 +309,18 @@ void Folder::slotSyncFinished(const SyncResult &result)
|
|||
void Folder::slotLocalPathChanged( const QString& dir )
|
||||
{
|
||||
QDir notifiedDir(dir);
|
||||
QDir localPath(_path );
|
||||
QDir localPath( path() );
|
||||
|
||||
if( notifiedDir == localPath ) {
|
||||
if( notifiedDir.absolutePath() == localPath.absolutePath() ) {
|
||||
if( !localPath.exists() ) {
|
||||
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();
|
||||
}
|
||||
|
||||
qDebug() << "ALARM: The local path was DELETED!";
|
||||
}
|
||||
}
|
||||
|
@ -312,20 +336,419 @@ QString Folder::configFile()
|
|||
return _configFile;
|
||||
}
|
||||
|
||||
void Folder::setBackend( const QString& b )
|
||||
void Folder::slotThreadTreeWalkResult(const SyncFileItemVector& items)
|
||||
{
|
||||
_backend = b;
|
||||
_syncResult.setSyncFileItemVector(items);
|
||||
}
|
||||
|
||||
QString Folder::backend() const
|
||||
void Folder::slotTerminateSync()
|
||||
{
|
||||
return _backend;
|
||||
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();
|
||||
}
|
||||
|
||||
// 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
|
||||
void Folder::wipe()
|
||||
{
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
int Folder::getauth(const char *prompt,
|
||||
char *buf,
|
||||
size_t len,
|
||||
int echo,
|
||||
int verify,
|
||||
void *userdata
|
||||
)
|
||||
{
|
||||
int re = 0;
|
||||
QMutex mutex;
|
||||
|
||||
QString qPrompt = QString::fromLatin1( prompt ).trimmed();
|
||||
QString user = CredentialStore::instance()->user();
|
||||
QString pwd = CredentialStore::instance()->password();
|
||||
|
||||
if( qPrompt == QLatin1String("Enter your username:") ) {
|
||||
// qDebug() << "OOO Username requested!";
|
||||
QMutexLocker locker( &mutex );
|
||||
qstrncpy( buf, user.toUtf8().constData(), len );
|
||||
} else if( qPrompt == QLatin1String("Enter your password:") ) {
|
||||
QMutexLocker locker( &mutex );
|
||||
// qDebug() << "OOO Password requested!";
|
||||
qstrncpy( buf, pwd.toUtf8().constData(), len );
|
||||
} else {
|
||||
if( qPrompt.startsWith( QLatin1String("There are problems with the SSL certificate:"))) {
|
||||
// SSL is requested. If the program came here, the SSL check was done by mirall
|
||||
// It needs to be checked if the chain is still equal to the one which
|
||||
// was verified by the user.
|
||||
QRegExp regexp("fingerprint: ([\\w\\d:]+)");
|
||||
bool certOk = false;
|
||||
|
||||
int pos = 0;
|
||||
|
||||
// This is the set of certificates which QNAM accepted, so we should accept
|
||||
// them as well
|
||||
QList<QSslCertificate> certs = ownCloudInfo::instance()->certificateChain();
|
||||
|
||||
while (!certOk && (pos = regexp.indexIn(qPrompt, 1+pos)) != -1) {
|
||||
QString neon_fingerprint = regexp.cap(1);
|
||||
|
||||
foreach( const QSslCertificate& c, certs ) {
|
||||
QString verified_shasum = Utility::formatFingerprint(c.digest(QCryptographicHash::Sha1).toHex());
|
||||
qDebug() << "SSL Fingerprint from neon: " << neon_fingerprint << " compared to verified: " << verified_shasum;
|
||||
if( verified_shasum == neon_fingerprint ) {
|
||||
certOk = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// certOk = false; DEBUG setting, keep disabled!
|
||||
if( !certOk ) { // Problem!
|
||||
qstrcpy( buf, "no" );
|
||||
re = -1;
|
||||
} else {
|
||||
qstrcpy( buf, "yes" ); // Certificate is fine!
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Unknown prompt: <" << prompt << ">";
|
||||
re = -1;
|
||||
}
|
||||
}
|
||||
return re;
|
||||
}
|
||||
|
||||
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->setLastAuthCookies(ownCloudInfo::instance()->getLastAuthCookies());
|
||||
_csync->moveToThread(_thread);
|
||||
|
||||
|
||||
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);
|
||||
connect(_csync, SIGNAL(fileTransmissionProgress(Progress::Kind, QString,long,long)),
|
||||
SLOT(slotFileTransmissionProgress(Progress::Kind, QString,long,long)));
|
||||
connect(_csync, SIGNAL(overallTransmissionProgress(QString, int, int, long long, long long)),
|
||||
SLOT(slotOverallTransmissionProgress(QString, int, int, long long, long long)));
|
||||
|
||||
|
||||
_thread->start();
|
||||
QMetaObject::invokeMethod(_csync, "startSync", Qt::QueuedConnection);
|
||||
emit syncStarted();
|
||||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
_syncResult.setStatus(SyncResult::Success);
|
||||
}
|
||||
|
||||
if( _thread && _thread->isRunning() ) {
|
||||
_thread->quit();
|
||||
}
|
||||
ownCloudInfo::instance()->getQuotaRequest("/");
|
||||
emit syncFinished( _syncResult );
|
||||
}
|
||||
|
||||
|
||||
void Folder::slotFileTransmissionProgress(Progress::Kind kind, const QString& file ,long p1, long p2)
|
||||
{
|
||||
if( kind == Progress::StartDownload ) {
|
||||
_progressKind = Progress::Download;
|
||||
}
|
||||
if( kind == Progress::StartUpload ) {
|
||||
_progressKind = Progress::Upload;
|
||||
}
|
||||
|
||||
// qDebug() << "Upload Progress: " << file << p1 << p2;
|
||||
ProgressDispatcher::instance()->setFolderProgress( _progressKind, alias(), file, p1, p2 );
|
||||
|
||||
if( kind == Progress::EndDownload || kind == Progress::EndUpload ) {
|
||||
_progressKind = Progress::Inactive;
|
||||
}
|
||||
}
|
||||
|
||||
void Folder::slotOverallTransmissionProgress( const QString& fileName, int fileNo, int fileCnt,
|
||||
long long o1, long long o2)
|
||||
{
|
||||
ProgressDispatcher::instance()->setOverallProgress( alias(), fileName, fileNo, fileCnt, qlonglong(o1), qlonglong(o2));
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
break;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace Mirall
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
/*
|
||||
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
|
||||
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
|
||||
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
||||
*
|
||||
* 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
|
||||
|
@ -15,38 +17,74 @@
|
|||
#ifndef MIRALL_FOLDER_H
|
||||
#define MIRALL_FOLDER_H
|
||||
|
||||
#include "mirall/syncresult.h"
|
||||
#include "mirall/progressdispatcher.h"
|
||||
#include "mirall/csyncthread.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QDir>
|
||||
#include <QHash>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkProxy>
|
||||
#include <QNetworkProxyFactory>
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
|
||||
#if QT_VERSION >= 0x040700
|
||||
#include <QNetworkConfigurationManager>
|
||||
#endif
|
||||
#include <QDebug>
|
||||
|
||||
#include "mirall/syncresult.h"
|
||||
|
||||
class QAction;
|
||||
class QIcon;
|
||||
class QFileSystemWatcher;
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
class FolderWatcher;
|
||||
|
||||
typedef enum SyncFileStatus_s {
|
||||
STATUS_NONE,
|
||||
STATUS_EVAL,
|
||||
STATUS_REMOVE,
|
||||
STATUS_RENAME,
|
||||
STATUS_NEW,
|
||||
STATUS_CONFLICT,
|
||||
STATUS_IGNORE,
|
||||
STATUS_SYNC,
|
||||
STATUS_STAT_ERROR,
|
||||
STATUS_ERROR,
|
||||
STATUS_UPDATED
|
||||
} SyncFileStatus;
|
||||
|
||||
class ServerActionNotifier : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ServerActionNotifier(QObject *parent = 0);
|
||||
public slots:
|
||||
void slotSyncFinished(const SyncResult &result);
|
||||
signals:
|
||||
void guiLog(const QString&, const QString&);
|
||||
void sendResults();
|
||||
private:
|
||||
};
|
||||
|
||||
class Folder : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
protected:
|
||||
friend class FolderMan;
|
||||
Folder(const QString&, const QString&, const QString& , QObject*parent = 0L);
|
||||
virtual ~Folder();
|
||||
|
||||
public:
|
||||
~Folder();
|
||||
|
||||
typedef QHash<QString, Folder*> Map;
|
||||
typedef QHashIterator<QString, Folder*> MapIterator;
|
||||
|
||||
/**
|
||||
* Get status about a single file.
|
||||
*/
|
||||
SyncFileStatus fileStatus( const QString& );
|
||||
|
||||
/**
|
||||
* alias or nickname
|
||||
*/
|
||||
|
@ -56,12 +94,16 @@ public:
|
|||
* local folder path
|
||||
*/
|
||||
QString path() const;
|
||||
virtual QString secondPath() const;
|
||||
/**
|
||||
* remote folder path
|
||||
*/
|
||||
QString secondPath() const;
|
||||
|
||||
/**
|
||||
* local folder path with native separators
|
||||
*/
|
||||
QString nativePath() const;
|
||||
|
||||
/**
|
||||
* switch sync on or off
|
||||
* If the sync is switched off, the startSync method is not going to
|
||||
|
@ -71,69 +113,17 @@ public:
|
|||
|
||||
bool syncEnabled() const;
|
||||
|
||||
/**
|
||||
* Starts a sync operation
|
||||
*
|
||||
* If the list of changed files is known, it is passed.
|
||||
*
|
||||
* If the list of changed files is empty, the folder
|
||||
* implementation should figure it by itself of
|
||||
* perform a full scan of changes
|
||||
*/
|
||||
virtual void startSync(const QStringList &pathList) = 0;
|
||||
|
||||
/**
|
||||
* True if the folder is busy and can't initiate
|
||||
* a synchronization
|
||||
*/
|
||||
virtual bool isBusy() const = 0;
|
||||
|
||||
/**
|
||||
* only sync when online in the network
|
||||
*/
|
||||
bool onlyOnlineEnabled() const;
|
||||
|
||||
/**
|
||||
* @see onlyOnlineEnabled
|
||||
*/
|
||||
void setOnlyOnlineEnabled(bool enabled);
|
||||
|
||||
/**
|
||||
* only sync when online in the same LAN
|
||||
* as the one used during setup
|
||||
*/
|
||||
bool onlyThisLANEnabled() const;
|
||||
|
||||
/**
|
||||
* @see onlyThisLANEnabled
|
||||
*/
|
||||
void setOnlyThisLANEnabled(bool enabled);
|
||||
|
||||
|
||||
/**
|
||||
* error counter, stop syncing after the counter reaches a certain
|
||||
* number.
|
||||
*/
|
||||
int errorCount();
|
||||
|
||||
void resetErrorCount();
|
||||
|
||||
void incrementErrorCount();
|
||||
virtual bool isBusy() const;
|
||||
|
||||
/**
|
||||
* return the last sync result with error message and status
|
||||
*/
|
||||
SyncResult syncResult() const;
|
||||
|
||||
/**
|
||||
* set the backend description string.
|
||||
*/
|
||||
void setBackend( const QString& );
|
||||
/**
|
||||
* get the backend description string.
|
||||
*/
|
||||
QString backend() const;
|
||||
|
||||
/**
|
||||
* set the config file name.
|
||||
*/
|
||||
|
@ -145,7 +135,6 @@ public:
|
|||
*/
|
||||
virtual void wipe();
|
||||
|
||||
QIcon icon( int size ) const;
|
||||
QTimer *_pollTimer;
|
||||
|
||||
signals:
|
||||
|
@ -165,7 +154,7 @@ public slots:
|
|||
/**
|
||||
* terminate the current sync run
|
||||
*/
|
||||
virtual void slotTerminateSync() = 0;
|
||||
void slotTerminateSync();
|
||||
|
||||
/**
|
||||
* Sets minimum amounts of milliseconds that will separate
|
||||
|
@ -173,7 +162,42 @@ public slots:
|
|||
*/
|
||||
void setPollInterval( int );
|
||||
|
||||
void slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool*);
|
||||
|
||||
|
||||
/**
|
||||
* Starts a sync operation
|
||||
*
|
||||
* If the list of changed files is known, it is passed.
|
||||
*/
|
||||
void startSync(const QStringList &pathList = QStringList());
|
||||
|
||||
private slots:
|
||||
void slotCSyncStarted();
|
||||
void slotCSyncError(const QString& );
|
||||
void slotCsyncUnavailable();
|
||||
void slotCSyncFinished();
|
||||
|
||||
void slotFileTransmissionProgress(Progress::Kind, const QString&,long, long);
|
||||
void slotOverallTransmissionProgress( const QString&, int, int, long long, long long);
|
||||
|
||||
|
||||
void slotPollTimerTimeout();
|
||||
|
||||
|
||||
/** called when the watcher detect a list of changed paths */
|
||||
|
||||
void slotSyncStarted();
|
||||
|
||||
/**
|
||||
* Triggered by a file system watcher on the local sync dir
|
||||
*/
|
||||
void slotLocalPathChanged( const QString& );
|
||||
void slotThreadTreeWalkResult(const SyncFileItemVector& );
|
||||
|
||||
protected:
|
||||
bool init();
|
||||
|
||||
/**
|
||||
* The minimum amounts of seconds to wait before
|
||||
* doing a full sync to see if the remote changed
|
||||
|
@ -181,27 +205,16 @@ protected:
|
|||
int pollInterval() const;
|
||||
void setSyncState(SyncResult::Status state);
|
||||
|
||||
FolderWatcher *_watcher;
|
||||
int _errorCount;
|
||||
SyncResult _syncResult;
|
||||
|
||||
protected slots:
|
||||
|
||||
void slotOnlineChanged(bool online);
|
||||
|
||||
void slotPollTimerTimeout();
|
||||
|
||||
/* called when the watcher detect a list of changed
|
||||
paths */
|
||||
|
||||
void slotSyncStarted();
|
||||
|
||||
/**
|
||||
* Triggered by a file system watcher on the local sync dir
|
||||
*/
|
||||
virtual void slotLocalPathChanged( const QString& );
|
||||
|
||||
private:
|
||||
void setIgnoredFiles();
|
||||
void setProxy();
|
||||
static int getauth(const char *prompt,
|
||||
char *buf,
|
||||
size_t len,
|
||||
int echo,
|
||||
int verify,
|
||||
void *userdata
|
||||
);
|
||||
const char* proxyTypeToCStr(QNetworkProxy::ProxyType type);
|
||||
|
||||
/**
|
||||
* Starts a sync (calling startSync)
|
||||
|
@ -209,24 +222,25 @@ private:
|
|||
*/
|
||||
void evaluateSync(const QStringList &pathList);
|
||||
|
||||
virtual void checkLocalPath();
|
||||
void checkLocalPath();
|
||||
|
||||
QString _path;
|
||||
QString _secondPath;
|
||||
QString _alias;
|
||||
bool _onlyOnlineEnabled;
|
||||
bool _onlyThisLANEnabled;
|
||||
QString _configFile;
|
||||
|
||||
QFileSystemWatcher *_pathWatcher;
|
||||
|
||||
#if QT_VERSION >= 0x040700
|
||||
QNetworkConfigurationManager _networkMgr;
|
||||
#endif
|
||||
bool _online;
|
||||
bool _enabled;
|
||||
QString _backend;
|
||||
FolderWatcher *_watcher;
|
||||
SyncResult _syncResult;
|
||||
QThread *_thread;
|
||||
CSyncThread *_csync;
|
||||
QStringList _errors;
|
||||
bool _csyncError;
|
||||
bool _csyncUnavail;
|
||||
bool _wipeDb;
|
||||
Progress::Kind _progressKind;
|
||||
|
||||
CSYNC *_csync_ctx;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include "mirall/folderman.h"
|
||||
#include "mirall/mirallconfigfile.h"
|
||||
#include "mirall/owncloudfolder.h"
|
||||
#include "mirall/folder.h"
|
||||
#include "mirall/syncresult.h"
|
||||
#include "mirall/inotify.h"
|
||||
#include "mirall/theme.h"
|
||||
|
@ -252,31 +252,21 @@ Folder* FolderMan::setupFolderFromConfigFile(const QString &file) {
|
|||
// QString connection = settings.value( QLatin1String("connection") ).toString();
|
||||
QString alias = unescapeAlias( escapedAlias );
|
||||
|
||||
if (!backend.isEmpty()) {
|
||||
|
||||
if( backend == QLatin1String("owncloud") ) {
|
||||
if (backend.isEmpty() || backend != QLatin1String("owncloud")) {
|
||||
qWarning() << "obsolete configuration of type" << backend;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// cut off the leading slash, oCUrl always has a trailing.
|
||||
if( targetPath.startsWith(QLatin1Char('/')) ) {
|
||||
targetPath.remove(0,1);
|
||||
}
|
||||
|
||||
folder = new ownCloudFolder( alias, path, targetPath, this );
|
||||
folder = new Folder( alias, path, targetPath, this );
|
||||
folder->setConfigFile(file);
|
||||
} else {
|
||||
qWarning() << "unknown backend" << backend;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( folder ) {
|
||||
folder->setBackend( backend );
|
||||
// folder->setOnlyOnlineEnabled(settings.value("folder/onlyOnline", false).toBool());
|
||||
folder->setOnlyThisLANEnabled(settings.value(QLatin1String("folder/onlyThisLAN"), false).toBool());
|
||||
|
||||
qDebug() << "Adding folder to Folder Map " << folder;
|
||||
_folderMap[alias] = folder;
|
||||
|
||||
qDebug() << "Adding folder to Folder Map " << folder;
|
||||
/* Use a signal mapper to connect the signals to the alias */
|
||||
connect(folder, SIGNAL(scheduleToSync(const QString&)), SLOT(slotScheduleSync(const QString&)));
|
||||
connect(folder, SIGNAL(syncStateChange()), _folderChangeSignalMapper, SLOT(map()));
|
||||
|
@ -284,7 +274,6 @@ Folder* FolderMan::setupFolderFromConfigFile(const QString &file) {
|
|||
connect(folder, SIGNAL(syncFinished(SyncResult)), SLOT(slotFolderSyncFinished(SyncResult)));
|
||||
|
||||
_folderChangeSignalMapper->setMapping( folder, folder->alias() );
|
||||
}
|
||||
return folder;
|
||||
}
|
||||
|
||||
|
@ -426,15 +415,11 @@ void FolderMan::slotFolderSyncFinished( const SyncResult& )
|
|||
/**
|
||||
* Add a folder definition to the config
|
||||
* Params:
|
||||
* QString backend
|
||||
* QString alias
|
||||
* QString sourceFolder on local machine
|
||||
* QString targetPath on remote
|
||||
* bool onlyThisLAN, currently unused.
|
||||
*/
|
||||
void FolderMan::addFolderDefinition( const QString& backend, const QString& alias,
|
||||
const QString& sourceFolder, const QString& targetPath,
|
||||
bool onlyThisLAN )
|
||||
void FolderMan::addFolderDefinition(const QString& alias, const QString& sourceFolder, const QString& targetPath )
|
||||
{
|
||||
QString escapedAlias = escapeAlias(alias);
|
||||
// Create a settings file named after the alias
|
||||
|
@ -442,9 +427,9 @@ void FolderMan::addFolderDefinition( const QString& backend, const QString& alia
|
|||
|
||||
settings.setValue(QString::fromLatin1("%1/localPath").arg(escapedAlias), sourceFolder );
|
||||
settings.setValue(QString::fromLatin1("%1/targetPath").arg(escapedAlias), targetPath );
|
||||
settings.setValue(QString::fromLatin1("%1/backend").arg(escapedAlias), backend );
|
||||
// for compat reasons
|
||||
settings.setValue(QString::fromLatin1("%1/backend").arg(escapedAlias), "owncloud" );
|
||||
settings.setValue(QString::fromLatin1("%1/connection").arg(escapedAlias), Theme::instance()->appName());
|
||||
settings.setValue(QString::fromLatin1("%1/onlyThisLAN").arg(escapedAlias), onlyThisLAN );
|
||||
settings.sync();
|
||||
}
|
||||
|
||||
|
|
|
@ -44,13 +44,11 @@ public:
|
|||
/**
|
||||
* Add a folder definition to the config
|
||||
* Params:
|
||||
* QString backend
|
||||
* QString alias
|
||||
* QString sourceFolder on local machine
|
||||
* QString targetPath on remote
|
||||
* bool onlyThisLAN, currently unused.
|
||||
*/
|
||||
void addFolderDefinition( const QString&, const QString&, const QString&, const QString&, bool );
|
||||
void addFolderDefinition(const QString&, const QString&, const QString& );
|
||||
|
||||
/**
|
||||
* return the folder by alias or NULL if no folder with the alias exists.
|
||||
|
|
|
@ -37,8 +37,8 @@
|
|||
#elif defined(Q_OS_MAC)
|
||||
#include "mirall/folderwatcher_mac.h"
|
||||
#elif defined(USE_INOTIFY)
|
||||
#include "mirall/folderwatcher_inotify.h"
|
||||
#endif
|
||||
#include "mirall/folderwatcher_inotify.h"
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
|
|
|
@ -1,572 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
|
||||
* Copyright (C) by Klaas Freitag <freitag@owncloud.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "mirall/owncloudfolder.h"
|
||||
#include "mirall/mirallconfigfile.h"
|
||||
#include "mirall/owncloudinfo.h"
|
||||
#include "mirall/credentialstore.h"
|
||||
#include "mirall/logger.h"
|
||||
#include "mirall/utility.h"
|
||||
#include "mirall/progressdispatcher.h"
|
||||
|
||||
#include <csync.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QUrl>
|
||||
#include <QMutexLocker>
|
||||
#include <QThread>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
#include <QTimer>
|
||||
#include <QNetworkProxy>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkProxyFactory>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
void csyncLogCatcher(CSYNC *ctx,
|
||||
int verbosity,
|
||||
const char *function,
|
||||
const char *buffer,
|
||||
void *userdata)
|
||||
{
|
||||
Logger::instance()->csyncLog( QString::fromUtf8(buffer) );
|
||||
}
|
||||
|
||||
static QString replaceScheme(const QString &urlStr)
|
||||
{
|
||||
|
||||
QUrl url( urlStr );
|
||||
if( url.scheme() == QLatin1String("http") ) {
|
||||
url.setScheme( QLatin1String("owncloud") );
|
||||
} else {
|
||||
// connect SSL!
|
||||
url.setScheme( QLatin1String("ownclouds") );
|
||||
}
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
ownCloudFolder::ownCloudFolder(const QString &alias,
|
||||
const QString &mpath,
|
||||
const QString &secondPath,
|
||||
QObject *parent)
|
||||
: Folder(alias, mpath, secondPath, parent)
|
||||
, _thread(0)
|
||||
, _csync(0)
|
||||
, _csyncError(false)
|
||||
, _csyncUnavail(false)
|
||||
, _csync_ctx(0)
|
||||
{
|
||||
ServerActionNotifier *notifier = new ServerActionNotifier(this);
|
||||
connect(notifier, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(optionalGuiLog(QString,QString)));
|
||||
connect(this, SIGNAL(syncFinished(SyncResult)), notifier, SLOT(slotSyncFinished(SyncResult)));
|
||||
qDebug() << "****** ownCloud folder using watcher *******";
|
||||
// The folder interval is set in the folder parent class.
|
||||
}
|
||||
|
||||
bool ownCloudFolder::init()
|
||||
{
|
||||
QString url = replaceScheme(ownCloudInfo::instance()->webdavUrl() + secondPath());
|
||||
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();
|
||||
csync_set_auth_callback( _csync_ctx, getauth );
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ownCloudFolder::~ownCloudFolder()
|
||||
{
|
||||
if( _thread ) {
|
||||
_thread->quit();
|
||||
csync_request_abort(_csync_ctx);
|
||||
_thread->wait();
|
||||
}
|
||||
delete _csync;
|
||||
// Destroy csync here.
|
||||
csync_destroy(_csync_ctx);
|
||||
}
|
||||
|
||||
void ownCloudFolder::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 ownCloudFolder::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* ownCloudFolder::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";
|
||||
}
|
||||
}
|
||||
|
||||
int ownCloudFolder::getauth(const char *prompt,
|
||||
char *buf,
|
||||
size_t len,
|
||||
int echo,
|
||||
int verify,
|
||||
void *userdata
|
||||
)
|
||||
{
|
||||
int re = 0;
|
||||
QMutex mutex;
|
||||
|
||||
QString qPrompt = QString::fromLatin1( prompt ).trimmed();
|
||||
QString user = CredentialStore::instance()->user();
|
||||
QString pwd = CredentialStore::instance()->password();
|
||||
|
||||
if( qPrompt == QLatin1String("Enter your username:") ) {
|
||||
// qDebug() << "OOO Username requested!";
|
||||
QMutexLocker locker( &mutex );
|
||||
qstrncpy( buf, user.toUtf8().constData(), len );
|
||||
} else if( qPrompt == QLatin1String("Enter your password:") ) {
|
||||
QMutexLocker locker( &mutex );
|
||||
// qDebug() << "OOO Password requested!";
|
||||
qstrncpy( buf, pwd.toUtf8().constData(), len );
|
||||
} else {
|
||||
if( qPrompt.startsWith( QLatin1String("There are problems with the SSL certificate:"))) {
|
||||
// SSL is requested. If the program came here, the SSL check was done by mirall
|
||||
// It needs to be checked if the chain is still equal to the one which
|
||||
// was verified by the user.
|
||||
QRegExp regexp("fingerprint: ([\\w\\d:]+)");
|
||||
bool certOk = false;
|
||||
|
||||
int pos = 0;
|
||||
|
||||
// This is the set of certificates which QNAM accepted, so we should accept
|
||||
// them as well
|
||||
QList<QSslCertificate> certs = ownCloudInfo::instance()->certificateChain();
|
||||
|
||||
while (!certOk && (pos = regexp.indexIn(qPrompt, 1+pos)) != -1) {
|
||||
QString neon_fingerprint = regexp.cap(1);
|
||||
|
||||
foreach( const QSslCertificate& c, certs ) {
|
||||
QString verified_shasum = Utility::formatFingerprint(c.digest(QCryptographicHash::Sha1).toHex());
|
||||
qDebug() << "SSL Fingerprint from neon: " << neon_fingerprint << " compared to verified: " << verified_shasum;
|
||||
if( verified_shasum == neon_fingerprint ) {
|
||||
certOk = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// certOk = false; DEBUG setting, keep disabled!
|
||||
if( !certOk ) { // Problem!
|
||||
qstrcpy( buf, "no" );
|
||||
re = -1;
|
||||
} else {
|
||||
qstrcpy( buf, "yes" ); // Certificate is fine!
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Unknown prompt: <" << prompt << ">";
|
||||
re = -1;
|
||||
}
|
||||
}
|
||||
return re;
|
||||
}
|
||||
|
||||
|
||||
bool ownCloudFolder::isBusy() const
|
||||
{
|
||||
return ( _thread && _thread->isRunning() );
|
||||
}
|
||||
|
||||
QString ownCloudFolder::secondPath() const
|
||||
{
|
||||
return Folder::secondPath();
|
||||
}
|
||||
|
||||
void ownCloudFolder::startSync()
|
||||
{
|
||||
startSync( QStringList() );
|
||||
}
|
||||
|
||||
void ownCloudFolder::startSync(const QStringList &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->setLastAuthCookies(ownCloudInfo::instance()->getLastAuthCookies());
|
||||
_csync->moveToThread(_thread);
|
||||
|
||||
|
||||
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);
|
||||
connect(_csync, SIGNAL(fileTransmissionProgress(Progress::Kind, QString,long,long)),
|
||||
SLOT(slotFileTransmissionProgress(Progress::Kind, QString,long,long)));
|
||||
connect(_csync, SIGNAL(overallTransmissionProgress(QString, int, int, long long, long long)),
|
||||
SLOT(slotOverallTransmissionProgress(QString, int, int, long long, long long)));
|
||||
|
||||
|
||||
_thread->start();
|
||||
QMetaObject::invokeMethod(_csync, "startSync", Qt::QueuedConnection);
|
||||
emit syncStarted();
|
||||
}
|
||||
|
||||
void ownCloudFolder::slotCSyncStarted()
|
||||
{
|
||||
qDebug() << " * csync thread started";
|
||||
_syncResult.setStatus(SyncResult::SyncRunning);
|
||||
emit syncStateChange();
|
||||
}
|
||||
|
||||
void ownCloudFolder::slotCSyncError(const QString& err)
|
||||
{
|
||||
_errors.append( err );
|
||||
_csyncError = true;
|
||||
}
|
||||
|
||||
void ownCloudFolder::slotCsyncUnavailable()
|
||||
{
|
||||
_csyncUnavail = true;
|
||||
}
|
||||
|
||||
void ownCloudFolder::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);
|
||||
} else {
|
||||
_syncResult.setStatus(SyncResult::Success);
|
||||
}
|
||||
|
||||
if( _thread && _thread->isRunning() ) {
|
||||
_thread->quit();
|
||||
}
|
||||
ownCloudInfo::instance()->getQuotaRequest("/");
|
||||
emit syncFinished( _syncResult );
|
||||
}
|
||||
|
||||
void ownCloudFolder::slotThreadTreeWalkResult(const SyncFileItemVector& items)
|
||||
{
|
||||
_syncResult.setSyncFileItemVector(items);
|
||||
}
|
||||
|
||||
void ownCloudFolder::slotTerminateSync()
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
void ownCloudFolder::slotLocalPathChanged( const QString& dir )
|
||||
{
|
||||
QDir notifiedDir(dir);
|
||||
QDir localPath( path() );
|
||||
|
||||
if( notifiedDir.absolutePath() == localPath.absolutePath() ) {
|
||||
if( !localPath.exists() ) {
|
||||
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();
|
||||
}
|
||||
|
||||
qDebug() << "ALARM: The local path was DELETED!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ownCloudFolder::slotFileTransmissionProgress(Progress::Kind kind, const QString& file ,long p1, long p2)
|
||||
{
|
||||
if( kind == Progress::StartDownload ) {
|
||||
_progressKind = Progress::Download;
|
||||
}
|
||||
if( kind == Progress::StartUpload ) {
|
||||
_progressKind = Progress::Upload;
|
||||
}
|
||||
|
||||
// qDebug() << "Upload Progress: " << file << p1 << p2;
|
||||
ProgressDispatcher::instance()->setFolderProgress( _progressKind, alias(), file, p1, p2 );
|
||||
|
||||
if( kind == Progress::EndDownload || kind == Progress::EndUpload ) {
|
||||
_progressKind = Progress::Inactive;
|
||||
}
|
||||
}
|
||||
|
||||
void ownCloudFolder::slotOverallTransmissionProgress( const QString& fileName, int fileNo, int fileCnt,
|
||||
long long o1, long long o2)
|
||||
{
|
||||
ProgressDispatcher::instance()->setOverallProgress( alias(), fileName, fileNo, fileCnt, qlonglong(o1), qlonglong(o2));
|
||||
}
|
||||
|
||||
|
||||
// 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
|
||||
void ownCloudFolder::wipe()
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
break;
|
||||
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 ownCloudFolder::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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // ns
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MIRALL_ownCloudFolder_H
|
||||
#define MIRALL_ownCloudFolder_H
|
||||
|
||||
#include <QMutex>
|
||||
#include <QThread>
|
||||
#include <QStringList>
|
||||
|
||||
#include "mirall/folder.h"
|
||||
#include "mirall/csyncthread.h"
|
||||
#include "mirall/progressdispatcher.h"
|
||||
|
||||
class QProcess;
|
||||
class QTimer;
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
enum SyncFileStatus_s {
|
||||
STATUS_NONE,
|
||||
STATUS_EVAL,
|
||||
STATUS_REMOVE,
|
||||
STATUS_RENAME,
|
||||
STATUS_NEW,
|
||||
STATUS_CONFLICT,
|
||||
STATUS_IGNORE,
|
||||
STATUS_SYNC,
|
||||
STATUS_STAT_ERROR,
|
||||
STATUS_ERROR,
|
||||
STATUS_UPDATED
|
||||
};
|
||||
typedef SyncFileStatus_s SyncFileStatus;
|
||||
|
||||
class ServerActionNotifier : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ServerActionNotifier(QObject *parent = 0);
|
||||
public slots:
|
||||
void slotSyncFinished(const SyncResult &result);
|
||||
signals:
|
||||
void guiLog(const QString&, const QString&);
|
||||
void sendResults();
|
||||
private:
|
||||
};
|
||||
|
||||
class ownCloudFolder : public Folder
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ownCloudFolder(const QString &alias,
|
||||
const QString &path,
|
||||
const QString &secondPath, QObject *parent = 0L);
|
||||
virtual ~ownCloudFolder();
|
||||
QString secondPath() const;
|
||||
virtual bool isBusy() const;
|
||||
virtual void startSync(const QStringList &pathList);
|
||||
|
||||
virtual void wipe();
|
||||
|
||||
/* get status about a singel file. */
|
||||
SyncFileStatus fileStatus( const QString& );
|
||||
|
||||
|
||||
public slots:
|
||||
void startSync();
|
||||
void slotTerminateSync();
|
||||
void slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool*);
|
||||
|
||||
protected slots:
|
||||
void slotLocalPathChanged( const QString& );
|
||||
void slotThreadTreeWalkResult(const SyncFileItemVector& );
|
||||
|
||||
private slots:
|
||||
void slotCSyncStarted();
|
||||
void slotCSyncError(const QString& );
|
||||
void slotCsyncUnavailable();
|
||||
void slotCSyncFinished();
|
||||
|
||||
void slotFileTransmissionProgress(Progress::Kind, const QString&,long, long);
|
||||
void slotOverallTransmissionProgress( const QString&, int, int, long long, long long);
|
||||
|
||||
private:
|
||||
void setIgnoredFiles();
|
||||
void setProxy();
|
||||
static int getauth(const char *prompt,
|
||||
char *buf,
|
||||
size_t len,
|
||||
int echo,
|
||||
int verify,
|
||||
void *userdata
|
||||
);
|
||||
const char* proxyTypeToCStr(QNetworkProxy::ProxyType type);
|
||||
|
||||
bool init();
|
||||
|
||||
QString _secondPath;
|
||||
QThread *_thread;
|
||||
CSyncThread *_csync;
|
||||
QStringList _errors;
|
||||
bool _csyncError;
|
||||
bool _csyncUnavail;
|
||||
bool _wipeDb;
|
||||
SyncFileItemVector _items;
|
||||
Progress::Kind _progressKind;
|
||||
|
||||
CSYNC *_csync_ctx;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -168,8 +168,8 @@ void OwncloudSetupWizard::slotAssistantFinished( int result )
|
|||
// Now write the resulting folder definition if folder names are set.
|
||||
if( acceptCfg && urlHasChanged ) {
|
||||
folderMan->removeAllFolderDefinitions();
|
||||
folderMan->addFolderDefinition( QLatin1String("owncloud"), Theme::instance()->appName(),
|
||||
localFolder, _remoteFolder, false );
|
||||
folderMan->addFolderDefinition(Theme::instance()->appName(),
|
||||
localFolder, _remoteFolder );
|
||||
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
|
||||
} else {
|
||||
// url is unchanged. Only the password was changed.
|
||||
|
|
Loading…
Reference in a new issue