2012-02-17 12:48:31 +04:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
* 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.
|
|
|
|
*/
|
2012-07-20 19:13:23 +04:00
|
|
|
|
2012-05-21 18:48:49 +04:00
|
|
|
#include "mirall/folderman.h"
|
2012-02-17 14:11:18 +04:00
|
|
|
#include "mirall/mirallconfigfile.h"
|
2012-02-17 12:48:31 +04:00
|
|
|
#include "mirall/unisonfolder.h"
|
|
|
|
#include "mirall/csyncfolder.h"
|
|
|
|
#include "mirall/owncloudfolder.h"
|
|
|
|
#include "mirall/syncresult.h"
|
2012-02-29 18:25:16 +04:00
|
|
|
#include "mirall/inotify.h"
|
2012-09-24 19:55:10 +04:00
|
|
|
#include "mirall/theme.h"
|
2012-02-17 12:48:31 +04:00
|
|
|
|
2012-05-21 18:48:49 +04:00
|
|
|
#include <QDesktopServices>
|
|
|
|
#include <QtCore>
|
|
|
|
|
2012-02-17 12:48:31 +04:00
|
|
|
namespace Mirall {
|
|
|
|
|
|
|
|
FolderMan::FolderMan(QObject *parent) :
|
2012-05-14 13:09:01 +04:00
|
|
|
QObject(parent)
|
2012-02-17 12:48:31 +04:00
|
|
|
{
|
|
|
|
// if QDir::mkpath would not be so stupid, I would not need to have this
|
|
|
|
// duplication of folderConfigPath() here
|
|
|
|
QDir storageDir(QDesktopServices::storageLocation(QDesktopServices::DataLocation));
|
2012-08-17 19:13:17 +04:00
|
|
|
storageDir.mkpath(QLatin1String("folders"));
|
|
|
|
_folderConfigPath = QDesktopServices::storageLocation(QDesktopServices::DataLocation) + QLatin1String("/folders");
|
2012-02-19 00:21:58 +04:00
|
|
|
|
|
|
|
_folderChangeSignalMapper = new QSignalMapper(this);
|
|
|
|
connect(_folderChangeSignalMapper, SIGNAL(mapped(const QString &)),
|
|
|
|
this, SIGNAL(folderSyncStateChange(const QString &)));
|
2012-02-17 12:48:31 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
FolderMan::~FolderMan()
|
|
|
|
{
|
|
|
|
foreach (Folder *folder, _folderMap) {
|
|
|
|
delete folder;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Mirall::Folder::Map FolderMan::map()
|
|
|
|
{
|
|
|
|
return _folderMap;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int FolderMan::setupFolders()
|
|
|
|
{
|
|
|
|
// setup a handler to look for configuration changes
|
2012-02-28 19:49:13 +04:00
|
|
|
#ifdef CHECK_FOR_SETUP_CHANGES
|
2012-02-17 15:16:48 +04:00
|
|
|
_configFolderWatcher = new FolderWatcher( _folderConfigPath );
|
2012-02-28 19:49:13 +04:00
|
|
|
_configFolderWatcher->setEventInterval(20000);
|
2012-02-17 12:48:31 +04:00
|
|
|
connect(_configFolderWatcher, SIGNAL(folderChanged(const QStringList &)),
|
2012-02-20 19:45:27 +04:00
|
|
|
this, SLOT( slotReparseConfiguration()) );
|
2012-02-28 19:49:13 +04:00
|
|
|
#endif
|
2012-02-20 19:45:27 +04:00
|
|
|
int cnt = setupKnownFolders();
|
2012-02-17 12:48:31 +04:00
|
|
|
|
2012-02-20 19:45:27 +04:00
|
|
|
return cnt;
|
2012-02-17 12:48:31 +04:00
|
|
|
}
|
|
|
|
|
2012-02-20 19:45:27 +04:00
|
|
|
void FolderMan::slotReparseConfiguration()
|
2012-02-17 12:48:31 +04:00
|
|
|
{
|
2012-02-20 19:45:27 +04:00
|
|
|
setupKnownFolders();
|
2012-02-17 12:48:31 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int FolderMan::setupKnownFolders()
|
|
|
|
{
|
2012-02-20 19:45:27 +04:00
|
|
|
qDebug() << "* Setup folders from " << _folderConfigPath;
|
2012-02-17 12:48:31 +04:00
|
|
|
|
2012-02-17 14:11:18 +04:00
|
|
|
_folderMap.clear(); // FIXME: check if delete of folder structure happens
|
|
|
|
|
2012-02-20 19:45:27 +04:00
|
|
|
QDir dir( _folderConfigPath );
|
2012-02-17 12:48:31 +04:00
|
|
|
dir.setFilter(QDir::Files);
|
|
|
|
QStringList list = dir.entryList();
|
2012-02-17 14:11:18 +04:00
|
|
|
|
2012-05-21 18:48:49 +04:00
|
|
|
foreach ( const QString& alias, list ) {
|
2012-02-17 14:11:18 +04:00
|
|
|
Folder *f = setupFolderFromConfigFile( alias );
|
2012-07-25 17:00:18 +04:00
|
|
|
if( f ) {
|
|
|
|
emit( folderSyncStateChange( f->alias() ) );
|
|
|
|
}
|
2012-02-17 12:48:31 +04:00
|
|
|
}
|
2012-02-17 14:11:18 +04:00
|
|
|
// return the number of valid folders.
|
|
|
|
return _folderMap.size();
|
2012-02-17 12:48:31 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// filename is the name of the file only, it does not include
|
|
|
|
// the configuration directory path
|
|
|
|
Folder* FolderMan::setupFolderFromConfigFile(const QString &file) {
|
|
|
|
Folder *folder = 0L;
|
|
|
|
|
|
|
|
qDebug() << " ` -> setting up:" << file;
|
2012-08-17 19:13:17 +04:00
|
|
|
QSettings settings( _folderConfigPath + QLatin1Char('/') + file, QSettings::IniFormat);
|
|
|
|
qDebug() << " -> file path: " << settings.fileName();
|
2012-02-17 12:48:31 +04:00
|
|
|
|
2012-02-17 14:11:18 +04:00
|
|
|
settings.beginGroup( file ); // read the group with the same name as the file which is the folder alias
|
2012-02-17 12:48:31 +04:00
|
|
|
|
2012-08-17 19:13:17 +04:00
|
|
|
QString path = settings.value(QLatin1String("localpath")).toString();
|
2012-02-17 14:11:18 +04:00
|
|
|
if ( path.isNull() || !QFileInfo( path ).isDir() ) {
|
|
|
|
qWarning() << " `->" << path << "does not exist. Skipping folder" << file;
|
2012-02-17 12:48:31 +04:00
|
|
|
// _tray->showMessage(tr("Unknown folder"),
|
|
|
|
// tr("Folder %1 does not exist").arg(path.toString()),
|
|
|
|
// QSystemTrayIcon::Critical);
|
|
|
|
return folder;
|
|
|
|
}
|
|
|
|
|
2012-08-17 19:13:17 +04:00
|
|
|
QString backend = settings.value(QLatin1String("backend")).toString();
|
|
|
|
QString targetPath = settings.value( QLatin1String("targetPath") ).toString();
|
|
|
|
QString connection = settings.value( QLatin1String("connection") ).toString();
|
2012-02-17 14:11:18 +04:00
|
|
|
|
2012-02-17 12:48:31 +04:00
|
|
|
if (!backend.isEmpty()) {
|
2012-02-17 14:11:18 +04:00
|
|
|
|
2012-08-17 19:13:17 +04:00
|
|
|
if (backend == QLatin1String("unison")) {
|
2012-02-17 14:11:18 +04:00
|
|
|
folder = new UnisonFolder(file, path, targetPath, this );
|
2012-08-17 19:13:17 +04:00
|
|
|
} else if (backend == QLatin1String("csync")) {
|
2012-02-17 12:48:31 +04:00
|
|
|
#ifdef WITH_CSYNC
|
2012-02-17 14:11:18 +04:00
|
|
|
folder = new CSyncFolder(file, path, targetPath, this );
|
2012-02-17 12:48:31 +04:00
|
|
|
#else
|
|
|
|
qCritical() << "* csync support not enabled!! ignoring:" << file;
|
|
|
|
#endif
|
2012-08-17 19:13:17 +04:00
|
|
|
} else if( backend == QLatin1String("owncloud") ) {
|
2012-02-17 12:48:31 +04:00
|
|
|
#ifdef WITH_CSYNC
|
2012-02-17 14:11:18 +04:00
|
|
|
|
|
|
|
MirallConfigFile cfgFile;
|
|
|
|
|
2012-05-14 18:18:08 +04:00
|
|
|
// assemble the owncloud url to pass to csync, incl. webdav
|
2012-08-17 19:13:17 +04:00
|
|
|
QString oCUrl = cfgFile.ownCloudUrl( QString::null, true );
|
2012-02-17 12:48:31 +04:00
|
|
|
|
2012-05-14 18:18:08 +04:00
|
|
|
// cut off the leading slash, oCUrl always has a trailing.
|
2012-08-17 19:13:17 +04:00
|
|
|
if( targetPath.startsWith(QLatin1Char('/')) ) {
|
|
|
|
|
2012-05-14 18:18:08 +04:00
|
|
|
targetPath.remove(0,1);
|
|
|
|
}
|
2012-02-17 12:48:31 +04:00
|
|
|
|
2012-05-14 18:18:08 +04:00
|
|
|
folder = new ownCloudFolder( file, path, oCUrl + targetPath, this );
|
2012-02-17 12:48:31 +04:00
|
|
|
#else
|
|
|
|
qCritical() << "* owncloud support not enabled!! ignoring:" << file;
|
|
|
|
#endif
|
2012-02-17 14:11:18 +04:00
|
|
|
} else {
|
2012-02-17 12:48:31 +04:00
|
|
|
qWarning() << "unknown backend" << backend;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
folder->setBackend( backend );
|
2012-02-17 14:11:18 +04:00
|
|
|
// folder->setOnlyOnlineEnabled(settings.value("folder/onlyOnline", false).toBool());
|
2012-08-17 19:13:17 +04:00
|
|
|
folder->setOnlyThisLANEnabled(settings.value(QLatin1String("folder/onlyThisLAN"), false).toBool());
|
2012-02-17 12:48:31 +04:00
|
|
|
|
|
|
|
_folderMap[file] = folder;
|
2012-02-19 00:21:58 +04:00
|
|
|
|
2012-02-17 12:48:31 +04:00
|
|
|
qDebug() << "Adding folder to Folder Map " << folder;
|
2012-02-19 00:21:58 +04:00
|
|
|
/* Use a signal mapper to connect the signals to the alias */
|
2012-03-29 12:13:19 +04:00
|
|
|
connect(folder, SIGNAL(scheduleToSync(const QString&)), SLOT(slotScheduleSync(const QString&)));
|
2012-02-19 00:21:58 +04:00
|
|
|
connect(folder, SIGNAL(syncStateChange()), _folderChangeSignalMapper, SLOT(map()));
|
2012-03-22 19:22:08 +04:00
|
|
|
connect(folder, SIGNAL(syncStarted()), SLOT(slotFolderSyncStarted()));
|
|
|
|
connect(folder, SIGNAL(syncFinished(SyncResult)), SLOT(slotFolderSyncFinished(SyncResult)));
|
|
|
|
|
2012-02-19 00:21:58 +04:00
|
|
|
_folderChangeSignalMapper->setMapping( folder, folder->alias() );
|
2012-02-17 12:48:31 +04:00
|
|
|
|
|
|
|
return folder;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FolderMan::disableFoldersWithRestore()
|
|
|
|
{
|
|
|
|
_folderEnabledMap.clear();
|
|
|
|
foreach( Folder *f, _folderMap ) {
|
|
|
|
// store the enabled state, then make sure it is disabled
|
|
|
|
_folderEnabledMap.insert(f->alias(), f->syncEnabled());
|
|
|
|
f->setSyncEnabled(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FolderMan::restoreEnabledFolders()
|
|
|
|
{
|
|
|
|
foreach( Folder *f, _folderMap ) {
|
|
|
|
if (_folderEnabledMap.contains( f->alias() )) {
|
2012-03-08 14:39:31 +04:00
|
|
|
f->setSyncEnabled( _folderEnabledMap.value( f->alias() ) );
|
2012-02-17 12:48:31 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FolderMan::slotEnableFolder( const QString& alias, bool enable )
|
|
|
|
{
|
|
|
|
if( ! _folderMap.contains( alias ) ) {
|
|
|
|
qDebug() << "!! Can not enable alias " << alias << ", can not be found in folderMap.";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Folder *f = _folderMap[alias];
|
2012-04-30 10:56:56 +04:00
|
|
|
if( f ) {
|
|
|
|
f->setSyncEnabled(enable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// this really terminates, ie. no questions, no prisoners.
|
|
|
|
// csync still remains in a stable state, regardless of that.
|
|
|
|
void FolderMan::terminateSyncProcess( const QString& alias )
|
|
|
|
{
|
|
|
|
Folder *f = _folderMap[alias];
|
|
|
|
if( f ) {
|
|
|
|
f->slotTerminateSync();
|
|
|
|
}
|
2012-02-17 12:48:31 +04:00
|
|
|
}
|
|
|
|
|
2012-02-21 14:50:19 +04:00
|
|
|
Folder *FolderMan::folder( const QString& alias )
|
|
|
|
{
|
|
|
|
if( !alias.isEmpty() ) {
|
|
|
|
if( _folderMap.contains( alias )) {
|
|
|
|
return _folderMap[alias];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-02-17 12:48:31 +04:00
|
|
|
SyncResult FolderMan::syncResult( const QString& alias )
|
|
|
|
{
|
|
|
|
SyncResult res;
|
2012-02-21 14:50:19 +04:00
|
|
|
Folder *f = folder( alias );
|
|
|
|
|
|
|
|
if( f ) {
|
2012-02-20 19:45:27 +04:00
|
|
|
res = f->syncResult();
|
2012-02-17 12:48:31 +04:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2012-03-22 19:22:08 +04:00
|
|
|
/*
|
|
|
|
* if a folder wants to be synced, it calls this slot and is added
|
|
|
|
* to the queue. The slot to actually start a sync is called afterwards.
|
|
|
|
*/
|
2012-03-29 12:13:19 +04:00
|
|
|
void FolderMan::slotScheduleSync( const QString& alias )
|
2012-03-22 19:22:08 +04:00
|
|
|
{
|
2012-03-29 12:13:19 +04:00
|
|
|
if( alias.isEmpty() ) return;
|
|
|
|
|
|
|
|
qDebug() << "Schedule folder " << alias << " to sync!";
|
|
|
|
if( _currentSyncFolder == alias ) {
|
|
|
|
// the current folder is currently syncing.
|
|
|
|
}
|
2012-03-22 19:22:08 +04:00
|
|
|
|
2012-03-29 12:13:19 +04:00
|
|
|
if( _scheduleQueue.contains( alias ) ) {
|
|
|
|
qDebug() << " II> Sync for folder " << alias << " already scheduled, do not enqueue!";
|
|
|
|
} else {
|
|
|
|
_scheduleQueue.append( alias );
|
|
|
|
|
|
|
|
slotScheduleFolderSync();
|
|
|
|
}
|
2012-03-22 19:22:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* slot to start folder syncs.
|
|
|
|
* It is either called from the slot where folders enqueue themselves for
|
|
|
|
* syncing or after a folder sync was finished.
|
|
|
|
*/
|
|
|
|
void FolderMan::slotScheduleFolderSync()
|
|
|
|
{
|
2012-03-29 12:13:19 +04:00
|
|
|
if( !_currentSyncFolder.isEmpty() ) {
|
2012-03-22 19:22:08 +04:00
|
|
|
qDebug() << "Currently folder " << _currentSyncFolder << " is running, wait for finish!";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-04-30 10:56:56 +04:00
|
|
|
qDebug() << "XX slotScheduleFolderSync: folderQueue size: " << _scheduleQueue.count();
|
2012-03-22 19:22:08 +04:00
|
|
|
if( ! _scheduleQueue.isEmpty() ) {
|
2012-03-29 12:13:19 +04:00
|
|
|
const QString alias = _scheduleQueue.takeFirst();
|
|
|
|
if( _folderMap.contains( alias ) ) {
|
|
|
|
Folder *f = _folderMap[alias];
|
|
|
|
_currentSyncFolder = alias;
|
|
|
|
f->startSync( QStringList() );
|
|
|
|
}
|
2012-03-22 19:22:08 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 12:48:31 +04:00
|
|
|
void FolderMan::slotFolderSyncStarted( )
|
|
|
|
{
|
2012-03-29 12:13:19 +04:00
|
|
|
qDebug() << ">===================================== sync started for " << _currentSyncFolder;
|
2012-02-17 12:48:31 +04:00
|
|
|
}
|
|
|
|
|
2012-03-22 19:22:08 +04:00
|
|
|
/*
|
|
|
|
* a folder indicates that its syncing is finished.
|
|
|
|
* Start the next sync after the system had some milliseconds to breath.
|
|
|
|
*/
|
2012-02-17 12:48:31 +04:00
|
|
|
void FolderMan::slotFolderSyncFinished( const SyncResult& )
|
|
|
|
{
|
2012-03-29 12:13:19 +04:00
|
|
|
qDebug() << "<===================================== sync finsihed for " << _currentSyncFolder;
|
|
|
|
|
2012-04-30 10:56:56 +04:00
|
|
|
_currentSyncFolder.clear();
|
2012-03-22 19:22:08 +04:00
|
|
|
QTimer::singleShot(200, this, SLOT(slotScheduleFolderSync()));
|
2012-02-17 12:48:31 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2012-04-02 15:21:13 +04:00
|
|
|
void FolderMan::addFolderDefinition( const QString& backend, const QString& alias,
|
|
|
|
const QString& sourceFolder, const QString& targetPath,
|
|
|
|
bool onlyThisLAN )
|
2012-02-17 12:48:31 +04:00
|
|
|
{
|
|
|
|
// Create a settings file named after the alias
|
2012-08-17 19:13:17 +04:00
|
|
|
QSettings settings( _folderConfigPath + QLatin1Char('/') + alias, QSettings::IniFormat);
|
2012-02-17 12:48:31 +04:00
|
|
|
|
2012-08-17 19:13:17 +04:00
|
|
|
settings.setValue(QString::fromLatin1("%1/localPath").arg(alias), sourceFolder );
|
|
|
|
settings.setValue(QString::fromLatin1("%1/targetPath").arg(alias), targetPath );
|
|
|
|
settings.setValue(QString::fromLatin1("%1/backend").arg(alias), backend );
|
2012-09-24 19:55:10 +04:00
|
|
|
settings.setValue(QString::fromLatin1("%1/connection").arg(alias), Theme::instance()->appName());
|
2012-08-17 19:13:17 +04:00
|
|
|
settings.setValue(QString::fromLatin1("%1/onlyThisLAN").arg(alias), onlyThisLAN );
|
2012-02-17 12:48:31 +04:00
|
|
|
settings.sync();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-06-13 13:30:26 +04:00
|
|
|
void FolderMan::removeAllFolderDefinitions()
|
|
|
|
{
|
|
|
|
foreach( Folder *f, _folderMap.values() ) {
|
|
|
|
slotRemoveFolder( f->alias() );
|
|
|
|
}
|
|
|
|
// clear the queue.
|
|
|
|
_scheduleQueue.clear();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-02-17 12:48:31 +04:00
|
|
|
void FolderMan::slotRemoveFolder( const QString& alias )
|
|
|
|
{
|
|
|
|
if( alias.isEmpty() ) return;
|
|
|
|
|
2012-03-29 12:13:19 +04:00
|
|
|
if( _currentSyncFolder == alias ) {
|
2012-05-14 13:09:01 +04:00
|
|
|
// terminate if the sync is currently underway.
|
|
|
|
terminateSyncProcess( alias );
|
2012-03-29 12:13:19 +04:00
|
|
|
}
|
2012-05-14 13:09:01 +04:00
|
|
|
removeFolder(alias);
|
2012-03-29 12:13:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// remove a folder from the map. Should be sure n
|
|
|
|
void FolderMan::removeFolder( const QString& alias )
|
|
|
|
{
|
2012-02-17 12:48:31 +04:00
|
|
|
if( _folderMap.contains( alias )) {
|
|
|
|
qDebug() << "Removing " << alias;
|
|
|
|
Folder *f = _folderMap.take( alias );
|
2012-06-11 12:10:07 +04:00
|
|
|
f->wipe();
|
2012-03-29 12:13:19 +04:00
|
|
|
f->deleteLater();
|
2012-02-17 12:48:31 +04:00
|
|
|
} else {
|
|
|
|
qDebug() << "!! Can not remove " << alias << ", not in folderMap.";
|
|
|
|
}
|
|
|
|
|
2012-08-17 19:13:17 +04:00
|
|
|
QFile file( _folderConfigPath + QLatin1Char('/') + alias );
|
2012-02-17 12:48:31 +04:00
|
|
|
if( file.exists() ) {
|
|
|
|
qDebug() << "Remove folder config file " << file.fileName();
|
|
|
|
file.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|