diff options
author | Daniel Molkentin <danimo@owncloud.com> | 2014-07-11 02:31:24 +0400 |
---|---|---|
committer | Daniel Molkentin <danimo@owncloud.com> | 2014-07-11 13:07:31 +0400 |
commit | df3c3bca025a7cdb5f20e55fc2ecc37618e7cc8d (patch) | |
tree | 22fa58b5a09ec9f93ad376dce2edd6272483fc1a /src/mirall | |
parent | d1b991e1984ef0c4ed803c5c5ead1ce3bfe00266 (diff) |
Split into three separate projects: library, gui and cmd
Diffstat (limited to 'src/mirall')
116 files changed, 0 insertions, 22122 deletions
diff --git a/src/mirall/account.cpp b/src/mirall/account.cpp deleted file mode 100644 index a41369197..000000000 --- a/src/mirall/account.cpp +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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/account.h" -#include "mirall/cookiejar.h" -#include "mirall/theme.h" -#include "mirall/networkjobs.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/mirallaccessmanager.h" -#include "mirall/quotainfo.h" -#include "creds/abstractcredentials.h" -#include "creds/credentialsfactory.h" - -#include <QSettings> -#include <QMutex> -#include <QNetworkReply> -#include <QNetworkAccessManager> -#include <QSslSocket> -#include <QNetworkCookieJar> - -#include <QDebug> - -namespace Mirall { - -static const char urlC[] = "url"; -static const char authTypeC[] = "authType"; -static const char userC[] = "user"; -static const char httpUserC[] = "http_user"; - -AccountManager *AccountManager::_instance = 0; - -AccountManager *AccountManager::instance() -{ - static QMutex mutex; - if (!_instance) - { - QMutexLocker lock(&mutex); - if (!_instance) { - _instance = new AccountManager; - } - } - - return _instance; -} - -void AccountManager::setAccount(Account *account) -{ - emit accountAboutToChange(account, _account); - std::swap(_account, account); - emit accountChanged(_account, account); -} - - -Account::Account(AbstractSslErrorHandler *sslErrorHandler, QObject *parent) - : QObject(parent) - , _url(Theme::instance()->overrideServerUrl()) - , _sslErrorHandler(sslErrorHandler) - , _quotaInfo(new QuotaInfo(this)) - , _am(0) - , _credentials(0) - , _treatSslErrorsAsFailure(false) - , _state(Account::Disconnected) - , _davPath("remote.php/webdav/") -{ - qRegisterMetaType<Account*>("Account*"); -} - -Account::~Account() -{ - delete _credentials; - delete _am; -} - -void Account::save() -{ - QScopedPointer<QSettings> settings(settingsWithGroup(Theme::instance()->appName())); - settings->setValue(QLatin1String(urlC), _url.toString()); - if (_credentials) { - _credentials->persist(this); - Q_FOREACH(QString key, _settingsMap.keys()) { - settings->setValue(key, _settingsMap.value(key)); - } - settings->setValue(QLatin1String(authTypeC), _credentials->authType()); - - // HACK: Save http_user also as user - if (_settingsMap.contains(httpUserC)) - settings->setValue(userC, _settingsMap.value(httpUserC)); - } - settings->sync(); - - // ### TODO port away from MirallConfigFile - MirallConfigFile cfg; - qDebug() << "Saving " << approvedCerts().count() << " unknown certs."; - QByteArray certs; - Q_FOREACH( const QSslCertificate& cert, approvedCerts() ) { - certs += cert.toPem() + '\n'; - } - if (!certs.isEmpty()) { - cfg.setCaCerts( certs ); - } -} - -Account* Account::restore() -{ - QScopedPointer<QSettings> settings(settingsWithGroup(Theme::instance()->appName())); - if (!settings->childKeys().isEmpty()) { - Account *acc = new Account; - MirallConfigFile cfg; - acc->setApprovedCerts(QSslCertificate::fromData(cfg.caCerts())); - acc->setUrl(settings->value(QLatin1String(urlC)).toUrl()); - acc->setCredentials(CredentialsFactory::create(settings->value(QLatin1String(authTypeC)).toString())); - - // We want to only restore settings for that auth type and the user value - acc->_settingsMap.insert(QLatin1String(userC), settings->value(userC)); - QString authTypePrefix = settings->value(authTypeC).toString() + "_"; - Q_FOREACH(QString key, settings->childKeys()) { - if (!key.startsWith(authTypePrefix)) - continue; - acc->_settingsMap.insert(key, settings->value(key)); - } - return acc; - } - return 0; -} - -static bool isEqualExceptProtocol(const QUrl &url1, const QUrl &url2) -{ - return (url1.host() != url2.host() || - url1.port() != url2.port() || - url1.path() != url2.path()); -} - -bool Account::changed(Account *other, bool ignoreUrlProtocol) const -{ - if (!other) { - return false; - } - bool changes = false; - if (ignoreUrlProtocol) { - changes = isEqualExceptProtocol(_url, other->_url); - } else { - changes = (_url == other->_url); - } - - changes |= _credentials->changed(other->_credentials); - - return changes; -} - -AbstractCredentials *Account::credentials() const -{ - return _credentials; -} - -void Account::setCredentials(AbstractCredentials *cred) -{ - // set active credential manager - QNetworkCookieJar *jar = 0; - if (_am) { - jar = _am->cookieJar(); - jar->setParent(0); - - _am->deleteLater(); - } - - if (_credentials) { - credentials()->deleteLater(); - } - _credentials = cred; - _am = _credentials->getQNAM(); - if (jar) { - _am->setCookieJar(jar); - } - connect(_am, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), - SLOT(slotHandleErrors(QNetworkReply*,QList<QSslError>))); -} - -QUrl Account::davUrl() const -{ - return concatUrlPath(url(), davPath()); -} - -QList<QNetworkCookie> Account::lastAuthCookies() const -{ - return _am->cookieJar()->cookiesForUrl(_url); -} - -void Account::clearCookieJar() -{ - _am->setCookieJar(new CookieJar); -} - -QNetworkAccessManager *Account::networkAccessManager() -{ - return _am; -} - -QNetworkReply *Account::headRequest(const QString &relPath) -{ - return headRequest(concatUrlPath(url(), relPath)); -} - -QNetworkReply *Account::headRequest(const QUrl &url) -{ - QNetworkRequest request(url); - return _am->head(request); -} - -QNetworkReply *Account::getRequest(const QString &relPath) -{ - return getRequest(concatUrlPath(url(), relPath)); -} - -QNetworkReply *Account::getRequest(const QUrl &url) -{ - QNetworkRequest request(url); - return _am->get(request); -} - -QNetworkReply *Account::davRequest(const QByteArray &verb, const QString &relPath, QNetworkRequest req, QIODevice *data) -{ - return davRequest(verb, concatUrlPath(davUrl(), relPath), req, data); -} - -QNetworkReply *Account::davRequest(const QByteArray &verb, const QUrl &url, QNetworkRequest req, QIODevice *data) -{ - req.setUrl(url); - return _am->sendCustomRequest(req, verb, data); -} - -void Account::setSslConfiguration(const QSslConfiguration &config) -{ - _sslConfiguration = config; -} - -void Account::setApprovedCerts(const QList<QSslCertificate> certs) -{ - _approvedCerts = certs; -} - -void Account::addApprovedCerts(const QList<QSslCertificate> certs) -{ - _approvedCerts += certs; -} - -void Account::setSslErrorHandler(AbstractSslErrorHandler *handler) -{ - _sslErrorHandler.reset(handler); -} - -void Account::setUrl(const QUrl &url) -{ - _url = url; -} - -QUrl Account::concatUrlPath(const QUrl &url, const QString &concatPath) -{ - QUrl tmpUrl = url; - QString path = tmpUrl.path(); - // avoid '//' - if (path.endsWith('/') && concatPath.startsWith('/')) { - path.chop(1); - } // avoid missing '/' - else if (!path.endsWith('/') && !concatPath.startsWith('/')) { - path += QLatin1Char('/'); - } - path += concatPath; - tmpUrl.setPath(path); - return tmpUrl; -} - -QString Account::_configFileName; - -QSettings *Account::settingsWithGroup(const QString& group, QObject *parent) -{ - if (_configFileName.isEmpty()) { - // cache file name - MirallConfigFile cfg; - _configFileName = cfg.configFile(); - } - QSettings *settings = new QSettings(_configFileName, QSettings::IniFormat, parent); - settings->beginGroup(group); - return settings; -} - -QVariant Account::credentialSetting(const QString &key) const -{ - if (_credentials) { - QString prefix = _credentials->authType(); - QString value = _settingsMap.value(prefix+"_"+key).toString(); - if (value.isEmpty()) { - value = _settingsMap.value(key).toString(); - } - return value; - } - return QVariant(); -} - -void Account::setCredentialSetting(const QString &key, const QVariant &value) -{ - if (_credentials) { - QString prefix = _credentials->authType(); - _settingsMap.insert(prefix+"_"+key, value); - } -} - -int Account::state() const -{ - return _state; -} - -void Account::setState(int state) -{ - if (_state != state) { - _state = state; - emit stateChanged(state); - } -} - -QuotaInfo *Account::quotaInfo() -{ - return _quotaInfo; -} - -void Account::slotHandleErrors(QNetworkReply *reply , QList<QSslError> errors) -{ - NetworkJobTimeoutPauser pauser(reply); - qDebug() << "SSL-Errors happened for url " << reply->url().toString(); - foreach(const QSslError &error, errors) { - qDebug() << "\tError in " << error.certificate() << ":" - << error.errorString() << "("<< error.error()<< ")"; - } - - if( _treatSslErrorsAsFailure ) { - // User decided once not to trust. Honor this decision. - qDebug() << "Certs not trusted by user decision, returning."; - return; - } - - QList<QSslCertificate> approvedCerts; - if (_sslErrorHandler.isNull() ) { - qDebug() << Q_FUNC_INFO << "called without valid SSL error handler for account" << url(); - } else { - if (_sslErrorHandler->handleErrors(errors, &approvedCerts, this)) { - QSslSocket::addDefaultCaCertificates(approvedCerts); - addApprovedCerts(approvedCerts); - // all ssl certs are known and accepted. We can ignore the problems right away. - qDebug() << "Certs are already known and trusted, Errors are not valid."; - reply->ignoreSslErrors(); - } else { - _treatSslErrorsAsFailure = true; - return; - } - } -} - -} // namespace Mirall diff --git a/src/mirall/account.h b/src/mirall/account.h deleted file mode 100644 index d782a7498..000000000 --- a/src/mirall/account.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 SERVERCONNECTION_H -#define SERVERCONNECTION_H - -#include <QByteArray> -#include <QUrl> -#include <QNetworkCookie> -#include <QNetworkRequest> -#include <QSslCertificate> -#include <QSslConfiguration> -#include <QSslError> -#include "utility.h" - -class QSettings; -class QNetworkReply; -class QUrl; -class QNetworkAccessManager; - -namespace Mirall { - -class AbstractCredentials; -class Account; -class QuotaInfo; -class MirallAccessManager; - -class OWNCLOUDSYNC_EXPORT AccountManager : public QObject { - Q_OBJECT -public: - static AccountManager *instance(); - ~AccountManager() {} - - void setAccount(Account *account); - Account *account() { return _account; } - -Q_SIGNALS: - void accountChanged(Account *newAccount, Account *oldAccount); - void accountAboutToChange(Account *newAccount, Account *oldAccount); - -private: - AccountManager() : _account(0) {} - Account *_account; - static AccountManager *_instance; -}; - -/* Reimplement this to handle SSL errors */ -class AbstractSslErrorHandler { -public: - virtual ~AbstractSslErrorHandler() {} - virtual bool handleErrors(QList<QSslError>, QList<QSslCertificate>*, Account*) = 0; -}; - -/** - * @brief This class represents an account on an ownCloud Server - */ -class OWNCLOUDSYNC_EXPORT Account : public QObject { - Q_OBJECT -public: - enum State { Disconnected = 0, /// no network connection - Connected, /// account is online - SignedOut, /// Disconnected + credential token has been discarded - InvalidCredidential /// The credidential are invalids and we are asking for them to the user - }; - - QString davPath() const { return _davPath; } - void setDavPath(const QString&s) { _davPath = s; } - - Account(AbstractSslErrorHandler *sslErrorHandler = 0, QObject *parent = 0); - ~Account(); - - /** - * Saves the account to a given settings file - */ - void save(); - - /** - * Creates an account object from from a given settings file. - */ - static Account* restore(); - - /** - * @brief Checks the Account instance is different from \param other - * - * @returns true, if credentials or url have changed, false otherwise - */ - bool changed(Account *other, bool ignoreUrlProtocol) const; - - /** Holds the accounts credentials */ - AbstractCredentials* credentials() const; - void setCredentials(AbstractCredentials *cred); - - /** Server url of the account */ - void setUrl(const QUrl &url); - QUrl url() const { return _url; } - - /** Returns webdav entry URL, based on url() */ - QUrl davUrl() const; - - QList<QNetworkCookie> lastAuthCookies() const; - - QNetworkReply* headRequest(const QString &relPath); - QNetworkReply* headRequest(const QUrl &url); - QNetworkReply* getRequest(const QString &relPath); - QNetworkReply* getRequest(const QUrl &url); - QNetworkReply* davRequest(const QByteArray &verb, const QString &relPath, QNetworkRequest req, QIODevice *data = 0); - QNetworkReply* davRequest(const QByteArray &verb, const QUrl &url, QNetworkRequest req, QIODevice *data = 0); - - /** The ssl configuration during the first connection */ - QSslConfiguration sslConfiguration() const { return _sslConfiguration; } - void setSslConfiguration(const QSslConfiguration &config); - /** The certificates of the account */ - QList<QSslCertificate> approvedCerts() const { return _approvedCerts; } - void setApprovedCerts(const QList<QSslCertificate> certs); - void addApprovedCerts(const QList<QSslCertificate> certs); - - // pluggable handler - void setSslErrorHandler(AbstractSslErrorHandler *handler); - - // static helper function - static QUrl concatUrlPath(const QUrl &url, const QString &concatPath); - - /** Returns a new settings pre-set in a specific group. The Settings will be created - with the given parent. If no parents is specified, the caller must destroy the settings */ - static QSettings* settingsWithGroup(const QString &group, QObject *parent = 0); - - // to be called by credentials only - QVariant credentialSetting(const QString& key) const; - void setCredentialSetting(const QString& key, const QVariant &value); - - int state() const; - void setState(int state); - - void clearCookieJar(); - - QNetworkAccessManager* networkAccessManager(); - - QuotaInfo *quotaInfo(); -signals: - void stateChanged(int state); - -protected Q_SLOTS: - void slotHandleErrors(QNetworkReply*,QList<QSslError>); - -private: - QMap<QString, QVariant> _settingsMap; - QUrl _url; - QList<QSslCertificate> _approvedCerts; - QSslConfiguration _sslConfiguration; - QScopedPointer<AbstractSslErrorHandler> _sslErrorHandler; - QuotaInfo *_quotaInfo; - QNetworkAccessManager *_am; - AbstractCredentials* _credentials; - bool _treatSslErrorsAsFailure; - int _state; - static QString _configFileName; - QString _davPath; // default "remote.php/webdav/"; -}; - -} - -Q_DECLARE_METATYPE(Mirall::Account*) - -#endif //SERVERCONNECTION_H diff --git a/src/mirall/accountsettings.cpp b/src/mirall/accountsettings.cpp deleted file mode 100644 index 6259d4493..000000000 --- a/src/mirall/accountsettings.cpp +++ /dev/null @@ -1,763 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 "accountsettings.h" -#include "ui_accountsettings.h" - -#include "mirall/theme.h" -#include "mirall/folderman.h" -#include "mirall/folderwizard.h" -#include "mirall/folderstatusmodel.h" -#include "mirall/utility.h" -#include "mirall/application.h" -#include "mirall/owncloudsetupwizard.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/ignorelisteditor.h" -#include "mirall/account.h" -#include "mirall/quotainfo.h" -#include "creds/abstractcredentials.h" - -#include <math.h> - -#include <QDebug> -#include <QDesktopServices> -#include <QListWidgetItem> -#include <QMessageBox> -#include <QAction> -#include <QKeySequence> -#include <QIcon> -#include <QVariant> - -#include "mirall/account.h" - -namespace Mirall { - -static const char progressBarStyleC[] = - "QProgressBar {" - "border: 1px solid grey;" - "border-radius: 5px;" - "text-align: center;" - "}" - "QProgressBar::chunk {" - "background-color: %1; width: 1px;" - "}"; - -AccountSettings::AccountSettings(QWidget *parent) : - QWidget(parent), - ui(new Ui::AccountSettings), - _wasDisabledBefore(false), - _account(AccountManager::instance()->account()) -{ - ui->setupUi(this); - - _model = new FolderStatusModel; - _model->setParent(this); - FolderStatusDelegate *delegate = new FolderStatusDelegate; - delegate->setParent(this); - - ui->_folderList->setItemDelegate( delegate ); - ui->_folderList->setModel( _model ); -#if defined(Q_OS_MAC) - ui->_folderList->setMinimumWidth( 400 ); -#else - ui->_folderList->setMinimumWidth( 300 ); -#endif - ui->_folderList->setEditTriggers( QAbstractItemView::NoEditTriggers ); - - ui->_buttonRemove->setEnabled(false); - ui->_buttonEnable->setEnabled(false); - ui->_buttonAdd->setEnabled(true); - - QAction *resetFolderAction = new QAction(this); - resetFolderAction->setShortcut(QKeySequence(Qt::Key_F5)); - connect(resetFolderAction, SIGNAL(triggered()), SLOT(slotResetCurrentFolder())); - addAction(resetFolderAction); - - QAction *syncNowAction = new QAction(this); - syncNowAction->setShortcut(QKeySequence(Qt::Key_F6)); - connect(syncNowAction, SIGNAL(triggered()), SLOT(slotSyncCurrentFolderNow())); - addAction(syncNowAction); - - connect(ui->_buttonRemove, SIGNAL(clicked()), this, SLOT(slotRemoveCurrentFolder())); - connect(ui->_buttonEnable, SIGNAL(clicked()), this, SLOT(slotEnableCurrentFolder())); - connect(ui->_buttonAdd, SIGNAL(clicked()), this, SLOT(slotAddFolder())); - connect(ui->modifyAccountButton, SIGNAL(clicked()), SLOT(slotOpenAccountWizard())); - connect(ui->ignoredFilesButton, SIGNAL(clicked()), SLOT(slotIgnoreFilesEditor()));; - - connect(ui->_folderList, SIGNAL(clicked(QModelIndex)), SLOT(slotFolderActivated(QModelIndex))); - connect(ui->_folderList, SIGNAL(doubleClicked(QModelIndex)),SLOT(slotDoubleClicked(QModelIndex))); - - QColor color = palette().highlight().color(); - ui->quotaProgressBar->setStyleSheet(QString::fromLatin1(progressBarStyleC).arg(color.name())); - ui->connectLabel->setWordWrap(true); - ui->connectLabel->setOpenExternalLinks(true); - ui->quotaLabel->setWordWrap(true); - - ui->connectLabel->setText(tr("No account configured.")); - ui->_buttonAdd->setEnabled(false); - - connect(AccountManager::instance(), SIGNAL(accountChanged(Account*,Account*)), - this, SLOT(slotAccountChanged(Account*,Account*))); - slotAccountChanged(AccountManager::instance()->account(), 0); - - connect(FolderMan::instance(), SIGNAL(folderListLoaded(Folder::Map)), - this, SLOT(setFolderList(Folder::Map))); - setFolderList(FolderMan::instance()->map()); -} - -void AccountSettings::slotAccountChanged(Account *newAccount, Account *oldAccount) -{ - if (oldAccount) { - disconnect(oldAccount, SIGNAL(stateChanged(int)), this, SLOT(slotAccountStateChanged(int))); - disconnect(oldAccount->quotaInfo(), SIGNAL(quotaUpdated(qint64,qint64)), - this, SLOT(slotUpdateQuota(qint64,qint64))); - } - - _account = newAccount; - if (_account) { - connect(_account, SIGNAL(stateChanged(int)), SLOT(slotAccountStateChanged(int))); - slotAccountStateChanged(_account->state()); - - QuotaInfo *quotaInfo = _account->quotaInfo(); - connect( quotaInfo, SIGNAL(quotaUpdated(qint64,qint64)), - this, SLOT(slotUpdateQuota(qint64,qint64))); - slotUpdateQuota(quotaInfo->lastQuotaTotalBytes(), quotaInfo->lastQuotaUsedBytes()); - } - -} - -void AccountSettings::slotFolderActivated( const QModelIndex& indx ) -{ - bool isValid = indx.isValid(); - - bool haveFolders = ui->_folderList->model()->rowCount() > 0; - - ui->_buttonRemove->setEnabled(isValid); - if( Theme::instance()->singleSyncFolder() ) { - // only one folder synced folder allowed. - ui->_buttonAdd->setVisible(!haveFolders); - } else { - ui->_buttonAdd->setVisible(true); - } - ui->_buttonAdd->setEnabled(_account && _account->state() == Account::Connected); - ui->_buttonEnable->setEnabled( isValid ); - - if ( isValid ) { - bool folderEnabled = _model->data( indx, FolderStatusDelegate::FolderSyncEnabled).toBool(); - if ( folderEnabled ) { - ui->_buttonEnable->setText( tr( "Pause" ) ); - } else { - ui->_buttonEnable->setText( tr( "Resume" ) ); - } - ui->_buttonEnable->setEnabled( _account && _account->state() == Account::Connected); - } -} - - - -void AccountSettings::slotAddFolder() -{ - FolderMan *folderMan = FolderMan::instance(); - folderMan->setSyncEnabled(false); // do not start more syncs. - - FolderWizard *folderWizard = new FolderWizard(this); - - connect(folderWizard, SIGNAL(accepted()), SLOT(slotFolderWizardAccepted())); - connect(folderWizard, SIGNAL(rejected()), SLOT(slotFolderWizardRejected())); - folderWizard->open(); -} - - -void AccountSettings::slotFolderWizardAccepted() -{ - FolderWizard *folderWizard = qobject_cast<FolderWizard*>(sender()); - FolderMan *folderMan = FolderMan::instance(); - - qDebug() << "* Folder wizard completed"; - - QString alias = folderWizard->field(QLatin1String("alias")).toString(); - QString sourceFolder = folderWizard->field(QLatin1String("sourceFolder")).toString(); - QString targetPath = folderWizard->property("targetPath").toString(); - - if (!FolderMan::ensureJournalGone( sourceFolder )) - return; - folderMan->addFolderDefinition(alias, sourceFolder, targetPath ); - Folder *f = folderMan->setupFolderFromConfigFile( alias ); - slotAddFolder( f ); - folderMan->setSyncEnabled(true); - if( f ) { - folderMan->slotScheduleAllFolders(); - emit folderChanged(); - } - slotButtonsSetEnabled(); -} - -void AccountSettings::slotFolderWizardRejected() -{ - qDebug() << "* Folder wizard cancelled"; - FolderMan *folderMan = FolderMan::instance(); - folderMan->setSyncEnabled(true); - folderMan->slotScheduleAllFolders(); -} - -void AccountSettings::slotOpenAccountWizard() -{ - this->topLevelWidget()->close(); - OwncloudSetupWizard::runWizard(qApp, SLOT(slotownCloudWizardDone(int)), 0); -} - -void AccountSettings::slotAddFolder( Folder *folder ) -{ - if( ! folder || folder->alias().isEmpty() ) return; - - QStandardItem *item = new QStandardItem(); - folderToModelItem( item, folder ); - _model->appendRow( item ); - // in order to update the enabled state of the "Sync now" button - connect(folder, SIGNAL(syncStateChange()), this, SLOT(slotFolderSyncStateChange()), Qt::UniqueConnection); -} - -void AccountSettings::slotButtonsSetEnabled() -{ - QModelIndex selected = ui->_folderList->currentIndex(); - - slotFolderActivated(selected); -} - -void AccountSettings::setGeneralErrors( const QStringList& errors ) -{ - _generalErrors = errors; - if (_account) { - // this will update the message - slotAccountStateChanged(_account->state()); - } -} - -void AccountSettings::folderToModelItem( QStandardItem *item, Folder *f ) -{ - if( ! item || !f ) return; - - item->setData( f->nativePath(), FolderStatusDelegate::FolderPathRole ); - item->setData( f->remotePath(), FolderStatusDelegate::FolderSecondPathRole ); - item->setData( f->alias(), FolderStatusDelegate::FolderAliasRole ); - item->setData( f->syncEnabled(), FolderStatusDelegate::FolderSyncEnabled ); - - SyncResult res = f->syncResult(); - SyncResult::Status status = res.status(); - - QStringList errorList = res.errorStrings(); - - Theme *theme = Theme::instance(); - item->setData( theme->statusHeaderText( status ), Qt::ToolTipRole ); - if( f->syncEnabled() ) { - if( status == SyncResult::SyncPrepare ) { - if( _wasDisabledBefore ) { - // if the folder was disabled before, set the sync icon - item->setData( theme->syncStateIcon( SyncResult::SyncRunning), FolderStatusDelegate::FolderStatusIconRole ); - } // we keep the previous icon for the SyncPrepare state. - } else if( status == SyncResult::Undefined ) { - // startup, the sync was never done. - qDebug() << "XXX FIRST time sync, setting icon to sync running!"; - item->setData( theme->syncStateIcon( SyncResult::SyncRunning), FolderStatusDelegate::FolderStatusIconRole ); - } else { - // kepp the previous icon for the prepare phase. - if( status == SyncResult::Problem) { - item->setData( theme->syncStateIcon( SyncResult::Success), FolderStatusDelegate::FolderStatusIconRole ); - } else { - item->setData( theme->syncStateIcon( status ), FolderStatusDelegate::FolderStatusIconRole ); - } - } - } else { - item->setData( theme->folderDisabledIcon( ), FolderStatusDelegate::FolderStatusIconRole ); // size 48 before - _wasDisabledBefore = false; - } - item->setData( theme->statusHeaderText( status ), FolderStatusDelegate::FolderStatus ); - - if( errorList.isEmpty() ) { - if( (status == SyncResult::Error || - status == SyncResult::SetupError || - status == SyncResult::SyncAbortRequested || - status == SyncResult::Unavailable)) { - errorList << theme->statusHeaderText(status); - } - } - - item->setData( errorList, FolderStatusDelegate::FolderErrorMsg); - - bool ongoing = false; - item->setData( QVariant(res.warnCount()), FolderStatusDelegate::WarningCount ); - if( status == SyncResult::SyncRunning ) { - ongoing = true; - } - item->setData( ongoing, FolderStatusDelegate::SyncRunning); - -} - -void AccountSettings::slotRemoveCurrentFolder() -{ - QModelIndex selected = ui->_folderList->selectionModel()->currentIndex(); - if( selected.isValid() ) { - int row = selected.row(); - - QString alias = _model->data( selected, FolderStatusDelegate::FolderAliasRole ).toString(); - qDebug() << "Remove Folder alias " << alias; - if( !alias.isEmpty() ) { - // remove from file system through folder man - // _model->removeRow( selected.row() ); - int ret = QMessageBox::question( this, tr("Confirm Folder Remove"), - tr("<p>Do you really want to stop syncing the folder <i>%1</i>?</p>" - "<p><b>Note:</b> This will not remove the files from your client.</p>").arg(alias), - QMessageBox::Yes|QMessageBox::No ); - - if( ret == QMessageBox::No ) { - return; - } - /* Remove the selected item from the timer hash. */ - QStandardItem *item = NULL; - if( selected.isValid() ) - item = _model->itemFromIndex(selected); - - if( selected.isValid() && item && _hideProgressTimers.contains(item) ) { - QTimer *t = _hideProgressTimers[item]; - t->stop(); - _hideProgressTimers.remove(item); - delete(t); - } - - FolderMan *folderMan = FolderMan::instance(); - folderMan->slotRemoveFolder( alias ); - _model->removeRow(row); - - // single folder fix to show add-button and hide remove-button - slotButtonsSetEnabled(); - - emit folderChanged(); - } - } -} - -void AccountSettings::slotResetCurrentFolder() -{ - QModelIndex selected = ui->_folderList->selectionModel()->currentIndex(); - if( selected.isValid() ) { - QString alias = _model->data( selected, FolderStatusDelegate::FolderAliasRole ).toString(); - int ret = QMessageBox::question( 0, tr("Confirm Folder Reset"), - tr("<p>Do you really want to reset folder <i>%1</i> and rebuild your client database?</p>" - "<p><b>Note:</b> This function is designed for maintenance purposes only. " - "No files will be removed, but this can cause significant data traffic and " - "take several minutes or hours to complete, depending on the size of the folder. " - "Only use this option if advised by your administrator.</p>").arg(alias), - QMessageBox::Yes|QMessageBox::No ); - if( ret == QMessageBox::Yes ) { - FolderMan *folderMan = FolderMan::instance(); - Folder *f = folderMan->folder(alias); - f->slotTerminateSync(); - f->wipe(); - folderMan->slotScheduleAllFolders(); - } - } -} - -void AccountSettings::slotDoubleClicked( const QModelIndex& indx ) -{ - if( ! indx.isValid() ) return; - QString alias = _model->data( indx, FolderStatusDelegate::FolderAliasRole ).toString(); - - emit openFolderAlias( alias ); -} - -void AccountSettings::showConnectionLabel( const QString& message, const QString& tooltip ) -{ - const QString errStyle = QLatin1String("color:#ffffff; background-color:#bb4d4d;padding:5px;" - "border-width: 1px; border-style: solid; border-color: #aaaaaa;" - "border-radius:5px;"); - if( _generalErrors.isEmpty() ) { - ui->connectLabel->setText( message ); - ui->connectLabel->setToolTip(tooltip); - ui->connectLabel->setStyleSheet(QString()); - } else { - const QString msg = _generalErrors.join(QLatin1String("\n")); - ui->connectLabel->setText( msg ); - ui->connectLabel->setToolTip(QString()); - ui->connectLabel->setStyleSheet(errStyle); - } -} - -void AccountSettings::setFolderList( const Folder::Map &folders ) -{ - _model->clear(); - - foreach(QTimer *t, _hideProgressTimers) { - t->stop(); - delete t; - } - _hideProgressTimers.clear(); - - foreach( Folder *f, folders ) { - slotAddFolder( f ); - } - - QModelIndex idx = _model->index(0, 0); - if (idx.isValid()) { - ui->_folderList->setCurrentIndex(idx); - } - slotButtonsSetEnabled(); - -} - -void AccountSettings::slotEnableCurrentFolder() -{ - QModelIndex selected = ui->_folderList->selectionModel()->currentIndex(); - - if( selected.isValid() ) { - QString alias = _model->data( selected, FolderStatusDelegate::FolderAliasRole ).toString(); - bool folderEnabled = _model->data( selected, FolderStatusDelegate::FolderSyncEnabled).toBool(); - qDebug() << "Toggle enabled/disabled Folder alias " << alias << " - current state: " << folderEnabled; - if( !alias.isEmpty() ) { - FolderMan *folderMan = FolderMan::instance(); - - qDebug() << "Application: enable folder with alias " << alias; - bool terminate = false; - - // this sets the folder status to disabled but does not interrupt it. - Folder *f = folderMan->folder( alias ); - if (!f) { - return; - } - - if( folderEnabled ) { - // check if a sync is still running and if so, ask if we should terminate. - if( f->isBusy() ) { // its still running -#if defined(Q_OS_MAC) - QWidget *parent = this; - Qt::WindowFlags flags = Qt::Sheet; -#else - QWidget *parent = 0; - Qt::WindowFlags flags = Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint; // default flags -#endif - QMessageBox msgbox(QMessageBox::Question, tr("Sync Running"), - tr("The syncing operation is running.<br/>Do you want to terminate it?"), - QMessageBox::Yes | QMessageBox::No, parent, flags); - msgbox.setDefaultButton(QMessageBox::Yes); - int reply = msgbox.exec(); - if ( reply == QMessageBox::Yes ) - terminate = true; - else - return; // do nothing - } - } - - // message box can return at any time while the thread keeps running, - // so better check again after the user has responded. - if ( f->isBusy() && terminate ) { - f->slotTerminateSync(); - } - - folderMan->slotEnableFolder( alias, !folderEnabled ); - - // keep state for the icon setting. - if( !folderEnabled ) _wasDisabledBefore = true; - - slotUpdateFolderState (f); - // set the button text accordingly. - slotFolderActivated( selected ); - } - } -} - -void AccountSettings::slotSyncCurrentFolderNow() -{ - QModelIndex selected = ui->_folderList->selectionModel()->currentIndex(); - if( !selected.isValid() ) - return; - QString alias = _model->data( selected, FolderStatusDelegate::FolderAliasRole ).toString(); - FolderMan *folderMan = FolderMan::instance(); - - folderMan->slotScheduleSync(alias); -} - -void AccountSettings::slotUpdateFolderState( Folder *folder ) -{ - QStandardItem *item = 0; - int row = 0; - - if( ! folder ) return; - - item = _model->item( row ); - - while( item ) { - if( item->data( FolderStatusDelegate::FolderAliasRole ) == folder->alias() ) { - // its the item to update! - break; - } - item = _model->item( ++row ); - } - - if( item ) { - folderToModelItem( item, folder ); - } else { - // the dialog is not visible. - } -} - -void AccountSettings::slotOpenOC() -{ - if( _OCUrl.isValid() ) - QDesktopServices::openUrl( _OCUrl ); -} - -QStandardItem* AccountSettings::itemForFolder(const QString& folder) -{ - QStandardItem *item = NULL; - - if( folder.isEmpty() ) { - return item; - } - - int row = 0; - - item = _model->item( row ); - - while( item ) { - if( item->data( FolderStatusDelegate::FolderAliasRole ) == folder ) { - // its the item to update! - break; - } - item = _model->item( ++row ); - } - return item; -} - -QString AccountSettings::shortenFilename( const QString& folder, const QString& file ) const -{ - // strip off the server prefix from the file name - QString shortFile(file); - if( shortFile.isEmpty() ) { - return QString::null; - } - - if(shortFile.startsWith(QLatin1String("ownclouds://")) || - shortFile.startsWith(QLatin1String("owncloud://")) ) { - // rip off the whole ownCloud URL. - Folder *f = FolderMan::instance()->folder(folder); - if( f ) { - QString remotePathUrl = f->remoteUrl().toString(); - shortFile.remove(Utility::toCSyncScheme(remotePathUrl)); - } - } - return shortFile; -} - -void AccountSettings::slotSetProgress(const QString& folder, const Progress::Info &progress ) -{ - QStandardItem *item = itemForFolder( folder ); - if( !item ) return; - - if(!progress._lastCompletedItem.isEmpty() - && Progress::isWarningKind(progress._lastCompletedItem._status)) { - int warnCount = item->data(FolderStatusDelegate::WarningCount).toInt(); - warnCount++; - item->setData( QVariant(warnCount), FolderStatusDelegate::WarningCount ); - } - - // find the single item to display: This is going to be the bigger item, or the last completed - // item if no items are in progress. - SyncFileItem curItem = progress._lastCompletedItem; - qint64 curItemProgress = -1; // -1 means finished - quint64 biggerItemSize = -1; - foreach(const Progress::Info::ProgressItem &citm, progress._currentItems) { - if (curItemProgress == -1 || (Progress::isSizeDependent(citm._item._instruction) - && biggerItemSize < citm._item._size)) { - curItemProgress = citm._completedSize; - curItem = citm._item; - biggerItemSize = citm._item._size; - } - } - if (curItemProgress == -1) { - curItemProgress = curItem._size; - } - - QString itemFileName = shortenFilename(folder, curItem._file); - QString kindString = Progress::asActionString(curItem); - - // switch on extra space. - item->setData( QVariant(true), FolderStatusDelegate::AddProgressSpace ); - - QString fileProgressString; - if (Progress::isSizeDependent(curItem._instruction)) { - QString s1 = Utility::octetsToString( curItemProgress ); - QString s2 = Utility::octetsToString( curItem._size ); - //: Example text: "uploading foobar.png (1MB of 2MB) time left 2 minutes at a rate of 24Kb/s" - fileProgressString = tr("%1 %2 (%3 of %4) %5 left at a rate of %6/s") - .arg(kindString, itemFileName, s1, s2, - Utility::timeToDescriptiveString(progress.getFileEstimate(curItem).getEtaEstimate(), 3, " ", true), - Utility::octetsToString(progress.getFileEstimate(curItem).getEstimatedBandwidth()) ); - } else { - //: Example text: "uploading foobar.png" - fileProgressString = tr("%1 %2").arg(kindString, itemFileName); - } - item->setData( fileProgressString,FolderStatusDelegate::SyncProgressItemString); - - // overall progress - quint64 completedSize = progress.completedSize(); - quint64 currentFile = progress._completedFileCount + progress._currentItems.count(); - QString s1 = Utility::octetsToString( completedSize ); - QString s2 = Utility::octetsToString( progress._totalSize ); - QString overallSyncString = tr("%1 of %2, file %3 of %4\nTotal time left %5") - .arg(s1, s2) - .arg(currentFile).arg(progress._totalFileCount) - .arg( Utility::timeToDescriptiveString(progress.totalEstimate().getEtaEstimate(), 3, " ", true) ); - - item->setData( overallSyncString, FolderStatusDelegate::SyncProgressOverallString ); - - int overallPercent = 0; - if( progress._totalFileCount > 0 ) { - // Add one 'byte' for each files so the percentage is moving when deleting or renaming files - overallPercent = qRound(double(completedSize + progress._completedFileCount)/double(progress._totalSize + progress._totalFileCount) * 100.0); - } - item->setData( overallPercent, FolderStatusDelegate::SyncProgressOverallPercent); -} - -void AccountSettings::slotHideProgress() -{ - QTimer *send_timer = qobject_cast<QTimer*>(this->sender()); - QHash<QStandardItem*, QTimer*>::const_iterator i = _hideProgressTimers.constBegin(); - while (i != _hideProgressTimers.constEnd()) { - if( i.value() == send_timer ) { - QStandardItem *item = i.key(); - - /* Check if this item is still existing */ - bool ok = false; - for( int r = 0; !ok && r < _model->rowCount(); r++) { - if( item == _model->item(r,0) ) { - ok = true; - } - } - - if( ok ) { - item->setData( false, FolderStatusDelegate::AddProgressSpace ); - item->setData( QString(), FolderStatusDelegate::SyncProgressOverallString ); - item->setData( QString(), FolderStatusDelegate::SyncProgressItemString ); - item->setData( 0, FolderStatusDelegate::SyncProgressOverallPercent ); - } - _hideProgressTimers.remove(item); - break; - } - ++i; - } - - send_timer->deleteLater(); -} - -void AccountSettings::slotFolderSyncStateChange() -{ - slotButtonsSetEnabled(); - Folder* folder = qobject_cast<Folder *>(sender()); - if (!folder) return; - - QStandardItem *item = itemForFolder( folder->alias() ); - if( !item ) return; - - SyncResult::Status state = folder->syncResult().status(); - if (state == SyncResult::SyncPrepare) { - item->setData( QVariant(0), FolderStatusDelegate::WarningCount ); - } else if (state == SyncResult::Success || state == SyncResult::Problem) { - // start a timer to stop the progress display - QTimer *timer; - if( _hideProgressTimers.contains(item) ) { - timer = _hideProgressTimers[item]; - // there is already one timer running. - } else { - timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(slotHideProgress())); - timer->setSingleShot(true); - _hideProgressTimers.insert(item, timer); - } - timer->start(5000); - } -} - - -void AccountSettings::slotUpdateQuota(qint64 total, qint64 used) -{ - if( total > 0 ) { - ui->quotaProgressBar->setVisible(true); - ui->quotaInfoLabel->setVisible(true); - ui->quotaProgressBar->setEnabled(true); - // workaround the label only accepting ints (which may be only 32 bit wide) - ui->quotaProgressBar->setMaximum(100); - int qVal = qRound(used/(double)total * 100); - if( qVal > 100 ) qVal = 100; - ui->quotaProgressBar->setValue(qVal); - QString usedStr = Utility::octetsToString(used); - QString totalStr = Utility::octetsToString(total); - double percent = used/(double)total*100; - QString percentStr = Utility::compactFormatDouble(percent, 1); - ui->quotaLabel->setText(tr("%1 (%3%) of %2 server space in use.").arg(usedStr, totalStr, percentStr)); - } else { - ui->quotaProgressBar->setVisible(false); - ui->quotaInfoLabel->setVisible(false); - ui->quotaLabel->setText(tr("Currently there is no storage usage information available.")); - } -} - -void AccountSettings::slotIgnoreFilesEditor() -{ - if (_ignoreEditor.isNull()) { - _ignoreEditor = new IgnoreListEditor(this); - _ignoreEditor->setAttribute( Qt::WA_DeleteOnClose, true ); - _ignoreEditor->open(); - } else { - ownCloudGui::raiseDialog(_ignoreEditor); - } -} - -void AccountSettings::slotAccountStateChanged(int state) -{ - if (_account) { - ui->sslButton->updateAccountInfo(_account); - QUrl safeUrl(_account->url()); - safeUrl.setPassword(QString()); // Remove the password from the URL to avoid showing it in the UI - slotButtonsSetEnabled(); - if (state == Account::Connected) { - QString user; - if (AbstractCredentials *cred = _account->credentials()) { - user = cred->user(); - } - if (user.isEmpty()) { - showConnectionLabel( tr("Connected to <a href=\"%1\">%2</a>.").arg(_account->url().toString(), safeUrl.toString()) - /*, tr("Version: %1 (%2)").arg(versionStr).arg(version) */ ); - } else { - showConnectionLabel( tr("Connected to <a href=\"%1\">%2</a> as <i>%3</i>.").arg(_account->url().toString(), safeUrl.toString(), user) - /*, tr("Version: %1 (%2)").arg(versionStr).arg(version) */ ); - } - } else { - showConnectionLabel( tr("No connection to %1 at <a href=\"%2\">%3</a>.") - .arg(Theme::instance()->appNameGUI(), - _account->url().toString(), - safeUrl.toString()) ); - } - } else { - // ownCloud is not yet configured. - showConnectionLabel( tr("No %1 connection configured.").arg(Theme::instance()->appNameGUI()) ); - ui->_buttonAdd->setEnabled( false); - } -} - -AccountSettings::~AccountSettings() -{ - delete ui; -} - -} // namespace Mirall diff --git a/src/mirall/accountsettings.h b/src/mirall/accountsettings.h deleted file mode 100644 index 4e64ea25e..000000000 --- a/src/mirall/accountsettings.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 ACCOUNTSETTINGS_H -#define ACCOUNTSETTINGS_H - -#include <QWidget> -#include <QUrl> -#include <QPointer> -#include <QHash> -#include <QTimer> -#include <QStandardItem> - -#include "mirall/folder.h" -#include "mirall/progressdispatcher.h" - -class QStandardItemModel; -class QModelIndex; -class QStandardItem; -class QNetworkReply; -class QListWidgetItem; - -namespace Mirall { - -namespace Ui { -class AccountSettings; -} - -class FolderMan; -class IgnoreListEditor; -class Account; - -class AccountSettings : public QWidget -{ - Q_OBJECT - -public: - explicit AccountSettings(QWidget *parent = 0); - ~AccountSettings(); - - -signals: - void folderChanged(); - void openProtocol(); - void openFolderAlias( const QString& ); - void infoFolderAlias( const QString& ); - -public slots: - void slotFolderActivated( const QModelIndex& ); - void slotOpenOC(); - void slotUpdateFolderState( Folder* ); - void slotDoubleClicked( const QModelIndex& ); - void slotSetProgress(const QString& folder, const Progress::Info& progress); - void slotButtonsSetEnabled(); - - void slotUpdateQuota( qint64,qint64 ); - void slotIgnoreFilesEditor(); - void slotAccountStateChanged(int state); - - void setGeneralErrors( const QStringList& errors ); - void setFolderList( const Folder::Map& ); - -protected slots: - void slotAddFolder(); - void slotAddFolder( Folder* ); - void slotEnableCurrentFolder(); - void slotSyncCurrentFolderNow(); - void slotRemoveCurrentFolder(); - void slotResetCurrentFolder(); - void slotFolderWizardAccepted(); - void slotFolderWizardRejected(); - void slotOpenAccountWizard(); - void slotHideProgress(); - -private: - QString shortenFilename( const QString& folder, const QString& file ) const; - void folderToModelItem( QStandardItem *, Folder * ); - QStandardItem* itemForFolder(const QString& ); - void showConnectionLabel( const QString& message, const QString& tooltip = QString() ); - - Ui::AccountSettings *ui; - QPointer<IgnoreListEditor> _ignoreEditor; - QStandardItemModel *_model; - QUrl _OCUrl; - QHash<QStandardItem*, QTimer*> _hideProgressTimers; - QStringList _generalErrors; - bool _wasDisabledBefore; - Account *_account; -private slots: - void slotFolderSyncStateChange(); - void slotAccountChanged(Account*,Account*); -}; - -} // namespace Mirall - -#endif // ACCOUNTSETTINGS_H diff --git a/src/mirall/accountsettings.ui b/src/mirall/accountsettings.ui deleted file mode 100644 index 133dfaab0..000000000 --- a/src/mirall/accountsettings.ui +++ /dev/null @@ -1,170 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>Mirall::AccountSettings</class> - <widget class="QWidget" name="Mirall::AccountSettings"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>615</width> - <height>422</height> - </rect> - </property> - <property name="windowTitle"> - <string>Form</string> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0" colspan="2"> - <widget class="QGroupBox" name="syncStatusGroupBox"> - <property name="title"> - <string>Account to Synchronize</string> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0" colspan="2"> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="SslButton" name="sslButton"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="connectLabel"> - <property name="text"> - <string>Connected with <server> as <user></string> - </property> - </widget> - </item> - </layout> - </item> - <item row="1" column="0"> - <widget class="QListView" name="_folderList"/> - </item> - <item row="1" column="1"> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <widget class="QPushButton" name="_buttonAdd"> - <property name="text"> - <string>Add Folder...</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="_buttonEnable"> - <property name="text"> - <string>Pause</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="_buttonRemove"> - <property name="text"> - <string>Remove</string> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer_3"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item row="1" column="0"> - <widget class="QGroupBox" name="storageGroupBox"> - <property name="title"> - <string>Storage Usage</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QProgressBar" name="quotaProgressBar"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="maximum"> - <number>0</number> - </property> - <property name="value"> - <number>-1</number> - </property> - <property name="textVisible"> - <bool>false</bool> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="quotaLabel"> - <property name="text"> - <string>Retrieving usage information...</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="quotaInfoLabel"> - <property name="text"> - <string><b>Note:</b> Some folders, including network mounted or shared folders, might have different limits.</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item row="1" column="1"> - <widget class="QGroupBox" name="maintenanceGroupBox"> - <property name="title"> - <string>Account Maintenance</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <item> - <widget class="QPushButton" name="ignoredFilesButton"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="text"> - <string>Edit Ignored Files</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="modifyAccountButton"> - <property name="text"> - <string>Modify Account</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>SslButton</class> - <extends>QToolButton</extends> - <header>sslbutton.h</header> - </customwidget> - </customwidgets> - <resources/> - <connections/> -</ui> diff --git a/src/mirall/application.cpp b/src/mirall/application.cpp deleted file mode 100644 index aac84b079..000000000 --- a/src/mirall/application.cpp +++ /dev/null @@ -1,560 +0,0 @@ -/* - * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> - * Copyright (C) by Klaas Freitag <freitag@owncloud.com> - * Copyright (C) by Daniel Molkentin <danimo@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. - */ - -#include <iostream> - -#include "config.h" - - -#include "mirall/account.h" -#include "mirall/application.h" -#include "mirall/connectionvalidator.h" -#include "mirall/folder.h" -#include "mirall/folderman.h" -#include "mirall/logger.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/socketapi.h" -#include "mirall/sslerrordialog.h" -#include "mirall/theme.h" -#include "mirall/utility.h" -#include "mirall/clientproxy.h" - -#include "updater/updater.h" -#include "creds/abstractcredentials.h" - -#include "config.h" - -#if defined(Q_OS_WIN) -#include <windows.h> -#endif - -#include <QTranslator> -#include <QMenu> -#include <QMessageBox> - -class QSocket; - -namespace Mirall { - -namespace { - -static const char optionsC[] = - "Options:\n" - " -h --help : show this help screen.\n" - " --logwindow : open a window to show log output.\n" - " --logfile <filename> : write log output to file <filename>.\n" - " --logdir <name> : write each sync log output in a new file\n" - " in directory <name>.\n" - " --logexpire <hours> : removes logs older than <hours> hours.\n" - " (to be used with --logdir)\n" - " --logflush : flush the log file after every write.\n" - " --confdir <dirname> : Use the given configuration directory.\n" - ; - -QString applicationTrPath() -{ -#if defined(Q_OS_WIN) - return QApplication::applicationDirPath(); -#elif defined(Q_OS_MAC) - return QApplication::applicationDirPath()+QLatin1String("/../Resources/Translations"); // path defaults to app dir. -#elif defined(Q_OS_UNIX) - return QString::fromLatin1(DATADIR "/" APPLICATION_EXECUTABLE "/i18n/"); -#endif -} -} - -// ---------------------------------------------------------------------------------- - -Application::Application(int &argc, char **argv) : - SharedTools::QtSingleApplication(Theme::instance()->appName() ,argc, argv), - _gui(0), - _theme(Theme::instance()), - _helpOnly(false), - _startupNetworkError(false), - _showLogWindow(false), - _logExpire(0), - _logFlush(false), - _userTriggeredConnect(false) -{ -// TODO: Can't set this without breaking current config pathes -// setOrganizationName(QLatin1String(APPLICATION_VENDOR)); - setOrganizationDomain(QLatin1String(APPLICATION_REV_DOMAIN)); - setApplicationName( _theme->appNameGUI() ); - setWindowIcon( _theme->applicationIcon() ); - - parseOptions(arguments()); - //no need to waste time; - if ( _helpOnly ) return; - - if (isRunning()) - return; - - setupLogging(); - setupTranslations(); - - connect( this, SIGNAL(messageReceived(QString, QObject*)), SLOT(slotParseOptions(QString, QObject*))); - - Account *account = Account::restore(); - if (account) { - account->setSslErrorHandler(new SslDialogErrorHandler); - AccountManager::instance()->setAccount(account); - } - - FolderMan::instance()->setSyncEnabled(false); - - setQuitOnLastWindowClosed(false); - - qRegisterMetaType<Progress::Info>("Progress::Info"); - - MirallConfigFile cfg; - _theme->setSystrayUseMonoIcons(cfg.monoIcons()); - connect (_theme, SIGNAL(systrayUseMonoIconsChanged(bool)), SLOT(slotUseMonoIconsChanged(bool))); - - FolderMan::instance()->setupFolders(); - _proxy.setupQtProxyFromConfig(); // folders have to be defined first, than we set up the Qt proxy. - - _gui = new ownCloudGui(this); - if( _showLogWindow ) { - _gui->slotToggleLogBrowser(); // _showLogWindow is set in parseOptions. - } - - if (account) { - slotAccountChanged(account); - } - connect(AccountManager::instance(), SIGNAL(accountChanged(Account*,Account*)), - this, SLOT(slotAccountChanged(Account*,Account*))); - - // startup procedure. - connect(&_checkConnectionTimer, SIGNAL(timeout()), this, SLOT(slotCheckConnection())); - _checkConnectionTimer.setInterval(32 * 1000); // check for connection every 32 seconds. - _checkConnectionTimer.start(); - // Also check immediatly - QTimer::singleShot( 0, this, SLOT( slotCheckConnection() )); - - if( cfg.skipUpdateCheck() ) { - qDebug() << Q_FUNC_INFO << "Skipping update check"; - } else { - QTimer::singleShot( 3000, this, SLOT( slotStartUpdateDetector() )); - } - - connect (this, SIGNAL(aboutToQuit()), SLOT(slotCleanup())); - - _socketApi = new SocketApi(this, QUrl::fromLocalFile(cfg.configPathWithAppName().append(QLatin1String("socket")))); - -} - -Application::~Application() -{ - delete AccountManager::instance()->account(); - // qDebug() << "* Mirall shutdown"; -} - -void Application::slotLogin() -{ - Account *a = AccountManager::instance()->account(); - if (a) { - FolderMan::instance()->setupFolders(); - _userTriggeredConnect = true; - slotCheckConnection(); - } -} - -void Application::slotLogout() -{ - Account *a = AccountManager::instance()->account(); - if (a) { - // invalidate & forget token/password - a->credentials()->invalidateToken(a); - // terminate all syncs and unload folders - FolderMan *folderMan = FolderMan::instance(); - folderMan->setSyncEnabled(false); - folderMan->terminateSyncProcess(); - folderMan->unloadAllFolders(); - a->setState(Account::SignedOut); - // show result - _gui->slotComputeOverallSyncStatus(); - } -} - -void Application::slotAccountChanged(Account *newAccount, Account *oldAccount) -{ - if (oldAccount) { - disconnect(oldAccount, SIGNAL(stateChanged(int)), _gui, SLOT(slotAccountStateChanged())); - disconnect(oldAccount, SIGNAL(stateChanged(int)), this, SLOT(slotToggleFolderman(int))); - connect(oldAccount->quotaInfo(), SIGNAL(quotaUpdated(qint64,qint64)), - _gui, SLOT(slotRefreshQuotaDisplay(qint64,qint64))); - } - connect(newAccount, SIGNAL(stateChanged(int)), _gui, SLOT(slotAccountStateChanged())); - connect(newAccount, SIGNAL(stateChanged(int)), this, SLOT(slotToggleFolderman(int))); - connect(newAccount->quotaInfo(), SIGNAL(quotaUpdated(qint64,qint64)), - _gui, SLOT(slotRefreshQuotaDisplay(qint64,qint64))); -} - - -void Application::slotCleanup() -{ - // explicitly close windows. This is somewhat of a hack to ensure - // that saving the geometries happens ASAP during a OS shutdown - Account *account = AccountManager::instance()->account(); - if (account) { - account->save(); - } - _gui->slotShutdown(); - _gui->deleteLater(); -} - -void Application::slotStartUpdateDetector() -{ - Updater *updater = Updater::instance(); - updater->backgroundCheckForUpdate(); -} - -void Application::slotCheckConnection() -{ - Account *account = AccountManager::instance()->account(); - - if( account ) { - if (account->state() == Account::InvalidCredidential - || account->state() == Account::SignedOut) { - //Do not try to connect if we are logged out - if (!_userTriggeredConnect) { - return; - } - } - - if (_conValidator) - _conValidator->deleteLater(); - _conValidator = new ConnectionValidator(account); - connect( _conValidator, SIGNAL(connectionResult(ConnectionValidator::Status)), - this, SLOT(slotConnectionValidatorResult(ConnectionValidator::Status)) ); - _conValidator->checkConnection(); - - } else { - // let gui open the setup wizard - _gui->slotOpenSettingsDialog( true ); - - _checkConnectionTimer.stop(); // don't popup the wizard on interval; - } -} - -void Application::slotCredentialsFetched() -{ - Account *account = AccountManager::instance()->account(); - Q_ASSERT(account); - disconnect(account->credentials(), SIGNAL(fetched()), this, SLOT(slotCredentialsFetched())); - if (!account->credentials()->ready()) { - // User canceled the connection or did not give a password - account->setState(Account::SignedOut); - return; - } - if (account->state() == Account::InvalidCredidential) { - // Then we ask again for the credidentials if they are wrong again - account->setState(Account::Disconnected); - } - slotCheckConnection(); -} - -void Application::slotToggleFolderman(int state) -{ - FolderMan* folderMan = FolderMan::instance(); - switch (state) { - case Account::Connected: - folderMan->setSyncEnabled(true); - folderMan->slotScheduleAllFolders(); - break; - case Account::Disconnected: - _checkConnectionTimer.start(); - // fall through - case Account::SignedOut: - case Account::InvalidCredidential: - folderMan->setSyncEnabled(false); - folderMan->terminateSyncProcess(); - break; - } - -} - -void Application::slotConnectionValidatorResult(ConnectionValidator::Status status) -{ - qDebug() << "Connection Validator Result: " << _conValidator->statusString(status); - QStringList startupFails; - - if( status == ConnectionValidator::Connected ) { - FolderMan *folderMan = FolderMan::instance(); - qDebug() << "######## Connection and Credentials are ok!"; - folderMan->setSyncEnabled(true); - // queue up the sync for all folders. - folderMan->slotScheduleAllFolders(); - _checkConnectionTimer.stop(); - } else { - // if we have problems here, it's unlikely that syncing will work. - FolderMan::instance()->setSyncEnabled(false); - - startupFails = _conValidator->errors(); - _startupNetworkError = _conValidator->networkError(); - if (_userTriggeredConnect) { - _userTriggeredConnect = false; - } - } - _gui->startupConnected( (status == ConnectionValidator::Connected), startupFails); - - _conValidator->deleteLater(); -} - -void Application::slotownCloudWizardDone( int res ) -{ - FolderMan *folderMan = FolderMan::instance(); - if( res == QDialog::Accepted ) { - int cnt = folderMan->setupFolders(); - qDebug() << "Set up " << cnt << " folders."; - // We have some sort of configuration. Enable autostart - Utility::setLaunchOnStartup(_theme->appName(), _theme->appNameGUI(), true); - } - folderMan->setSyncEnabled( true ); - if( res == QDialog::Accepted ) { - _checkConnectionTimer.start(); - slotCheckConnection(); - } - -} - -void Application::setupLogging() -{ - // might be called from second instance - Logger::instance()->setLogFile(_logFile); - Logger::instance()->setLogDir(_logDir); - Logger::instance()->setLogExpire(_logExpire); - Logger::instance()->setLogFlush(_logFlush); - - Logger::instance()->enterNextLogFile(); - - qDebug() << QString::fromLatin1( "################## %1 %2 (%3) %4").arg(_theme->appName()) - .arg( QLocale::system().name() ) - .arg(property("ui_lang").toString()) - .arg(_theme->version()); - -} - -void Application::slotUseMonoIconsChanged(bool) -{ - _gui->slotComputeOverallSyncStatus(); -} - -void Application::slotParseOptions(const QString &opts, QObject*) -{ - QStringList options = opts.split(QLatin1Char('|')); - parseOptions(options); - setupLogging(); -} - -void Application::parseOptions(const QStringList &options) -{ - QStringListIterator it(options); - // skip file name; - if (it.hasNext()) it.next(); - - //parse options; if help or bad option exit - while (it.hasNext()) { - QString option = it.next(); - if (option == QLatin1String("--help") || option == QLatin1String("-h")) { - setHelp(); - break; - } else if (option == QLatin1String("--logwindow") || - option == QLatin1String("-l")) { - _showLogWindow = true; - } else if (option == QLatin1String("--logfile")) { - if (it.hasNext() && !it.peekNext().startsWith(QLatin1String("--"))) { - _logFile = it.next(); - } else { - setHelp(); - } - } else if (option == QLatin1String("--logdir")) { - if (it.hasNext() && !it.peekNext().startsWith(QLatin1String("--"))) { - _logDir = it.next(); - } else { - setHelp(); - } - } else if (option == QLatin1String("--logexpire")) { - if (it.hasNext() && !it.peekNext().startsWith(QLatin1String("--"))) { - _logExpire = it.next().toInt(); - } else { - setHelp(); - } - } else if (option == QLatin1String("--logflush")) { - _logFlush = true; - } else if (option == QLatin1String("--confdir")) { - if (it.hasNext() && !it.peekNext().startsWith(QLatin1String("--"))) { - QString confDir = it.next(); - MirallConfigFile::setConfDir( confDir ); - } else { - showHelp(); - } - } else { - setHelp(); - break; - } - } -} - -// Helpers for displaying messages. Note that there is no console on Windows. -#ifdef Q_OS_WIN -// Format as <pre> HTML -static inline void toHtml(QString &t) -{ - t.replace(QLatin1Char('&'), QLatin1String("&")); - t.replace(QLatin1Char('<'), QLatin1String("<")); - t.replace(QLatin1Char('>'), QLatin1String(">")); - t.insert(0, QLatin1String("<html><pre>")); - t.append(QLatin1String("</pre></html>")); -} - -static void displayHelpText(QString t) // No console on Windows. -{ - toHtml(t); - QMessageBox::information(0, Theme::instance()->appNameGUI(), t); -} - -#else - -static void displayHelpText(const QString &t) -{ - std::cout << qPrintable(t); -} -#endif - -void Application::showHelp() -{ - setHelp(); - QString helpText; - QTextStream stream(&helpText); - stream << _theme->appName().toLatin1().constData() - << QLatin1String(" version ") - << _theme->version().toLatin1().constData() << endl; - - stream << QLatin1String("File synchronisation desktop utility.") << endl << endl - << QLatin1String(optionsC); - - if (_theme->appName() == QLatin1String("ownCloud")) - stream << endl << "For more information, see http://www.owncloud.org" << endl << endl; - - displayHelpText(helpText); -} - -void Application::setHelp() -{ - _helpOnly = true; -} - -#if defined(Q_OS_WIN) && QT_VERSION < QT_VERSION_CHECK(5,0,0) -bool Application::winEventFilter(MSG *pMsg, long *result) -{ - if (pMsg->message == WM_POWERBROADCAST) { - switch(pMsg->wParam) { - case PBT_APMPOWERSTATUSCHANGE: - qDebug() << "WM_POWERBROADCAST: Power state changed"; - break; - case PBT_APMSUSPEND: - qDebug() << "WM_POWERBROADCAST: Entering low power state"; - break; - case PBT_APMRESUMEAUTOMATIC: - qDebug() << "WM_POWERBROADCAST: Resuming from low power state"; - break; - default: - break; - } - return true; - } - - return SharedTools::QtSingleApplication::winEventFilter(pMsg, result); -} -#endif - -QString substLang(const QString &lang) -{ - // Map the more apropriate script codes - // to country codes as used by Qt and - // transifex translation conventions. - - // Simplified Chinese - if (lang == QLatin1String("zh_Hans")) - return QLatin1String("zh_CN"); - // Traditional Chinese - if (lang == QLatin1String("zh_Hant")) - return QLatin1String("zh_TW"); - return lang; -} - -void Application::setupTranslations() -{ - QStringList uiLanguages; - // uiLanguages crashes on Windows with 4.8.0 release builds - #if (QT_VERSION >= 0x040801) || (QT_VERSION >= 0x040800 && !defined(Q_OS_WIN)) - uiLanguages = QLocale::system().uiLanguages(); - #else - // older versions need to fall back to the systems locale - uiLanguages << QLocale::system().name(); - #endif - - QString enforcedLocale = Theme::instance()->enforcedLocale(); - if (!enforcedLocale.isEmpty()) - uiLanguages.prepend(enforcedLocale); - - QTranslator *translator = new QTranslator(this); - QTranslator *qtTranslator = new QTranslator(this); - QTranslator *qtkeychainTranslator = new QTranslator(this); - - foreach(QString lang, uiLanguages) { - lang.replace(QLatin1Char('-'), QLatin1Char('_')); // work around QTBUG-25973 - lang = substLang(lang); - const QString trPath = applicationTrPath(); - const QString trFile = QLatin1String("mirall_") + lang; - if (translator->load(trFile, trPath) || - lang.startsWith(QLatin1String("en"))) { - // Permissive approach: Qt and keychain translations - // may be missing, but Qt translations must be there in order - // for us to accept the language. Otherwise, we try with the next. - // "en" is an exeption as it is the default language and may not - // have a translation file provided. - qDebug() << Q_FUNC_INFO << "Using" << lang << "translation"; - setProperty("ui_lang", lang); - const QString qtTrPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath); - const QString qtTrFile = QLatin1String("qt_") + lang; - if (qtTranslator->load(qtTrFile, qtTrPath)) { - qtTranslator->load(qtTrFile, trPath); - } - const QString qtkeychainFile = QLatin1String("qt_") + lang; - if (!qtkeychainTranslator->load(qtkeychainFile, qtTrPath)) { - qtkeychainTranslator->load(qtkeychainFile, trPath); - } - if (!translator->isEmpty()) - installTranslator(translator); - if (!qtTranslator->isEmpty()) - installTranslator(qtTranslator); - if (!qtkeychainTranslator->isEmpty()) - installTranslator(qtkeychainTranslator); - break; - } - if (property("ui_lang").isNull()) - setProperty("ui_lang", "C"); - } -} - -bool Application::giveHelp() -{ - return _helpOnly; -} -} // namespace Mirall - diff --git a/src/mirall/application.h b/src/mirall/application.h deleted file mode 100644 index 36d3baa5c..000000000 --- a/src/mirall/application.h +++ /dev/null @@ -1,118 +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 APPLICATION_H -#define APPLICATION_H - -#include <QApplication> -#include <QPointer> -#include <QQueue> -#include <QTimer> - -#include "qtsingleapplication.h" - -#include "mirall/syncresult.h" -#include "mirall/logbrowser.h" -#include "mirall/owncloudgui.h" -#include "mirall/connectionvalidator.h" -#include "mirall/progressdispatcher.h" -#include "mirall/clientproxy.h" -#include "mirall/folderman.h" - -class QMessageBox; -class QSystemTrayIcon; -class QSocket; - -namespace Mirall { -class Theme; -class Folder; -class SslErrorDialog; -class SocketApi; - -class Application : public SharedTools::QtSingleApplication -{ - Q_OBJECT -public: - explicit Application(int &argc, char **argv); - ~Application(); - - bool giveHelp(); - void showHelp(); - -public slots: - // TODO: this should not be public - void slotownCloudWizardDone(int); - -protected: - void parseOptions(const QStringList& ); - void setupTranslations(); - void setupLogging(); - void enterNextLogFile(); - bool checkConfigExists(bool openSettings); - - // reimplemented -#if defined(Q_OS_WIN) && QT_VERSION < QT_VERSION_CHECK(5,0,0) - bool winEventFilter( MSG * message, long * result ); -#endif - -signals: - void folderRemoved(); - void folderStateChanged(Folder*); - -protected slots: - void slotParseOptions( const QString&, QObject* ); - void slotCheckConnection(); - void slotConnectionValidatorResult(ConnectionValidator::Status); - void slotStartUpdateDetector(); - void slotUseMonoIconsChanged( bool ); - void slotLogin(); - void slotLogout(); - void slotCleanup(); - void slotAccountChanged(Account *newAccount, Account *oldAccount = 0); - void slotCredentialsFetched(); - void slotToggleFolderman(int state); - -private: - void setHelp(); - - QPointer<ownCloudGui> _gui; - QPointer<SocketApi> _socketApi; - - QPointer<ConnectionValidator> _conValidator; - - Theme *_theme; - - bool _helpOnly; - bool _startupNetworkError; - - // options from command line: - bool _showLogWindow; - QString _logFile; - QString _logDir; - int _logExpire; - bool _logFlush; - bool _userTriggeredConnect; - - ClientProxy _proxy; - - QTimer _checkConnectionTimer; - - FolderMan folderManager; - - friend class ownCloudGui; // for _startupNetworkError -}; - -} // namespace Mirall - -#endif // APPLICATION_H diff --git a/src/mirall/clientproxy.cpp b/src/mirall/clientproxy.cpp deleted file mode 100644 index 4b03b8b7f..000000000 --- a/src/mirall/clientproxy.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 "clientproxy.h" - -#include "mirall/mirallconfigfile.h" -#include "mirall/folderman.h" -#include <QUrl> - -namespace Mirall { - -ClientProxy::ClientProxy(QObject *parent) : - QObject(parent) -{ -} - -QNetworkProxy ClientProxy::proxyFromConfig(const MirallConfigFile& cfg) -{ - QNetworkProxy proxy; - - if (cfg.proxyHostName().isEmpty()) - return QNetworkProxy(); - - proxy.setHostName(cfg.proxyHostName()); - proxy.setPort(cfg.proxyPort()); - if (cfg.proxyNeedsAuth()) { - proxy.setUser(cfg.proxyUser()); - proxy.setPassword(cfg.proxyPassword()); - } - return proxy; -} - -void ClientProxy::setupQtProxyFromConfig() -{ - Mirall::MirallConfigFile cfg; - int proxyType = QNetworkProxy::DefaultProxy; - QNetworkProxy proxy; - - // if there is no config file, default to system proxy. - if( cfg.exists() ) { - proxyType = cfg.proxyType(); - proxy = proxyFromConfig(cfg); - } - - switch(proxyType) { - case QNetworkProxy::NoProxy: - QNetworkProxyFactory::setUseSystemConfiguration(false); - QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy); - break; - case QNetworkProxy::DefaultProxy: - QNetworkProxyFactory::setUseSystemConfiguration(true); - break; - case QNetworkProxy::Socks5Proxy: - proxy.setType(QNetworkProxy::Socks5Proxy); - QNetworkProxyFactory::setUseSystemConfiguration(false); - QNetworkProxy::setApplicationProxy(proxy); - break; - case QNetworkProxy::HttpProxy: - proxy.setType(QNetworkProxy::HttpProxy); - QNetworkProxyFactory::setUseSystemConfiguration(false); - QNetworkProxy::setApplicationProxy(proxy); - break; - default: - break; - } -} - -const char* ClientProxy::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 ClientProxy::setCSyncProxy( const QUrl& url, CSYNC *csync_ctx ) -{ - /* Store proxy */ - QList<QNetworkProxy> proxies = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(url)); - // 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" << url.toString(); - } else { - qDebug() << "Passing" << proxy.hostName() << "of proxy type " << proxy.type() - << " to csync for" << url.toString(); - } - - csync_set_module_property( csync_ctx, "proxy_type", (void*)(proxyTypeToCStr(proxy.type()))); - csync_set_module_property( csync_ctx, "proxy_host", proxy.hostName().toUtf8().data()); - int proxy_port = proxy.port(); - csync_set_module_property( csync_ctx, "proxy_port", &proxy_port ); - csync_set_module_property( csync_ctx, "proxy_user", proxy.user().toUtf8().data()); - csync_set_module_property( csync_ctx, "proxy_pwd", proxy.password().toUtf8().data()); - -} - -} diff --git a/src/mirall/clientproxy.h b/src/mirall/clientproxy.h deleted file mode 100644 index 4fe372938..000000000 --- a/src/mirall/clientproxy.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 CLIENTPROXY_H -#define CLIENTPROXY_H - -#include <QObject> -#include <QNetworkProxy> - -#include <csync.h> -#include "utility.h" - -namespace Mirall { - -class MirallConfigFile; - -class OWNCLOUDSYNC_EXPORT ClientProxy : public QObject -{ - Q_OBJECT -public: - explicit ClientProxy(QObject *parent = 0); - -signals: - -public slots: - void setCSyncProxy( const QUrl& url, CSYNC *csync_ctx ); - void setupQtProxyFromConfig(); - -private: - QNetworkProxy proxyFromConfig(const MirallConfigFile& cfg); - const char* proxyTypeToCStr(QNetworkProxy::ProxyType type); -}; - -} - -#endif // CLIENTPROXY_H diff --git a/src/mirall/cocoainitializer.h b/src/mirall/cocoainitializer.h deleted file mode 100644 index fd4200a98..000000000 --- a/src/mirall/cocoainitializer.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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. - */ - -namespace Mirall { -namespace Mac { - -/** CocoaInitializer provides an AutoRelease Pool via RIIA for use in main() */ -class CocoaInitializer { -public: - CocoaInitializer(); - ~CocoaInitializer(); -private: - class Private; - Private *d; -}; - -} // namespace Mac -} // namespace Mirall diff --git a/src/mirall/cocoainitializer_mac.mm b/src/mirall/cocoainitializer_mac.mm deleted file mode 100644 index b65804bda..000000000 --- a/src/mirall/cocoainitializer_mac.mm +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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/cocoainitializer.h" - -#import <Foundation/NSAutoreleasePool.h> -#import <AppKit/NSApplication.h> - -namespace Mirall { -namespace Mac { - -class CocoaInitializer::Private { - public: - NSAutoreleasePool* autoReleasePool; -}; - -CocoaInitializer::CocoaInitializer() { - d = new CocoaInitializer::Private(); - NSApplicationLoad(); - d->autoReleasePool = [[NSAutoreleasePool alloc] init]; -} - -CocoaInitializer::~CocoaInitializer() { - [d->autoReleasePool release]; - delete d; -} - -} // namespace Mac -} // namespace Mirall diff --git a/src/mirall/connectionvalidator.cpp b/src/mirall/connectionvalidator.cpp deleted file mode 100644 index 24954f548..000000000 --- a/src/mirall/connectionvalidator.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 <QtCore> -#include <QNetworkReply> - -#include "mirall/connectionvalidator.h" -#include "mirall/theme.h" -#include "mirall/account.h" -#include "mirall/networkjobs.h" -#include <creds/abstractcredentials.h> - -namespace Mirall { - -ConnectionValidator::ConnectionValidator(Account *account, QObject *parent) - : QObject(parent), - _account(account), - _networkError(QNetworkReply::NoError) -{ -} - -QStringList ConnectionValidator::errors() const -{ - return _errors; -} - -bool ConnectionValidator::networkError() const -{ - return _networkError; -} - -QString ConnectionValidator::statusString( Status stat ) const -{ - QString re; - - switch( stat ) { - case Undefined: - re = QLatin1String("Undefined"); - break; - case Connected: - re = QLatin1String("Connected"); - break; - case NotConfigured: - re = QLatin1String("NotConfigured"); - break; - case ServerVersionMismatch: - re = QLatin1String("Server Version Mismatch"); - break; - case CredentialsTooManyAttempts: - re = QLatin1String("Credentials Too Many Attempts"); - break; - case CredentialError: - re = QLatin1String("CredentialError"); - break; - case CredentialsUserCanceled: - re = QLatin1String("Credential User Canceled"); - break; - case CredentialsWrong: - re = QLatin1String("Credentials Wrong"); - break; - case StatusNotFound: - re = QLatin1String("Status not found"); - break; - default: - re = QLatin1String("status undeclared."); - } - return re; -} - - -void ConnectionValidator::checkConnection() -{ - if( _account ) { - CheckServerJob *checkJob = new CheckServerJob(_account, false, this); - checkJob->setIgnoreCredentialFailure(true); - connect(checkJob, SIGNAL(instanceFound(QUrl,QVariantMap)), SLOT(slotStatusFound(QUrl,QVariantMap))); - connect(checkJob, SIGNAL(networkError(QNetworkReply*)), SLOT(slotNoStatusFound(QNetworkReply*))); - checkJob->start(); - } else { - _errors << tr("No ownCloud account configured"); - emit connectionResult( NotConfigured ); - } -} - -void ConnectionValidator::slotStatusFound(const QUrl&url, const QVariantMap &info) -{ - // status.php was found. - qDebug() << "** Application: ownCloud found: " - << url << " with version " - << CheckServerJob::versionString(info) - << "(" << CheckServerJob::version(info) << ")"; - // now check the authentication - - if( CheckServerJob::version(info).startsWith("4.0") ) { - _errors.append( tr("The configured server for this client is too old") ); - _errors.append( tr("Please update to the latest server and restart the client.") ); - emit connectionResult( ServerVersionMismatch ); - return; - } - - AbstractCredentials *creds = _account->credentials(); - if (creds->ready()) { - QTimer::singleShot( 0, this, SLOT( slotCheckAuthentication() )); - } else { - connect( creds, SIGNAL(fetched()), - this, SLOT(slotCheckAuthentication()), Qt::UniqueConnection); - creds->fetch(_account); - } -} - -// status.php could not be loaded. -void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply) -{ - _account->setState(Account::Disconnected); - - _errors.append(tr("Unable to connect to %1").arg(_account->url().toString())); - _errors.append( reply->errorString() ); - _networkError = (reply->error() != QNetworkReply::NoError); - emit connectionResult( StatusNotFound ); - -} - -void ConnectionValidator::slotCheckAuthentication() -{ - AbstractCredentials *creds = _account->credentials(); - disconnect( creds, SIGNAL(fetched()), - this, SLOT(slotCheckAuthentication())); - // simply GET the webdav root, will fail if credentials are wrong. - // continue in slotAuthCheck here :-) - PropfindJob *job = new PropfindJob(_account, "/", this); - job->setProperties(QList<QByteArray>() << "getlastmodified"); - connect(job, SIGNAL(result(QVariantMap)), SLOT(slotAuthSuccess())); - connect(job, SIGNAL(networkError(QNetworkReply*)), SLOT(slotAuthFailed(QNetworkReply*))); - job->start(); - qDebug() << "# checking for authentication settings."; -} - -void ConnectionValidator::slotAuthFailed(QNetworkReply *reply) -{ - Status stat = StatusNotFound; - - if( reply->error() == QNetworkReply::AuthenticationRequiredError || - reply->error() == QNetworkReply::OperationCanceledError ) { // returned if the user/pwd is wrong. - qDebug() << reply->error() << reply->errorString(); - qDebug() << "******** Password is wrong!"; - _errors << tr("The provided credentials are not correct"); - stat = CredentialsWrong; - switch (_account->state()) { - case Account::SignedOut: - _account->setState(Account::SignedOut); - break; - default: - _account->setState(Account::Disconnected); - } - - } else if( reply->error() != QNetworkReply::NoError ) { - _errors << reply->errorString(); - } - - emit connectionResult( stat ); -} - -void ConnectionValidator::slotAuthSuccess() -{ - _account->setState(Account::Connected); - emit connectionResult(Connected); -} - -} // namespace Mirall diff --git a/src/mirall/connectionvalidator.h b/src/mirall/connectionvalidator.h deleted file mode 100644 index e930ccdd4..000000000 --- a/src/mirall/connectionvalidator.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 CONNECTIONVALIDATOR_H -#define CONNECTIONVALIDATOR_H - -#include "owncloudlib.h" -#include <QObject> -#include <QStringList> -#include <QVariantMap> -#include <QNetworkReply> - -namespace Mirall { - -class Account; - -class OWNCLOUDSYNC_EXPORT ConnectionValidator : public QObject -{ - Q_OBJECT -public: - explicit ConnectionValidator(Account *account, QObject *parent = 0); - - enum Status { - Undefined, - Connected, - NotConfigured, - ServerVersionMismatch, - CredentialsTooManyAttempts, - CredentialError, - CredentialsUserCanceled, - CredentialsWrong, - StatusNotFound - - }; - - QStringList errors() const; - bool networkError() const; - - void checkConnection(); - - QString statusString( Status ) const; - -signals: - void connectionResult( ConnectionValidator::Status ); - // void connectionAvailable(); - // void connectionFailed(); - -public slots: - -protected slots: - void slotStatusFound(const QUrl&url, const QVariantMap &info); - void slotNoStatusFound(QNetworkReply *reply); - - void slotCheckAuthentication(); - void slotAuthFailed(QNetworkReply *reply); - void slotAuthSuccess(); - -private: - QStringList _errors; - Account *_account; - bool _networkError; -}; - -} - -#endif // CONNECTIONVALIDATOR_H diff --git a/src/mirall/cookiejar.cpp b/src/mirall/cookiejar.cpp deleted file mode 100644 index 53539ac6c..000000000 --- a/src/mirall/cookiejar.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 "cookiejar.h" - -#include "mirall/mirallconfigfile.h" - -#include <QDebug> -#include <QFile> -#include <QDateTime> -#include <QNetworkCookie> - -namespace Mirall { - -namespace { - const unsigned int JAR_VERSION = 23; -} - -QDataStream &operator<<(QDataStream &stream, const QList<QNetworkCookie> &list) -{ - stream << JAR_VERSION; - stream << quint32(list.size()); - for (int i = 0; i < list.size(); ++i) - stream << list.at(i).toRawForm(); - return stream; -} - -QDataStream &operator>>(QDataStream &stream, QList<QNetworkCookie> &list) -{ - list.clear(); - - quint32 version; - stream >> version; - - if (version != JAR_VERSION) - return stream; - - quint32 count; - stream >> count; - for(quint32 i = 0; i < count; ++i) - { - QByteArray value; - stream >> value; - QList<QNetworkCookie> newCookies = QNetworkCookie::parseCookies(value); - if (newCookies.count() == 0 && value.length() != 0) { - qWarning() << "CookieJar: Unable to parse saved cookie:" << value; - } - for (int j = 0; j < newCookies.count(); ++j) - list.append(newCookies.at(j)); - if (stream.atEnd()) - break; - } - return stream; -} - -CookieJar::CookieJar(QObject *parent) : - QNetworkCookieJar(parent) -{ - restore(); -} - -CookieJar::~CookieJar() -{ - save(); -} - -bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url) -{ - if (QNetworkCookieJar::setCookiesFromUrl(cookieList, url)) { - Q_EMIT newCookiesForUrl(cookieList, url); - return true; - } - - return false; -} - -QList<QNetworkCookie> CookieJar::cookiesForUrl(const QUrl &url) const -{ - QList<QNetworkCookie> cookies = QNetworkCookieJar::cookiesForUrl(url); -// qDebug() << url << "requests:" << cookies; - return cookies; -} - -bool CookieJar::deleteCookie(const QNetworkCookie &delCookie) -{ - QList<QNetworkCookie> cookies = allCookies(); - bool removeSucceeded = false; - foreach(const QNetworkCookie &cookie, cookies) { - // ### cookies are not identical in attriutes, why? - if (cookie.name() == delCookie.name()) { - cookies.removeOne(cookie); - removeSucceeded = true; - } - } - setAllCookies(cookies); - return removeSucceeded; -} - -void CookieJar::clearSessionCookies() -{ - setAllCookies(removeExpired(allCookies())); -} - - -void CookieJar::save() -{ - QFile file; - file.setFileName(storagePath()); - qDebug() << storagePath(); - file.open(QIODevice::WriteOnly); - QDataStream stream(&file); - stream << allCookies(); - file.close(); -} - -void CookieJar::restore() -{ - QFile file; - file.setFileName(storagePath()); - file.open(QIODevice::ReadOnly); - QDataStream stream(&file); - QList<QNetworkCookie> list; - stream >> list; - setAllCookies(removeExpired(list)); - file.close(); -} - -QList<QNetworkCookie> CookieJar::removeExpired(const QList<QNetworkCookie> &cookies) -{ - QList<QNetworkCookie> updatedList; - foreach(const QNetworkCookie &cookie, cookies) { - if (cookie.expirationDate() > QDateTime::currentDateTime() && !cookie.isSessionCookie()) { - updatedList << cookie; - } - } - return updatedList; -} - -QString CookieJar::storagePath() const -{ - MirallConfigFile cfg; - return cfg.configPath() + "/cookies.db"; -} - -} // namespace Mirall diff --git a/src/mirall/cookiejar.h b/src/mirall/cookiejar.h deleted file mode 100644 index 3166b547d..000000000 --- a/src/mirall/cookiejar.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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_COOKIEJAR_H -#define MIRALL_COOKIEJAR_H - -#include <QNetworkCookieJar> - -#include "owncloudlib.h" - -namespace Mirall { - -class OWNCLOUDSYNC_EXPORT CookieJar : public QNetworkCookieJar -{ - Q_OBJECT -public: - explicit CookieJar(QObject *parent = 0); - ~CookieJar(); - bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url) Q_DECL_OVERRIDE; - QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const Q_DECL_OVERRIDE; - - bool deleteCookie(const QNetworkCookie & cookie) -#if QT_VERSION > QT_VERSION_CHECK(5, 0, 0) - Q_DECL_OVERRIDE //that function is not virtual in Qt4 -#endif - ; - void clearSessionCookies(); - -signals: - void newCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url); -private: - void save(); - void restore(); - QList<QNetworkCookie> removeExpired(const QList<QNetworkCookie> &cookies); - QString storagePath() const; - -}; - -} // namespace Mirall - -#endif // MIRALL_COOKIEJAR_H diff --git a/src/mirall/filesystem.cpp b/src/mirall/filesystem.cpp deleted file mode 100644 index b317b320d..000000000 --- a/src/mirall/filesystem.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 "filesystem.h" -#include <QFile> -#include <QDebug> - -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) -#include <qabstractfileengine.h> -#endif - -#ifdef Q_OS_WIN -#include <windef.h> -#include <winbase.h> -#endif - - -// We use some internals of csync: -extern "C" int c_utimes(const char *, const struct timeval *); -extern "C" void csync_win32_set_file_hidden( const char *file, bool h ); - -namespace Mirall { - -bool FileSystem::fileEquals(const QString& fn1, const QString& fn2) -{ - // compare two files with given filename and return true if they have the same content - QFile f1(fn1); - QFile f2(fn2); - if (!f1.open(QIODevice::ReadOnly) || !f2.open(QIODevice::ReadOnly)) { - qDebug() << "fileEquals: Failed to open " << fn1 << "or" << fn2; - return false; - } - - if (f1.size() != f2.size()) { - return false; - } - - const int BufferSize = 16 * 1024; - char buffer1[BufferSize]; - char buffer2[BufferSize]; - do { - int r = f1.read(buffer1, BufferSize); - if (f2.read(buffer2, BufferSize) != r) { - // this should normaly not happen: the file are supposed to have the same size. - return false; - } - if (r <= 0) { - return true; - } - if (memcmp(buffer1, buffer2, r) != 0) { - return false; - } - } while (true); - return false; -} - -void FileSystem::setFileHidden(const QString& filename, bool hidden) -{ - return csync_win32_set_file_hidden(filename.toUtf8().constData(), hidden); -} - -void FileSystem::setModTime(const QString& filename, time_t modTime) -{ - struct timeval times[2]; - times[0].tv_sec = times[1].tv_sec = modTime; - times[0].tv_usec = times[1].tv_usec = 0; - c_utimes(filename.toUtf8().data(), times); -} - -bool FileSystem::renameReplace(const QString& originFileName, const QString& destinationFileName, QString* errorString) -{ -#ifndef Q_OS_WIN - bool success; - QFile orig(originFileName); -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - success = orig.fileEngine()->rename(destinationFileName); - // qDebug() << "Renaming " << tmpFile.fileName() << " to " << fn; -#else - // We want a rename that also overwite. QFile::rename does not overwite. - // Qt 5.1 has QSaveFile::renameOverwrite we cold use. - // ### FIXME - QFile::remove(destinationFileName); - success = orig.rename(destinationFileName); -#endif - if (!success) { - *errorString = orig.errorString(); - qDebug() << "FAIL: renaming temp file to final failed: " << *errorString ; - return false; - } -#else //Q_OS_WIN - BOOL ok; - ok = MoveFileEx((wchar_t*)originFileName.utf16(), - (wchar_t*)destinationFileName.utf16(), - MOVEFILE_REPLACE_EXISTING+MOVEFILE_COPY_ALLOWED+MOVEFILE_WRITE_THROUGH); - if (!ok) { - wchar_t *string = 0; - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, - NULL, ::GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPWSTR)&string, 0, NULL); - - *errorString = QString::fromWCharArray(string); - LocalFree((HLOCAL)string); - return false; - } -#endif - return true; -} - - - -} diff --git a/src/mirall/filesystem.h b/src/mirall/filesystem.h deleted file mode 100644 index c8e10ceb0..000000000 --- a/src/mirall/filesystem.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) by Olivier Goffart <ogoffart@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; version 2 of the License. - * - * 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. - */ - -#pragma once - -#include <QString> -#include <ctime> - -#include <owncloudlib.h> - -namespace Mirall { - -/** - * This file contains file system helper. - */ - -namespace FileSystem { - -/** compare two files with given filename and return true if they have the same content */ -bool fileEquals(const QString &fn1, const QString &fn2); - -/** Mark the file as hidden (only has effects on windows) */ -void OWNCLOUDSYNC_EXPORT setFileHidden(const QString& filename, bool hidden); - -void setModTime(const QString &filename, time_t modTime); - -/** - * Rename the file \a originFileName to \a destinationFileName, and overwrite the destination if it - * already exists - */ -bool renameReplace(const QString &originFileName, const QString &destinationFileName, - QString *errorString); - -}} diff --git a/src/mirall/folder.cpp b/src/mirall/folder.cpp deleted file mode 100644 index 5f14ae913..000000000 --- a/src/mirall/folder.cpp +++ /dev/null @@ -1,741 +0,0 @@ -/* - * 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 - * 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 "config.h" - -#include "mirall/account.h" -#include "mirall/folder.h" -#include "mirall/folderman.h" -#include "mirall/logger.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/networkjobs.h" -#include "mirall/syncjournalfilerecord.h" -#include "mirall/syncresult.h" -#include "mirall/utility.h" -#include "mirall/clientproxy.h" -#include "mirall/syncengine.h" -#include "mirall/syncrunfilelog.h" - -#include "creds/abstractcredentials.h" - -#include <QDebug> -#include <QTimer> -#include <QUrl> -#include <QDir> - -#include <QMessageBox> -#include <QPushButton> - -namespace Mirall { - -static void csyncLogCatcher(int /*verbosity*/, - const char */*function*/, - const char *buffer, - void */*userdata*/) -{ - Logger::instance()->csyncLog( QString::fromUtf8(buffer) ); -} - - -Folder::Folder(const QString &alias, const QString &path, const QString& secondPath, QObject *parent) - : QObject(parent) - , _path(path) - , _remotePath(secondPath) - , _alias(alias) - , _enabled(true) - , _csyncError(false) - , _csyncUnavail(false) - , _wipeDb(false) - , _proxyDirty(true) - , _journal(path) - , _csync_ctx(0) -{ - qsrand(QTime::currentTime().msec()); - _timeSinceLastSync.start(); - - MirallConfigFile cfg; - - _syncResult.setStatus( SyncResult::NotYetStarted ); - - // check if the local path exists - checkLocalPath(); - - int polltime = cfg.remotePollInterval(); - qDebug() << "setting remote poll timer interval to" << polltime << "msec"; - _pollTimer.setInterval( polltime ); - QObject::connect(&_pollTimer, SIGNAL(timeout()), this, SLOT(slotPollTimerTimeout())); - _pollTimer.start(); - - _syncResult.setFolder(alias); -} - -bool Folder::init() -{ - Account *account = AccountManager::instance()->account(); - if (!account) { - // Normaly this should not happen, but it could be that there is something - // wrong with the config and it is better not to crash. - qWarning() << "WRN: No account configured, can't sync"; - return false; - } - - // We need to reconstruct the url because the path need to be fully decoded, as csync will re-encode the path: - // Remember that csync will just append the filename to the path and pass it to the vio plugin. - // csync_owncloud will then re-encode everything. -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) - QUrl url = remoteUrl(); - QString url_string = url.scheme() + QLatin1String("://") + url.authority(QUrl::EncodeDelimiters) + url.path(QUrl::FullyDecoded); -#else - // Qt4 was broken anyway as it did not encode the '#' as it should have done (it was actually a provlem when parsing the path from QUrl::setPath - QString url_string = remoteUrl().toString(); -#endif - url_string = Utility::toCSyncScheme(url_string); - - QString localpath = path(); - - if( csync_create( &_csync_ctx, localpath.toUtf8().data(), url_string.toUtf8().data() ) < 0 ) { - qDebug() << "Unable to create csync-context!"; - slotSyncError(tr("Unable to create csync-context")); - _csync_ctx = 0; - } else { - csync_set_log_callback( csyncLogCatcher ); - csync_set_log_level( 11 ); - - if (Account *account = AccountManager::instance()->account()) { - account->credentials()->syncContextPreInit(_csync_ctx); - } else { - qDebug() << Q_FUNC_INFO << "No default Account object, huh?"; - } - - if( csync_init( _csync_ctx ) < 0 ) { - qDebug() << "Could not initialize csync!" << csync_get_status(_csync_ctx) << csync_get_status_string(_csync_ctx); - QString errStr = SyncEngine::csyncErrorToString(CSYNC_STATUS(csync_get_status(_csync_ctx))); - const char *errMsg = csync_get_status_string(_csync_ctx); - if( errMsg ) { - errStr += QLatin1String("<br/>"); - errStr += QString::fromUtf8(errMsg); - } - slotSyncError(errStr); - csync_destroy(_csync_ctx); - _csync_ctx = 0; - } - } - return _csync_ctx; -} - -Folder::~Folder() -{ - if( _engine ) { - _engine->abort(); - _engine.reset(0); - } - // Destroy csync here. - csync_destroy(_csync_ctx); -} - -void Folder::checkLocalPath() -{ - QFileInfo fi(_path); - - if( fi.isDir() && fi.isReadable() ) { - qDebug() << "Checked local path ok"; - } else { - if( !fi.exists() ) { - // try to create the local dir - QDir d(_path); - if( d.mkpath(_path) ) { - qDebug() << "Successfully created the local dir " << _path; - } - } - // Check directory again - if( !fi.exists() ) { - _syncResult.setErrorString(tr("Local folder %1 does not exist.").arg(_path)); - _syncResult.setStatus( SyncResult::SetupError ); - } else if( !fi.isDir() ) { - _syncResult.setErrorString(tr("%1 should be a directory but is not.").arg(_path)); - _syncResult.setStatus( SyncResult::SetupError ); - } else if( !fi.isReadable() ) { - _syncResult.setErrorString(tr("%1 is not readable.").arg(_path)); - _syncResult.setStatus( SyncResult::SetupError ); - } - } -} - -QString Folder::alias() const -{ - return _alias; -} - -QString Folder::path() const -{ - QString p(_path); - if( ! p.endsWith(QLatin1Char('/')) ) { - p.append(QLatin1Char('/')); - } - return p; -} - -bool Folder::isBusy() const -{ - return !_engine.isNull(); -} - -QString Folder::remotePath() const -{ - return _remotePath; -} - -QUrl Folder::remoteUrl() const -{ - Account *account = AccountManager::instance()->account(); - QUrl url = account->davUrl(); - QString path = url.path(); - if (!path.endsWith('/')) { - path.append('/'); - } - path.append(_remotePath); - url.setPath(path); - return url; -} - -QString Folder::nativePath() const -{ - return QDir::toNativeSeparators(_path); -} - -bool Folder::syncEnabled() const -{ - return _enabled; -} - -void Folder::setSyncEnabled( bool doit ) -{ - _enabled = doit; - - if( doit ) { - // qDebug() << "Syncing enabled on folder " << name(); - } else { - // do not stop or start the watcher here, that is done internally by - // folder class. Even if the watcher fires, the folder does not - // schedule itself because it checks the var. _enabled before. - _pollTimer.stop(); - setSyncState(SyncResult::Paused); - } -} - -void Folder::setSyncState(SyncResult::Status state) -{ - _syncResult.setStatus(state); -} - -SyncResult Folder::syncResult() const -{ - return _syncResult; -} - -void Folder::prepareToSync() -{ - _syncResult.setStatus( SyncResult::NotYetStarted ); - _syncResult.clearErrors(); -} - -void Folder::slotPollTimerTimeout() -{ - qDebug() << "* Polling" << alias() << "for changes. (time since last sync:" << (_timeSinceLastSync.elapsed() / 1000) << "s)"; - - if (quint64(_timeSinceLastSync.elapsed()) > MirallConfigFile().forceSyncInterval() || - !(_syncResult.status() == SyncResult::Success ||_syncResult.status() == SyncResult::Problem)) { - qDebug() << "** Force Sync now, state is " << _syncResult.statusString(); - emit scheduleToSync(alias()); - } else { - RequestEtagJob* job = new RequestEtagJob(AccountManager::instance()->account(), remotePath(), this); - // check if the etag is different - QObject::connect(job, SIGNAL(etagRetreived(QString)), this, SLOT(etagRetreived(QString))); - QObject::connect(job, SIGNAL(networkError(QNetworkReply*)), this, SLOT(slotNetworkUnavailable())); - job->start(); - } -} - -void Folder::etagRetreived(const QString& etag) -{ - qDebug() << "* Compare etag with previous etag: " << (_lastEtag != etag); - - // re-enable sync if it was disabled because network was down - FolderMan::instance()->setSyncEnabled(true); - - if (_lastEtag != etag) { - _lastEtag = etag; - emit scheduleToSync(alias()); - } -} - -void Folder::slotNetworkUnavailable() -{ - Account *account = AccountManager::instance()->account(); - if (account && account->state() == Account::Connected) { - account->setState(Account::Disconnected); - } - _syncResult.setStatus(SyncResult::Unavailable); - emit syncStateChange(); -} - -void Folder::bubbleUpSyncResult() -{ - // count new, removed and updated items - int newItems = 0; - int removedItems = 0; - int updatedItems = 0; - int ignoredItems = 0; - int renamedItems = 0; - - SyncFileItem firstItemNew; - SyncFileItem firstItemDeleted; - SyncFileItem firstItemUpdated; - SyncFileItem firstItemRenamed; - Logger *logger = Logger::instance(); - - SyncRunFileLog syncFileLog; - - syncFileLog.start(path(), _engine ? _engine->stopWatch() : Utility::StopWatch() ); - - QElapsedTimer timer; - timer.start(); - - foreach (const SyncFileItem &item, _syncResult.syncFileItemVector() ) { - // Log the item - syncFileLog.logItem( item ); - - // and process the item to the gui - if( item._status == SyncFileItem::FatalError || item._status == SyncFileItem::NormalError ) { - slotSyncError( tr("%1: %2").arg(item._file, item._errorString) ); - logger->postOptionalGuiLog(item._file, item._errorString); - } else { - // add new directories or remove gone away dirs to the watcher - if (item._isDirectory && item._instruction == CSYNC_INSTRUCTION_NEW ) { - FolderMan::instance()->addMonitorPath( alias(), path()+item._file ); - } - if (item._isDirectory && item._instruction == CSYNC_INSTRUCTION_REMOVE ) { - FolderMan::instance()->removeMonitorPath( alias(), path()+item._file ); - } - - if (item._direction == SyncFileItem::Down) { - switch (item._instruction) { - case CSYNC_INSTRUCTION_NEW: - newItems++; - if (firstItemNew.isEmpty()) - firstItemNew = item; - break; - case CSYNC_INSTRUCTION_REMOVE: - removedItems++; - if (firstItemDeleted.isEmpty()) - firstItemDeleted = item; - break; - case CSYNC_INSTRUCTION_CONFLICT: - case CSYNC_INSTRUCTION_SYNC: - updatedItems++; - if (firstItemUpdated.isEmpty()) - firstItemUpdated = item; - break; - case CSYNC_INSTRUCTION_ERROR: - qDebug() << "Got Instruction ERROR. " << _syncResult.errorString(); - break; - case CSYNC_INSTRUCTION_RENAME: - if (firstItemRenamed.isEmpty()) { - firstItemRenamed = item; - } - renamedItems++; - break; - default: - // nothing. - break; - } - } else if( item._direction == SyncFileItem::None ) { // ignored files counting. - if( item._instruction == CSYNC_INSTRUCTION_IGNORE ) { - ignoredItems++; - } - } - } - } - syncFileLog.close(); - - qDebug() << "Processing result list and logging took " << timer.elapsed() << " Milliseconds."; - _syncResult.setWarnCount(ignoredItems); - - createGuiLog( firstItemNew._file, SyncFileStatus(SyncFileStatus::STATUS_NEW), newItems ); - createGuiLog( firstItemDeleted._file, SyncFileStatus(SyncFileStatus::STATUS_REMOVE), removedItems ); - createGuiLog( firstItemUpdated._file, SyncFileStatus(SyncFileStatus::STATUS_UPDATED), updatedItems ); - - if( !firstItemRenamed.isEmpty() ) { - SyncFileStatus status(SyncFileStatus::STATUS_RENAME); - // if the path changes it's rather a move - QDir renTarget = QFileInfo(firstItemRenamed._renameTarget).dir(); - QDir renSource = QFileInfo(firstItemRenamed._file).dir(); - if(renTarget != renSource) { - status.set(SyncFileStatus::STATUS_MOVE); - } - createGuiLog( firstItemRenamed._file, status, renamedItems, firstItemRenamed._renameTarget ); - } - - qDebug() << "OO folder slotSyncFinished: result: " << int(_syncResult.status()); -} - -void Folder::createGuiLog( const QString& filename, SyncFileStatus status, int count, - const QString& renameTarget ) -{ - if(count > 0) { - Logger *logger = Logger::instance(); - - QString file = QDir::toNativeSeparators(filename); - QString text; - - // not all possible values of status are evaluated here because the others - // are not used in the calling function. Please check there. - switch (status.tag()) { - case SyncFileStatus::STATUS_REMOVE: - if( count > 1 ) { - text = tr("%1 and %2 other files have been removed.", "%1 names a file.").arg(file).arg(count-1); - } else { - text = tr("%1 has been removed.", "%1 names a file.").arg(file); - } - break; - case SyncFileStatus::STATUS_NEW: - if( count > 1 ) { - text = tr("%1 and %2 other files have been downloaded.", "%1 names a file.").arg(file).arg(count-1); - } else { - text = tr("%1 has been downloaded.", "%1 names a file.").arg(file); - } - break; - case SyncFileStatus::STATUS_UPDATED: - if( count > 1 ) { - text = tr("%1 and %2 other files have been updated.").arg(file).arg(count-1); - } else { - text = tr("%1 has been updated.", "%1 names a file.").arg(file); - } - break; - case SyncFileStatus::STATUS_RENAME: - if( count > 1 ) { - text = tr("%1 has been renamed to %2 and %3 other files have been renamed.").arg(file).arg(renameTarget).arg(count-1); - } else { - text = tr("%1 has been renamed to %2.", "%1 and %2 name files.").arg(file).arg(renameTarget); - } - break; - case SyncFileStatus::STATUS_MOVE: - if( count > 1 ) { - text = tr("%1 has been moved to %2 and %3 other files have been moved.").arg(file).arg(renameTarget).arg(count-1); - } else { - text = tr("%1 has been moved to %2.").arg(file).arg(renameTarget); - } - break; - default: - break; - } - - if( !text.isEmpty() ) { - logger->postOptionalGuiLog( tr("Sync Activity"), text ); - } - } -} - -int Folder::blackListEntryCount() -{ - return _journal.blackListEntryCount(); -} - -int Folder::slotWipeBlacklist() -{ - return _journal.wipeBlacklist(); -} - -void Folder::setConfigFile( const QString& file ) -{ - _configFile = file; -} - -QString Folder::configFile() -{ - return _configFile; -} - -void Folder::slotThreadTreeWalkResult(const SyncFileItemVector& items) -{ - _syncResult.setSyncFileItemVector(items); -} - -void Folder::slotTerminateSync() -{ - qDebug() << "folder " << alias() << " Terminating!"; - - if( _engine ) { - _engine->abort(); - - // Do not display an error message, user knows his own actions. - // _errors.append( tr("The CSync thread terminated.") ); - // _csyncError = true; - setSyncEnabled(false); - setSyncState(SyncResult::SyncAbortRequested); - return; - } -} - -// This removes the csync File database -// This is needed to provide a clean startup again in case another -// local folder is synced to the same ownCloud. -void Folder::wipe() -{ - QString stateDbFile = path()+QLatin1String(".csync_journal.db"); - - _journal.close(); // close the sync journal - - QFile file(stateDbFile); - if( file.exists() ) { - if( !file.remove()) { - qDebug() << "WRN: Failed to remove existing csync StateDB " << stateDbFile; - } else { - qDebug() << "wipe: Removed csync StateDB " << stateDbFile; - } - } else { - qDebug() << "WRN: statedb is empty, can not remove."; - } - // Check if the tmp database file also exists - QString ctmpName = path() + QLatin1String(".csync_journal.db.ctmp"); - QFile ctmpFile( ctmpName ); - if( ctmpFile.exists() ) { - ctmpFile.remove(); - } -} - -void Folder::setIgnoredFiles() -{ - MirallConfigFile cfgFile; - csync_clear_exclude_list( _csync_ctx ); - QString excludeList = cfgFile.excludeFile( MirallConfigFile::SystemScope ); - if( !excludeList.isEmpty() ) { - qDebug() << "==== added system ignore list to csync:" << excludeList.toUtf8(); - csync_add_exclude_list( _csync_ctx, excludeList.toUtf8() ); - } - excludeList = cfgFile.excludeFile( MirallConfigFile::UserScope ); - if( !excludeList.isEmpty() ) { - qDebug() << "==== added user defined ignore list to csync:" << excludeList.toUtf8(); - csync_add_exclude_list( _csync_ctx, excludeList.toUtf8() ); - } -} - -void Folder::setProxyDirty(bool value) -{ - _proxyDirty = value; -} - -bool Folder::proxyDirty() -{ - return _proxyDirty; -} - -void Folder::startSync(const QStringList &pathList) -{ - Q_UNUSED(pathList) - if (!_csync_ctx) { - // no _csync_ctx yet, initialize it. - init(); - - if (!_csync_ctx) { - qDebug() << Q_FUNC_INFO << "init failed."; - // the error should already be set - QMetaObject::invokeMethod(this, "slotCSyncFinished", Qt::QueuedConnection); - return; - } - _clientProxy.setCSyncProxy(AccountManager::instance()->account()->url(), _csync_ctx); - } else if (proxyDirty()) { - _clientProxy.setCSyncProxy(AccountManager::instance()->account()->url(), _csync_ctx); - setProxyDirty(false); - } - - if (isBusy()) { - qCritical() << "* ERROR csync is still running and new sync requested."; - return; - } - _errors.clear(); - _csyncError = false; - _csyncUnavail = false; - - _syncResult.clearErrors(); - _syncResult.setStatus( SyncResult::SyncPrepare ); - emit syncStateChange(); - - - qDebug() << "*** Start syncing"; - setIgnoredFiles(); - _engine.reset(new SyncEngine( _csync_ctx, path(), remoteUrl().path(), _remotePath, &_journal)); - - qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector"); - qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction"); - - connect( _engine.data(), SIGNAL(treeWalkResult(const SyncFileItemVector&)), - this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection); - - connect(_engine.data(), SIGNAL(started()), SLOT(slotSyncStarted()), Qt::QueuedConnection); - connect(_engine.data(), SIGNAL(finished()), SLOT(slotSyncFinished()), Qt::QueuedConnection); - connect(_engine.data(), SIGNAL(csyncError(QString)), SLOT(slotSyncError(QString)), Qt::QueuedConnection); - connect(_engine.data(), SIGNAL(csyncUnavailable()), SLOT(slotCsyncUnavailable()), Qt::QueuedConnection); - - //direct connection so the message box is blocking the sync. - connect(_engine.data(), SIGNAL(aboutToRemoveAllFiles(SyncFileItem::Direction,bool*)), - SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*))); - connect(_engine.data(), SIGNAL(transmissionProgress(Progress::Info)), this, SLOT(slotTransmissionProgress(Progress::Info))); - connect(_engine.data(), SIGNAL(jobCompleted(SyncFileItem)), this, SLOT(slotJobCompleted(SyncFileItem))); - - setDirtyNetworkLimits(); - - QMetaObject::invokeMethod(_engine.data(), "startSync", Qt::QueuedConnection); - - // disable events until syncing is done - // _watcher->setEventsEnabled(false); - _pollTimer.stop(); - emit syncStarted(); -} - -void Folder::setDirtyNetworkLimits() -{ - if (_engine) { - - MirallConfigFile cfg; - int downloadLimit = 0; - if (cfg.useDownloadLimit()) { - downloadLimit = cfg.downloadLimit() * 1000; - } - int uploadLimit = -75; // 75% - int useUpLimit = cfg.useUploadLimit(); - if ( useUpLimit >= 1) { - uploadLimit = cfg.uploadLimit() * 1000; - } else if (useUpLimit == 0) { - uploadLimit = 0; - } - - _engine->setNetworkLimits(uploadLimit, downloadLimit); - } -} - -void Folder::slotSyncError(const QString& err) -{ - _errors.append( err ); - _csyncError = true; -} - -void Folder::slotSyncStarted() -{ - qDebug() << " * csync thread started"; - _syncResult.setStatus(SyncResult::SyncRunning); - emit syncStateChange(); -} - -void Folder::slotCsyncUnavailable() -{ - _csyncUnavail = true; -} - -void Folder::slotSyncFinished() -{ - qDebug() << "-> CSync Finished slot with error " << _csyncError << "warn count" << _syncResult.warnCount(); - - bubbleUpSyncResult(); - - _engine.reset(0); - // _watcher->setEventsEnabledDelayed(2000); - _pollTimer.start(); - _timeSinceLastSync.restart(); - - - if (_csyncError) { - _syncResult.setStatus(SyncResult::Error); - qDebug() << " ** error Strings: " << _errors; - _syncResult.setErrorStrings( _errors ); - qDebug() << " * owncloud csync thread finished with error"; - } else if (_csyncUnavail) { - _syncResult.setStatus(SyncResult::Unavailable); - } else if( _syncResult.warnCount() > 0 ) { - // there have been warnings on the way. - _syncResult.setStatus(SyncResult::Problem); - } else { - _syncResult.setStatus(SyncResult::Success); - } - - emit syncStateChange(); - - // The syncFinished result that is to be triggered here makes the folderman - // clearing the current running sync folder marker. - // Lets wait a bit to do that because, as long as this marker is not cleared, - // file system change notifications are ignored for that folder. And it takes - // some time under certain conditions to make the file system notifications - // all come in. - QTimer::singleShot(200, this, SLOT(slotEmitFinishedDelayed() )); - -} - -void Folder::slotEmitFinishedDelayed() -{ - emit syncFinished( _syncResult ); -} - - - -// the progress comes without a folder and the valid path set. Add that here -// and hand the result over to the progress dispatcher. -void Folder::slotTransmissionProgress(const Progress::Info &pi) -{ - if( pi._completedFileCount ) { - // No job completed yet, this is the beginning of a sync, set the warning level to 0 - _syncResult.setWarnCount(0); - } - ProgressDispatcher::instance()->setProgressInfo(alias(), pi); -} - -// a job is completed: count the errors and forward to the ProgressDispatcher -void Folder::slotJobCompleted(const SyncFileItem &item) -{ - if (Progress::isWarningKind(item._status)) { - // Count all error conditions. - _syncResult.setWarnCount(_syncResult.warnCount()+1); - } - emit ProgressDispatcher::instance()->jobCompleted(alias(), item); -} - - -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(); - // speed up next sync - _lastEtag = QString(); - QTimer::singleShot(50, this, SLOT(slotPollTimerTimeout())); - } -} -} // namespace Mirall - diff --git a/src/mirall/folder.h b/src/mirall/folder.h deleted file mode 100644 index 8a9d55411..000000000 --- a/src/mirall/folder.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * 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 - * 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_FOLDER_H -#define MIRALL_FOLDER_H - -#include "mirall/syncresult.h" -#include "mirall/progressdispatcher.h" -#include "mirall/syncjournaldb.h" -#include "mirall/clientproxy.h" -#include "mirall/syncfilestatus.h" - -#include <csync.h> - -#include <QDir> -#include <QHash> -#include <QObject> -#include <QStringList> - -#include <QDebug> -#include <QTimer> -#include <qelapsedtimer.h> - -class QFileSystemWatcher; -class QThread; - -namespace Mirall { - -class SyncEngine; - -class FolderWatcher; - -class Folder : public QObject -{ - Q_OBJECT - -public: - Folder(const QString&, const QString&, const QString& , QObject*parent = 0L); - - ~Folder(); - - typedef QHash<QString, Folder*> Map; - typedef QHashIterator<QString, Folder*> MapIterator; - - /** - * alias or nickname - */ - QString alias() const; - - /** - * local folder path - */ - QString path() const; - - /** - * remote folder path - */ - QString remotePath() const; - - /** - * remote folder path with server url - */ - QUrl remoteUrl() 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 - * be called. - */ - void setSyncEnabled( bool ); - - bool syncEnabled() const; - - void prepareToSync(); - - /** - * True if the folder is busy and can't initiate - * a synchronization - */ - virtual bool isBusy() const; - - /** - * return the last sync result with error message and status - */ - SyncResult syncResult() const; - - /** - * set the config file name. - */ - void setConfigFile( const QString& ); - QString configFile(); - - /** - * This is called if the sync folder definition is removed. Do cleanups here. - */ - virtual void wipe(); - - void setSyncState(SyncResult::Status state); - - void setDirtyNetworkLimits(); - - // Used by the Socket API - SyncJournalDb *journalDb() { return &_journal; } - CSYNC *csyncContext() { return _csync_ctx; } - - -signals: - void syncStateChange(); - void syncStarted(); - void syncFinished(const SyncResult &result); - void scheduleToSync( const QString& ); - -public slots: - - /** - * terminate the current sync run - */ - void slotTerminateSync(); - - 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()); - - void setProxyDirty(bool value); - bool proxyDirty(); - - int slotWipeBlacklist(); - int blackListEntryCount(); - -private slots: - void slotSyncStarted(); - void slotSyncError(const QString& ); - void slotCsyncUnavailable(); - void slotSyncFinished(); - - void slotTransmissionProgress(const Progress::Info& pi); - void slotJobCompleted(const SyncFileItem&); - - void slotPollTimerTimeout(); - void etagRetreived(const QString &); - void slotNetworkUnavailable(); - - void slotThreadTreeWalkResult(const SyncFileItemVector& ); - - void slotEmitFinishedDelayed(); - -private: - bool init(); - - void setIgnoredFiles(); - - void bubbleUpSyncResult(); - - void checkLocalPath(); - - void createGuiLog(const QString& filename, SyncFileStatus status, int count, - const QString& renameTarget = QString::null ); - - QString _path; - QString _remotePath; - QString _alias; - QString _configFile; - bool _enabled; - SyncResult _syncResult; - QScopedPointer<SyncEngine> _engine; - QStringList _errors; - bool _csyncError; - bool _csyncUnavail; - bool _wipeDb; - bool _proxyDirty; - QTimer _pollTimer; - QString _lastEtag; - QElapsedTimer _timeSinceLastSync; - - SyncJournalDb _journal; - - ClientProxy _clientProxy; - - CSYNC *_csync_ctx; -}; - -} - -#endif diff --git a/src/mirall/folderman.cpp b/src/mirall/folderman.cpp deleted file mode 100644 index 496608b8d..000000000 --- a/src/mirall/folderman.cpp +++ /dev/null @@ -1,788 +0,0 @@ -/* - * 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. - */ - -#include "mirall/folderman.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/folder.h" -#include "mirall/syncresult.h" -#include "mirall/theme.h" - -#include <neon/ne_socket.h> - -#ifdef Q_OS_MAC -#include <CoreServices/CoreServices.h> -#endif -#ifdef Q_OS_WIN -#include <shlobj.h> -#endif - -#include <QMessageBox> - -#include <QtCore> - -namespace Mirall { - -FolderMan* FolderMan::_instance = 0; - -FolderMan::FolderMan(QObject *parent) : - QObject(parent), - _syncEnabled( true ) -{ - _folderChangeSignalMapper = new QSignalMapper(this); - connect(_folderChangeSignalMapper, SIGNAL(mapped(const QString &)), - this, SIGNAL(folderSyncStateChange(const QString &))); - - _folderWatcherSignalMapper = new QSignalMapper(this); - connect(_folderWatcherSignalMapper, SIGNAL(mapped(const QString&)), - this, SLOT(slotScheduleSync(const QString&))); - - ne_sock_init(); - Q_ASSERT(!_instance); - _instance = this; -} - -FolderMan *FolderMan::instance() -{ - return _instance; -} - -FolderMan::~FolderMan() -{ - qDeleteAll(_folderMap); - ne_sock_exit(); - _instance = 0; -} - -Mirall::Folder::Map FolderMan::map() -{ - return _folderMap; -} - -int FolderMan::unloadAllFolders() -{ - int cnt = 0; - - // clear the list of existing folders. - Folder::MapIterator i(_folderMap); - while (i.hasNext()) { - i.next(); - delete _folderMap.take( i.key() ); - cnt++; - } - _currentSyncFolder.clear(); - _scheduleQueue.clear(); - return cnt; -} - -// add a monitor to the local file system. If there is a change in the -// file system, the method slotFolderMonitorFired is triggered through -// the SignalMapper -void FolderMan::registerFolderMonitor( Folder *folder ) -{ - if( !folder ) return; - - if( !_folderWatchers.contains(folder->alias() ) ) { - FolderWatcher *fw = new FolderWatcher(folder->path(), this); - MirallConfigFile cfg; - fw->addIgnoreListFile( cfg.excludeFile(MirallConfigFile::SystemScope) ); - fw->addIgnoreListFile( cfg.excludeFile(MirallConfigFile::UserScope) ); - - // Connect the folderChanged signal, which comes with the changed path, - // to the signal mapper which maps to the folder alias. The changed path - // is lost this way, but we do not need it for the current implementation. - connect(fw, SIGNAL(folderChanged(QString)), _folderWatcherSignalMapper, SLOT(map())); - _folderWatcherSignalMapper->setMapping(fw, folder->alias()); - _folderWatchers.insert(folder->alias(), fw); - } -} - -void FolderMan::addMonitorPath( const QString& alias, const QString& path ) -{ - if( !alias.isEmpty() && _folderWatchers.contains(alias) ) { - FolderWatcher *fw = _folderWatchers[alias]; - - if( fw ) { - fw->addPath(path); - } - } -} - -void FolderMan::removeMonitorPath( const QString& alias, const QString& path ) -{ - if( !alias.isEmpty() && _folderWatchers.contains(alias) ) { - FolderWatcher *fw = _folderWatchers[alias]; - - if( fw ) { - fw->removePath(path); - } - } -} - -int FolderMan::setupFolders() -{ - qDebug() << "* Setup folders from " << _folderConfigPath; - - unloadAllFolders(); - - MirallConfigFile cfg; - QDir storageDir(cfg.configPath()); - storageDir.mkpath(QLatin1String("folders")); - _folderConfigPath = cfg.configPath() + QLatin1String("folders"); - - QDir dir( _folderConfigPath ); - //We need to include hidden files just in case the alias starts with '.' - dir.setFilter(QDir::Files | QDir::Hidden); - QStringList list = dir.entryList(); - - foreach ( const QString& alias, list ) { - Folder *f = setupFolderFromConfigFile( alias ); - if( f ) { - slotScheduleSync(alias); - emit( folderSyncStateChange( f->alias() ) ); - } - } - - emit folderListLoaded(_folderMap); - - // return the number of valid folders. - return _folderMap.size(); -} - -bool FolderMan::ensureJournalGone(const QString &localPath) -{ - // FIXME move this to UI, not libowncloudsync - // remove old .csync_journal file - QString stateDbFile = localPath+QLatin1String("/.csync_journal.db"); - while (QFile::exists(stateDbFile) && !QFile::remove(stateDbFile)) { - int ret = QMessageBox::warning(0, tr("Could not reset folder state"), - tr("An old sync journal '%1' was found, " - "but could not be removed. Please make sure " - "that no application is currently using it.") - .arg(QDir::fromNativeSeparators(QDir::cleanPath(stateDbFile))), - QMessageBox::Retry|QMessageBox::Abort); - if (ret == QMessageBox::Abort) { - return false; - } - } - return true; -} - -void FolderMan::terminateCurrentSync() -{ - if( !_currentSyncFolder.isEmpty() ) { - qDebug() << "Terminating syncing on folder " << _currentSyncFolder; - terminateSyncProcess( _currentSyncFolder ); - } -} - -#define SLASH_TAG QLatin1String("__SLASH__") -#define BSLASH_TAG QLatin1String("__BSLASH__") -#define QMARK_TAG QLatin1String("__QMARK__") -#define PERCENT_TAG QLatin1String("__PERCENT__") -#define STAR_TAG QLatin1String("__STAR__") -#define COLON_TAG QLatin1String("__COLON__") -#define PIPE_TAG QLatin1String("__PIPE__") -#define QUOTE_TAG QLatin1String("__QUOTE__") -#define LT_TAG QLatin1String("__LESS_THAN__") -#define GT_TAG QLatin1String("__GREATER_THAN__") -#define PAR_O_TAG QLatin1String("__PAR_OPEN__") -#define PAR_C_TAG QLatin1String("__PAR_CLOSE__") - -QString FolderMan::escapeAlias( const QString& alias ) const -{ - QString a(alias); - - a.replace( QLatin1Char('/'), SLASH_TAG ); - a.replace( QLatin1Char('\\'), BSLASH_TAG ); - a.replace( QLatin1Char('?'), QMARK_TAG ); - a.replace( QLatin1Char('%'), PERCENT_TAG ); - a.replace( QLatin1Char('*'), STAR_TAG ); - a.replace( QLatin1Char(':'), COLON_TAG ); - a.replace( QLatin1Char('|'), PIPE_TAG ); - a.replace( QLatin1Char('"'), QUOTE_TAG ); - a.replace( QLatin1Char('<'), LT_TAG ); - a.replace( QLatin1Char('>'), GT_TAG ); - a.replace( QLatin1Char('['), PAR_O_TAG ); - a.replace( QLatin1Char(']'), PAR_C_TAG ); - return a; -} - -QString FolderMan::unescapeAlias( const QString& alias ) const -{ - QString a(alias); - - a.replace( SLASH_TAG, QLatin1String("/") ); - a.replace( BSLASH_TAG, QLatin1String("\\") ); - a.replace( QMARK_TAG, QLatin1String("?") ); - a.replace( PERCENT_TAG, QLatin1String("%") ); - a.replace( STAR_TAG, QLatin1String("*") ); - a.replace( COLON_TAG, QLatin1String(":") ); - a.replace( PIPE_TAG, QLatin1String("|") ); - a.replace( QUOTE_TAG, QLatin1String("\"") ); - a.replace( LT_TAG, QLatin1String("<") ); - a.replace( GT_TAG, QLatin1String(">") ); - a.replace( PAR_O_TAG, QLatin1String("[") ); - a.replace( PAR_C_TAG, QLatin1String("]") ); - - return a; -} - -// filename is the name of the file only, it does not include -// the configuration directory path -Folder* FolderMan::setupFolderFromConfigFile(const QString &file) { - Folder *folder = 0; - - qDebug() << " ` -> setting up:" << file; - QString escapedAlias(file); - // check the unescaped variant (for the case the filename comes out - // of the directory listing. If the file is not existing, escape the - // file and try again. - QFileInfo cfgFile( _folderConfigPath, file); - - if( !cfgFile.exists() ) { - // try the escaped variant. - escapedAlias = escapeAlias(file); - cfgFile.setFile( _folderConfigPath, escapedAlias ); - } - if( !cfgFile.isReadable() ) { - qDebug() << "Can not read folder definition for alias " << cfgFile.filePath(); - return folder; - } - - QSettings settings( _folderConfigPath + QLatin1Char('/') + escapedAlias, QSettings::IniFormat); - qDebug() << " -> file path: " << settings.fileName(); - - // Check if the filename is equal to the group setting. If not, use the group - // name as an alias. - QStringList groups = settings.childGroups(); - - if( ! groups.contains(escapedAlias) && groups.count() > 0 ) { - escapedAlias = groups.first(); - } - - settings.beginGroup( escapedAlias ); // read the group with the same name as the file which is the folder alias - - QString path = settings.value(QLatin1String("localPath")).toString(); - QString backend = settings.value(QLatin1String("backend")).toString(); - QString targetPath = settings.value( QLatin1String("targetPath")).toString(); - bool paused = settings.value( QLatin1String("paused"), false).toBool(); - // QString connection = settings.value( QLatin1String("connection") ).toString(); - QString alias = unescapeAlias( escapedAlias ); - - 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 Folder( alias, path, targetPath, this ); - folder->setConfigFile(file); - qDebug() << "Adding folder to Folder Map " << folder; - _folderMap[alias] = folder; - if (paused) { - folder->setSyncEnabled(!paused); - _disabledFolders.insert(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())); - connect(folder, SIGNAL(syncStarted()), SLOT(slotFolderSyncStarted())); - connect(folder, SIGNAL(syncFinished(SyncResult)), SLOT(slotFolderSyncFinished(SyncResult))); - - _folderChangeSignalMapper->setMapping( folder, folder->alias() ); - - registerFolderMonitor(folder); - return folder; -} - -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]; - if( f ) { - f->setSyncEnabled(enable); - slotScheduleSync(alias); - - // FIXME: Use MirallConfigFile - QSettings settings(_folderConfigPath + QLatin1Char('/') + f->configFile(), QSettings::IniFormat); - settings.beginGroup(escapeAlias(f->alias())); - if (enable) { - settings.remove("paused"); - _disabledFolders.remove(f); - } else { - settings.setValue("paused", true); - _disabledFolders.insert(f); - } - emit folderSyncStateChange(alias); - } -} - -// this really terminates, ie. no questions, no prisoners. -// csync still remains in a stable state, regardless of that. -void FolderMan::terminateSyncProcess( const QString& alias ) -{ - QString folderAlias = alias; - if( alias.isEmpty() ) { - folderAlias = _currentSyncFolder; - } - if( ! folderAlias.isEmpty() && _folderMap.contains(folderAlias) ) { - Folder *f = _folderMap[folderAlias]; - if( f ) { - f->slotTerminateSync(); - if(_currentSyncFolder == folderAlias ) { - _currentSyncFolder.clear(); - } - } - } -} - -Folder *FolderMan::folder( const QString& alias ) -{ - if( !alias.isEmpty() ) { - if( _folderMap.contains( alias )) { - return _folderMap[alias]; - } - } - return 0; -} - -SyncResult FolderMan::syncResult( const QString& alias ) -{ - Folder *f = folder( alias ); - return f ? f->syncResult() : SyncResult(); -} - -void FolderMan::slotScheduleAllFolders() -{ - foreach( Folder *f, _folderMap.values() ) { - if (f && f->syncEnabled()) { - slotScheduleSync( f->alias() ); - } - } -} - -/* - * 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. - */ -void FolderMan::slotScheduleSync( const QString& alias ) -{ - if( alias.isEmpty() ) return; - - if( _currentSyncFolder == alias ) { - qDebug() << " the current folder is currently syncing."; - return; - } - qDebug() << "Schedule folder " << alias << " to sync!"; - - if( ! _scheduleQueue.contains(alias ) && _folderMap.contains(alias) ) { - Folder *f = _folderMap[alias]; - if( f ) { - if( f->syncEnabled() ) { - f->prepareToSync(); - } else { - qDebug() << "Folder is not enabled, not scheduled!"; - return; - } - } - _scheduleQueue.enqueue(alias); - - } else { - qDebug() << " II> Sync for folder " << alias << " already scheduled, do not enqueue!"; - } - // wait a moment until the syncing starts - QTimer::singleShot(500, this, SLOT(slotScheduleFolderSync())); -} - -void FolderMan::setSyncEnabled( bool enabled ) -{ - if (!_syncEnabled && enabled && !_scheduleQueue.isEmpty()) { - // We have things in our queue that were waiting the the connection to go back on. - QTimer::singleShot(200, this, SLOT(slotScheduleFolderSync())); - } - _syncEnabled = enabled; - - foreach( Folder *f, _folderMap.values() ) { - if(f) { // check for f != 0. That can happen, do not remove the check! - f->setSyncEnabled(enabled && !_disabledFolders.contains(f)); - } - } -} - -/* - * 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() -{ - if( !_currentSyncFolder.isEmpty() ) { - qDebug() << "Currently folder " << _currentSyncFolder << " is running, wait for finish!"; - return; - } - - if( ! _syncEnabled ) { - qDebug() << "FolderMan: Syncing is disabled, no scheduling."; - return; - } - - qDebug() << "XX slotScheduleFolderSync: folderQueue size: " << _scheduleQueue.count(); - if( ! _scheduleQueue.isEmpty() ) { - const QString alias = _scheduleQueue.dequeue(); - if( _folderMap.contains( alias ) ) { - Folder *f = _folderMap[alias]; - if( f && f->syncEnabled() ) { - _currentSyncFolder = alias; - - f->startSync( QStringList() ); - } - } - } -} - -void FolderMan::slotFolderSyncStarted( ) -{ - qDebug() << ">===================================== sync started for " << _currentSyncFolder; -} - -/* - * a folder indicates that its syncing is finished. - * Start the next sync after the system had some milliseconds to breath. - */ -void FolderMan::slotFolderSyncFinished( const SyncResult& ) -{ - qDebug() << "<===================================== sync finished for " << _currentSyncFolder; - - _currentSyncFolder.clear(); - - QTimer::singleShot(200, this, SLOT(slotScheduleFolderSync())); -} - -void FolderMan::addFolderDefinition(const QString& alias, const QString& sourceFolder, const QString& targetPath ) -{ - QString escapedAlias = escapeAlias(alias); - // Create a settings file named after the alias - QSettings settings( _folderConfigPath + QLatin1Char('/') + escapedAlias, QSettings::IniFormat); - settings.beginGroup(escapedAlias); - settings.setValue(QLatin1String("localPath"), sourceFolder ); - settings.setValue(QLatin1String("targetPath"), targetPath ); - // for compat reasons - settings.setValue(QLatin1String("backend"), "owncloud" ); - settings.setValue(QLatin1String("connection"), Theme::instance()->appName()); - settings.sync(); -} - -Folder *FolderMan::folderForPath(const QString &path) -{ - QString absolutePath = QDir::cleanPath(path+QLatin1Char('/')); - - foreach(Folder* folder, map().values()) - { - if(absolutePath.startsWith(QDir::cleanPath(folder->path()))) - { - qDebug() << "found folder: " << folder->path() << " for " << absolutePath; - return folder; - } - } - - return 0; -} - -void FolderMan::removeAllFolderDefinitions() -{ - foreach( Folder *f, _folderMap.values() ) { - if(f) { - slotRemoveFolder( f->alias() ); - } - } - // clear the queue. - _scheduleQueue.clear(); - -} - -void FolderMan::slotRemoveFolder( const QString& alias ) -{ - if( alias.isEmpty() ) return; - - if( _currentSyncFolder == alias ) { - // terminate if the sync is currently underway. - terminateSyncProcess( alias ); - } - removeFolder(alias); -} - -// remove a folder from the map. Should be sure n -void FolderMan::removeFolder( const QString& alias ) -{ - Folder *f = 0; - - _scheduleQueue.removeAll(alias); - - if( _folderMap.contains( alias )) { - qDebug() << "Removing " << alias; - f = _folderMap.take( alias ); - } else { - qDebug() << "!! Can not remove " << alias << ", not in folderMap."; - } - - if( f ) { - f->wipe(); - - // can be removed if we are able to delete the folder object. - f->setSyncEnabled(false); - - // remove the folder configuration - QFile file( _folderConfigPath + QLatin1Char('/') + f->configFile() ); - if( file.exists() ) { - qDebug() << "Remove folder config file " << file.fileName(); - file.remove(); - } - // FIXME: this is a temporar dirty fix against a crash happening because - // the csync owncloud module still has static components. Activate the - // delete once the module is fixed. - // f->deleteLater(); - } -} - -QString FolderMan::getBackupName( const QString& fullPathName ) const -{ - if( fullPathName.isEmpty() ) return QString::null; - - QString newName = fullPathName + QLatin1String(".oC_bak"); - QFileInfo fi( newName ); - int cnt = 1; - do { - if( fi.exists() ) { - newName = fullPathName + QString( ".oC_bak_%1").arg(cnt++); - fi.setFile(newName); - } - } while( fi.exists() ); - - return newName; -} - -bool FolderMan::startFromScratch( const QString& localFolder ) -{ - if( localFolder.isEmpty() ) return false; - - QFileInfo fi( localFolder ); - if( fi.exists() && fi.isDir() ) { - QDir file = fi.dir(); - - // check if there are files in the directory. - if( file.count() == 0 ) { - // directory is existing, but its empty. Use it. - qDebug() << "startFromScratch: Directory is empty!"; - return true; - } - QString newName = getBackupName( fi.absoluteFilePath() ); - - if( file.rename( fi.absoluteFilePath(), newName )) { - if( file.mkdir( fi.absoluteFilePath() ) ) { - return true; - } - } - } - return false; -} - -void FolderMan::setDirtyProxy(bool value) -{ - foreach( Folder *f, _folderMap.values() ) { - if(f) { - f->setProxyDirty(value); - } - } -} - -void FolderMan::setDirtyNetworkLimits() -{ - foreach( Folder *f, _folderMap.values() ) { - // set only in busy folders. Otherwise they read the config anyway. - if(f && f->isBusy()) { - f->setDirtyNetworkLimits(); - } - } - -} - -SyncResult FolderMan::accountStatus(const QList<Folder*> &folders) -{ - SyncResult overallResult(SyncResult::Undefined); - - int cnt = folders.count(); - - // if one folder: show the state of the one folder. - // if more folder: - // if one of them has an error -> show error - // if one is paused, but others ok, show ok - // do not show "problem" in the tray - // - if( cnt == 1 ) { - Folder *folder = folders.at(0); - if( folder ) { - SyncResult::Status syncStatus = folder->syncResult().status(); - - switch( syncStatus ) { - case SyncResult::Undefined: - overallResult.setStatus(SyncResult::Error); - break; - case SyncResult::NotYetStarted: - overallResult.setStatus( SyncResult::NotYetStarted ); - break; - case SyncResult::SyncPrepare: - overallResult.setStatus( SyncResult::SyncPrepare ); - break; - case SyncResult::SyncRunning: - overallResult.setStatus( SyncResult::SyncRunning ); - break; - case SyncResult::Unavailable: - overallResult.setStatus( SyncResult::Unavailable ); - break; - case SyncResult::Problem: // don't show the problem icon in tray. - case SyncResult::Success: - if( overallResult.status() == SyncResult::Undefined ) - overallResult.setStatus( SyncResult::Success ); - break; - case SyncResult::Error: - overallResult.setStatus( SyncResult::Error ); - break; - case SyncResult::SetupError: - if ( overallResult.status() != SyncResult::Error ) - overallResult.setStatus( SyncResult::SetupError ); - break; - case SyncResult::SyncAbortRequested: - overallResult.setStatus( SyncResult::SyncAbortRequested); - break; - case SyncResult::Paused: - overallResult.setStatus( SyncResult::Paused); - break; - } - } - } else { - int errorsSeen = 0; - int goodSeen = 0; - int abortSeen = 0; - int runSeen = 0; - int various = 0; - int unavail = 0; - - foreach ( Folder *folder, folders ) { - SyncResult folderResult = folder->syncResult(); - SyncResult::Status syncStatus = folderResult.status(); - - switch( syncStatus ) { - case SyncResult::Undefined: - case SyncResult::NotYetStarted: - case SyncResult::SyncPrepare: - various++; - break; - case SyncResult::SyncRunning: - runSeen++; - break; - case SyncResult::Unavailable: - unavail++; - break; - case SyncResult::Problem: // don't show the problem icon in tray. - case SyncResult::Success: - goodSeen++; - break; - case SyncResult::Error: - case SyncResult::SetupError: - errorsSeen++; - break; - case SyncResult::SyncAbortRequested: - case SyncResult::Paused: - abortSeen++; - // no default case on purpose, check compiler warnings - } - } - bool set = false; - if( errorsSeen > 0 ) { - overallResult.setStatus(SyncResult::Error); - set = true; - } - if( !set && abortSeen > 0 && abortSeen == cnt ) { - // only if all folders are paused - overallResult.setStatus(SyncResult::Paused); - set = true; - } - if( !set && runSeen > 0 ) { - overallResult.setStatus(SyncResult::SyncRunning); - set = true; - } - if( !set && goodSeen > 0 ) { - overallResult.setStatus(SyncResult::Success); - set = true; - } - } - - return overallResult; -} - -QString FolderMan::statusToString( SyncResult syncStatus, bool enabled ) const -{ - QString folderMessage; - switch( syncStatus.status() ) { - case SyncResult::Undefined: - folderMessage = tr( "Undefined State." ); - break; - case SyncResult::NotYetStarted: - folderMessage = tr( "Waits to start syncing." ); - break; - case SyncResult::SyncPrepare: - folderMessage = tr( "Preparing for sync." ); - break; - case SyncResult::SyncRunning: - folderMessage = tr( "Sync is running." ); - break; - case SyncResult::Unavailable: - folderMessage = tr( "Server is currently not available." ); - break; - case SyncResult::Success: - folderMessage = tr( "Last Sync was successful." ); - break; - case SyncResult::Error: - break; - case SyncResult::Problem: - folderMessage = tr( "Last Sync was successful, but with warnings on individual files."); - break; - case SyncResult::SetupError: - folderMessage = tr( "Setup Error." ); - break; - case SyncResult::SyncAbortRequested: - folderMessage = tr( "User Abort." ); - break; - case SyncResult::Paused: - folderMessage = tr("Sync is paused."); - break; - // no default case on purpose, check compiler warnings - } - if( !enabled ) { - // sync is disabled. - folderMessage = tr( "%1 (Sync is paused)" ).arg(folderMessage); - } - return folderMessage; -} - -} // namespace Mirall diff --git a/src/mirall/folderman.h b/src/mirall/folderman.h deleted file mode 100644 index 82f69701d..000000000 --- a/src/mirall/folderman.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * 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. - */ - - -#ifndef FOLDERMAN_H -#define FOLDERMAN_H - -#include <QObject> -#include <QQueue> -#include <QList> - -#include "mirall/folder.h" -#include "mirall/folderwatcher.h" -#include "mirall/syncfileitem.h" - -class QSignalMapper; - -class SyncResult; - -namespace Mirall { - -class Application; - -class FolderMan : public QObject -{ - Q_OBJECT -public: - static FolderMan* instance(); - - int setupFolders(); - - Mirall::Folder::Map map(); - - /** - * Add a folder definition to the config - * Params: - * QString alias - * QString sourceFolder on local machine - * QString targetPath on remote - */ - void addFolderDefinition(const QString&, const QString&, const QString& ); - - /** Returns the folder which the file or directory stored in path is in */ - Folder* folderForPath(const QString& path); - - /** Returns the folder by alias or NULL if no folder with the alias exists. */ - Folder *folder( const QString& ); - - /** Returns the last sync result by alias */ - SyncResult syncResult( const QString& ); - - /** Creates a folder for a specific configuration, identified by alias. */ - Folder* setupFolderFromConfigFile(const QString & ); - - /** Wipes all folder defintions. No way back! */ - void removeAllFolderDefinitions(); - - /** - * Ensures that a given directory does not contain a .csync_journal. - * - * @returns false if the journal could not be removed, true otherwise. - */ - static bool ensureJournalGone(const QString &path); - - /** Creates a new and empty local directory. */ - bool startFromScratch( const QString& ); - - QString statusToString( SyncResult, bool enabled ) const; - - static SyncResult accountStatus( const QList<Folder*> &folders ); - - void removeMonitorPath( const QString& alias, const QString& path ); - void addMonitorPath( const QString& alias, const QString& path ); - -signals: - /** - * signal to indicate a folder named by alias has changed its sync state. - * Get the state via the Folder Map or the syncResult and syncState methods. - */ - void folderSyncStateChange( const QString & ); - - void folderListLoaded(const Folder::Map &); - -public slots: - void slotRemoveFolder( const QString& ); - void slotEnableFolder( const QString&, bool ); - - void slotFolderSyncStarted(); - void slotFolderSyncFinished( const SyncResult& ); - - void terminateSyncProcess( const QString& alias = QString::null ); - - /* delete all folder objects */ - int unloadAllFolders(); - - // if enabled is set to false, no new folders will start to sync. - // the current one will finish. - void setSyncEnabled( bool ); - - void slotScheduleAllFolders(); - - void setDirtyProxy(bool value = true); - void setDirtyNetworkLimits(); - - // slot to add a folder to the syncing queue - void slotScheduleSync( const QString & ); - -private slots: - - // slot to take the next folder from queue and start syncing. - void slotScheduleFolderSync(); - -private: - // finds all folder configuration files - // and create the folders - void terminateCurrentSync(); - QString getBackupName( const QString& ) const; - void registerFolderMonitor( Folder *folder ); - - // Escaping of the alias which is used in QSettings AND the file - // system, thus need to be escaped. - QString escapeAlias( const QString& ) const; - QString unescapeAlias( const QString& ) const; - - void removeFolder( const QString& ); - - QSet<Folder*> _disabledFolders; - Folder::Map _folderMap; - QString _folderConfigPath; - QSignalMapper *_folderChangeSignalMapper; - QSignalMapper *_folderWatcherSignalMapper; - QString _currentSyncFolder; - bool _syncEnabled; - QQueue<QString> _scheduleQueue; - QMap<QString, FolderWatcher*> _folderWatchers; - - static FolderMan *_instance; - explicit FolderMan(QObject *parent = 0); - ~FolderMan(); - friend class Mirall::Application; -}; - -} // namespace Mirall -#endif // FOLDERMAN_H diff --git a/src/mirall/folderstatusmodel.cpp b/src/mirall/folderstatusmodel.cpp deleted file mode 100644 index b94239a35..000000000 --- a/src/mirall/folderstatusmodel.cpp +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright (C) by Klaas Freitag <freitag@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. - */ - -#include "mirall/folderstatusmodel.h" -#include "mirall/utility.h" - -#include <QtCore> -#include <QtGui> -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) -#include <QtWidgets> -#endif - -namespace Mirall { - -FolderStatusModel::FolderStatusModel() - :QStandardItemModel() -{ - -} - -Qt::ItemFlags FolderStatusModel::flags ( const QModelIndex& ) const -{ - return Qt::ItemIsSelectable | Qt::ItemIsEnabled; -} - -QVariant FolderStatusModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - if (role == Qt::EditRole) - return QVariant(); - else - return QStandardItemModel::data(index,role); -} - -// ==================================================================================== - -FolderStatusDelegate::FolderStatusDelegate() - :QStyledItemDelegate() -{ - -} - -FolderStatusDelegate::~FolderStatusDelegate() -{ - // TODO Auto-generated destructor stub -} - -//alocate each item size in listview. -QSize FolderStatusDelegate::sizeHint(const QStyleOptionViewItem & option , - const QModelIndex & index) const -{ - Q_UNUSED(option) - QFont aliasFont = option.font; - QFont font = option.font; - aliasFont.setPointSize( font.pointSize() +2 ); - - QFontMetrics fm(font); - QFontMetrics aliasFm(aliasFont); - - int aliasMargin = aliasFm.height()/2; - int margin = fm.height()/4; - - // calc height - - int h = aliasMargin; // margin to top - h += aliasFm.height(); // alias - h += margin; // between alias and local path - h += fm.height(); // local path - h += margin; // between local and remote path - h += fm.height(); // remote path - h += aliasMargin; // bottom margin - - // add some space to show an error condition. - if( ! qvariant_cast<QStringList>(index.data(FolderErrorMsg)).isEmpty() ) { - QStringList errMsgs = qvariant_cast<QStringList>(index.data(FolderErrorMsg)); - h += aliasMargin*2 + errMsgs.count()*fm.height(); - } - - if( qvariant_cast<bool>(index.data(AddProgressSpace)) ) { - int margin = fm.height()/4; - h += (5 * margin); // All the margins - h += 2* fm.boundingRect(tr("File")).height(); - } - - return QSize( 0, h); -} - -void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const -{ - QStyledItemDelegate::paint(painter,option,index); - - painter->save(); - - QFont aliasFont = option.font; - QFont subFont = option.font; - QFont errorFont = subFont; - QFont progressFont = subFont; - - progressFont.setPointSize( subFont.pointSize()-2); - //font.setPixelSize(font.weight()+); - aliasFont.setBold(true); - aliasFont.setPointSize( subFont.pointSize()+2 ); - - QFontMetrics subFm( subFont ); - QFontMetrics aliasFm( aliasFont ); - QFontMetrics progressFm( progressFont ); - - int aliasMargin = aliasFm.height()/2; - int margin = subFm.height()/4; - - QIcon statusIcon = qvariant_cast<QIcon>(index.data(FolderStatusIconRole)); - QString aliasText = qvariant_cast<QString>(index.data(FolderAliasRole)); - QString pathText = qvariant_cast<QString>(index.data(FolderPathRole)); - QString remotePath = qvariant_cast<QString>(index.data(FolderSecondPathRole)); - QStringList errorTexts= qvariant_cast<QStringList>(index.data(FolderErrorMsg)); - - int overallPercent = qvariant_cast<int>(index.data(SyncProgressOverallPercent)); - QString overallString = qvariant_cast<QString>(index.data(SyncProgressOverallString)); - QString itemString = qvariant_cast<QString>(index.data(SyncProgressItemString)); - int warningCount = qvariant_cast<int>(index.data(WarningCount)); - bool syncOngoing = qvariant_cast<bool>(index.data(SyncRunning)); - // QString statusText = qvariant_cast<QString>(index.data(FolderStatus)); - bool syncEnabled = index.data(FolderSyncEnabled).toBool(); - // QString syncStatus = syncEnabled? tr( "Enabled" ) : tr( "Disabled" ); - - QRect iconRect = option.rect; - QRect aliasRect = option.rect; - - iconRect.setLeft( aliasMargin ); - iconRect.setTop( iconRect.top() + aliasMargin ); // (iconRect.height()-iconsize.height())/2); - - // alias box - aliasRect.setTop(aliasRect.top() + aliasMargin ); - aliasRect.setBottom(aliasRect.top() + aliasFm.height()); - aliasRect.setRight(aliasRect.right() - aliasMargin ); - - // remote directory box - QRect remotePathRect = aliasRect; - remotePathRect.setTop(aliasRect.bottom() + margin ); - remotePathRect.setBottom(remotePathRect.top() + subFm.height()); - - // local directory box - QRect localPathRect = remotePathRect; - localPathRect.setTop( remotePathRect.bottom() + margin ); - localPathRect.setBottom( localPathRect.top() + subFm.height()); - - iconRect.setBottom(localPathRect.bottom()); - iconRect.setWidth(iconRect.height()); - - int nextToIcon = iconRect.right()+aliasMargin; - aliasRect.setLeft(nextToIcon); - localPathRect.setLeft(nextToIcon); - remotePathRect.setLeft(nextToIcon); - - int iconSize = iconRect.width(); - - QPixmap pm = statusIcon.pixmap(iconSize, iconSize, syncEnabled ? QIcon::Normal : QIcon::Disabled ); - painter->drawPixmap(QPoint(iconRect.left(), iconRect.top()), pm); - - // only show the warning icon if the sync is running. Otherwise its - // encoded in the status icon. - if( warningCount > 0 && syncOngoing) { - QRect warnRect; - warnRect.setLeft(iconRect.left()); - warnRect.setTop(iconRect.bottom()-17); - warnRect.setWidth(16); - warnRect.setHeight(16); - - QIcon warnIcon(":/mirall/resources/warning-16"); - QPixmap pm = warnIcon.pixmap(16,16, syncEnabled ? QIcon::Normal : QIcon::Disabled ); - painter->drawPixmap(QPoint(warnRect.left(), warnRect.top()),pm ); - } - - if ((option.state & QStyle::State_Selected) - && (option.state & QStyle::State_Active) - // Hack: Windows Vista's light blue is not contrasting enough for white - && !qApp->style()->inherits("QWindowsVistaStyle")) { - painter->setPen(option.palette.color(QPalette::HighlightedText)); - } else { - painter->setPen(option.palette.color(QPalette::Text)); - } - QString elidedAlias = aliasFm.elidedText(aliasText, Qt::ElideRight, aliasRect.width()); - painter->setFont(aliasFont); - painter->drawText(aliasRect, elidedAlias); - - painter->setFont(subFont); - QString elidedRemotePathText; - - if (remotePath.isEmpty() || remotePath == QLatin1String("/")) { - elidedRemotePathText = subFm.elidedText(tr("Syncing all files in your account with"), - Qt::ElideRight, remotePathRect.width()); - } else { - elidedRemotePathText = subFm.elidedText(tr("Remote path: %1").arg(remotePath), - Qt::ElideMiddle, remotePathRect.width()); - } - painter->drawText(remotePathRect, elidedRemotePathText); - - QString elidedPathText = subFm.elidedText(pathText, Qt::ElideMiddle, localPathRect.width()); - painter->drawText(localPathRect, elidedPathText); - - // paint an error overlay if there is an error string - - int h = iconRect.bottom(); - if( !errorTexts.isEmpty() ) { - h += aliasMargin; - QRect errorRect = localPathRect; - errorRect.setLeft( iconRect.left()); - errorRect.setTop( h ); - errorRect.setHeight(errorTexts.count() * subFm.height()+aliasMargin); - errorRect.setRight( option.rect.right()-aliasMargin ); - - painter->setBrush( QColor(0xbb, 0x4d, 0x4d) ); - painter->setPen( QColor(0xaa, 0xaa, 0xaa)); - painter->drawRoundedRect( errorRect, 4, 4 ); - - painter->setPen( Qt::white ); - painter->setFont(errorFont); - QRect errorTextRect = errorRect; - errorTextRect.setLeft( errorTextRect.left()+aliasMargin ); - errorTextRect.setTop( errorTextRect.top()+aliasMargin/2 ); - - int x = errorTextRect.left(); - int y = errorTextRect.top()+aliasMargin/2 + subFm.height()/2; - - foreach( QString eText, errorTexts ) { - painter->drawText(x, y, subFm.elidedText( eText, Qt::ElideLeft, errorTextRect.width()-2*aliasMargin)); - y += subFm.height(); - } - - h = errorRect.bottom(); - } - h += aliasMargin; - - // Sync File Progress Bar: Show it if syncFile is not empty. - if( !overallString.isEmpty()) { - int fileNameTextHeight = subFm.boundingRect(tr("File")).height(); - int barHeight = qMax(fileNameTextHeight, aliasFm.height()+4); ; - int overallWidth = option.rect.width()-2*aliasMargin; - - painter->save(); - - // Sizes-Text - QRect octetRect = progressFm.boundingRect( overallString ); - int progressTextWidth = octetRect.width() + 2; - - // Overall Progress Bar. - QRect pBRect; - pBRect.setTop( h ); - pBRect.setLeft( iconRect.left()); - pBRect.setHeight(barHeight); - pBRect.setWidth( overallWidth - progressTextWidth - margin ); - - QStyleOptionProgressBarV2 pBarOpt; - - pBarOpt.state = option.state | QStyle::State_Horizontal; - pBarOpt.minimum = 0; - pBarOpt.maximum = 100; - pBarOpt.progress = overallPercent; - pBarOpt.orientation = Qt::Horizontal; - pBarOpt.palette = option.palette; - pBarOpt.rect = pBRect; - - QApplication::style()->drawControl( QStyle::CE_ProgressBar, &pBarOpt, painter ); - - // Overall Progress Text - QRect overallProgressRect; - overallProgressRect.setTop( pBRect.top() ); - overallProgressRect.setHeight( pBRect.height() ); - overallProgressRect.setLeft( pBRect.right()+margin); - overallProgressRect.setWidth( progressTextWidth ); - painter->setFont(progressFont); - - painter->drawText( overallProgressRect, Qt::AlignRight+Qt::AlignVCenter, overallString); - // painter->drawRect(overallProgressRect); - - // Individual File Progress - QRect fileRect; - fileRect.setTop( pBRect.bottom() + margin); - fileRect.setLeft( iconRect.left()); - fileRect.setWidth(overallWidth); - fileRect.setHeight(fileNameTextHeight); - QString elidedText = progressFm.elidedText(itemString, Qt::ElideLeft, fileRect.width()); - - painter->drawText( fileRect, Qt::AlignLeft+Qt::AlignVCenter, elidedText); - - painter->restore(); - } - painter->restore(); -} - -bool FolderStatusDelegate::editorEvent ( QEvent * /*event*/, QAbstractItemModel * /*model*/, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/ ) -{ - return false; -} - -} // namespace Mirall diff --git a/src/mirall/folderstatusmodel.h b/src/mirall/folderstatusmodel.h deleted file mode 100644 index 74acaa08a..000000000 --- a/src/mirall/folderstatusmodel.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) by Klaas Freitag <freitag@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 FOLDERSTATUSMODEL_H -#define FOLDERSTATUSMODEL_H - -#include <QStyledItemDelegate> -#include <QStandardItemModel> - -namespace Mirall { - -class FolderStatusModel : public QStandardItemModel -{ -public: - FolderStatusModel(); - virtual Qt::ItemFlags flags( const QModelIndex& ) const Q_DECL_OVERRIDE; - QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; - -}; - -class FolderStatusDelegate : public QStyledItemDelegate -{ - Q_OBJECT - public: - FolderStatusDelegate(); - virtual ~FolderStatusDelegate(); - - enum datarole { FolderAliasRole = Qt::UserRole + 100, - FolderPathRole, - FolderSecondPathRole, - FolderRemotePath, - FolderStatus, - FolderErrorMsg, - FolderSyncEnabled, - FolderStatusIconRole, - - SyncProgressOverallPercent, - SyncProgressOverallString, - SyncProgressItemString, - AddProgressSpace, - WarningCount, - SyncRunning - }; - void paint( QPainter*, const QStyleOptionViewItem&, const QModelIndex& ) const Q_DECL_OVERRIDE; - QSize sizeHint( const QStyleOptionViewItem&, const QModelIndex& ) const Q_DECL_OVERRIDE; - bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, - const QModelIndex& index ) Q_DECL_OVERRIDE; -}; - -} // namespace Mirall - -#endif // FOLDERSTATUSMODEL_H diff --git a/src/mirall/folderwatcher.cpp b/src/mirall/folderwatcher.cpp deleted file mode 100644 index 7813a1e7f..000000000 --- a/src/mirall/folderwatcher.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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. - */ - -// event masks -#include "mirall/folderwatcher.h" - -#include <stdint.h> - -#include <QFileInfo> -#include <QFlags> -#include <QDebug> -#include <QDir> -#include <QMutexLocker> -#include <QStringList> -#include <QTimer> - -#if defined(Q_OS_WIN) -#include "mirall/folderwatcher_win.h" -#elif defined(Q_OS_MAC) -#include "mirall/folderwatcher_mac.h" -#elif defined(Q_OS_UNIX) -#include "mirall/folderwatcher_linux.h" -#endif - - -namespace Mirall { - -FolderWatcher::FolderWatcher(const QString &root, QObject *parent) - : QObject(parent) -{ - _d.reset(new FolderWatcherPrivate(this, root)); - - _timer.start(); -} - -FolderWatcher::~FolderWatcher() -{ } - -void FolderWatcher::addIgnoreListFile( const QString& file ) -{ - if( file.isEmpty() ) return; - - QFile infile( file ); - if (!infile.open(QIODevice::ReadOnly | QIODevice::Text)) - return; - - while (!infile.atEnd()) { - QString line = QString::fromLocal8Bit( infile.readLine() ).trimmed(); - if( !(line.startsWith( QLatin1Char('#') ) || line.isEmpty()) ) { - _ignores.append(line); - } - } -} - -QStringList FolderWatcher::ignores() const -{ - return _ignores; -} - -bool FolderWatcher::pathIsIgnored( const QString& path ) -{ - if( path.isEmpty() ) return true; - - // Remember: here only directories are checked! - // If that changes to files too at some day, remember to check - // for the database name as well as the trailing slash rule for - // dirs only. Best use csync_ignore than somehow. - foreach (QString pattern, _ignores) { - QRegExp regexp(pattern); - regexp.setPatternSyntax(QRegExp::Wildcard); - - QFileInfo fInfo(path); - if( fInfo.isHidden() ) { - qDebug() << "* Discarded as is hidden!"; - return true; - } - - if(pattern.endsWith('/')) { - // directory only pattern. But since only dirs here, we cut off the trailing dir. - pattern.remove(pattern.length()-1, 1); // remove the last char. - } - // if the pattern contains / it needs to match the entire path - if (pattern.contains('/') && regexp.exactMatch(path)) { - qDebug() << "* Discarded by ignore pattern: " << path; - return true; - } - - QStringList components = path.split('/'); - foreach (const QString& comp, components) { - if(regexp.exactMatch(comp)) { - qDebug() << "* Discarded by component ignore pattern " << comp; - return true; - } - } - } - return false; -} - -void FolderWatcher::changeDetected( const QString& path ) -{ - QStringList paths(path); - changeDetected(paths); -} - -void FolderWatcher::changeDetected( const QStringList& paths ) -{ - // qDebug() << Q_FUNC_INFO << paths; - - // TODO: this shortcut doesn't look very reliable: - // - why is the timeout only 1 second? - // - what if there are more than one file being updated frequently? - // - why do we skip the file alltogether instead of e.g. reducing the upload frequency? - - // Check if the same path was reported within the last second. - QSet<QString> pathsSet = paths.toSet(); - if( pathsSet == _lastPaths && _timer.elapsed() < 1000 ) { - // the same path was reported within the last second. Skip. - return; - } - _lastPaths = pathsSet; - _timer.restart(); - - QSet<QString> changedFolders; - - // ------- handle ignores: - for (int i = 0; i < paths.size(); ++i) { - QString path = paths[i]; - if( pathIsIgnored(path) ) { - continue; - } - - QFileInfo fi(path); - if (fi.isDir()) { - changedFolders.insert(path); - } else { - changedFolders.insert(fi.dir().path()); - } - } - if (changedFolders.isEmpty()) { - return; - } - - qDebug() << "detected changes in folders:" << changedFolders; - foreach (const QString &path, changedFolders) { - emit folderChanged(path); - } -} - -void FolderWatcher::addPath(const QString &path ) -{ - _d->addPath(path); -} - -void FolderWatcher::removePath(const QString &path ) -{ - _d->removePath(path); -} - - -} // namespace Mirall - diff --git a/src/mirall/folderwatcher.h b/src/mirall/folderwatcher.h deleted file mode 100644 index bcdb5f0ee..000000000 --- a/src/mirall/folderwatcher.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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_FOLDERWATCHER_H -#define MIRALL_FOLDERWATCHER_H - -#include "config.h" - -#include <QList> -#include <QObject> -#include <QString> -#include <QStringList> -#include <QTime> -#include <QHash> -#include <QScopedPointer> -#include <QSet> - -class QTimer; - -namespace Mirall { - -class FolderWatcherPrivate; - -/* - * Folder Watcher monitors a directory and its sub directories - * for changes in the local file system. Changes are signalled - * through the folderChanged() signal. - * - * Note that if new folders are created, this folderwatcher class - * does not automatically adds them to the list of monitored - * dirs. That is the responsibility of the user of this class to - * call addPath() with the new dir. - */ - -class FolderWatcher : public QObject -{ - Q_OBJECT -public: - /** - * @param root Path of the root of the folder - */ - FolderWatcher(const QString &root, QObject *parent = 0L); - virtual ~FolderWatcher(); - - /** - * Set a file name to load a file with ignore patterns. - * - * Valid entries do not start with a hash sign (#) - * and may contain wildcards - */ - void addIgnoreListFile( const QString& ); - - QStringList ignores() const; - - /** - * Not all backends are recursive by default. - * Those need to be notified when a directory is added or removed while the watcher is disabled. - * This is a no-op for backend that are recursive - */ - void addPath(const QString&); - void removePath(const QString&); - - /* Check if the path is ignored. */ - bool pathIsIgnored( const QString& path ); - -signals: - /** Emitted when one of the paths is changed */ - void folderChanged(const QString &path); - - /** Emitted if an error occurs */ - void error(const QString& error); - -protected slots: - // called from the implementations to indicate a change in path - void changeDetected( const QString& path); - void changeDetected( const QStringList& paths); - -protected: - QHash<QString, int> _pendingPathes; - -private: - QScopedPointer<FolderWatcherPrivate> _d; - QStringList _ignores; - QTime _timer; - QSet<QString> _lastPaths; - - friend class FolderWatcherPrivate; -}; - -} - -#endif diff --git a/src/mirall/folderwatcher_linux.cpp b/src/mirall/folderwatcher_linux.cpp deleted file mode 100644 index c44fdd622..000000000 --- a/src/mirall/folderwatcher_linux.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 "config.h" - -#include <sys/inotify.h> - -#include "mirall/folder.h" -#include "mirall/folderwatcher_linux.h" - -#include <cerrno> -#include <QDebug> -#include <QStringList> -#include <QObject> -#include <QVarLengthArray> - -namespace Mirall { - -FolderWatcherPrivate::FolderWatcherPrivate(FolderWatcher *p, const QString& path) - : QObject(), - _parent(p), - _folder(path) -{ - _fd = inotify_init(); - if (_fd != -1) { - _socket.reset( new QSocketNotifier(_fd, QSocketNotifier::Read) ); - connect(_socket.data(), SIGNAL(activated(int)), SLOT(slotReceivedNotification(int))); - } else { - qDebug() << Q_FUNC_INFO << "notify_init() failed: " << strerror(errno); - } - - QMetaObject::invokeMethod(this, "slotAddFolderRecursive", Q_ARG(QString, path)); - -} - -FolderWatcherPrivate::~FolderWatcherPrivate() -{ - -} - -// attention: result list passed by reference! -bool FolderWatcherPrivate::findFoldersBelow( const QDir& dir, QStringList& fullList ) -{ - bool ok = true; - if( !(dir.exists() && dir.isReadable()) ) { - qDebug() << "Non existing path coming in: " << dir.absolutePath(); - ok = false; - } else { - QStringList nameFilter; - nameFilter << QLatin1String("*"); - QDir::Filters filter = QDir::Dirs | QDir::NoDotAndDotDot|QDir::NoSymLinks; - const QStringList pathes = dir.entryList(nameFilter, filter); - - QStringList::const_iterator constIterator; - for (constIterator = pathes.constBegin(); constIterator != pathes.constEnd(); - ++constIterator) { - const QString fullPath(dir.path()+QLatin1String("/")+(*constIterator)); - fullList.append(fullPath); - ok = findFoldersBelow(QDir(fullPath), fullList); - } - } - - return ok; -} - -void FolderWatcherPrivate::inotifyRegisterPath(const QString& path) -{ - if( !path.isEmpty()) { - int wd = inotify_add_watch(_fd, path.toUtf8().constData(), - IN_CLOSE_WRITE | IN_ATTRIB | IN_MOVE | - IN_CREATE |IN_DELETE | IN_DELETE_SELF | - IN_MOVE_SELF |IN_UNMOUNT |IN_ONLYDIR | - IN_DONT_FOLLOW ); - if( wd > -1 ) { - _watches.insert(wd, path); - } - } -} - -void FolderWatcherPrivate::slotAddFolderRecursive(const QString &path) -{ - int subdirs = 0; - qDebug() << "(+) Watcher:" << path; - - QDir inPath(path); - inotifyRegisterPath(inPath.absolutePath()); - - const QStringList watchedFolders = _watches.values(); - - QStringList allSubfolders; - if( !findFoldersBelow(QDir(path), allSubfolders)) { - qDebug() << "Could not traverse all sub folders"; - } - // qDebug() << "currently watching " << watchedFolders; - QStringListIterator subfoldersIt(allSubfolders); - while (subfoldersIt.hasNext()) { - QString subfolder = subfoldersIt.next(); - // qDebug() << " (**) subfolder: " << subfolder; - QDir folder (subfolder); - if (folder.exists() && !watchedFolders.contains(folder.absolutePath())) { - subdirs++; - if( _parent->pathIsIgnored(subfolder) ) { - qDebug() << "* Not adding" << folder.path(); - continue; - } - inotifyRegisterPath(folder.absolutePath()); - } else { - qDebug() << " `-> discarded:" << folder.path(); - } - } - - if (subdirs >0) { - qDebug() << " `-> and" << subdirs << "subdirectories"; - } -} - -void FolderWatcherPrivate::slotReceivedNotification(int fd) -{ - int len; - struct inotify_event* event; - int i; - int error; - QVarLengthArray<char, 2048> buffer(2048); - - do { - len = read(fd, buffer.data(), buffer.size()); - error = errno; - /** - * From inotify documentation: - * - * The behavior when the buffer given to read(2) is too - * small to return information about the next event - * depends on the kernel version: in kernels before 2.6.21, - * read(2) returns 0; since kernel 2.6.21, read(2) fails with - * the error EINVAL. - */ - if (len < 0 && error == EINVAL) - { - // double the buffer size - buffer.resize(buffer.size() * 2); - /* and try again ... */ - continue; - } - } while (false); - - // reset counter - i = 0; - // while there are enough events in the buffer - while(i + sizeof(struct inotify_event) < static_cast<unsigned int>(len)) { - // cast an inotify_event - event = (struct inotify_event*)&buffer[i]; - // with the help of watch descriptor, retrieve, corresponding INotify - if (event == NULL) { - qDebug() << "NULL event"; - i += sizeof(struct inotify_event); - continue; - } - - // fire event - // Note: The name of the changed file and stuff could be taken from - // the event data structure. That does not happen yet. - if (event->len > 0 && event->wd > -1) { - // qDebug() << Q_FUNC_INFO << event->name; - if (QByteArray(event->name).startsWith(".csync") || - QByteArray(event->name).startsWith(".owncloudsync.log")) { - // qDebug() << "ignore journal"; - } else { - const QString p = _watches[event->wd]; - _parent->changeDetected(p); - } - } - - // increment counter - i += sizeof(struct inotify_event) + event->len; - } - -} - -void FolderWatcherPrivate::addPath(const QString& path) -{ - slotAddFolderRecursive(path); -} - -void FolderWatcherPrivate::removePath(const QString& path) -{ - int wid = -1; - // Remove the inotify watch. - QHash<int, QString>::const_iterator i = _watches.constBegin(); - - while (i != _watches.constEnd()) { - if( i.value() == path ) { - wid = i.key(); - break; - } - ++i; - } - if( wid > -1 ) { - inotify_rm_watch(_fd, wid); - _watches.remove(wid); - } -} - -} // ns mirall diff --git a/src/mirall/folderwatcher_linux.h b/src/mirall/folderwatcher_linux.h deleted file mode 100644 index f033a92c6..000000000 --- a/src/mirall/folderwatcher_linux.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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_FOLDERWATCHER_LINUX_H -#define MIRALL_FOLDERWATCHER_LINUX_H - -#include <QObject> -#include <QString> -#include <QSocketNotifier> -#include <QHash> -#include <QDir> - -#include "mirall/folderwatcher.h" - -namespace Mirall -{ -class FolderWatcherPrivate : public QObject -{ - Q_OBJECT -public: - FolderWatcherPrivate() { } - FolderWatcherPrivate(FolderWatcher *p, const QString &path); - ~FolderWatcherPrivate(); - - void addPath(const QString &path); - void removePath(const QString &); - -protected slots: - void slotReceivedNotification(int fd); - void slotAddFolderRecursive(const QString &path); - -protected: - bool findFoldersBelow( const QDir& dir, QStringList& fullList ); - void inotifyRegisterPath(const QString& path); - -private: - FolderWatcher *_parent; - - QString _folder; - QHash <int, QString> _watches; - QScopedPointer<QSocketNotifier> _socket; - int _fd; -}; - -} - -#endif diff --git a/src/mirall/folderwatcher_mac.cpp b/src/mirall/folderwatcher_mac.cpp deleted file mode 100644 index abeec707c..000000000 --- a/src/mirall/folderwatcher_mac.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) by Markus Goetz <markus@woboq.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; version 2 of the License. - * - * 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 "config.h" - -#include "mirall/folder.h" -#include "mirall/folderwatcher.h" -#include "mirall/folderwatcher_mac.h" - - -#include <cerrno> -#include <QDebug> -#include <QStringList> - - - -namespace Mirall { - -FolderWatcherPrivate::FolderWatcherPrivate(FolderWatcher *p, const QString& path) - : _parent(p), - _folder(path) -{ - this->startWatching(); -} - -FolderWatcherPrivate::~FolderWatcherPrivate() -{ - FSEventStreamStop(_stream); - FSEventStreamInvalidate(_stream); - FSEventStreamRelease(_stream); -} - -static void callback( - ConstFSEventStreamRef streamRef, - void *clientCallBackInfo, - size_t numEvents, - void *eventPathsVoid, - const FSEventStreamEventFlags eventFlags[], - const FSEventStreamEventId eventIds[]) -{ - qDebug() << "FolderWatcherPrivate::callback by OS X"; - - QStringList paths; - CFArrayRef eventPaths = (CFArrayRef)eventPathsVoid; - for (int i = 0; i < numEvents; ++i) { - CFStringRef path = reinterpret_cast<CFStringRef>(CFArrayGetValueAtIndex(eventPaths, i)); - - QString qstring; - CFIndex pathLength = CFStringGetLength(path); - qstring.resize(pathLength); - CFStringGetCharacters(path, CFRangeMake(0, pathLength), reinterpret_cast<UniChar *>(qstring.data())); - - paths.append(qstring); - } - - reinterpret_cast<FolderWatcherPrivate*>(clientCallBackInfo)->doNotifyParent(paths); -} - -void FolderWatcherPrivate::startWatching() -{ - qDebug() << "FolderWatcherPrivate::startWatching()" << _folder; - CFStringRef folderCF = CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar *>(_folder.unicode()), - _folder.length()); - CFArrayRef pathsToWatch = CFStringCreateArrayBySeparatingStrings (NULL, folderCF, CFSTR(":")); - - FSEventStreamContext ctx = {0, this, NULL, NULL, NULL}; - - // TODO: Add kFSEventStreamCreateFlagFileEvents ? - - _stream = FSEventStreamCreate(NULL, - &callback, - &ctx, - pathsToWatch, - kFSEventStreamEventIdSinceNow, - 0, // latency - kFSEventStreamCreateFlagUseCFTypes|kFSEventStreamCreateFlagFileEvents|kFSEventStreamCreateFlagIgnoreSelf - ); - - CFRelease(pathsToWatch); - FSEventStreamScheduleWithRunLoop(_stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - FSEventStreamStart(_stream); -} - -void FolderWatcherPrivate::doNotifyParent(const QStringList &paths) { - - _parent->changeDetected(paths); -} - - - -} // ns mirall diff --git a/src/mirall/folderwatcher_mac.h b/src/mirall/folderwatcher_mac.h deleted file mode 100644 index c2e3821d2..000000000 --- a/src/mirall/folderwatcher_mac.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) by Markus Goetz <markus@woboq.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; version 2 of the License. - * - * 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_FOLDERWATCHER_MAC_H -#define MIRALL_FOLDERWATCHER_MAC_H - -#include <QObject> -#include <QString> - -#include <CoreServices/CoreServices.h> - - -namespace Mirall -{ - -class FolderWatcherPrivate -{ -public: - - FolderWatcherPrivate(FolderWatcher *p, const QString &path); - ~FolderWatcherPrivate(); - - void addPath(const QString &) {} - void removePath(const QString &) {} - - void startWatching(); - void doNotifyParent(const QStringList &); - -private: - FolderWatcher *_parent; - - QString _folder; - - FSEventStreamRef _stream; -}; - -} - -#endif diff --git a/src/mirall/folderwatcher_qt.cpp b/src/mirall/folderwatcher_qt.cpp deleted file mode 100644 index 103e063a8..000000000 --- a/src/mirall/folderwatcher_qt.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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/folderwatcher.h" -#include "mirall/folderwatcher_qt.h" - -#include <QDir> -#include <QFileInfo> -#include <QDebug> - -namespace Mirall { - -FolderWatcherPrivate::FolderWatcherPrivate() - :QObject(), _parent(0) -{ - -} - -FolderWatcherPrivate::FolderWatcherPrivate(FolderWatcher *p, const QString &path) - : QObject(), _parent(p) - -{ - _watcher.reset(new QFileSystemWatcher); - - QObject::connect(_watcher.data(), SIGNAL(directoryChanged(QString)), - _parent, SLOT(changeDetected(QString)) ); - - QMetaObject::invokeMethod(this, "slotAddFolderRecursive", Q_ARG(QString, path)); -} - -// attention: result list passed by reference! -bool FolderWatcherPrivate::findFoldersBelow( const QDir& dir, QStringList& fullList ) -{ - bool ok = true; - if( !(dir.exists() && dir.isReadable()) ) { - qDebug() << "Non existing path coming in: " << dir.absolutePath(); - ok = false; - } else { - QStringList nameFilter; - nameFilter << QLatin1String("*"); - QDir::Filters filter = QDir::Dirs | QDir::NoDotAndDotDot|QDir::NoSymLinks; - const QStringList pathes = dir.entryList(nameFilter, filter); - - QStringList::const_iterator constIterator; - for (constIterator = pathes.constBegin(); constIterator != pathes.constEnd(); - ++constIterator) { - const QString fullPath(dir.path()+QLatin1String("/")+(*constIterator)); - fullList.append(fullPath); - ok = findFoldersBelow(QDir(fullPath), fullList); - } - } - - return ok; -} - -void FolderWatcherPrivate::slotAddFolderRecursive(const QString &path) -{ - int subdirs = 0; - qDebug() << "(+) Watcher:" << path; - - _watcher->addPath(path); - const QStringList watchedFolders(_watcher->directories()); - - QStringList allSubfolders; - if( !findFoldersBelow(QDir(path), allSubfolders)) { - qDebug() << "Could not traverse all sub folders"; - } - // qDebug() << "currently watching " << watchedFolders; - QStringListIterator subfoldersIt(allSubfolders); - while (subfoldersIt.hasNext()) { - QString subfolder = subfoldersIt.next(); - // qDebug() << " (**) subfolder: " << subfolder; - QDir folder (subfolder); - if (folder.exists() && !watchedFolders.contains(folder.path())) { - subdirs++; - if( _parent->pathIsIgnored(subfolder) ) { - qDebug() << "* Not adding" << folder.path(); - continue; - } - _watcher->addPath(folder.path()); - } else { - qDebug() << " `-> discarded:" << folder.path(); - } - } - - if (subdirs >0) { - qDebug() << " `-> and" << subdirs << "subdirectories"; - } -} - -void FolderWatcherPrivate::removePath(const QString &path ) -{ - _watcher->removePath(path); -} - - -} // namespace Mirall diff --git a/src/mirall/folderwatcher_qt.h b/src/mirall/folderwatcher_qt.h deleted file mode 100644 index 5ae6ba335..000000000 --- a/src/mirall/folderwatcher_qt.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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_FOLDERWATCHER_QT_H -#define MIRALL_FOLDERWATCHER_QT_H - -#include <QObject> -#include <QDir> -#include <QFileSystemWatcher> - -namespace Mirall { - -class FolderWatcher; - -class FolderWatcherPrivate : public QObject { - Q_OBJECT -public: - FolderWatcherPrivate(); - FolderWatcherPrivate(FolderWatcher *p, const QString& path); - void addPath(const QString &path) { slotAddFolderRecursive(path); } - void removePath(const QString &); - -signals: - void error(const QString& error); - -private slots: - void slotAddFolderRecursive(const QString &path); - -protected: - bool findFoldersBelow( const QDir& dir, QStringList& fullList ); - -private: - QScopedPointer<QFileSystemWatcher> _watcher; - - FolderWatcher *_parent; - -}; - -} - -#endif // MIRALL_FOLDERWATCHER_QT_H diff --git a/src/mirall/folderwatcher_win.cpp b/src/mirall/folderwatcher_win.cpp deleted file mode 100644 index c6c8242fa..000000000 --- a/src/mirall/folderwatcher_win.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 <QThread> -#include <QDebug> - -#include "mirall/folderwatcher.h" -#include "mirall/folderwatcher_win.h" - -#include <stdlib.h> -#include <stdio.h> -#include <tchar.h> - -namespace Mirall { - -void WatcherThread::run() -{ - _handle = FindFirstChangeNotification((wchar_t*)_path.utf16(), - true, // recursive watch - FILE_NOTIFY_CHANGE_FILE_NAME | - FILE_NOTIFY_CHANGE_DIR_NAME | - FILE_NOTIFY_CHANGE_LAST_WRITE); - - if (_handle == INVALID_HANDLE_VALUE) - { - qDebug() << Q_FUNC_INFO << "FindFirstChangeNotification function failed, stopping watcher!"; - FindCloseChangeNotification(_handle); - _handle = 0; - return; - } - - if (_handle == NULL) - { - qDebug() << Q_FUNC_INFO << "FindFirstChangeNotification returned null, stopping watcher!"; - FindCloseChangeNotification(_handle); - _handle = 0; - return; - } - - while(true) { - switch(WaitForSingleObject(_handle, /*wait*/ INFINITE)) { - case WAIT_OBJECT_0: - if (FindNextChangeNotification(_handle) == false) { - qDebug() << Q_FUNC_INFO << "FindFirstChangeNotification returned FALSE, stopping watcher!"; - FindCloseChangeNotification(_handle); - _handle = 0; - return; - } - // qDebug() << Q_FUNC_INFO << "Change detected in" << _path << "from" << QThread::currentThread (); - emit changed(_path); - break; - default: - qDebug() << Q_FUNC_INFO << "Error while watching"; - } - } -} - -WatcherThread::~WatcherThread() -{ - if (_handle) - FindCloseChangeNotification(_handle); -} - -FolderWatcherPrivate::FolderWatcherPrivate(FolderWatcher *p, const QString& path) - : _parent(p) -{ - _thread = new WatcherThread(path); - connect(_thread, SIGNAL(changed(const QString&)), - _parent,SLOT(changeDetected(const QString&))); - _thread->start(); -} - -FolderWatcherPrivate::~FolderWatcherPrivate() -{ - _thread->terminate(); - _thread->wait(); - delete _thread; -} - -} // namespace Mirall diff --git a/src/mirall/folderwatcher_win.h b/src/mirall/folderwatcher_win.h deleted file mode 100644 index 56ddfccd0..000000000 --- a/src/mirall/folderwatcher_win.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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_FOLDERWATCHER_WIN_H -#define MIRALL_FOLDERWATCHER_WIN_H - -#include <QThread> -#include <windows.h> - -namespace Mirall { - -class FolderWatcher; - -// watcher thread - -class WatcherThread : public QThread { - Q_OBJECT -public: - WatcherThread(const QString &path) : - QThread(), _path(path), _handle(0) {} - - ~WatcherThread(); - -protected: - void run(); - -signals: - void changed(const QString &path); - -private: - QString _path; - HANDLE _handle; -}; - -class FolderWatcherPrivate : public QObject { - Q_OBJECT -public: - FolderWatcherPrivate(FolderWatcher *p, const QString& path); - ~FolderWatcherPrivate(); - - void addPath(const QString &) {} - void removePath(const QString &) {} - -private: - FolderWatcher *_parent; - WatcherThread *_thread; -}; - -} - -#endif // MIRALL_FOLDERWATCHER_WIN_H diff --git a/src/mirall/folderwizard.cpp b/src/mirall/folderwizard.cpp deleted file mode 100644 index e5792abe0..000000000 --- a/src/mirall/folderwizard.cpp +++ /dev/null @@ -1,454 +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. - */ - -#include "mirall/folderwizard.h" -#include "mirall/folderman.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/theme.h" -#include "mirall/networkjobs.h" -#include "mirall/account.h" - -#include <QDebug> -#include <QDesktopServices> -#include <QDir> -#include <QFileDialog> -#include <QFileInfo> -#include <QFileIconProvider> -#include <QInputDialog> -#include <QUrl> -#include <QValidator> -#include <QWizardPage> -#include <QTreeWidget> - -#include <stdlib.h> - -namespace Mirall -{ - -QString FormatWarningsWizardPage::formatWarnings(const QStringList &warnings) const -{ - QString ret; - if (warnings.count() == 1) { - ret = tr("<b>Warning:</b> ") + warnings.first(); - } else if (warnings.count() > 1) { - ret = tr("<b>Warning:</b> ") + "<ul>"; - Q_FOREACH(QString warning, warnings) { - ret += QString::fromLatin1("<li>%1</li>").arg(warning); - } - ret += "</ul>"; - } - - return ret; -} - -FolderWizardLocalPath::FolderWizardLocalPath() - : FormatWarningsWizardPage() -{ - _ui.setupUi(this); - registerField(QLatin1String("sourceFolder*"), _ui.localFolderLineEdit); - connect(_ui.localFolderChooseBtn, SIGNAL(clicked()), this, SLOT(slotChooseLocalFolder())); - _ui.localFolderChooseBtn->setToolTip(tr("Click to select a local folder to sync.")); - - QString defaultPath = QString::fromLatin1( "%1/%2").arg( QDir::homePath() ).arg(Theme::instance()->appName() ); - _ui.localFolderLineEdit->setText( QDir::toNativeSeparators( defaultPath ) ); - _ui.localFolderLineEdit->setToolTip(tr("Enter the path to the local folder.")); - - registerField(QLatin1String("alias*"), _ui.aliasLineEdit); - _ui.aliasLineEdit->setText( Theme::instance()->appNameGUI() ); - _ui.aliasLineEdit->setToolTip(tr("The directory alias is a descriptive name for this sync connection.")); - _ui.warnLabel->setTextFormat(Qt::RichText); - _ui.warnLabel->hide(); -} - -FolderWizardLocalPath::~FolderWizardLocalPath() -{ - -} - -void FolderWizardLocalPath::initializePage() -{ - _ui.warnLabel->hide(); -} - -void FolderWizardLocalPath::cleanupPage() -{ - _ui.warnLabel->hide(); -} - -bool FolderWizardLocalPath::isComplete() const -{ - QFileInfo selFile( QDir::fromNativeSeparators(_ui.localFolderLineEdit->text()) ); - QString userInput = selFile.canonicalFilePath(); - - QStringList warnStrings; - - bool isOk = selFile.isDir(); - if( !isOk ) { - warnStrings.append(tr("No valid local folder selected!")); - } - - if (isOk && !selFile.isWritable()) { - isOk = false; - warnStrings.append(tr("You have no permission to write to the selected folder!")); - } - - // check if the local directory isn't used yet in another ownCloud sync - Folder::Map map = FolderMan::instance()->map(); - - if( isOk ) { - Folder::Map::const_iterator i = map.constBegin(); - while( isOk && i != map.constEnd() ) { - Folder *f = static_cast<Folder*>(i.value()); - QString folderDir = QDir( f->path() ).canonicalPath(); - if( folderDir.isEmpty() ) - { - isOk = true; - qDebug() << "Absolute path for folder: " << f->path() << " doesn't exist. Skipping."; - i++; - continue; - } - if( ! folderDir.endsWith(QLatin1Char('/')) ) folderDir.append(QLatin1Char('/')); - - qDebug() << "Checking local path: " << folderDir << " <-> " << userInput; - if( QDir::cleanPath(f->path()) == QDir::cleanPath(userInput) && - QDir::cleanPath(QDir(f->path()).canonicalPath()) == QDir(userInput).canonicalPath() ) { - isOk = false; - warnStrings.append( tr("The local path %1 is already an upload folder. Please pick another one!") - .arg(QDir::toNativeSeparators(userInput)) ); - } - if( isOk && QDir::cleanPath(folderDir).startsWith(QDir::cleanPath(userInput)+'/') ) { - qDebug() << "A already configured folder is child of the current selected"; - warnStrings.append( tr("An already configured folder is contained in the current entry.")); - isOk = false; - } - - QString absCleanUserFolder = QDir::cleanPath(QDir(userInput).canonicalPath())+'/'; - if( isOk && QDir::cleanPath(folderDir).startsWith(absCleanUserFolder) ) { - qDebug() << "A already configured folder is child of the current selected"; - warnStrings.append( tr("The selected folder is a symbolic link. An already configured " - "folder is contained in the folder this link is pointing to.")); - isOk = false; - } - - if( isOk && QDir::cleanPath(QString(userInput)).startsWith( QDir::cleanPath(folderDir)+'/') ) { - qDebug() << "An already configured folder is parent of the current selected"; - warnStrings.append( tr("An already configured folder contains the currently entered folder.")); - isOk = false; - } - if( isOk && absCleanUserFolder.startsWith( QDir::cleanPath(folderDir)+'/') ) { - qDebug() << "The selected folder is a symbolic link. An already configured folder is\n" - "the parent of the current selected contains the folder this link is pointing to."; - warnStrings.append( tr("The selected folder is a symbolic link. An already configured folder " - "is the parent of the current selected contains the folder this link is " - "pointing to.")); - isOk = false; - } - - i++; - } - } - - // check if the alias is unique. - QString alias = _ui.aliasLineEdit->text(); - if( alias.isEmpty() ) { - warnStrings.append( tr("The alias can not be empty. Please provide a descriptive alias word.") ); - isOk = false; - } - - Folder::Map::const_iterator i = map.constBegin(); - bool goon = true; - while( goon && i != map.constEnd() ) { - Folder *f = i.value(); - if( f ) { - qDebug() << "Checking local alias: " << f->alias(); - if( f->alias() == alias ) { - warnStrings.append( tr("The alias <i>%1</i> is already in use. Please pick another alias.").arg(alias) ); - isOk = false; - goon = false; - } - } - i++; - } - - _ui.warnLabel->setWordWrap(true); - if( isOk ) { - _ui.warnLabel->hide(); - _ui.warnLabel->setText( QString::null ); - } else { - _ui.warnLabel->show(); - QString warnings = formatWarnings(warnStrings); - _ui.warnLabel->setText( warnings ); - } - return isOk; -} - -void FolderWizardLocalPath::slotChooseLocalFolder() -{ - QString sf = QDesktopServices::storageLocation(QDesktopServices::HomeLocation); - QDir d(sf); - - // open the first entry of the home dir. Otherwise the dir picker comes - // up with the closed home dir icon, stupid Qt default... - QStringList dirs = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks, - QDir::DirsFirst|QDir::Name); - - if(dirs.count() > 0) sf += "/"+dirs.at(0); // Take the first dir in home dir. - - QString dir = QFileDialog::getExistingDirectory(this, - tr("Select the source folder"), - sf); - if (!dir.isEmpty()) { - // set the last directory component name as alias - _ui.localFolderLineEdit->setText(QDir::toNativeSeparators(dir)); - - QDir pickedDir(dir); - QString newAlias = pickedDir.dirName(); - if( !newAlias.isEmpty() ) { - _ui.aliasLineEdit->setText(newAlias); - } - } - emit completeChanged(); -} - -// ================================================================================= -FolderWizardRemotePath::FolderWizardRemotePath() - : FormatWarningsWizardPage() - ,_warnWasVisible(false) - -{ - _ui.setupUi(this); - _ui.warnFrame->hide(); - - connect(_ui.addFolderButton, SIGNAL(clicked()), SLOT(slotAddRemoteFolder())); - connect(_ui.refreshButton, SIGNAL(clicked()), SLOT(slotRefreshFolders())); - connect(_ui.folderTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), SIGNAL(completeChanged())); - connect(_ui.folderTreeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), SIGNAL(completeChanged())); - connect(_ui.folderTreeWidget, SIGNAL(itemExpanded(QTreeWidgetItem*)), SLOT(slotItemExpanded(QTreeWidgetItem*))); - -} - -void FolderWizardRemotePath::slotAddRemoteFolder() -{ - QTreeWidgetItem *current = _ui.folderTreeWidget->currentItem(); - - QString parent('/'); - if (current) { - parent = current->data(0, Qt::UserRole).toString(); - } - - QInputDialog *dlg = new QInputDialog(this); - - dlg->setWindowTitle(tr("Add Remote Folder")); - dlg->setLabelText(tr("Enter the name of the new folder:")); - dlg->setTextValue(parent); - dlg->open(this, SLOT(slotCreateRemoteFolder(QString))); - dlg->setAttribute(Qt::WA_DeleteOnClose); -} - -void FolderWizardRemotePath::slotCreateRemoteFolder(const QString &folder) -{ - if( folder.isEmpty() ) return; - - MkColJob *job = new MkColJob(AccountManager::instance()->account(), folder, this); - /* check the owncloud configuration file and query the ownCloud */ - connect(job, SIGNAL(finished(QNetworkReply::NetworkError)), - SLOT(slotCreateRemoteFolderFinished(QNetworkReply::NetworkError))); - connect(job, SIGNAL(networkError(QNetworkReply*)), SLOT(slotHandleNetworkError(QNetworkReply*))); - job->start(); -} - -void FolderWizardRemotePath::slotCreateRemoteFolderFinished(QNetworkReply::NetworkError error) -{ - if (error == QNetworkReply::NoError) { - qDebug() << "** webdav mkdir request finished"; - showWarn(tr("Folder was successfully created on %1.").arg(Theme::instance()->appNameGUI())); - slotRefreshFolders(); - } -} - -void FolderWizardRemotePath::slotHandleNetworkError(QNetworkReply *reply) -{ - qDebug() << "** webdav mkdir request failed:" << reply->error(); - showWarn(tr("Failed to create the folder on %1. Please check manually.") - .arg(Theme::instance()->appNameGUI())); -} - -static QTreeWidgetItem* findFirstChild(QTreeWidgetItem *parent, const QString& text) -{ - for (int i = 0; i < parent->childCount(); ++i) { - QTreeWidgetItem *child = parent->child(i); - if (child->text(0) == text) { - return child; - } - } - return 0; -} - -void FolderWizardRemotePath::recursiveInsert(QTreeWidgetItem *parent, QStringList pathTrail, QString path) -{ - QFileIconProvider prov; - QIcon folderIcon = prov.icon(QFileIconProvider::Folder); - if (pathTrail.size() == 0) { - if (path.endsWith('/')) { - path.chop(1); - } - parent->setToolTip(0, path); - parent->setData(0, Qt::UserRole, path); - } else { - QTreeWidgetItem *item = findFirstChild(parent, pathTrail.first()); - if (!item) { - item = new QTreeWidgetItem(parent); - item->setIcon(0, folderIcon); - item->setText(0, pathTrail.first()); - item->setData(0, Qt::UserRole, pathTrail.first()); - item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); - } - - pathTrail.removeFirst(); - recursiveInsert(item, pathTrail, path); - } -} - -void FolderWizardRemotePath::slotUpdateDirectories(const QStringList &list) -{ - QString webdavFolder = QUrl(AccountManager::instance()->account()->davUrl()).path(); - - QTreeWidgetItem *root = _ui.folderTreeWidget->topLevelItem(0); - if (!root) { - root = new QTreeWidgetItem(_ui.folderTreeWidget); - root->setText(0, Theme::instance()->appNameGUI()); - root->setIcon(0, Theme::instance()->applicationIcon()); - root->setToolTip(0, tr("Choose this to sync the entire account")); - root->setData(0, Qt::UserRole, "/"); - } - foreach (QString path, list) { - path.remove(webdavFolder); - QStringList paths = path.split('/'); - if (paths.last().isEmpty()) paths.removeLast(); - recursiveInsert(root, paths, path); - } - root->setExpanded(true); -} - -void FolderWizardRemotePath::slotRefreshFolders() -{ - LsColJob *job = new LsColJob(AccountManager::instance()->account(), "/", this); - connect(job, SIGNAL(directoryListing(QStringList)), - SLOT(slotUpdateDirectories(QStringList))); - job->start(); - _ui.folderTreeWidget->clear(); -} - -void FolderWizardRemotePath::slotItemExpanded(QTreeWidgetItem *item) -{ - QString dir = item->data(0, Qt::UserRole).toString(); - LsColJob *job = new LsColJob(AccountManager::instance()->account(), dir, this); - connect(job, SIGNAL(directoryListing(QStringList)), - SLOT(slotUpdateDirectories(QStringList))); - job->start(); -} - -FolderWizardRemotePath::~FolderWizardRemotePath() -{ -} - -bool FolderWizardRemotePath::isComplete() const -{ - if (!_ui.folderTreeWidget->currentItem()) - return false; - - QStringList warnStrings; - QString dir = _ui.folderTreeWidget->currentItem()->data(0, Qt::UserRole).toString(); - if (!dir.startsWith(QLatin1Char('/'))) { - dir.prepend(QLatin1Char('/')); - } - wizard()->setProperty("targetPath", dir); - - Folder::Map map = FolderMan::instance()->map(); - Folder::Map::const_iterator i = map.constBegin(); - for(i = map.constBegin();i != map.constEnd(); i++ ) { - Folder *f = static_cast<Folder*>(i.value()); - QString curDir = f->remotePath(); - if (!curDir.startsWith(QLatin1Char('/'))) { - curDir.prepend(QLatin1Char('/')); - } - if (QDir::cleanPath(dir) == QDir::cleanPath(curDir)) { - warnStrings.append(tr("This folder is already being synced.")); - } else if (dir.startsWith(curDir + QLatin1Char('/'))) { - warnStrings.append(tr("You are already syncing <i>%1</i>, which is a parent folder of <i>%2</i>.").arg(curDir).arg(dir)); - } - - if (curDir == QLatin1String("/")) { - warnStrings.append(tr("You are already syncing all your files. Syncing another folder is <b>not</b> supported. " - "If you want to sync multiple folders, please remove the currently configured " - "root folder sync.")); - } - } - - showWarn(formatWarnings(warnStrings)); - return warnStrings.isEmpty(); -} - -void FolderWizardRemotePath::cleanupPage() -{ - showWarn(); -} - -void FolderWizardRemotePath::initializePage() -{ - showWarn(); - slotRefreshFolders(); -} - -void FolderWizardRemotePath::showWarn( const QString& msg ) const -{ - if( msg.isEmpty() ) { - _ui.warnFrame->hide(); - - } else { - _ui.warnFrame->show(); - _ui.warnLabel->setText( msg ); - } -} - -// ==================================================================================== - -/** - * Folder wizard itself - */ - -FolderWizard::FolderWizard( QWidget *parent ) - : QWizard(parent), - _folderWizardSourcePage(new FolderWizardLocalPath), - _folderWizardTargetPage(0) -{ - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - setPage(Page_Source, _folderWizardSourcePage ); - if (!Theme::instance()->singleSyncFolder()) { - _folderWizardTargetPage = new FolderWizardRemotePath(); - setPage(Page_Target, _folderWizardTargetPage ); - } - - setWindowTitle( tr("Add Folder") ); - setOptions(QWizard::CancelButtonOnLeft); - setButtonText(QWizard::FinishButton, tr("Add Folder")); -} - -FolderWizard::~FolderWizard() -{ -} - - -} // end namespace - diff --git a/src/mirall/folderwizard.h b/src/mirall/folderwizard.h deleted file mode 100644 index 8db9b1319..000000000 --- a/src/mirall/folderwizard.h +++ /dev/null @@ -1,118 +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_FOLDERWIZARD_H -#define MIRALL_FOLDERWIZARD_H - -#include <QWizard> -#include <QNetworkReply> -#include <QTimer> - -#include "folder.h" - -#include "ui_folderwizardsourcepage.h" -#include "ui_folderwizardtargetpage.h" - -namespace Mirall { - -class ownCloudInfo; - -class FormatWarningsWizardPage : public QWizardPage { -protected: - QString formatWarnings(const QStringList &warnings) const; -}; - -/** - * page to ask for the local source folder - */ -class FolderWizardLocalPath : public FormatWarningsWizardPage -{ - Q_OBJECT -public: - FolderWizardLocalPath(); - ~FolderWizardLocalPath(); - - virtual bool isComplete() const Q_DECL_OVERRIDE; - void initializePage() Q_DECL_OVERRIDE; - void cleanupPage() Q_DECL_OVERRIDE; - - void setFolderMap( const Folder::Map &fm ) { _folderMap = fm; } -protected slots: - void slotChooseLocalFolder(); - -private: - Ui_FolderWizardSourcePage _ui; - Folder::Map _folderMap; -}; - - -/** - * page to ask for the target folder - */ - -class FolderWizardRemotePath : public FormatWarningsWizardPage -{ - Q_OBJECT -public: - FolderWizardRemotePath(); - ~FolderWizardRemotePath(); - - virtual bool isComplete() const Q_DECL_OVERRIDE; - - virtual void initializePage() Q_DECL_OVERRIDE; - virtual void cleanupPage() Q_DECL_OVERRIDE; - -protected slots: - - void showWarn( const QString& = QString() ) const; - void slotAddRemoteFolder(); - void slotCreateRemoteFolder(const QString&); - void slotCreateRemoteFolderFinished(QNetworkReply::NetworkError error); - void slotHandleNetworkError(QNetworkReply*); - void slotUpdateDirectories(const QStringList&); - void slotRefreshFolders(); - void slotItemExpanded(QTreeWidgetItem*); -private: - void recursiveInsert(QTreeWidgetItem *parent, QStringList pathTrail, QString path); - Ui_FolderWizardTargetPage _ui; - bool _warnWasVisible; - -}; - -/** - * - */ -class FolderWizard : public QWizard -{ - Q_OBJECT -public: - - enum { - Page_Source, - Page_Target - }; - - FolderWizard(QWidget *parent = 0); - ~FolderWizard(); - -private: - - FolderWizardLocalPath *_folderWizardSourcePage; - FolderWizardRemotePath *_folderWizardTargetPage; -}; - - -} // ns Mirall - -#endif diff --git a/src/mirall/folderwizardsourcepage.ui b/src/mirall/folderwizardsourcepage.ui deleted file mode 100644 index 5dc05c4fc..000000000 --- a/src/mirall/folderwizardsourcepage.ui +++ /dev/null @@ -1,157 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>FolderWizardSourcePage</class> - <widget class="QWidget" name="FolderWizardSourcePage"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>423</width> - <height>155</height> - </rect> - </property> - <property name="windowTitle"> - <string>Form</string> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="2" column="0"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>349</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="0"> - <widget class="QGroupBox" name="groupBox"> - <property name="title"> - <string>Pick a local folder on your computer to sync</string> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> - <widget class="QLineEdit" name="localFolderLineEdit"/> - </item> - <item> - <widget class="QPushButton" name="localFolderChooseBtn"> - <property name="text"> - <string>&Choose...</string> - </property> - </widget> - </item> - </layout> - </item> - <item row="1" column="0"> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>&Directory alias name:</string> - </property> - <property name="buddy"> - <cstring>aliasLineEdit</cstring> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="aliasLineEdit"/> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="warnLabel"> - <property name="palette"> - <palette> - <active> - <colorrole role="Base"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>255</red> - <green>255</green> - <blue>255</blue> - </color> - </brush> - </colorrole> - <colorrole role="Window"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>255</red> - <green>255</green> - <blue>192</blue> - </color> - </brush> - </colorrole> - </active> - <inactive> - <colorrole role="Base"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>255</red> - <green>255</green> - <blue>255</blue> - </color> - </brush> - </colorrole> - <colorrole role="Window"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>255</red> - <green>255</green> - <blue>192</blue> - </color> - </brush> - </colorrole> - </inactive> - <disabled> - <colorrole role="Base"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>255</red> - <green>255</green> - <blue>192</blue> - </color> - </brush> - </colorrole> - <colorrole role="Window"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>255</red> - <green>255</green> - <blue>192</blue> - </color> - </brush> - </colorrole> - </disabled> - </palette> - </property> - <property name="autoFillBackground"> - <bool>true</bool> - </property> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="text"> - <string/> - </property> - <property name="textFormat"> - <enum>Qt::AutoText</enum> - </property> - <property name="margin"> - <number>3</number> - </property> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/src/mirall/folderwizardtargetpage.ui b/src/mirall/folderwizardtargetpage.ui deleted file mode 100644 index 483178ae9..000000000 --- a/src/mirall/folderwizardtargetpage.ui +++ /dev/null @@ -1,199 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>FolderWizardTargetPage</class> - <widget class="QWidget" name="FolderWizardTargetPage"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>520</width> - <height>300</height> - </rect> - </property> - <property name="windowTitle"> - <string>Form</string> - </property> - <layout class="QGridLayout" name="gridLayout_6"> - <item row="3" column="0"> - <widget class="QFrame" name="warnFrame"> - <property name="palette"> - <palette> - <active> - <colorrole role="Base"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>255</red> - <green>255</green> - <blue>255</blue> - </color> - </brush> - </colorrole> - <colorrole role="Window"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>255</red> - <green>255</green> - <blue>153</blue> - </color> - </brush> - </colorrole> - </active> - <inactive> - <colorrole role="Base"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>255</red> - <green>255</green> - <blue>255</blue> - </color> - </brush> - </colorrole> - <colorrole role="Window"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>255</red> - <green>255</green> - <blue>153</blue> - </color> - </brush> - </colorrole> - </inactive> - <disabled> - <colorrole role="Base"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>255</red> - <green>255</green> - <blue>153</blue> - </color> - </brush> - </colorrole> - <colorrole role="Window"> - <brush brushstyle="SolidPattern"> - <color alpha="255"> - <red>255</red> - <green>255</green> - <blue>153</blue> - </color> - </brush> - </colorrole> - </disabled> - </palette> - </property> - <property name="autoFillBackground"> - <bool>true</bool> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - <layout class="QGridLayout" name="gridLayout_5"> - <item row="0" column="0"> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QLabel" name="warnLabel"> - <property name="autoFillBackground"> - <bool>true</bool> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="text"> - <string>TextLabel</string> - </property> - <property name="textFormat"> - <enum>Qt::AutoText</enum> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - <property name="margin"> - <number>3</number> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item row="0" column="0"> - <widget class="QGroupBox" name="groupBox"> - <property name="title"> - <string>Select a remote destination folder</string> - </property> - <property name="flat"> - <bool>true</bool> - </property> - <property name="checkable"> - <bool>false</bool> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="1" column="1"> - <widget class="QPushButton" name="addFolderButton"> - <property name="text"> - <string>Add Folder</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item row="2" column="1"> - <widget class="QPushButton" name="refreshButton"> - <property name="text"> - <string>Refresh</string> - </property> - </widget> - </item> - <item row="0" column="0" rowspan="4"> - <widget class="QTreeWidget" name="folderTreeWidget"> - <property name="sortingEnabled"> - <bool>true</bool> - </property> - <property name="headerHidden"> - <bool>true</bool> - </property> - <column> - <property name="text"> - <string>Folders</string> - </property> - </column> - </widget> - </item> - </layout> - </widget> - </item> - <item row="4" column="0"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/src/mirall/generalsettings.cpp b/src/mirall/generalsettings.cpp deleted file mode 100644 index 6c8fe5914..000000000 --- a/src/mirall/generalsettings.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 "generalsettings.h" -#include "ui_generalsettings.h" - -#include "mirall/theme.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/application.h" -#include "mirall/utility.h" -#include "mirall/mirallconfigfile.h" - -#include "updater/updater.h" -#include "updater/ocupdater.h" - -#include <QNetworkProxy> -#include <QDir> - -namespace Mirall { - -GeneralSettings::GeneralSettings(QWidget *parent) : - QWidget(parent), - _ui(new Ui::GeneralSettings) -{ - _ui->setupUi(this); - - connect(_ui->desktopNotificationsCheckBox, SIGNAL(toggled(bool)), - SLOT(slotToggleOptionalDesktopNotifications(bool))); - - _ui->autostartCheckBox->setChecked(Utility::hasLaunchOnStartup(Theme::instance()->appName())); - connect(_ui->autostartCheckBox, SIGNAL(toggled(bool)), SLOT(slotToggleLaunchOnStartup(bool))); - - // setup about section - QString about = Theme::instance()->about(); - if (about.isEmpty()) { - _ui->aboutGroupBox->hide(); - } else { - _ui->aboutLabel->setText(about); - _ui->aboutLabel->setOpenExternalLinks(true); - } - - loadMiscSettings(); - slotUpdateInfo(); - - // misc - connect(_ui->monoIconsCheckBox, SIGNAL(toggled(bool)), SLOT(saveMiscSettings())); - - // OEM themes are not obliged to ship mono icons, so there - // is no point in offering an option - QString themeDir = QString::fromLatin1(":/mirall/theme/%1/") - .arg(Theme::instance()->systrayIconFlavor(true)); - _ui->monoIconsCheckBox->setVisible(QDir(themeDir).exists()); -} - -GeneralSettings::~GeneralSettings() -{ - delete _ui; -} - -void GeneralSettings::loadMiscSettings() -{ - MirallConfigFile cfgFile; - _ui->monoIconsCheckBox->setChecked(cfgFile.monoIcons()); - _ui->desktopNotificationsCheckBox->setChecked(cfgFile.optionalDesktopNotifications()); -} - -void GeneralSettings::slotUpdateInfo() -{ - if (OCUpdater *updater = dynamic_cast<OCUpdater*>(Updater::instance())) - { - connect(updater, SIGNAL(downloadStateChanged()), SLOT(slotUpdateInfo()), Qt::UniqueConnection); - connect(_ui->restartButton, SIGNAL(clicked()), updater, SLOT(slotStartInstaller()), Qt::UniqueConnection); - connect(_ui->restartButton, SIGNAL(clicked()), qApp, SLOT(quit()), Qt::UniqueConnection); - _ui->updateStateLabel->setText(updater->statusString()); - _ui->restartButton->setVisible(updater->downloadState() == OCUpdater::DownloadComplete); - } else { - // can't have those infos from sparkle currently - _ui->updatesGroupBox->setVisible(false); - } -} - -void GeneralSettings::saveMiscSettings() -{ - MirallConfigFile cfgFile; - bool isChecked = _ui->monoIconsCheckBox->isChecked(); - cfgFile.setMonoIcons(isChecked); - Theme::instance()->setSystrayUseMonoIcons(isChecked); -} - -void GeneralSettings::slotToggleLaunchOnStartup(bool enable) -{ - Theme *theme = Theme::instance(); - Utility::setLaunchOnStartup(theme->appName(), theme->appNameGUI(), enable); -} - -void GeneralSettings::slotToggleOptionalDesktopNotifications(bool enable) -{ - MirallConfigFile cfgFile; - cfgFile.setOptionalDesktopNotifications(enable); -} - -} // namespace Mirall diff --git a/src/mirall/generalsettings.h b/src/mirall/generalsettings.h deleted file mode 100644 index 50dfd7a6f..000000000 --- a/src/mirall/generalsettings.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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_GENERALSETTINGS_H -#define MIRALL_GENERALSETTINGS_H - -#include <QWidget> - - -namespace Mirall { - -namespace Ui { -class GeneralSettings; -} - -class GeneralSettings : public QWidget -{ - Q_OBJECT - -public: - explicit GeneralSettings(QWidget *parent = 0); - ~GeneralSettings(); - -private slots: - void saveMiscSettings(); - void slotToggleLaunchOnStartup(bool); - void slotToggleOptionalDesktopNotifications(bool); - void slotUpdateInfo(); - -private: - void loadMiscSettings(); - - Ui::GeneralSettings *_ui; -}; - - -} // namespace Mirall -#endif // MIRALL_GENERALSETTINGS_H diff --git a/src/mirall/generalsettings.ui b/src/mirall/generalsettings.ui deleted file mode 100644 index 1ae6761bd..000000000 --- a/src/mirall/generalsettings.ui +++ /dev/null @@ -1,131 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>Mirall::GeneralSettings</class> - <widget class="QWidget" name="Mirall::GeneralSettings"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>468</width> - <height>249</height> - </rect> - </property> - <property name="windowTitle"> - <string>Form</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <widget class="QGroupBox" name="generalGroupBox"> - <property name="title"> - <string>General Settings</string> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0"> - <widget class="QCheckBox" name="autostartCheckBox"> - <property name="text"> - <string>Launch on System Startup</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QCheckBox" name="desktopNotificationsCheckBox"> - <property name="text"> - <string>Show Desktop Notifications</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QCheckBox" name="monoIconsCheckBox"> - <property name="text"> - <string>Use Monochrome Icons</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="aboutGroupBox"> - <property name="title"> - <string>About</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <item> - <widget class="QLabel" name="aboutLabel"> - <property name="text"> - <string>About</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="updatesGroupBox"> - <property name="title"> - <string>Updates</string> - </property> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QLabel" name="updateStateLabel"> - <property name="text"> - <string/> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - <property name="openExternalLinks"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="restartButton"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>&Restart && Update</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Preferred</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/src/mirall/ignorelisteditor.cpp b/src/mirall/ignorelisteditor.cpp deleted file mode 100644 index 7d3beb9fa..000000000 --- a/src/mirall/ignorelisteditor.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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/mirallconfigfile.h" - -#include "ignorelisteditor.h" -#include "ui_ignorelisteditor.h" - -#include <QFile> -#include <QDir> -#include <QListWidget> -#include <QListWidgetItem> -#include <QMessageBox> -#include <QInputDialog> - -namespace Mirall { - -IgnoreListEditor::IgnoreListEditor(QWidget *parent) : - QDialog(parent), - ui(new Ui::IgnoreListEditor) -{ - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - ui->setupUi(this); - - ui->descriptionLabel->setText(tr("Files or directories matching a pattern will not be synchronized.\n\n" - "Checked items will also be deleted if they prevent a directory from " - "being removed. This is useful for meta data.")); - - MirallConfigFile cfgFile; - readIgnoreFile(cfgFile.excludeFile(MirallConfigFile::SystemScope), true); - readIgnoreFile(cfgFile.excludeFile(MirallConfigFile::UserScope), false); - - connect(this, SIGNAL(accepted()), SLOT(slotUpdateLocalIgnoreList())); - ui->removePushButton->setEnabled(false); - connect(ui->listWidget, SIGNAL(itemSelectionChanged()), SLOT(slotItemSelectionChanged())); - connect(ui->listWidget, SIGNAL(itemActivated(QListWidgetItem*)), SLOT(slotItemChanged(QListWidgetItem*))); - connect(ui->removePushButton, SIGNAL(clicked()), SLOT(slotRemoveCurrentItem())); - connect(ui->addPushButton, SIGNAL(clicked()), SLOT(slotAddPattern())); - connect(ui->listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), SLOT(slotEditPattern(QListWidgetItem*))); -} - -static void setupItemFlags(QListWidgetItem* item) -{ - item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsUserCheckable); - item->setCheckState(Qt::Unchecked); -} - -IgnoreListEditor::~IgnoreListEditor() -{ - delete ui; -} - -void IgnoreListEditor::slotItemSelectionChanged() -{ - QListWidgetItem *item = ui->listWidget->currentItem(); - if (!item) { - ui->removePushButton->setEnabled(false); - return; - } - - bool enable = item->flags() & Qt::ItemIsEnabled; - ui->removePushButton->setEnabled(enable); -} - -void IgnoreListEditor::slotRemoveCurrentItem() -{ - delete ui->listWidget->currentItem(); -} - -void IgnoreListEditor::slotUpdateLocalIgnoreList() -{ - MirallConfigFile cfgFile; - QString ignoreFile = cfgFile.excludeFile(MirallConfigFile::UserScope); - QFile ignores(ignoreFile); - if (ignores.open(QIODevice::WriteOnly)) { - for(int i = 0; i < ui->listWidget->count(); ++i) { - QListWidgetItem *item = ui->listWidget->item(i); - if (item->flags() & Qt::ItemIsEnabled) { - QByteArray prepend; - if (item->checkState() == Qt::Checked) { - prepend = "]"; - } - ignores.write(prepend+item->text().toUtf8()+'\n'); - } - } - } else { - QMessageBox::warning(this, tr("Could not open file"), - tr("Cannot write changes to '%1'.").arg(ignoreFile)); - } -} - -void IgnoreListEditor::slotAddPattern() -{ - bool okClicked; - QString pattern = QInputDialog::getText(this, tr("Add Ignore Pattern"), - tr("Add a new ignore pattern:"), - QLineEdit::Normal, QString(), &okClicked); - - if (!okClicked || pattern.isEmpty()) - return; - - QListWidgetItem *item = new QListWidgetItem; - setupItemFlags(item); - if (pattern.startsWith("]")) { - pattern = pattern.mid(1); - item->setCheckState(Qt::Checked); - } - item->setText(pattern); - ui->listWidget->addItem(item); - ui->listWidget->scrollToItem(item); -} - -void IgnoreListEditor::slotEditPattern(QListWidgetItem *item) -{ - if (!(item->flags() & Qt::ItemIsEnabled)) - return; - - QString pattern = QInputDialog::getText(this, tr("Edit Ignore Pattern"), - tr("Edit ignore pattern:"), - QLineEdit::Normal, item->text()); - if (!pattern.isEmpty()) { - item->setText(pattern); - } -} - -void IgnoreListEditor::readIgnoreFile(const QString &file, bool readOnly) -{ - - MirallConfigFile cfgFile; - const QString disabledTip(tr("This entry is provided by the system at '%1' " - "and cannot be modified in this view.") - .arg(QDir::toNativeSeparators(cfgFile.excludeFile(MirallConfigFile::SystemScope)))); - - QFile ignores(file); - if (ignores.open(QIODevice::ReadOnly)) { - while (!ignores.atEnd()) { - QString line = QString::fromUtf8(ignores.readLine()); - line.chop(1); - if (!line.isEmpty() && !line.startsWith("#")) { - QListWidgetItem *item = new QListWidgetItem; - setupItemFlags(item); - if (line.startsWith("]")) { - line = line.mid(1); - item->setCheckState(Qt::Checked); - } - item->setText(line); - if (readOnly) { - item->setFlags(item->flags() ^ Qt::ItemIsEnabled); - item->setToolTip(disabledTip); - } - ui->listWidget->addItem(item); - } - } - } -} - -} // namespace Mirall diff --git a/src/mirall/ignorelisteditor.h b/src/mirall/ignorelisteditor.h deleted file mode 100644 index 208e1e7df..000000000 --- a/src/mirall/ignorelisteditor.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 IGNORELISTEDITOR_H -#define IGNORELISTEDITOR_H - -#include <QDialog> - -class QListWidgetItem; - -namespace Mirall { - -namespace Ui { -class IgnoreListEditor; -} - -class IgnoreListEditor : public QDialog -{ - Q_OBJECT - -public: - explicit IgnoreListEditor(QWidget *parent = 0); - ~IgnoreListEditor(); - -private slots: - void slotItemSelectionChanged(); - void slotRemoveCurrentItem(); - void slotUpdateLocalIgnoreList(); - void slotAddPattern(); - void slotEditPattern(QListWidgetItem*); - -private: - void readIgnoreFile(const QString& file, bool readOnly); - Ui::IgnoreListEditor *ui; -}; - -} // namespace Mirall - -#endif // IGNORELISTEDITOR_H diff --git a/src/mirall/ignorelisteditor.ui b/src/mirall/ignorelisteditor.ui deleted file mode 100644 index f65d3cb0f..000000000 --- a/src/mirall/ignorelisteditor.ui +++ /dev/null @@ -1,117 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>Mirall::IgnoreListEditor</class> - <widget class="QDialog" name="Mirall::IgnoreListEditor"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>471</width> - <height>359</height> - </rect> - </property> - <property name="windowTitle"> - <string>Ignored Files Editor</string> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="5" column="0" colspan="2"> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="standardButtons"> - <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> - </property> - </widget> - </item> - <item row="3" column="1"> - <spacer name="verticalSpacer"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>213</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="0" rowspan="3"> - <widget class="QListWidget" name="listWidget"> - <property name="enabled"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QPushButton" name="addPushButton"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="text"> - <string>Add</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QPushButton" name="removePushButton"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="text"> - <string>Remove</string> - </property> - </widget> - </item> - <item row="4" column="0" colspan="2"> - <widget class="QLabel" name="descriptionLabel"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="text"> - <string/> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections> - <connection> - <sender>buttonBox</sender> - <signal>accepted()</signal> - <receiver>Mirall::IgnoreListEditor</receiver> - <slot>accept()</slot> - <hints> - <hint type="sourcelabel"> - <x>348</x> - <y>333</y> - </hint> - <hint type="destinationlabel"> - <x>361</x> - <y>355</y> - </hint> - </hints> - </connection> - <connection> - <sender>buttonBox</sender> - <signal>rejected()</signal> - <receiver>Mirall::IgnoreListEditor</receiver> - <slot>reject()</slot> - <hints> - <hint type="sourcelabel"> - <x>210</x> - <y>333</y> - </hint> - <hint type="destinationlabel"> - <x>385</x> - <y>297</y> - </hint> - </hints> - </connection> - </connections> -</ui> diff --git a/src/mirall/logbrowser.cpp b/src/mirall/logbrowser.cpp deleted file mode 100644 index db41fc803..000000000 --- a/src/mirall/logbrowser.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/* - * 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. - */ - -#include "logbrowser.h" - -#include "stdio.h" -#include <iostream> - -#include <QDialogButtonBox> -#include <QTextDocument> -#include <QLayout> -#include <QPushButton> -#include <QLabel> -#include <QFileDialog> -#include <QDir> -#include <QTextStream> -#include <QMessageBox> -#include <QCoreApplication> -#include <QDebug> -#include <QSettings> -#include <QAction> - -#include "mirall/mirallconfigfile.h" -#include "mirall/logger.h" - -namespace Mirall { - -// ============================================================================== - -LogWidget::LogWidget(QWidget *parent) - :QPlainTextEdit(parent) -{ - setReadOnly( true ); - QFont font; - font.setFamily(QLatin1String("Courier New")); - font.setFixedPitch(true); - document()->setDefaultFont( font ); -} - -// ============================================================================== - -LogBrowser::LogBrowser(QWidget *parent) : - QDialog(parent), - _logWidget( new LogWidget(parent) ) -{ - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - setObjectName("LogBrowser"); // for save/restoreGeometry() - setWindowTitle(tr("Log Output")); - setMinimumWidth(600); - - QVBoxLayout *mainLayout = new QVBoxLayout; - // mainLayout->setMargin(0); - - mainLayout->addWidget( _logWidget ); - - QHBoxLayout *toolLayout = new QHBoxLayout; - mainLayout->addLayout( toolLayout ); - - // Search input field - QLabel *lab = new QLabel(tr("&Search: ")); - _findTermEdit = new QLineEdit; - lab->setBuddy( _findTermEdit ); - toolLayout->addWidget(lab); - toolLayout->addWidget( _findTermEdit ); - - // find button - QPushButton *findBtn = new QPushButton; - findBtn->setText( tr("&Find") ); - connect( findBtn, SIGNAL(clicked()), this, SLOT(slotFind())); - toolLayout->addWidget( findBtn ); - - // stretch - toolLayout->addStretch(1); - _statusLabel = new QLabel; - toolLayout->addWidget( _statusLabel ); - toolLayout->addStretch(5); - - QDialogButtonBox *btnbox = new QDialogButtonBox; - QPushButton *closeBtn = btnbox->addButton( QDialogButtonBox::Close ); - connect(closeBtn,SIGNAL(clicked()),this,SLOT(close())); - - mainLayout->addWidget( btnbox ); - - // clear button - _clearBtn = new QPushButton; - _clearBtn->setText( tr("Clear") ); - _clearBtn->setToolTip( tr("Clear the log display.") ); - btnbox->addButton(_clearBtn, QDialogButtonBox::ActionRole); - connect( _clearBtn, SIGNAL(clicked()), this, SLOT(slotClearLog())); - - // save Button - _saveBtn = new QPushButton; - _saveBtn->setText( tr("S&ave") ); - _saveBtn->setToolTip(tr("Save the log file to a file on disk for debugging.")); - btnbox->addButton(_saveBtn, QDialogButtonBox::ActionRole); - connect( _saveBtn, SIGNAL(clicked()),this, SLOT(slotSave())); - - setLayout( mainLayout ); - - setModal(false); - - // Direct connection for log comming from this thread, and queued for the one in a different thread - connect(Logger::instance(), SIGNAL(newLog(QString)),this,SLOT(slotNewLog(QString)), Qt::AutoConnection); - - QAction *showLogWindow = new QAction(this); - showLogWindow->setShortcut(QKeySequence("F12")); - connect(showLogWindow, SIGNAL(triggered()), SLOT(close())); - addAction(showLogWindow); - - MirallConfigFile cfg; - cfg.restoreGeometry(this); - int lines = cfg.maxLogLines(); - // qDebug() << "# ## Have " << lines << " Loglines!"; - _logWidget->document()->setMaximumBlockCount( lines ); - -} - -LogBrowser::~LogBrowser() -{ -} - -void LogBrowser::closeEvent(QCloseEvent *) -{ - MirallConfigFile cfg; - cfg.saveGeometry(this); -} - - -void LogBrowser::slotNewLog( const QString& msg ) -{ - if( _logWidget->isVisible() ) { - _logWidget->appendPlainText( msg ); - } -} - - -void LogBrowser::slotFind() -{ - QString searchText = _findTermEdit->text(); - - if( searchText.isEmpty() ) return; - - search( searchText ); -} - -void LogBrowser::search( const QString& str ) -{ - QList<QTextEdit::ExtraSelection> extraSelections; - - _logWidget->moveCursor(QTextCursor::Start); - QColor color = QColor(Qt::gray).lighter(130); - _statusLabel->clear(); - - while(_logWidget->find(str)) - { - QTextEdit::ExtraSelection extra; - extra.format.setBackground(color); - - extra.cursor = _logWidget->textCursor(); - extraSelections.append(extra); - } - - QString stat = QString::fromLatin1("Search term %1 with %2 search results.").arg(str).arg(extraSelections.count()); - _statusLabel->setText(stat); - - _logWidget->setExtraSelections(extraSelections); -} - -void LogBrowser::slotSave() -{ - _saveBtn->setEnabled(false); - - QString saveFile = QFileDialog::getSaveFileName( this, tr("Save log file"), QDir::homePath() ); - - if( ! saveFile.isEmpty() ) { - QFile file(saveFile); - - if (file.open(QIODevice::WriteOnly)) { - QTextStream stream(&file); - stream << _logWidget->toPlainText(); - file.close(); - } else { - QMessageBox::critical(this, tr("Error"), tr("Could not write to log file ")+ saveFile); - } - } - _saveBtn->setEnabled(true); - -} - -void LogBrowser::slotClearLog() -{ - _logWidget->clear(); -} - -} // namespace diff --git a/src/mirall/logbrowser.h b/src/mirall/logbrowser.h deleted file mode 100644 index 24f2406bb..000000000 --- a/src/mirall/logbrowser.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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. - */ - -#ifndef LOGBROWSER_H -#define LOGBROWSER_H - -#include <QPlainTextEdit> -#include <QTextStream> -#include <QFile> -#include <QObject> -#include <QList> -#include <QDateTime> -#include <QDialog> -#include <QLineEdit> -#include <QPushButton> -#include <QLabel> - -namespace Mirall { - -class LogWidget : public QPlainTextEdit -{ - Q_OBJECT -public: - explicit LogWidget(QWidget *parent = 0); - -signals: - -}; - -class LogBrowser : public QDialog -{ - Q_OBJECT -public: - explicit LogBrowser(QWidget *parent = 0); - ~LogBrowser(); - - void setLogFile(const QString& , bool ); - -protected: - void closeEvent(QCloseEvent *) Q_DECL_OVERRIDE; - -protected slots: - void slotNewLog( const QString &msg ); - void slotFind(); - void search( const QString& ); - void slotSave(); - void slotClearLog(); - -private: - LogWidget *_logWidget; - QLineEdit *_findTermEdit; - QPushButton *_saveBtn; - QPushButton *_clearBtn; - QLabel *_statusLabel; - -}; - -} // namespace - -#endif // LOGBROWSER_H diff --git a/src/mirall/logger.cpp b/src/mirall/logger.cpp deleted file mode 100644 index 0bc8d1ccb..000000000 --- a/src/mirall/logger.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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. - */ - -#include "mirall/logger.h" - -#include <QDir> -#include <QStringList> - -namespace Mirall { - -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) -// logging handler. -static void mirallLogCatcher(QtMsgType type, const char *msg) -{ - Q_UNUSED(type) - // qDebug() exports to local8Bit, which is not always UTF-8 - Logger::instance()->mirallLog( QString::fromLocal8Bit(msg) ); -} -static void qInstallMessageHandler(QtMsgHandler h) { - qInstallMsgHandler(h); -} -#else -static void mirallLogCatcher(QtMsgType, const QMessageLogContext &ctx, const QString &message) { - Q_UNUSED(ctx); - - QByteArray file = ctx.file; - file = file.mid(file.lastIndexOf('/') + 1); - Logger::instance()->mirallLog( QString::fromLocal8Bit(file) + QLatin1Char(':') + QString::number(ctx.line) - + QLatin1Char(' ') + message) ; -} -#endif - -Logger *Logger::instance() -{ - static Logger log; - return &log; -} - -Logger::Logger( QObject* parent) : QObject(parent), - _showTime(true), _doLogging(false), _doFileFlush(false), _logExpire(0) -{ - qInstallMessageHandler(mirallLogCatcher); -} - -Logger::~Logger() { - qInstallMessageHandler(0); -} - - -void Logger::postGuiLog(const QString &title, const QString &message) -{ - emit guiLog(title, message); -} - -void Logger::postOptionalGuiLog(const QString &title, const QString &message) -{ - emit optionalGuiLog(title, message); -} - -void Logger::postGuiMessage(const QString &title, const QString &message) -{ - emit guiMessage(title, message); -} - -void Logger::log(Log log) -{ - QString msg; - if( _showTime ) { - msg = log.timeStamp.toString(QLatin1String("MM-dd hh:mm:ss:zzz")) + QLatin1Char(' '); - } - - if( log.source == Log::CSync ) { - // msg += "csync - "; - } else { - // msg += "ownCloud - "; - } - msg += log.message; - // _logs.append(log); - // std::cout << qPrintable(log.message) << std::endl; - - { - QMutexLocker lock(&_mutex); - if( _logstream ) { - (*_logstream) << msg << endl; - if( _doFileFlush ) _logstream->flush(); - } - } - - emit newLog(msg); -} - -void Logger::csyncLog( const QString& message ) -{ - Log log; - log.source = Log::CSync; - log.timeStamp = QDateTime::currentDateTime(); - log.message = message; - - Logger::instance()->log(log); -} - -void Logger::mirallLog( const QString& message ) -{ - Log log_; - log_.source = Log::Mirall; - log_.timeStamp = QDateTime::currentDateTime(); - log_.message = message; - - Logger::instance()->log( log_ ); -} - -void Logger::setLogFile(const QString & name) -{ - QMutexLocker locker(&_mutex); - - if( _logstream ) { - _logstream.reset(0); - _logFile.close(); - } - - if( name.isEmpty() ) { - return; - } - - bool openSucceeded = false; - if (name == QLatin1String("-")) { - openSucceeded = _logFile.open(1, QIODevice::WriteOnly); - } else { - _logFile.setFileName( name ); - openSucceeded = _logFile.open(QIODevice::WriteOnly); - } - - if(!openSucceeded) { - locker.unlock(); // Just in case postGuiMessage has a qDebug() - postGuiMessage( tr("Error"), - QString(tr("<nobr>File '%1'<br/>cannot be opened for writing.<br/><br/>" - "The log output can <b>not</b> be saved!</nobr>")) - .arg(name)); - return; - } - - _logstream.reset(new QTextStream( &_logFile )); -} - -void Logger::setLogExpire( int expire ) -{ - _logExpire = expire; -} - -void Logger::setLogDir( const QString& dir ) -{ - _logDirectory = dir; -} - -void Logger::setLogFlush( bool flush ) -{ - _doFileFlush = flush; -} - -void Logger::enterNextLogFile() -{ - if (!_logDirectory.isEmpty()) { - QDir dir(_logDirectory); - if (!dir.exists()) { - dir.mkpath("."); - } - - // Find out what is the file with the highest nymber if any - QStringList files = dir.entryList(QStringList("owncloud.log.*"), - QDir::Files); - QRegExp rx("owncloud.log.(\\d+)"); - uint maxNumber = 0; - QDateTime now = QDateTime::currentDateTime(); - foreach(const QString &s, files) { - if (rx.exactMatch(s)) { - maxNumber = qMax(maxNumber, rx.cap(1).toUInt()); - if (_logExpire > 0) { - QFileInfo fileInfo = dir.absoluteFilePath(s); - if (fileInfo.lastModified().addSecs(60*60 * _logExpire) < now) { - dir.remove(s); - } - } - } - } - - QString filename = _logDirectory + "/owncloud.log." + QString::number(maxNumber+1); - setLogFile(filename); - } -} - -} // namespace Mirall diff --git a/src/mirall/logger.h b/src/mirall/logger.h deleted file mode 100644 index 8e4fdbe6c..000000000 --- a/src/mirall/logger.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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. - */ - -#ifndef LOGGER_H -#define LOGGER_H - -#include <QObject> -#include <QList> -#include <QDateTime> -#include <QFile> -#include <QTextStream> -#include <qmutex.h> - -#include "utility.h" - -namespace Mirall { - -struct Log{ - typedef enum{ - Mirall, - CSync - } Source; - - QDateTime timeStamp; - Source source; - QString message; -}; - -class OWNCLOUDSYNC_EXPORT Logger : public QObject -{ - Q_OBJECT -public: - - void log(Log log); - - static void csyncLog( const QString& message ); - static void mirallLog( const QString& message ); - - const QList<Log>& logs() const {return _logs;} - - static Logger* instance(); - - void postGuiLog(const QString& title, const QString& message); - void postOptionalGuiLog(const QString& title, const QString& message); - void postGuiMessage(const QString& title, const QString& message); - - void setLogFile( const QString & name ); - void setLogExpire( int expire ); - void setLogDir( const QString& dir ); - void setLogFlush( bool flush ); - -signals: - void newLog(const QString&); - void guiLog(const QString&, const QString&); - void guiMessage(const QString&, const QString&); - void optionalGuiLog(const QString&, const QString&); - -public slots: - void enterNextLogFile(); - -private: - Logger(QObject* parent=0); - ~Logger(); - QList<Log> _logs; - bool _showTime; - bool _doLogging; - QFile _logFile; - bool _doFileFlush; - int _logExpire; - QScopedPointer<QTextStream> _logstream; - QMutex _mutex; - QString _logDirectory; - -}; - -} // namespace Mirall - -#endif // LOGGER_H diff --git a/src/mirall/mirallaccessmanager.cpp b/src/mirall/mirallaccessmanager.cpp deleted file mode 100644 index ddb9be013..000000000 --- a/src/mirall/mirallaccessmanager.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) by Krzesimir Nowak <krzesimir@endocode.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; version 2 of the License. - * - * 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 <QNetworkRequest> -#include <QNetworkProxy> -#include <QAuthenticator> -#include <QSslConfiguration> - -#include "mirall/cookiejar.h" -#include "mirall/mirallaccessmanager.h" -#include "mirall/utility.h" - -namespace Mirall -{ - -MirallAccessManager::MirallAccessManager(QObject* parent) - : QNetworkAccessManager (parent) -{ -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) && defined(Q_OS_MAC) - // FIXME Workaround http://stackoverflow.com/a/15707366/2941 https://bugreports.qt-project.org/browse/QTBUG-30434 - QNetworkProxy proxy = this->proxy(); - proxy.setHostName(" "); - setProxy(proxy); -#endif - setCookieJar(new CookieJar); - QObject::connect(this, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), - this, SLOT(slotProxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); -} - -QNetworkReply* MirallAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData) -{ - QNetworkRequest newRequest(request); - newRequest.setRawHeader(QByteArray("User-Agent"), Utility::userAgentString()); - QByteArray verb = newRequest.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray(); - // For PROPFIND (assumed to be a WebDAV op), set xml/utf8 as content type/encoding - // This needs extension - if (verb == "PROPFIND") { - newRequest.setHeader( QNetworkRequest::ContentTypeHeader, QLatin1String("text/xml; charset=utf-8")); - } - return QNetworkAccessManager::createRequest(op, newRequest, outgoingData); -} - -void MirallAccessManager::slotProxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator) -{ - Q_UNUSED(authenticator); - qDebug() << Q_FUNC_INFO << proxy.type(); - // We put in the password here and in ClientProxy in the proxy itself. - if (!proxy.user().isEmpty() || !proxy.password().isEmpty()) { - authenticator->setUser(proxy.user()); - authenticator->setPassword(proxy.password()); - } -} - -} // ns Mirall diff --git a/src/mirall/mirallaccessmanager.h b/src/mirall/mirallaccessmanager.h deleted file mode 100644 index d2fc0e531..000000000 --- a/src/mirall/mirallaccessmanager.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) by Krzesimir Nowak <krzesimir@endocode.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; version 2 of the License. - * - * 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_ACCESS_MANAGER_H -#define MIRALL_ACCESS_MANAGER_H - -#include "owncloudlib.h" -#include <QNetworkAccessManager> - -namespace Mirall -{ - -class OWNCLOUDSYNC_EXPORT MirallAccessManager : public QNetworkAccessManager -{ - Q_OBJECT - -public: - MirallAccessManager(QObject* parent = 0); - -protected: - QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData = 0) Q_DECL_OVERRIDE; -protected slots: - void slotProxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator); -}; - -} // ns Mirall - -#endif diff --git a/src/mirall/mirallconfigfile.cpp b/src/mirall/mirallconfigfile.cpp deleted file mode 100644 index 8988a05fa..000000000 --- a/src/mirall/mirallconfigfile.cpp +++ /dev/null @@ -1,543 +0,0 @@ -/* - * 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. - */ - -#include "config.h" - -#include "mirall/mirallconfigfile.h" -#include "mirall/owncloudtheme.h" -#include "mirall/theme.h" -#include "mirall/utility.h" - -#include "creds/abstractcredentials.h" -#include "creds/credentialsfactory.h" - -#ifndef TOKEN_AUTH_ONLY -#include <QWidget> -#include <QHeaderView> -#include <QDesktopServices> -#endif - -#include <QCoreApplication> -#include <QDir> -#include <QFile> -#include <QFileInfo> -#include <QSettings> -#include <QDebug> -#include <QNetworkProxy> - -#define DEFAULT_REMOTE_POLL_INTERVAL 30000 // default remote poll time in milliseconds -#define DEFAULT_MAX_LOG_LINES 20000 - -namespace Mirall { - -static const char caCertsKeyC[] = "CaCertificates"; -static const char remotePollIntervalC[] = "remotePollInterval"; -static const char forceSyncIntervalC[] = "forceSyncInterval"; -static const char monoIconsC[] = "monoIcons"; -static const char optionalDesktopNoficationsC[] = "optionalDesktopNotifications"; -static const char skipUpdateCheckC[] = "skipUpdateCheck"; -static const char geometryC[] = "geometry"; -static const char timeoutC[] = "timeout"; - -static const char proxyHostC[] = "Proxy/host"; -static const char proxyTypeC[] = "Proxy/type"; -static const char proxyPortC[] = "Proxy/port"; -static const char proxyUserC[] = "Proxy/user"; -static const char proxyPassC[] = "Proxy/pass"; -static const char proxyNeedsAuthC[] = "Proxy/needsAuth"; - -static const char useUploadLimitC[] = "BWLimit/useUploadLimit"; -static const char useDownloadLimitC[] = "BWLimit/useDownloadLimit"; -static const char uploadLimitC[] = "BWLimit/uploadLimit"; -static const char downloadLimitC[] = "BWLimit/downloadLimit"; - -static const char maxLogLinesC[] = "Logging/maxLogLines"; - -QString MirallConfigFile::_confDir = QString::null; -bool MirallConfigFile::_askedUser = false; - -MirallConfigFile::MirallConfigFile() -{ - QSettings::setDefaultFormat(QSettings::IniFormat); - - const QString config = configFile(); - - - QSettings settings(config, QSettings::IniFormat); - settings.beginGroup( defaultConnection() ); - - // qDebug() << "Loading config: " << config << " (URL is " << settings.value("url").toString() << ")"; -} - -void MirallConfigFile::setConfDir(const QString &value) -{ - QString dirPath = value; - if( dirPath.isEmpty() ) return; - - QFileInfo fi(dirPath); - if ( !fi.exists() && !fi.isAbsolute() ) { - QDir::current().mkdir(dirPath); - QDir dir = QDir::current(); - dir.cd(dirPath); - fi.setFile(dir.path()); - } - if( fi.exists() && fi.isDir() ) { - dirPath = fi.absoluteFilePath(); - qDebug() << "** Using custom config dir " << dirPath; - _confDir=dirPath; - } -} - -bool MirallConfigFile::optionalDesktopNotifications() const -{ - QSettings settings(configFile(), QSettings::IniFormat); - return settings.value(QLatin1String(optionalDesktopNoficationsC), true).toBool(); -} - -int MirallConfigFile::timeout() const -{ - QSettings settings(configFile(), QSettings::IniFormat); - return settings.value(QLatin1String(timeoutC), 300).toInt(); // default to 5 min -} - -void MirallConfigFile::setOptionalDesktopNotifications(bool show) -{ - QSettings settings(configFile(), QSettings::IniFormat); - settings.setValue(QLatin1String(optionalDesktopNoficationsC), show); - settings.sync(); -} - -void MirallConfigFile::saveGeometry(QWidget *w) -{ -#ifndef TOKEN_AUTH_ONLY - Q_ASSERT(!w->objectName().isNull()); - QSettings settings(configFile(), QSettings::IniFormat); - settings.beginGroup(w->objectName()); - settings.setValue(QLatin1String(geometryC), w->saveGeometry()); - settings.sync(); -#endif -} - -void MirallConfigFile::restoreGeometry(QWidget *w) -{ -#ifndef TOKEN_AUTH_ONLY - w->restoreGeometry(getValue(geometryC, w->objectName()).toByteArray()); -#endif -} - -void MirallConfigFile::saveGeometryHeader(QHeaderView *header) -{ -#ifndef TOKEN_AUTH_ONLY - if(!header) return; - Q_ASSERT(!header->objectName().isNull()); - - QSettings settings(configFile(), QSettings::IniFormat); - settings.beginGroup(header->objectName()); - settings.setValue(QLatin1String(geometryC), header->saveState()); - settings.sync(); -#endif -} - -void MirallConfigFile::restoreGeometryHeader(QHeaderView *header) -{ -#ifndef TOKEN_AUTH_ONLY - if(!header) return; - Q_ASSERT(!header->objectName().isNull()); - - QSettings settings(configFile(), QSettings::IniFormat); - settings.beginGroup(header->objectName()); - header->restoreState(getValue(geometryC, header->objectName()).toByteArray()); -#endif -} - -QVariant MirallConfigFile::getPolicySetting(const QString &setting, const QVariant& defaultValue) const -{ - if (Utility::isWindows()) { - // check for policies first and return immediately if a value is found. - QSettings userPolicy(QString::fromLatin1("HKEY_CURRENT_USER\\Software\\Policies\\%1\\%2") - .arg(APPLICATION_VENDOR).arg(Theme::instance()->appName()), - QSettings::NativeFormat); - if(userPolicy.contains(setting)) { - return userPolicy.value(setting); - } - - QSettings machinePolicy(QString::fromLatin1("HKEY_LOCAL_MACHINE\\Software\\Policies\\%1\\%2") - .arg(APPLICATION_VENDOR).arg(APPLICATION_NAME), - QSettings::NativeFormat); - if(machinePolicy.contains(setting)) { - return machinePolicy.value(setting); - } - } - return defaultValue; -} - -QString MirallConfigFile::configPath() const -{ - #ifndef TOKEN_AUTH_ONLY - if( _confDir.isEmpty() ) { - // Qt 5's QStandardPaths::writableLocation gives us wrong results (without /data/), - // so we'll have to use the deprecated version for now - _confDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation); - } - #endif - QString dir = _confDir; - - if( !dir.endsWith(QLatin1Char('/')) ) dir.append(QLatin1Char('/')); - return dir; -} - -QString MirallConfigFile::configPathWithAppName() const -{ - //HACK - return QFileInfo( configFile() ).dir().absolutePath().append("/"); -} - -QString MirallConfigFile::excludeFile(Scope scope) const -{ - // prefer sync-exclude.lst, but if it does not exist, check for - // exclude.lst for compatibility reasons in the user writeable - // directories. - const QString exclFile("sync-exclude.lst"); - QFileInfo fi; - - if (scope != SystemScope) { - fi.setFile( configPath(), exclFile ); - - if( ! fi.isReadable() ) { - fi.setFile( configPath(), QLatin1String("exclude.lst") ); - } - if( ! fi.isReadable() ) { - fi.setFile( configPath(), exclFile ); - } - } - - if (scope != UserScope) { - // Check alternative places... - if( ! fi.isReadable() ) { -#ifdef Q_OS_WIN - fi.setFile( QCoreApplication::applicationDirPath(), exclFile ); -#endif -#ifdef Q_OS_UNIX - fi.setFile( QString( SYSCONFDIR "/%1").arg(Theme::instance()->appName()), exclFile ); -#endif -#ifdef Q_OS_MAC - // exec path is inside the bundle - fi.setFile( QCoreApplication::applicationDirPath(), - QLatin1String("../Resources/") + exclFile ); -#endif - } - } - return fi.absoluteFilePath(); -} - -QString MirallConfigFile::configFile() const -{ - if( qApp->applicationName().isEmpty() ) { - qApp->setApplicationName( Theme::instance()->appNameGUI() ); - } - return configPath() + Theme::instance()->configFileName(); -} - -bool MirallConfigFile::exists() -{ - QFile file( configFile() ); - return file.exists(); -} - -QString MirallConfigFile::defaultConnection() const -{ - return Theme::instance()->appName(); -} - -void MirallConfigFile::storeData(const QString& group, const QString& key, const QVariant& value) -{ - const QString con(group.isEmpty() ? defaultConnection() : group); - QSettings settings(configFile(), QSettings::IniFormat); - - settings.beginGroup(con); - settings.setValue(key, value); - settings.sync(); -} - -QVariant MirallConfigFile::retrieveData(const QString& group, const QString& key) const -{ - const QString con(group.isEmpty() ? defaultConnection() : group); - QSettings settings(configFile(), QSettings::IniFormat); - - settings.beginGroup(con); - return settings.value(key); -} - -void MirallConfigFile::removeData(const QString& group, const QString& key) -{ - const QString con(group.isEmpty() ? defaultConnection() : group); - QSettings settings(configFile(), QSettings::IniFormat); - - settings.beginGroup(con); - settings.remove(key); -} - -bool MirallConfigFile::dataExists(const QString& group, const QString& key) const -{ - const QString con(group.isEmpty() ? defaultConnection() : group); - QSettings settings(configFile(), QSettings::IniFormat); - - settings.beginGroup(con); - return settings.contains(key); -} - -QByteArray MirallConfigFile::caCerts( ) -{ - QSettings settings(configFile(), QSettings::IniFormat); - return settings.value( QLatin1String(caCertsKeyC) ).toByteArray(); -} - -void MirallConfigFile::setCaCerts( const QByteArray & certs ) -{ - QSettings settings(configFile(), QSettings::IniFormat); - - settings.setValue( QLatin1String(caCertsKeyC), certs ); - settings.sync(); -} - -int MirallConfigFile::remotePollInterval( const QString& connection ) const -{ - QString con( connection ); - if( connection.isEmpty() ) con = defaultConnection(); - - QSettings settings(configFile(), QSettings::IniFormat); - settings.beginGroup( con ); - - int remoteInterval = settings.value( QLatin1String(remotePollIntervalC), DEFAULT_REMOTE_POLL_INTERVAL ).toInt(); - if( remoteInterval < 5000) { - qDebug() << "Remote Interval is less than 5 seconds, reverting to" << DEFAULT_REMOTE_POLL_INTERVAL; - remoteInterval = DEFAULT_REMOTE_POLL_INTERVAL; - } - return remoteInterval; -} - -void MirallConfigFile::setRemotePollInterval(int interval, const QString &connection ) -{ - QString con( connection ); - if( connection.isEmpty() ) con = defaultConnection(); - - if( interval < 5000 ) { - qDebug() << "Remote Poll interval of " << interval << " is below fife seconds."; - return; - } - QSettings settings(configFile(), QSettings::IniFormat); - settings.beginGroup( con ); - settings.setValue(QLatin1String(remotePollIntervalC), interval ); - settings.sync(); -} - -quint64 MirallConfigFile::forceSyncInterval(const QString& connection) const -{ - uint pollInterval = remotePollInterval(connection); - - QString con( connection ); - if( connection.isEmpty() ) con = defaultConnection(); - QSettings settings(configFile(), QSettings::IniFormat); - settings.beginGroup( con ); - - quint64 interval = settings.value( QLatin1String(forceSyncIntervalC), 10 * pollInterval ).toULongLong(); - if( interval < pollInterval) { - qDebug() << "Force sync interval is less than the remote poll inteval, reverting to" << pollInterval; - interval = pollInterval; - } - return interval; -} - -bool MirallConfigFile::skipUpdateCheck( const QString& connection ) const -{ - QString con( connection ); - if( connection.isEmpty() ) con = defaultConnection(); - - QVariant fallback = getValue(QLatin1String(skipUpdateCheckC), con, false); - fallback = getValue(QLatin1String(skipUpdateCheckC), QString(), fallback); - - QVariant value = getPolicySetting(QLatin1String(skipUpdateCheckC), fallback); - return value.toBool(); -} - -void MirallConfigFile::setSkipUpdateCheck( bool skip, const QString& connection ) -{ - QString con( connection ); - if( connection.isEmpty() ) con = defaultConnection(); - - QSettings settings(configFile(), QSettings::IniFormat); - settings.beginGroup( con ); - - settings.setValue( QLatin1String(skipUpdateCheckC), QVariant(skip) ); - settings.sync(); - -} - -int MirallConfigFile::maxLogLines() const -{ - QSettings settings(configFile(), QSettings::IniFormat); - return settings.value( QLatin1String(maxLogLinesC), DEFAULT_MAX_LOG_LINES ).toInt(); -} - -void MirallConfigFile::setMaxLogLines( int lines ) -{ - QSettings settings(configFile(), QSettings::IniFormat); - settings.setValue(QLatin1String(maxLogLinesC), lines); - settings.sync(); -} - -void MirallConfigFile::setProxyType(int proxyType, - const QString& host, - int port, bool needsAuth, - const QString& user, - const QString& pass) -{ - QSettings settings(configFile(), QSettings::IniFormat); - - settings.setValue(QLatin1String(proxyTypeC), proxyType); - - if (proxyType == QNetworkProxy::HttpProxy || - proxyType == QNetworkProxy::Socks5Proxy) { - settings.setValue(QLatin1String(proxyHostC), host); - settings.setValue(QLatin1String(proxyPortC), port); - settings.setValue(QLatin1String(proxyNeedsAuthC), needsAuth); - settings.setValue(QLatin1String(proxyUserC), user); - settings.setValue(QLatin1String(proxyPassC), pass.toUtf8().toBase64()); - } - settings.sync(); -} - -QVariant MirallConfigFile::getValue(const QString& param, const QString& group, - const QVariant& defaultValue) const -{ - QVariant systemSetting; - if (Utility::isMac()) { - QSettings systemSettings(QLatin1String("/Library/Preferences/" APPLICATION_REV_DOMAIN ".plist"), QSettings::NativeFormat); - if (!group.isEmpty()) { - systemSettings.beginGroup(group); - } - systemSetting = systemSettings.value(param, defaultValue); - } else if (Utility::isUnix()) { - QSettings systemSettings(QString( SYSCONFDIR "/%1/%1.conf").arg(Theme::instance()->appName()), QSettings::NativeFormat); - if (!group.isEmpty()) { - systemSettings.beginGroup(group); - } - systemSetting = systemSettings.value(param, defaultValue); - } else { // Windows - QSettings systemSettings(QString::fromLatin1("HKEY_LOCAL_MACHINE\\Software\\%1\\%2") - .arg(APPLICATION_VENDOR).arg(Theme::instance()->appName()), - QSettings::NativeFormat); - if (!group.isEmpty()) { - systemSettings.beginGroup(group); - } - systemSetting = systemSettings.value(param, defaultValue); - } - - QSettings settings(configFile(), QSettings::IniFormat); - if (!group.isEmpty()) settings.beginGroup(group); - - return settings.value(param, systemSetting); -} - -void MirallConfigFile::setValue(const QString& key, const QVariant &value) -{ - QSettings settings(configFile(), QSettings::IniFormat); - - settings.setValue(key, value); -} - -int MirallConfigFile::proxyType() const -{ - return getValue(QLatin1String(proxyTypeC)).toInt(); -} - -QString MirallConfigFile::proxyHostName() const -{ - return getValue(QLatin1String(proxyHostC)).toString(); -} - -int MirallConfigFile::proxyPort() const -{ - return getValue(QLatin1String(proxyPortC)).toInt(); -} - -bool MirallConfigFile::proxyNeedsAuth() const -{ - return getValue(QLatin1String(proxyNeedsAuthC)).toBool(); -} - -QString MirallConfigFile::proxyUser() const -{ - return getValue(QLatin1String(proxyUserC)).toString(); -} - -QString MirallConfigFile::proxyPassword() const -{ - QByteArray pass = getValue(proxyPassC).toByteArray(); - return QString::fromUtf8(QByteArray::fromBase64(pass)); -} - -int MirallConfigFile::useUploadLimit() const -{ - return getValue(useUploadLimitC, QString::null, 0).toInt(); -} - -bool MirallConfigFile::useDownloadLimit() const -{ - return getValue(useDownloadLimitC, QString::null, false).toBool(); -} - -void MirallConfigFile::setUseUploadLimit(int val) -{ - setValue(useUploadLimitC, val); -} - -void MirallConfigFile::setUseDownloadLimit(bool enable) -{ - setValue(useDownloadLimitC, enable); -} - -int MirallConfigFile::uploadLimit() const -{ - return getValue(uploadLimitC, QString::null, 10).toInt(); -} - -int MirallConfigFile::downloadLimit() const -{ - return getValue(downloadLimitC, QString::null, 80).toInt(); -} - -void MirallConfigFile::setUploadLimit(int kbytes) -{ - setValue(uploadLimitC, kbytes); -} - -void MirallConfigFile::setDownloadLimit(int kbytes) -{ - setValue(downloadLimitC, kbytes); -} - -bool MirallConfigFile::monoIcons() const -{ - QSettings settings(configFile(), QSettings::IniFormat); - return settings.value(QLatin1String(monoIconsC), false).toBool(); -} - -void MirallConfigFile::setMonoIcons(bool useMonoIcons) -{ - QSettings settings(configFile(), QSettings::IniFormat); - settings.setValue(QLatin1String(monoIconsC), useMonoIcons); -} - -} diff --git a/src/mirall/mirallconfigfile.h b/src/mirall/mirallconfigfile.h deleted file mode 100644 index 8b7423fc8..000000000 --- a/src/mirall/mirallconfigfile.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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. - */ - -#ifndef MIRALLCONFIGFILE_H -#define MIRALLCONFIGFILE_H - -#include "owncloudlib.h" -#include <QSharedPointer> -#include <QString> -#include <QVariant> - -class QWidget; -class QHeaderView; - -namespace Mirall { - -class AbstractCredentials; - -class OWNCLOUDSYNC_EXPORT MirallConfigFile -{ -public: - MirallConfigFile(); - - enum Scope { UserScope, SystemScope }; - - QString configPath() const; - QString configPathWithAppName() const; - QString configFile() const; - QString excludeFile(Scope scope) const; - - bool exists(); - - QString defaultConnection() const; - - // the certs do not depend on a connection. - QByteArray caCerts(); - void setCaCerts( const QByteArray& ); - - bool passwordStorageAllowed(const QString &connection = QString::null ); - - QString ownCloudVersion() const; - void setOwnCloudVersion( const QString& ); - - // max count of lines in the log window - int maxLogLines() const; - void setMaxLogLines(int); - - /* Server poll interval in milliseconds */ - int remotePollInterval( const QString& connection = QString() ) const; - /* Set poll interval. Value in microseconds has to be larger than 5000 */ - void setRemotePollInterval(int interval, const QString& connection = QString() ); - - /* Force sync interval, in milliseconds */ - quint64 forceSyncInterval(const QString &connection = QString()) const; - - bool monoIcons() const; - void setMonoIcons(bool); - - // proxy settings - void setProxyType(int proxyType, - const QString& host = QString(), - int port = 0, bool needsAuth = false, - const QString& user = QString(), - const QString& pass = QString()); - - int proxyType() const; - QString proxyHostName() const; - int proxyPort() const; - bool proxyNeedsAuth() const; - QString proxyUser() const; - QString proxyPassword() const; - - /** 0: no limit, 1: manual, >0: automatic */ - int useUploadLimit() const; - bool useDownloadLimit() const; - void setUseUploadLimit(int); - void setUseDownloadLimit(bool); - /** in kbyte/s */ - int uploadLimit() const; - int downloadLimit() const; - void setUploadLimit(int kbytes); - void setDownloadLimit(int kbytes); - - static void setConfDir(const QString &value); - - bool optionalDesktopNotifications() const; - void setOptionalDesktopNotifications(bool show); - - int timeout() const; - - void saveGeometry(QWidget *w); - void restoreGeometry(QWidget *w); - - // installer - bool skipUpdateCheck( const QString& connection = QString() ) const; - void setSkipUpdateCheck( bool, const QString& ); - - QString lastVersion() const; - void setLastVersion(const QString &version); - - void saveGeometryHeader(QHeaderView *header); - void restoreGeometryHeader(QHeaderView *header); - -protected: - QVariant getPolicySetting(const QString& policy, const QVariant& defaultValue = QVariant()) const; - void storeData(const QString& group, const QString& key, const QVariant& value); - QVariant retrieveData(const QString& group, const QString& key) const; - void removeData(const QString& group, const QString& key); - bool dataExists(const QString& group, const QString& key) const; - -private: - QVariant getValue(const QString& param, const QString& group = QString::null, - const QVariant& defaultValue = QVariant()) const; - void setValue(const QString& key, const QVariant &value); - -private: - typedef QSharedPointer< AbstractCredentials > SharedCreds; - - static bool _askedUser; - static QString _oCVersion; - static QString _confDir; -}; - -} -#endif // MIRALLCONFIGFILE_H diff --git a/src/mirall/networkjobs.cpp b/src/mirall/networkjobs.cpp deleted file mode 100644 index 7034f148e..000000000 --- a/src/mirall/networkjobs.cpp +++ /dev/null @@ -1,610 +0,0 @@ -/* - * Copyright (C) by Klaas Freitag <freitag@owncloud.com> - * Copyright (C) by Daniel Molkentin <danimo@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. - */ - -#include <QNetworkRequest> -#include <QNetworkAccessManager> -#include <QNetworkReply> -#include <QNetworkRequest> -#include <QSslConfiguration> -#include <QBuffer> -#include <QXmlStreamReader> -#include <QStringList> -#include <QStack> -#include <QTimer> -#include <QMutex> -#include <QDebug> -#include <QCoreApplication> - -#include "json.h" - -#include "mirall/networkjobs.h" -#include "mirall/account.h" - -#include "creds/credentialsfactory.h" -#include "creds/abstractcredentials.h" - -Q_DECLARE_METATYPE(QTimer*) - -namespace Mirall { - -AbstractNetworkJob::AbstractNetworkJob(Account *account, const QString &path, QObject *parent) - : QObject(parent) - , _duration(0) - , _ignoreCredentialFailure(false) - , _reply(0) - , _account(account) - , _path(path) -{ - _timer.setSingleShot(true); - _timer.setInterval(10*1000); // default to 10 seconds. - connect(&_timer, SIGNAL(timeout()), this, SLOT(slotTimeout())); -} - -void AbstractNetworkJob::setReply(QNetworkReply *reply) -{ - if (_reply) { - _reply->deleteLater(); - } - _reply = reply; -} - -void AbstractNetworkJob::setTimeout(qint64 msec) -{ - qDebug() << Q_FUNC_INFO << msec; - - _timer.start(msec); -} - -void AbstractNetworkJob::resetTimeout() -{ - qint64 interval = _timer.interval(); - _timer.stop(); - _timer.start(interval); -} - -void AbstractNetworkJob::setIgnoreCredentialFailure(bool ignore) -{ - _ignoreCredentialFailure = ignore; -} - -void AbstractNetworkJob::setAccount(Account *account) -{ - _account = account; -} - -void AbstractNetworkJob::setPath(const QString &path) -{ - _path = path; -} - -void AbstractNetworkJob::setupConnections(QNetworkReply *reply) -{ - connect(reply, SIGNAL(finished()), SLOT(slotFinished())); -} - -QNetworkReply* AbstractNetworkJob::addTimer(QNetworkReply *reply) -{ - reply->setProperty("timer", QVariant::fromValue(&_timer)); - return reply; -} - -QNetworkReply* AbstractNetworkJob::davRequest(const QByteArray &verb, const QString &relPath, - QNetworkRequest req, QIODevice *data) -{ - return addTimer(_account->davRequest(verb, relPath, req, data)); -} - -QNetworkReply *AbstractNetworkJob::davRequest(const QByteArray &verb, const QUrl &url, QNetworkRequest req, QIODevice *data) -{ - return addTimer(_account->davRequest(verb, url, req, data)); -} - -QNetworkReply* AbstractNetworkJob::getRequest(const QString &relPath) -{ - return addTimer(_account->getRequest(relPath)); -} - -QNetworkReply *AbstractNetworkJob::getRequest(const QUrl &url) -{ - return addTimer(_account->getRequest(url)); -} - -QNetworkReply *AbstractNetworkJob::headRequest(const QString &relPath) -{ - return addTimer(_account->headRequest(relPath)); -} - -QNetworkReply *AbstractNetworkJob::headRequest(const QUrl &url) -{ - return addTimer(_account->headRequest(url)); -} - -void AbstractNetworkJob::slotFinished() -{ - _timer.stop(); - - if( _reply->error() != QNetworkReply::NoError ) { - qDebug() << Q_FUNC_INFO << _reply->error() << _reply->errorString(); - if (_reply->error() == QNetworkReply::ProxyAuthenticationRequiredError) { - qDebug() << Q_FUNC_INFO << _reply->rawHeader("Proxy-Authenticate"); - } - emit networkError(_reply); - } - - // get the Date timestamp from reply - _responseTimestamp = QString::fromAscii(_reply->rawHeader("Date")); - _duration = _durationTimer.elapsed(); - - bool discard = finished(); - AbstractCredentials *creds = _account->credentials(); - if (!creds->stillValid(_reply) &&! _ignoreCredentialFailure - && _account->state() != Account::InvalidCredidential) { - _account->setState(Account::InvalidCredidential); - - // invalidate & forget token/password - // but try to re-sign in. - connect( creds, SIGNAL(fetched()), - qApp, SLOT(slotCredentialsFetched()), Qt::UniqueConnection); - if (creds->ready()) { - creds->invalidateAndFetch(_account); - } else { - creds->fetch(_account); - } - } - if (discard) { - deleteLater(); - } -} - -quint64 AbstractNetworkJob::duration() -{ - return _duration; -} - -QString AbstractNetworkJob::responseTimestamp() -{ - return _responseTimestamp; -} - -AbstractNetworkJob::~AbstractNetworkJob() { - _reply->deleteLater(); -} - -void AbstractNetworkJob::start() -{ - _timer.start(); - _durationTimer.start(); - _duration = 0; - - qDebug() << "!!!" << metaObject()->className() << "created for" << account()->url() << "querying" << path(); -} - -/*********************************************************************************************/ - -RequestEtagJob::RequestEtagJob(Account *account, const QString &path, QObject *parent) - : AbstractNetworkJob(account, path, parent) -{ -} - -void RequestEtagJob::start() -{ - QNetworkRequest req; - if (path().isEmpty() || path() == QLatin1String("/")) { - /* For the root directory, we need to query the etags of all the sub directories - * because, at the time I am writing this comment (Owncloud 5.0.9), the etag of the - * root directory is not updated when the sub directories changes */ - req.setRawHeader("Depth", "1"); - } else { - req.setRawHeader("Depth", "0"); - } - QByteArray xml("<?xml version=\"1.0\" ?>\n" - "<d:propfind xmlns:d=\"DAV:\">\n" - " <d:prop>\n" - " <d:getetag/>\n" - " </d:prop>\n" - "</d:propfind>\n"); - QBuffer *buf = new QBuffer(this); - buf->setData(xml); - buf->open(QIODevice::ReadOnly); - // assumes ownership - setReply(davRequest("PROPFIND", path(), req, buf)); - buf->setParent(reply()); - setupConnections(reply()); - - if( reply()->error() != QNetworkReply::NoError ) { - qDebug() << "getting etag: request network error: " << reply()->errorString(); - } - AbstractNetworkJob::start(); -} - -bool RequestEtagJob::finished() -{ - if (reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) { - // Parse DAV response - QXmlStreamReader reader(reply()); - reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:")); - QString etag; - while (!reader.atEnd()) { - QXmlStreamReader::TokenType type = reader.readNext(); - if (type == QXmlStreamReader::StartElement && - reader.namespaceUri() == QLatin1String("DAV:")) { - QString name = reader.name().toString(); - if (name == QLatin1String("getetag")) { - etag += reader.readElementText(); - } - } - } - emit etagRetreived(etag); - } - return true; -} - -/*********************************************************************************************/ - -MkColJob::MkColJob(Account *account, const QString &path, QObject *parent) - : AbstractNetworkJob(account, path, parent) -{ -} - -void MkColJob::start() -{ - // assumes ownership - QNetworkReply *reply = davRequest("MKCOL", path()); - setReply(reply); - setupConnections(reply); - AbstractNetworkJob::start(); -} - -bool MkColJob::finished() -{ - emit finished(reply()->error()); - return true; -} - -/*********************************************************************************************/ - -LsColJob::LsColJob(Account *account, const QString &path, QObject *parent) - : AbstractNetworkJob(account, path, parent) -{ -} - -void LsColJob::start() -{ - QNetworkRequest req; - req.setRawHeader("Depth", "1"); - QByteArray xml("<?xml version=\"1.0\" ?>\n" - "<d:propfind xmlns:d=\"DAV:\">\n" - " <d:prop>\n" - " <d:resourcetype/>\n" - " </d:prop>\n" - "</d:propfind>\n"); - QBuffer *buf = new QBuffer(this); - buf->setData(xml); - buf->open(QIODevice::ReadOnly); - QNetworkReply *reply = davRequest("PROPFIND", path(), req, buf); - buf->setParent(reply); - setReply(reply); - setupConnections(reply); - AbstractNetworkJob::start(); -} - -bool LsColJob::finished() -{ - if (reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) { - // Parse DAV response - QXmlStreamReader reader(reply()); - reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:")); - - QStringList folders; - QString currentItem; - - while (!reader.atEnd()) { - QXmlStreamReader::TokenType type = reader.readNext(); - if (type == QXmlStreamReader::StartElement && - reader.namespaceUri() == QLatin1String("DAV:")) { - QString name = reader.name().toString(); - if (name == QLatin1String("href")) { - currentItem = reader.readElementText(); - } else if (name == QLatin1String("collection") && - !currentItem.isEmpty()) { - folders.append(QUrl::fromEncoded(currentItem.toLatin1()).path()); - currentItem.clear(); - } - } - } - emit directoryListing(folders); - } - return true; -} - -/*********************************************************************************************/ - -namespace { -const char statusphpC[] = "status.php"; -const char owncloudDirC[] = "owncloud/"; -} - -CheckServerJob::CheckServerJob(Account *account, bool followRedirect, QObject *parent) - : AbstractNetworkJob(account, QLatin1String(statusphpC) , parent) - , _followRedirects(followRedirect) - , _subdirFallback(false) - , _redirectCount(0) -{ - setIgnoreCredentialFailure(true); -} - -void CheckServerJob::start() -{ - setReply(getRequest(path())); - setupConnections(reply()); - AbstractNetworkJob::start(); -} - -void CheckServerJob::slotTimeout() -{ - qDebug() << "TIMEOUT" << Q_FUNC_INFO; - if (reply()->isRunning()) - emit timeout(reply()->url()); -} - -QString CheckServerJob::version(const QVariantMap &info) -{ - return info.value(QLatin1String("version")).toString(); -} - -QString CheckServerJob::versionString(const QVariantMap &info) -{ - return info.value(QLatin1String("versionstring")).toString(); -} - -bool CheckServerJob::installed(const QVariantMap &info) -{ - return info.value(QLatin1String("installed")).toBool(); -} - -bool CheckServerJob::finished() -{ - account()->setSslConfiguration(reply()->sslConfiguration()); - - // ### the qDebugs here should be exported via displayErrors() so they - // ### can be presented to the user if the job executor has a GUI - QUrl requestedUrl = reply()->request().url(); - QUrl redirectUrl = reply()->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); - if (!redirectUrl.isEmpty()) { - _redirectCount++; - if (requestedUrl.scheme() == QLatin1String("https") && - redirectUrl.scheme() == QLatin1String("http")) { - qDebug() << Q_FUNC_INFO << "HTTPS->HTTP downgrade detected!"; - } else if (requestedUrl == redirectUrl || _redirectCount >= maxRedirects()) { - qDebug() << Q_FUNC_INFO << "Redirect loop detected!"; - } else { - resetTimeout(); - setReply(getRequest(redirectUrl)); - setupConnections(reply()); - return false; - } - } - - // The serverInstalls to /owncloud. Let's try that if the file wasn't found - // at the original location - if ((reply()->error() == QNetworkReply::ContentNotFoundError) && (!_subdirFallback)) { - _subdirFallback = true; - setPath(QLatin1String(owncloudDirC)+QLatin1String(statusphpC)); - start(); - qDebug() << "Retrying with" << reply()->url(); - return false; - } - - bool success = false; - QByteArray body = reply()->readAll(); - if( body.isEmpty() ) { - emit instanceNotFound(reply()); - } else { - QVariantMap status = QtJson::parse(QString::fromUtf8(body), success).toMap(); - // empty or invalid response - if (!success || status.isEmpty()) { - qDebug() << "status.php from server is not valid JSON!"; - } - - qDebug() << "status.php returns: " << status << " " << reply()->error() << " Reply: " << reply(); - if( status.contains("installed") - && status.contains("version") - && status.contains("versionstring") ) { - emit instanceFound(reply()->url(), status); - } else { - qDebug() << "No proper answer on " << requestedUrl; - emit instanceNotFound(reply()); - } - } - return true; -} - -/*********************************************************************************************/ - -PropfindJob::PropfindJob(Account *account, const QString &path, QObject *parent) - : AbstractNetworkJob(account, path, parent) -{ - -} - -void PropfindJob::start() -{ - QList<QByteArray> properties = _properties; - - if (properties.isEmpty()) { - properties << "allprop"; - } - QNetworkRequest req; - req.setRawHeader("Depth", "0"); - QByteArray propStr; - foreach (const QByteArray &prop, properties) { - propStr += " <d:" + prop + " />\n"; - } - QByteArray xml = "<?xml version=\"1.0\" ?>\n" - "<d:propfind xmlns:d=\"DAV:\">\n" - " <d:prop>\n" - + propStr + - " </d:prop>\n" - "</d:propfind>\n"; - - QBuffer *buf = new QBuffer(this); - buf->setData(xml); - buf->open(QIODevice::ReadOnly); - setReply(davRequest("PROPFIND", path(), req, buf)); - buf->setParent(reply()); - setupConnections(reply()); - AbstractNetworkJob::start(); -} - -void PropfindJob::setProperties(QList<QByteArray> properties) -{ - _properties = properties; -} - -QList<QByteArray> PropfindJob::properties() const -{ - return _properties; -} - -bool PropfindJob::finished() -{ - int http_result_code = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - - if (http_result_code == 207) { - // Parse DAV response - QXmlStreamReader reader(reply()); - reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:")); - - QVariantMap items; - // introduced to nesting is ignored - QStack<QString> curElement; - - while (!reader.atEnd()) { - QXmlStreamReader::TokenType type = reader.readNext(); - if (type == QXmlStreamReader::StartElement && - reader.namespaceUri() == QLatin1String("DAV:")) { - if (curElement.isEmpty()) { - curElement.push(reader.name().toString()); - items.insert(reader.name().toString(), reader.text().toString()); - } - } - if (type == QXmlStreamReader::EndElement && - reader.namespaceUri() == QLatin1String("DAV:")) { - if(curElement.top() == reader.name()) { - curElement.pop(); - } - } - - } - emit result(items); - } else { - qDebug() << "Quota request *not* successful, http result code is" << http_result_code - << (http_result_code == 302 ? reply()->header(QNetworkRequest::LocationHeader).toString() : QLatin1String("")); - } - return true; -} - -/*********************************************************************************************/ - -EntityExistsJob::EntityExistsJob(Account *account, const QString &path, QObject *parent) - : AbstractNetworkJob(account, path, parent) -{ -} - -void EntityExistsJob::start() -{ - setReply(headRequest(path())); - setupConnections(reply()); - AbstractNetworkJob::start(); -} - -bool EntityExistsJob::finished() -{ - emit exists(reply()); - return true; -} - -/*********************************************************************************************/ - -CheckQuotaJob::CheckQuotaJob(Account *account, const QString &path, QObject *parent) - : AbstractNetworkJob(account, path, parent) -{ -} - -void CheckQuotaJob::start() -{ - QNetworkRequest req; - req.setRawHeader("Depth", "0"); - QByteArray xml("<?xml version=\"1.0\" ?>\n" - "<d:propfind xmlns:d=\"DAV:\">\n" - " <d:prop>\n" - " <d:quota-available-bytes/>\n" - " <d:quota-used-bytes/>\n" - " </d:prop>\n" - "</d:propfind>\n"); - QBuffer *buf = new QBuffer(this); - buf->setData(xml); - buf->open(QIODevice::ReadOnly); - // assumes ownership - setReply(davRequest("PROPFIND", path(), req, buf)); - buf->setParent(reply()); - setupConnections(reply()); - AbstractNetworkJob::start(); -} - -bool CheckQuotaJob::finished() -{ - if (reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) { - // Parse DAV response - QXmlStreamReader reader(reply()); - reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:")); - qint64 quotaAvailableBytes = 0; - qint64 quotaUsedBytes = 0; - while (!reader.atEnd()) { - QXmlStreamReader::TokenType type = reader.readNext(); - if (type == QXmlStreamReader::StartElement && - reader.namespaceUri() == QLatin1String("DAV:")) { - QString name = reader.name().toString(); - if (name == QLatin1String("quota-available-bytes")) { - // I have seen the server returning frational bytes: - // <d:quota-available-bytes>1374532061.2</d:quota-available-bytes> - quotaAvailableBytes = reader.readElementText().toDouble(); - } else if (name == QLatin1String("quota-used-bytes")) { - quotaUsedBytes = reader.readElementText().toDouble(); - } - } - } - qint64 total = quotaUsedBytes + quotaAvailableBytes; - emit quotaRetrieved(total, quotaUsedBytes); - } - return true; -} - -NetworkJobTimeoutPauser::NetworkJobTimeoutPauser(QNetworkReply *reply) -{ - _timer = reply->property("timer").value<QTimer*>(); - if(!_timer.isNull()) { - _timer->stop(); - } -} - -NetworkJobTimeoutPauser::~NetworkJobTimeoutPauser() -{ - if(!_timer.isNull()) { - _timer->start(); - } -} - -} // namespace Mirall diff --git a/src/mirall/networkjobs.h b/src/mirall/networkjobs.h deleted file mode 100644 index 5b8c196d3..000000000 --- a/src/mirall/networkjobs.h +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (C) by Klaas Freitag <freitag@owncloud.com> - * Copyright (C) by Daniel Molkentin <danimo@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. - */ - -#ifndef NETWORKJOBS_H -#define NETWORKJOBS_H - -#include "owncloudlib.h" -#include <QObject> -#include <QNetworkRequest> -#include <QNetworkReply> -#include <QPointer> -#include <QElapsedTimer> -#include <QDateTime> -#include <QTimer> - -class QUrl; - -namespace Mirall { - -class Account; -class AbstractSslErrorHandler; - - -/** - * @brief Internal Helper class - */ -class NetworkJobTimeoutPauser { -public: - NetworkJobTimeoutPauser(QNetworkReply *reply); - ~NetworkJobTimeoutPauser(); -private: - QPointer<QTimer> _timer; -}; - -/** - * @brief The AbstractNetworkJob class - */ -class OWNCLOUDSYNC_EXPORT AbstractNetworkJob : public QObject { - Q_OBJECT -public: - explicit AbstractNetworkJob(Account *account, const QString &path, QObject* parent = 0); - virtual ~AbstractNetworkJob(); - - virtual void start(); - - void setAccount(Account *account); - Account* account() const { return _account; } - void setPath(const QString &path); - QString path() const { return _path; } - - void setReply(QNetworkReply *reply); - QNetworkReply* reply() const { return _reply; } - - - void setIgnoreCredentialFailure(bool ignore); - bool ignoreCredentialFailure() const { return _ignoreCredentialFailure; } - - QString responseTimestamp(); - quint64 duration(); - -public slots: - void setTimeout(qint64 msec); - void resetTimeout(); -signals: - void networkError(QNetworkReply *reply); -protected: - void setupConnections(QNetworkReply *reply); - QNetworkReply* davRequest(const QByteArray& verb, const QString &relPath, - QNetworkRequest req = QNetworkRequest(), - QIODevice *data = 0); - QNetworkReply* davRequest(const QByteArray& verb, const QUrl &url, - QNetworkRequest req = QNetworkRequest(), - QIODevice *data = 0); - QNetworkReply* getRequest(const QString &relPath); - QNetworkReply* getRequest(const QUrl &url); - QNetworkReply* headRequest(const QString &relPath); - QNetworkReply* headRequest(const QUrl &url); - - int maxRedirects() const { return 10; } - virtual bool finished() = 0; - QString _responseTimestamp; - QElapsedTimer _durationTimer; - quint64 _duration; - -private slots: - void slotFinished(); - virtual void slotTimeout() {} - -private: - QNetworkReply* addTimer(QNetworkReply *reply); - bool _ignoreCredentialFailure; - QPointer<QNetworkReply> _reply; // (QPointer because the NetworkManager may be destroyed before the jobs at exit) - Account *_account; - QString _path; - QTimer _timer; -}; - -/** - * @brief The EntityExistsJob class - */ -class OWNCLOUDSYNC_EXPORT EntityExistsJob : public AbstractNetworkJob { - Q_OBJECT -public: - explicit EntityExistsJob(Account *account, const QString &path, QObject* parent = 0); - void start() Q_DECL_OVERRIDE; - -signals: - void exists(QNetworkReply*); - -private slots: - virtual bool finished() Q_DECL_OVERRIDE; -}; - -/** - * @brief The LsColJob class - */ -class OWNCLOUDSYNC_EXPORT LsColJob : public AbstractNetworkJob { - Q_OBJECT -public: - explicit LsColJob(Account *account, const QString &path, QObject *parent = 0); - void start() Q_DECL_OVERRIDE; - -signals: - void directoryListing(const QStringList &items); - -private slots: - virtual bool finished() Q_DECL_OVERRIDE; -}; - -/** - * @brief The PropfindJob class - */ -class PropfindJob : public AbstractNetworkJob { - Q_OBJECT -public: - explicit PropfindJob(Account *account, const QString &path, QObject *parent = 0); - void start() Q_DECL_OVERRIDE; - void setProperties(QList<QByteArray> properties); - QList<QByteArray> properties() const; - -signals: - void result(const QVariantMap &values); - -private slots: - virtual bool finished() Q_DECL_OVERRIDE; - -private: - QList<QByteArray> _properties; -}; - -/** - * @brief The MkColJob class - */ -class OWNCLOUDSYNC_EXPORT MkColJob : public AbstractNetworkJob { - Q_OBJECT -public: - explicit MkColJob(Account *account, const QString &path, QObject *parent = 0); - void start() Q_DECL_OVERRIDE; - -signals: - void finished(QNetworkReply::NetworkError); - -private slots: - virtual bool finished() Q_DECL_OVERRIDE; -}; - -/** - * @brief The CheckServerJob class - */ -class OWNCLOUDSYNC_EXPORT CheckServerJob : public AbstractNetworkJob { - Q_OBJECT -public: - explicit CheckServerJob(Account *account, bool followRedirect = false, QObject *parent = 0); - void start() Q_DECL_OVERRIDE; - - static QString version(const QVariantMap &info); - static QString versionString(const QVariantMap &info); - static bool installed(const QVariantMap &info); - -signals: - void instanceFound(const QUrl&url, const QVariantMap &info); - void instanceNotFound(QNetworkReply *reply); - void timeout(const QUrl&url); - -private slots: - virtual bool finished() Q_DECL_OVERRIDE; - virtual void slotTimeout() Q_DECL_OVERRIDE; - -private: - bool _followRedirects; - bool _subdirFallback; - int _redirectCount; -}; - - -/** - * @brief The RequestEtagJob class - */ -class OWNCLOUDSYNC_EXPORT RequestEtagJob : public AbstractNetworkJob { - Q_OBJECT -public: - explicit RequestEtagJob(Account *account, const QString &path, QObject *parent = 0); - void start() Q_DECL_OVERRIDE; - -signals: - void etagRetreived(const QString &etag); - -private slots: - virtual bool finished() Q_DECL_OVERRIDE; -}; - -/** - * @brief The CheckQuota class - */ -class CheckQuotaJob : public AbstractNetworkJob { - Q_OBJECT -public: - explicit CheckQuotaJob(Account *account, const QString &path, QObject *parent = 0); - void start() Q_DECL_OVERRIDE; - -signals: - void quotaRetrieved(qint64 totalBytes, qint64 availableBytes); - -private slots: - /** Return true if you want the job to be deleted after this slot has finished running. */ - virtual bool finished() Q_DECL_OVERRIDE; -}; - -} // namespace Mirall - -#endif // NETWORKJOBS_H diff --git a/src/mirall/networksettings.cpp b/src/mirall/networksettings.cpp deleted file mode 100644 index 6aecfd165..000000000 --- a/src/mirall/networksettings.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 "networksettings.h" -#include "ui_networksettings.h" - -#include "mirall/theme.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/application.h" -#include "mirall/utility.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/folderman.h" - -#include <QNetworkProxy> - -namespace Mirall { - -NetworkSettings::NetworkSettings(QWidget *parent) : - QWidget(parent), - _ui(new Ui::NetworkSettings) -{ - _ui->setupUi(this); - - _ui->hostLineEdit->setPlaceholderText(tr("Hostname of proxy server")); - _ui->userLineEdit->setPlaceholderText(tr("Username for proxy server")); - _ui->passwordLineEdit->setPlaceholderText(tr("Password for proxy server")); - - _ui->typeComboBox->addItem(tr("HTTP(S) proxy"), QNetworkProxy::HttpProxy); - _ui->typeComboBox->addItem(tr("SOCKS5 proxy"), QNetworkProxy::Socks5Proxy); - - _ui->authRequiredcheckBox->setEnabled(true); - - connect(_ui->manualProxyRadioButton, SIGNAL(toggled(bool)), - _ui->manualSettings, SLOT(setEnabled(bool))); - connect(_ui->manualProxyRadioButton, SIGNAL(toggled(bool)), - _ui->typeComboBox, SLOT(setEnabled(bool))); - connect(_ui->authRequiredcheckBox, SIGNAL(toggled(bool)), - _ui->authWidgets, SLOT(setEnabled(bool))); - - loadProxySettings(); - loadBWLimitSettings(); - - // proxy - connect(_ui->typeComboBox, SIGNAL(currentIndexChanged(int)), SLOT(saveProxySettings())); - connect(_ui->proxyButtonGroup, SIGNAL(buttonClicked(int)), SLOT(saveProxySettings())); - connect(_ui->hostLineEdit, SIGNAL(editingFinished()), SLOT(saveProxySettings())); - connect(_ui->userLineEdit, SIGNAL(editingFinished()), SLOT(saveProxySettings())); - connect(_ui->passwordLineEdit, SIGNAL(editingFinished()), SLOT(saveProxySettings())); - connect(_ui->portSpinBox, SIGNAL(editingFinished()), SLOT(saveProxySettings())); - - connect(_ui->uploadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings())); - connect(_ui->noUploadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings())); - connect(_ui->autoUploadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings())); - connect(_ui->downloadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings())); - connect(_ui->noDownloadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings())); - connect(_ui->downloadSpinBox, SIGNAL(valueChanged(int)), SLOT(saveBWLimitSettings())); - connect(_ui->uploadSpinBox, SIGNAL(valueChanged(int)), SLOT(saveBWLimitSettings())); -} - -NetworkSettings::~NetworkSettings() -{ - delete _ui; -} - -void NetworkSettings::loadProxySettings() -{ - // load current proxy settings - Mirall::MirallConfigFile cfgFile; - int type = cfgFile.proxyType(); - switch (type) { - case QNetworkProxy::NoProxy: - _ui->noProxyRadioButton->setChecked(true); - break; - case QNetworkProxy::DefaultProxy: - _ui->systemProxyRadioButton->setChecked(true); - break; - case QNetworkProxy::Socks5Proxy: - case QNetworkProxy::HttpProxy: - _ui->typeComboBox->setCurrentIndex(_ui->typeComboBox->findData(type)); - _ui->manualProxyRadioButton->setChecked(true); - break; - default: - break; - } - - _ui->hostLineEdit->setText(cfgFile.proxyHostName()); - int port = cfgFile.proxyPort(); - if (port == 0) - port = 8080; - _ui->portSpinBox->setValue(port); - if (!cfgFile.proxyUser().isEmpty()) - { - _ui->authRequiredcheckBox->setChecked(true); - _ui->userLineEdit->setText(cfgFile.proxyUser()); - _ui->passwordLineEdit->setText(cfgFile.proxyPassword()); - } -} - -void NetworkSettings::loadBWLimitSettings() -{ - MirallConfigFile cfgFile; - _ui->downloadLimitRadioButton->setChecked(cfgFile.useDownloadLimit()); - int uploadLimit = cfgFile.useUploadLimit(); - if ( uploadLimit >= 1 ) { - _ui->uploadLimitRadioButton->setChecked(true); - } else if (uploadLimit == 0){ - _ui->noUploadLimitRadioButton->setChecked(true); - } else { - _ui->autoUploadLimitRadioButton->setChecked(true); - } - _ui->downloadSpinBox->setValue(cfgFile.downloadLimit()); - _ui->uploadSpinBox->setValue(cfgFile.uploadLimit()); -} - -void NetworkSettings::saveProxySettings() -{ - MirallConfigFile cfgFile; - - if (_ui->noProxyRadioButton->isChecked()){ - cfgFile.setProxyType(QNetworkProxy::NoProxy); - } else if (_ui->systemProxyRadioButton->isChecked()){ - cfgFile.setProxyType(QNetworkProxy::DefaultProxy); - } else if (_ui->manualProxyRadioButton->isChecked()) { - int type = _ui->typeComboBox->itemData(_ui->typeComboBox->currentIndex()).toInt(); - bool needsAuth = _ui->authRequiredcheckBox->isChecked(); - QString user = _ui->userLineEdit->text(); - QString pass = _ui->passwordLineEdit->text(); - cfgFile.setProxyType(type, _ui->hostLineEdit->text(), - _ui->portSpinBox->value(), needsAuth, user, pass); - } - - ClientProxy proxy; - proxy.setupQtProxyFromConfig(); // Refresh the Qt proxy settings as the - // quota check can happen all the time. - - // ...and set the folders dirty, they refresh their proxy next time they - // start the sync. - FolderMan::instance()->setDirtyProxy(true); -} - -void NetworkSettings::saveBWLimitSettings() -{ - MirallConfigFile cfgFile; - cfgFile.setUseDownloadLimit(_ui->downloadLimitRadioButton->isChecked()); - - if (_ui->uploadLimitRadioButton->isChecked()) { - cfgFile.setUseUploadLimit(1); - } else if (_ui->noUploadLimitRadioButton->isChecked()) { - cfgFile.setUseUploadLimit(0); - } else if (_ui->autoUploadLimitRadioButton->isChecked()) { - cfgFile.setUseUploadLimit(-1); - } - - cfgFile.setDownloadLimit(_ui->downloadSpinBox->value()); - cfgFile.setUploadLimit(_ui->uploadSpinBox->value()); - - FolderMan::instance()->setDirtyNetworkLimits(); -} - -} // namespace Mirall diff --git a/src/mirall/networksettings.h b/src/mirall/networksettings.h deleted file mode 100644 index cb93e3782..000000000 --- a/src/mirall/networksettings.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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_NETWORKSETTINGS_H -#define MIRALL_NETWORKSETTINGS_H - -#include <QWidget> - - -namespace Mirall { - -namespace Ui { -class NetworkSettings; -} - -class NetworkSettings : public QWidget -{ - Q_OBJECT - -public: - explicit NetworkSettings(QWidget *parent = 0); - ~NetworkSettings(); - -private slots: - void saveProxySettings(); - void saveBWLimitSettings(); - -private: - void loadProxySettings(); - void loadBWLimitSettings(); - - Ui::NetworkSettings *_ui; -}; - - -} // namespace Mirall -#endif // MIRALL_NETWORKSETTINGS_H diff --git a/src/mirall/networksettings.ui b/src/mirall/networksettings.ui deleted file mode 100644 index 4f98f4b4a..000000000 --- a/src/mirall/networksettings.ui +++ /dev/null @@ -1,401 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>Mirall::NetworkSettings</class> - <widget class="QWidget" name="Mirall::NetworkSettings"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>518</width> - <height>384</height> - </rect> - </property> - <property name="windowTitle"> - <string>Form</string> - </property> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="0" column="0"> - <widget class="QGroupBox" name="proxyGroupBox"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="title"> - <string>Proxy Settings</string> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <widget class="QRadioButton" name="noProxyRadioButton"> - <property name="text"> - <string>No Proxy</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - <attribute name="buttonGroup"> - <string notr="true">proxyButtonGroup</string> - </attribute> - </widget> - </item> - <item row="1" column="0"> - <widget class="QRadioButton" name="systemProxyRadioButton"> - <property name="text"> - <string>Use system proxy</string> - </property> - <attribute name="buttonGroup"> - <string notr="true">proxyButtonGroup</string> - </attribute> - </widget> - </item> - <item row="2" column="0"> - <widget class="QRadioButton" name="manualProxyRadioButton"> - <property name="text"> - <string>Specify proxy manually as</string> - </property> - <attribute name="buttonGroup"> - <string notr="true">proxyButtonGroup</string> - </attribute> - </widget> - </item> - <item row="2" column="1"> - <widget class="QComboBox" name="typeComboBox"> - <property name="enabled"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="3" column="0" colspan="2"> - <widget class="QWidget" name="manualSettings" native="true"> - <property name="enabled"> - <bool>false</bool> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <property name="rightMargin"> - <number>0</number> - </property> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QLabel" name="hostLabel"> - <property name="text"> - <string>Host</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="hostLineEdit"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label"> - <property name="text"> - <string>:</string> - </property> - </widget> - </item> - <item> - <widget class="QSpinBox" name="portSpinBox"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>65535</number> - </property> - <property name="value"> - <number>8080</number> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QCheckBox" name="authRequiredcheckBox"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>Proxy server requires authentication</string> - </property> - </widget> - </item> - <item> - <widget class="QWidget" name="authWidgets" native="true"> - <property name="enabled"> - <bool>false</bool> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <property name="margin"> - <number>0</number> - </property> - <item> - <widget class="QLineEdit" name="userLineEdit"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="passwordLineEdit"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="text"> - <string/> - </property> - <property name="echoMode"> - <enum>QLineEdit::Password</enum> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - </item> - <item row="1" column="0"> - <layout class="QHBoxLayout" name="horizontalLayout_5"> - <item> - <widget class="QGroupBox" name="groupBox"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="title"> - <string>Download Bandwidth</string> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="2" column="0"> - <widget class="QRadioButton" name="downloadLimitRadioButton"> - <property name="text"> - <string>Limit to</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <item> - <widget class="QSpinBox" name="downloadSpinBox"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="maximum"> - <number>9999</number> - </property> - <property name="value"> - <number>80</number> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>KBytes/s</string> - </property> - </widget> - </item> - </layout> - </item> - <item row="0" column="0" colspan="2"> - <widget class="QRadioButton" name="noDownloadLimitRadioButton"> - <property name="text"> - <string>No limit</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="2" column="2"> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="3" column="0" colspan="2"> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>147</width> - <height>25</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="groupBox_2"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="title"> - <string>Upload Bandwidth</string> - </property> - <layout class="QGridLayout" name="gridLayout_4"> - <item row="2" column="0"> - <widget class="QRadioButton" name="uploadLimitRadioButton"> - <property name="text"> - <string>Limit to</string> - </property> - </widget> - </item> - <item row="1" column="0" colspan="2"> - <widget class="QRadioButton" name="autoUploadLimitRadioButton"> - <property name="text"> - <string>Limit automatically</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="0" column="0" colspan="2"> - <widget class="QRadioButton" name="noUploadLimitRadioButton"> - <property name="text"> - <string>No limit</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <layout class="QHBoxLayout" name="horizontalLayout_4"> - <item> - <widget class="QSpinBox" name="uploadSpinBox"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>9999</number> - </property> - <property name="value"> - <number>10</number> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string>KBytes/s</string> - </property> - </widget> - </item> - </layout> - </item> - <item row="2" column="2"> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - <zorder>autoUploadLimitRadioButton</zorder> - <zorder>uploadLimitRadioButton</zorder> - <zorder>noUploadLimitRadioButton</zorder> - <zorder>horizontalSpacer_2</zorder> - </widget> - </item> - </layout> - </item> - <item row="2" column="0"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <resources/> - <connections> - <connection> - <sender>downloadLimitRadioButton</sender> - <signal>toggled(bool)</signal> - <receiver>downloadSpinBox</receiver> - <slot>setEnabled(bool)</slot> - <hints> - <hint type="sourcelabel"> - <x>73</x> - <y>69</y> - </hint> - <hint type="destinationlabel"> - <x>131</x> - <y>78</y> - </hint> - </hints> - </connection> - <connection> - <sender>uploadLimitRadioButton</sender> - <signal>toggled(bool)</signal> - <receiver>uploadSpinBox</receiver> - <slot>setEnabled(bool)</slot> - <hints> - <hint type="sourcelabel"> - <x>322</x> - <y>101</y> - </hint> - <hint type="destinationlabel"> - <x>411</x> - <y>106</y> - </hint> - </hints> - </connection> - </connections> - <buttongroups> - <buttongroup name="proxyButtonGroup"/> - </buttongroups> -</ui> diff --git a/src/mirall/openfilemanager.cpp b/src/mirall/openfilemanager.cpp deleted file mode 100644 index 397c5c56a..000000000 --- a/src/mirall/openfilemanager.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) by Klaas Freitag <freitag@owncloud.com> - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 "openfilemanager.h" -#include "utility.h" -#include <QProcess> -#include <QSettings> -#include <QDir> -#include <QUrl> -#include <QDesktopServices> -#include <QDebug> -#include <QApplication> - -namespace Mirall { - -// according to the QStandardDir impl from Qt5 -static QStringList xdgDataDirs() -{ - QStringList dirs; - // http://standards.freedesktop.org/basedir-spec/latest/ - QString xdgDataDirsEnv = QFile::decodeName(qgetenv("XDG_DATA_DIRS")); - if (xdgDataDirsEnv.isEmpty()) { - dirs.append(QString::fromLatin1("/usr/local/share")); - dirs.append(QString::fromLatin1("/usr/share")); - } else { - dirs = xdgDataDirsEnv.split(QLatin1Char(':')); - } - // local location - QString xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME")); - if (xdgDataHome.isEmpty()) { - xdgDataHome = QDir::homePath()+"/.local/share"; - } - dirs.prepend(xdgDataHome); - return dirs; -} - -// Linux impl only, make sure to process %u and %U which might be returned -static QString findDefaultFileManager() -{ - QProcess p; - p.start("xdg-mime", QStringList() << "query" << "default" << "inode/directory", QFile::ReadOnly); - p.waitForFinished(); - QString fileName = QString::fromUtf8(p.readAll().trimmed()); - if (fileName.isEmpty()) - return QString(); - - QFileInfo fi; - QStringList dirs = xdgDataDirs(); - QStringList subdirs; - subdirs << "/applications/" << "/applications/kde4/"; - foreach(QString dir, dirs) { - foreach(QString subdir, subdirs) { - fi.setFile(dir + subdir + fileName); - if (fi.exists()) { - return fi.absoluteFilePath(); - } - } - } - return QString(); -} - -// early dolphin versions did not have --select -static bool checkDolphinCanSelect() -{ - QProcess p; - p.start("dolphin", QStringList() << "--help", QFile::ReadOnly); - p.waitForFinished(); - return p.readAll().contains("--select"); -} - - -// inspired by Qt Creator's showInGraphicalShell(); -void showInFileManager(const QString &localPath) -{ - if (Utility::isWindows()) { -#ifdef Q_OS_WIN - if (QSysInfo::windowsVersion() <= QSysInfo::WV_2003) { - return; - } -#endif - QString explorer = "explorer.exe "; // FIXME: we trust it's in PATH - - if (!QFileInfo(localPath).isDir()) { - explorer += QLatin1String("/select,"); - } - explorer += QLatin1Char('"'); - explorer += QDir::toNativeSeparators(localPath); - explorer += QLatin1Char('"'); - - qDebug() << "OO Open explorer commandline:" << explorer; - QProcess p; - p.start(explorer); - p.waitForFinished(5000); - } else if (Utility::isMac()) { - QStringList scriptArgs; - scriptArgs << QLatin1String("-e") - << QString::fromLatin1("tell application \"Finder\" to reveal POSIX file \"%1\"") - .arg(localPath); - QProcess::execute(QLatin1String("/usr/bin/osascript"), scriptArgs); - scriptArgs.clear(); - scriptArgs << QLatin1String("-e") - << QLatin1String("tell application \"Finder\" to activate"); - QProcess::execute(QLatin1String("/usr/bin/osascript"), scriptArgs); - } else { - QString app; - QStringList args; - - static QString defaultManager = findDefaultFileManager(); - QSettings desktopFile(defaultManager, QSettings::IniFormat); - QString exec = desktopFile.value("Desktop Entry/Exec").toString(); - - QString fileToOpen = QFileInfo(localPath).absoluteFilePath(); - QString pathToOpen = QFileInfo(localPath).absolutePath(); - bool canHandleFile = false; // assume dumb fm - - args = exec.split(' '); - if (args.count() > 0) app = args.takeFirst(); - - QString kdeSelectParam("--select"); - - if (app.contains("konqueror") && !args.contains(kdeSelectParam)) { - // konq needs '--select' in order not to launch the file - args.prepend(kdeSelectParam); - canHandleFile = true; - } - - if (app.contains("dolphin")) - { - static bool dolphinCanSelect = checkDolphinCanSelect(); - if (dolphinCanSelect && !args.contains(kdeSelectParam)) { - args.prepend(kdeSelectParam); - canHandleFile = true; - } - } - - // whitelist - if (app.contains("nautilus") || app.contains("nemo")) { - canHandleFile = true; - } - - static QString name; - if (name.isEmpty()) { - name = desktopFile.value(QString::fromLatin1("Desktop Entry/Name[%1]").arg(qApp->property("ui_lang").toString())).toString(); - if (name.isEmpty()) { - name = desktopFile.value(QString::fromLatin1("Desktop Entry/Name")).toString(); - } - } - - std::replace(args.begin(), args.end(), QString::fromLatin1("%c"), name); - std::replace(args.begin(), args.end(), QString::fromLatin1("%u"), fileToOpen); - std::replace(args.begin(), args.end(), QString::fromLatin1("%U"), fileToOpen); - std::replace(args.begin(), args.end(), QString::fromLatin1("%f"), fileToOpen); - std::replace(args.begin(), args.end(), QString::fromLatin1("%F"), fileToOpen); - - // fixme: needs to append --icon, according to http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables - QStringList::iterator it = std::find(args.begin(), args.end(), QString::fromLatin1("%i")); - if (it != args.end()) { - (*it) = desktopFile.value("Desktop Entry/Icon").toString(); - args.insert(it, QString::fromLatin1("--icon")); // before - } - - - if (args.count() == 0) args << fileToOpen; - - if (app.isEmpty() || args.isEmpty() || !canHandleFile) { - // fall back: open the default file manager, without ever selecting the file - QDesktopServices::openUrl(QUrl::fromLocalFile(pathToOpen)); - } else { - QProcess::startDetached(app, args); - } - } -} - -}
\ No newline at end of file diff --git a/src/mirall/openfilemanager.h b/src/mirall/openfilemanager.h deleted file mode 100644 index c395f15fe..000000000 --- a/src/mirall/openfilemanager.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) by Olivier Goffart <ogoffart@woboq.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; version 2 of the License. - * - * 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. - */ -#pragma once - -#include <QString> - -namespace Mirall { -/** Open the file manager with the specified file pre-selected */ -void showInFileManager(const QString &localPath); -} diff --git a/src/mirall/owncloudgui.cpp b/src/mirall/owncloudgui.cpp deleted file mode 100644 index 7de5c5cb0..000000000 --- a/src/mirall/owncloudgui.cpp +++ /dev/null @@ -1,541 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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/application.h" -#include "mirall/owncloudgui.h" -#include "mirall/theme.h" -#include "mirall/folderman.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/utility.h" -#include "mirall/progressdispatcher.h" -#include "mirall/owncloudsetupwizard.h" -#if defined(Q_OS_MAC) -# include "mirall/settingsdialogmac.h" -#else -# include "mirall/settingsdialog.h" -#endif -#include "mirall/logger.h" -#include "mirall/logbrowser.h" -#include "mirall/account.h" -#include "openfilemanager.h" -#include "creds/abstractcredentials.h" - -#include <QDesktopServices> -#include <QMessageBox> -#include <QSignalMapper> - -namespace Mirall { - -ownCloudGui::ownCloudGui(Application *parent) : - QObject(parent), - _tray(0), -#if defined(Q_OS_MAC) - _settingsDialog(new SettingsDialogMac(this)), -#else - _settingsDialog(new SettingsDialog(this)), -#endif - _logBrowser(0), - _contextMenu(0), - _recentActionsMenu(0), - _folderOpenActionMapper(new QSignalMapper(this)), - _recentItemsMapper(new QSignalMapper(this)), - _app(parent) -{ - _tray = new Systray(); - _tray->setParent(this); - _tray->setIcon( Theme::instance()->syncStateIcon( SyncResult::NotYetStarted, true ) ); - - connect(_tray.data(), SIGNAL(activated(QSystemTrayIcon::ActivationReason)), - SLOT(slotTrayClicked(QSystemTrayIcon::ActivationReason))); - - setupActions(); - setupContextMenu(); - - _tray->show(); - - /* use a signal mapper to map the open requests to the alias names */ - connect(_folderOpenActionMapper, SIGNAL(mapped(QString)), - this, SLOT(slotFolderOpenAction(QString))); - - connect(_recentItemsMapper, SIGNAL(mapped(QString)), - this, SLOT(slotOpenPath(QString))); - - ProgressDispatcher *pd = ProgressDispatcher::instance(); - connect( pd, SIGNAL(progressInfo(QString,Progress::Info)), this, - SLOT(slotUpdateProgress(QString,Progress::Info)) ); - - FolderMan *folderMan = FolderMan::instance(); - connect( folderMan, SIGNAL(folderSyncStateChange(QString)), - this,SLOT(slotSyncStateChange(QString))); - - connect( Logger::instance(), SIGNAL(guiLog(QString,QString)), - SLOT(slotShowTrayMessage(QString,QString))); - connect( Logger::instance(), SIGNAL(optionalGuiLog(QString,QString)), - SLOT(slotShowOptionalTrayMessage(QString,QString))); - connect( Logger::instance(), SIGNAL(guiMessage(QString,QString)), - SLOT(slotShowGuiMessage(QString,QString))); -} - -// This should rather be in application.... or rather in MirallConfigFile? -void ownCloudGui::slotOpenSettingsDialog( bool openSettings ) -{ - // if account is set up, start the configuration wizard. - if( AccountManager::instance()->account() ) { - if( openSettings ) { - if (_settingsDialog.isNull() || !_settingsDialog->isVisible()) { - slotShowSettings(); - } else { - _settingsDialog->close(); - } - } - } else { - qDebug() << "No configured folders yet, starting setup wizard"; - OwncloudSetupWizard::runWizard(qApp, SLOT(slotownCloudWizardDone(int))); - } -} - -void ownCloudGui::slotTrayClicked( QSystemTrayIcon::ActivationReason reason ) -{ - // A click on the tray icon should only open the status window on Win and - // Linux, not on Mac. They want a menu entry. -#if !defined Q_OS_MAC - if( reason == QSystemTrayIcon::Trigger ) { - slotOpenSettingsDialog(true); // start settings if config is existing. - } -#endif -} - -void ownCloudGui::slotSyncStateChange( const QString& alias ) -{ - FolderMan *folderMan = FolderMan::instance(); - const SyncResult& result = folderMan->syncResult( alias ); - - slotComputeOverallSyncStatus(); - - qDebug() << "Sync state changed for folder " << alias << ": " << result.statusString(); - - // Promote sync result to settings-dialog for sync protocol? - // if( _progressDialog ) { - // _progressDialog->setSyncResult(result); - // } - if (result.status() == SyncResult::Success || result.status() == SyncResult::Error) { - Logger::instance()->enterNextLogFile(); - } -} - -void ownCloudGui::slotFoldersChanged() -{ - slotComputeOverallSyncStatus(); - setupContextMenu(); -} - -void ownCloudGui::slotOpenPath(const QString &path) -{ - showInFileManager(path); -} - -void ownCloudGui::slotAccountStateChanged() -{ - setupContextMenu(); - slotComputeOverallSyncStatus(); -} - -void ownCloudGui::startupConnected( bool connected, const QStringList& fails ) -{ - FolderMan *folderMan = FolderMan::instance(); - - if( connected ) { - qDebug() << "######## connected to ownCloud Server!"; - folderMan->setSyncEnabled(true); - _tray->setIcon( Theme::instance()->syncStateIcon( SyncResult::NotYetStarted, true ) ); - _tray->show(); - } - - _startupFails = fails; // store that for the settings dialog once it appears. - if( !_settingsDialog.isNull() ) - _settingsDialog->setGeneralErrors( _startupFails ); - -} - -void ownCloudGui::slotComputeOverallSyncStatus() -{ - if (Account *a = AccountManager::instance()->account()) { - if (a->state() == Account::SignedOut) { - _tray->setIcon(Theme::instance()->syncStateIcon( SyncResult::Unavailable, true)); - _tray->setToolTip(tr("Please sign in")); - return; - } - if (a->state() == Account::Disconnected) { - _tray->setIcon(Theme::instance()->syncStateIcon( SyncResult::Unavailable, true)); - _tray->setToolTip(tr("Disconnected from server")); - return; - } - } - // display the info of the least successful sync (eg. not just display the result of the latest sync - QString trayMessage; - FolderMan *folderMan = FolderMan::instance(); - Folder::Map map = folderMan->map(); - SyncResult overallResult = FolderMan::accountStatus(map.values()); - - // if there have been startup problems, show an error message. - if( !_settingsDialog.isNull() ) - _settingsDialog->setGeneralErrors( _startupFails ); - - if( !_startupFails.isEmpty() ) { - trayMessage = _startupFails.join(QLatin1String("\n")); - QIcon statusIcon; - if (_app->_startupNetworkError) { - statusIcon = Theme::instance()->syncStateIcon( SyncResult::NotYetStarted, true ); - } else { - statusIcon = Theme::instance()->syncStateIcon( SyncResult::Error, true ); - } - - _tray->setIcon( statusIcon ); - _tray->setToolTip(trayMessage); - } else { - // create the tray blob message, check if we have an defined state - if( overallResult.status() != SyncResult::Undefined ) { - QStringList allStatusStrings; - foreach(Folder* folder, map.values()) { - qDebug() << "Folder in overallStatus Message: " << folder << " with name " << folder->alias(); - QString folderMessage = folderMan->statusToString(folder->syncResult().status(), folder->syncEnabled()); - allStatusStrings += tr("Folder %1: %2").arg(folder->alias(), folderMessage); - } - - if( ! allStatusStrings.isEmpty() ) - trayMessage = allStatusStrings.join(QLatin1String("\n")); - else - trayMessage = tr("No sync folders configured."); - - QIcon statusIcon = Theme::instance()->syncStateIcon( overallResult.status(), true); - _tray->setIcon( statusIcon ); - _tray->setToolTip(trayMessage); - } - } -} - -void ownCloudGui::setupContextMenu() -{ - FolderMan *folderMan = FolderMan::instance(); - - Account *a = AccountManager::instance()->account(); - - bool isConfigured = (a != 0); - _actionOpenoC->setEnabled(isConfigured); - bool isConnected = false; - if (isConfigured) { - isConnected = (a->state() == Account::Connected); - } - - if ( _contextMenu ) { - _contextMenu->clear(); - _recentActionsMenu->clear(); - _recentActionsMenu->addAction(tr("None.")); - _recentActionsMenu->addAction(_actionRecent); - } else { - _contextMenu = new QMenu(_contextMenu); - _recentActionsMenu = new QMenu(tr("Recent Changes")); - // this must be called only once after creating the context menu, or - // it will trigger a bug in Ubuntu's SNI bridge patch (11.10, 12.04). - _tray->setContextMenu(_contextMenu); - } - _contextMenu->setTitle(Theme::instance()->appNameGUI() ); - _contextMenu->addAction(_actionOpenoC); - - int folderCnt = folderMan->map().size(); - // add open actions for all sync folders to the tray menu - if( Theme::instance()->singleSyncFolder() ) { - // there should be exactly one folder. No sync-folder add action will be shown. - QStringList li = folderMan->map().keys(); - if( li.size() == 1 ) { - Folder *folder = folderMan->map().value(li.first()); - if( folder ) { - // if there is singleFolder mode, a generic open action is displayed. - QAction *action = new QAction( tr("Open %1 folder").arg(Theme::instance()->appNameGUI()), this); - connect( action, SIGNAL(triggered()),_folderOpenActionMapper,SLOT(map())); - _folderOpenActionMapper->setMapping( action, folder->alias() ); - - _contextMenu->addAction(action); - } - } - } else { - // show a grouping with more than one folder. - if ( folderCnt > 1) { - _contextMenu->addAction(tr("Managed Folders:"))->setDisabled(true); - } - foreach (Folder *folder, folderMan->map() ) { - QAction *action = new QAction( tr("Open folder '%1'").arg(folder->alias()), this ); - connect( action, SIGNAL(triggered()),_folderOpenActionMapper,SLOT(map())); - _folderOpenActionMapper->setMapping( action, folder->alias() ); - - _contextMenu->addAction(action); - } - } - _contextMenu->addSeparator(); - - if (isConfigured && isConnected) { - _contextMenu->addAction(_actionQuota); - _contextMenu->addSeparator(); - _contextMenu->addAction(_actionStatus); - _contextMenu->addMenu(_recentActionsMenu); - _contextMenu->addSeparator(); - } - _contextMenu->addAction(_actionSettings); - if (!Theme::instance()->helpUrl().isEmpty()) { - _contextMenu->addAction(_actionHelp); - } - _contextMenu->addSeparator(); - if (isConfigured && isConnected) { - _contextMenu->addAction(_actionLogout); - } else { - _contextMenu->addAction(_actionLogin); - } - _contextMenu->addAction(_actionQuit); -} - - -void ownCloudGui::slotShowTrayMessage(const QString &title, const QString &msg) -{ - if( _tray ) - _tray->showMessage(title, msg); - else - qDebug() << "Tray not ready: " << msg; -} - -void ownCloudGui::slotShowOptionalTrayMessage(const QString &title, const QString &msg) -{ - MirallConfigFile cfg; - if (cfg.optionalDesktopNotifications()) { - slotShowTrayMessage(title, msg); - } -} - - -/* - * open the folder with the given Alais - */ -void ownCloudGui::slotFolderOpenAction( const QString& alias ) -{ - Folder *f = FolderMan::instance()->folder(alias); - if( f ) { - qDebug() << "opening local url " << f->path(); - QUrl url = QUrl::fromLocalFile(f->path()); - -#ifdef Q_OS_WIN - // work around a bug in QDesktopServices on Win32, see i-net - QString filePath = f->path(); - - if (filePath.startsWith(QLatin1String("\\\\")) || filePath.startsWith(QLatin1String("//"))) - url.setUrl(QDir::toNativeSeparators(filePath)); - else - url = QUrl::fromLocalFile(filePath); -#endif - QDesktopServices::openUrl(url); - } -} - -void ownCloudGui::setupActions() -{ - _actionOpenoC = new QAction(tr("Open %1 in browser").arg(Theme::instance()->appNameGUI()), this); - QObject::connect(_actionOpenoC, SIGNAL(triggered(bool)), SLOT(slotOpenOwnCloud())); - _actionQuota = new QAction(tr("Calculating quota..."), this); - _actionQuota->setEnabled( false ); - _actionStatus = new QAction(tr("Unknown status"), this); - _actionStatus->setEnabled( false ); - _actionSettings = new QAction(tr("Settings..."), this); - _actionRecent = new QAction(tr("Details..."), this); - _actionRecent->setEnabled( true ); - - QObject::connect(_actionRecent, SIGNAL(triggered(bool)), SLOT(slotShowSyncProtocol())); - QObject::connect(_actionSettings, SIGNAL(triggered(bool)), SLOT(slotShowSettings())); - _actionHelp = new QAction(tr("Help"), this); - QObject::connect(_actionHelp, SIGNAL(triggered(bool)), SLOT(slotHelp())); - _actionQuit = new QAction(tr("Quit %1").arg(Theme::instance()->appNameGUI()), this); - QObject::connect(_actionQuit, SIGNAL(triggered(bool)), _app, SLOT(quit())); - - _actionLogin = new QAction(tr("Sign in..."), this); - connect(_actionLogin, SIGNAL(triggered()), _app, SLOT(slotLogin())); - _actionLogout = new QAction(tr("Sign out"), this); - connect(_actionLogout, SIGNAL(triggered()), _app, SLOT(slotLogout())); - -} - -void ownCloudGui::slotRefreshQuotaDisplay( qint64 total, qint64 used ) -{ - if (total == 0) { - _actionQuota->setText(tr("Quota n/a")); - return; - } - - double percent = used/(double)total*100; - QString percentFormatted = Utility::compactFormatDouble(percent, 1); - QString totalFormatted = Utility::octetsToString(total); - _actionQuota->setText(tr("%1% of %2 in use").arg(percentFormatted).arg(totalFormatted)); -} - -void ownCloudGui::slotRebuildRecentMenus() -{ - _recentActionsMenu->clear(); - if (!_recentItemsActions.isEmpty()) { - foreach(QAction *a, _recentItemsActions) { - _recentActionsMenu->addAction(a); - } - _recentActionsMenu->addSeparator(); - } else { - _recentActionsMenu->addAction(tr("No items synced recently"))->setEnabled(false); - } - // add a more... entry. - _recentActionsMenu->addAction(_actionRecent); -} - - -void ownCloudGui::slotUpdateProgress(const QString &folder, const Progress::Info& progress) -{ - Q_UNUSED(folder); - - QString totalSizeStr = Utility::octetsToString( progress._totalSize ); - if(progress._totalSize == 0 ) { - quint64 currentFile = progress._completedFileCount + progress._currentItems.count(); - _actionStatus->setText( tr("Syncing %1 of %2 (%3 left)") - .arg( currentFile ).arg( progress._totalFileCount ) - .arg( Utility::timeToDescriptiveString(progress.totalEstimate().getEtaEstimate(), 2, " ",true) ) ); - } else { - _actionStatus->setText( tr("Syncing %1 (%2 left)") - .arg( totalSizeStr ) - .arg( Utility::timeToDescriptiveString(progress.totalEstimate().getEtaEstimate(), 2, " ",true) ) ); - } - - - - - _actionRecent->setIcon( QIcon() ); // Fixme: Set a "in-progress"-item eventually. - - if (!progress._lastCompletedItem.isEmpty()) { - - if (Progress::isWarningKind(progress._lastCompletedItem._status)) { - // display a warn icon if warnings happend. - QIcon warnIcon(":/mirall/resources/warning-16"); - _actionRecent->setIcon(warnIcon); - } - - QString kindStr = Progress::asResultString(progress._lastCompletedItem); - QString timeStr = QTime::currentTime().toString("hh:mm"); - QString actionText = tr("%1 (%2, %3)").arg(progress._lastCompletedItem._file, kindStr, timeStr); - QAction *action = new QAction(actionText, this); - Folder *f = FolderMan::instance()->folder(folder); - if (f) { - QString fullPath = f->path() + '/' + progress._lastCompletedItem._file; - if (QFile(fullPath).exists()) { - _recentItemsMapper->setMapping(action, fullPath); - connect(action, SIGNAL(triggered()), _recentItemsMapper, SLOT(map())); - } else { - action->setEnabled(false); - } - } - if (_recentItemsActions.length() > 5) { - _recentItemsActions.takeFirst()->deleteLater(); - } - _recentItemsActions.append(action); - - slotRebuildRecentMenus(); - } - - if (progress._completedFileCount == progress._totalFileCount) { - QTimer::singleShot(2000, this, SLOT(slotDisplayIdle())); - } -} - -void ownCloudGui::slotDisplayIdle() -{ - _actionStatus->setText(tr("Up to date")); -} - -void ownCloudGui::slotShowGuiMessage(const QString &title, const QString &message) -{ - QMessageBox *msgBox = new QMessageBox; - msgBox->setAttribute(Qt::WA_DeleteOnClose); - msgBox->setText(message); - msgBox->setWindowTitle(title); - msgBox->setIcon(QMessageBox::Information); - msgBox->open(); -} - -void ownCloudGui::slotShowSettings() -{ - if (_settingsDialog.isNull()) { - _settingsDialog = -#if defined(Q_OS_MAC) - new SettingsDialogMac(this); -#else - new SettingsDialog(this); -#endif - _settingsDialog->setAttribute( Qt::WA_DeleteOnClose, true ); - _settingsDialog->show(); - } - _settingsDialog->setGeneralErrors( _startupFails ); - raiseDialog(_settingsDialog.data()); -} - -void ownCloudGui::slotShowSyncProtocol() -{ - slotShowSettings(); - _settingsDialog->showActivityPage(); -} - - -void ownCloudGui::slotShutdown() -{ - // those do delete on close - if (!_settingsDialog.isNull()) _settingsDialog->close(); - if (!_logBrowser.isNull()) _logBrowser->deleteLater(); -} - -void ownCloudGui::slotToggleLogBrowser() -{ - if (_logBrowser.isNull()) { - // init the log browser. - _logBrowser = new LogBrowser; - // ## TODO: allow new log name maybe? - } - - if (_logBrowser->isVisible() ) { - _logBrowser->hide(); - } else { - raiseDialog(_logBrowser); - } -} - -void ownCloudGui::slotOpenOwnCloud() -{ - if (Account *account = AccountManager::instance()->account()) { - QDesktopServices::openUrl(account->url()); - } -} - -void ownCloudGui::slotHelp() -{ - QDesktopServices::openUrl(QUrl(Theme::instance()->helpUrl())); -} - -void ownCloudGui::raiseDialog( QWidget *raiseWidget ) -{ - if( raiseWidget && raiseWidget->parentWidget() == 0) { - // Qt has a bug which causes parent-less dialogs to pop-under. - raiseWidget->showNormal(); - raiseWidget->raise(); - raiseWidget->activateWindow(); - } -} - - -} // end namespace diff --git a/src/mirall/owncloudgui.h b/src/mirall/owncloudgui.h deleted file mode 100644 index c67e43c21..000000000 --- a/src/mirall/owncloudgui.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 OWNCLOUDGUI_H -#define OWNCLOUDGUI_H - -#include "mirall/systray.h" -#include "mirall/connectionvalidator.h" -#include "mirall/progressdispatcher.h" -#include "mirall/quotainfo.h" - -#include <QObject> -#include <QPointer> -#include <QAction> -#include <QMenu> -#include <QSignalMapper> - -namespace Mirall { - -class SettingsDialog; -class SettingsDialogMac; -class Application; -class LogBrowser; - -class ownCloudGui : public QObject -{ - Q_OBJECT -public: - explicit ownCloudGui(Application *parent = 0); - - void setupContextMenu(); - void startupConnected(bool connected , const QStringList &fails); - - bool checkAccountExists(bool openSettings); - - static void raiseDialog(QWidget *raiseWidget); - -signals: - void setupProxy(); - -public slots: - void slotComputeOverallSyncStatus(); - void slotShowTrayMessage(const QString &title, const QString &msg); - void slotShowOptionalTrayMessage(const QString &title, const QString &msg); - void slotFolderOpenAction( const QString& alias ); - void slotRefreshQuotaDisplay( qint64 total, qint64 used ); - void slotRebuildRecentMenus(); - void slotUpdateProgress(const QString &folder, const Progress::Info& progress); - void slotShowGuiMessage(const QString &title, const QString &message); - void slotFoldersChanged(); - void slotShowSettings(); - void slotShowSyncProtocol(); - void slotShutdown(); - void slotSyncStateChange( const QString& alias ); - void slotTrayClicked( QSystemTrayIcon::ActivationReason reason ); - void slotToggleLogBrowser(); - void slotOpenOwnCloud(); - void slotOpenSettingsDialog( bool openSettings ); - void slotHelp(); - void slotOpenPath(const QString& path); - void slotAccountStateChanged(); - -private slots: - void slotDisplayIdle(); - -private: - void setupActions(); - - QPointer<Systray> _tray; -#if defined(Q_OS_MAC) - QPointer<SettingsDialogMac> _settingsDialog; -#else - QPointer<SettingsDialog> _settingsDialog; -#endif - QPointer<LogBrowser>_logBrowser; - // tray's menu - QMenu *_contextMenu; - QMenu *_recentActionsMenu; - - QAction *_actionLogin; - QAction *_actionLogout; - - QAction *_actionOpenoC; - QAction *_actionSettings; - QAction *_actionQuota; - QAction *_actionStatus; - QAction *_actionEstimate; - QAction *_actionRecent; - QAction *_actionHelp; - QAction *_actionQuit; - - QList<QAction*> _recentItemsActions; - - QSignalMapper *_folderOpenActionMapper; - QSignalMapper *_recentItemsMapper; - - Application *_app; - - QStringList _startupFails; -}; - -} // namespace Mirall - -#endif // OWNCLOUDGUI_H diff --git a/src/mirall/owncloudpropagator.cpp b/src/mirall/owncloudpropagator.cpp deleted file mode 100644 index 876e97d94..000000000 --- a/src/mirall/owncloudpropagator.cpp +++ /dev/null @@ -1,453 +0,0 @@ -/* - * Copyright (C) by Olivier Goffart <ogoffart@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 - * 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 "owncloudpropagator.h" -#include "syncjournaldb.h" -#include "syncjournalfilerecord.h" -#include "propagator_qnam.h" -#include "propagatorjobs.h" -#include "propagator_legacy.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/utility.h" - -#ifdef Q_OS_WIN -#include <windef.h> -#include <winbase.h> -#endif - -#include <QStack> -#include <QFileInfo> -#include <QDir> - -namespace Mirall { - -/* The maximum number of active job in parallel */ -static int maximumActiveJob() { - static int max = qgetenv("OWNCLOUD_MAX_PARALLEL").toUInt(); - if (!max) { - max = 3; //default - } - return max; -} - -void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorString) -{ - if (_item._isRestoration) { - if( status == SyncFileItem::Success || status == SyncFileItem::Conflict) { - status = SyncFileItem::Restoration; - } else { - _item._errorString += tr("; Restoration Failed: ") + errorString; - } - } else { - _item._errorString = errorString; - } - _item._status = status; - - // Blacklisting - int retries = 0; - - if( _item._httpErrorCode == 403 ||_item._httpErrorCode == 413 || _item._httpErrorCode == 415 ) { - qDebug() << "Fatal Error condition" << _item._httpErrorCode << ", forbid retry!"; - retries = -1; - } else { - static QAtomicInt defaultRetriesCount(qgetenv("OWNCLOUD_BLACKLIST_COUNT").toInt()); - if (defaultRetriesCount.fetchAndAddAcquire(0) <= 0) { - defaultRetriesCount.fetchAndStoreRelease(3); - } - retries = defaultRetriesCount.fetchAndAddAcquire(0); - } - SyncJournalBlacklistRecord record(_item, retries);; - - switch( status ) { - case SyncFileItem::SoftError: - case SyncFileItem::FatalError: - // do not blacklist in case of soft error or fatal error. - break; - case SyncFileItem::NormalError: -#ifdef OWNCLOUD_5XX_NO_BLACKLIST - if (_item._httpErrorCode / 100 == 5) { - // In this configuration, never blacklist error 5xx - qDebug() << "Do not blacklist error " << _item._httpErrorCode; - break; - } -#endif - _propagator->_journal->updateBlacklistEntry( record ); - break; - case SyncFileItem::Success: - case SyncFileItem::Restoration: - if( _item._blacklistedInDb ) { - // wipe blacklist entry. - _propagator->_journal->wipeBlacklistEntry(_item._file); - } - break; - case SyncFileItem::Conflict: - case SyncFileItem::FileIgnored: - case SyncFileItem::NoStatus: - // nothing - break; - } - - emit completed(_item); - emit finished(status); -} - -/** - * For delete or remove, check that we are not removing from a shared directory. - * If we are, try to restore the file - * - * Return true if the problem is handled. - */ -bool PropagateItemJob::checkForProblemsWithShared(int httpStatusCode, const QString& msg) -{ - PropagateItemJob *newJob = NULL; - - if( httpStatusCode == 403 && _propagator->isInSharedDirectory(_item._file )) { - if( !_item._isDirectory ) { - SyncFileItem downloadItem(_item); - if (downloadItem._instruction == CSYNC_INSTRUCTION_NEW) { - // don't try to recover pushing new files - return false; - } else if (downloadItem._instruction == CSYNC_INSTRUCTION_SYNC) { - // we modified the file locally, jsut create a conflict then - downloadItem._instruction = CSYNC_INSTRUCTION_CONFLICT; - - // HACK to avoid continuation: See task #1448: We do not know the _modtime from the - // server, at this point, so just set the current one. (rather than the one locally) - downloadItem._modtime = Utility::qDateTimeToTime_t(QDateTime::currentDateTime()); - } else { - // the file was removed or renamed, just recover the old one - downloadItem._instruction = CSYNC_INSTRUCTION_SYNC; - } - downloadItem._direction = SyncFileItem::Down; - newJob = new PropagateDownloadFileLegacy(_propagator, downloadItem); - } else { - // Directories are harder to recover. - // But just re-create the directory, next sync will be able to recover the files - SyncFileItem mkdirItem(_item); - mkdirItem._instruction = CSYNC_INSTRUCTION_SYNC; - mkdirItem._direction = SyncFileItem::Down; - newJob = new PropagateLocalMkdir(_propagator, mkdirItem); - // Also remove the inodes and fileid from the db so no further renames are tried for - // this item. - _propagator->_journal->avoidRenamesOnNextSync(_item._file); - } - if( newJob ) { - newJob->setRestoreJobMsg(msg); - _restoreJob.reset(newJob); - connect(_restoreJob.data(), SIGNAL(completed(SyncFileItem)), - this, SLOT(slotRestoreJobCompleted(SyncFileItem))); - QMetaObject::invokeMethod(newJob, "start"); - } - return true; - } - return false; -} - -void PropagateItemJob::slotRestoreJobCompleted(const SyncFileItem& item ) -{ - QString msg; - if(_restoreJob) { - msg = _restoreJob->restoreJobMsg(); - _restoreJob->setRestoreJobMsg(); - } - - if( item._status == SyncFileItem::Success || item._status == SyncFileItem::Conflict - || item._status == SyncFileItem::Restoration) { - done( SyncFileItem::SoftError, msg); - } else { - done( item._status, tr("A file or directory was removed from a read only share, but restoring failed: %1").arg(item._errorString) ); - } -} - -// ================================================================================ - -PropagateItemJob* OwncloudPropagator::createJob(const SyncFileItem& item) { - switch(item._instruction) { - case CSYNC_INSTRUCTION_REMOVE: - if (item._direction == SyncFileItem::Down) return new PropagateLocalRemove(this, item); - else return new PropagateRemoteRemove(this, item); - case CSYNC_INSTRUCTION_NEW: - if (item._isDirectory) { - if (item._direction == SyncFileItem::Down) return new PropagateLocalMkdir(this, item); - else return new PropagateRemoteMkdir(this, item); - } //fall trough - case CSYNC_INSTRUCTION_SYNC: - case CSYNC_INSTRUCTION_CONFLICT: - if (item._isDirectory) { - // Should we set the mtime? - return 0; - } - if (useLegacyJobs()) { - if (item._direction != SyncFileItem::Up) { - return new PropagateDownloadFileLegacy(this, item); - } else { - return new PropagateUploadFileLegacy(this, item); - } - } else { - if (item._direction != SyncFileItem::Up) { - return new PropagateDownloadFileQNAM(this, item); - } else { - return new PropagateUploadFileQNAM(this, item); - } - } - case CSYNC_INSTRUCTION_RENAME: - if (item._direction == SyncFileItem::Up) { - return new PropagateRemoteRename(this, item); - } else { - return new PropagateLocalRename(this, item); - } - case CSYNC_INSTRUCTION_IGNORE: - case CSYNC_INSTRUCTION_ERROR: - return new PropagateIgnoreJob(this, item); - default: - return 0; - } - return 0; -} - -void OwncloudPropagator::start(const SyncFileItemVector& items) -{ - /* This builds all the job needed for the propagation. - * Each directories is a PropagateDirectory job, which contains the files in it. - * In order to do that we loop over the items. (which are sorted by destination) - * When we enter adirectory, we can create the directory job and push it on the stack. */ - - _rootJob.reset(new PropagateDirectory(this)); - QStack<QPair<QString /* directory name */, PropagateDirectory* /* job */> > directories; - directories.push(qMakePair(QString(), _rootJob.data())); - QVector<PropagatorJob*> directoriesToRemove; - QString removedDirectory; - foreach(const SyncFileItem &item, items) { - - if (!removedDirectory.isEmpty() && item._file.startsWith(removedDirectory)) { - // this is an item in a directory which is going to be removed. - if (item._instruction == CSYNC_INSTRUCTION_REMOVE) { - //already taken care of. (by the removal of the parent directory) - continue; - } else if (item._instruction == CSYNC_INSTRUCTION_NEW && item._isDirectory) { - // create a new directory within a deleted directory? That can happen if the directory - // etag were not fetched properly on the previous sync because the sync was aborted - // while uploading this directory (which is now removed). We can ignore it. - continue; - } else if (item._instruction == CSYNC_INSTRUCTION_IGNORE) { - continue; - } - - qWarning() << "WARNING: Job within a removed directory? This should not happen!" - << item._file << item._instruction; - } - - while (!item.destination().startsWith(directories.top().first)) { - directories.pop(); - } - - if (item._isDirectory) { - PropagateDirectory *dir = new PropagateDirectory(this, item); - dir->_firstJob.reset(createJob(item)); - if (item._instruction == CSYNC_INSTRUCTION_REMOVE) { - //We do the removal of directories at the end, because there might be moves from - // this directories that will happen later. - directoriesToRemove.append(dir); - removedDirectory = item._file + "/"; - - // We should not update the etag of parent directories of the removed directory - // since it would be done before the actual remove (issue #1845) - // NOTE: Currently this means that we don't update those etag at all in this sync, - // but it should not be a problem, they will be updated in the next sync. - for (int i = 0; i < directories.size(); ++i) { - directories[i].second->_item._should_update_etag = false; - } - } else { - PropagateDirectory* currentDirJob = directories.top().second; - currentDirJob->append(dir); - } - directories.push(qMakePair(item.destination() + "/" , dir)); - } else if (PropagateItemJob* current = createJob(item)) { - directories.top().second->append(current); - } - } - - foreach(PropagatorJob* it, directoriesToRemove) { - _rootJob->append(it); - } - - connect(_rootJob.data(), SIGNAL(completed(SyncFileItem)), this, SIGNAL(completed(SyncFileItem))); - connect(_rootJob.data(), SIGNAL(progress(SyncFileItem,quint64)), this, SIGNAL(progress(SyncFileItem,quint64))); - connect(_rootJob.data(), SIGNAL(finished(SyncFileItem::Status)), this, SLOT(emitFinished())); - - qDebug() << (useLegacyJobs() ? "Using legacy libneon/HTTP sequential code path" : "Using QNAM/HTTP parallel code path"); - - QMetaObject::invokeMethod(_rootJob.data(), "start", Qt::QueuedConnection); -} - -bool OwncloudPropagator::isInSharedDirectory(const QString& file) -{ - bool re = false; - if( _remoteDir.contains("remote.php/webdav/Shared") ) { - // The Shared directory is synced as its own sync connection - re = true; - } else { - if( file.startsWith("Shared/") || file == "Shared" ) { - // The whole ownCloud is synced and Shared is always a top dir - re = true; - } - } - return re; -} - -/** - * Return true if we should use the legacy jobs. - * Some feature are not supported by QNAM and therefore we still use the legacy jobs - * for this case. - */ -bool OwncloudPropagator::useLegacyJobs() -{ - if (_downloadLimit.fetchAndAddAcquire(0) != 0 || _uploadLimit.fetchAndAddAcquire(0) != 0) { - // QNAM does not support bandwith limiting - return true; - } - - // Allow an environement variable for debugging - QByteArray env = qgetenv("OWNCLOUD_USE_LEGACY_JOBS"); - return env=="true" || env =="1"; -} - -int OwncloudPropagator::httpTimeout() -{ - static int timeout; - if (!timeout) { - timeout = qgetenv("OWNCLOUD_TIMEOUT").toUInt(); - if (timeout == 0) { - MirallConfigFile cfg; - timeout = cfg.timeout(); - } - - } - return timeout; -} - -bool OwncloudPropagator::localFileNameClash( const QString& relFile ) -{ - bool re = false; - const QString file( _localDir + relFile ); - - if( !file.isEmpty() && Utility::fsCasePreserving() ) { -#ifdef Q_OS_MAC - QFileInfo fileInfo(file); - if (!fileInfo.exists()) { - re = false; - } else { - re = ( ! fileInfo.canonicalFilePath().endsWith(relFile, Qt::CaseSensitive) ); - } -#elif defined(Q_OS_WIN) - const QString file( _localDir + relFile ); - qDebug() << "CaseClashCheck for " << file; - WIN32_FIND_DATA FindFileData; - HANDLE hFind; - - hFind = FindFirstFileW( (wchar_t*)file.utf16(), &FindFileData); - if (hFind == INVALID_HANDLE_VALUE) { - //qDebug() << "FindFirstFile failed " << GetLastError(); - // returns false. - } else { - QString realFileName = QString::fromWCharArray( FindFileData.cFileName ); - qDebug() << Q_FUNC_INFO << "Real file name is " << realFileName; - FindClose(hFind); - - if( ! file.endsWith(realFileName, Qt::CaseSensitive) ) { - re = true; - } - } -#else - // On Linux, the file system is case sensitive, but this code is usefull for testing. - // Just check that there is no other file with the same name and different casing. - QFileInfo fileInfo(file); - const QString fn = fileInfo.fileName(); - QStringList list = fileInfo.dir().entryList(QStringList() << fn); - if (list.count() > 1 || (list.count() == 1 && list[0] != fn)) { - re = true; - } -#endif - } - return re; -} - -// ================================================================================ - -void PropagateDirectory::start() -{ - _current = -1; - _hasError = SyncFileItem::NoStatus; - if (!_firstJob) { - slotSubJobReady(); - } else { - startJob(_firstJob.data()); - } -} - -void PropagateDirectory::slotSubJobFinished(SyncFileItem::Status status) -{ - if (status == SyncFileItem::FatalError || - (_current == -1 && status != SyncFileItem::Success && status != SyncFileItem::Restoration)) { - abort(); - emit finished(status); - return; - } else if (status == SyncFileItem::NormalError || status == SyncFileItem::SoftError) { - _hasError = status; - } - _runningNow--; - slotSubJobReady(); -} - -void PropagateDirectory::slotSubJobReady() -{ - if (_runningNow && _current == -1) - return; // Ignore the case when the _fistJob is ready and not yet finished - if (_runningNow && _current >= 0 && _current < _subJobs.count()) { - // there is a job running and the current one is not ready yet, we can't start new job - if (!_subJobs[_current]->_readySent || _propagator->_activeJobs >= maximumActiveJob()) - return; - } - - _current++; - if (_current < _subJobs.size() && !_propagator->_abortRequested.fetchAndAddRelaxed(0)) { - PropagatorJob *next = _subJobs.at(_current); - startJob(next); - return; - } - // We finished to processing all the jobs - emitReady(); - if (!_runningNow) { - if (!_item.isEmpty() && _hasError == SyncFileItem::NoStatus) { - if( !_item._renameTarget.isEmpty() ) { - _item._file = _item._renameTarget; - } - - if (_item._should_update_etag && _item._instruction != CSYNC_INSTRUCTION_REMOVE) { - if (PropagateRemoteMkdir* mkdir = qobject_cast<PropagateRemoteMkdir*>(_firstJob.data())) { - // special case from MKDIR, get the fileId from the job there - if (_item._fileId.isEmpty() && !mkdir->_item._fileId.isEmpty()) { - _item._fileId = mkdir->_item._fileId; - } - } - SyncJournalFileRecord record(_item, _propagator->_localDir + _item._file); - _propagator->_journal->setFileRecord(record); - } - } - emit finished(_hasError == SyncFileItem::NoStatus ? SyncFileItem::Success : _hasError); - } -} - -} diff --git a/src/mirall/owncloudpropagator.h b/src/mirall/owncloudpropagator.h deleted file mode 100644 index cfec6653b..000000000 --- a/src/mirall/owncloudpropagator.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (C) by Olivier Goffart <ogoffart@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. - */ - -#ifndef OWNCLOUDPROPAGATOR_H -#define OWNCLOUDPROPAGATOR_H - -#include <neon/ne_request.h> -#include <QHash> -#include <QObject> -#include <qelapsedtimer.h> - -#include "syncfileitem.h" - -struct hbf_transfer_s; -struct ne_session_s; -struct ne_decompress_s; -typedef struct ne_prop_result_set_s ne_prop_result_set; - -namespace Mirall { - -class SyncJournalDb; -class OwncloudPropagator; - -class PropagatorJob : public QObject { - Q_OBJECT -protected: - OwncloudPropagator *_propagator; - void emitReady() { - bool wasReady = _readySent; - _readySent = true; - if (!wasReady) - emit ready(); - }; -public: - bool _readySent; - explicit PropagatorJob(OwncloudPropagator* propagator) : _propagator(propagator), _readySent(false) {} - -public slots: - virtual void start() = 0; - virtual void abort() {} -signals: - /** - * Emitted when the job is fully finished - */ - void finished(SyncFileItem::Status); - - /** - * Emitted when one item has been completed within a job. - */ - void completed(const SyncFileItem &); - - /** - * Emitted when all the sub-jobs have been scheduled and - * we are ready and more jobs might be started - * This signal is not always emitted. - */ - void ready(); - - void progress(const SyncFileItem& item, quint64 bytes); - -}; - -/* - * Propagate a directory, and all its sub entries. - */ -class PropagateDirectory : public PropagatorJob { - Q_OBJECT -public: - // e.g: create the directory - QScopedPointer<PropagatorJob>_firstJob; - - // all the sub files or sub directories. - QVector<PropagatorJob *> _subJobs; - - SyncFileItem _item; - - int _current; // index of the current running job - int _runningNow; // number of subJob running now - SyncFileItem::Status _hasError; // NoStatus, or NormalError / SoftError if there was an error - - - explicit PropagateDirectory(OwncloudPropagator *propagator, const SyncFileItem &item = SyncFileItem()) - : PropagatorJob(propagator) - , _firstJob(0), _item(item), _current(-1), _runningNow(0), _hasError(SyncFileItem::NoStatus) { } - - virtual ~PropagateDirectory() { - qDeleteAll(_subJobs); - } - - void append(PropagatorJob *subJob) { - _subJobs.append(subJob); - } - - virtual void start() Q_DECL_OVERRIDE; - virtual void abort() Q_DECL_OVERRIDE { - if (_firstJob) - _firstJob->abort(); - foreach (PropagatorJob *j, _subJobs) - j->abort(); - } - -private slots: - void startJob(PropagatorJob *next) { - connect(next, SIGNAL(finished(SyncFileItem::Status)), this, SLOT(slotSubJobFinished(SyncFileItem::Status)), Qt::QueuedConnection); - connect(next, SIGNAL(completed(SyncFileItem)), this, SIGNAL(completed(SyncFileItem))); - connect(next, SIGNAL(progress(SyncFileItem,quint64)), this, SIGNAL(progress(SyncFileItem,quint64))); - connect(next, SIGNAL(ready()), this, SLOT(slotSubJobReady())); - _runningNow++; - QMetaObject::invokeMethod(next, "start", Qt::QueuedConnection); - } - - void slotSubJobFinished(SyncFileItem::Status status); - void slotSubJobReady(); -}; - - -/* - * Abstract class to propagate a single item - * (Only used for neon job) - */ -class PropagateItemJob : public PropagatorJob { - Q_OBJECT -protected: - void done(SyncFileItem::Status status, const QString &errorString = QString()); - - bool checkForProblemsWithShared(int httpStatusCode, const QString& msg); - - /* - * set a custom restore job message that is used if the restore job succeeded. - * It is displayed in the activity view. - */ - QString restoreJobMsg() const { - return _item._isRestoration ? _item._errorString : QString(); - } - void setRestoreJobMsg( const QString& msg = QString() ) { - _item._isRestoration = true; - _item._errorString = msg; - } - - SyncFileItem _item; - -protected slots: - void slotRestoreJobCompleted(const SyncFileItem& ); - -private: - QScopedPointer<PropagateItemJob> _restoreJob; - -public: - PropagateItemJob(OwncloudPropagator* propagator, const SyncFileItem &item) - : PropagatorJob(propagator), _item(item) {} - -}; - -// Dummy job that just mark it as completed and ignored. -class PropagateIgnoreJob : public PropagateItemJob { - Q_OBJECT -public: - PropagateIgnoreJob(OwncloudPropagator* propagator,const SyncFileItem& item) - : PropagateItemJob(propagator, item) {} - void start() Q_DECL_OVERRIDE { - SyncFileItem::Status status = _item._status; - done(status == SyncFileItem::NoStatus ? SyncFileItem::FileIgnored : status, _item._errorString); - } -}; - - -class OwncloudPropagator : public QObject { - Q_OBJECT - - PropagateItemJob *createJob(const SyncFileItem& item); - QScopedPointer<PropagateDirectory> _rootJob; - bool useLegacyJobs(); - -public: - /* 'const' because they are accessed by the thread */ - - QThread* _neonThread; - ne_session_s * const _session; - - const QString _localDir; // absolute path to the local directory. ends with '/' - const QString _remoteDir; // path to the root of the remote. ends with '/' (include remote.php/webdav) - const QString _remoteFolder; // folder. (same as remoteDir but without remote.php/webdav) - - SyncJournalDb * const _journal; - bool _finishedEmited; // used to ensure that finished is only emit once - -public: - OwncloudPropagator(ne_session_s *session, const QString &localDir, const QString &remoteDir, const QString &remoteFolder, - SyncJournalDb *progressDb, QThread *neonThread) - : _neonThread(neonThread) - , _session(session) - , _localDir((localDir.endsWith(QChar('/'))) ? localDir : localDir+'/' ) - , _remoteDir((remoteDir.endsWith(QChar('/'))) ? remoteDir : remoteDir+'/' ) - , _remoteFolder((remoteFolder.endsWith(QChar('/'))) ? remoteFolder : remoteFolder+'/' ) - , _journal(progressDb) - , _finishedEmited(false) - , _activeJobs(0) - { } - - void start(const SyncFileItemVector &_syncedItems); - - QAtomicInt _downloadLimit; - QAtomicInt _uploadLimit; - - QAtomicInt _abortRequested; // boolean set by the main thread to abort. - - /* The number of currently active jobs */ - int _activeJobs; - - bool isInSharedDirectory(const QString& file); - bool localFileNameClash(const QString& relfile); - - void abort() { - _abortRequested.fetchAndStoreOrdered(true); - if (_rootJob) { - _rootJob->abort(); - } - emitFinished(); - } - - // timeout in seconds - static int httpTimeout(); - -private slots: - - /** Emit the finished signal and make sure it is only emit once */ - void emitFinished() { - if (!_finishedEmited) - emit finished(); - _finishedEmited = true; - } - -signals: - void completed(const SyncFileItem &); - void progress(const SyncFileItem&, quint64 bytes); - void finished(); - /** - * Called when we detect that the total number of bytes changes (because a download or upload - * turns out to be bigger or smaller than what was initially computed in the update phase - */ - void adjustTotalTransmissionSize( qint64 adjust ); - -}; - -} - -#endif diff --git a/src/mirall/owncloudpropagator_p.h b/src/mirall/owncloudpropagator_p.h deleted file mode 100644 index 3f98f6604..000000000 --- a/src/mirall/owncloudpropagator_p.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) by Olivier Goffart <ogoffart@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 - * 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. - */ - -#pragma once - -namespace Mirall { - -inline QByteArray parseEtag(const char *header) { - if (!header) - return QByteArray(); - QByteArray arr = header; - arr.replace("-gzip", ""); // https://github.com/owncloud/mirall/issues/1195 - if(arr.length() >= 2 && arr.startsWith('"') && arr.endsWith('"')) { - arr = arr.mid(1, arr.length() - 2); - } - return arr; -} - - -} diff --git a/src/mirall/owncloudsetuppage.ui b/src/mirall/owncloudsetuppage.ui deleted file mode 100644 index 6190119d0..000000000 --- a/src/mirall/owncloudsetuppage.ui +++ /dev/null @@ -1,185 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>OwncloudSetupPage</class> - <widget class="QWidget" name="OwncloudSetupPage"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>480</width> - <height>278</height> - </rect> - </property> - <property name="windowTitle"> - <string>Form</string> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="1" column="0"> - <widget class="QLabel" name="serverAddressLabel"> - <property name="text"> - <string>Server &address:</string> - </property> - <property name="buddy"> - <cstring>leUrl</cstring> - </property> - </widget> - </item> - <item row="0" column="0" colspan="2"> - <widget class="QLabel" name="topLabel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>TextLabel</string> - </property> - </widget> - </item> - <item row="3" column="0" colspan="2"> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QCheckBox" name="cbSecureConnect"> - <property name="text"> - <string>Use &secure connection</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="cbConnectOC"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="text"> - <string>CheckBox</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <layout class="QFormLayout" name="formLayout"> - <item row="0" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>&Username:</string> - </property> - <property name="buddy"> - <cstring>leUsername</cstring> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLineEdit" name="leUsername"> - <property name="toolTip"> - <string>Enter the ownCloud username.</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string>&Password:</string> - </property> - <property name="buddy"> - <cstring>lePassword</cstring> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLineEdit" name="lePassword"> - <property name="toolTip"> - <string>Enter the ownCloud password.</string> - </property> - <property name="text"> - <string/> - </property> - <property name="echoMode"> - <enum>QLineEdit::Password</enum> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QCheckBox" name="cbNoPasswordStore"> - <property name="toolTip"> - <string>Do not allow the local storage of the password.</string> - </property> - <property name="text"> - <string>&Do not store password on local machine</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QLabel" name="sideLabel"> - <property name="text"> - <string>TextLabel</string> - </property> - </widget> - </item> - </layout> - </item> - <item row="2" column="0" colspan="2"> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QLabel" name="protocolLabel"> - <property name="text"> - <string>https://</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="leUrl"> - <property name="toolTip"> - <string>Enter the url of the ownCloud you want to connect to (without http or https).</string> - </property> - </widget> - </item> - </layout> - </item> - <item row="4" column="0" colspan="2"> - <widget class="QLabel" name="bottomLabel"> - <property name="text"> - <string>TextLabel</string> - </property> - </widget> - </item> - <item row="5" column="1"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>344</width> - <height>1</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <tabstops> - <tabstop>leUrl</tabstop> - <tabstop>cbSecureConnect</tabstop> - <tabstop>cbConnectOC</tabstop> - <tabstop>leUsername</tabstop> - <tabstop>lePassword</tabstop> - <tabstop>cbNoPasswordStore</tabstop> - </tabstops> - <resources/> - <connections/> -</ui> diff --git a/src/mirall/owncloudsetupwizard.cpp b/src/mirall/owncloudsetupwizard.cpp deleted file mode 100644 index a7d866b51..000000000 --- a/src/mirall/owncloudsetupwizard.cpp +++ /dev/null @@ -1,502 +0,0 @@ -/* - * Copyright (C) by Klaas Freitag <freitag@owncloud.com> - * Copyright (C) by Krzesimir Nowak <krzesimir@endocode.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. - */ - -#include <QAbstractButton> -#include <QtCore> -#include <QProcess> -#include <QMessageBox> -#include <QDesktopServices> - -#include "wizard/owncloudwizardcommon.h" -#include "wizard/owncloudwizard.h" -#include "mirall/owncloudsetupwizard.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/folderman.h" -#include "mirall/utility.h" -#include "mirall/mirallaccessmanager.h" -#include "mirall/account.h" -#include "mirall/networkjobs.h" -#include "mirall/sslerrordialog.h" - -#include "creds/credentialsfactory.h" -#include "creds/abstractcredentials.h" -#include "creds/dummycredentials.h" - -namespace Mirall { - -OwncloudSetupWizard::OwncloudSetupWizard(QObject* parent) : - QObject( parent ), - _account(0), - _ocWizard(new OwncloudWizard), - _remoteFolder() -{ - connect( _ocWizard, SIGNAL(determineAuthType(const QString&)), - this, SLOT(slotDetermineAuthType(const QString&))); - connect( _ocWizard, SIGNAL(connectToOCUrl( const QString& ) ), - this, SLOT(slotConnectToOCUrl( const QString& ))); - connect( _ocWizard, SIGNAL(createLocalAndRemoteFolders(QString, QString)), - this, SLOT(slotCreateLocalAndRemoteFolders(QString, QString))); - /* basicSetupFinished might be called from a reply from the network. - slotAssistantFinished might destroy the temporary QNetworkAccessManager. - Therefore Qt::QueuedConnection is required */ - connect( _ocWizard, SIGNAL(basicSetupFinished(int)), - this, SLOT(slotAssistantFinished(int)), Qt::QueuedConnection); - connect( _ocWizard, SIGNAL(finished(int)), SLOT(deleteLater())); -} - -OwncloudSetupWizard::~OwncloudSetupWizard() -{ - _ocWizard->deleteLater(); -} - -void OwncloudSetupWizard::runWizard(QObject* obj, const char* amember, QWidget *parent) -{ - static QPointer<OwncloudSetupWizard> wiz; - - if (!wiz.isNull()) { - return; - } - - wiz = new OwncloudSetupWizard(parent); - connect( wiz, SIGNAL(ownCloudWizardDone(int)), obj, amember); - FolderMan::instance()->setSyncEnabled(false); - wiz->startWizard(); -} - -void OwncloudSetupWizard::startWizard() -{ - FolderMan *folderMan = FolderMan::instance(); - bool multiFolderSetup = folderMan->map().count() > 1; - // ### - Account *account = Account::restore(); - if (!account) { - _ocWizard->setConfigExists(false); - account = new Account; - account->setCredentials(CredentialsFactory::create("dummy")); - } else { - _ocWizard->setConfigExists(true); - } - account->setSslErrorHandler(new SslDialogErrorHandler); - _ocWizard->setAccount(account); - _ocWizard->setOCUrl(account->url().toString()); - - _remoteFolder = Theme::instance()->defaultServerFolder(); - // remoteFolder may be empty, which means / - QString localFolder = Theme::instance()->defaultClientFolder(); - - // if its a relative path, prepend with users home dir, otherwise use as absolute path - - if( !QDir(localFolder).isAbsolute() ) { - localFolder = QDir::homePath() + QDir::separator() + localFolder; - } - - if (!multiFolderSetup) { - QList<Folder*> folders = folderMan->map().values(); - if (!folders.isEmpty()) { - Folder* folder = folders.first(); - localFolder = QDir(folder->path()).absolutePath(); - } - } - - _ocWizard->setProperty("localFolder", localFolder); - _ocWizard->setRemoteFolder(_remoteFolder); - - _ocWizard->setStartId(WizardCommon::Page_ServerSetup); - - _ocWizard->restart(); - - // settings re-initialized in initPage must be set here after restart - _ocWizard->setMultipleFoldersExist( multiFolderSetup ); - - _ocWizard->open(); - _ocWizard->raise(); -} - -// also checks if an installation is valid and determines auth type in a second step -void OwncloudSetupWizard::slotDetermineAuthType(const QString &urlString) -{ - QString fixedUrl = urlString; - QUrl url = QUrl::fromUserInput(fixedUrl); - // fromUserInput defaults to http, not http if no scheme is specified - if (!fixedUrl.startsWith("http://") && !fixedUrl.startsWith("https://")) { - url.setScheme("https"); - } - Account *account = _ocWizard->account(); - account->setUrl(url); - CheckServerJob *job = new CheckServerJob(_ocWizard->account(), false, this); - job->setIgnoreCredentialFailure(true); - connect(job, SIGNAL(instanceFound(QUrl,QVariantMap)), SLOT(slotOwnCloudFoundAuth(QUrl,QVariantMap))); - connect(job, SIGNAL(instanceNotFound(QNetworkReply*)), SLOT(slotNoOwnCloudFoundAuth(QNetworkReply*))); - connect(job, SIGNAL(timeout(const QUrl&)), SLOT(slotNoOwnCloudFoundAuthTimeout(const QUrl&))); - job->setTimeout(10*1000); - job->start(); -} - -void OwncloudSetupWizard::slotOwnCloudFoundAuth(const QUrl& url, const QVariantMap &info) -{ - _ocWizard->appendToConfigurationLog(tr("<font color=\"green\">Successfully connected to %1: %2 version %3 (%4)</font><br/><br/>") - .arg(url.toString()) - .arg(Theme::instance()->appNameGUI()) - .arg(CheckServerJob::versionString(info)) - .arg(CheckServerJob::version(info))); - - QString p = url.path(); - if (p.endsWith("/status.php")) { - // We might be redirected, update the account - QUrl redirectedUrl = url; - redirectedUrl.setPath(url.path().left(url.path().length() - 11)); - _ocWizard->account()->setUrl(redirectedUrl); - qDebug() << Q_FUNC_INFO << " was redirected to" << redirectedUrl.toString(); - } - - DetermineAuthTypeJob *job = new DetermineAuthTypeJob(_ocWizard->account(), this); - job->setIgnoreCredentialFailure(true); - connect(job, SIGNAL(authType(WizardCommon::AuthType)), - _ocWizard, SLOT(setAuthType(WizardCommon::AuthType))); - job->start(); -} - -void OwncloudSetupWizard::slotNoOwnCloudFoundAuth(QNetworkReply *reply) -{ - _ocWizard->displayError(tr("Failed to connect to %1 at %2:<br/>%3") - .arg(Theme::instance()->appNameGUI()) - .arg(reply->url().toString()) - .arg(reply->errorString())); -} - -void OwncloudSetupWizard::slotNoOwnCloudFoundAuthTimeout(const QUrl&url) -{ - _ocWizard->displayError(tr("Failed to connect to %1 at %2:<br/>%3") - .arg(Theme::instance()->appNameGUI()) - .arg(url.toString()) - .arg("Timeout")); -} - -void OwncloudSetupWizard::slotConnectToOCUrl( const QString& url ) -{ - qDebug() << "Connect to url: " << url; - AbstractCredentials *creds = _ocWizard->getCredentials(); - _ocWizard->account()->setCredentials(creds); - _ocWizard->setField(QLatin1String("OCUrl"), url ); - _ocWizard->appendToConfigurationLog(tr("Trying to connect to %1 at %2...") - .arg( Theme::instance()->appNameGUI() ).arg(url) ); - - testOwnCloudConnect(); -} - -void OwncloudSetupWizard::testOwnCloudConnect() -{ - Account *account = _ocWizard->account(); - - ValidateDavAuthJob *job = new ValidateDavAuthJob(account, this); - job->setIgnoreCredentialFailure(true); - connect(job, SIGNAL(authResult(QNetworkReply*)), SLOT(slotConnectionCheck(QNetworkReply*))); - job->start(); -} - -void OwncloudSetupWizard::slotConnectionCheck(QNetworkReply* reply) -{ - switch (reply->error()) { - case QNetworkReply::NoError: - case QNetworkReply::ContentNotFoundError: - _ocWizard->successfulStep(); - break; - - default: - _ocWizard->displayError(tr("Error: Wrong credentials.")); - break; - } -} - -void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString& localFolder, const QString& remoteFolder) -{ - qDebug() << "Setup local sync folder for new oC connection " << localFolder; - const QDir fi( localFolder ); - - bool nextStep = true; - if( fi.exists() ) { - // there is an existing local folder. If its non empty, it can only be synced if the - // ownCloud is newly created. - _ocWizard->appendToConfigurationLog( tr("Local sync folder %1 already exists, setting it up for sync.<br/><br/>").arg(localFolder)); - } else { - QString res = tr("Creating local sync folder %1... ").arg(localFolder); - if( fi.mkpath( localFolder ) ) { - Utility::setupFavLink( localFolder ); - // FIXME: Create a local sync folder. - res += tr("ok"); - } else { - res += tr("failed."); - qDebug() << "Failed to create " << fi.path(); - _ocWizard->displayError(tr("Could not create local folder %1").arg(localFolder)); - nextStep = false; - } - _ocWizard->appendToConfigurationLog( res ); - } - if (nextStep) { - EntityExistsJob *job = new EntityExistsJob(_ocWizard->account(), remoteFolder, this); - connect(job, SIGNAL(exists(QNetworkReply*)), SLOT(slotAuthCheckReply(QNetworkReply*))); - job->start(); - } else { - finalizeSetup( false ); - } -} - -// ### TODO move into EntityExistsJob once we decide if/how to return gui strings from jobs -void OwncloudSetupWizard::slotAuthCheckReply(QNetworkReply *reply) -{ - bool ok = true; - QString error; - QNetworkReply::NetworkError errId = reply->error(); - - if( errId == QNetworkReply::NoError ) { - qDebug() << "******** Remote folder found, all cool!"; - } else if( errId == QNetworkReply::ContentNotFoundError ) { - if( _remoteFolder.isEmpty() ) { - error = tr("No remote folder specified!"); - ok = false; - } else { - createRemoteFolder(); - } - } else { - error = tr("Error: %1").arg(reply->errorString()); - ok = false; - } - - if( !ok ) { - _ocWizard->displayError(error); - } - - finalizeSetup( ok ); -} - -void OwncloudSetupWizard::createRemoteFolder() -{ - _ocWizard->appendToConfigurationLog( tr("creating folder on ownCloud: %1" ).arg( _remoteFolder )); - - MkColJob *job = new MkColJob(_ocWizard->account(), _remoteFolder, this); - connect(job, SIGNAL(finished(QNetworkReply::NetworkError)), SLOT(slotCreateRemoteFolderFinished(QNetworkReply::NetworkError))); - job->start(); -} - -void OwncloudSetupWizard::slotCreateRemoteFolderFinished( QNetworkReply::NetworkError error ) -{ - qDebug() << "** webdav mkdir request finished " << error; - // disconnect(ownCloudInfo::instance(), SIGNAL(webdavColCreated(QNetworkReply::NetworkError)), - // this, SLOT(slotCreateRemoteFolderFinished(QNetworkReply::NetworkError))); - - bool success = true; - - if( error == QNetworkReply::NoError ) { - _ocWizard->appendToConfigurationLog( tr("Remote folder %1 created successfully.").arg(_remoteFolder)); - } else if( error == 202 ) { - _ocWizard->appendToConfigurationLog( tr("The remote folder %1 already exists. Connecting it for syncing.").arg(_remoteFolder)); - } else if( error > 202 && error < 300 ) { - _ocWizard->displayError( tr("The folder creation resulted in HTTP error code %1").arg((int)error )); - - _ocWizard->appendToConfigurationLog( tr("The folder creation resulted in HTTP error code %1").arg((int)error) ); - } else if( error == QNetworkReply::OperationCanceledError ) { - _ocWizard->displayError( tr("The remote folder creation failed because the provided credentials " - "are wrong!" - "<br/>Please go back and check your credentials.</p>")); - _ocWizard->appendToConfigurationLog( tr("<p><font color=\"red\">Remote folder creation failed probably because the provided credentials are wrong.</font>" - "<br/>Please go back and check your credentials.</p>")); - _remoteFolder.clear(); - success = false; - } else { - _ocWizard->appendToConfigurationLog( tr("Remote folder %1 creation failed with error <tt>%2</tt>.").arg(_remoteFolder).arg(error)); - _ocWizard->displayError( tr("Remote folder %1 creation failed with error <tt>%2</tt>.").arg(_remoteFolder).arg(error) ); - _remoteFolder.clear(); - success = false; - } - - finalizeSetup( success ); -} - -void OwncloudSetupWizard::finalizeSetup( bool success ) -{ - // enable/disable the finish button. - _ocWizard->enableFinishOnResultWidget(success); - - const QString localFolder = _ocWizard->property("localFolder").toString(); - if( success ) { - if( !(localFolder.isEmpty() || _remoteFolder.isEmpty() )) { - _ocWizard->appendToConfigurationLog( tr("A sync connection from %1 to remote directory %2 was set up.") - .arg(localFolder).arg(_remoteFolder)); - } - _ocWizard->appendToConfigurationLog( QLatin1String(" ")); - _ocWizard->appendToConfigurationLog( QLatin1String("<p><font color=\"green\"><b>") - + tr("Successfully connected to %1!") - .arg(Theme::instance()->appNameGUI()) - + QLatin1String("</b></font></p>")); - _ocWizard->successfulStep(); - } else { - // ### this is not quite true, pass in the real problem as optional parameter - _ocWizard->appendToConfigurationLog(QLatin1String("<p><font color=\"red\">") - + tr("Connection to %1 could not be established. Please check again.") - .arg(Theme::instance()->appNameGUI()) - + QLatin1String("</font></p>")); - } -} - -bool OwncloudSetupWizard::ensureStartFromScratch(const QString &localFolder) { - // first try to rename (backup) the current local dir. - bool renameOk = false; - while( !renameOk ) { - renameOk = FolderMan::instance()->startFromScratch(localFolder); - if( ! renameOk ) { - QMessageBox::StandardButton but; - but = QMessageBox::question( 0, tr("Folder rename failed"), - tr("Can't remove and back up the folder because the folder or a file in it is open in another program." - " Please close the folder or file and hit retry or cancel the setup."), QMessageBox::Retry | QMessageBox::Abort, QMessageBox::Retry); - if( but == QMessageBox::Abort ) { - break; - } - } - } - return renameOk; -} - -void OwncloudSetupWizard::replaceDefaultAccountWith(Account *newAccount) -{ - // new Account - AccountManager *mgr = AccountManager::instance(); - if (mgr->account()) { - mgr->account()->deleteLater(); - } - mgr->setAccount(newAccount); - newAccount->save(); -} - -// Method executed when the user ends has finished the basic setup. -void OwncloudSetupWizard::slotAssistantFinished( int result ) -{ - FolderMan *folderMan = FolderMan::instance(); - - if( result == QDialog::Rejected ) { - // the old config remains valid. Remove the temporary one. - _ocWizard->account()->deleteLater(); - qDebug() << "Rejected the new config, use the old!"; - } else if( result == QDialog::Accepted ) { - - Account *newAccount = _ocWizard->account(); - Account *origAccount = AccountManager::instance()->account(); - const QString localFolder = _ocWizard->localFolder(); - - bool isInitialSetup = (origAccount == 0); - bool reinitRequired = newAccount->changed(origAccount, true /* ignoreProtocol, allows http->https */); - bool startFromScratch = _ocWizard->field("OCSyncFromScratch").toBool(); - - // This distinguishes three possibilities: - // 1. Initial setup, no prior account exists - if (isInitialSetup) { - folderMan->addFolderDefinition(Theme::instance()->appName(), - localFolder, _remoteFolder ); - replaceDefaultAccountWith(newAccount); - } - // 2. Server URL or user changed, requires reinit of folders - else if (reinitRequired) { - // 2.1: startFromScratch: (Re)move local data, clean slate sync - if (startFromScratch) { - if (ensureStartFromScratch(localFolder)) { - folderMan->addFolderDefinition(Theme::instance()->appName(), - localFolder, _remoteFolder ); - _ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder)); - replaceDefaultAccountWith(newAccount); - } - } - // 2.2: Reinit: Remove journal and start a sync - else { - folderMan->removeAllFolderDefinitions(); - folderMan->addFolderDefinition(Theme::instance()->appName(), - localFolder, _remoteFolder ); - _ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder)); - replaceDefaultAccountWith(newAccount); - } - } - // 3. Existing setup, http -> https or password changed - else { - replaceDefaultAccountWith(newAccount); - qDebug() << "Only password was changed, no changes to folder configuration."; - } - } - - // notify others. - emit ownCloudWizardDone( result ); -} - -DetermineAuthTypeJob::DetermineAuthTypeJob(Account *account, QObject *parent) - : AbstractNetworkJob(account, QString(), parent) - , _redirects(0) -{ -} - -void DetermineAuthTypeJob::start() -{ - QNetworkReply *reply = getRequest(account()->davPath()); - setReply(reply); - setupConnections(reply); - AbstractNetworkJob::start(); -} - -bool DetermineAuthTypeJob::finished() -{ - QUrl redirection = reply()->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); - qDebug() << Q_FUNC_INFO << redirection.toString(); - if (_redirects >= maxRedirects()) { - redirection.clear(); - } - if ((reply()->error() == QNetworkReply::AuthenticationRequiredError) || redirection.isEmpty()) { - emit authType(WizardCommon::HttpCreds); - } else if (redirection.toString().endsWith(account()->davPath())) { - // do a new run - _redirects++; - setReply(getRequest(redirection)); - setupConnections(reply()); - } else { - QRegExp shibbolethyWords("SAML|wayf"); - - shibbolethyWords.setCaseSensitivity(Qt::CaseInsensitive); - if (redirection.toString().contains(shibbolethyWords)) { - emit authType(WizardCommon::Shibboleth); - } else { - // TODO: Send an error. - // eh? - emit authType(WizardCommon::HttpCreds); - } - } - return true; -} - -ValidateDavAuthJob::ValidateDavAuthJob(Account *account, QObject *parent) - : AbstractNetworkJob(account, QString(), parent) -{ -} - -void ValidateDavAuthJob::start() -{ - QString p = account()->davPath(); - QNetworkReply *reply = getRequest(p); - setReply(reply); - setupConnections(reply); - AbstractNetworkJob::start(); -} - -bool ValidateDavAuthJob::finished() -{ - emit authResult(reply()); - return true; -} - -} // ns Mirall diff --git a/src/mirall/owncloudsetupwizard.h b/src/mirall/owncloudsetupwizard.h deleted file mode 100644 index a35c57c2b..000000000 --- a/src/mirall/owncloudsetupwizard.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) by Klaas Freitag <freitag@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 OWNCLOUDSETUPWIZARD_H -#define OWNCLOUDSETUPWIZARD_H - -#include <QObject> -#include <QWidget> -#include <QProcess> -#include <QNetworkReply> -#include <QPointer> - -#include "mirall/theme.h" -#include "mirall/networkjobs.h" - -#include "wizard/owncloudwizardcommon.h" - -namespace Mirall { - -class OwncloudWizard; -class Account; - -class ValidateDavAuthJob : public AbstractNetworkJob { - Q_OBJECT -public: - ValidateDavAuthJob(Account* account, QObject *parent = 0); - void start() Q_DECL_OVERRIDE; -signals: - void authResult(QNetworkReply*); -private slots: - bool finished() Q_DECL_OVERRIDE; -}; - -class DetermineAuthTypeJob : public AbstractNetworkJob { - Q_OBJECT -public: - explicit DetermineAuthTypeJob(Account *account, QObject *parent = 0); - void start() Q_DECL_OVERRIDE; -signals: - void authType(WizardCommon::AuthType); -private slots: - bool finished() Q_DECL_OVERRIDE; -private: - int _redirects; -}; - - -class OwncloudSetupWizard : public QObject -{ - Q_OBJECT -public: - /** Run the wizard */ - static void runWizard(QObject *obj, const char* amember, QWidget *parent = 0 ); - -signals: - // overall dialog close signal. - void ownCloudWizardDone( int ); - -private slots: - void slotDetermineAuthType(const QString&); - void slotOwnCloudFoundAuth(const QUrl&, const QVariantMap&); - void slotNoOwnCloudFoundAuth(QNetworkReply *reply); - void slotNoOwnCloudFoundAuthTimeout(const QUrl&url); - - void slotConnectToOCUrl(const QString&); - void slotConnectionCheck(QNetworkReply*); - - void slotCreateLocalAndRemoteFolders(const QString&, const QString&); - void slotAuthCheckReply(QNetworkReply*); - void slotCreateRemoteFolderFinished(QNetworkReply::NetworkError); - void slotAssistantFinished( int ); - -private: - explicit OwncloudSetupWizard(QObject *parent = 0 ); - ~OwncloudSetupWizard(); - - void startWizard(); - void testOwnCloudConnect(); - void createRemoteFolder(); - void finalizeSetup( bool ); - bool ensureStartFromScratch(const QString &localFolder); - void replaceDefaultAccountWith(Account *newAccount); - - Account* _account; - OwncloudWizard* _ocWizard; - QString _remoteFolder; - -}; - -} - -#endif // OWNCLOUDSETUPWIZARD_H diff --git a/src/mirall/owncloudtheme.cpp b/src/mirall/owncloudtheme.cpp deleted file mode 100644 index f73aa7c55..000000000 --- a/src/mirall/owncloudtheme.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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. - */ - -#include "owncloudtheme.h" - -#include <QString> -#include <QVariant> -#ifndef TOKEN_AUTH_ONLY -#include <QPixmap> -#include <QIcon> -#include <QStyle> -#include <QApplication> -#endif -#include <QCoreApplication> - -#include <QDebug> - -#include "mirall/version.h" -#include "config.h" - -namespace Mirall { - -ownCloudTheme::ownCloudTheme() : - Theme() -{ - // qDebug() << " ** running ownCloud theme!"; -} - -QString ownCloudTheme::configFileName() const -{ - return QLatin1String("owncloud.cfg"); -} - -QString ownCloudTheme::about() const -{ - QString devString; -#ifdef GIT_SHA1 - const QString githubPrefix(QLatin1String( - "https://github.com/owncloud/mirall/commit/")); - const QString gitSha1(QLatin1String(GIT_SHA1)); - devString = QCoreApplication::translate("ownCloudTheme::about()", - "<p><small>Built from Git revision <a href=\"%1\">%2</a>" - " on %3, %4 using Qt %5.</small></p>") - .arg(githubPrefix+gitSha1).arg(gitSha1.left(6)) - .arg(__DATE__).arg(__TIME__) - .arg(QT_VERSION_STR); -#endif - return QCoreApplication::translate("ownCloudTheme::about()", - "<p>Version %2. " - "For more information visit <a href=\"%3\">%4</a></p>" - "<p><small>By Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, ownCloud Inc.<br>" - "Based on Mirall by Duncan Mac-Vicar P.</small></p>" - "%7" - ) - .arg(MIRALL_VERSION_STRING) - .arg("http://" MIRALL_STRINGIFY(APPLICATION_DOMAIN)) - .arg(MIRALL_STRINGIFY(APPLICATION_DOMAIN)) - .arg(devString); - -} - -#ifndef TOKEN_AUTH_ONLY -QIcon ownCloudTheme::trayFolderIcon( const QString& ) const -{ - QPixmap fallback = qApp->style()->standardPixmap(QStyle::SP_FileDialogNewFolder); - return QIcon::fromTheme("folder", fallback); -} - -QIcon ownCloudTheme::folderDisabledIcon( ) const -{ - // Fixme: Do we really want the dialog-canel from theme here? - return themeIcon( QLatin1String("state-pause") ); -} - -QIcon ownCloudTheme::applicationIcon( ) const -{ - return themeIcon( QLatin1String("owncloud-icon") ); -} - -#endif - -QVariant ownCloudTheme::customMedia(Theme::CustomMediaType type) -{ - if (type == Theme::oCSetupTop) { - return QCoreApplication::translate("ownCloudTheme", - "If you don't have an ownCloud server yet, " - "see <a href=\"https://owncloud.com\">owncloud.com</a> for more info.", - "Top text in setup wizard. Keep short!"); - } else { - return QVariant(); - } -} - -QString ownCloudTheme::helpUrl() const -{ - return QString::fromLatin1("http://doc.owncloud.org/desktop/%1.%2/").arg(MIRALL_VERSION_MAJOR).arg(MIRALL_VERSION_MINOR); -} - -#ifndef TOKEN_AUTH_ONLY -QColor ownCloudTheme::wizardHeaderBackgroundColor() const -{ - return QColor("#1d2d42"); -} - -QColor ownCloudTheme::wizardHeaderTitleColor() const -{ - return QColor("#ffffff"); -} - -QPixmap ownCloudTheme::wizardHeaderLogo() const -{ - return QPixmap(":/mirall/theme/colored/wizard_logo.png"); -} -#endif - - -} - diff --git a/src/mirall/owncloudtheme.h b/src/mirall/owncloudtheme.h deleted file mode 100644 index 33b33e2a9..000000000 --- a/src/mirall/owncloudtheme.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - */ - -#ifndef OWNCLOUD_THEME_H -#define OWNCLOUD_THEME_H - -#include "theme.h" - -namespace Mirall { - -class ownCloudTheme : public Theme -{ - Q_OBJECT -public: - ownCloudTheme(); - - QString configFileName() const Q_DECL_OVERRIDE; - QString about() const Q_DECL_OVERRIDE; - QPixmap splashScreen() const; - - QIcon folderIcon( const QString& ) const; - QIcon trayFolderIcon( const QString& ) const Q_DECL_OVERRIDE; - QIcon folderDisabledIcon() const Q_DECL_OVERRIDE; - QIcon applicationIcon() const Q_DECL_OVERRIDE; - - QVariant customMedia(CustomMediaType type) Q_DECL_OVERRIDE; - QString helpUrl() const Q_DECL_OVERRIDE; - - QColor wizardHeaderBackgroundColor() const Q_DECL_OVERRIDE; - QColor wizardHeaderTitleColor() const Q_DECL_OVERRIDE; - QPixmap wizardHeaderLogo() const Q_DECL_OVERRIDE; -private: - - -}; - -} -#endif // OWNCLOUD_MIRALL_THEME_H diff --git a/src/mirall/progressdispatcher.cpp b/src/mirall/progressdispatcher.cpp deleted file mode 100644 index 384b78d03..000000000 --- a/src/mirall/progressdispatcher.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 "progressdispatcher.h" - -#include <QObject> -#include <QMetaType> -#include <QDebug> -#include <QCoreApplication> - -namespace Mirall { - -ProgressDispatcher* ProgressDispatcher::_instance = 0; - -QString Progress::asResultString( const SyncFileItem& item) -{ - switch(item._instruction) { - case CSYNC_INSTRUCTION_CONFLICT: - case CSYNC_INSTRUCTION_SYNC: - case CSYNC_INSTRUCTION_NEW: - if (item._direction != SyncFileItem::Up) { - return QCoreApplication::translate( "progress", "Downloaded"); - } else { - return QCoreApplication::translate( "progress", "Uploaded"); - } - case CSYNC_INSTRUCTION_REMOVE: - return QCoreApplication::translate( "progress", "Deleted"); - case CSYNC_INSTRUCTION_EVAL_RENAME: - case CSYNC_INSTRUCTION_RENAME: - return QCoreApplication::translate( "progress", "Moved to %1").arg(item._renameTarget); - case CSYNC_INSTRUCTION_IGNORE: - return QCoreApplication::translate( "progress", "Ignored"); - case CSYNC_INSTRUCTION_STAT_ERROR: - return QCoreApplication::translate( "progress", "Filesystem access error"); - case CSYNC_INSTRUCTION_ERROR: - return QCoreApplication::translate( "progress", "Error"); - case CSYNC_INSTRUCTION_NONE: - case CSYNC_INSTRUCTION_EVAL: - return QCoreApplication::translate( "progress", "Unknown"); - - } - return QCoreApplication::translate( "progress", "Unknown"); -} - -QString Progress::asActionString( const SyncFileItem &item ) -{ - switch(item._instruction) { - case CSYNC_INSTRUCTION_CONFLICT: - case CSYNC_INSTRUCTION_SYNC: - case CSYNC_INSTRUCTION_NEW: - if (item._direction != SyncFileItem::Up) - return QCoreApplication::translate( "progress", "downloading"); - else - return QCoreApplication::translate( "progress", "uploading"); - case CSYNC_INSTRUCTION_REMOVE: - return QCoreApplication::translate( "progress", "deleting"); - case CSYNC_INSTRUCTION_EVAL_RENAME: - case CSYNC_INSTRUCTION_RENAME: - return QCoreApplication::translate( "progress", "moving"); - case CSYNC_INSTRUCTION_IGNORE: - return QCoreApplication::translate( "progress", "ignoring"); - case CSYNC_INSTRUCTION_STAT_ERROR: - return QCoreApplication::translate( "progress", "error"); - case CSYNC_INSTRUCTION_ERROR: - return QCoreApplication::translate( "progress", "error"); - case CSYNC_INSTRUCTION_NONE: - case CSYNC_INSTRUCTION_EVAL: - return QCoreApplication::translate( "progress", "unknown"); - } - return QCoreApplication::translate( "progress", "unknown"); -} - -bool Progress::isWarningKind( SyncFileItem::Status kind) -{ - return kind == SyncFileItem::SoftError || kind == SyncFileItem::NormalError - || kind == SyncFileItem::FatalError || kind == SyncFileItem::FileIgnored - || kind == SyncFileItem::Conflict || kind == SyncFileItem::Restoration; - -} - -ProgressDispatcher* ProgressDispatcher::instance() { - if (!_instance) { - _instance = new ProgressDispatcher(); - } - return _instance; -} - -ProgressDispatcher::ProgressDispatcher(QObject *parent) : - QObject(parent) -{ - -} - -ProgressDispatcher::~ProgressDispatcher() -{ - -} - -void ProgressDispatcher::setProgressInfo(const QString& folder, const Progress::Info& progress) -{ - if( folder.isEmpty() || - (progress._currentItems.size() == 0 - && progress._totalFileCount == 0) ) { - return; - } - emit progressInfo( folder, progress ); -} - - -} diff --git a/src/mirall/progressdispatcher.h b/src/mirall/progressdispatcher.h deleted file mode 100644 index a3a1e0a31..000000000 --- a/src/mirall/progressdispatcher.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 PROGRESSDISPATCHER_H -#define PROGRESSDISPATCHER_H - -#include "owncloudlib.h" -#include <QObject> -#include <QHash> -#include <QTime> -#include <QQueue> -#include <QElapsedTimer> -#include "syncfileitem.h" - -namespace Mirall { - -/** - * @brief The FolderScheduler class schedules folders for sync - */ -namespace Progress -{ - /** Return true is the size need to be taken in account in the total amount of time */ - inline bool isSizeDependent(csync_instructions_e instruction) { - return instruction == CSYNC_INSTRUCTION_CONFLICT || instruction == CSYNC_INSTRUCTION_SYNC - || instruction == CSYNC_INSTRUCTION_NEW; - } - - - struct Info { - Info() : _totalFileCount(0), _totalSize(0), _completedFileCount(0), _completedSize(0) {} - - quint64 _totalFileCount; - quint64 _totalSize; - quint64 _completedFileCount; - quint64 _completedSize; - // Should this be in a separate file? - struct EtaEstimate { - EtaEstimate() : _startedTime(QDateTime::currentMSecsSinceEpoch()), _agvEtaMSecs(0),_effectivProgressPerSec(0),_sampleCount(1) {} - - static const int MAX_AVG_DIVIDER=60; - static const int INITAL_WAIT_TIME=5; - - quint64 _startedTime ; - quint64 _agvEtaMSecs; - quint64 _effectivProgressPerSec; - float _sampleCount; - - /** - * reset the estiamte. - */ - void reset() { - _startedTime = QDateTime::currentMSecsSinceEpoch(); - _sampleCount =1; - _effectivProgressPerSec = _agvEtaMSecs = 0; - } - - /** - * update the estimated eta time with more current data. - * @param quint64 completed the amount the was completed. - * @param quint64 total the total amout that should be completed. - */ - void updateTime(quint64 completed, quint64 total) { - quint64 elapsedTime = QDateTime::currentMSecsSinceEpoch() - this->_startedTime ; - //don't start until you have some good data to process, prevents jittring estiamtes at the start of the syncing process - if(total != 0 && completed != 0 && elapsedTime > INITAL_WAIT_TIME ) { - if(_sampleCount < MAX_AVG_DIVIDER) { _sampleCount+=0.01f; } - // (elapsedTime-1) is an hack to avoid float "rounding" issue (ie. 0.99999999999999999999....) - _agvEtaMSecs = _agvEtaMSecs + (((static_cast<float>(total) / completed) * elapsedTime) - (elapsedTime-1)) - this->getEtaEstimate(); - _effectivProgressPerSec = ( total - completed ) / (1+this->getEtaEstimate()/1000); - } - } - - /** - * Get the eta estimate in milliseconds - * @return quint64 the estimate amount of milliseconds to end the process. - */ - quint64 getEtaEstimate() const { - return _agvEtaMSecs / _sampleCount; - } - - /** - * Get the estimated average bandwidth usage. - * @return quint64 the estimated bandwidth usage in bytes. - */ - quint64 getEstimatedBandwidth() const { - return _effectivProgressPerSec; - } - }; - EtaEstimate _totalEtaEstimate; - - struct ProgressItem { - ProgressItem() : _completedSize(0) {} - SyncFileItem _item; - quint64 _completedSize; - EtaEstimate _etaEstimate; - }; - QHash<QString, ProgressItem> _currentItems; - SyncFileItem _lastCompletedItem; - - void setProgressComplete(const SyncFileItem &item) { - _currentItems.remove(item._file); - if (!item._isDirectory) { - _completedFileCount++; - if (Progress::isSizeDependent(item._instruction)) { - _completedSize += item._size; - } - } - _lastCompletedItem = item; - this->updateEstimation(); - } - void setProgressItem(const SyncFileItem &item, quint64 size) { - _currentItems[item._file]._item = item; - _currentItems[item._file]._completedSize = size; - _lastCompletedItem = SyncFileItem(); - this->updateEstimation(); - _currentItems[item._file]._etaEstimate.updateTime(size,item._size); - } - - void updateEstimation() { - if(this->_totalSize > 0) { - _totalEtaEstimate.updateTime(this->completedSize(),this->_totalSize); - } else { - _totalEtaEstimate.updateTime(this->_completedFileCount,this->_totalFileCount); - } - } - - quint64 completedSize() const { - quint64 r = _completedSize; - foreach(const ProgressItem &i, _currentItems) { - if (!i._item._isDirectory) - r += i._completedSize; - } - return r; - } - /** - * Get the total completion estimate structure - * @return EtaEstimate a structure containing the total completion information. - */ - EtaEstimate totalEstimate() const { - return _totalEtaEstimate; - } - - /** - * Get the current file completion estimate structure - * @return EtaEstimate a structure containing the current file completion information. - */ - EtaEstimate getFileEstimate(const SyncFileItem &item) const { - return _currentItems[item._file]._etaEstimate; - } - }; - - OWNCLOUDSYNC_EXPORT QString asActionString( const SyncFileItem& item ); - OWNCLOUDSYNC_EXPORT QString asResultString( const SyncFileItem& item ); - - OWNCLOUDSYNC_EXPORT bool isWarningKind( SyncFileItem::Status ); - -} - -/** - * @file progressdispatcher.h - * @brief A singleton class to provide sync progress information to other gui classes. - * - * How to use the ProgressDispatcher: - * Just connect to the two signals either to progress for every individual file - * or the overall sync progress. - * - */ -class OWNCLOUDSYNC_EXPORT ProgressDispatcher : public QObject -{ - Q_OBJECT - - friend class Folder; // only allow Folder class to access the setting slots. -public: - static ProgressDispatcher* instance(); - ~ProgressDispatcher(); - -signals: - /** - @brief Signals the progress of data transmission. - - @param[out] folder The folder which is being processed - @param[out] progress A struct with all progress info. - - */ - void progressInfo( const QString& folder, const Progress::Info& progress ); - /** - * @brief: the item's job is completed - */ - void jobCompleted(const QString &folder, const SyncFileItem & item); - -protected: - void setProgressInfo(const QString& folder, const Progress::Info& progress); - -private: - ProgressDispatcher(QObject* parent = 0); - - QElapsedTimer _timer; - static ProgressDispatcher* _instance; -}; - -} -#endif // PROGRESSDISPATCHER_H diff --git a/src/mirall/propagator_legacy.cpp b/src/mirall/propagator_legacy.cpp deleted file mode 100644 index ff1d34113..000000000 --- a/src/mirall/propagator_legacy.cpp +++ /dev/null @@ -1,615 +0,0 @@ -/* - * Copyright (C) by Olivier Goffart <ogoffart@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 - * 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 "propagator_legacy.h" -#include "owncloudpropagator_p.h" - -#include "utility.h" -#include "syncjournaldb.h" -#include "syncjournalfilerecord.h" -#include "filesystem.h" -#include <httpbf.h> -#include <qfile.h> -#include <qdir.h> -#include <qdiriterator.h> -#include <qtemporaryfile.h> -#include <QDebug> -#include <QDateTime> -#include <qstack.h> -#include <QCoreApplication> - -#include <neon/ne_basic.h> -#include <neon/ne_socket.h> -#include <neon/ne_session.h> -#include <neon/ne_props.h> -#include <neon/ne_auth.h> -#include <neon/ne_dates.h> -#include <neon/ne_compress.h> -#include <neon/ne_redirect.h> - -#include <time.h> - - -namespace Mirall { - - -void PropagateUploadFileLegacy::start() -{ - if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) - return; - - QFile file(_propagator->_localDir + _item._file); - if (!file.open(QIODevice::ReadOnly)) { - done(SyncFileItem::NormalError, file.errorString()); - return; - } - QScopedPointer<char, QScopedPointerPodDeleter> uri( - ne_path_escape((_propagator->_remoteDir + _item._file).toUtf8())); - - int attempts = 0; - - /* - * do ten tries to upload the file chunked. Check the file size and mtime - * before submitting a chunk and after having submitted the last one. - * If the file has changed, retry. - */ - qDebug() << "** PUT request to" << uri.data(); - const SyncJournalDb::UploadInfo progressInfo = _propagator->_journal->getUploadInfo(_item._file); - - do { - Hbf_State state = HBF_SUCCESS; - QScopedPointer<hbf_transfer_t, ScopedPointerHelpers> trans(hbf_init_transfer(uri.data())); - Q_ASSERT(trans); - trans->user_data = this; - hbf_set_log_callback(trans.data(), _log_callback); - hbf_set_abort_callback(trans.data(), _user_want_abort); - trans.data()->chunk_finished_cb = chunk_finished_cb; - static uint chunkSize = qgetenv("OWNCLOUD_CHUNK_SIZE").toUInt(); - if (chunkSize > 0) { - trans->block_size = trans->threshold = chunkSize; - } - - state = hbf_splitlist(trans.data(), file.handle()); - - // If the source file has changed during upload, it is detected and the - // variable _previousFileSize is set accordingly. The propagator waits a - // couple of seconds and retries. - if(_previousFileSize > 0) { - qDebug() << "File size changed underway: " << trans->stat_size - _previousFileSize; - // Report the change of the overall transmission size to the propagator (queued connection because we are in a thread) - QMetaObject::invokeMethod(_propagator, "adjustTotalTransmissionSize", Qt::QueuedConnection, - Q_ARG(qint64, trans->stat_size - _previousFileSize)); - // update the item's values to the current from trans. hbf_splitlist does a stat - _item._size = trans->stat_size; - _item._modtime = trans->modtime; - - } - emit progress(_item, 0); - - if (progressInfo._valid) { - if (Utility::qDateTimeToTime_t(progressInfo._modtime) == _item._modtime) { - trans->start_id = progressInfo._chunk; - trans->transfer_id = progressInfo._transferid; - } - } - - ne_set_notifier(_propagator->_session, notify_status_cb, this); - _lastTime.restart(); - _lastProgress = 0; - _chunked_done = 0; - _chunked_total_size = _item._size; - - if( state == HBF_SUCCESS ) { - QByteArray previousEtag; - if (!_item._etag.isEmpty() && _item._etag != "empty_etag") { - // We add quotes because the owncloud server always add quotes around the etag, and - // csync_owncloud.c's owncloud_file_id always strip the quotes. - previousEtag = '"' + _item._etag + '"'; - trans->previous_etag = previousEtag.data(); - } - _chunked_total_size = trans->stat_size; - qDebug() << "About to upload " << _item._file << " (" << previousEtag << _item._size << " bytes )"; - /* Transfer all the chunks through the HTTP session using PUT. */ - state = hbf_transfer( _propagator->_session, trans.data(), "PUT" ); - } - - // the file id should only be empty for new files up- or downloaded - QByteArray fid = hbf_transfer_file_id( trans.data() ); - if( !fid.isEmpty() ) { - if( !_item._fileId.isEmpty() && _item._fileId != fid ) { - qDebug() << "WARN: File ID changed!" << _item._fileId << fid; - } - _item._fileId = fid; - } - - /* Handle errors. */ - if ( state != HBF_SUCCESS ) { - - /* If the source file changed during submission, lets try again */ - if( state == HBF_SOURCE_FILE_CHANGE ) { - if( attempts++ < 5 ) { /* FIXME: How often do we want to try? */ - qDebug("SOURCE file has changed during upload, retry #%d in %d seconds!", attempts, 2*attempts); - Utility::sleep(2*attempts); - if( _previousFileSize == 0 ) { - _previousFileSize = _item._size; - } else { - _previousFileSize = trans->stat_size; - } - continue; - } - - const QString errMsg = tr("Local file changed during sync, syncing once it arrived completely"); - done( SyncFileItem::SoftError, errMsg ); - } else if( state == HBF_USER_ABORTED ) { - const QString errMsg = tr("Sync was aborted by user."); - done( SyncFileItem::SoftError, errMsg ); - } else { - // Other HBF error conditions. - _item._httpErrorCode = hbf_fail_http_code(trans.data()); - if(checkForProblemsWithShared(_item._httpErrorCode, - tr("The file was edited locally but is part of a read only share. " - "It is restored and your edit is in the conflict file."))) - return; - - done(SyncFileItem::NormalError, hbf_error_string(trans.data(), state)); - } - return; - } - - ne_set_notifier(_propagator->_session, 0, 0); - - if( trans->modtime_accepted ) { - _item._etag = parseEtag(hbf_transfer_etag( trans.data() )); - } else { - if (!updateMTimeAndETag(uri.data(), _item._modtime)) - return; - } - - _propagator->_journal->setFileRecord(SyncJournalFileRecord(_item, _propagator->_localDir + _item._file)); - // Remove from the progress database: - _propagator->_journal->setUploadInfo(_item._file, SyncJournalDb::UploadInfo()); - _propagator->_journal->commit("upload file start"); - - if (hbf_validate_source_file(trans.data()) == HBF_SOURCE_FILE_CHANGE) { - /* Did the source file changed since the upload ? - * This is different from the previous check because the previous check happens between - * chunks while this one happens when the whole file has been uploaded. - * - * The new etag is already stored in the database in the previous lines so in case of - * crash, we won't have a conflict but we will properly do a new upload - */ - - if( attempts++ < 5 ) { /* FIXME: How often do we want to try? */ - qDebug("SOURCE file has changed after upload, retry #%d in %d seconds!", attempts, 2*attempts); - Utility::sleep(2*attempts); - continue; - } - - // Still the file change error, but we tried a couple of times. - // Ignore this file for now. - // Lets remove the file from the server (at least if it is new) as it is different - // from our file here. - if( _item._instruction == CSYNC_INSTRUCTION_NEW ) { - QScopedPointer<char, QScopedPointerPodDeleter> uri( - ne_path_escape((_propagator->_remoteDir + _item._file).toUtf8())); - - int rc = ne_delete(_propagator->_session, uri.data()); - qDebug() << "Remove the invalid file from server:" << rc; - } - - const QString errMsg = tr("Local file changed during sync, syncing once it arrived completely"); - done( SyncFileItem::SoftError, errMsg ); - return; - } - - done(SyncFileItem::Success); - return; - - } while( true ); -} - -void PropagateUploadFileLegacy::chunk_finished_cb(hbf_transfer_s *trans, int chunk, void* userdata) -{ - PropagateUploadFileLegacy *that = static_cast<PropagateUploadFileLegacy *>(userdata); - Q_ASSERT(that); - that->_chunked_done += trans->block_arr[chunk]->size; - if (trans->block_cnt > 1) { - SyncJournalDb::UploadInfo pi; - pi._valid = true; - pi._chunk = chunk + 1; // next chunk to start with - pi._transferid = trans->transfer_id; - pi._modtime = Utility::qDateTimeFromTime_t(trans->modtime); - that->_propagator->_journal->setUploadInfo(that->_item._file, pi); - that->_propagator->_journal->commit("Upload info"); - } -} - -void PropagateUploadFileLegacy::notify_status_cb(void* userdata, ne_session_status status, - const ne_session_status_info* info) -{ - PropagateUploadFileLegacy* that = reinterpret_cast<PropagateUploadFileLegacy*>(userdata); - - if (status == ne_status_sending && info->sr.total > 0) { - emit that->progress(that->_item, that->_chunked_done + info->sr.progress); - - that->limitBandwidth(that->_chunked_done + info->sr.progress, that->_propagator->_uploadLimit.fetchAndAddAcquire(0)); - } -} - - - -static QByteArray parseFileId(ne_request *req) { - QByteArray fileId; - - const char *header = ne_get_response_header(req, "OC-FileId"); - if( header ) { - fileId = header; - } - return fileId; -} - -bool PropagateNeonJob::updateMTimeAndETag(const char* uri, time_t mtime) -{ - QByteArray modtime = QByteArray::number(qlonglong(mtime)); - ne_propname pname; - pname.nspace = "DAV:"; - pname.name = "lastmodified"; - ne_proppatch_operation ops[2]; - ops[0].name = &pname; - ops[0].type = ne_propset; - ops[0].value = modtime.constData(); - ops[1].name = NULL; - - int rc = ne_proppatch( _propagator->_session, uri, ops ); - Q_UNUSED(rc); - /* FIXME: error handling - * bool error = updateErrorFromSession( rc ); - * if( error ) { - * // FIXME: We could not set the mtime. Error or not? - * qDebug() << "PROP-Patching of modified date failed."; -}*/ - - // get the etag - QScopedPointer<ne_request, ScopedPointerHelpers> req(ne_request_create(_propagator->_session, "HEAD", uri)); - int neon_stat = ne_request_dispatch(req.data()); - if (updateErrorFromSession(neon_stat, req.data())) { - return false; - } else { - _item._etag = parseEtag(ne_get_response_header(req.data(), "etag")); - QByteArray fid = parseFileId(req.data()); - if( _item._fileId.isEmpty() ) { - _item._fileId = fid; - qDebug() << "FileID was empty, set it to " << _item._fileId; - } else { - if( !fid.isEmpty() && fid != _item._fileId ) { - qDebug() << "WARN: FileID seems to have changed: "<< fid << _item._fileId; - } else { - qDebug() << "FileID is " << _item._fileId; - } - } - return true; - } -} - -void PropagateNeonJob::limitBandwidth(qint64 progress, qint64 bandwidth_limit) -{ - if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) { - // Do not limit bandwidth when aborting to speed up the current transfer - return; - } - - if (bandwidth_limit > 0) { - int64_t diff = _lastTime.nsecsElapsed() / 1000; - int64_t len = progress - _lastProgress; - if (len > 0 && diff > 0 && (1000000 * len / diff) > bandwidth_limit) { - int64_t wait_time = (1000000 * len / bandwidth_limit) - diff; - if (wait_time > 0) { - //qDebug() << "Limiting bandwidth to " << bandwidth_limit << "KB/s by waiting " << wait_time << " µs; "; - Mirall::Utility::usleep(wait_time); - } - } - _lastProgress = progress; - _lastTime.start(); - } else if (bandwidth_limit < 0 && bandwidth_limit > -100) { - int64_t diff = _lastTime.nsecsElapsed() / 1000; - if (diff > 0) { - // -bandwidth_limit is the % of bandwidth - int64_t wait_time = -diff * (1 + 100.0 / bandwidth_limit); - if (wait_time > 0) { - Mirall::Utility::usleep(wait_time); - - } - } - _lastTime.start(); - } -} - -int PropagateDownloadFileLegacy::content_reader(void *userdata, const char *buf, size_t len) -{ - PropagateDownloadFileLegacy *that = static_cast<PropagateDownloadFileLegacy *>(userdata); - size_t written = 0; - - if (that->_propagator->_abortRequested.fetchAndAddRelaxed(0)) { - ne_set_error(that->_propagator->_session, "%s", tr("Sync was aborted by user.").toUtf8().data()); - return NE_ERROR; - } - - if(buf) { - written = that->_file->write(buf, len); - if( len != written || that->_file->error() != QFile::NoError) { - qDebug() << "WRN: content_reader wrote wrong num of bytes:" << len << "," << written; - return NE_ERROR; - } - return NE_OK; - } - - return NE_ERROR; -} - -/* - * This hook is called after the response is here from the server, but before - * the response body is parsed. It decides if the response is compressed and - * if it is it installs the compression reader accordingly. - * If the response is not compressed, the normal response body reader is installed. - */ -void PropagateDownloadFileLegacy::install_content_reader( ne_request *req, void *userdata, const ne_status *status ) -{ - PropagateDownloadFileLegacy *that = static_cast<PropagateDownloadFileLegacy *>(userdata); - - Q_UNUSED(status); - - if( !that ) { - qDebug("Error: install_content_reader called without valid write context!"); - return; - } - - if( ne_get_status(req)->klass != 2 ) { - qDebug() << "Request class != 2, aborting."; - ne_add_response_body_reader( req, do_not_accept, - do_not_download_content_reader, - (void*) that ); - return; - } - - QByteArray reason_phrase = ne_get_status(req)->reason_phrase; - if(reason_phrase == QByteArray("Connection established")) { - ne_add_response_body_reader( req, ne_accept_2xx, - content_reader, - (void*) that ); - return; - } - - QByteArray etag = parseEtag(ne_get_response_header(req, "etag")); - if(etag.isEmpty()) - etag = parseEtag(ne_get_response_header(req, "ETag")); - - if (etag.isEmpty()) { - qDebug() << Q_FUNC_INFO << "No E-Tag reply by server, considering it invalid" << ne_get_response_header(req, "etag"); - that->errorString = tr("No E-Tag received from server, check Proxy/Gateway"); - ne_set_error(that->_propagator->_session, "%s", that->errorString.toUtf8().data()); - ne_add_response_body_reader( req, do_not_accept, - do_not_download_content_reader, - (void*) that ); - return; - } else if (!that->_expectedEtagForResume.isEmpty() && that->_expectedEtagForResume != etag) { - qDebug() << Q_FUNC_INFO << "We received a different E-Tag for resuming!" - << QString::fromLatin1(that->_expectedEtagForResume.data()) << "vs" - << QString::fromLatin1(etag.data()); - that->errorString = tr("We received a different E-Tag for resuming. Retrying next time."); - ne_set_error(that->_propagator->_session, "%s", that->errorString.toUtf8().data()); - ne_add_response_body_reader( req, do_not_accept, - do_not_download_content_reader, - (void*) that ); - return; - } - - - const char *enc = ne_get_response_header( req, "Content-Encoding" ); - qDebug("Content encoding ist <%s> with status %d", enc ? enc : "empty", - status ? status->code : -1 ); - - if( enc == QLatin1String("gzip") ) { - that->_decompress.reset(ne_decompress_reader( req, ne_accept_2xx, - content_reader, /* reader callback */ - that )); /* userdata */ - } else { - ne_add_response_body_reader( req, ne_accept_2xx, - content_reader, - (void*) that ); - } -} - -void PropagateDownloadFileLegacy::notify_status_cb(void* userdata, ne_session_status status, - const ne_session_status_info* info) -{ - PropagateDownloadFileLegacy* that = reinterpret_cast<PropagateDownloadFileLegacy*>(userdata); - if (status == ne_status_recving && info->sr.total > 0) { - emit that->progress(that->_item, info->sr.progress ); - - that->limitBandwidth(info->sr.progress, that->_propagator->_downloadLimit.fetchAndAddAcquire(0)); - } -} - -extern QString makeConflictFileName(const QString &fn, const QDateTime &dt); // _qnam.cpp - -void PropagateDownloadFileLegacy::start() -{ - if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) - return; - - // do a case clash check. - if( _propagator->localFileNameClash(_item._file) ) { - done( SyncFileItem::NormalError, tr("File %1 can not be downloaded because of a local file name clash!") - .arg(QDir::toNativeSeparators(_item._file)) ); - return; - } - - emit progress(_item, 0); - - QString tmpFileName; - const SyncJournalDb::DownloadInfo progressInfo = _propagator->_journal->getDownloadInfo(_item._file); - if (progressInfo._valid) { - // if the etag has changed meanwhile, remove the already downloaded part. - if (progressInfo._etag != _item._etag) { - QFile::remove(_propagator->_localDir + progressInfo._tmpfile); - _propagator->_journal->setDownloadInfo(_item._file, SyncJournalDb::DownloadInfo()); - } else { - tmpFileName = progressInfo._tmpfile; - _expectedEtagForResume = progressInfo._etag; - } - - } - - if (tmpFileName.isEmpty()) { - tmpFileName = _item._file; - //add a dot at the begining of the filename to hide the file. - int slashPos = tmpFileName.lastIndexOf('/'); - tmpFileName.insert(slashPos+1, '.'); - //add the suffix - tmpFileName += ".~" + QString::number(uint(qrand()), 16); - } - - QFile tmpFile(_propagator->_localDir + tmpFileName); - _file = &tmpFile; - if (!tmpFile.open(QIODevice::Append | QIODevice::Unbuffered)) { - done(SyncFileItem::NormalError, tmpFile.errorString()); - return; - } - - FileSystem::setFileHidden(tmpFile.fileName(), true); - - { - SyncJournalDb::DownloadInfo pi; - pi._etag = _item._etag; - pi._tmpfile = tmpFileName; - pi._valid = true; - _propagator->_journal->setDownloadInfo(_item._file, pi); - _propagator->_journal->commit("download file start"); - } - - if (!_item._directDownloadUrl.isEmpty()) { - qDebug() << Q_FUNC_INFO << "Direct download URL" << _item._directDownloadUrl << "not supported with legacy propagator, will go via ownCloud server"; - } - - /* actually do the request */ - int retry = 0; - - QScopedPointer<char, QScopedPointerPodDeleter> uri( - ne_path_escape((_propagator->_remoteDir + _item._file).toUtf8())); - - do { - QScopedPointer<ne_request, ScopedPointerHelpers> req(ne_request_create(_propagator->_session, "GET", uri.data())); - - /* Allow compressed content by setting the header */ - ne_add_request_header( req.data(), "Accept-Encoding", "gzip" ); - - if (tmpFile.size() > 0) { - quint64 done = tmpFile.size(); - if (done == _item._size) { - qDebug() << "File is already complete, no need to download"; - break; - } - QByteArray rangeRequest = "bytes=" + QByteArray::number(done) +'-'; - ne_add_request_header(req.data(), "Range", rangeRequest.constData()); - ne_add_request_header(req.data(), "Accept-Ranges", "bytes"); - qDebug() << "Retry with range " << rangeRequest; - } - - /* hook called before the content is parsed to set the correct reader, - * either the compressed- or uncompressed reader. - */ - ne_hook_post_headers( _propagator->_session, install_content_reader, this); - ne_set_notifier(_propagator->_session, notify_status_cb, this); - _lastProgress = 0; - _lastTime.start(); - - int neon_stat = ne_request_dispatch(req.data()); - - _decompress.reset(); // Destroy the decompress after the request has been dispatched. - - /* delete the hook again, otherwise they get chained as they are with the session */ - ne_unhook_post_headers( _propagator->_session, install_content_reader, this ); - ne_set_notifier(_propagator->_session, 0, 0); - - if (neon_stat == NE_TIMEOUT && (++retry) < 3) { - continue; - } - - // This one is set by install_content_reader if e.g. there is no E-Tag - if (!errorString.isEmpty()) { - // don't keep the temporary file as the file downloaded so far is invalid - tmpFile.close(); - tmpFile.remove(); - _propagator->_journal->setDownloadInfo(_item._file, SyncJournalDb::DownloadInfo()); - done(SyncFileItem::SoftError, errorString); - return; - } - - // This one is set by neon - if( updateErrorFromSession(neon_stat, req.data() ) ) { - qDebug("Error GET: Neon: %d", neon_stat); - if (tmpFile.size() == 0) { - // don't keep the temporary file if it is empty. - tmpFile.close(); - tmpFile.remove(); - _propagator->_journal->setDownloadInfo(_item._file, SyncJournalDb::DownloadInfo()); - } - return; - } - _item._etag = parseEtag(ne_get_response_header(req.data(), "etag")); - break; - } while (1); - - tmpFile.close(); - tmpFile.flush(); - QString fn = _propagator->_localDir + _item._file; - - - bool isConflict = _item._instruction == CSYNC_INSTRUCTION_CONFLICT - && !FileSystem::fileEquals(fn, tmpFile.fileName()); // compare the files to see if there was an actual conflict. - //In case of conflict, make a backup of the old file - if (isConflict) { - QFile f(fn); - QString conflictFileName = makeConflictFileName(fn, Utility::qDateTimeFromTime_t(_item._modtime)); - if (!f.rename(conflictFileName)) { - //If the rename fails, don't replace it. - done(SyncFileItem::NormalError, f.errorString()); - return; - } - } - - QFileInfo existingFile(fn); - if(existingFile.exists() && existingFile.permissions() != tmpFile.permissions()) { - tmpFile.setPermissions(existingFile.permissions()); - } - - FileSystem::setFileHidden(tmpFile.fileName(), false); - - QString error; - if (!FileSystem::renameReplace(tmpFile.fileName(), fn, &error)) { - done(SyncFileItem::NormalError, error); - return; - } - - FileSystem::setModTime(fn, _item._modtime); - - _propagator->_journal->setFileRecord(SyncJournalFileRecord(_item, fn)); - _propagator->_journal->setDownloadInfo(_item._file, SyncJournalDb::DownloadInfo()); - _propagator->_journal->commit("download file start2"); - done(isConflict ? SyncFileItem::Conflict : SyncFileItem::Success); -} - - -} diff --git a/src/mirall/propagator_legacy.h b/src/mirall/propagator_legacy.h deleted file mode 100644 index eee25c0dd..000000000 --- a/src/mirall/propagator_legacy.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) by Olivier Goffart <ogoffart@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 - * 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. - */ - -#pragma once - -#include "propagatorjobs.h" - -namespace Mirall { - -class PropagateUploadFileLegacy: public PropagateNeonJob { - Q_OBJECT -public: - explicit PropagateUploadFileLegacy(OwncloudPropagator* propagator,const SyncFileItem& item) - : PropagateNeonJob(propagator, item) - , _chunked_done(0), _chunked_total_size(0), _previousFileSize(0) {} - void start() Q_DECL_OVERRIDE; -private: - // Log callback for httpbf - static void _log_callback(const char *func, const char *text, void*) - { - qDebug() << " " << func << text; - } - - // abort callback for httpbf - static int _user_want_abort(void *userData) - { - return static_cast<PropagateUploadFileLegacy *>(userData)->_propagator->_abortRequested.fetchAndAddRelaxed(0); - } - - // callback from httpbf when a chunk is finished - static void chunk_finished_cb(hbf_transfer_s *trans, int chunk, void* userdata); - static void notify_status_cb(void* userdata, ne_session_status status, - const ne_session_status_info* info); - - qint64 _chunked_done; // amount of bytes already sent with the previous chunks - qint64 _chunked_total_size; // total size of the whole file - qint64 _previousFileSize; // In case the file size has changed during upload, this is the previous one. -}; - -class PropagateDownloadFileLegacy: public PropagateNeonJob { - Q_OBJECT -public: - explicit PropagateDownloadFileLegacy(OwncloudPropagator* propagator,const SyncFileItem& item) - : PropagateNeonJob(propagator, item), _file(0) {} - void start() Q_DECL_OVERRIDE; -private: - QFile *_file; - QScopedPointer<ne_decompress, ScopedPointerHelpers> _decompress; - QString errorString; - QByteArray _expectedEtagForResume; - - static int do_not_accept (void *userdata, ne_request *req, const ne_status *st) - { - Q_UNUSED(userdata); Q_UNUSED(req); Q_UNUSED(st); - return 0; // ignore this response - } - - static int do_not_download_content_reader(void *userdata, const char *buf, size_t len) - { - Q_UNUSED(userdata); Q_UNUSED(buf); Q_UNUSED(len); - return NE_ERROR; - } - - // neon hooks: - static int content_reader(void *userdata, const char *buf, size_t len); - static void install_content_reader( ne_request *req, void *userdata, const ne_status *status ); - static void notify_status_cb(void* userdata, ne_session_status status, - const ne_session_status_info* info); -}; - -} diff --git a/src/mirall/propagator_qnam.cpp b/src/mirall/propagator_qnam.cpp deleted file mode 100644 index 475a5b98a..000000000 --- a/src/mirall/propagator_qnam.cpp +++ /dev/null @@ -1,703 +0,0 @@ -/* - * Copyright (C) by Olivier Goffart <ogoffart@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. - */ - -#include "propagator_qnam.h" -#include "networkjobs.h" -#include "account.h" -#include "syncjournaldb.h" -#include "syncjournalfilerecord.h" -#include "utility.h" -#include "filesystem.h" -#include "propagatorjobs.h" -#include <QNetworkAccessManager> -#include <QFileInfo> -#include <QDir> -#include <cmath> - -namespace Mirall { - -static uint chunkSize() { - static uint chunkSize; - if (!chunkSize) { - chunkSize = qgetenv("OWNCLOUD_CHUNK_SIZE").toUInt(); - if (chunkSize == 0) { - chunkSize = 10*1024*1024; // default to 10 MiB - } - } - return chunkSize; -} - -/** - * Fiven an error from the network, map to a SyncFileItem::Status error - */ -static SyncFileItem::Status classifyError(QNetworkReply::NetworkError nerror, int httpCode) { - Q_ASSERT (nerror != QNetworkReply::NoError); // we should only be called when there is an error - - if (nerror > QNetworkReply::NoError && nerror <= QNetworkReply::UnknownProxyError) { - // network error or proxy error -> fatal - return SyncFileItem::FatalError; - } - - if (httpCode == 412) { - // "Precondition Failed" - // Happens when the e-tag has changed - return SyncFileItem::SoftError; - } - - return SyncFileItem::NormalError; -} - -void PUTFileJob::start() { - QNetworkRequest req; - for(QMap<QByteArray, QByteArray>::const_iterator it = _headers.begin(); it != _headers.end(); ++it) { - req.setRawHeader(it.key(), it.value()); - } - - setReply(davRequest("PUT", path(), req, _device)); - _device->setParent(reply()); - setupConnections(reply()); - - if( reply()->error() != QNetworkReply::NoError ) { - qWarning() << Q_FUNC_INFO << " Network error: " << reply()->errorString(); - } - - connect(reply(), SIGNAL(uploadProgress(qint64,qint64)), this, SIGNAL(uploadProgress(qint64,qint64))); - connect(reply(), SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(resetTimeout())); - - AbstractNetworkJob::start(); -} - -void PUTFileJob::slotTimeout() { - _errorString = tr("Connection Timeout"); - reply()->abort(); -} - -void PropagateUploadFileQNAM::start() -{ - if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) - return; - - _file = new QFile(_propagator->_localDir + _item._file, this); - if (!_file->open(QIODevice::ReadOnly)) { - done(SyncFileItem::NormalError, _file->errorString()); - delete _file; - return; - } - - quint64 fileSize = _file->size(); - _chunkCount = std::ceil(fileSize/double(chunkSize())); - _startChunk = 0; - _transferId = qrand() ^ _item._modtime ^ (_item._size << 16); - - const SyncJournalDb::UploadInfo progressInfo = _propagator->_journal->getUploadInfo(_item._file); - - if (progressInfo._valid && Utility::qDateTimeToTime_t(progressInfo._modtime) == _item._modtime ) { - _startChunk = progressInfo._chunk; - _transferId = progressInfo._transferid; - qDebug() << Q_FUNC_INFO << _item._file << ": Resuming from chunk " << _startChunk; - } - - _currentChunk = 0; - _duration.start(); - - _propagator->_activeJobs++; - emit progress(_item, 0); - emitReady(); - this->startNextChunk(); -} - -struct ChunkDevice : QIODevice { -public: - QIODevice *_file; - qint64 _read; - qint64 _size; - qint64 _start; - - ChunkDevice(QIODevice *file, qint64 start, qint64 size) - : QIODevice(file), _file(file), _read(0), _size(size), _start(start) { - _file->seek(start); - } - - virtual qint64 writeData(const char* , qint64 ) Q_DECL_OVERRIDE { - Q_ASSERT(!"write to read only device"); - return 0; - } - - virtual qint64 readData(char* data, qint64 maxlen) Q_DECL_OVERRIDE { - maxlen = qMin(maxlen, chunkSize() - _read); - if (maxlen == 0) - return 0; - qint64 ret = _file->read(data, maxlen); - if (ret < 0) - return -1; - _read += ret; - return ret; - } - - virtual bool atEnd() const Q_DECL_OVERRIDE { - return _read >= chunkSize() || _file->atEnd(); - } - - virtual qint64 size() const Q_DECL_OVERRIDE{ - return _size; - } - - qint64 bytesAvailable() const Q_DECL_OVERRIDE - { - return _size - _read + QIODevice::bytesAvailable(); - } - - // random access, we can seek - virtual bool isSequential() const Q_DECL_OVERRIDE{ - return false; - } - - virtual bool seek ( qint64 pos ) Q_DECL_OVERRIDE { - _read = pos; - return _file->seek(pos + _start); - } -}; - -void PropagateUploadFileQNAM::startNextChunk() -{ - if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) - return; - - - /* - * // If the source file has changed during upload, it is detected and the - * // variable _previousFileSize is set accordingly. The propagator waits a - * // couple of seconds and retries. - * if(_previousFileSize > 0) { - * qDebug() << "File size changed underway: " << trans->stat_size - _previousFileSize; - * // Report the change of the overall transmission size to the propagator - * _propagator->overallTransmissionSizeChanged(qint64(trans->stat_size - _previousFileSize)); - * // update the item's values to the current from trans. hbf_splitlist does a stat - * _item._size = trans->stat_size; - * _item._modtime = trans->modtime; - * - */ - quint64 fileSize = _item._size; - QMap<QByteArray, QByteArray> headers; - headers["OC-Total-Length"] = QByteArray::number(fileSize); - headers["Content-Type"] = "application/octet-stream"; - headers["X-OC-Mtime"] = QByteArray::number(qint64(_item._modtime)); - if (!_item._etag.isEmpty() && _item._etag != "empty_etag") { - // We add quotes because the owncloud server always add quotes around the etag, and - // csync_owncloud.c's owncloud_file_id always strip the quotes. - headers["If-Match"] = '"' + _item._etag + '"'; - } - - QString path = _item._file; - QIODevice *device = 0; - if (_chunkCount > 1) { - int sendingChunk = (_currentChunk + _startChunk) % _chunkCount; - // XOR with chunk size to make sure everything goes well if chunk size change between runs - uint transid = _transferId ^ chunkSize(); - path += QString("-chunking-%1-%2-%3").arg(transid).arg(_chunkCount).arg(sendingChunk); - headers["OC-Chunked"] = "1"; - int currentChunkSize = chunkSize(); - if (sendingChunk == _chunkCount - 1) { // last chunk - currentChunkSize = (fileSize % chunkSize()); - if( currentChunkSize == 0 ) { // if the last chunk pretents to be 0, its actually the full chunk size. - currentChunkSize = chunkSize(); - } - } - device = new ChunkDevice(_file, chunkSize() * sendingChunk, currentChunkSize); - } else { - device = _file; - } - - bool isOpen = true; - if (!device->isOpen()) { - isOpen = device->open(QIODevice::ReadOnly); - } - - if( isOpen ) { - _job = new PUTFileJob(AccountManager::instance()->account(), _propagator->_remoteFolder + path, device, headers); - _job->setTimeout(_propagator->httpTimeout() * 1000); - connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished())); - connect(_job, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(slotUploadProgress(qint64,qint64))); - _job->start(); - } else { - qDebug() << "ERR: Could not open upload file: " << device->errorString(); - done( SyncFileItem::NormalError, device->errorString() ); - delete device; - return; - } -} - -void PropagateUploadFileQNAM::slotPutFinished() -{ - PUTFileJob *job = qobject_cast<PUTFileJob *>(sender()); - Q_ASSERT(job); - - qDebug() << Q_FUNC_INFO << job->reply()->request().url() << "FINISHED WITH STATUS" - << job->reply()->error() - << (job->reply()->error() == QNetworkReply::NoError ? QLatin1String("") : job->reply()->errorString()) - << job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute) - << job->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute); - - QNetworkReply::NetworkError err = job->reply()->error(); - if (err != QNetworkReply::NoError) { - _item._httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - _propagator->_activeJobs--; - if(checkForProblemsWithShared(_item._httpErrorCode, - tr("The file was edited locally but is part of a read only share. " - "It is restored and your edit is in the conflict file."))) { - return; - } - QString errorString = job->errorString(); - - QByteArray replyContent = job->reply()->readAll(); - qDebug() << replyContent; // display the XML error in the debug - QRegExp rx("<s:message>(.*)</s:message>"); // Issue #1366: display server exception - if (rx.indexIn(QString::fromUtf8(replyContent)) != -1) { - errorString += QLatin1String(" (") + rx.cap(1) + QLatin1Char(')'); - } - - if (_item._httpErrorCode == 412) { - // Precondition Failed: Maybe the bad etag is in the database, we need to clear the - // parent folder etag so we won't read from DB next sync. - _propagator->_journal->avoidReadFromDbOnNextSync(_item._file); - } - - done(classifyError(err, _item._httpErrorCode), errorString); - return; - } - - bool finished = job->reply()->hasRawHeader("ETag"); - - if (!finished) { - QFileInfo fi(_propagator->_localDir + _item._file); - if( !fi.exists() ) { - _propagator->_activeJobs--; - done(SyncFileItem::SoftError, tr("The local file was removed during sync.")); - return; - } - - if (Utility::qDateTimeToTime_t(fi.lastModified()) != _item._modtime) { - /* Uh oh: The local file has changed during upload */ - _propagator->_activeJobs--; - done(SyncFileItem::SoftError, tr("Local file changed during sync.")); - // FIXME: the legacy code was retrying for a few seconds. - // and also checking that after the last chunk, and removed the file in case of INSTRUCTION_NEW - return; - } - - // Proceed to next chunk. - _currentChunk++; - if (_currentChunk >= _chunkCount) { - _propagator->_activeJobs--; - done(SyncFileItem::NormalError, tr("The server did not acknowledge the last chunk. (No e-tag were present)")); - return; - } - - SyncJournalDb::UploadInfo pi; - pi._valid = true; - pi._chunk = (_currentChunk + _startChunk) % _chunkCount; // next chunk to start with - pi._transferid = _transferId; - pi._modtime = Utility::qDateTimeFromTime_t(_item._modtime); - _propagator->_journal->setUploadInfo(_item._file, pi); - _propagator->_journal->commit("Upload info"); - startNextChunk(); - return; - } - - // the following code only happens after all chunks were uploaded. - // - // the file id should only be empty for new files up- or downloaded - QByteArray fid = job->reply()->rawHeader("OC-FileID"); - if( !fid.isEmpty() ) { - if( !_item._fileId.isEmpty() && _item._fileId != fid ) { - qDebug() << "WARN: File ID changed!" << _item._fileId << fid; - } - _item._fileId = fid; - } - - _item._etag = parseEtag(job->reply()->rawHeader("ETag")); - _item._responseTimeStamp = job->responseTimestamp(); - - if (job->reply()->rawHeader("X-OC-MTime") != "accepted") { - // X-OC-MTime is supported since owncloud 5.0. But not when chunking. - // Normaly Owncloud 6 always put X-OC-MTime - qDebug() << "Server do not support X-OC-MTime"; - PropagatorJob *newJob = new UpdateMTimeAndETagJob(_propagator, _item); - QObject::connect(newJob, SIGNAL(completed(SyncFileItem)), this, SLOT(finalize(SyncFileItem))); - QMetaObject::invokeMethod(newJob, "start"); - return; - } - finalize(_item); -} - -void PropagateUploadFileQNAM::finalize(const SyncFileItem ©) -{ - // Normally, copy == _item, but when it comes from the UpdateMTimeAndETagJob, we need to do - // some updates - _item._etag = copy._etag; - _item._fileId = copy._fileId; - - _propagator->_activeJobs--; - - _item._requestDuration = _duration.elapsed(); - - _propagator->_journal->setFileRecord(SyncJournalFileRecord(_item, _propagator->_localDir + _item._file)); - // Remove from the progress database: - _propagator->_journal->setUploadInfo(_item._file, SyncJournalDb::UploadInfo()); - _propagator->_journal->commit("upload file start"); - - done(SyncFileItem::Success); -} - -void PropagateUploadFileQNAM::slotUploadProgress(qint64 sent, qint64) -{ - int progressChunk = _currentChunk + _startChunk; - if (progressChunk >= _chunkCount) - progressChunk = _currentChunk; - emit progress(_item, sent + _currentChunk * chunkSize()); -} - - -void PropagateUploadFileQNAM::abort() -{ - if (_job && _job->reply()) { - qDebug() << Q_FUNC_INFO << this->_item._file; - _job->reply()->abort(); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -// DOES NOT take owncership of the device. -GETFileJob::GETFileJob(Account* account, const QString& path, QIODevice *device, - const QMap<QByteArray, QByteArray> &headers, QByteArray expectedEtagForResume, - QObject* parent) -: AbstractNetworkJob(account, path, parent), - _device(device), _headers(headers), _expectedEtagForResume(expectedEtagForResume), - _errorStatus(SyncFileItem::NoStatus) -{ -} - -GETFileJob::GETFileJob(Account* account, const QUrl& url, QIODevice *device, - const QMap<QByteArray, QByteArray> &headers, - QObject* parent) -: AbstractNetworkJob(account, url.toEncoded(), parent), - _device(device), _headers(headers), - _errorStatus(SyncFileItem::NoStatus), _directDownloadUrl(url) -{ -} - - -void GETFileJob::start() { - QNetworkRequest req; - for(QMap<QByteArray, QByteArray>::const_iterator it = _headers.begin(); it != _headers.end(); ++it) { - req.setRawHeader(it.key(), it.value()); - } - - if (_directDownloadUrl.isEmpty()) { - setReply(davRequest("GET", path(), req)); - } else { - // Use direct URL - setReply(davRequest("GET", _directDownloadUrl, req)); - } - setupConnections(reply()); - - if( reply()->error() != QNetworkReply::NoError ) { - qWarning() << Q_FUNC_INFO << " Network error: " << reply()->errorString(); - } - - connect(reply(), SIGNAL(metaDataChanged()), this, SLOT(slotMetaDataChanged())); - connect(reply(), SIGNAL(readyRead()), this, SLOT(slotReadyRead())); - connect(reply(), SIGNAL(downloadProgress(qint64,qint64)), this, SIGNAL(downloadProgress(qint64,qint64))); - - AbstractNetworkJob::start(); -} - -void GETFileJob::slotMetaDataChanged() -{ - if (reply()->error() != QNetworkReply::NoError - || reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() / 100 != 2) { - // We will handle the error when the job is finished. - return; - } - - _etag = parseEtag(reply()->rawHeader("Etag")); - if (!_directDownloadUrl.isEmpty() && !_etag.isEmpty()) { - qDebug() << Q_FUNC_INFO << "Direct download used, ignoring server ETag" << _etag; - _etag = QByteArray(); // reset received ETag - } else if (!_directDownloadUrl.isEmpty()) { - // All fine, ETag empty and directDownloadUrl used - } else if (_etag.isEmpty()) { - qDebug() << Q_FUNC_INFO << "No E-Tag reply by server, considering it invalid"; - _errorString = tr("No E-Tag received from server, check Proxy/Gateway"); - _errorStatus = SyncFileItem::NormalError; - reply()->abort(); - return; - } else if (!_expectedEtagForResume.isEmpty() && _expectedEtagForResume != _etag) { - qDebug() << Q_FUNC_INFO << "We received a different E-Tag for resuming!" - << _expectedEtagForResume << "vs" << _etag; - _errorString = tr("We received a different E-Tag for resuming. Retrying next time."); - _errorStatus = SyncFileItem::NormalError; - reply()->abort(); - return; - } -} - -void GETFileJob::slotReadyRead() -{ - int bufferSize = qMax(1024*8ll , reply()->bytesAvailable()); - QByteArray buffer(bufferSize, Qt::Uninitialized); - - while(reply()->bytesAvailable() > 0) { - qint64 r = reply()->read(buffer.data(), bufferSize); - if (r < 0) { - _errorString = reply()->errorString(); - _errorStatus = SyncFileItem::NormalError; - qDebug() << "Error while reading from device: " << _errorString; - reply()->abort(); - return; - } - - qint64 w = _device->write(buffer.constData(), r); - if (w != r) { - _errorString = _device->errorString(); - _errorStatus = SyncFileItem::NormalError; - qDebug() << "Error while writing to file" << w << r << _errorString; - reply()->abort(); - return; - } - } - resetTimeout(); -} - -void GETFileJob::slotTimeout() -{ - _errorString = tr("Connection Timeout"); - _errorStatus = SyncFileItem::FatalError; - reply()->abort(); -} - -void PropagateDownloadFileQNAM::start() -{ - if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) - return; - - qDebug() << Q_FUNC_INFO << _item._file << _propagator->_activeJobs; - - // do a klaas' case clash check. - if( _propagator->localFileNameClash(_item._file) ) { - done( SyncFileItem::NormalError, tr("File %1 can not be downloaded because of a local file name clash!") - .arg(QDir::toNativeSeparators(_item._file)) ); - return; - } - - emit progress(_item, 0); - - QString tmpFileName; - QByteArray expectedEtagForResume; - const SyncJournalDb::DownloadInfo progressInfo = _propagator->_journal->getDownloadInfo(_item._file); - if (progressInfo._valid) { - // if the etag has changed meanwhile, remove the already downloaded part. - if (progressInfo._etag != _item._etag) { - QFile::remove(_propagator->_localDir + progressInfo._tmpfile); - _propagator->_journal->setDownloadInfo(_item._file, SyncJournalDb::DownloadInfo()); - } else { - tmpFileName = progressInfo._tmpfile; - expectedEtagForResume = progressInfo._etag; - } - - } - - if (tmpFileName.isEmpty()) { - tmpFileName = _item._file; - //add a dot at the begining of the filename to hide the file. - int slashPos = tmpFileName.lastIndexOf('/'); - tmpFileName.insert(slashPos+1, '.'); - //add the suffix - tmpFileName += ".~" + QString::number(uint(qrand()), 16); - } - - _tmpFile.setFileName(_propagator->_localDir + tmpFileName); - if (!_tmpFile.open(QIODevice::Append | QIODevice::Unbuffered)) { - done(SyncFileItem::NormalError, _tmpFile.errorString()); - return; - } - - FileSystem::setFileHidden(_tmpFile.fileName(), true); - - { - SyncJournalDb::DownloadInfo pi; - pi._etag = _item._etag; - pi._tmpfile = tmpFileName; - pi._valid = true; - _propagator->_journal->setDownloadInfo(_item._file, pi); - _propagator->_journal->commit("download file start"); - } - - - QMap<QByteArray, QByteArray> headers; - - if (_tmpFile.size() > 0) { - quint64 done = _tmpFile.size(); - if (done == _item._size) { - qDebug() << "File is already complete, no need to download"; - downloadFinished(); - return; - } - headers["Range"] = "bytes=" + QByteArray::number(done) +'-'; - headers["Accept-Ranges"] = "bytes"; - qDebug() << "Retry with range " << headers["Range"]; - _startSize = done; - } - - if (_item._directDownloadUrl.isEmpty()) { - // Normal job, download from oC instance - _job = new GETFileJob(AccountManager::instance()->account(), - _propagator->_remoteFolder + _item._file, - &_tmpFile, headers, expectedEtagForResume); - } else { - // We were provided a direct URL, use that one - if (!_item._directDownloadCookies.isEmpty()) { - headers["Cookie"] = _item._directDownloadCookies.toUtf8(); - } - QUrl url = QUrl::fromUserInput(_item._directDownloadUrl); - _job = new GETFileJob(AccountManager::instance()->account(), - url, - &_tmpFile, headers); - qDebug() << Q_FUNC_INFO << "directDownloadUrl given for " << _item._file << _item._directDownloadUrl; - } - _job->setTimeout(_propagator->httpTimeout() * 1000); - connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished())); - connect(_job, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slotDownloadProgress(qint64,qint64))); - _propagator->_activeJobs ++; - _job->start(); - emitReady(); -} - -void PropagateDownloadFileQNAM::slotGetFinished() -{ - _propagator->_activeJobs--; - - GETFileJob *job = qobject_cast<GETFileJob *>(sender()); - Q_ASSERT(job); - - qDebug() << Q_FUNC_INFO << job->reply()->request().url() << "FINISHED WITH STATUS" - << job->reply()->error() - << (job->reply()->error() == QNetworkReply::NoError ? QLatin1String("") : job->reply()->errorString()); - - QNetworkReply::NetworkError err = job->reply()->error(); - if (err != QNetworkReply::NoError) { - if (_tmpFile.size() == 0) { - // don't keep the temporary file if it is empty. - _tmpFile.close(); - _tmpFile.remove(); - _propagator->_journal->setDownloadInfo(_item._file, SyncJournalDb::DownloadInfo()); - } - _item._httpErrorCode = job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - _propagator->_activeJobs--; - SyncFileItem::Status status = job->errorStatus(); - if (status == SyncFileItem::NoStatus) { - status = classifyError(err, _item._httpErrorCode); - } - done(status, job->errorString()); - return; - } - - if (!job->etag().isEmpty()) { - // The etag will be empty if we used a direct download URL. - // (If it was really empty by the server, the GETFileJob will have errored - _item._etag = parseEtag(job->etag()); - } - _item._requestDuration = job->duration(); - _item._responseTimeStamp = job->responseTimestamp(); - - _tmpFile.close(); - _tmpFile.flush(); - downloadFinished(); -} - -QString makeConflictFileName(const QString &fn, const QDateTime &dt) -{ - QString conflictFileName(fn); - // Add _conflict-XXXX before the extention. - int dotLocation = conflictFileName.lastIndexOf('.'); - // If no extention, add it at the end (take care of cases like foo/.hidden or foo.bar/file) - if (dotLocation <= conflictFileName.lastIndexOf('/') + 1) { - dotLocation = conflictFileName.size(); - } - QString timeString = dt.toString("yyyyMMdd-hhmmss"); - - // Additional marker - QByteArray conflictFileUserName = qgetenv("CSYNC_CONFLICT_FILE_USERNAME"); - if (conflictFileUserName.isEmpty()) - conflictFileName.insert(dotLocation, "_conflict-" + timeString); - else - conflictFileName.insert(dotLocation, "_conflict_" + QString::fromUtf8(conflictFileUserName) + "-" + timeString); - - return conflictFileName; -} - -void PropagateDownloadFileQNAM::downloadFinished() -{ - - QString fn = _propagator->_localDir + _item._file; - - - bool isConflict = _item._instruction == CSYNC_INSTRUCTION_CONFLICT - && !FileSystem::fileEquals(fn, _tmpFile.fileName()); // compare the files to see if there was an actual conflict. - //In case of conflict, make a backup of the old file - if (isConflict) { - QFile f(fn); - QString conflictFileName = makeConflictFileName(fn, Utility::qDateTimeFromTime_t(_item._modtime)); - if (!f.rename(conflictFileName)) { - //If the rename fails, don't replace it. - done(SyncFileItem::NormalError, f.errorString()); - return; - } - } - - QFileInfo existingFile(fn); - if(existingFile.exists() && existingFile.permissions() != _tmpFile.permissions()) { - _tmpFile.setPermissions(existingFile.permissions()); - } - - FileSystem::setFileHidden(_tmpFile.fileName(), false); - - QString error; - if (!FileSystem::renameReplace(_tmpFile.fileName(), fn, &error)) { - done(SyncFileItem::NormalError, error); - return; - } - - FileSystem::setModTime(fn, _item._modtime); - - _propagator->_journal->setFileRecord(SyncJournalFileRecord(_item, fn)); - _propagator->_journal->setDownloadInfo(_item._file, SyncJournalDb::DownloadInfo()); - _propagator->_journal->commit("download file start2"); - done(isConflict ? SyncFileItem::Conflict : SyncFileItem::Success); -} - -void PropagateDownloadFileQNAM::slotDownloadProgress(qint64 received, qint64) -{ - emit progress(_item, received + _startSize); -} - - -void PropagateDownloadFileQNAM::abort() -{ - if (_job && _job->reply()) - _job->reply()->abort(); -} - -} diff --git a/src/mirall/propagator_qnam.h b/src/mirall/propagator_qnam.h deleted file mode 100644 index fee64cf5a..000000000 --- a/src/mirall/propagator_qnam.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) by Olivier Goffart <ogoffart@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 - * 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. - */ -#pragma once - - -#include "owncloudpropagator.h" -#include "owncloudpropagator_p.h" -#include "networkjobs.h" - -#include <QBuffer> -#include <QFile> - -namespace Mirall { - -class ChunkBlock { - -public: - explicit ChunkBlock() : _state(NotTransfered) { } - enum State { - CHUNK_SUCCESS, - NotTransfered, /* never tried to transfer */ - Transfered, /* transfer currently running */ - TransferFailed, /* transfer tried but failed */ - TransferSuccess, /* block transfer succeeded. */ - Fail - }; - - int _sequenceNo; - int64_t _start; - int64_t _size; - - State _state; - int _httpResultCode; - QString _httpErrorMsg; - QString _etag; - QBuffer *_buffer; - -}; - -class PUTFileJob : public AbstractNetworkJob { - Q_OBJECT - QIODevice* _device; - QMap<QByteArray, QByteArray> _headers; - QString _errorString; - -public: - // Takes ownership of the device - explicit PUTFileJob(Account* account, const QString& path, QIODevice *device, - const QMap<QByteArray, QByteArray> &headers, QObject* parent = 0) - : AbstractNetworkJob(account, path, parent), _device(device), _headers(headers) {} - - virtual void start() Q_DECL_OVERRIDE; - - virtual bool finished() Q_DECL_OVERRIDE { - emit finishedSignal(); - return true; - } - - QString errorString() { - return _errorString.isEmpty() ? reply()->errorString() : _errorString; - }; - - virtual void slotTimeout() Q_DECL_OVERRIDE; - - -signals: - void finishedSignal(); - void uploadProgress(qint64,qint64); -}; - - -class PropagateUploadFileQNAM : public PropagateItemJob { - Q_OBJECT - QPointer<PUTFileJob> _job; - QFile *_file; - int _startChunk; - int _currentChunk; - int _chunkCount; - int _transferId; - QElapsedTimer _duration; -public: - PropagateUploadFileQNAM(OwncloudPropagator* propagator,const SyncFileItem& item) - : PropagateItemJob(propagator, item), _startChunk(0), _currentChunk(0), _chunkCount(0), _transferId(0) {} - void start() Q_DECL_OVERRIDE; -private slots: - void slotPutFinished(); - void slotUploadProgress(qint64,qint64); - void abort() Q_DECL_OVERRIDE; - void startNextChunk(); - void finalize(const Mirall::SyncFileItem&); -}; - - -class GETFileJob : public AbstractNetworkJob { - Q_OBJECT - QIODevice* _device; - QMap<QByteArray, QByteArray> _headers; - QString _errorString; - QByteArray _expectedEtagForResume; - SyncFileItem::Status _errorStatus; - QUrl _directDownloadUrl; - QByteArray _etag; -public: - - // DOES NOT take owncership of the device. - explicit GETFileJob(Account* account, const QString& path, QIODevice *device, - const QMap<QByteArray, QByteArray> &headers, QByteArray expectedEtagForResume, - QObject* parent = 0); - // For directDownloadUrl: - explicit GETFileJob(Account* account, const QUrl& url, QIODevice *device, - const QMap<QByteArray, QByteArray> &headers, - QObject* parent = 0); - - virtual void start() Q_DECL_OVERRIDE; - virtual bool finished() Q_DECL_OVERRIDE { - emit finishedSignal(); - return true; - } - - QString errorString() { - return _errorString.isEmpty() ? reply()->errorString() : _errorString; - }; - - SyncFileItem::Status errorStatus() { return _errorStatus; } - - virtual void slotTimeout() Q_DECL_OVERRIDE; - - QByteArray &etag() { return _etag; } - - -signals: - void finishedSignal(); - void downloadProgress(qint64,qint64); -private slots: - void slotReadyRead(); - void slotMetaDataChanged(); -}; - - -class PropagateDownloadFileQNAM : public PropagateItemJob { - Q_OBJECT - QPointer<GETFileJob> _job; - -// QFile *_file; - QFile _tmpFile; - quint64 _startSize; -public: - PropagateDownloadFileQNAM(OwncloudPropagator* propagator,const SyncFileItem& item) - : PropagateItemJob(propagator, item), _startSize(0) {} - void start() Q_DECL_OVERRIDE; -private slots: - void slotGetFinished(); - void abort() Q_DECL_OVERRIDE; - void downloadFinished(); - void slotDownloadProgress(qint64,qint64); - - -}; - - - -} diff --git a/src/mirall/propagatorjobs.cpp b/src/mirall/propagatorjobs.cpp deleted file mode 100644 index a94c04a75..000000000 --- a/src/mirall/propagatorjobs.cpp +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright (C) by Olivier Goffart <ogoffart@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 - * 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 "propagatorjobs.h" -#include "owncloudpropagator_p.h" -#include "propagator_legacy.h" - -#include "utility.h" -#include "syncjournaldb.h" -#include "syncjournalfilerecord.h" -#include <httpbf.h> -#include <qfile.h> -#include <qdir.h> -#include <qdiriterator.h> -#include <qtemporaryfile.h> -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) -#include <qabstractfileengine.h> -#else -#include <qsavefile.h> -#endif -#include <QDebug> -#include <QDateTime> -#include <qstack.h> -#include <QCoreApplication> - -#include <neon/ne_basic.h> -#include <neon/ne_socket.h> -#include <neon/ne_session.h> -#include <neon/ne_props.h> -#include <neon/ne_auth.h> -#include <neon/ne_dates.h> -#include <neon/ne_compress.h> -#include <neon/ne_redirect.h> - -#include <time.h> - - -namespace Mirall { - -// Code copied from Qt5's QDir::removeRecursively -static bool removeRecursively(const QString &path) -{ - bool success = true; - QDirIterator di(path, QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot); - while (di.hasNext()) { - di.next(); - const QFileInfo& fi = di.fileInfo(); - bool ok; - if (fi.isDir() && !fi.isSymLink()) - ok = removeRecursively(di.filePath()); // recursive - else - ok = QFile::remove(di.filePath()); - if (!ok) - success = false; - } - if (success) - success = QDir().rmdir(path); - return success; -} - -void PropagateLocalRemove::start() -{ - if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) - return; - - QString filename = _propagator->_localDir + _item._file; - if( _propagator->localFileNameClash(_item._file)) { - done(SyncFileItem::NormalError, tr("Could not remove %1 because of a local file name clash") - .arg(QDir::toNativeSeparators(filename))); - return; - } - - if (_item._isDirectory) { - if (QDir(filename).exists() && !removeRecursively(filename)) { - done(SyncFileItem::NormalError, tr("Could not remove directory %1") - .arg(QDir::toNativeSeparators(filename))); - return; - } - } else { - QFile file(filename); - if (file.exists() && !file.remove()) { - done(SyncFileItem::NormalError, file.errorString()); - return; - } - } - emit progress(_item, 0); - _propagator->_journal->deleteFileRecord(_item._originalFile, _item._isDirectory); - _propagator->_journal->commit("Local remove"); - done(SyncFileItem::Success); -} - -void PropagateLocalMkdir::start() -{ - if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) - return; - - QDir newDir(_propagator->_localDir + _item._file); - QString newDirStr = QDir::toNativeSeparators(newDir.path()); - if( Utility::fsCasePreserving() && _propagator->localFileNameClash(_item._file ) ) { - qDebug() << "WARN: new directory to create locally already exists!"; - done( SyncFileItem::NormalError, tr("Attention, possible case sensitivity clash with %1").arg(newDirStr) ); - return; - } - QDir localDir(_propagator->_localDir); - if (!localDir.mkpath(_item._file)) { - done( SyncFileItem::NormalError, tr("could not create directory %1").arg(newDirStr) ); - return; - } - done(SyncFileItem::Success); -} - -void PropagateRemoteRemove::start() -{ - if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) - return; - - QScopedPointer<char, QScopedPointerPodDeleter> uri( - ne_path_escape((_propagator->_remoteDir + _item._file).toUtf8())); - emit progress(_item, 0); - qDebug() << "** DELETE " << uri.data(); - int rc = ne_delete(_propagator->_session, uri.data()); - - QString errorString = QString::fromUtf8(ne_get_error(_propagator->_session)); - int httpStatusCode = errorString.mid(0, errorString.indexOf(QChar(' '))).toInt(); - if( checkForProblemsWithShared(httpStatusCode, - tr("The file has been removed from a read only share. It was restored.")) ) { - return; - } - - /* Ignore the error 404, it means it is already deleted */ - if (updateErrorFromSession(rc, 0, 404)) { - return; - } - - // Wed, 15 Nov 1995 06:25:24 GMT - QDateTime dt = QDateTime::currentDateTimeUtc(); - _item._responseTimeStamp = dt.toString("hh:mm:ss"); - - _propagator->_journal->deleteFileRecord(_item._originalFile, _item._isDirectory); - _propagator->_journal->commit("Remote Remove"); - done(SyncFileItem::Success); -} - -/* The list of properties that is fetched in PropFind after a MKCOL */ -static const ne_propname ls_props[] = { - { "DAV:", "getetag"}, - { "http://owncloud.org/ns", "id"}, - { NULL, NULL } -}; - -/* - * Parse the PROPFIND result after a MKCOL - */ -void PropagateRemoteMkdir::propfind_results(void *userdata, - const ne_uri *uri, - const ne_prop_result_set *set) -{ - PropagateRemoteMkdir *job = static_cast<PropagateRemoteMkdir *>(userdata); - - job->_item._etag = parseEtag(ne_propset_value( set, &ls_props[0] )); - - const char* fileId = ne_propset_value( set, &ls_props[1] ); - if (fileId) { - job->_item._fileId = fileId; - qDebug() << "MKCOL: " << uri << " FileID set it to " << fileId; - - // save the file id already so we can detect rename - SyncJournalFileRecord record(job->_item, job->_propagator->_localDir + job->_item._renameTarget); - job->_propagator->_journal->setFileRecord(record); - } -} - -void PropagateRemoteMkdir::start() -{ - if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) - return; - - QScopedPointer<char, QScopedPointerPodDeleter> uri( - ne_path_escape((_propagator->_remoteDir + _item._file).toUtf8())); - - int rc = ne_mkcol(_propagator->_session, uri.data()); - - /* Special for mkcol: it returns 405 if the directory already exists. - * Ignore that error */ - // Wed, 15 Nov 1995 06:25:24 GMT - QDateTime dt = QDateTime::currentDateTimeUtc(); - _item._responseTimeStamp = dt.toString("hh:mm:ss"); - - if( updateErrorFromSession( rc , 0, 405 ) ) { - return; - } - - // Get the fileid - // This is required so that wa can detect moves even if the folder is renamed on the server - // while files are still uploading - // TODO: Now we have to do a propfind because the server does not give the file id in the request - // https://github.com/owncloud/core/issues/9000 - - ne_propfind_handler *hdl = ne_propfind_create(_propagator->_session, uri.data(), 0); - ne_propfind_named(hdl, ls_props, propfind_results, this); - ne_propfind_destroy(hdl); - - done(SyncFileItem::Success); -} - - -void PropagateLocalRename::start() -{ - if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) - return; - - // if the file is a file underneath a moved dir, the _item.file is equal - // to _item.renameTarget and the file is not moved as a result. - if (_item._file != _item._renameTarget) { - emit progress(_item, 0); - qDebug() << "MOVE " << _propagator->_localDir + _item._file << " => " << _propagator->_localDir + _item._renameTarget; - QFile file(_propagator->_localDir + _item._file); - - if (_propagator->localFileNameClash(_item._renameTarget)) { - // Fixme: the file that is the reason for the clash could be named here, - // it would have to come out the localFileNameClash function - done(SyncFileItem::NormalError, tr( "File %1 can not be renamed to %2 because of a local file name clash") - .arg(QDir::toNativeSeparators(_item._file)).arg(QDir::toNativeSeparators(_item._renameTarget)) ); - return; - } - if (!file.rename(_propagator->_localDir + _item._file, _propagator->_localDir + _item._renameTarget)) { - done(SyncFileItem::NormalError, file.errorString()); - return; - } - } - - _propagator->_journal->deleteFileRecord(_item._originalFile); - - // store the rename file name in the item. - _item._file = _item._renameTarget; - - SyncJournalFileRecord record(_item, _propagator->_localDir + _item._renameTarget); - record._path = _item._renameTarget; - - if (!_item._isDirectory) { // Directory are saved at the end - _propagator->_journal->setFileRecord(record); - } - _propagator->_journal->commit("localRename"); - - - done(SyncFileItem::Success); -} - -void PropagateRemoteRename::start() -{ - if (_propagator->_abortRequested.fetchAndAddRelaxed(0)) - return; - - if (_item._file == _item._renameTarget) { - // The parents has been renamed already so there is nothing more to do. - } else if (_item._file == QLatin1String("Shared") ) { - // Check if it is the toplevel Shared folder and do not propagate it. - if( QFile::rename( _propagator->_localDir + _item._renameTarget, _propagator->_localDir + QLatin1String("Shared")) ) { - done(SyncFileItem::NormalError, tr("This folder must not be renamed. It is renamed back to its original name.")); - } else { - done(SyncFileItem::NormalError, tr("This folder must not be renamed. Please name it back to Shared.")); - } - return; - } else { - emit progress(_item, 0); - - QScopedPointer<char, QScopedPointerPodDeleter> uri1(ne_path_escape((_propagator->_remoteDir + _item._file).toUtf8())); - QScopedPointer<char, QScopedPointerPodDeleter> uri2(ne_path_escape((_propagator->_remoteDir + _item._renameTarget).toUtf8())); - qDebug() << "MOVE on Server: " << uri1.data() << "->" << uri2.data(); - - int rc = ne_move(_propagator->_session, 1, uri1.data(), uri2.data()); - - QString errorString = QString::fromUtf8(ne_get_error(_propagator->_session)); - int httpStatusCode = errorString.mid(0, errorString.indexOf(QChar(' '))).toInt(); - if( checkForProblemsWithShared(httpStatusCode, - tr("The file was renamed but is part of a read only share. The original file was restored."))) { - return; - } - - if (updateErrorFromSession(rc)) { - return; - } - - if (!updateMTimeAndETag(uri2.data(), _item._modtime)) - return; - } - // Wed, 15 Nov 1995 06:25:24 GMT - QDateTime dt = QDateTime::currentDateTimeUtc(); - _item._responseTimeStamp = dt.toString("hh:mm:ss"); - - _propagator->_journal->deleteFileRecord(_item._originalFile); - SyncJournalFileRecord record(_item, _propagator->_localDir + _item._renameTarget); - record._path = _item._renameTarget; - - _propagator->_journal->setFileRecord(record); - _propagator->_journal->commit("Remote Rename"); - done(SyncFileItem::Success); -} - -bool PropagateNeonJob::updateErrorFromSession(int neon_code, ne_request* req, int ignoreHttpCode) -{ - if( neon_code != NE_OK ) { - qDebug("Neon error code was %d", neon_code); - } - - QString errorString; - int httpStatusCode = 0; - - switch(neon_code) { - case NE_OK: /* Success, but still the possiblity of problems */ - if( req ) { - const ne_status *status = ne_get_status(req); - - if (status) { - if ( status->klass == 2 || status->code == ignoreHttpCode) { - // Everything is ok, no error. - return false; - } - errorString = QString::fromUtf8( status->reason_phrase ); - httpStatusCode = status->code; - _item._httpErrorCode = httpStatusCode; - } - } else { - errorString = QString::fromUtf8(ne_get_error(_propagator->_session)); - httpStatusCode = errorString.mid(0, errorString.indexOf(QChar(' '))).toInt(); - _item._httpErrorCode = httpStatusCode; - if ((httpStatusCode >= 200 && httpStatusCode < 300) - || (httpStatusCode != 0 && httpStatusCode == ignoreHttpCode)) { - // No error - return false; - } - } - // FIXME: classify the error - done (SyncFileItem::NormalError, errorString); - return true; - case NE_ERROR: /* Generic error; use ne_get_error(session) for message */ - errorString = QString::fromUtf8(ne_get_error(_propagator->_session)); - // Check if we don't need to ignore that error. - httpStatusCode = errorString.mid(0, errorString.indexOf(QChar(' '))).toInt(); - _item._httpErrorCode = httpStatusCode; - qDebug() << Q_FUNC_INFO << "NE_ERROR" << errorString << httpStatusCode << ignoreHttpCode; - if (ignoreHttpCode && httpStatusCode == ignoreHttpCode) - return false; - - done(SyncFileItem::NormalError, errorString); - return true; - case NE_LOOKUP: /* Server or proxy hostname lookup failed */ - case NE_AUTH: /* User authentication failed on server */ - case NE_PROXYAUTH: /* User authentication failed on proxy */ - case NE_CONNECT: /* Could not connect to server */ - case NE_TIMEOUT: /* Connection timed out */ - done(SyncFileItem::FatalError, QString::fromUtf8(ne_get_error(_propagator->_session))); - return true; - case NE_FAILED: /* The precondition failed */ - case NE_RETRY: /* Retry request (ne_end_request ONLY) */ - case NE_REDIRECT: /* See ne_redirect.h */ - default: - done(SyncFileItem::SoftError, QString::fromUtf8(ne_get_error(_propagator->_session))); - return true; - } - return false; -} - -void UpdateMTimeAndETagJob::start() -{ - QScopedPointer<char, QScopedPointerPodDeleter> uri( - ne_path_escape((_propagator->_remoteDir + _item._file).toUtf8())); - if (!updateMTimeAndETag(uri.data(), _item._modtime)) - return; - done(SyncFileItem::Success); -} - - - -} diff --git a/src/mirall/propagatorjobs.h b/src/mirall/propagatorjobs.h deleted file mode 100644 index df7a5e472..000000000 --- a/src/mirall/propagatorjobs.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) by Olivier Goffart <ogoffart@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 - * 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. - */ - -#pragma once - -#include "owncloudpropagator.h" -#include <httpbf.h> -#include <neon/ne_compress.h> -#include <QFile> -#include <qdebug.h> - -namespace Mirall { - -/* Helper for QScopedPointer<>, to be used as the deleter. - * QScopePointer will call the right overload of cleanup for the pointer it holds - */ -struct ScopedPointerHelpers { - static inline void cleanup(hbf_transfer_t *pointer) { if (pointer) hbf_free_transfer(pointer); } - static inline void cleanup(ne_request *pointer) { if (pointer) ne_request_destroy(pointer); } - static inline void cleanup(ne_decompress *pointer) { if (pointer) ne_decompress_destroy(pointer); } -// static inline void cleanup(ne_propfind_handler *pointer) { if (pointer) ne_propfind_destroy(pointer); } -}; - -/* - * Abstract class for neon job. Lives in the neon thread - */ -class PropagateNeonJob : public PropagateItemJob { - Q_OBJECT -protected: - - /* Issue a PROPPATCH and PROPFIND to update the mtime, and fetch the etag - * Return true in case of success, and false if the PROPFIND failed and the - * error has been reported - */ - bool updateMTimeAndETag(const char *uri, time_t); - - /* fetch the error code and string from the session - in case of error, calls done with the error and returns true. - - If the HTTP error code is ignoreHTTPError, the error is ignored - */ - bool updateErrorFromSession(int neon_code = 0, ne_request *req = 0, int ignoreHTTPError = 0); - - /* - * to be called by the progress callback and will wait the amount of time needed. - */ - void limitBandwidth(qint64 progress, qint64 limit); - - QElapsedTimer _lastTime; - qint64 _lastProgress; - int _httpStatusCode; - -public: - PropagateNeonJob(OwncloudPropagator* propagator, const SyncFileItem &item) - : PropagateItemJob(propagator, item), _lastProgress(0), _httpStatusCode(0) { - moveToThread(propagator->_neonThread); - } - -}; - -class PropagateLocalRemove : public PropagateItemJob { - Q_OBJECT -public: - PropagateLocalRemove (OwncloudPropagator* propagator,const SyncFileItem& item) : PropagateItemJob(propagator, item) {} - void start() Q_DECL_OVERRIDE; -}; -class PropagateLocalMkdir : public PropagateItemJob { - Q_OBJECT -public: - PropagateLocalMkdir (OwncloudPropagator* propagator,const SyncFileItem& item) : PropagateItemJob(propagator, item) {} - void start() Q_DECL_OVERRIDE; - -}; -class PropagateRemoteRemove : public PropagateNeonJob { - Q_OBJECT -public: - PropagateRemoteRemove (OwncloudPropagator* propagator,const SyncFileItem& item) : PropagateNeonJob(propagator, item) {} - void start() Q_DECL_OVERRIDE; -}; -class PropagateRemoteMkdir : public PropagateNeonJob { - Q_OBJECT -public: - PropagateRemoteMkdir (OwncloudPropagator* propagator,const SyncFileItem& item) : PropagateNeonJob(propagator, item) {} - void start() Q_DECL_OVERRIDE; -private: - static void propfind_results(void *userdata, const ne_uri *uri, const ne_prop_result_set *set); - friend class PropagateDirectory; // So it can access the _item; -}; -class PropagateLocalRename : public PropagateItemJob { - Q_OBJECT -public: - PropagateLocalRename (OwncloudPropagator* propagator,const SyncFileItem& item) : PropagateItemJob(propagator, item) {} - void start() Q_DECL_OVERRIDE; -}; -class PropagateRemoteRename : public PropagateNeonJob { - Q_OBJECT -public: - PropagateRemoteRename (OwncloudPropagator* propagator,const SyncFileItem& item) : PropagateNeonJob(propagator, item) {} - void start() Q_DECL_OVERRIDE; -}; - - -// To support older owncloud in the -class UpdateMTimeAndETagJob : public PropagateNeonJob{ - Q_OBJECT -public: - UpdateMTimeAndETagJob (OwncloudPropagator* propagator, const SyncFileItem& item) : PropagateNeonJob(propagator, item) {} - void start() Q_DECL_OVERRIDE; -}; - - -} diff --git a/src/mirall/protocolwidget.cpp b/src/mirall/protocolwidget.cpp deleted file mode 100644 index f15b0aba4..000000000 --- a/src/mirall/protocolwidget.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 <QtGui> -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) -#include <QtWidgets> -#endif - -#include "mirall/protocolwidget.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/syncresult.h" -#include "mirall/logger.h" -#include "mirall/utility.h" -#include "mirall/theme.h" -#include "mirall/folderman.h" -#include "mirall/syncfileitem.h" -#include "mirall/folder.h" -#include "openfilemanager.h" - -#include "ui_protocolwidget.h" - -namespace Mirall { - -ProtocolWidget::ProtocolWidget(QWidget *parent) : - QWidget(parent), - IgnoredIndicatorRole( Qt::UserRole +1 ), - _ui(new Ui::ProtocolWidget) -{ - _ui->setupUi(this); - - connect(ProgressDispatcher::instance(), SIGNAL(progressInfo(QString,Progress::Info)), - this, SLOT(slotProgressInfo(QString,Progress::Info))); - - connect(_ui->_treeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), SLOT(slotOpenFile(QTreeWidgetItem*,int))); - - // Adjust copyToClipboard() when making changes here! - QStringList header; - header << tr("Time"); - header << tr("File"); - header << tr("Folder"); - header << tr("Action"); - header << tr("Size"); - - _ui->_treeWidget->setHeaderLabels( header ); - _ui->_treeWidget->setColumnWidth(1, 180); - _ui->_treeWidget->setColumnCount(5); - _ui->_treeWidget->setRootIsDecorated(false); - _ui->_treeWidget->setTextElideMode(Qt::ElideMiddle); - _ui->_treeWidget->header()->setObjectName("ActivityListHeader"); -#if defined(Q_OS_MAC) - _ui->_treeWidget->setMinimumWidth(400); -#endif - - connect(this, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(guiLog(QString,QString))); - - _clearBlacklistBtn = _ui->_dialogButtonBox->addButton(tr("Retry Sync"), QDialogButtonBox::ActionRole); - _clearBlacklistBtn->setEnabled(false); - connect(_clearBlacklistBtn, SIGNAL(clicked()), SLOT(slotClearBlacklist())); - - QPushButton *copyBtn = _ui->_dialogButtonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole); - copyBtn->setToolTip( tr("Copy the activity list to the clipboard.")); - connect(copyBtn, SIGNAL(clicked()), SLOT(copyToClipboard())); - - MirallConfigFile cfg; - cfg.restoreGeometryHeader(_ui->_treeWidget->header()); -} - -ProtocolWidget::~ProtocolWidget() -{ - MirallConfigFile cfg; - cfg.saveGeometryHeader(_ui->_treeWidget->header() ); - - delete _ui; -} - -void ProtocolWidget::copyToClipboard() -{ - QString text; - QTextStream ts(&text); - - int topLevelItems = _ui->_treeWidget->topLevelItemCount(); - for (int i = 0; i < topLevelItems; i++) { - QTreeWidgetItem *child = _ui->_treeWidget->topLevelItem(i); - ts << left - // time stamp - << qSetFieldWidth(10) - << child->data(0,Qt::DisplayRole).toString() - // file name - << qSetFieldWidth(64) - << child->data(1,Qt::DisplayRole).toString() - // folder - << qSetFieldWidth(15) - << child->data(2, Qt::DisplayRole).toString() - // action - << qSetFieldWidth(15) - << child->data(3, Qt::DisplayRole).toString() - // size - << qSetFieldWidth(10) - << child->data(4, Qt::DisplayRole).toString() - << qSetFieldWidth(0) - << endl; - } - - QApplication::clipboard()->setText(text); - emit guiLog(tr("Copied to clipboard"), tr("The sync status has been copied to the clipboard.")); -} - -void ProtocolWidget::slotClearBlacklist() -{ - FolderMan *folderMan = FolderMan::instance(); - - Folder::Map folders = folderMan->map(); - - foreach( Folder *f, folders ) { - int num = f->slotWipeBlacklist(); - qDebug() << num << "entries were removed from"<< f->alias() << "blacklist"; - } - - folderMan->slotScheduleAllFolders(); -} - -void ProtocolWidget::cleanIgnoreItems(const QString& folder) -{ - int itemCnt = _ui->_treeWidget->topLevelItemCount(); - for( int cnt = itemCnt-1; cnt >=0 ; cnt-- ) { - QTreeWidgetItem *item = _ui->_treeWidget->topLevelItem(cnt); - bool isErrorItem = item->data(0, IgnoredIndicatorRole).toBool(); - QString itemFolder = item->data(2, Qt::DisplayRole).toString(); - if( isErrorItem && itemFolder == folder ) { - delete item; - } - } -} - -QString ProtocolWidget::timeString(QDateTime dt, QLocale::FormatType format) const -{ - QLocale loc = QLocale::system(); - QString timeStr; - QDate today = QDate::currentDate(); - - if( format == QLocale::NarrowFormat ) { - if( dt.date().day() == today.day() ) { - timeStr = loc.toString(dt.time(), QLocale::NarrowFormat); - } else { - timeStr = loc.toString(dt, QLocale::NarrowFormat); - } - } else { - timeStr = loc.toString(dt, format); - } - return timeStr; -} - -void ProtocolWidget::slotOpenFile( QTreeWidgetItem *item, int ) -{ - QString folderName = item->text(2); - QString fileName = item->text(1); - - Folder *folder = FolderMan::instance()->folder(folderName); - if (folder) { - // folder->path() always comes back with trailing path - QString fullPath = folder->path() + fileName; - if (QFile(fullPath).exists()) { - showInFileManager(fullPath); - } - } -} - -QTreeWidgetItem* ProtocolWidget::createCompletedTreewidgetItem(const QString& folder, const SyncFileItem& item) -{ - QStringList columns; - QDateTime timestamp = QDateTime::currentDateTime(); - const QString timeStr = timeString(timestamp); - const QString longTimeStr = timeString(timestamp, QLocale::LongFormat); - QIcon icon; - QString message; - - columns << timeStr; - columns << item._file; - columns << folder; - if (Progress::isWarningKind(item._status)) { - message= item._errorString; - columns << message; - if (item._status == SyncFileItem::NormalError || item._status == SyncFileItem::FatalError) { - icon = Theme::instance()->syncStateIcon(SyncResult::Error); - } else { - icon = Theme::instance()->syncStateIcon(SyncResult::Problem); - } - - } else { - message = Progress::asResultString(item); - columns << message; - if (Progress::isSizeDependent(item._instruction)) { - columns << Utility::octetsToString( item._size ); - } - } - - QTreeWidgetItem *twitem = new QTreeWidgetItem(columns); - if (item._status == SyncFileItem::FileIgnored) { - // Tell that we want to remove it on the next sync. - twitem->setData(0, IgnoredIndicatorRole, true); - } - - twitem->setIcon(0, icon); - twitem->setToolTip(0, longTimeStr); - twitem->setToolTip(1, item._file); - twitem->setToolTip(3, message ); - return twitem; -} - -void ProtocolWidget::computeResyncButtonEnabled() -{ - FolderMan *folderMan = FolderMan::instance(); - Folder::Map folders = folderMan->map(); - - int cnt = 0; - foreach( Folder *f, folders ) { - cnt += f->blackListEntryCount(); - } - - QString t = tr("Currently no files are ignored because of previous errors."); - if(cnt > 0) { - t = tr("%1 files are ignored because of previous errors.\n Try to sync these again.").arg(cnt); - } - - _clearBlacklistBtn->setEnabled(cnt > 0); - _clearBlacklistBtn->setToolTip(t); - -} - -void ProtocolWidget::slotProgressInfo( const QString& folder, const Progress::Info& progress ) -{ - if( progress._completedFileCount == 0 ) { - // The sync is restarting, clean the old items - cleanIgnoreItems(folder); - computeResyncButtonEnabled(); - } else if (progress._totalFileCount == progress._completedFileCount) { - //Sync completed - computeResyncButtonEnabled(); - } - SyncFileItem last = progress._lastCompletedItem; - if (last.isEmpty()) return; - - QTreeWidgetItem *item = createCompletedTreewidgetItem(folder, last); - if(item) { - _ui->_treeWidget->insertTopLevelItem(0, item); - } -} - - -} diff --git a/src/mirall/protocolwidget.h b/src/mirall/protocolwidget.h deleted file mode 100644 index 88e2ee722..000000000 --- a/src/mirall/protocolwidget.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 PROTOCOLWIDGET_H -#define PROTOCOLWIDGET_H - -#include <QDialog> -#include <QDateTime> -#include <QLocale> - -#include "mirall/progressdispatcher.h" - -#include "ui_protocolwidget.h" - -class QPushButton; - -namespace Mirall { -class SyncResult; - -namespace Ui { - class ProtocolWidget; -} -class Application; - -class ProtocolWidget : public QWidget -{ - Q_OBJECT -public: - explicit ProtocolWidget(QWidget *parent = 0); - ~ProtocolWidget(); - -signals: - -public slots: - void slotProgressInfo( const QString& folder, const Progress::Info& progress ); - void slotOpenFile( QTreeWidgetItem* item, int ); - -protected slots: - void copyToClipboard(); - void slotClearBlacklist(); - -signals: - void guiLog(const QString&, const QString&); - -private: - void setSyncResultStatus(const SyncResult& result ); - void cleanIgnoreItems( const QString& folder ); - void computeResyncButtonEnabled(); - - QTreeWidgetItem* createCompletedTreewidgetItem(const QString &folder, const SyncFileItem &item ); - - QString timeString(QDateTime dt, QLocale::FormatType format = QLocale::NarrowFormat) const; - - const int IgnoredIndicatorRole; - Ui::ProtocolWidget *_ui; - QPushButton *_clearBlacklistBtn; -}; - -} -#endif // PROTOCOLWIDGET_H diff --git a/src/mirall/protocolwidget.ui b/src/mirall/protocolwidget.ui deleted file mode 100644 index b1b29106f..000000000 --- a/src/mirall/protocolwidget.ui +++ /dev/null @@ -1,73 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>Mirall::ProtocolWidget</class> - <widget class="QWidget" name="Mirall::ProtocolWidget"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>612</width> - <height>515</height> - </rect> - </property> - <property name="windowTitle"> - <string>Form</string> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0"> - <widget class="QGroupBox" name="groupBox"> - <property name="title"> - <string>Sync Activity</string> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <widget class="QTreeWidget" name="_treeWidget"> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - <property name="rootIsDecorated"> - <bool>true</bool> - </property> - <property name="uniformRowHeights"> - <bool>true</bool> - </property> - <property name="columnCount"> - <number>4</number> - </property> - <column> - <property name="text"> - <string notr="true">1</string> - </property> - </column> - <column> - <property name="text"> - <string notr="true">2</string> - </property> - </column> - <column> - <property name="text"> - <string>3</string> - </property> - </column> - <column> - <property name="text"> - <string>4</string> - </property> - </column> - </widget> - </item> - <item row="1" column="0"> - <widget class="QDialogButtonBox" name="_dialogButtonBox"> - <property name="standardButtons"> - <set>QDialogButtonBox::NoButton</set> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/src/mirall/quotainfo.cpp b/src/mirall/quotainfo.cpp deleted file mode 100644 index 71fd29ccd..000000000 --- a/src/mirall/quotainfo.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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/quotainfo.h" -#include "mirall/account.h" -#include "mirall/networkjobs.h" -#include "creds/abstractcredentials.h" - -#include <QTimer> -#include <QDebug> - -namespace Mirall { - -namespace { -static const int defaultIntervalT = 30*1000; -static const int failIntervalT = 5*1000; -static const int initialTimeT = 1*1000; -} - -QuotaInfo::QuotaInfo(Account *account) - : QObject(account) - , _account(account) - , _lastQuotaTotalBytes(0) - , _lastQuotaUsedBytes(0) - , _jobRestartTimer(new QTimer(this)) -{ - connect(_account, SIGNAL(stateChanged(int)), SLOT(slotAccountStateChanged(int))); - connect(_jobRestartTimer, SIGNAL(timeout()), SLOT(slotCheckQuota())); - _jobRestartTimer->setSingleShot(true); - _jobRestartTimer->start(initialTimeT); -} - -void QuotaInfo::slotAccountChanged(Account *newAccount, Account *oldAccount) -{ - _account = newAccount; - disconnect(oldAccount, SIGNAL(stateChanged(int)), this, SLOT(slotAccountStateChanged(int))); - connect(newAccount, SIGNAL(stateChanged(int)), this, SLOT(slotAccountStateChanged(int))); -} - -void QuotaInfo::slotAccountStateChanged(int state) -{ - switch (state) { - case Account::SignedOut: // fall through - case Account::InvalidCredidential: - case Account::Disconnected: - _jobRestartTimer->stop(); - break; - case Account::Connected: // fall through - slotCheckQuota(); - } -} - -void QuotaInfo::slotRequestFailed() -{ - if (!_account.isNull() && _account->state() == Account::Connected) { - _account->setState(Account::Disconnected); - } - - _lastQuotaTotalBytes = 0; - _lastQuotaUsedBytes = 0; - _jobRestartTimer->start(failIntervalT); -} - -void QuotaInfo::slotCheckQuota() -{ - if (!_account.isNull() && _account->state() == Account::Connected - && _account->credentials() && _account->credentials()->ready()) { - CheckQuotaJob *job = new CheckQuotaJob(_account, "/", this); - connect(job, SIGNAL(quotaRetrieved(qint64,qint64)), SLOT(slotUpdateLastQuota(qint64,qint64))); - connect(job, SIGNAL(networkError(QNetworkReply*)), SLOT(slotRequestFailed())); - job->start(); - } -} - -void QuotaInfo::slotUpdateLastQuota(qint64 total, qint64 used) -{ - if(_account->state() == Account::Disconnected) { - _account->setState(Account::Connected); - } - _lastQuotaTotalBytes = total; - _lastQuotaUsedBytes = used; - emit quotaUpdated(total, used); - _jobRestartTimer->start(defaultIntervalT); -} - -} diff --git a/src/mirall/quotainfo.h b/src/mirall/quotainfo.h deleted file mode 100644 index 14ccbbf9f..000000000 --- a/src/mirall/quotainfo.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 QUOTAINFO_H -#define QUOTAINFO_H - -#include <QObject> -#include <QPointer> - -class QTimer; - -namespace Mirall { - -class Account; - -class QuotaInfo : public QObject { - Q_OBJECT -public: - QuotaInfo(Account *account); - - qint64 lastQuotaTotalBytes() const { return _lastQuotaTotalBytes; } - qint64 lastQuotaUsedBytes() const { return _lastQuotaUsedBytes; } - -public Q_SLOTS: - void slotUpdateLastQuota(qint64 total, qint64 used); - void slotCheckQuota(); - -private Q_SLOTS: - void slotAccountChanged(Account *newAccount, Account *oldAccount); - void slotAccountStateChanged(int state); - void slotRequestFailed(); - -Q_SIGNALS: - void quotaUpdated(qint64 total, qint64 used); - -private: - QPointer<Account> _account; - qint64 _lastQuotaTotalBytes; - qint64 _lastQuotaUsedBytes; - QTimer *_jobRestartTimer; -}; - - - -} // namespace Mirall - -#endif //QUOTAINFO_H diff --git a/src/mirall/settingsdialog.cpp b/src/mirall/settingsdialog.cpp deleted file mode 100644 index ff44af869..000000000 --- a/src/mirall/settingsdialog.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 "settingsdialog.h" -#include "ui_settingsdialog.h" - -#include "mirall/folderman.h" -#include "mirall/theme.h" -#include "mirall/generalsettings.h" -#include "mirall/networksettings.h" -#include "mirall/accountsettings.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/progressdispatcher.h" -#include "mirall/owncloudgui.h" -#include "mirall/protocolwidget.h" - -#include <QLabel> -#include <QStandardItemModel> -#include <QPushButton> -#include <QDebug> -#include <QSettings> - -namespace Mirall { - -QIcon createDummy() { - QIcon icon; - QPixmap p(32,32); - p.fill(Qt::transparent); - icon.addPixmap(p); - return icon; -} - -SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent) : - QDialog(parent), - _ui(new Ui::SettingsDialog) -{ - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - _ui->setupUi(this); - setObjectName("Settings"); // required as group for saveGeometry call - - setWindowTitle(tr("%1").arg(Theme::instance()->appNameGUI())); - - _accountSettings = new AccountSettings(this); - addAccount(tr("Account"), _accountSettings); - - QIcon protocolIcon(QLatin1String(":/mirall/resources/activity.png")); - QListWidgetItem *protocol= new QListWidgetItem(protocolIcon, tr("Activity"), _ui->labelWidget); - protocol->setSizeHint(QSize(0, 32)); - _ui->labelWidget->addItem(protocol); - _protocolWidget = new ProtocolWidget; - _protocolIdx = _ui->stack->addWidget(_protocolWidget); - - QIcon generalIcon(QLatin1String(":/mirall/resources/settings.png")); - QListWidgetItem *general = new QListWidgetItem(generalIcon, tr("General"), _ui->labelWidget); - general->setSizeHint(QSize(0, 32)); - _ui->labelWidget->addItem(general); - GeneralSettings *generalSettings = new GeneralSettings; - _ui->stack->addWidget(generalSettings); - - QIcon networkIcon(QLatin1String(":/mirall/resources/network.png")); - QListWidgetItem *network = new QListWidgetItem(networkIcon, tr("Network"), _ui->labelWidget); - network->setSizeHint(QSize(0, 32)); - _ui->labelWidget->addItem(network); - NetworkSettings *networkSettings = new NetworkSettings; - _ui->stack->addWidget(networkSettings); - - FolderMan *folderMan = FolderMan::instance(); - connect( folderMan, SIGNAL(folderSyncStateChange(QString)), - this, SLOT(slotSyncStateChange(QString))); - - connect( _accountSettings, SIGNAL(folderChanged()), gui, SLOT(slotFoldersChanged())); - connect( _accountSettings, SIGNAL(openFolderAlias(const QString&)), - gui, SLOT(slotFolderOpenAction(QString))); - - connect( ProgressDispatcher::instance(), SIGNAL(progressInfo(QString, Progress::Info)), - _accountSettings, SLOT(slotSetProgress(QString, Progress::Info)) ); - - _ui->labelWidget->setCurrentRow(_ui->labelWidget->row(_accountItem)); - - connect(_ui->labelWidget, SIGNAL(currentRowChanged(int)), - _ui->stack, SLOT(setCurrentIndex(int))); - - QPushButton *closeButton = _ui->buttonBox->button(QDialogButtonBox::Close); - connect(closeButton, SIGNAL(clicked()), SLOT(accept())); - - QAction *showLogWindow = new QAction(this); - showLogWindow->setShortcut(QKeySequence("F12")); - connect(showLogWindow, SIGNAL(triggered()), gui, SLOT(slotToggleLogBrowser())); - addAction(showLogWindow); - - int iconSize = 32; - QListWidget *listWidget = _ui->labelWidget; - int spacing = 20; - // reverse at least ~8 characters - int effectiveWidth = fontMetrics().averageCharWidth() * 8 + iconSize + spacing; - // less than ~16 characters, elide otherwise - int maxWidth = fontMetrics().averageCharWidth() * 16 + iconSize + spacing; - for (int i = 0; i < listWidget->count(); i++) { - QListWidgetItem *item = listWidget->item(i); - QFontMetrics fm(item->font()); - int curWidth = fm.width(item->text()) + iconSize + spacing; - effectiveWidth = qMax(curWidth, effectiveWidth); - if (curWidth > maxWidth) item->setToolTip(item->text()); - } - effectiveWidth = qMin(effectiveWidth, maxWidth); - listWidget->setFixedWidth(effectiveWidth); - - MirallConfigFile cfg; - cfg.restoreGeometry(this); -} - -SettingsDialog::~SettingsDialog() -{ - delete _ui; -} - -void SettingsDialog::addAccount(const QString &title, QWidget *widget) -{ - _accountItem = new QListWidgetItem(title); - _accountItem->setSizeHint(QSize(0, 32)); - _ui->labelWidget->addItem(_accountItem); - _ui->stack->addWidget(widget); - slotSyncStateChange(); - -} - -void SettingsDialog::slotSyncStateChange(const QString& alias) -{ - FolderMan *folderMan = FolderMan::instance(); - SyncResult state = folderMan->accountStatus(folderMan->map().values()); - _accountItem->setIcon(Theme::instance()->syncStateIcon(state.status())); - - if (!alias.isEmpty()) { - Folder *folder = folderMan->folder(alias); - if( folder ) { - _accountSettings->slotUpdateFolderState(folder); - } - } -} - -void SettingsDialog::setGeneralErrors(const QStringList &errors) -{ - if( _accountSettings ) { - _accountSettings->setGeneralErrors(errors); - } -} - -// close event is not being called here -void SettingsDialog::reject() { - MirallConfigFile cfg; - cfg.saveGeometry(this); - QDialog::reject(); -} - -void SettingsDialog::accept() { - MirallConfigFile cfg; - cfg.saveGeometry(this); - QDialog::accept(); -} - -void SettingsDialog::showActivityPage() -{ - _ui->labelWidget->setCurrentRow(_protocolIdx); -} - - -} // namespace Mirall diff --git a/src/mirall/settingsdialog.h b/src/mirall/settingsdialog.h deleted file mode 100644 index fe82e77e5..000000000 --- a/src/mirall/settingsdialog.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 SETTINGSDIALOG_H -#define SETTINGSDIALOG_H - -#include <QDialog> -#include <QStyledItemDelegate> - -#include "mirall/progressdispatcher.h" - -class QStandardItemModel; -class QListWidgetItem; - -namespace Mirall { - -namespace Ui { -class SettingsDialog; -} -class AccountSettings; -class ProtocolWidget; -class Application; -class FolderMan; -class ownCloudGui; - -class SettingsDialog : public QDialog -{ - Q_OBJECT - -public: - explicit SettingsDialog(ownCloudGui *gui, QWidget *parent = 0); - ~SettingsDialog(); - - void addAccount(const QString &title, QWidget *widget); - void setGeneralErrors( const QStringList& errors ); - -public slots: - void slotSyncStateChange(const QString& alias = QString()); - void showActivityPage(); - -protected: - void reject() Q_DECL_OVERRIDE; - void accept() Q_DECL_OVERRIDE; - -private: - Ui::SettingsDialog *_ui; - AccountSettings *_accountSettings; - QListWidgetItem *_accountItem; - ProtocolWidget *_protocolWidget; - - int _protocolIdx; -}; - -} - -#endif // SETTINGSDIALOG_H diff --git a/src/mirall/settingsdialog.ui b/src/mirall/settingsdialog.ui deleted file mode 100644 index 0f58d33f4..000000000 --- a/src/mirall/settingsdialog.ui +++ /dev/null @@ -1,62 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>Mirall::SettingsDialog</class> - <widget class="QDialog" name="Mirall::SettingsDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>693</width> - <height>457</height> - </rect> - </property> - <property name="windowTitle"> - <string>Settings</string> - </property> - <layout class="QGridLayout" name="gridLayout"> - <property name="margin"> - <number>0</number> - </property> - <property name="spacing"> - <number>0</number> - </property> - <item row="0" column="0" rowspan="2"> - <widget class="QListWidget" name="labelWidget"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QStackedWidget" name="stack"/> - </item> - <item row="1" column="1"> - <widget class="QWidget" name="widget" native="true"> - <layout class="QVBoxLayout" name="verticalLayout"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <item> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="standardButtons"> - <set>QDialogButtonBox::Close</set> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/src/mirall/settingsdialogmac.cpp b/src/mirall/settingsdialogmac.cpp deleted file mode 100644 index 23466c6b9..000000000 --- a/src/mirall/settingsdialogmac.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "settingsdialogmac.h" - -#include "macstandardicon.h" - -#include "mirall/folderman.h" -#include "mirall/theme.h" -#include "mirall/generalsettings.h" -#include "mirall/networksettings.h" -#include "mirall/accountsettings.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/progressdispatcher.h" -#include "mirall/owncloudgui.h" -#include "mirall/protocolwidget.h" - -#include <QLabel> -#include <QStandardItemModel> -#include <QPushButton> -#include <QDebug> -#include <QSettings> - -namespace Mirall { - -SettingsDialogMac::SettingsDialogMac(ownCloudGui *gui, QWidget *parent) - : MacPreferencesWindow(parent) -{ - // do not show minimize button. There is no use, and retoring the - // dialog from minimize is broken in MacPreferencesWindow - setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint | - Qt::WindowCloseButtonHint | Qt::WindowMaximizeButtonHint); - - - // Emulate dialog behavior: Escape means close - QAction *closeWindowAction = new QAction(this); - closeWindowAction->setShortcut(QKeySequence(Qt::Key_Escape)); - connect(closeWindowAction, SIGNAL(triggered()), SLOT(close())); - addAction(closeWindowAction); - - setObjectName("SettingsMac"); // required as group for saveGeometry call - - setWindowTitle(tr("%1").arg(Theme::instance()->appNameGUI())); - - _accountSettings = new AccountSettings; - QIcon icon = Theme::instance()->syncStateIcon(SyncResult::Undefined, true); - _accountIdx = addPreferencesPanel(icon, tr("Account"), _accountSettings); - - QIcon protocolIcon(QLatin1String(":/mirall/resources/activity.png")); - _protocolWidget = new ProtocolWidget; - _protocolIdx = addPreferencesPanel(protocolIcon, tr("Activity"), _protocolWidget); - - QIcon generalIcon = MacStandardIcon::icon(MacStandardIcon::PreferencesGeneral); - GeneralSettings *generalSettings = new GeneralSettings; - addPreferencesPanel(generalIcon, tr("General"), generalSettings); - - QIcon networkIcon = MacStandardIcon::icon(MacStandardIcon::Network); - NetworkSettings *networkSettings = new NetworkSettings; - addPreferencesPanel(networkIcon, tr("Network"), networkSettings); - - FolderMan *folderMan = FolderMan::instance(); - connect( folderMan, SIGNAL(folderSyncStateChange(QString)), - this, SLOT(slotSyncStateChange(QString))); - - connect( ProgressDispatcher::instance(), SIGNAL(progressInfo(QString, Progress::Info)), - _accountSettings, SLOT(slotSetProgress(QString, Progress::Info)) ); - - QAction *showLogWindow = new QAction(this); - showLogWindow->setShortcut(QKeySequence("F12")); - connect(showLogWindow, SIGNAL(triggered()), gui, SLOT(slotToggleLogBrowser())); - addAction(showLogWindow); - - MirallConfigFile cfg; - cfg.restoreGeometry(this); -} - -void SettingsDialogMac::slotSyncStateChange(const QString& alias) -{ - FolderMan *folderMan = FolderMan::instance(); - SyncResult state = folderMan->accountStatus(folderMan->map().values()); - QIcon accountIcon = Theme::instance()->syncStateIcon(state.status()); - setPreferencesPanelIcon(_accountIdx, accountIcon); - - Folder *folder = folderMan->folder(alias); - if( folder ) { - _accountSettings->slotUpdateFolderState(folder); - } -} - -void SettingsDialogMac::setGeneralErrors(const QStringList &errors) -{ - if( _accountSettings ) { - _accountSettings->setGeneralErrors(errors); - } -} - -void SettingsDialogMac::closeEvent(QCloseEvent *event) -{ - MirallConfigFile cfg; - cfg.saveGeometry(this); - MacPreferencesWindow::closeEvent(event); -} - -void SettingsDialogMac::showActivityPage() -{ - setCurrentPanelIndex(_protocolIdx); -} - -} diff --git a/src/mirall/settingsdialogmac.h b/src/mirall/settingsdialogmac.h deleted file mode 100644 index c44fbc9de..000000000 --- a/src/mirall/settingsdialogmac.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef SETTINGSDIALOGMAC_H -#define SETTINGSDIALOGMAC_H - -#include "mirall/progressdispatcher.h" -#include "macpreferenceswindow.h" - -class QStandardItemModel; -class QListWidgetItem; - -namespace Mirall { - -class AccountSettings; -class ProtocolWidget; -class Application; -class FolderMan; -class ownCloudGui; - -class SettingsDialogMac : public MacPreferencesWindow -{ - Q_OBJECT - -public: - explicit SettingsDialogMac(ownCloudGui *gui, QWidget *parent = 0); - - void setGeneralErrors( const QStringList& errors ); - -public slots: - void slotSyncStateChange(const QString& alias); - void showActivityPage(); - -private: - void closeEvent(QCloseEvent *event); - - AccountSettings *_accountSettings; - QListWidgetItem *_accountItem; - ProtocolWidget *_protocolWidget; - - int _accountIdx; - int _protocolIdx; -}; - -} - -#endif // SETTINGSDIALOGMAC_H diff --git a/src/mirall/socketapi.cpp b/src/mirall/socketapi.cpp deleted file mode 100644 index 8a0b7c629..000000000 --- a/src/mirall/socketapi.cpp +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright (C) by Dominik Schmidt <dev@dominik-schmidt.de> - * - * 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/socketapi.h" - -#include "mirall/mirallconfigfile.h" -#include "mirall/folderman.h" -#include "mirall/folder.h" -#include "mirall/utility.h" -#include "mirall/theme.h" -#include "mirall/syncjournalfilerecord.h" -#include "mirall/syncfileitem.h" - -#include <QDebug> -#include <QUrl> -#include <QMetaObject> -#include <QStringList> -#include <QScopedPointer> -#include <QFile> -#include <QDir> -#include <QApplication> - -extern "C" { - -enum csync_exclude_type_e { - CSYNC_NOT_EXCLUDED = 0, - CSYNC_FILE_SILENTLY_EXCLUDED, - CSYNC_FILE_EXCLUDE_AND_REMOVE, - CSYNC_FILE_EXCLUDE_LIST, - CSYNC_FILE_EXCLUDE_INVALID_CHAR -}; -typedef enum csync_exclude_type_e CSYNC_EXCLUDE_TYPE; - -CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype); - -} - -namespace Mirall { - -#define DEBUG qDebug() << "SocketApi: " - -namespace SocketApiHelper { - -SyncFileStatus fileStatus(Folder *folder, const QString& fileName ); - -/** - * @brief recursiveFolderStatus - * @param fileName - the relative file name to examine - * @return the resulting status - * - * The resulting status can only be either SYNC which means all files - * are in sync, ERROR if an error occured, or EVAL if something needs - * to be synced underneath this dir. - */ -// compute the file status of a directory recursively. It returns either -// "all in sync" or "needs update" or "error", no more details. -SyncFileStatus recursiveFolderStatus(Folder *folder, const QString& fileName ) -{ - QDir dir(folder->path() + fileName); - - const QStringList dirEntries = dir.entryList( QDir::AllEntries | QDir::NoDotAndDotDot ); - - SyncFileStatus result(SyncFileStatus::STATUS_SYNC); - - foreach( const QString entry, dirEntries ) { - QFileInfo fi(entry); - SyncFileStatus sfs; - if( fi.isDir() ) { - sfs = recursiveFolderStatus(folder, fileName + QLatin1Char('/') + entry ); - } else { - QString fs( fileName + QLatin1Char('/') + entry ); - if( fileName.isEmpty() ) { - // toplevel, no slash etc. needed. - fs = entry; - } - sfs = fileStatus(folder, fs ); - } - - if( sfs.tag() == SyncFileStatus::STATUS_STAT_ERROR || sfs.tag() == SyncFileStatus::STATUS_ERROR ) { - return SyncFileStatus::STATUS_ERROR; - } else if( sfs.tag() == SyncFileStatus::STATUS_EVAL || sfs.tag() == SyncFileStatus::STATUS_NEW) { - result.set(SyncFileStatus::STATUS_EVAL); - } - } - return result; -} - -/** - * Get status about a single file. - */ -SyncFileStatus fileStatus(Folder *folder, const QString& fileName ) -{ - // FIXME: Find a way for STATUS_ERROR - - QString file = fileName; - if( folder->path() != QLatin1String("/") ) { - file = folder->path() + fileName; - } - - QFileInfo fi(file); - - if( !fi.exists() ) { - return SyncFileStatus(SyncFileStatus::STATUS_STAT_ERROR); - } - - // file is ignored? - if( fi.isSymLink() ) { - return SyncFileStatus(SyncFileStatus::STATUS_IGNORE); - } - int type = CSYNC_FTW_TYPE_FILE; - if( fi.isDir() ) { - type = CSYNC_FTW_TYPE_DIR; - } - - CSYNC_EXCLUDE_TYPE excl = csync_excluded(folder->csyncContext(), file.toUtf8(), type); - if( excl != CSYNC_NOT_EXCLUDED ) { - return SyncFileStatus(SyncFileStatus::STATUS_IGNORE); - } - - SyncJournalFileRecord rec = folder->journalDb()->getFileRecord(fileName); - if( !rec.isValid() ) { - return SyncFileStatus(SyncFileStatus::STATUS_NEW); - } - - SyncFileStatus stat(SyncFileStatus::STATUS_NONE); - if( type == CSYNC_FTW_TYPE_DIR ) { - // compute recursive status of the directory - stat = recursiveFolderStatus( folder, fileName ); - } else if(fi.lastModified() != rec._modtime ) { - // file was locally modified. - stat.set(SyncFileStatus::STATUS_EVAL); - } else { - stat.set(SyncFileStatus::STATUS_SYNC); - } - - if (rec._remotePerm.contains("S")) { - // FIXME! that should be an additional flag - stat.setSharedWithMe(true); - } - - return stat; -} - - -} - - -SocketApi::SocketApi(QObject* parent, const QUrl& localFile) - : QObject(parent) - , _localServer(0) -{ - QString socketPath; - if (Utility::isWindows()) { - socketPath = QLatin1String("\\\\.\\pipe\\") - + Theme::instance()->appName(); - } else { - socketPath = localFile.toLocalFile(); - - } - - // setup socket - _localServer = new QTcpServer(this); - _localServer->listen( QHostAddress::LocalHost, 33001); - connect(_localServer, SIGNAL(newConnection()), this, SLOT(slotNewConnection())); - - // folder watcher - connect(FolderMan::instance(), SIGNAL(folderSyncStateChange(QString)), SLOT(slotSyncStateChanged(QString))); - connect(ProgressDispatcher::instance(), SIGNAL(jobCompleted(QString,SyncFileItem)), SLOT(slotJobCompleted(QString,SyncFileItem))); -} - -SocketApi::~SocketApi() -{ - DEBUG << "dtor"; - _localServer->close(); -} - -void SocketApi::slotNewConnection() -{ - QTcpSocket* socket = _localServer->nextPendingConnection(); - - if( ! socket ) { - return; - } - DEBUG << "New connection " << socket; - connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadSocket())); - connect(socket, SIGNAL(disconnected()), this, SLOT(onLostConnection())); - Q_ASSERT(socket->readAll().isEmpty()); - - _listeners.append(socket); -} - -void SocketApi::onLostConnection() -{ - DEBUG << "Lost connection " << sender(); - - QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender()); - _listeners.removeAll(socket); -} - - -void SocketApi::slotReadSocket() -{ - QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender()); - Q_ASSERT(socket); - - while(socket->canReadLine()) { - QString line = QString::fromUtf8(socket->readLine()).trimmed(); - QString command = line.split(":").first(); - QString function = QString(QLatin1String("command_")).append(command); - - QString functionWithArguments = function + QLatin1String("(QString,QTcpSocket*)"); - int indexOfMethod = this->metaObject()->indexOfMethod(functionWithArguments.toAscii()); - - QString argument = line.remove(0, command.length()+1).trimmed(); - if(indexOfMethod != -1) { - QMetaObject::invokeMethod(this, function.toAscii(), Q_ARG(QString, argument), Q_ARG(QTcpSocket*, socket)); - } else { - DEBUG << "The command is not supported by this version of the client:" << command << "with argument:" << argument; - } - } -} - -void SocketApi::slotSyncStateChanged(const QString&) -{ - broadcastMessage("UPDATE_VIEW"); -} - -void SocketApi::slotJobCompleted(const QString &folder, const SyncFileItem &item) -{ - Folder *f = FolderMan::instance()->folder(folder); - if (!f) - return; - - const QString path = f->path() + item.destination(); - - QString command = QLatin1String("OK"); - if (Progress::isWarningKind(item._status)) { - command = QLatin1String("ERROR"); - } - - broadcastMessage(QLatin1String("BROADCAST:") + command + QLatin1Char(':') + path); -} - - - -void SocketApi::sendMessage(QTcpSocket *socket, const QString& message) -{ - DEBUG << "Sending message: " << message; - QString localMessage = message; - socket->write(localMessage.append("\n").toUtf8()); -} - -void SocketApi::broadcastMessage(const QString& message) -{ - DEBUG << "Broadcasting to" << _listeners.count() << "listeners: " << message; - foreach(QTcpSocket* current, _listeners) { - sendMessage(current, message); - } -} - -void SocketApi::command_RETRIEVE_FOLDER_STATUS(const QString& argument, QTcpSocket* socket) -{ - // This command is the same as RETRIEVE_FILE_STATUS - - qDebug() << Q_FUNC_INFO << argument; - command_RETRIEVE_FILE_STATUS(argument, socket); -} - -void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, QTcpSocket* socket) -{ - if( !socket ) { - qDebug() << "No valid socket object."; - return; - } - - qDebug() << Q_FUNC_INFO << argument; - - QString statusString; - - Folder* syncFolder = FolderMan::instance()->folderForPath( argument ); - if (!syncFolder) { - // this can happen in offline mode e.g.: nothing to worry about - DEBUG << "folder offline or not watched:" << argument; - statusString = QLatin1String("NOP"); - } else { - const QString file = argument.mid(syncFolder->path().length()); - SyncFileStatus fileStatus = SocketApiHelper::fileStatus(syncFolder, file); - - statusString = fileStatus.toSocketAPIString(); - } - - QString message = QLatin1String("STATUS:")+statusString+QLatin1Char(':')+argument; - sendMessage(socket, message); -} - -} // namespace Mirall diff --git a/src/mirall/socketapi.h b/src/mirall/socketapi.h deleted file mode 100644 index 6bf28bbf0..000000000 --- a/src/mirall/socketapi.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) by Dominik Schmidt <dev@dominik-schmidt.de> - * - * 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 SOCKETAPI_H -#define SOCKETAPI_H - -#include <QWeakPointer> -#include <QTcpSocket> -#include <QTcpServer> - -#include "mirall/syncfileitem.h" - -class QUrl; -class QLocalSocket; -class QStringList; - -namespace Mirall { - -class SocketApi : public QObject -{ -Q_OBJECT - -public: - SocketApi(QObject* parent, const QUrl& localFile); - virtual ~SocketApi(); - -private slots: - void slotNewConnection(); - void onLostConnection(); - void slotReadSocket(); - void slotSyncStateChanged(const QString&); - void slotJobCompleted(const QString &, const SyncFileItem &); - -private: - void sendMessage(QTcpSocket* socket, const QString& message); - void broadcastMessage(const QString& message); - - Q_INVOKABLE void command_RETRIEVE_FOLDER_STATUS(const QString& argument, QTcpSocket* socket); - Q_INVOKABLE void command_RETRIEVE_FILE_STATUS(const QString& argument, QTcpSocket* socket); - -private: - QTcpServer *_localServer; - QList<QTcpSocket*> _listeners; -}; - -} -#endif // SOCKETAPI_H diff --git a/src/mirall/sslbutton.cpp b/src/mirall/sslbutton.cpp deleted file mode 100644 index e103b36bf..000000000 --- a/src/mirall/sslbutton.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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/sslbutton.h" -#include "mirall/account.h" -#include "mirall/utility.h" - -#include <QMenu> -#include <QUrl> -#include <QtNetwork> -#include <QSslConfiguration> -#include <QWidgetAction> -#include <QLabel> - -namespace Mirall { - -SslButton::SslButton(QWidget *parent) : - QToolButton(parent) -{ - setPopupMode(QToolButton::InstantPopup); - setAutoRaise(true); -} - -QString SslButton::protoToString(QSsl::SslProtocol proto) -{ - switch(proto) { - break; - case QSsl::SslV2: - return QLatin1String("SSL v2"); - case QSsl::SslV3: - return QLatin1String("SSL v3"); - case QSsl::TlsV1: - return QLatin1String("TLS"); - default: - return QString(); - } -} - -static QString addCertDetailsField(const QString &key, const QString &value) -{ - if (value.isEmpty()) - return QString(); - - return QString::fromLatin1("<tr><td style=\"vertical-align: top;\"><b>%1</b></td><td style=\"vertical-align: bottom;\">%2</td></tr>").arg(key).arg(value); -} - - -// necessary indication only, not sufficient for primary validation! -static bool isSelfSigned(const QSslCertificate &certificate) -{ - return certificate.issuerInfo(QSslCertificate::CommonName) == certificate.subjectInfo(QSslCertificate::CommonName) && - certificate.issuerInfo(QSslCertificate::OrganizationalUnitName) == certificate.subjectInfo(QSslCertificate::OrganizationalUnitName); -} - -QMenu* SslButton::buildCertMenu(QMenu *parent, const QSslCertificate& cert, - const QList<QSslCertificate>& userApproved, int pos) -{ - QString cn = QStringList(cert.subjectInfo(QSslCertificate::CommonName)).join(QChar(';')); - QString ou = QStringList(cert.subjectInfo(QSslCertificate::OrganizationalUnitName)).join(QChar(';')); - QString org = QStringList(cert.subjectInfo(QSslCertificate::Organization)).join(QChar(';')); - QString country = QStringList(cert.subjectInfo(QSslCertificate::CountryName)).join(QChar(';')); - QString state = QStringList(cert.subjectInfo(QSslCertificate::StateOrProvinceName)).join(QChar(';')); - QString issuer = QStringList(cert.issuerInfo(QSslCertificate::CommonName)).join(QChar(';')); - if (issuer.isEmpty()) - issuer = QStringList(cert.issuerInfo(QSslCertificate::OrganizationalUnitName)).join(QChar(';')); - QString sha1 = Utility::formatFingerprint(cert.digest(QCryptographicHash::Sha1).toHex(), false); -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - QString md5 = Utility::formatFingerprint(cert.digest(QCryptographicHash::Md5).toHex(), false); -#else - QByteArray sha265hash = cert.digest(QCryptographicHash::Sha256).toHex(); - QString sha256escaped = - Utility::escape(Utility::formatFingerprint(sha265hash.left(sha265hash.length()/2), false)) + - QLatin1String("<br/>") + - Utility::escape(Utility::formatFingerprint(sha265hash.mid(sha265hash.length()/2), false)); -#endif - QString serial = QString::fromUtf8(cert.serialNumber()); - QString effectiveDate = cert.effectiveDate().date().toString(); - QString expiryDate = cert.expiryDate().date().toString(); - QString sna = QStringList(cert.alternateSubjectNames().values()).join(" "); - - QString details; - QTextStream stream(&details); - - stream << QLatin1String("<html><body>"); - - stream << tr("<h3>Certificate Details</h3>"); - - stream << QLatin1String("<table>"); - stream << addCertDetailsField(tr("Common Name (CN):"), Utility::escape(cn)); - stream << addCertDetailsField(tr("Subject Alternative Names:"), Utility::escape(sna) - .replace(" ", "<br/>")); - stream << addCertDetailsField(tr("Organization (O):"), Utility::escape(org)); - stream << addCertDetailsField(tr("Organizational Unit (OU):"), Utility::escape(ou)); - stream << addCertDetailsField(tr("State/Province:"), Utility::escape(state)); - stream << addCertDetailsField(tr("Country:"), Utility::escape(country)); - stream << addCertDetailsField(tr("Serial:"), Utility::escape(serial)); - stream << QLatin1String("</table>"); - - stream << tr("<h3>Issuer</h3>"); - - stream << QLatin1String("<table>"); - stream << addCertDetailsField(tr("Issuer:"), Utility::escape(issuer)); - stream << addCertDetailsField(tr("Issued on:"), Utility::escape(effectiveDate)); - stream << addCertDetailsField(tr("Expires on:"), Utility::escape(expiryDate)); - stream << QLatin1String("</table>"); - - stream << tr("<h3>Fingerprints</h3>"); - - stream << QLatin1String("<table>"); -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - stream << addCertDetailsField(tr("MD 5:"), Utility::escape(md5)); -#else - stream << addCertDetailsField(tr("SHA-256:"), sha256escaped); -#endif - stream << addCertDetailsField(tr("SHA-1:"), Utility::escape(sha1)); - stream << QLatin1String("</table>"); - - if (userApproved.contains(cert)) { - stream << tr("<p><b>Note:</b> This certificate was manually approved</p>"); - } - stream << QLatin1String("</body></html>"); - - QString txt; - if (pos > 0) { - txt += QString(2*pos, ' '); - if (!Utility::isWindows()) { - // doesn't seem to work reliably on Windows - txt += QChar(0x21AA); // nicer '->' symbol - txt += QChar(' '); - } - } - - QString certId = cn.isEmpty() ? ou : cn; - - if (QSslSocket::systemCaCertificates().contains(cert)) { - txt += certId; - } else { - if (isSelfSigned(cert)) { - txt += tr("%1 (self-signed)").arg(certId); - } else { - txt += tr("%1").arg(certId); - } - } - - // create label first - QLabel *label = new QLabel(parent); - label->setStyleSheet(QLatin1String("QLabel { padding: 8px; background-color: #fff; }")); - label->setText(details); - // plug label into widget action - QWidgetAction *action = new QWidgetAction(parent); - action->setDefaultWidget(label); - // plug action into menu - QMenu *menu = new QMenu(parent); - menu->menuAction()->setText(txt); - menu->addAction(action); - - return menu; - -} - -void SslButton::updateAccountInfo(Account *account) -{ - if (!account || account->state() != Account::Connected) { - setVisible(false); - return; - } else { - setVisible(true); - } - if (account->url().scheme() == QLatin1String("https")) { - setIcon(QIcon(QPixmap(":/mirall/resources/lock-https.png"))); - QSslCipher cipher = account->sslConfiguration().sessionCipher(); - setToolTip(tr("This connection is encrypted using %1 bit %2.\n").arg(cipher.usedBits()).arg(cipher.name())); - QMenu *menu = new QMenu(this); - QList<QSslCertificate> chain = account->sslConfiguration().peerCertificateChain(); - menu->addAction(tr("Certificate information:"))->setEnabled(false); - - QList<QSslCertificate> tmpChain; - foreach(QSslCertificate cert, chain) { - tmpChain << cert; - if (QSslSocket::systemCaCertificates().contains(cert)) - break; - } - chain = tmpChain; - - // find trust anchor (informational only, verification is done by QSslSocket!) - foreach(QSslCertificate rootCA, QSslSocket::systemCaCertificates()) { - if (rootCA.issuerInfo(QSslCertificate::CommonName) == chain.last().issuerInfo(QSslCertificate::CommonName) && - rootCA.issuerInfo(QSslCertificate::Organization) == chain.last().issuerInfo(QSslCertificate::Organization)) { - chain.append(rootCA); - break; - } - } - - QListIterator<QSslCertificate> it(chain); - it.toBack(); - int i = 0; - while (it.hasPrevious()) { - menu->addMenu(buildCertMenu(menu, it.previous(), account->approvedCerts(), i)); - i++; - } - setMenu(menu); - } else { - setIcon(QIcon(QPixmap(":/mirall/resources/lock-http.png"))); - setToolTip(tr("This connection is NOT secure as it is not encrypted.\n")); - setMenu(0); - } -} - -} // namespace Mirall diff --git a/src/mirall/sslbutton.h b/src/mirall/sslbutton.h deleted file mode 100644 index 65bfe7fb0..000000000 --- a/src/mirall/sslbutton.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 SSLBUTTON_H -#define SSLBUTTON_H - -#include <QToolButton> -#include <QPointer> -#include <QSsl> - -class QAction; -class QSslCertificate; -class QSslConfiguration; - -namespace Mirall { - -class Account; - -class SslButton : public QToolButton -{ - Q_OBJECT -public: - explicit SslButton(QWidget *parent = 0); - QString protoToString(QSsl::SslProtocol proto); - void updateAccountInfo(Account *account); - -private: - QMenu* buildCertMenu(QMenu *parent, const QSslCertificate& cert, - const QList<QSslCertificate>& userApproved, int pos); -}; - -} // namespace Mirall - -#endif // SSLBUTTON_H diff --git a/src/mirall/sslerrordialog.cpp b/src/mirall/sslerrordialog.cpp deleted file mode 100644 index 2193ed3c6..000000000 --- a/src/mirall/sslerrordialog.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (C) by Klaas Freitag <freitag@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. - */ -#include "mirall/mirallconfigfile.h" -#include "mirall/utility.h" -#include "mirall/sslerrordialog.h" - -#include <QtGui> -#include <QtNetwork> -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) -#include <QtWidgets> -#endif - - -#include "ui_sslerrordialog.h" - -namespace Mirall -{ - -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) -namespace Utility { - // Used for QSSLCertificate::subjectInfo which returns a QStringList in Qt5, but a QString in Qt4 - QString escape(const QStringList &l) { return escape(l.join(';')); } -} -#endif - -bool SslDialogErrorHandler::handleErrors(QList<QSslError> errors, QList<QSslCertificate> *certs, Account *account) -{ - if (!certs) { - qDebug() << "Certs parameter required but is NULL!"; - return false; - } - - SslErrorDialog dlg(account); - // whether the failing certs have previously been accepted - if (dlg.checkFailingCertsKnown(errors)) { - *certs = dlg.unknownCerts(); - return true; - } - // whether the user accepted the certs - if (dlg.exec() == QDialog::Accepted) { - if (dlg.trustConnection()) { - *certs = dlg.unknownCerts(); - return true; - } - } - return false; -} - -SslErrorDialog::SslErrorDialog(Account *account, QWidget *parent) : - QDialog(parent), _allTrusted(false), _ui(new Ui::SslErrorDialog), _account(account) -{ - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - _ui->setupUi( this ); - setWindowTitle( tr("SSL Connection") ); - QPushButton *okButton = - _ui->_dialogButtonBox->button( QDialogButtonBox::Ok ); - QPushButton *cancelButton = - _ui->_dialogButtonBox->button( QDialogButtonBox::Cancel ); - okButton->setEnabled(false); - connect(_ui->_cbTrustConnect, SIGNAL(clicked(bool)), - okButton, SLOT(setEnabled(bool))); - - if( okButton ) { - okButton->setDefault(true); - connect( okButton, SIGNAL(clicked()),SLOT(accept())); - connect( cancelButton, SIGNAL(clicked()),SLOT(reject())); - } -} - -SslErrorDialog::~SslErrorDialog() -{ - delete _ui; -} - - -QString SslErrorDialog::styleSheet() const -{ - const QString style = QLatin1String( - "#cert {margin-left: 5px;} " - "#ca_error { color:#a00011; margin-left:5px; margin-right:5px; }" - "#ca_error p { margin-top: 2px; margin-bottom:2px; }" - "#ccert { margin-left: 5px; }" - "#issuer { margin-left: 5px; }" - "tt { font-size: small; }" - ); - - return style; -} -#define QL(x) QLatin1String(x) - -bool SslErrorDialog::checkFailingCertsKnown( const QList<QSslError> &errors ) -{ - // check if unknown certs caused errors. - _unknownCerts.clear(); - - QStringList errorStrings; - - QList<QSslCertificate> trustedCerts = _account->approvedCerts(); - - for (int i = 0; i < errors.count(); ++i) { - QSslError error = errors.at(i); - if (trustedCerts.contains(error.certificate()) || - _unknownCerts.contains(error.certificate() )) { - continue; - } - errorStrings += error.errorString(); - if (!error.certificate().isNull()) { - _unknownCerts.append(error.certificate()); - } - } - - // if there are no errors left, all Certs were known. - if (errorStrings.isEmpty()) { - _allTrusted = true; - return true; - } - - QString msg = QL("<html><head>"); - msg += QL("<link rel='stylesheet' type='text/css' href='format.css'>"); - msg += QL("</head><body>"); - - // loop over the unknown certs and line up their errors. - msg += QL("<h3>") + tr("Warnings about current SSL Connection:") + QL("</h3>"); - msg += QL("<div id=\"ca_errors\">"); - foreach( const QSslCertificate& cert, _unknownCerts ) { - msg += QL("<div id=\"ca_error\">"); - // add the errors for this cert - foreach( QSslError err, errors ) { - if( err.certificate() == cert ) { - msg += QL("<p>") + err.errorString() + QL("</p>"); - } - } - msg += QL("</div>"); - msg += certDiv( cert ); - if( _unknownCerts.count() > 1 ) { - msg += QL("<hr/>"); - } - } - msg += QL("</div></body></html>"); - - qDebug() << "# # # # # # "; - qDebug() << msg; - QTextDocument *doc = new QTextDocument(0); - QString style = styleSheet(); - qDebug() << "Style: " << style; - doc->addResource( QTextDocument::StyleSheetResource, QUrl( QL("format.css") ), style); - doc->setHtml( msg ); - - _ui->_tbErrors->setDocument( doc ); - _ui->_tbErrors->show(); - - return false; -} - -QString SslErrorDialog::certDiv( QSslCertificate cert ) const -{ - QString msg; - msg += QL("<div id=\"cert\">"); - msg += QL("<h3>") + tr("with Certificate %1").arg( Utility::escape(cert.subjectInfo( QSslCertificate::CommonName ))) + QL("</h3>"); - - msg += QL("<div id=\"ccert\">"); - QStringList li; - - QString org = Utility::escape(cert.subjectInfo( QSslCertificate::Organization)); - QString unit = Utility::escape(cert.subjectInfo( QSslCertificate::OrganizationalUnitName)); - QString country = Utility::escape(cert.subjectInfo( QSslCertificate::CountryName)); - if (unit.isEmpty()) unit = tr("<not specified>"); - if (org.isEmpty()) org = tr("<not specified>"); - if (country.isEmpty()) country = tr("<not specified>"); - li << tr("Organization: %1").arg(org); - li << tr("Unit: %1").arg(unit); - li << tr("Country: %1").arg(country); - msg += QL("<p>") + li.join(QL("<br/>")) + QL("</p>"); - - msg += QL("<p>"); - - QString md5sum = Utility::formatFingerprint(cert.digest(QCryptographicHash::Md5).toHex()); - QString sha1sum = Utility::formatFingerprint(cert.digest(QCryptographicHash::Sha1).toHex()); - msg += tr("Fingerprint (MD5): <tt>%1</tt>").arg(md5sum) + QL("<br/>"); - msg += tr("Fingerprint (SHA1): <tt>%1</tt>").arg(sha1sum) + QL("<br/>"); - msg += QL("<br/>"); - msg += tr("Effective Date: %1").arg( cert.effectiveDate().toString()) + QL("<br/>"); - msg += tr("Expiry Date: %1").arg( cert.expiryDate().toString()) + QL("</p>"); - - msg += QL("</div>" ); - - msg += QL("<h3>") + tr("Issuer: %1").arg(Utility::escape(cert.issuerInfo( QSslCertificate::CommonName))) + QL("</h3>"); - msg += QL("<div id=\"issuer\">"); - li.clear(); - li << tr("Organization: %1").arg(Utility::escape(cert.issuerInfo( QSslCertificate::Organization))); - li << tr("Unit: %1").arg(Utility::escape(cert.issuerInfo( QSslCertificate::OrganizationalUnitName))); - li << tr("Country: %1").arg(Utility::escape(cert.issuerInfo( QSslCertificate::CountryName))); - msg += QL("<p>") + li.join(QL("<br/>")) + QL("</p>"); - msg += QL("</div>" ); - msg += QL("</div>" ); - - return msg; -} - -bool SslErrorDialog::trustConnection() -{ - if( _allTrusted ) return true; - - bool stat = ( _ui->_cbTrustConnect->checkState() == Qt::Checked ); - qDebug() << "SSL-Connection is trusted: " << stat; - - return stat; -} - -} // end namespace diff --git a/src/mirall/sslerrordialog.h b/src/mirall/sslerrordialog.h deleted file mode 100644 index b8639844a..000000000 --- a/src/mirall/sslerrordialog.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) by Klaas Freitag <freitag@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 SSLERRORDIALOG_H -#define SSLERRORDIALOG_H - -#include <QtCore> -#include <QDialog> -#include <QSslCertificate> -#include <QList> - -#include "mirall/account.h" - -class QSslError; -class QSslCertificate; - -namespace Mirall -{ - -namespace Ui { -class SslErrorDialog; -} - -class SslDialogErrorHandler : public AbstractSslErrorHandler { -public: - bool handleErrors(QList<QSslError> errors, QList<QSslCertificate> *certs, Account*) Q_DECL_OVERRIDE; -}; - -class SslErrorDialog : public QDialog -{ - Q_OBJECT -public: - explicit SslErrorDialog(Account *account, QWidget *parent = 0); - ~SslErrorDialog(); - bool checkFailingCertsKnown( const QList<QSslError> &errors ); - bool trustConnection(); - QList<QSslCertificate> unknownCerts() const { return _unknownCerts; } - -private: - QString styleSheet() const; - bool _allTrusted; - - QString certDiv( QSslCertificate ) const; - - QList<QSslCertificate> _unknownCerts; - QString _customConfigHandle; - Ui::SslErrorDialog *_ui; - Account *_account; -}; -} // end namespace - -#endif // SSLERRORDIALOG_H diff --git a/src/mirall/sslerrordialog.ui b/src/mirall/sslerrordialog.ui deleted file mode 100644 index 39adabdf5..000000000 --- a/src/mirall/sslerrordialog.ui +++ /dev/null @@ -1,59 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>Mirall::SslErrorDialog</class> - <widget class="QWidget" name="Mirall::SslErrorDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>640</width> - <height>560</height> - </rect> - </property> - <property name="windowTitle"> - <string>Form</string> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="2" column="0"> - <widget class="QCheckBox" name="_cbTrustConnect"> - <property name="font"> - <font> - <pointsize>11</pointsize> - </font> - </property> - <property name="text"> - <string>Trust this certificate anyway</string> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QDialogButtonBox" name="_dialogButtonBox"> - <property name="standardButtons"> - <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="label"> - <property name="font"> - <font> - <pointsize>14</pointsize> - </font> - </property> - <property name="text"> - <string>SSL Connection</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QTextBrowser" name="_tbErrors"> - <property name="openExternalLinks"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/src/mirall/syncengine.cpp b/src/mirall/syncengine.cpp deleted file mode 100644 index ddfe6eac1..000000000 --- a/src/mirall/syncengine.cpp +++ /dev/null @@ -1,905 +0,0 @@ -/* - * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> - * 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. - */ - -#include "mirall/syncengine.h" -#include "mirall/account.h" -#include "mirall/theme.h" -#include "owncloudpropagator.h" -#include "syncjournaldb.h" -#include "syncjournalfilerecord.h" -#include "creds/abstractcredentials.h" - -#ifdef Q_OS_WIN -#include <windows.h> -#else -#include <unistd.h> -#endif - -#include <assert.h> - -#include <QDebug> -#include <QSslSocket> -#include <QDir> -#include <QMutexLocker> -#include <QThread> -#include <QStringList> -#include <QTextStream> -#include <QTime> -#include <QUrl> -#include <QSslCertificate> - -namespace Mirall { - -bool SyncEngine::_syncRunning = false; - -SyncEngine::SyncEngine(CSYNC *ctx, const QString& localPath, const QString& remoteURL, const QString& remotePath, Mirall::SyncJournalDb* journal) - : _csync_ctx(ctx) - , _needsUpdate(false) - , _localPath(localPath) - , _remoteUrl(remoteURL) - , _remotePath(remotePath) - , _journal(journal) - , _hasFiles(false) - , _uploadLimit(0) - , _downloadLimit(0) -{ - qRegisterMetaType<SyncFileItem>("SyncFileItem"); - qRegisterMetaType<SyncFileItem::Status>("SyncFileItem::Status"); - qRegisterMetaType<Progress::Info>("Progress::Info"); - - _thread.setObjectName("CSync_Neon_Thread"); - _thread.start(); -} - -SyncEngine::~SyncEngine() -{ - _thread.quit(); - _thread.wait(); -} - -//Convert an error code from csync to a user readable string. -// Keep that function thread safe as it can be called from the sync thread or the main thread -QString SyncEngine::csyncErrorToString(CSYNC_STATUS err) -{ - QString errStr; - - switch( err ) { - case CSYNC_STATUS_OK: - errStr = tr("Success."); - break; - case CSYNC_STATUS_NO_LOCK: - errStr = tr("CSync failed to create a lock file."); - break; - case CSYNC_STATUS_STATEDB_LOAD_ERROR: - errStr = tr("CSync failed to load or create the journal file. " - "Make sure you have read and write permissions in the local sync directory."); - break; - case CSYNC_STATUS_STATEDB_WRITE_ERROR: - errStr = tr("CSync failed to write the journal file."); - break; - case CSYNC_STATUS_NO_MODULE: - errStr = tr("<p>The %1 plugin for csync could not be loaded.<br/>Please verify the installation!</p>").arg(Theme::instance()->appNameGUI()); - break; - case CSYNC_STATUS_TIMESKEW: - errStr = tr("The system time on this client is different than the system time on the server. " - "Please use a time synchronization service (NTP) on the server and client machines " - "so that the times remain the same."); - break; - case CSYNC_STATUS_FILESYSTEM_UNKNOWN: - errStr = tr("CSync could not detect the filesystem type."); - break; - case CSYNC_STATUS_TREE_ERROR: - errStr = tr("CSync got an error while processing internal trees."); - break; - case CSYNC_STATUS_MEMORY_ERROR: - errStr = tr("CSync failed to reserve memory."); - break; - case CSYNC_STATUS_PARAM_ERROR: - errStr = tr("CSync fatal parameter error."); - break; - case CSYNC_STATUS_UPDATE_ERROR: - errStr = tr("CSync processing step update failed."); - break; - case CSYNC_STATUS_RECONCILE_ERROR: - errStr = tr("CSync processing step reconcile failed."); - break; - case CSYNC_STATUS_PROPAGATE_ERROR: - errStr = tr("CSync processing step propagate failed."); - break; - case CSYNC_STATUS_REMOTE_ACCESS_ERROR: - errStr = tr("<p>The target directory does not exist.</p><p>Please check the sync setup.</p>"); - break; - case CSYNC_STATUS_REMOTE_CREATE_ERROR: - case CSYNC_STATUS_REMOTE_STAT_ERROR: - errStr = tr("A remote file can not be written. Please check the remote access."); - break; - case CSYNC_STATUS_LOCAL_CREATE_ERROR: - case CSYNC_STATUS_LOCAL_STAT_ERROR: - errStr = tr("The local filesystem can not be written. Please check permissions."); - break; - case CSYNC_STATUS_PROXY_ERROR: - errStr = tr("CSync failed to connect through a proxy."); - break; - case CSYNC_STATUS_PROXY_AUTH_ERROR: - errStr = tr("CSync could not authenticate at the proxy."); - break; - case CSYNC_STATUS_LOOKUP_ERROR: - errStr = tr("CSync failed to lookup proxy or server."); - break; - case CSYNC_STATUS_SERVER_AUTH_ERROR: - errStr = tr("CSync failed to authenticate at the %1 server.").arg(Theme::instance()->appNameGUI()); - break; - case CSYNC_STATUS_CONNECT_ERROR: - errStr = tr("CSync failed to connect to the network."); - break; - case CSYNC_STATUS_TIMEOUT: - errStr = tr("A network connection timeout happened."); - break; - case CSYNC_STATUS_HTTP_ERROR: - errStr = tr("A HTTP transmission error happened."); - break; - case CSYNC_STATUS_PERMISSION_DENIED: - errStr = tr("CSync failed due to not handled permission deniend."); - break; - case CSYNC_STATUS_NOT_FOUND: - errStr = tr("CSync failed to access "); // filename gets added. - break; - case CSYNC_STATUS_FILE_EXISTS: - errStr = tr("CSync tried to create a directory that already exists."); - break; - case CSYNC_STATUS_OUT_OF_SPACE: - errStr = tr("CSync: No space on %1 server available.").arg(Theme::instance()->appNameGUI()); - break; - case CSYNC_STATUS_QUOTA_EXCEEDED: - errStr = tr("CSync: No space on %1 server available.").arg(Theme::instance()->appNameGUI()); - break; - case CSYNC_STATUS_UNSUCCESSFUL: - errStr = tr("CSync unspecified error."); - break; - case CSYNC_STATUS_ABORTED: - errStr = tr("Aborted by the user"); - break; - - default: - errStr = tr("An internal error number %1 happened.").arg( (int) err ); - } - - return errStr; - -} - -bool SyncEngine::checkBlacklisting( SyncFileItem *item ) -{ - bool re = false; - - if( !_journal ) { - qWarning() << "Journal is undefined!"; - return false; - } - - SyncJournalBlacklistRecord entry = _journal->blacklistEntry(item->_file); - item->_blacklistedInDb = false; - - // if there is a valid entry in the blacklist table and the retry count is - // already null or smaller than 0, the file is blacklisted. - if( entry.isValid() ) { - item->_blacklistedInDb = true; - - if( entry._retryCount <= 0 ) { - re = true; - } - - // if the retryCount is 0, but the etag for downloads or the mtime for uploads - // has changed, it is tried again - // note that if the retryCount is -1 we never try again. - if( entry._retryCount == 0 ) { - if( item->_direction == SyncFileItem::Up ) { // check the modtime - if(item->_modtime == 0 || entry._lastTryModtime == 0) { - re = false; - } else { - if( item->_modtime != entry._lastTryModtime ) { - re = false; - qDebug() << item->_file << " is blacklisted, but has changed mtime!"; - } - } - } else { - // download, check the etag. - if( item->_etag.isEmpty() || entry._lastTryEtag.isEmpty() ) { - qDebug() << item->_file << "one ETag is empty, no blacklisting"; - return false; - } else { - if( item->_etag != entry._lastTryEtag ) { - re = false; - qDebug() << item->_file << " is blacklisted, but has changed etag!"; - } - } - } - } - - if( re ) { - qDebug() << "Item is on blacklist: " << entry._file << "retries:" << entry._retryCount; - item->_instruction = CSYNC_INSTRUCTION_ERROR; - item->_status = SyncFileItem::FileIgnored; - item->_errorString = tr("The item is not synced because of previous errors: %1").arg(entry._errorString); - } - } - - return re; -} - -int SyncEngine::treewalkLocal( TREE_WALK_FILE* file, void *data ) -{ - return static_cast<SyncEngine*>(data)->treewalkFile( file, false ); -} - -int SyncEngine::treewalkRemote( TREE_WALK_FILE* file, void *data ) -{ - return static_cast<SyncEngine*>(data)->treewalkFile( file, true ); -} - -int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote ) -{ - if( ! file ) return -1; - SyncFileItem item; - item._file = QString::fromUtf8( file->path ); - item._originalFile = item._file; - item._instruction = file->instruction; - item._direction = SyncFileItem::None; - item._fileId = file->file_id; - if (file->directDownloadUrl) { - item._directDownloadUrl = QString::fromUtf8( file->directDownloadUrl ); - } - if (file->directDownloadCookies) { - item._directDownloadCookies = QString::fromUtf8( file->directDownloadCookies ); - } - if (file->remotePerm && file->remotePerm[0]) { - item._remotePerm = QByteArray(file->remotePerm); - } - - // record the seen files to be able to clean the journal later - _seenFiles.insert(item._file); - - if (remote && file->remotePerm && file->remotePerm[0]) { - _remotePerms[item._file] = file->remotePerm; - } - - switch(file->error_status) { - case CSYNC_STATUS_OK: - break; - case CSYNC_STATUS_INDIVIDUAL_IS_SYMLINK: - item._errorString = tr("Symbolic links are not supported in syncing."); - break; - case CSYNC_STATUS_INDIVIDUAL_IGNORE_LIST: - item._errorString = tr("File is listed on the ignore list."); - break; - case CSYNC_STATUS_INDIVIDUAL_IS_INVALID_CHARS: - item._errorString = tr("File contains invalid characters that can not be synced cross platform."); - break; - case CYSNC_STATUS_FILE_LOCKED_OR_OPEN: - item._errorString = QLatin1String("File locked"); // don't translate, internal use! - break; - - default: - Q_ASSERT("Non handled error-status"); - /* No error string */ - } - item._isDirectory = file->type == CSYNC_FTW_TYPE_DIR; - item._modtime = file->modtime; - item._etag = file->etag; - item._size = file->size; - item._inode = file->inode; - - item._should_update_etag = file->should_update_etag; - switch( file->type ) { - case CSYNC_FTW_TYPE_DIR: - item._type = SyncFileItem::Directory; - break; - case CSYNC_FTW_TYPE_FILE: - item._type = SyncFileItem::File; - break; - case CSYNC_FTW_TYPE_SLINK: - item._type = SyncFileItem::SoftLink; - break; - default: - item._type = SyncFileItem::UnknownType; - } - - SyncFileItem::Direction dir; - - int re = 0; - - switch(file->instruction) { - case CSYNC_INSTRUCTION_NONE: - if (file->should_update_etag && !item._isDirectory) { - // Update the database now already (new fileid or etag or remotePerm) - _journal->setFileRecord(SyncJournalFileRecord(item, _localPath + item._file)); - item._should_update_etag = false; - } - if (item._isDirectory && (remote || file->should_update_etag)) { - // Because we want still to update etags of directories - dir = SyncFileItem::None; - } else { - // No need to do anything. - _hasFiles = true; - - emit syncItemDiscovered(item); - return re; - } - break; - case CSYNC_INSTRUCTION_RENAME: - dir = !remote ? SyncFileItem::Down : SyncFileItem::Up; - item._renameTarget = QString::fromUtf8( file->rename_path ); - if (item._isDirectory) - _renamedFolders.insert(item._file, item._renameTarget); - break; - case CSYNC_INSTRUCTION_REMOVE: - dir = !remote ? SyncFileItem::Down : SyncFileItem::Up; - break; - case CSYNC_INSTRUCTION_CONFLICT: - case CSYNC_INSTRUCTION_IGNORE: - case CSYNC_INSTRUCTION_ERROR: - dir = SyncFileItem::None; - break; - case CSYNC_INSTRUCTION_EVAL: - case CSYNC_INSTRUCTION_NEW: - case CSYNC_INSTRUCTION_SYNC: - case CSYNC_INSTRUCTION_STAT_ERROR: - default: - dir = remote ? SyncFileItem::Down : SyncFileItem::Up; - break; - } - - item._direction = dir; - // check for blacklisting of this item. - // if the item is on blacklist, the instruction was set to IGNORE - checkBlacklisting( &item ); - - if (file->instruction != CSYNC_INSTRUCTION_IGNORE - && file->instruction != CSYNC_INSTRUCTION_REMOVE - && file->instruction != CSYNC_INSTRUCTION_ERROR) { - _hasFiles = true; - } - - if (!item._isDirectory) { - _progressInfo._totalFileCount++; - if (Progress::isSizeDependent(file->instruction)) { - _progressInfo._totalSize += file->size; - } - } - _needsUpdate = true; - - item.log._etag = file->etag; - item.log._fileId = file->file_id; - item.log._instruction = file->instruction; - item.log._modtime = file->modtime; - item.log._size = file->size; - - item.log._other_etag = file->other.etag; - item.log._other_fileId = file->other.file_id; - item.log._other_instruction = file->other.instruction; - item.log._other_modtime = file->other.modtime; - item.log._other_size = file->other.size; - - _syncedItems.append(item); - - emit syncItemDiscovered(item); - return re; -} - -void SyncEngine::handleSyncError(CSYNC *ctx, const char *state) { - CSYNC_STATUS err = csync_get_status( ctx ); - const char *errMsg = csync_get_status_string( ctx ); - QString errStr = csyncErrorToString(err); - if( errMsg ) { - if( !errStr.endsWith(" ")) { - errStr.append(" "); - } - errStr += QString::fromUtf8(errMsg); - } - - // if there is csyncs url modifier in the error message, replace it. - if( errStr.contains("ownclouds://") ) errStr.replace("ownclouds://", "https://"); - if( errStr.contains("owncloud://") ) errStr.replace("owncloud://", "http://"); - - qDebug() << " #### ERROR during "<< state << ": " << errStr; - - if( CSYNC_STATUS_IS_EQUAL( err, CSYNC_STATUS_ABORTED) ) { - qDebug() << "Update phase was aborted by user!"; - } else if( CSYNC_STATUS_IS_EQUAL( err, CSYNC_STATUS_SERVICE_UNAVAILABLE ) || - CSYNC_STATUS_IS_EQUAL( err, CSYNC_STATUS_CONNECT_ERROR )) { - emit csyncUnavailable(); - } else { - emit csyncError(errStr); - } - finalize(); -} - -void SyncEngine::startSync() -{ - Q_ASSERT(!_syncRunning); - _syncRunning = true; - - Q_ASSERT(_csync_ctx); - - _syncedItems.clear(); - _needsUpdate = false; - - csync_resume(_csync_ctx); - - if (!_journal->exists()) { - qDebug() << "=====sync looks new (no DB exists), activating recursive PROPFIND if csync supports it"; - bool no_recursive_propfind = false; - csync_set_module_property(_csync_ctx, "no_recursive_propfind", &no_recursive_propfind); - } else { - // retrieve the file count from the db and close it afterwards because - // csync_update also opens the database. - int fileRecordCount = 0; - fileRecordCount = _journal->getFileRecordCount(); - bool isUpdateFrom_1_5 = _journal->isUpdateFrom_1_5(); - _journal->close(); - - if( fileRecordCount == -1 ) { - qDebug() << "No way to create a sync journal!"; - emit csyncError(tr("Unable to initialize a sync journal.")); - finalize(); - return; - // database creation error! - } else if ( fileRecordCount < 50 ) { - qDebug() << "=====sync DB has only" << fileRecordCount << "items, enable recursive PROPFIND if csync supports it"; - bool no_recursive_propfind = false; - csync_set_module_property(_csync_ctx, "no_recursive_propfind", &no_recursive_propfind); - } else { - qDebug() << "=====sync with existing DB"; - } - - if (fileRecordCount > 1 && isUpdateFrom_1_5) { - qDebug() << "detected update from 1.5"; - // Disable the read from DB to be sure to re-read all the fileid and etags. - csync_set_read_from_db(_csync_ctx, false); - } - } - - csync_set_userdata(_csync_ctx, this); - // TODO: This should be a part of this method, but we don't have - // any way to get "session_key" module property from csync. Had we - // have it, then we could keep this code and remove it from - // AbstractCredentials implementations. - if (Account *account = AccountManager::instance()->account()) { - account->credentials()->syncContextPreStart(_csync_ctx); - } else { - qDebug() << Q_FUNC_INFO << "No default Account object, huh?"; - } - // if (_lastAuthCookies.length() > 0) { - // // Stuff cookies inside csync, then we can avoid the intermediate HTTP 401 reply - // // when https://github.com/owncloud/core/pull/4042 is merged. - // QString cookiesAsString; - // foreach(QNetworkCookie c, _lastAuthCookies) { - // cookiesAsString += c.name(); - // cookiesAsString += '='; - // cookiesAsString += c.value(); - // cookiesAsString += "; "; - // } - // csync_set_module_property(_csync_ctx, "session_key", cookiesAsString.to - // } - - // csync_set_auth_callback( _csync_ctx, getauth ); - //csync_set_log_level( 11 ); don't set the loglevel here, it shall be done by folder.cpp or owncloudcmd.cpp - int timeout = OwncloudPropagator::httpTimeout(); - csync_set_module_property(_csync_ctx, "timeout", &timeout); - - - _stopWatch.start(); - - qDebug() << "#### Update start #################################################### >>"; - - UpdateJob *job = new UpdateJob(_csync_ctx); - job->moveToThread(&_thread); - connect(job, SIGNAL(finished(int)), this, SLOT(slotUpdateFinished(int))); - QMetaObject::invokeMethod(job, "start", Qt::QueuedConnection); -} - -void SyncEngine::slotUpdateFinished(int updateResult) -{ - if (updateResult < 0 ) { - handleSyncError(_csync_ctx, "csync_update"); - return; - } - qDebug() << "<<#### Update end #################################################### " << _stopWatch.addLapTime(QLatin1String("Update Finished")); - - if( csync_reconcile(_csync_ctx) < 0 ) { - handleSyncError(_csync_ctx, "csync_reconcile"); - return; - } - - _stopWatch.addLapTime(QLatin1String("Reconcile Finished")); - - _progressInfo = Progress::Info(); - - _hasFiles = false; - bool walkOk = true; - _seenFiles.clear(); - - if( csync_walk_local_tree(_csync_ctx, &treewalkLocal, 0) < 0 ) { - qDebug() << "Error in local treewalk."; - walkOk = false; - } - if( walkOk && csync_walk_remote_tree(_csync_ctx, &treewalkRemote, 0) < 0 ) { - qDebug() << "Error in remote treewalk."; - } - - // Adjust the paths for the renames. - for (SyncFileItemVector::iterator it = _syncedItems.begin(); - it != _syncedItems.end(); ++it) { - it->_file = adjustRenamedPath(it->_file); - } - - // Sort items per destination - std::sort(_syncedItems.begin(), _syncedItems.end()); - - // make sure everything is allowed - checkForPermission(); - - // Sanity check - if (!_journal->isConnected()) { - qDebug() << "Bailing out, DB failure"; - emit csyncError(tr("Cannot open the sync journal")); - finalize(); - return; - } - - // To announce the beginning of the sync - emit aboutToPropagate(_syncedItems); - emit transmissionProgress(_progressInfo); - - if (!_hasFiles && !_syncedItems.isEmpty()) { - qDebug() << Q_FUNC_INFO << "All the files are going to be removed, asking the user"; - bool cancel = false; - emit aboutToRemoveAllFiles(_syncedItems.first()._direction, &cancel); - if (cancel) { - qDebug() << Q_FUNC_INFO << "Abort sync"; - finalize(); - return; - } - } - - if (_needsUpdate) - emit(started()); - - ne_session_s *session = 0; - // that call to set property actually is a get which will return the session - csync_set_module_property(_csync_ctx, "get_dav_session", &session); - Q_ASSERT(session); - - _propagator.reset(new OwncloudPropagator (session, _localPath, _remoteUrl, _remotePath, - _journal, &_thread)); - connect(_propagator.data(), SIGNAL(completed(SyncFileItem)), - this, SLOT(slotJobCompleted(SyncFileItem))); - connect(_propagator.data(), SIGNAL(progress(SyncFileItem,quint64)), - this, SLOT(slotProgress(SyncFileItem,quint64))); - connect(_propagator.data(), SIGNAL(adjustTotalTransmissionSize(qint64)), this, SLOT(slotAdjustTotalTransmissionSize(qint64))); - connect(_propagator.data(), SIGNAL(finished()), this, SLOT(slotFinished()), Qt::QueuedConnection); - - // apply the network limits to the propagator - setNetworkLimits(_uploadLimit, _downloadLimit); - - _propagator->start(_syncedItems); -} - -void SyncEngine::setNetworkLimits(int upload, int download) -{ - _uploadLimit = upload; - _downloadLimit = download; - - if( !_propagator ) return; - - _propagator->_uploadLimit = upload; - _propagator->_downloadLimit = download; - - int propDownloadLimit = _propagator->_downloadLimit -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) - .load() -#endif - ; - int propUploadLimit = _propagator->_uploadLimit -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) - .load() -#endif - ; - - if( propDownloadLimit != 0 || propUploadLimit != 0 ) { - qDebug() << " N------N Network Limits (down/up) " << propDownloadLimit << propUploadLimit; - } -} - -void SyncEngine::slotJobCompleted(const SyncFileItem &item) -{ - qDebug() << Q_FUNC_INFO << item._file << item._status << item._errorString; - - /* Update the _syncedItems vector */ - int idx = _syncedItems.indexOf(item); - if (idx >= 0) { - _syncedItems[idx]._instruction = item._instruction; - _syncedItems[idx]._errorString = item._errorString; - _syncedItems[idx]._status = item._status; - - _syncedItems[idx]._requestDuration = item._requestDuration; - _syncedItems[idx]._responseTimeStamp = item._responseTimeStamp; - } else { - qWarning() << Q_FUNC_INFO << "Could not find index in synced items!"; - - } - - _progressInfo.setProgressComplete(item); - - if (item._status == SyncFileItem::FatalError) { - emit csyncError(item._errorString); - } - - emit transmissionProgress(_progressInfo); - emit jobCompleted(item); -} - -void SyncEngine::slotFinished() -{ - // emit the treewalk results. - if( ! _journal->postSyncCleanup( _seenFiles ) ) { - qDebug() << "Cleaning of synced "; - } - - _journal->commit("All Finished.", false); - emit treeWalkResult(_syncedItems); - finalize(); -} - -void SyncEngine::finalize() -{ - _thread.quit(); - _thread.wait(); - csync_commit(_csync_ctx); - - qDebug() << "CSync run took " << _stopWatch.addLapTime(QLatin1String("Sync Finished")); - _stopWatch.stop(); - - _propagator.reset(0); - _syncRunning = false; - emit finished(); -} - -void SyncEngine::slotProgress(const SyncFileItem& item, quint64 current) -{ - _progressInfo.setProgressItem(item, current); - emit transmissionProgress(_progressInfo); -} - - -void SyncEngine::slotAdjustTotalTransmissionSize(qint64 change) -{ - _progressInfo._totalSize += change; -} - -/* Given a path on the remote, give the path as it is when the rename is done */ -QString SyncEngine::adjustRenamedPath(const QString& original) -{ - int slashPos = original.size(); - while ((slashPos = original.lastIndexOf('/' , slashPos - 1)) > 0) { - QHash< QString, QString >::const_iterator it = _renamedFolders.constFind(original.left(slashPos)); - if (it != _renamedFolders.constEnd()) { - return *it + original.mid(slashPos); - } - } - return original; -} - -void SyncEngine::checkForPermission() -{ - for (SyncFileItemVector::iterator it = _syncedItems.begin(); it != _syncedItems.end(); ++it) { - - if (it->_direction != SyncFileItem::Up) { - // Currently we only check server-side permissions - continue; - } - - switch(it->_instruction) { - case CSYNC_INSTRUCTION_NEW: { - int slashPos = it->_file.lastIndexOf('/'); - QString parentDir = slashPos <= 0 ? "" : it->_file.mid(0, slashPos); - const QByteArray perms = getPermissions(parentDir); - if (perms.isNull()) { - // No permissions set - break; - } else if (it->_isDirectory && !perms.contains("K")) { - qDebug() << "checkForPermission: ERROR" << it->_file; - it->_instruction = CSYNC_INSTRUCTION_ERROR; - it->_status = SyncFileItem::NormalError; - it->_errorString = tr("Not allowed because you don't have permission to add sub-directories in that directory"); - - const QString path = it->_file + QLatin1Char('/'); - for (SyncFileItemVector::iterator it_next = it + 1; it_next != _syncedItems.end() && it_next->_file.startsWith(path); ++it_next) { - it = it_next; - it->_instruction = CSYNC_INSTRUCTION_ERROR; - it->_status = SyncFileItem::NormalError; - it->_errorString = tr("Not allowed because you don't have permission to add parent directory"); - } - - } else if (!it->_isDirectory && !perms.contains("C")) { - qDebug() << "checkForPermission: ERROR" << it->_file; - it->_instruction = CSYNC_INSTRUCTION_ERROR; - it->_status = SyncFileItem::NormalError; - it->_errorString = tr("Not allowed because you don't have permission to add files in that directory"); - } - break; - } - case CSYNC_INSTRUCTION_SYNC: { - const QByteArray perms = getPermissions(it->_file); - if (perms.isNull()) { - // No permissions set - break; - } if (!it->_isDirectory && !perms.contains("W")) { - qDebug() << "checkForPermission: RESTORING" << it->_file; - it->_instruction = CSYNC_INSTRUCTION_CONFLICT; - it->_direction = SyncFileItem::Down; - it->_isRestoration = true; - // take the things to write to the db from the "other" node (i.e: info from server) - it->_modtime = it->log._other_modtime; - it->_fileId = it->log._other_fileId; - it->_etag = it->log._other_etag; - it->_errorString = tr("Not allowed to upload this file because it is read-only on the server, restoring"); - continue; - } - break; - } - case CSYNC_INSTRUCTION_REMOVE: { - const QByteArray perms = getPermissions(it->_file); - if (perms.isNull()) { - // No permissions set - break; - } if (!perms.contains("D")) { - qDebug() << "checkForPermission: RESTORING" << it->_file; - it->_instruction = CSYNC_INSTRUCTION_NEW; - it->_direction = SyncFileItem::Down; - it->_isRestoration = true; - it->_errorString = tr("Not allowed to remove, restoring"); - - if (it->_isDirectory) { - // restore all sub items - const QString path = it->_file + QLatin1Char('/'); - for (SyncFileItemVector::iterator it_next = it + 1; - it_next != _syncedItems.end() && it_next->_file.startsWith(path); ++it_next) { - it = it_next; - - if (it->_instruction != CSYNC_INSTRUCTION_REMOVE) { - qWarning() << "non-removed job within a removed directory" - << it->_file << it->_instruction; - continue; - } - - qDebug() << "checkForPermission: RESTORING" << it->_file; - - it->_instruction = CSYNC_INSTRUCTION_NEW; - it->_direction = SyncFileItem::Down; - it->_isRestoration = true; - it->_errorString = tr("Not allowed to remove, restoring"); - } - } - } - break; - } - - case CSYNC_INSTRUCTION_RENAME: { - - int slashPos = it->_renameTarget.lastIndexOf('/'); - const QString parentDir = slashPos <= 0 ? "" : it->_renameTarget.mid(0, slashPos-1); - const QByteArray destPerms = getPermissions(parentDir); - const QByteArray filePerms = getPermissions(it->_file); - - //true when it is just a rename in the same directory. (not a move) - bool isRename = it->_file.startsWith(parentDir) && it->_file.lastIndexOf('/') == slashPos; - - - // Check if we are allowed to move to the destination. - bool destinationOK = true; - if (isRename || destPerms.isNull()) { - // no need to check for the destination dir permission - destinationOK = true; - } else if (it->_isDirectory && !destPerms.contains("K")) { - destinationOK = false; - } else if (!it->_isDirectory && !destPerms.contains("C")) { - destinationOK = false; - } - - // check if we are allowed to move from the source - bool sourceOK = true; - if (!filePerms.isNull() - && ((isRename && !filePerms.contains("N")) - || (!isRename && !filePerms.contains("M")))) { - - // We are not allowed to move or rename this file - sourceOK = false; - - if (filePerms.contains("D") && destinationOK) { - // but we are allowed to delete it - // TODO! simulate delete & upload - } - } - -#if 0 /* We don't like the idea of renaming behind user's back, as the user may be working with the files */ - - if (!sourceOK && !destinationOK) { - // Both the source and the destination won't allow move. Move back to the original - std::swap(it->_file, it->_renameTarget); - it->_direction = SyncFileItem::Down; - it->_errorString = tr("Move not allowed, item restored"); - it->_isRestoration = true; - qDebug() << "checkForPermission: MOVING BACK" << it->_file; - } else -#endif - if (!sourceOK || !destinationOK) { - // One of them is not possible, just throw an error - it->_instruction = CSYNC_INSTRUCTION_ERROR; - it->_status = SyncFileItem::NormalError; - const QString errorString = tr("Move not allowed because %1 is read-only").arg( - sourceOK ? tr("the destination") : tr("the source")); - it->_errorString = errorString; - - qDebug() << "checkForPermission: ERROR MOVING" << it->_file << errorString; - - // Avoid a rename on next sync: - // TODO: do the resolution now already so we don't need two sync - // At this point we would need to go back to the propagate phase on both remote to take - // the decision. - _journal->avoidRenamesOnNextSync(it->_file); - - - if (it->_isDirectory) { - const QString path = it->_renameTarget + QLatin1Char('/'); - for (SyncFileItemVector::iterator it_next = it + 1; - it_next != _syncedItems.end() && it_next->destination().startsWith(path); ++it_next) { - it = it_next; - it->_instruction = CSYNC_INSTRUCTION_ERROR; - it->_status = SyncFileItem::NormalError; - it->_errorString = errorString; - qDebug() << "checkForPermission: ERROR MOVING" << it->_file; - } - } - } - break; - } - default: - break; - } - } -} - -QByteArray SyncEngine::getPermissions(const QString& file) const -{ - static bool isTest = qgetenv("OWNCLOUD_TEST_PERMISSIONS").toInt(); - if (isTest) { - QRegExp rx("_PERM_([^_]*)_[^/]*$"); - if (rx.indexIn(file) != -1) { - return rx.cap(1).toLatin1(); - } - } - return _remotePerms.value(file); -} - - -void SyncEngine::abort() -{ - csync_request_abort(_csync_ctx); - if(_propagator) - _propagator->abort(); -} - -} // ns Mirall diff --git a/src/mirall/syncengine.h b/src/mirall/syncengine.h deleted file mode 100644 index c4a9af7bb..000000000 --- a/src/mirall/syncengine.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> - * 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. - */ - -#ifndef CSYNCTHREAD_H -#define CSYNCTHREAD_H - -#include <stdint.h> - -#include <QMutex> -#include <QThread> -#include <QString> -#include <QSet> -#include <qelapsedtimer.h> - -#include <csync.h> - -#include "mirall/syncfileitem.h" -#include "mirall/progressdispatcher.h" -#include "mirall/utility.h" - -class QProcess; - -namespace Mirall { - -class SyncJournalFileRecord; - -class SyncJournalDb; - -class OwncloudPropagator; - -class OWNCLOUDSYNC_EXPORT SyncEngine : public QObject -{ - Q_OBJECT -public: - SyncEngine(CSYNC *, const QString &localPath, const QString &remoteURL, const QString &remotePath, SyncJournalDb *journal); - ~SyncEngine(); - - static QString csyncErrorToString( CSYNC_STATUS); - - Q_INVOKABLE void startSync(); - void setNetworkLimits(int upload, int download); - - /* Abort the sync. Called from the main thread */ - void abort(); - - Utility::StopWatch &stopWatch() { return _stopWatch; } - -signals: - void csyncError( const QString& ); - void csyncUnavailable(); - - // before actual syncing (after update+reconcile) for each item - void syncItemDiscovered(const SyncFileItem&); - // after the above signals. with the items that actually need propagating - void aboutToPropagate(const SyncFileItemVector&); - - // after each job (successful or not) - void jobCompleted(const SyncFileItem&); - - // after sync is done - void treeWalkResult(const SyncFileItemVector&); - - void transmissionProgress( const Progress::Info& progress ); - - void csyncStateDbFile( const QString& ); - void wipeDb(); - - void finished(); - void started(); - - void aboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel); - -private slots: - void slotJobCompleted(const SyncFileItem& item); - void slotFinished(); - void slotProgress(const SyncFileItem& item, quint64 curent); - void slotAdjustTotalTransmissionSize(qint64 change); - void slotUpdateFinished(int updateResult); - -private: - void handleSyncError(CSYNC *ctx, const char *state); - - static int treewalkLocal( TREE_WALK_FILE*, void *); - static int treewalkRemote( TREE_WALK_FILE*, void *); - int treewalkFile( TREE_WALK_FILE*, bool ); - bool checkBlacklisting( SyncFileItem *item ); - - // cleanup and emit the finished signal - void finalize(); - - static bool _syncRunning; //true when one sync is running somewhere (for debugging) - SyncFileItemVector _syncedItems; - - CSYNC *_csync_ctx; - bool _needsUpdate; - QString _localPath; - QString _remoteUrl; - QString _remotePath; - SyncJournalDb *_journal; - QScopedPointer <OwncloudPropagator> _propagator; - QString _lastDeleted; // if the last item was a path and it has been deleted - QSet<QString> _seenFiles; - QThread _thread; - - Progress::Info _progressInfo; - - Utility::StopWatch _stopWatch; - - // maps the origin and the target of the folders that have been renamed - QHash<QString, QString> _renamedFolders; - QString adjustRenamedPath(const QString &original); - - /** - * check if we are allowed to propagate everything, and if we are not, adjust the instructions - * to recover - */ - void checkForPermission(); - QByteArray getPermissions(const QString& file) const; - - bool _hasFiles; // true if there is at least one file that is not ignored or removed - - int _uploadLimit; - int _downloadLimit; - - // hash containing the permissions on the remote directory - QHash<QString, QByteArray> _remotePerms; -}; - - -class UpdateJob : public QObject { - Q_OBJECT - CSYNC *_csync_ctx; - csync_log_callback _log_callback; - int _log_level; - void* _log_userdata; - Q_INVOKABLE void start() { - csync_set_log_callback(_log_callback); - csync_set_log_level(_log_level); - csync_set_log_userdata(_log_userdata); - emit finished(csync_update(_csync_ctx)); - deleteLater(); - } -public: - explicit UpdateJob(CSYNC *ctx, QObject* parent = 0) - : QObject(parent), _csync_ctx(ctx) { - // We need to forward the log property as csync uses thread local - // and updates run in another thread - _log_callback = csync_get_log_callback(); - _log_level = csync_get_log_level(); - _log_userdata = csync_get_log_userdata(); - } -signals: - void finished(int result); -}; - - -} - -#endif // CSYNCTHREAD_H diff --git a/src/mirall/syncfileitem.h b/src/mirall/syncfileitem.h deleted file mode 100644 index 4ce515f4a..000000000 --- a/src/mirall/syncfileitem.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 SYNCFILEITEM_H -#define SYNCFILEITEM_H - -#include <QVector> -#include <QString> -#include <QDateTime> -#include <QMetaType> - -#include <csync.h> - -namespace Mirall { - -class SyncFileItem { -public: - enum Direction { - None = 0, - Up, - Down }; - - enum Type { - UnknownType = 0, - File = CSYNC_FTW_TYPE_FILE, - Directory = CSYNC_FTW_TYPE_DIR, - SoftLink = CSYNC_FTW_TYPE_SLINK - }; - - enum Status { - NoStatus, - - FatalError, ///< Error that causes the sync to stop - NormalError, ///< Error attached to a particular file - SoftError, ///< More like an information - - Success, ///< The file was properly synced - Conflict, ///< The file was properly synced, but a conflict was created - FileIgnored, ///< The file is in the ignored list - Restoration ///< The file was restored because what should have been done was not allowed - }; - - SyncFileItem() : _type(UnknownType), _direction(None), _isDirectory(false), - _instruction(CSYNC_INSTRUCTION_NONE), _modtime(0), - _size(0), _inode(0), _should_update_etag(false), _blacklistedInDb(false), - _status(NoStatus), _httpErrorCode(0), _requestDuration(0), _isRestoration(false) {} - - friend bool operator==(const SyncFileItem& item1, const SyncFileItem& item2) { - return item1._file == item2._file; - } - - friend bool operator<(const SyncFileItem& item1, const SyncFileItem& item2) { - // Sort by destination - return item1.destination() < item2.destination(); - } - - QString destination() const { - return _instruction == CSYNC_INSTRUCTION_RENAME ? _renameTarget : _file; - } - - bool isEmpty() const { - return _file.isEmpty(); - } - - // Variables usefull for everybody - QString _file; - QString _renameTarget; - Type _type; - Direction _direction; - bool _isDirectory; - - // Variables used by the propagator - QString _originalFile; // as it is in the csync tree - csync_instructions_e _instruction; - time_t _modtime; - QByteArray _etag; - quint64 _size; - quint64 _inode; - bool _should_update_etag; - QByteArray _fileId; - QByteArray _remotePerm; - QString _directDownloadUrl; - QString _directDownloadCookies; - bool _blacklistedInDb; - - // Variables usefull to report to the user - Status _status; - QString _errorString; // Contains a string only in case of error - int _httpErrorCode; - QString _responseTimeStamp; - quint64 _requestDuration; - bool _isRestoration; // The original operation was forbidden, and this is a restoration - - struct { - quint64 _size; - time_t _modtime; - QByteArray _etag; - QByteArray _fileId; - enum csync_instructions_e _instruction; - quint64 _other_size; - time_t _other_modtime; - QByteArray _other_etag; - QByteArray _other_fileId; - QByteArray _other_remotePerm; - enum csync_instructions_e _other_instruction; - } log; -}; - - - -typedef QVector<SyncFileItem> SyncFileItemVector; - -} - -Q_DECLARE_METATYPE(Mirall::SyncFileItem) - -#endif // SYNCFILEITEM_H diff --git a/src/mirall/syncfilestatus.cpp b/src/mirall/syncfilestatus.cpp deleted file mode 100644 index 8c8770ae3..000000000 --- a/src/mirall/syncfilestatus.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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/syncfilestatus.h" - -#include <QDebug> - -namespace Mirall { -SyncFileStatus::SyncFileStatus() - :_tag(STATUS_NONE), _sharedWithMe(false) -{ -} - -SyncFileStatus::SyncFileStatus(SyncFileStatusTag tag) - :_tag(tag), _sharedWithMe(false) -{ - -} - -void SyncFileStatus::set(SyncFileStatusTag tag) -{ - _tag = tag; -} - -SyncFileStatus::SyncFileStatusTag SyncFileStatus::tag() -{ - return _tag; -} - -void SyncFileStatus::setSharedWithMe(bool isShared) -{ - _sharedWithMe = isShared; -} - -bool SyncFileStatus::sharedWithMe() -{ - return _sharedWithMe; -} - -QString SyncFileStatus::toSocketAPIString() const -{ - QString statusString; - - switch(_tag) - { - case STATUS_NONE: - statusString = QLatin1String("NONE"); - break; - case STATUS_EVAL: - statusString = QLatin1String("SYNC"); - break; - case STATUS_NEW: - statusString = QLatin1String("NEW"); - break; - case STATUS_IGNORE: - statusString = QLatin1String("IGNORE"); - break; - case STATUS_SYNC: - case STATUS_UPDATED: - statusString = QLatin1String("OK"); - break; - case STATUS_STAT_ERROR: - case STATUS_ERROR: - statusString = QLatin1String("ERROR"); - break; - default: - qWarning() << "This status should not be here:" << _tag; - Q_ASSERT(false); - statusString = QLatin1String("NONE"); - } - if(_sharedWithMe) { - statusString += QLatin1String("+SWM"); - } - - return statusString; -} -} diff --git a/src/mirall/syncfilestatus.h b/src/mirall/syncfilestatus.h deleted file mode 100644 index 9e656f50b..000000000 --- a/src/mirall/syncfilestatus.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 SYNCFILESTATUS_H -#define SYNCFILESTATUS_H - -#include <QString> - -#include "owncloudlib.h" - -namespace Mirall { - -class OWNCLOUDSYNC_EXPORT SyncFileStatus -{ -public: - enum SyncFileStatusTag { - STATUS_NONE, - STATUS_EVAL, - STATUS_REMOVE, - STATUS_RENAME, - STATUS_MOVE, - STATUS_NEW, - STATUS_CONFLICT, - STATUS_IGNORE, - STATUS_SYNC, - STATUS_STAT_ERROR, - STATUS_ERROR, - STATUS_UPDATED - }; - - SyncFileStatus(); - SyncFileStatus(SyncFileStatusTag); - - void set(SyncFileStatusTag tag); - SyncFileStatusTag tag(); - - void setSharedWithMe( bool isShared ); - bool sharedWithMe(); - - QString toSocketAPIString() const; -private: - SyncFileStatusTag _tag; - bool _sharedWithMe; - -}; -} - -#endif // SYNCFILESTATUS_H diff --git a/src/mirall/syncjournaldb.cpp b/src/mirall/syncjournaldb.cpp deleted file mode 100644 index 6f7497a12..000000000 --- a/src/mirall/syncjournaldb.cpp +++ /dev/null @@ -1,902 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 <QFile> -#include <QStringList> -#include <QDebug> -#include <QSqlError> -#include <QSqlQuery> - -#include <inttypes.h> - -#include "syncjournaldb.h" -#include "syncjournalfilerecord.h" -#include "utility.h" -#include "version.h" - -#include "../../csync/src/std/c_jhash.h" - -#define QSQLITE "QSQLITE" - -namespace Mirall { - -SyncJournalDb::SyncJournalDb(const QString& path, QObject *parent) : - QObject(parent), _transaction(0), _possibleUpgradeFromMirall_1_5(false) -{ - - _dbFile = path; - if( !_dbFile.endsWith('/') ) { - _dbFile.append('/'); - } - _dbFile.append(".csync_journal.db"); - - -} - -bool SyncJournalDb::exists() -{ - QMutexLocker locker(&_mutex); - return (!_dbFile.isEmpty() && QFile::exists(_dbFile)); -} - -void SyncJournalDb::startTransaction() -{ - if( _transaction == 0 ) { - if( !_db.transaction() ) { - qDebug() << "ERROR committing to the database: " << _db.lastError().text(); - return; - } - _transaction = 1; - // qDebug() << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Transaction start!"; - } else { - qDebug() << "Database Transaction is running, do not starting another one!"; - } -} - -void SyncJournalDb::commitTransaction() -{ - if( _transaction == 1 ) { - if( ! _db.commit() ) { - qDebug() << "ERROR committing to the database: " << _db.lastError().text(); - return; - } - _transaction = 0; - // qDebug() << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Transaction END!"; - } else { - qDebug() << "No database Transaction to commit"; - } -} - -bool SyncJournalDb::sqlFail( const QString& log, const QSqlQuery& query ) -{ - commitTransaction(); - qWarning() << "Error" << log << query.lastError().text(); - - return false; -} - -bool SyncJournalDb::checkConnect() -{ - if( _db.isOpen() ) { - return true; - } - - if( _dbFile.isEmpty() || !QFile::exists(_dbFile) ) { - qDebug() << "Database " + _dbFile + " is empty or does not exist"; - return false; - } - - QStringList list = QSqlDatabase::drivers(); - if( list.size() == 0 ) { - qDebug() << "Database Drivers could not be loaded."; - return false ; - } else { - if( list.indexOf( QSQLITE ) == -1 ) { - qDebug() << "Database Driver QSQLITE could not be loaded!"; - return false; - } - } - - // Add the connection - _db = QSqlDatabase::addDatabase( QSQLITE, _dbFile); - - // Open the file - _db.setDatabaseName(_dbFile); - - if (!_db.isOpen()) { - if( !_db.open() ) { - QSqlError error = _db.lastError(); - qDebug() << "Error opening the db: " << error.text(); - return false; - } - } - - QSqlQuery pragma1(_db); - pragma1.prepare("PRAGMA synchronous = 1;"); - if (!pragma1.exec()) { - return sqlFail("Set PRAGMA synchronous", pragma1); - } - pragma1.prepare("PRAGMA case_sensitive_like = ON;"); - if (!pragma1.exec()) { - return sqlFail("Set PRAGMA case_sensitivity", pragma1); - } - - /* Because insert are so slow, e do everything in a transaction, and one need to call commit */ - startTransaction(); - - QSqlQuery createQuery(_db); - createQuery.prepare("CREATE TABLE IF NOT EXISTS metadata(" - "phash INTEGER(8)," - "pathlen INTEGER," - "path VARCHAR(4096)," - "inode INTEGER," - "uid INTEGER," - "gid INTEGER," - "mode INTEGER," - "modtime INTEGER(8)," - "type INTEGER," - "md5 VARCHAR(32)," /* This is the etag. Called md5 for compatibility */ - // updateDatabaseStructure() will add a fileid column - // updateDatabaseStructure() will add a remotePerm column - "PRIMARY KEY(phash)" - ");"); - - if (!createQuery.exec()) { - return sqlFail("Create table metadata", createQuery); - } - - createQuery.prepare("CREATE TABLE IF NOT EXISTS downloadinfo(" - "path VARCHAR(4096)," - "tmpfile VARCHAR(4096)," - "etag VARCHAR(32)," - "errorcount INTEGER," - "PRIMARY KEY(path)" - ");"); - - if (!createQuery.exec()) { - return sqlFail("Create table downloadinfo", createQuery); - } - - createQuery.prepare("CREATE TABLE IF NOT EXISTS uploadinfo(" - "path VARCHAR(4096)," - "chunk INTEGER," - "transferid INTEGER," - "errorcount INTEGER," - "size INTEGER(8)," - "modtime INTEGER(8)," - "PRIMARY KEY(path)" - ");"); - - if (!createQuery.exec()) { - return sqlFail("Create table uploadinfo", createQuery); - } - - // create the blacklist table. - createQuery.prepare("CREATE TABLE IF NOT EXISTS blacklist (" - "path VARCHAR(4096)," - "lastTryEtag VARCHAR[32]," - "lastTryModtime INTEGER[8]," - "retrycount INTEGER," - "errorstring VARCHAR[4096]," - "PRIMARY KEY(path)" - ");"); - - if (!createQuery.exec()) { - return sqlFail("Create table blacklist", createQuery); - } - - createQuery.prepare("CREATE TABLE IF NOT EXISTS version(" - "major INTEGER(8)," - "minor INTEGER(8)," - "patch INTEGER(8)," - "custom VARCHAR(256)" - ");"); - if (!createQuery.exec()) { - return sqlFail("Create table blacklist", createQuery); - } - - QSqlQuery versionQuery("SELECT major, minor FROM version;", _db); - if (!versionQuery.next()) { - // If there was no entry in the table, it means we are likely upgrading from 1.5 - _possibleUpgradeFromMirall_1_5 = true; - } else { - // Delete the existing entry so we can replace it by the new one - createQuery.prepare("DELETE FROM version;"); - if (!createQuery.exec()) { - return sqlFail("Remove version", createQuery); - } - } - createQuery.prepare("INSERT INTO version (major, minor, patch) VALUES ( ? , ? , ? );"); - createQuery.bindValue(0, MIRALL_VERSION_MAJOR); - createQuery.bindValue(1, MIRALL_VERSION_MINOR); - createQuery.bindValue(2, MIRALL_VERSION_PATCH); - if (!createQuery.exec()) { - return sqlFail("Insert Version", createQuery); - } - - commitInternal("checkConnect"); - - bool rc = updateDatabaseStructure(); - if( rc ) { - _getFileRecordQuery.reset(new QSqlQuery(_db)); - _getFileRecordQuery->prepare("SELECT path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm FROM " - "metadata WHERE phash=:ph" ); - - _setFileRecordQuery.reset(new QSqlQuery(_db) ); - _setFileRecordQuery->prepare("INSERT OR REPLACE INTO metadata " - "(phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm) " - "VALUES ( ? , ?, ? , ? , ? , ? , ?, ? , ? , ?, ?, ? )" ); - - _getDownloadInfoQuery.reset(new QSqlQuery(_db) ); - _getDownloadInfoQuery->prepare( "SELECT tmpfile, etag, errorcount FROM " - "downloadinfo WHERE path=:pa" ); - - _setDownloadInfoQuery.reset(new QSqlQuery(_db) ); - _setDownloadInfoQuery->prepare( "INSERT OR REPLACE INTO downloadinfo " - "(path, tmpfile, etag, errorcount) " - "VALUES ( ? , ?, ? , ? )" ); - - _deleteDownloadInfoQuery.reset(new QSqlQuery(_db) ); - _deleteDownloadInfoQuery->prepare( "DELETE FROM downloadinfo WHERE path=?" ); - - _getUploadInfoQuery.reset(new QSqlQuery(_db)); - _getUploadInfoQuery->prepare( "SELECT chunk, transferid, errorcount, size, modtime FROM " - "uploadinfo WHERE path=:pa" ); - - _setUploadInfoQuery.reset(new QSqlQuery(_db)); - _setUploadInfoQuery->prepare( "INSERT OR REPLACE INTO uploadinfo " - "(path, chunk, transferid, errorcount, size, modtime) " - "VALUES ( ? , ?, ? , ? , ? , ? )"); - - _deleteUploadInfoQuery.reset(new QSqlQuery(_db)); - _deleteUploadInfoQuery->prepare("DELETE FROM uploadinfo WHERE path=?" ); - - - _deleteFileRecordPhash.reset(new QSqlQuery(_db)); - _deleteFileRecordPhash->prepare("DELETE FROM metadata WHERE phash=?"); - - _deleteFileRecordRecursively.reset(new QSqlQuery(_db)); - _deleteFileRecordRecursively->prepare("DELETE FROM metadata WHERE path LIKE(?||'/%')"); - - _blacklistQuery.reset(new QSqlQuery(_db)); - _blacklistQuery->prepare("SELECT lastTryEtag, lastTryModtime, retrycount, errorstring " - "FROM blacklist WHERE path=:path"); - } - return rc; -} - -void SyncJournalDb::close() -{ - QMutexLocker locker(&_mutex); - - commitTransaction(); - - _getFileRecordQuery.reset(0); - _setFileRecordQuery.reset(0); - _getDownloadInfoQuery.reset(0); - _setDownloadInfoQuery.reset(0); - _deleteDownloadInfoQuery.reset(0); - _getUploadInfoQuery.reset(0); - _setUploadInfoQuery.reset(0); - _deleteUploadInfoQuery.reset(0); - _deleteFileRecordPhash.reset(0); - _deleteFileRecordRecursively.reset(0); - _blacklistQuery.reset(0); - _possibleUpgradeFromMirall_1_5 = false; - - _db.close(); - _db = QSqlDatabase(); // avoid the warning QSqlDatabasePrivate::removeDatabase: connection [...] still in use - QSqlDatabase::removeDatabase(_dbFile); -} - - -bool SyncJournalDb::updateDatabaseStructure() -{ - QStringList columns = tableColumns("metadata"); - bool re = true; - - // check if the file_id column is there and create it if not - if( !checkConnect() ) { - return false; - } - if( columns.indexOf(QLatin1String("fileid")) == -1 ) { - - QSqlQuery query(_db); - query.prepare("ALTER TABLE metadata ADD COLUMN fileid VARCHAR(128);"); - re = query.exec(); - - query.prepare("CREATE INDEX metadata_file_id ON metadata(fileid);"); - re = re && query.exec(); - - commitInternal("update database structure"); - } - if( columns.indexOf(QLatin1String("remotePerm")) == -1 ) { - - QSqlQuery query(_db); - query.prepare("ALTER TABLE metadata ADD COLUMN remotePerm VARCHAR(128);"); - re = query.exec(); - commitInternal("update database structure (remotePerm"); - } - - return re; -} - -QStringList SyncJournalDb::tableColumns( const QString& table ) -{ - QStringList columns; - if( !table.isEmpty() ) { - - if( checkConnect() ) { - QString q = QString("PRAGMA table_info(%1);").arg(table); - QSqlQuery query(_db); - query.prepare(q); - - if(!query.exec()) { - QString err = query.lastError().text(); - qDebug() << "Error creating prepared statement: " << query.lastQuery() << ", Error:" << err;; - return columns; - } - - while( query.next() ) { - columns.append( query.value(1).toString() ); - } - } - } - qDebug() << "Columns in the current journal: " << columns; - - return columns; -} - -qint64 SyncJournalDb::getPHash(const QString& file) const -{ - QByteArray utf8File = file.toUtf8(); - int64_t h; - - if( file.isEmpty() ) { - return -1; - } - - int len = utf8File.length(); - - h = c_jhash64((uint8_t *) utf8File.data(), len, 0); - return h; -} - -bool SyncJournalDb::setFileRecord( const SyncJournalFileRecord& record ) -{ - QMutexLocker locker(&_mutex); - qlonglong phash = getPHash(record._path); - if( checkConnect() ) { - QByteArray arr = record._path.toUtf8(); - int plen = arr.length(); - - QString etag( record._etag ); - if( etag.isEmpty() ) etag = ""; - QString fileId( record._fileId); - if( fileId.isEmpty() ) fileId = ""; - QString remotePerm (record._remotePerm); - if (remotePerm.isEmpty()) remotePerm = QString(); // have NULL in DB (vs empty) - - _setFileRecordQuery->bindValue(0, QString::number(phash)); - _setFileRecordQuery->bindValue(1, plen); - _setFileRecordQuery->bindValue(2, record._path ); - _setFileRecordQuery->bindValue(3, record._inode ); - _setFileRecordQuery->bindValue(4, 0 ); // uid Not used - _setFileRecordQuery->bindValue(5, 0 ); // gid Not used - _setFileRecordQuery->bindValue(6, record._mode ); - _setFileRecordQuery->bindValue(7, QString::number(Utility::qDateTimeToTime_t(record._modtime))); - _setFileRecordQuery->bindValue(8, QString::number(record._type) ); - _setFileRecordQuery->bindValue(9, etag ); - _setFileRecordQuery->bindValue(10, fileId ); - _setFileRecordQuery->bindValue(11, remotePerm ); - - if( !_setFileRecordQuery->exec() ) { - qWarning() << "Error SQL statement setFileRecord: " << _setFileRecordQuery->lastQuery() << " :" - << _setFileRecordQuery->lastError().text(); - return false; - } - - qDebug() << _setFileRecordQuery->lastQuery() << phash << plen << record._path << record._inode - << record._mode - << QString::number(Utility::qDateTimeToTime_t(record._modtime)) << QString::number(record._type) - << record._etag << record._fileId << record._remotePerm; - _setFileRecordQuery->finish(); - - return true; - } else { - qDebug() << "Failed to connect database."; - return false; // checkConnect failed. - } -} - -bool SyncJournalDb::deleteFileRecord(const QString& filename, bool recursively) -{ - QMutexLocker locker(&_mutex); - - if( checkConnect() ) { - // if (!recursively) { - // always delete the actual file. - - qlonglong phash = getPHash(filename); - _deleteFileRecordPhash->bindValue( 0, QString::number(phash) ); - - if( !_deleteFileRecordPhash->exec() ) { - qWarning() << "Exec error of SQL statement: " - << _deleteFileRecordPhash->lastQuery() - << " : " << _deleteFileRecordPhash->lastError().text(); - return false; - } - qDebug() << _deleteFileRecordPhash->executedQuery() << phash << filename; - _deleteFileRecordPhash->finish(); - if( recursively) { - _deleteFileRecordRecursively->bindValue(0, filename); - if( !_deleteFileRecordRecursively->exec() ) { - qWarning() << "Exec error of SQL statement: " - << _deleteFileRecordRecursively->lastQuery() - << " : " << _deleteFileRecordRecursively->lastError().text(); - return false; - } - qDebug() << _deleteFileRecordRecursively->executedQuery() << filename; - _deleteFileRecordRecursively->finish(); - } - return true; - } else { - qDebug() << "Failed to connect database."; - return false; // checkConnect failed. - } -} - - -SyncJournalFileRecord SyncJournalDb::getFileRecord( const QString& filename ) -{ - QMutexLocker locker(&_mutex); - - qlonglong phash = getPHash( filename ); - SyncJournalFileRecord rec; - - if( checkConnect() ) { - _getFileRecordQuery->bindValue(":ph", QString::number(phash)); - - if (!_getFileRecordQuery->exec()) { - QString err = _getFileRecordQuery->lastError().text(); - qDebug() << "Error creating prepared statement: " << _getFileRecordQuery->lastQuery() << ", Error:" << err;; - return rec; - } - - if( _getFileRecordQuery->next() ) { - bool ok; - rec._path = _getFileRecordQuery->value(0).toString(); - rec._inode = _getFileRecordQuery->value(1).toInt(&ok); - //rec._uid = _getFileRecordQuery->value(2).toInt(&ok); Not Used - //rec._gid = _getFileRecordQuery->value(3).toInt(&ok); Not Used - rec._mode = _getFileRecordQuery->value(4).toInt(&ok); - rec._modtime = Utility::qDateTimeFromTime_t(_getFileRecordQuery->value(5).toLongLong(&ok)); - rec._type = _getFileRecordQuery->value(6).toInt(&ok); - rec._etag = _getFileRecordQuery->value(7).toByteArray(); - rec._fileId = _getFileRecordQuery->value(8).toByteArray(); - rec._remotePerm = _getFileRecordQuery->value(9).toByteArray(); - - _getFileRecordQuery->finish(); - } else { - QString err = _getFileRecordQuery->lastError().text(); - qDebug() << "No journal entry found for " << filename; - } - } - return rec; -} - -bool SyncJournalDb::postSyncCleanup(const QSet<QString> &items ) -{ - QMutexLocker locker(&_mutex); - - if( !checkConnect() ) { - return false; - } - - QSqlQuery query(_db); - query.prepare("SELECT phash, path FROM metadata order by path"); - - if (!query.exec()) { - QString err = query.lastError().text(); - qDebug() << "Error creating prepared statement: " << query.lastQuery() << ", Error:" << err;; - return false; - } - - QStringList superfluousItems; - - while(query.next()) { - const QString file = query.value(1).toString(); - bool contained = items.contains(file); - if( !contained ) { - superfluousItems.append(query.value(0).toString()); - } - } - - if( superfluousItems.count() ) { - QString sql = "DELETE FROM metadata WHERE phash in ("+ superfluousItems.join(",")+")"; - qDebug() << "Sync Journal cleanup: " << sql; - QSqlQuery delQuery(_db); - delQuery.prepare(sql); - if( !delQuery.exec() ) { - QString err = delQuery.lastError().text(); - qDebug() << "Error removing superfluous journal entries: " << delQuery.lastQuery() << ", Error:" << err;; - return false; - } - } - return true; -} - -int SyncJournalDb::getFileRecordCount() -{ - QMutexLocker locker(&_mutex); - - if( !checkConnect() ) { - return -1; - } - - QSqlQuery query(_db); - query.prepare("SELECT COUNT(*) FROM metadata"); - - if (!query.exec()) { - QString err = query.lastError().text(); - qDebug() << "Error creating prepared statement: " << query.lastQuery() << ", Error:" << err;; - return 0; - } - - if (query.next()) { - int count = query.value(0).toInt(); - return count; - } - - return 0; -} - -SyncJournalDb::DownloadInfo SyncJournalDb::getDownloadInfo(const QString& file) -{ - QMutexLocker locker(&_mutex); - - DownloadInfo res; - - if( checkConnect() ) { - _getDownloadInfoQuery->bindValue(":pa", file); - - if (!_getDownloadInfoQuery->exec()) { - QString err = _getDownloadInfoQuery->lastError().text(); - qDebug() << "Database error for file " << file << " : " << _getDownloadInfoQuery->lastQuery() << ", Error:" << err;; - return res; - } - - if( _getDownloadInfoQuery->next() ) { - bool ok = true; - res._tmpfile = _getDownloadInfoQuery->value(0).toString(); - res._etag = _getDownloadInfoQuery->value(1).toByteArray(); - res._errorCount = _getDownloadInfoQuery->value(2).toInt(&ok); - res._valid = ok; - } - _getDownloadInfoQuery->finish(); - } - return res; -} - -void SyncJournalDb::setDownloadInfo(const QString& file, const SyncJournalDb::DownloadInfo& i) -{ - QMutexLocker locker(&_mutex); - - if( !checkConnect() ) { - return; - } - - if (i._valid) { - _setDownloadInfoQuery->bindValue(0, file); - _setDownloadInfoQuery->bindValue(1, i._tmpfile); - _setDownloadInfoQuery->bindValue(2, i._etag ); - _setDownloadInfoQuery->bindValue(3, i._errorCount ); - - if( !_setDownloadInfoQuery->exec() ) { - qWarning() << "Exec error of SQL statement: " << _setDownloadInfoQuery->lastQuery() << " :" << _setDownloadInfoQuery->lastError().text(); - return; - } - - qDebug() << _setDownloadInfoQuery->lastQuery() << file << i._tmpfile << i._etag << i._errorCount; - _setDownloadInfoQuery->finish(); - - } else { - _deleteDownloadInfoQuery->bindValue( 0, file ); - - if( !_deleteDownloadInfoQuery->exec() ) { - qWarning() << "Exec error of SQL statement: " << _deleteDownloadInfoQuery->lastQuery() << " : " << _deleteDownloadInfoQuery->lastError().text(); - return; - } - qDebug() << _deleteDownloadInfoQuery->executedQuery() << file; - _deleteDownloadInfoQuery->finish(); - } -} - -SyncJournalDb::UploadInfo SyncJournalDb::getUploadInfo(const QString& file) -{ - QMutexLocker locker(&_mutex); - - UploadInfo res; - - if( checkConnect() ) { - - _getUploadInfoQuery->bindValue(":pa", file); - - if (!_getUploadInfoQuery->exec()) { - QString err = _getUploadInfoQuery->lastError().text(); - qDebug() << "Database error for file " << file << " : " << _getUploadInfoQuery->lastQuery() << ", Error:" << err; - return res; - } - - if( _getUploadInfoQuery->next() ) { - bool ok = true; - res._chunk = _getUploadInfoQuery->value(0).toInt(&ok); - res._transferid = _getUploadInfoQuery->value(1).toInt(&ok); - res._errorCount = _getUploadInfoQuery->value(2).toInt(&ok); - res._size = _getUploadInfoQuery->value(3).toLongLong(&ok); - res._modtime = Utility::qDateTimeFromTime_t(_getUploadInfoQuery->value(4).toLongLong(&ok)); - res._valid = ok; - } - _getUploadInfoQuery->finish(); - } - return res; -} - -void SyncJournalDb::setUploadInfo(const QString& file, const SyncJournalDb::UploadInfo& i) -{ - QMutexLocker locker(&_mutex); - - if( !checkConnect() ) { - return; - } - - if (i._valid) { - _setUploadInfoQuery->bindValue(0, file); - _setUploadInfoQuery->bindValue(1, i._chunk); - _setUploadInfoQuery->bindValue(2, i._transferid ); - _setUploadInfoQuery->bindValue(3, i._errorCount ); - _setUploadInfoQuery->bindValue(4, i._size ); - _setUploadInfoQuery->bindValue(5, Utility::qDateTimeToTime_t(i._modtime) ); - - if( !_setUploadInfoQuery->exec() ) { - qWarning() << "Exec error of SQL statement: " << _setUploadInfoQuery->lastQuery() << " :" << _setUploadInfoQuery->lastError().text(); - return; - } - - qDebug() << _setUploadInfoQuery->lastQuery() << file << i._chunk << i._transferid << i._errorCount; - _setUploadInfoQuery->finish(); - } else { - _deleteUploadInfoQuery->bindValue(0, file); - - if( !_deleteUploadInfoQuery->exec() ) { - qWarning() << "Exec error of SQL statement: " << _deleteUploadInfoQuery->lastQuery() << " : " << _deleteUploadInfoQuery->lastError().text(); - return; - } - qDebug() << _deleteUploadInfoQuery->executedQuery() << file; - _deleteUploadInfoQuery->finish(); - } -} - -SyncJournalBlacklistRecord SyncJournalDb::blacklistEntry( const QString& file ) -{ - QMutexLocker locker(&_mutex); - SyncJournalBlacklistRecord entry; - - if( file.isEmpty() ) return entry; - - // SELECT lastTryEtag, lastTryModtime, retrycount, errorstring - - if( checkConnect() ) { - _blacklistQuery->bindValue( ":path", file ); - if( _blacklistQuery->exec() ){ - if( _blacklistQuery->next() ) { - bool ok; - entry._lastTryEtag = _blacklistQuery->value(0).toByteArray(); - entry._lastTryModtime = _blacklistQuery->value(1).toLongLong(&ok); - entry._retryCount = _blacklistQuery->value(2).toInt(); - entry._errorString = _blacklistQuery->value(3).toString(); - entry._file = file; - } - } else { - qWarning() << "Exec error blacklist: " << _blacklistQuery->lastQuery() << " : " - << _blacklistQuery->lastError().text(); - } - _blacklistQuery->finish(); - } - - return entry; -} - -int SyncJournalDb::blackListEntryCount() -{ - int re = 0; - - QMutexLocker locker(&_mutex); - if( checkConnect() ) { - QSqlQuery query(_db); - if( ! query.exec("SELECT count(*) FROM blacklist") ) { - sqlFail("Count number of blacklist entries failed", query); - } - if( query.next() ) { - re = query.value(0).toInt(); - } - } - return re; -} - -int SyncJournalDb::wipeBlacklist() -{ - QMutexLocker locker(&_mutex); - if( checkConnect() ) { - QSqlQuery query(_db); - - query.prepare("DELETE FROM blacklist"); - - if( ! query.exec() ) { - sqlFail("Deletion of whole blacklist failed", query); - return -1; - } - return query.numRowsAffected(); - } - return -1; -} - -void SyncJournalDb::wipeBlacklistEntry( const QString& file ) -{ - QMutexLocker locker(&_mutex); - if( checkConnect() ) { - QSqlQuery query(_db); - - query.prepare("DELETE FROM blacklist WHERE path=:path"); - query.bindValue(":path", file); - if( ! query.exec() ) { - sqlFail("Deletion of blacklist item failed.", query); - } - } -} - -void SyncJournalDb::updateBlacklistEntry( const SyncJournalBlacklistRecord& item ) -{ - QMutexLocker locker(&_mutex); - QSqlQuery query(_db); - - if( !checkConnect() ) { - return; - } - - QString sql("SELECT retrycount FROM blacklist WHERE path=:path"); - - if( Utility::fsCasePreserving() ) { - // if the file system is case preserving we have to check the blacklist - // case insensitively - sql += QLatin1String(" COLLATE NOCASE"); - } - - query.prepare(sql); - query.bindValue(":path", item._file); - - if( !query.exec() ) { - qDebug() << "SQL exec blacklistitem failed:" << query.lastError().text(); - return; - } - - QSqlQuery iQuery(_db); - if( query.next() ) { - int retries = query.value(0).toInt(); - retries--; - if( retries < 0 ) retries = 0; - - iQuery.prepare( "UPDATE blacklist SET lastTryEtag = :etag, lastTryModtime = :modtime, " - "retrycount = :retries, errorstring = :errStr WHERE path=:path"); - iQuery.bindValue(":etag", item._lastTryEtag); - iQuery.bindValue(":modtime", QString::number(item._lastTryModtime)); - iQuery.bindValue(":retries", retries); - iQuery.bindValue(":errStr", item._errorString); - iQuery.bindValue(":path", item._file); - } else { - // there is no entry yet. - iQuery.prepare("INSERT INTO blacklist (path, lastTryEtag, lastTryModtime, retrycount, errorstring) " - "VALUES (:path, :lastEtag, :lastMTime, :retrycount, :errorstring);"); - - iQuery.bindValue(":path", item._file ); - iQuery.bindValue(":lastEtag", item._lastTryEtag); - iQuery.bindValue(":lastMTime", QString::number(item._lastTryModtime)); - iQuery.bindValue(":retrycount", item._retryCount); - iQuery.bindValue(":errorstring", item._errorString); - } - if( !iQuery.exec() ) { - qDebug() << "SQL exec blacklistitem insert/update failed: "<< iQuery.lastError().text(); - } - -} - -void SyncJournalDb::avoidRenamesOnNextSync(const QString& path) -{ - QMutexLocker locker(&_mutex); - - if( !checkConnect() ) { - return; - } - - QSqlQuery query(_db); - query.prepare("UPDATE metadata SET fileid = '', inode = '0' WHERE path == ? OR path LIKE(?||'/%')"); - query.bindValue(0, path); - query.bindValue(1, path); - if( !query.exec() ) { - qDebug() << "SQL error in avoidRenamesOnNextSync: "<< query.lastError().text(); - } else { - qDebug() << query.executedQuery() << path; - } -} - -void SyncJournalDb::avoidReadFromDbOnNextSync(const QString& fileName) -{ - //Make sure that on the next sync, filName is not read from the DB but use the PROPFIND to - //get the info from the server - // We achieve that by clearing the etag of the parents directory recursively - - QMutexLocker locker(&_mutex); - - if( !checkConnect() ) { - return; - } - - QSqlQuery query(_db); - // This query will match entries for whitch the path is a prefix of fileName - query.prepare("UPDATE metadata SET md5='_invalid_' WHERE ? LIKE(path||'/%') AND type == 2"); // CSYNC_FTW_TYPE_DIR == 2 - query.bindValue(0, fileName); - if( !query.exec() ) { - qDebug() << "SQL error in avoidRenamesOnNextSync: "<< query.lastError().text(); - } else { - qDebug() << query.executedQuery() << fileName; - } -} - -void SyncJournalDb::commit(const QString& context, bool startTrans) -{ - QMutexLocker lock(&_mutex); - commitInternal(context, startTrans); -} - - -void SyncJournalDb::commitInternal(const QString& context, bool startTrans ) -{ - qDebug() << "Transaction Start " << context; - commitTransaction(); - - if( startTrans ) { - startTransaction(); - } -} - -SyncJournalDb::~SyncJournalDb() -{ - close(); -} - -bool SyncJournalDb::isConnected() -{ - QMutexLocker lock(&_mutex); - return checkConnect(); -} - -bool SyncJournalDb::isUpdateFrom_1_5() -{ - QMutexLocker lock(&_mutex); - checkConnect(); - return _possibleUpgradeFromMirall_1_5; -} - - - -} // namespace Mirall diff --git a/src/mirall/syncjournaldb.h b/src/mirall/syncjournaldb.h deleted file mode 100644 index bf11f11c6..000000000 --- a/src/mirall/syncjournaldb.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 SYNCJOURNALDB_H -#define SYNCJOURNALDB_H - -#include <QObject> -#include <qmutex.h> -#include <QDateTime> -#include <QSqlDatabase> -#include <QHash> -#include <QSqlQuery> - -#include "utility.h" - -namespace Mirall { -class SyncJournalFileRecord; -class SyncJournalBlacklistRecord; - -/** - * Class that handle the sync database - * - * This class is thread safe. All public function are locking the mutex. - */ -class OWNCLOUDSYNC_EXPORT SyncJournalDb : public QObject -{ - Q_OBJECT -public: - explicit SyncJournalDb(const QString& path, QObject *parent = 0); - virtual ~SyncJournalDb(); - SyncJournalFileRecord getFileRecord( const QString& filename ); - bool setFileRecord( const SyncJournalFileRecord& record ); - bool deleteFileRecord( const QString& filename, bool recursively = false ); - int getFileRecordCount(); - bool exists(); - - void updateBlacklistEntry( const SyncJournalBlacklistRecord& item ); - void wipeBlacklistEntry(const QString& file); - int wipeBlacklist(); - int blackListEntryCount(); - - struct DownloadInfo { - DownloadInfo() : _errorCount(0), _valid(false) {} - QString _tmpfile; - QByteArray _etag; - int _errorCount; - bool _valid; - }; - struct UploadInfo { - UploadInfo() : _chunk(0), _transferid(0), _size(0), _errorCount(0), _valid(false) {} - int _chunk; - int _transferid; - quint64 _size; //currently unused - QDateTime _modtime; - int _errorCount; - bool _valid; - }; - - DownloadInfo getDownloadInfo(const QString &file); - void setDownloadInfo(const QString &file, const DownloadInfo &i); - UploadInfo getUploadInfo(const QString &file); - void setUploadInfo(const QString &file, const UploadInfo &i); - SyncJournalBlacklistRecord blacklistEntry( const QString& ); - void avoidRenamesOnNextSync(const QString &path); - - /** - * Make sure that on the next sync, filName is not read from the DB but use the PROPFIND to - * get the info from the server - */ - void avoidReadFromDbOnNextSync(const QString& fileName); - - bool postSyncCleanup( const QSet<QString>& items ); - - /* Because sqlite transactions is really slow, we encapsulate everything in big transactions - * Commit will actually commit the transaction and create a new one. - */ - void commit(const QString &context, bool startTrans = true); - - void close(); - - /** - * return true if everything is correct - */ - bool isConnected(); - - /** - * Tell the sync engine if we need to disable the fetch from db to be sure that the fileid - * are updated. - */ - bool isUpdateFrom_1_5(); - - - - -signals: - -public slots: - -private: - qint64 getPHash(const QString& ) const; - bool updateDatabaseStructure(); - bool sqlFail(const QString& log, const QSqlQuery &query ); - void commitInternal(const QString &context, bool startTrans = true); - void startTransaction(); - void commitTransaction(); - QStringList tableColumns( const QString& table ); - bool checkConnect(); - - QSqlDatabase _db; - QString _dbFile; - QMutex _mutex; // Public functions are protected with the mutex. - int _transaction; - bool _possibleUpgradeFromMirall_1_5; - QScopedPointer<QSqlQuery> _getFileRecordQuery; - QScopedPointer<QSqlQuery> _setFileRecordQuery; - QScopedPointer<QSqlQuery> _getDownloadInfoQuery; - QScopedPointer<QSqlQuery> _setDownloadInfoQuery; - QScopedPointer<QSqlQuery> _deleteDownloadInfoQuery; - QScopedPointer<QSqlQuery> _getUploadInfoQuery; - QScopedPointer<QSqlQuery> _setUploadInfoQuery; - QScopedPointer<QSqlQuery> _deleteUploadInfoQuery; - QScopedPointer<QSqlQuery> _deleteFileRecordPhash; - QScopedPointer<QSqlQuery> _deleteFileRecordRecursively; - QScopedPointer<QSqlQuery> _blacklistQuery; -}; - -} // namespace Mirall -#endif // SYNCJOURNALDB_H diff --git a/src/mirall/syncjournalfilerecord.cpp b/src/mirall/syncjournalfilerecord.cpp deleted file mode 100644 index f29ec8876..000000000 --- a/src/mirall/syncjournalfilerecord.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 "syncjournalfilerecord.h" -#include "syncfileitem.h" -#include "utility.h" - -#include <qfileinfo.h> -#include <qdebug.h> - -#ifdef Q_OS_WIN -#include <windows.h> -#else -#include <sys/stat.h> -#endif - -namespace Mirall { - -SyncJournalFileRecord::SyncJournalFileRecord() - :_inode(0), _type(0), _mode(0) -{ -} - -SyncJournalFileRecord::SyncJournalFileRecord(const SyncFileItem &item, const QString &localFileName) - : _path(item._file), _modtime(Utility::qDateTimeFromTime_t(item._modtime)), - _type(item._type), _etag(item._etag), _fileId(item._fileId), _remotePerm(item._remotePerm), - _mode(0) -{ - // use the "old" inode coming with the item for the case where the - // filesystem stat fails. That can happen if the the file was removed - // or renamed meanwhile. For the rename case we still need the inode to - // detect the rename tough. - _inode = item._inode; - -#ifdef Q_OS_WIN - /* Query the inode: - based on code from csync_vio_local.c (csync_vio_local_stat) - Get the Windows file id as an inode replacement. */ - HANDLE h = CreateFileW( (wchar_t*)localFileName.utf16(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL+FILE_FLAG_BACKUP_SEMANTICS, NULL ); - - if( h == INVALID_HANDLE_VALUE ) { - qWarning() << "Failed to query the 'inode' because CreateFileW failed for file " << localFileName; - } else { - BY_HANDLE_FILE_INFORMATION fileInfo; - - if( GetFileInformationByHandle( h, &fileInfo ) ) { - ULARGE_INTEGER FileIndex; - FileIndex.HighPart = fileInfo.nFileIndexHigh; - FileIndex.LowPart = fileInfo.nFileIndexLow; - FileIndex.QuadPart &= 0x0000FFFFFFFFFFFF; - - /* printf("Index: %I64i\n", FileIndex.QuadPart); */ - - _inode = FileIndex.QuadPart; - } else { - qWarning() << "Failed to query the 'inode' for file " << localFileName; - - } - CloseHandle(h); - } -#else - struct stat sb; - if( stat(QFile::encodeName(localFileName).constData(), &sb) < 0) { - qWarning() << "Failed to query the 'inode' for file " << localFileName; - } else { - _inode = sb.st_ino; - } -#endif - -} - -SyncJournalBlacklistRecord::SyncJournalBlacklistRecord(const SyncFileItem& item, int retries) - :_retryCount(retries), _errorString(item._errorString), _lastTryModtime(item._modtime) - , _lastTryEtag(item._etag), _file(item._file) -{ - -} - -} diff --git a/src/mirall/syncjournalfilerecord.h b/src/mirall/syncjournalfilerecord.h deleted file mode 100644 index 7ba8c3b45..000000000 --- a/src/mirall/syncjournalfilerecord.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 SYNCJOURNALFILERECORD_H -#define SYNCJOURNALFILERECORD_H - -#include <QString> -#include <QDateTime> - -namespace Mirall { - -class SyncFileItem; - -class SyncJournalFileRecord -{ -public: - SyncJournalFileRecord(); - SyncJournalFileRecord(const SyncFileItem&, const QString &localFileName); - - bool isValid() { - return !_path.isEmpty(); - } - - QString _path; - quint64 _inode; - QDateTime _modtime; - int _type; - QByteArray _etag; - QByteArray _fileId; - QByteArray _remotePerm; - int _mode; -}; - -class SyncJournalBlacklistRecord -{ -public: - SyncJournalBlacklistRecord() : _retryCount(0), _lastTryModtime(0) { } - - SyncJournalBlacklistRecord(const SyncFileItem&, int retries); - - // query("SELECT path, inode, uid, gid, mode, modtime, type, md5 FROM metadata WHERE phash=:phash"); - int _retryCount; - QString _errorString; - time_t _lastTryModtime; - QByteArray _lastTryEtag; - QString _file; - - bool isValid() { return(_lastTryEtag.length() > 0 || _lastTryModtime > 0); } -}; - -} - -#endif // SYNCJOURNALFILERECORD_H diff --git a/src/mirall/syncresult.cpp b/src/mirall/syncresult.cpp deleted file mode 100644 index b10a1a459..000000000 --- a/src/mirall/syncresult.cpp +++ /dev/null @@ -1,152 +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. - */ - -#include "mirall/syncresult.h" - -namespace Mirall -{ - -SyncResult::SyncResult() - : _status( Undefined ), - _warnCount(0) -{ -} - -SyncResult::SyncResult(SyncResult::Status status ) - : _status(status), - _warnCount(0) -{ -} - -SyncResult::Status SyncResult::status() const -{ - return _status; -} - -QString SyncResult::statusString() const -{ - QString re; - Status stat = status(); - - switch( stat ){ - case Undefined: - re = QLatin1String("Undefined"); - break; - case NotYetStarted: - re = QLatin1String("Not yet Started"); - break; - case SyncRunning: - re = QLatin1String("Sync Running"); - break; - case Success: - re = QLatin1String("Success"); - break; - case Error: - re = QLatin1String("Error"); - break; - case SetupError: - re = QLatin1String("SetupError"); - break; - case SyncPrepare: - re = QLatin1String("SyncPrepare"); - break; - case Problem: - re = QLatin1String("Success, some files were ignored."); - break; - case Unavailable: - re = QLatin1String("Not availabe"); - break; - case SyncAbortRequested: - re = QLatin1String("Sync Request aborted by user"); - break; - case Paused: - re = QLatin1String("Sync Paused"); - break; - } - return re; -} - -void SyncResult::setStatus( Status stat ) -{ - _status = stat; - _syncTime = QDateTime::currentDateTime(); -} - -void SyncResult::setSyncFileItemVector( const SyncFileItemVector& items ) -{ - _syncItems = items; -} - -SyncFileItemVector SyncResult::syncFileItemVector() const -{ - return _syncItems; -} - -QDateTime SyncResult::syncTime() const -{ - return _syncTime; -} - -void SyncResult::setWarnCount(int wc) -{ - _warnCount = wc; -} - -int SyncResult::warnCount() const -{ - return _warnCount; -} - -void SyncResult::setErrorStrings( const QStringList& list ) -{ - _errors = list; -} - -QStringList SyncResult::errorStrings() const -{ - return _errors; -} - -void SyncResult::setErrorString( const QString& err ) -{ - _errors.append( err ); -} - -QString SyncResult::errorString() const -{ - if( _errors.isEmpty() ) return QString::null; - return _errors.first(); -} - -void SyncResult::clearErrors() -{ - _errors.clear(); -} - -void SyncResult::setFolder(const QString& folder) -{ - _folder = folder; -} - -QString SyncResult::folder() const -{ - return _folder; -} - -SyncResult::~SyncResult() -{ - -} - -} // ns mirall diff --git a/src/mirall/syncresult.h b/src/mirall/syncresult.h deleted file mode 100644 index 3350eda72..000000000 --- a/src/mirall/syncresult.h +++ /dev/null @@ -1,82 +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_SYNCRESULT_H -#define MIRALL_SYNCRESULT_H - -#include <QStringList> -#include <QHash> -#include <QDateTime> - -#include "owncloudlib.h" -#include "mirall/syncfileitem.h" - -namespace Mirall -{ - -class OWNCLOUDSYNC_EXPORT SyncResult -{ -public: - enum Status - { - Undefined, - NotYetStarted, - SyncPrepare, - SyncRunning, - SyncAbortRequested, - Success, - Problem, - Error, - SetupError, - Paused, - Unavailable - }; - - SyncResult(); - SyncResult( Status status ); - ~SyncResult(); - void setErrorString( const QString& ); - void setErrorStrings( const QStringList& ); - QString errorString() const; - QStringList errorStrings() const; - int warnCount() const; - void setWarnCount(int wc); - void clearErrors(); - - // handle a list of changed items. - void setSyncFileItemVector( const SyncFileItemVector& ); - SyncFileItemVector syncFileItemVector() const; - - void setStatus( Status ); - Status status() const; - QString statusString() const; - QDateTime syncTime() const; - void setFolder(const QString& folder); - QString folder() const; - -private: - Status _status; - SyncFileItemVector _syncItems; - QDateTime _syncTime; - QString _folder; - /** - * when the sync tool support this... - */ - QStringList _errors; - int _warnCount; -}; - -} - -#endif diff --git a/src/mirall/syncrunfilelog.cpp b/src/mirall/syncrunfilelog.cpp deleted file mode 100644 index 908406c4b..000000000 --- a/src/mirall/syncrunfilelog.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 <QRegExp> - -#include "mirall/syncrunfilelog.h" -#include "mirall/utility.h" -#include "filesystem.h" -#include <qfileinfo.h> - -namespace Mirall { - -SyncRunFileLog::SyncRunFileLog() -{ -} - -QString SyncRunFileLog::dateTimeStr( const QDateTime& dt ) -{ - return dt.toString(Qt::ISODate); -} - -QString SyncRunFileLog::directionToStr( SyncFileItem::Direction dir ) -{ - QString re("N"); - if( dir == SyncFileItem::Up ) { - re = QLatin1String("Up"); - } else if( dir == SyncFileItem::Down ) { - re = QLatin1String("Down"); - } - return re; -} - -QString SyncRunFileLog::instructionToStr( csync_instructions_e inst ) -{ - QString re; - - switch( inst ) { - case CSYNC_INSTRUCTION_NONE: - re = "INST_NONE"; - break; - case CSYNC_INSTRUCTION_EVAL: - re = "INST_EVAL"; - break; - case CSYNC_INSTRUCTION_REMOVE: - re = "INST_REMOVE"; - break; - case CSYNC_INSTRUCTION_RENAME: - re = "INST_RENAME"; - break; - case CSYNC_INSTRUCTION_EVAL_RENAME: - re = "INST_EVAL_RENAME"; - break; - case CSYNC_INSTRUCTION_NEW: - re = "INST_NEW"; - break; - case CSYNC_INSTRUCTION_CONFLICT: - re = "INST_CONFLICT"; - break; - case CSYNC_INSTRUCTION_IGNORE: - re = "INST_IGNORE"; - break; - case CSYNC_INSTRUCTION_SYNC: - re = "INST_SYNC"; - break; - case CSYNC_INSTRUCTION_STAT_ERROR: - re = "INST_STAT_ERR"; - break; - case CSYNC_INSTRUCTION_ERROR: - re = "INST_ERROR"; - break; - } - - return re; -} - - -void SyncRunFileLog::start(const QString &folderPath, const Utility::StopWatch &stopWatch ) -{ - const qint64 logfileMaxSize = 1024*1024; // 1MiB - - // Note; this name is ignored in csync_exclude.c - const QString filename = folderPath + QLatin1String(".owncloudsync.log"); - - // When the file is too big, just rename it to an old name. - QFileInfo info(filename); - bool exists = info.exists(); - if (exists && info.size() > logfileMaxSize) { - exists = false; - QString newFilename = filename + QLatin1String(".1"); - QFile::remove(newFilename); - QFile::rename(filename, newFilename); - } - _file.reset(new QFile(filename)); - - _file->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text); - _out.setDevice( _file.data() ); - - QDateTime dt = stopWatch.startTime(); - QDateTime de = stopWatch.timeOfLap(QLatin1String("Sync Finished")); - - if (!exists) { - // We are creating a new file, add the note. - _out << "# timestamp | duration | file | instruction | dir | modtime | etag | " - "size | fileId | status | errorString | http result code | " - "other size | other modtime | other etag | other fileId | " - "other instruction" << endl; - - FileSystem::setFileHidden(filename, true); - } - - - _out << "#=#=#=# Syncrun started " << dateTimeStr(dt) << " until " << dateTimeStr(de) << " (" - << stopWatch.durationOfLap(QLatin1String("Sync Finished")) << " msec)" << endl; -} - -void SyncRunFileLog::logItem( const SyncFileItem& item ) -{ - // don't log the directory items that are in the list - if( item._direction == SyncFileItem::None ) { - return; - } - QString ts = item._responseTimeStamp; - if( ts.length() > 6 ) { - QRegExp rx("(\\d\\d:\\d\\d:\\d\\d)"); - if( ts.contains(rx) ) { - ts = rx.cap(0); - } - } - - const QChar L = QLatin1Char('|'); - _out << ts << L; - _out << QString::number(item._requestDuration) << L; - _out << item._file << L; - _out << instructionToStr( item.log._instruction ) << L; - _out << directionToStr( item._direction ) << L; - _out << QString::number(item.log._modtime) << L; - _out << item.log._etag << L; - _out << QString::number(item.log._size) << L; - _out << item.log._fileId << L; - _out << item._status << L; - _out << item._errorString << L; - _out << QString::number(item._httpErrorCode) << L; - _out << QString::number(item.log._other_size) << L; - _out << QString::number(item.log._other_modtime) << L; - _out << item.log._other_etag << L; - _out << item.log._other_fileId << L; - _out << instructionToStr(item.log._other_instruction) << L; - - _out << endl; -} - -void SyncRunFileLog::close() -{ - _file->close(); -} - -} diff --git a/src/mirall/syncrunfilelog.h b/src/mirall/syncrunfilelog.h deleted file mode 100644 index eb6dd5e4f..000000000 --- a/src/mirall/syncrunfilelog.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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; version 2 of the License. - * - * 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 SYNCRUNFILELOG_H -#define SYNCRUNFILELOG_H - -#include <QFile> -#include <QTextStream> -#include <QScopedPointer> - -#include "mirall/syncfileitem.h" -#include "mirall/utility.h" - -namespace Mirall { -class SyncFileItem; - -class SyncRunFileLog -{ -public: - SyncRunFileLog(); - void start( const QString& folderPath, const Utility::StopWatch& stopWatch ); - void logItem( const SyncFileItem& item ); - void close(); - -protected: - -private: - QString dateTimeStr( const QDateTime& dt ); - QString instructionToStr( csync_instructions_e inst ); - QString directionToStr( SyncFileItem::Direction dir ); - - QScopedPointer<QFile> _file; - QTextStream _out; - -}; -} - -#endif // SYNCRUNFILELOG_H diff --git a/src/mirall/systray.cpp b/src/mirall/systray.cpp deleted file mode 100644 index 617d1408b..000000000 --- a/src/mirall/systray.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) by Cédric Bellegarde <gnumdk@gmail.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. - */ - -#include "systray.h" -#include "mirall/theme.h" - -#ifdef USE_FDO_NOTIFICATIONS -#include <QDBusConnection> -#include <QDBusInterface> -#include <QDBusMessage> -#include <QDBusPendingCall> -#define NOTIFICATIONS_SERVICE "org.freedesktop.Notifications" -#define NOTIFICATIONS_PATH "/org/freedesktop/Notifications" -#define NOTIFICATIONS_IFACE "org.freedesktop.Notifications" -#endif - -namespace Mirall { - -void Systray::showMessage(const QString & title, const QString & message, MessageIcon icon, int millisecondsTimeoutHint) -{ - -#ifdef USE_FDO_NOTIFICATIONS - if(QDBusInterface(NOTIFICATIONS_SERVICE, NOTIFICATIONS_PATH, NOTIFICATIONS_IFACE).isValid()) { - QList<QVariant> args = QList<QVariant>() << "owncloud" << quint32(0) << "owncloud" - << title << message << QStringList () << QVariantMap() << qint32(-1); - QDBusMessage method = QDBusMessage::createMethodCall(NOTIFICATIONS_SERVICE, NOTIFICATIONS_PATH, NOTIFICATIONS_IFACE, "Notify"); - method.setArguments(args); - QDBusConnection::sessionBus().asyncCall(method); - } else -#endif - { - QSystemTrayIcon::showMessage(title, message, icon, millisecondsTimeoutHint); - } -} - -void Systray::setToolTip(const QString &tip) -{ - QSystemTrayIcon::setToolTip(tr("%1: %2").arg(Theme::instance()->appNameGUI(), tip)); -} - -} // namespace Mirall diff --git a/src/mirall/systray.h b/src/mirall/systray.h deleted file mode 100644 index 827f7c020..000000000 --- a/src/mirall/systray.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) by Cédric Bellegarde <gnumdk@gmail.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. - */ - -#ifndef SYSTRAY_H -#define SYSTRAY_H - -#include <QSystemTrayIcon> - -class QIcon; - -namespace Mirall { - -class Systray : public QSystemTrayIcon -{ - Q_OBJECT -public: - void showMessage(const QString & title, const QString & message, MessageIcon icon = Information, int millisecondsTimeoutHint = 10000); - void setToolTip(const QString &tip); -}; - -} // namespace Mirall - -#endif //SYSTRAY_H diff --git a/src/mirall/theme.cpp b/src/mirall/theme.cpp deleted file mode 100644 index f69d327ab..000000000 --- a/src/mirall/theme.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/* - * 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. - */ - -#include "theme.h" -#include "version.h" -#include "config.h" - -#include <QtCore> -#ifndef TOKEN_AUTH_ONLY -#include <QtGui> -#endif - -#include "mirall/owncloudtheme.h" - -#ifdef THEME_INCLUDE -# define QUOTEME(M) #M -# define INCLUDE_FILE(M) QUOTEME(M) -# include INCLUDE_FILE(THEME_INCLUDE) -#endif - -namespace Mirall { - -Theme* Theme::_instance = 0; - -Theme* Theme::instance() { - if (!_instance) { - _instance = new THEME_CLASS; - // some themes may not call the base ctor - _instance->_mono = false; - } - return _instance; -} - -QString Theme::statusHeaderText( SyncResult::Status status ) const -{ - QString resultStr; - - switch( status ) { - case SyncResult::Undefined: - resultStr = QCoreApplication::translate("theme", "Status undefined"); - break; - case SyncResult::NotYetStarted: - resultStr = QCoreApplication::translate("theme", "Waiting to start sync"); - break; - case SyncResult::SyncRunning: - resultStr = QCoreApplication::translate("theme", "Sync is running"); - break; - case SyncResult::Success: - resultStr = QCoreApplication::translate("theme", "Sync Success"); - break; - case SyncResult::Problem: - resultStr = QCoreApplication::translate("theme", "Sync Success, some files were ignored."); - break; - case SyncResult::Error: - resultStr = QCoreApplication::translate("theme", "Sync Error"); - break; - case SyncResult::SetupError: - resultStr = QCoreApplication::translate("theme", "Setup Error" ); - break; - case SyncResult::Unavailable: - resultStr = QCoreApplication::translate("theme", "The server is currently unavailable" ); - break; - case SyncResult::SyncPrepare: - resultStr = QCoreApplication::translate("theme", "Preparing to sync" ); - break; - case SyncResult::SyncAbortRequested: - resultStr = QCoreApplication::translate("theme", "Aborting..." ); - break; - case SyncResult::Paused: - resultStr = QCoreApplication::translate("theme", "Sync is paused"); - break; - } - return resultStr; -} - -QString Theme::appNameGUI() const -{ - return QLatin1String(APPLICATION_NAME); -} - -QString Theme::appName() const -{ - return QLatin1String(APPLICATION_SHORTNAME); -} - -QString Theme::version() const -{ - return QString::fromLocal8Bit( MIRALL_STRINGIFY( MIRALL_VERSION )); -} - -#ifndef TOKEN_AUTH_ONLY - -QIcon Theme::trayFolderIcon( const QString& backend ) const -{ - Q_UNUSED(backend) - return applicationIcon(); -} - -/* - * helper to load a icon from either the icon theme the desktop provides or from - * the apps Qt resources. - */ -QIcon Theme::themeIcon( const QString& name, bool sysTray ) const -{ - QString flavor; - if (sysTray) { - flavor = systrayIconFlavor(_mono); - } else { - flavor = QLatin1String("colored"); - } - - QIcon icon; - if( QIcon::hasThemeIcon( name )) { - // use from theme - icon = QIcon::fromTheme( name ); - } else { - QList<int> sizes; - sizes <<16 << 22 << 32 << 48 << 64 << 128; - foreach (int size, sizes) { - QString pixmapName = QString::fromLatin1(":/mirall/theme/%1/%2-%3.png").arg(flavor).arg(name).arg(size); - if (QFile::exists(pixmapName)) { - QPixmap px(pixmapName); - // HACK, get rid of it by supporting FDO icon themes, this is really just emulating ubuntu-mono - if (qgetenv("DESKTOP_SESSION") == "ubuntu") { - QBitmap mask = px.createMaskFromColor(Qt::white, Qt::MaskOutColor); - QPainter p(&px); - p.setPen(QColor("#dfdbd2")); - p.drawPixmap(px.rect(), mask, mask.rect()); - } - icon.addPixmap(px); - } - } - if (icon.isNull()) { - foreach (int size, sizes) { - QString pixmapName = QString::fromLatin1(":/mirall/resources/%1-%2.png").arg(name).arg(size); - if (QFile::exists(pixmapName)) { - icon.addFile(pixmapName); - } - } - } - } - return icon; -} - -Theme::Theme() : - QObject(0) - ,_mono(false) -{ - -} -#endif - -// if this option return true, the client only supports one folder to sync. -// The Add-Button is removed accoringly. -bool Theme::singleSyncFolder() const { - return false; -} - -QString Theme::defaultServerFolder() const -{ - return QLatin1String("/"); -} - -QString Theme::overrideServerUrl() const -{ - return QString::null; -} - -QString Theme::defaultClientFolder() const -{ - return appName(); -} - -QString Theme::systrayIconFlavor(bool mono) const -{ - QString flavor; - if (mono) { -#ifdef Q_OS_MAC - flavor = QLatin1String("black"); -#else - flavor = QLatin1String("white"); -#endif - } else { - flavor = QLatin1String("colored"); - } - return flavor; -} - -void Theme::setSystrayUseMonoIcons(bool mono) -{ - _mono = mono; - emit systrayUseMonoIconsChanged(mono); -} - -bool Theme::systrayUseMonoIcons() const -{ - return _mono; -} - -QString Theme::updateCheckUrl() const -{ - return QLatin1String("https://updates.owncloud.com/client/"); -} - -QString Theme::about() const -{ - return tr("<p>Version %1 For more information please visit <a href='%2'>%3</a>.</p>" - "<p>Copyright ownCloud, Inc.<p>" - "<p>Distributed by %4 and licensed under the GNU General Public License (GPL) Version 2.0.<br>" - "%5 and the %5 logo are registered trademarks of %4 in the<br>" - "United States, other countries, or both.</p>") - .arg(MIRALL_VERSION_STRING).arg("http://" MIRALL_STRINGIFY(APPLICATION_DOMAIN)) - .arg(MIRALL_STRINGIFY(APPLICATION_DOMAIN)).arg(APPLICATION_VENDOR).arg(APPLICATION_NAME); -} - -#ifndef TOKEN_AUTH_ONLY -QVariant Theme::customMedia( CustomMediaType type ) -{ - QVariant re; - QString key; - - switch ( type ) - { - case oCSetupTop: - key = QLatin1String("oCSetupTop"); - break; - case oCSetupSide: - key = QLatin1String("oCSetupSide"); - break; - case oCSetupBottom: - key = QLatin1String("oCSetupBottom"); - break; - case oCSetupResultTop: - key = QLatin1String("oCSetupResultTop"); - break; - } - - QString imgPath = QString::fromLatin1(":/mirall/theme/colored/%1.png").arg(key); - if ( QFile::exists( imgPath ) ) { - QPixmap pix( imgPath ); - if( pix.isNull() ) { - // pixmap loading hasn't succeeded. We take the text instead. - re.setValue( key ); - } else { - re.setValue( pix ); - } - } - return re; -} - -QIcon Theme::syncStateIcon( SyncResult::Status status, bool sysTray ) const -{ - // FIXME: Mind the size! - QString statusIcon; - - switch( status ) { - case SyncResult::Undefined: - case SyncResult::NotYetStarted: - case SyncResult::Unavailable: - statusIcon = QLatin1String("state-offline"); - break; - case SyncResult::SyncRunning: - statusIcon = QLatin1String("state-sync"); - break; - case SyncResult::SyncAbortRequested: - case SyncResult::Paused: - statusIcon = QLatin1String("state-pause"); - break; - case SyncResult::SyncPrepare: - case SyncResult::Success: - statusIcon = QLatin1String("state-ok"); - break; - case SyncResult::Problem: - statusIcon = QLatin1String("state-information"); - break; - case SyncResult::Error: - case SyncResult::SetupError: - statusIcon = QLatin1String("state-error"); // FIXME: Use state-problem once we have an icon. - default: - statusIcon = QLatin1String("state-error"); - } - - return themeIcon( statusIcon, sysTray ); -} - -QColor Theme::wizardHeaderTitleColor() const -{ - return qApp->palette().text().color(); -} - -QColor Theme::wizardHeaderBackgroundColor() const -{ - return QColor(); -} - -QPixmap Theme::wizardHeaderLogo() const -{ - return applicationIcon().pixmap(64); -} - -QPixmap Theme::wizardHeaderBanner() const -{ - QColor c = wizardHeaderBackgroundColor(); - if (!c.isValid()) - return QPixmap(); - - QPixmap pix(QSize(600, 78)); - pix.fill(wizardHeaderBackgroundColor()); - return pix; -} -#endif - -} // end namespace mirall - diff --git a/src/mirall/theme.h b/src/mirall/theme.h deleted file mode 100644 index 7f8166e6c..000000000 --- a/src/mirall/theme.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * 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. - */ - -#ifndef _THEME_H -#define _THEME_H - -#include "mirall/syncresult.h" - - -class QIcon; -class QString; -class QObject; -class QPixmap; -class QColor; - -namespace Mirall { - -class SyncResult; - -class OWNCLOUDSYNC_EXPORT Theme : public QObject -{ - Q_OBJECT -public: - enum CustomMediaType { - oCSetupTop, // ownCloud connect page - oCSetupSide, - oCSetupBottom, - oCSetupResultTop // ownCloud connect result page - }; - - /* returns a singleton instance. */ - static Theme* instance(); - - /** - * @brief appNameGUI - Human readable application name. - * - * Use and redefine this if the human readable name contains spaces, - * special chars and such. - * - * By default, the name is derived from the APPLICATION_NAME - * cmake variable. - * - * @return QString with human readable app name. - */ - virtual QString appNameGUI() const; - - /** - * @brief appName - Application name (short) - * - * Use and redefine this as an application name. Keep it straight as - * it is used for config files etc. If you need a more sophisticated - * name in the GUI, redefine appNameGUI. - * - * By default, the name is derived from the APPLICATION_SHORTNAME - * cmake variable, and should be the same. This method is only - * reimplementable for legacy reasons. - * - * Warning: Do not modify this value, as many things, e.g. settings - * depend on it! You most likely want to modify \ref appNameGUI(). - * - * @return QString with app name. - */ - virtual QString appName() const; - - /** - * @brief configFileName - * @return the name of the config file. - */ - virtual QString configFileName() const = 0; - -#ifndef TOKEN_AUTH_ONLY - /** - * the icon that is shown in the tray context menu left of the folder name - */ - virtual QIcon trayFolderIcon( const QString& ) const; - - /** - * get an sync state icon - */ - virtual QIcon syncStateIcon( SyncResult::Status, bool sysTray = false ) const; - - virtual QIcon folderDisabledIcon() const = 0; - virtual QIcon applicationIcon() const = 0; -#endif - - virtual QString statusHeaderText( SyncResult::Status ) const; - virtual QString version() const; - - /** - * Characteristics: bool if more than one sync folder is allowed - */ - virtual bool singleSyncFolder() const; - - /** - * URL to help file - */ - virtual QString helpUrl() const { return QString::null; } - - /** - * Setting a value here will pre-define the server url. - * - * The respective UI controls will be disabled - */ - virtual QString overrideServerUrl() const; - - /** - * The default folder name without path on the server at setup time. - */ - virtual QString defaultServerFolder() const; - - /** - * The default folder name without path on the client side at setup time. - */ - virtual QString defaultClientFolder() const; - - /** - * Override to encforce a particular locale, i.e. "de" or "pt_BR" - */ - virtual QString enforcedLocale() const { return QString::null; } - - /** colored, white or black */ - QString systrayIconFlavor(bool mono) const; - -#ifndef TOKEN_AUTH_ONLY - /** - * Override to use a string or a custom image name. - * The default implementation will try to look up - * :/mirall/theme/<type>.png - */ - virtual QVariant customMedia( CustomMediaType type ); - - /** @return color for the setup wizard */ - virtual QColor wizardHeaderTitleColor() const; - - /** @return color for the setup wizard. */ - virtual QColor wizardHeaderBackgroundColor() const; - - /** @return logo for the setup wizard. */ - virtual QPixmap wizardHeaderLogo() const; - - /** - * The default implementation creates a - * background based on - * \ref wizardHeaderTitleColor(). - * - * @return banner for the setup wizard. - */ - virtual QPixmap wizardHeaderBanner() const; -#endif - - /** - * About dialog contents - */ - virtual QString about() const; - - /** - * Define if the systray icons should be using mono design - */ - void setSystrayUseMonoIcons(bool mono); - - /** - * Retrieve wether to use mono icons for systray - */ - bool systrayUseMonoIcons() const; - - /** - * @brief Where to check for new Updates. - */ - virtual QString updateCheckUrl() const; - -protected: - QIcon themeIcon(const QString& name, bool sysTray = false) const; - Theme(); - -signals: - void systrayUseMonoIconsChanged(bool); - -private: - Theme(Theme const&); - Theme& operator=(Theme const&); - - static Theme* _instance; - bool _mono; - -}; - -} -#endif // _THEME_H diff --git a/src/mirall/utility.cpp b/src/mirall/utility.cpp deleted file mode 100644 index 1b4956fc9..000000000 --- a/src/mirall/utility.cpp +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Copyright (C) by Klaas Freitag <freitag@owncloud.com> - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 "utility.h" - -#include "mirall/version.h" - -#include <QCoreApplication> -#include <QSettings> -#include <QTextStream> -#include <QDir> -#include <QFile> -#include <QUrl> -#include <QDebug> -#include <QProcess> -#include <QThread> -#include <QDateTime> -#include <QSysInfo> - -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) -#include <QTextDocument> -#else -#include <QStandardPaths> -#endif - -#ifdef Q_OS_UNIX -#include <sys/statvfs.h> -#include <sys/types.h> -#include <unistd.h> -#endif - -#include <stdarg.h> - -#if defined(Q_OS_WIN) -#include "mirall/utility_win.cpp" -#elif defined(Q_OS_MAC) -#include "mirall/utility_mac.cpp" -#else -#include "mirall/utility_unix.cpp" -#endif - -namespace Mirall { - -bool Utility::writeRandomFile( const QString& fname, int size ) -{ - int maxSize = 10*10*1024; - qsrand(QDateTime::currentMSecsSinceEpoch()); - - if( size == -1 ) size = qrand() % maxSize; - - QString randString; - for( int i = 0; i < size; i++ ) { - int r = qrand() % 128; - randString.append(QChar(r)); - } - - QFile file(fname); - if( file.open(QIODevice::WriteOnly | QIODevice::Text) ) { - QTextStream out(&file); - out << randString; - // optional, as QFile destructor will already do it: - file.close(); - return true; - } - return false; - -} - -QString Utility::formatFingerprint( const QByteArray& fmhash, bool colonSeparated ) -{ - QByteArray hash; - int steps = fmhash.length()/2; - for (int i = 0; i < steps; i++) { - hash.append(fmhash[i*2]); - hash.append(fmhash[i*2+1]); - hash.append(' '); - } - - QString fp = QString::fromLatin1( hash.trimmed() ); - if (colonSeparated) { - fp.replace(QChar(' '), QChar(':')); - } - - return fp; -} - -void Utility::setupFavLink(const QString &folder) -{ - setupFavLink_private(folder); -} - -QString Utility::octetsToString( qint64 octets ) -{ - static const qint64 kb = 1024; - static const qint64 mb = 1024 * kb; - static const qint64 gb = 1024 * mb; - static const qint64 tb = 1024 * gb; - - QString s; - qreal value = octets; - if (octets >= tb) { - s = QCoreApplication::translate("Utility", "%L1 TB"); - value /= tb; - } else if (octets >= gb) { - s = QCoreApplication::translate("Utility", "%L1 GB"); - value /= gb; - } else if (octets >= mb) { - s = QCoreApplication::translate("Utility", "%L1 MB"); - value /= mb; - } else if (octets >= kb) { - s = QCoreApplication::translate("Utility", "%L1 kB"); - value /= kb; - } else { - s = QCoreApplication::translate("Utility", "%L1 B"); - } - - return (value > 9.95) ? s.arg(qRound(value)) : s.arg(value, 0, 'g', 2); -} - -// Qtified version of get_platforms() in csync_owncloud.c -QString Utility::platform() -{ -#if defined(Q_OS_WIN) - return QLatin1String("Windows"); -#elif defined(Q_OS_MAC) - return QLatin1String("Macintosh"); -#elif defined(Q_OS_LINUX) - return QLatin1String("Linux"); -#elif defined(__DragonFly__) // Q_OS_FREEBSD also defined - return QLatin1String("DragonFlyBSD"); -#elif defined(Q_OS_FREEBSD) || defined(Q_OS_FREEBSD_KERNEL) - return QLatin1String("FreeBSD"); -#elif defined(Q_OS_NETBSD) - return QLatin1String("NetBSD"); -#elif defined(Q_OS_OPENBSD) - return QLatin1String("OpenBSD"); -#elif defined(Q_OS_SOLARIS) - return QLatin1String("Solaris"); -#else - return QLatin1String("Unknown OS"); -#endif -} - -QByteArray Utility::userAgentString() -{ - return QString::fromLatin1("Mozilla/5.0 (%1) mirall/%2") - .arg(Utility::platform()) - .arg(QLatin1String(MIRALL_STRINGIFY(MIRALL_VERSION))) - .toLatin1(); -} - -bool Utility::hasLaunchOnStartup(const QString &appName) -{ - return hasLaunchOnStartup_private(appName); -} - -void Utility::setLaunchOnStartup(const QString &appName, const QString& guiName, bool enable) -{ - setLaunchOnStartup_private(appName, guiName, enable); -} - -qint64 Utility::freeDiskSpace(const QString &path, bool *ok) -{ -#if defined(Q_OS_MAC) || defined(Q_OS_FREEBSD) || defined(Q_OS_FREEBSD_KERNEL) - struct statvfs stat; - statvfs(path.toUtf8().data(), &stat); - return (qint64) stat.f_bavail * stat.f_frsize; -#elif defined(Q_OS_UNIX) - Q_UNUSED(ok) - struct statvfs64 stat; - statvfs64(path.toUtf8().data(), &stat); - return (qint64) stat.f_bavail * stat.f_frsize; -#elif defined(Q_OS_WIN) - ULARGE_INTEGER freeBytes; - freeBytes.QuadPart = 0L; - QString drive = QDir().absoluteFilePath(path).left(2); - if( !GetDiskFreeSpaceEx( reinterpret_cast<const wchar_t *>(drive.utf16()), &freeBytes, NULL, NULL ) ) { - if (ok) *ok = false; - } - return freeBytes.QuadPart; -#else - if (ok) *ok = false; - return 0; -#endif -} - -QString Utility::compactFormatDouble(double value, int prec, const QString& unit) -{ - QLocale locale = QLocale::system(); - QChar decPoint = locale.decimalPoint(); - QString str = locale.toString(value, 'f', prec); - while (str.endsWith('0') || str.endsWith(decPoint)) { - if (str.endsWith(decPoint)) { - str.chop(1); - break; - } - str.chop(1); - } - if( !unit.isEmpty() ) - str += (QLatin1Char(' ')+unit); - return str; -} - -QString Utility::toCSyncScheme(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(); -} - -QString Utility::escape(const QString &in) -{ -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - return Qt::escape(in); -#else - return in.toHtmlEscaped(); -#endif -} - -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) -// In Qt 4, QThread::sleep functions are protected. -// This is a hack to make them visible in this namespace. -struct QThread : ::QThread { - using ::QThread::sleep; - using ::QThread::usleep; -}; -#endif - -void Utility::sleep(int sec) -{ - QThread::sleep(sec); -} - -void Utility::usleep(int usec) -{ - QThread::usleep(usec); -} - -bool Utility::fsCasePreserving() -{ - bool re = false; - if( isWindows() || isMac() ) { - re = true; - } else { - static bool isTest = qgetenv("OWNCLOUD_TEST_CASE_PRESERVING").toInt(); - re = isTest; - } - return re; -} - -QDateTime Utility::qDateTimeFromTime_t(qint64 t) -{ - return QDateTime::fromMSecsSinceEpoch(t * 1000); -} - -qint64 Utility::qDateTimeToTime_t(const QDateTime& t) -{ - return t.toMSecsSinceEpoch() / 1000; -} - -//TODO change to initializers list when possible. -static QList<QPair<QString,quint32> > timeMapping = QList<QPair<QString,quint32> >() << - QPair<QString,quint32>("%1 years",86400*365) << - QPair<QString,quint32>("%1 months",86400*30) << - QPair<QString,quint32>("%1 days",86400) << - QPair<QString,quint32>("%1h",3600) << - QPair<QString,quint32>("%1m",60) << - QPair<QString,quint32>("%1s",1); - - -QString Utility::timeToDescriptiveString(quint64 msecs, quint8 precision, QString separator, bool specific) -{ - return timeToDescriptiveString( timeMapping , msecs, precision, separator, specific); -} - - -QString Utility::timeToDescriptiveString(QList<QPair<QString,quint32> > &timeMapping, quint64 msecs, quint8 precision, QString separator, bool specific) -{ - quint64 secs = msecs / 1000; - QString retStr = QString(timeMapping.last().first).arg(0); // default value in case theres no actual time in msecs. - QList<QPair<QString,quint32> > values; - bool timeStartFound = false; - - for(QList<QPair<QString,quint32> >::Iterator itr = timeMapping.begin(); itr != timeMapping.end() && precision > 0; itr++) { - quint64 result = secs / itr->second; - if(!timeStartFound) { - if(result == 0 ) { - continue; - } - retStr = ""; - timeStartFound= true; - } - secs -= result * itr->second; - values.append(QPair<QString,quint32>(itr->first,result)); - precision--; - } - - for(QList<QPair<QString,quint32> >::Iterator itr = values.begin(); itr < values.end(); itr++) { - retStr = retStr.append((specific || itr == values.end()-1) ? itr->first : "%1").arg(itr->second, (itr == values.begin() ? 1 :2 ), 10, QChar('0')); - if(itr < values.end()-1) { - retStr.append(separator); - } - - - } - - return retStr; -} - - -bool Utility::isWindows() -{ -#ifdef Q_OS_WIN - return true; -#else - return false; -#endif -} - -bool Utility::isMac() -{ -#ifdef Q_OS_MAC - return true; -#else - return false; -#endif -} - -bool Utility::isUnix() -{ -#ifdef Q_OS_UNIX - return true; -#else - return false; -#endif -} - -bool Utility::isLinux() -{ -#ifdef Q_OS_LINUX - return true; -#else - return false; -#endif -} - -static const char STOPWATCH_END_TAG[] = "_STOPWATCH_END"; - -void Utility::StopWatch::start() -{ - _startTime = QDateTime::currentDateTime(); - _timer.start(); -} - -void Utility::StopWatch::stop() -{ - addLapTime(QLatin1String(STOPWATCH_END_TAG)); - _timer.invalidate(); -} - -void Utility::StopWatch::reset() -{ - _timer.invalidate(); - _startTime.setMSecsSinceEpoch(0); - _lapTimes.clear(); -} - -quint64 Utility::StopWatch::addLapTime( const QString& lapName ) -{ - if( !_timer.isValid() ) { - start(); - } - quint64 re = _timer.elapsed(); - _lapTimes[lapName] = re; - return re; -} - -QDateTime Utility::StopWatch::startTime() const -{ - return _startTime; -} - -QDateTime Utility::StopWatch::timeOfLap( const QString& lapName ) const -{ - quint64 t = durationOfLap(lapName); - if( t ) { - QDateTime re(_startTime); - return re.addMSecs(t); - } - - return QDateTime(); -} - -quint64 Utility::StopWatch::durationOfLap( const QString& lapName ) const -{ - return _lapTimes.value(lapName, 0); -} - - -} // namespace Mirall diff --git a/src/mirall/utility.h b/src/mirall/utility.h deleted file mode 100644 index 0d46146b9..000000000 --- a/src/mirall/utility.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) by Klaas Freitag <freitag@owncloud.com> - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 UTILITY_H -#define UTILITY_H - -#include "owncloudlib.h" -#include <QString> -#include <QByteArray> -#include <QDateTime> -#include <QElapsedTimer> -#include <QHash> - -class QWidget; - -namespace Mirall { - -namespace Utility -{ - OWNCLOUDSYNC_EXPORT void sleep(int sec); - OWNCLOUDSYNC_EXPORT void usleep(int usec); - OWNCLOUDSYNC_EXPORT QString formatFingerprint( const QByteArray&, bool colonSeparated = true ); - OWNCLOUDSYNC_EXPORT void setupFavLink( const QString &folder ); - OWNCLOUDSYNC_EXPORT bool writeRandomFile( const QString& fname, int size = -1); - OWNCLOUDSYNC_EXPORT QString octetsToString( qint64 octets ); - OWNCLOUDSYNC_EXPORT QString platform(); - OWNCLOUDSYNC_EXPORT QByteArray userAgentString(); - OWNCLOUDSYNC_EXPORT bool hasLaunchOnStartup(const QString &appName); - OWNCLOUDSYNC_EXPORT void setLaunchOnStartup(const QString &appName, const QString& guiName, bool launch); - OWNCLOUDSYNC_EXPORT qint64 freeDiskSpace(const QString &path, bool *ok = 0); - OWNCLOUDSYNC_EXPORT QString toCSyncScheme(const QString &urlStr); - /** Like QLocale::toString(double, 'f', prec), but drops trailing zeros after the decimal point */ - - /** - * @brief compactFormatDouble - formats a double value human readable. - * - * @param value the value to format. - * @param prec the precision. - * @param unit an optional unit that is appended if present. - * @return the formatted string. - */ - OWNCLOUDSYNC_EXPORT QString compactFormatDouble(double value, int prec, const QString& unit = QString::null); - - // porting methods - OWNCLOUDSYNC_EXPORT QString escape(const QString&); - - // conversion function QDateTime <-> time_t (because the ones builtin work on only unsigned 32bit) - OWNCLOUDSYNC_EXPORT QDateTime qDateTimeFromTime_t(qint64 t); - OWNCLOUDSYNC_EXPORT qint64 qDateTimeToTime_t(const QDateTime &t); - - - - /** - * @brief Convert milliseconds to HMS string. - * @param quint64 msecs the milliseconds to convert to string. - * @param uint precision the amount of sub dviving scale to include in the result. - * @return an HMS representation of the milliseconds value. - */ - OWNCLOUDSYNC_EXPORT QString timeToDescriptiveString(QList<QPair<QString,quint32> > &timeMapping, quint64 msecs, quint8 precision, QString separator, bool specific); - OWNCLOUDSYNC_EXPORT QString timeToDescriptiveString(quint64 msecs, quint8 precision, QString separator, bool specific); - - // convinience OS detection methods - OWNCLOUDSYNC_EXPORT bool isWindows(); - OWNCLOUDSYNC_EXPORT bool isMac(); - OWNCLOUDSYNC_EXPORT bool isUnix(); - OWNCLOUDSYNC_EXPORT bool isLinux(); // use with care - - // Case preserving file system underneath? - // if this function returns true, the file system is case preserving, - // that means "test" means the same as "TEST" for filenames. - // if false, the two cases are two different files. - OWNCLOUDSYNC_EXPORT bool fsCasePreserving(); - - class OWNCLOUDSYNC_EXPORT StopWatch { - private: - QHash<QString, quint64> _lapTimes; - QDateTime _startTime; - QElapsedTimer _timer; - public: - void start(); - void stop(); - quint64 addLapTime( const QString& lapName ); - void reset(); - - // out helpers, return the masured times. - QDateTime startTime() const; - QDateTime timeOfLap( const QString& lapName ) const; - quint64 durationOfLap( const QString& lapName ) const; - }; -} - -} -#endif // UTILITY_H diff --git a/src/mirall/utility_mac.cpp b/src/mirall/utility_mac.cpp deleted file mode 100644 index a71bbd79a..000000000 --- a/src/mirall/utility_mac.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 <CoreServices/CoreServices.h> -#include <CoreFoundation/CoreFoundation.h> - -static void setupFavLink_private(const QString &folder) -{ - // Finder: Place under "Places"/"Favorites" on the left sidebar - CFStringRef folderCFStr = CFStringCreateWithCString(0, folder.toUtf8().data(), kCFStringEncodingUTF8); - CFURLRef urlRef = CFURLCreateWithFileSystemPath (0, folderCFStr, kCFURLPOSIXPathStyle, true); - - LSSharedFileListRef placesItems = LSSharedFileListCreate(0, kLSSharedFileListFavoriteItems, 0); - if (placesItems) { - //Insert an item to the list. - LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(placesItems, - kLSSharedFileListItemLast, 0, 0, - urlRef, 0, 0); - if (item) - CFRelease(item); - } - CFRelease(placesItems); - CFRelease(folderCFStr); - CFRelease(urlRef); -} - -bool hasLaunchOnStartup_private(const QString &) -{ - // this is quite some duplicate code with setLaunchOnStartup, at some point we should fix this FIXME. - bool returnValue = false; - QString filePath = QDir(QCoreApplication::applicationDirPath()+QLatin1String("/../..")).absolutePath(); - CFStringRef folderCFStr = CFStringCreateWithCString(0, filePath.toUtf8().data(), kCFStringEncodingUTF8); - CFURLRef urlRef = CFURLCreateWithFileSystemPath (0, folderCFStr, kCFURLPOSIXPathStyle, true); - LSSharedFileListRef loginItems = LSSharedFileListCreate(0, kLSSharedFileListSessionLoginItems, 0); - if (loginItems) { - // We need to iterate over the items and check which one is "ours". - UInt32 seedValue; - CFArrayRef itemsArray = LSSharedFileListCopySnapshot(loginItems, &seedValue); - CFStringRef appUrlRefString = CFURLGetString(urlRef); // no need for release - for (int i = 0; i < CFArrayGetCount(itemsArray); i++) { - LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(itemsArray, i); - CFURLRef itemUrlRef = NULL; - - if (LSSharedFileListItemResolve(item, 0, &itemUrlRef, NULL) == noErr) { - CFStringRef itemUrlString = CFURLGetString(itemUrlRef); - if (CFStringCompare(itemUrlString,appUrlRefString,0) == kCFCompareEqualTo) { - returnValue = true; - } - CFRelease(itemUrlRef); - } - } - CFRelease(itemsArray); - } - CFRelease(loginItems); - CFRelease(folderCFStr); - CFRelease(urlRef); - return returnValue; -} - -void setLaunchOnStartup_private(const QString &appName, const QString& guiName, bool enable) -{ - Q_UNUSED(guiName) - QString filePath = QDir(QCoreApplication::applicationDirPath()+QLatin1String("/../..")).absolutePath(); - CFStringRef folderCFStr = CFStringCreateWithCString(0, filePath.toUtf8().data(), kCFStringEncodingUTF8); - CFURLRef urlRef = CFURLCreateWithFileSystemPath (0, folderCFStr, kCFURLPOSIXPathStyle, true); - LSSharedFileListRef loginItems = LSSharedFileListCreate(0, kLSSharedFileListSessionLoginItems, 0); - - if (loginItems && enable) { - //Insert an item to the list. - LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(loginItems, - kLSSharedFileListItemLast, 0, 0, - urlRef, 0, 0); - if (item) - CFRelease(item); - CFRelease(loginItems); - } else if (loginItems && !enable){ - // We need to iterate over the items and check which one is "ours". - UInt32 seedValue; - CFArrayRef itemsArray = LSSharedFileListCopySnapshot(loginItems, &seedValue); - CFStringRef appUrlRefString = CFURLGetString(urlRef); - for (int i = 0; i < CFArrayGetCount(itemsArray); i++) { - LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(itemsArray, i); - CFURLRef itemUrlRef = NULL; - - if (LSSharedFileListItemResolve(item, 0, &itemUrlRef, NULL) == noErr) { - CFStringRef itemUrlString = CFURLGetString(itemUrlRef); - if (CFStringCompare(itemUrlString,appUrlRefString,0) == kCFCompareEqualTo) { - LSSharedFileListItemRemove(loginItems,item); // remove it! - } - CFRelease(itemUrlRef); - } - } - CFRelease(itemsArray); - CFRelease(loginItems); - }; - - CFRelease(folderCFStr); - CFRelease(urlRef); -} - diff --git a/src/mirall/utility_unix.cpp b/src/mirall/utility_unix.cpp deleted file mode 100644 index df90ed37e..000000000 --- a/src/mirall/utility_unix.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) by Klaas Freitag <freitag@owncloud.com> - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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. - */ - -static void setupFavLink_private(const QString &folder) { - // Nautilus: add to ~/.gtk-bookmarks - QFile gtkBookmarks(QDir::homePath()+QLatin1String("/.gtk-bookmarks")); - QByteArray folderUrl = "file://" + folder.toUtf8(); - if (gtkBookmarks.open(QFile::ReadWrite)) { - QByteArray places = gtkBookmarks.readAll(); - if (!places.contains(folderUrl)) { - places += folderUrl; - gtkBookmarks.reset(); - gtkBookmarks.write(places + '\n'); - } - } -} - -// returns the autostart directory the linux way -// and respects the XDG_CONFIG_HOME env variable -// can be replaces for qt5 with QStandardPaths -QString getUserAutostartDir_private() -{ - QString config = QFile::decodeName(qgetenv("XDG_CONFIG_HOME")); - - if (config.isEmpty()) { - config = QDir::homePath()+QLatin1String("/.config"); - } - config += QLatin1String("/autostart/"); - return config; -} - -bool hasLaunchOnStartup_private(const QString &appName) -{ - QString desktopFileLocation = getUserAutostartDir_private()+appName+QLatin1String(".desktop"); - return QFile::exists(desktopFileLocation); -} - - -void setLaunchOnStartup_private(const QString &appName, const QString& guiName, bool enable) -{ - QString userAutoStartPath = getUserAutostartDir_private(); - QString desktopFileLocation = userAutoStartPath+appName+QLatin1String(".desktop"); - if (enable) { - if (!QDir().exists(userAutoStartPath) && !QDir().mkpath(userAutoStartPath)) { - qDebug() << "Could not create autostart directory"; - return; - } - QFile iniFile(desktopFileLocation); - if (!iniFile.open(QIODevice::WriteOnly)) { - qDebug() << "Could not write auto start entry" << desktopFileLocation; - return; - } - QTextStream ts(&iniFile); - ts.setCodec("UTF-8"); - ts << QLatin1String("[Desktop Entry]") << endl - << QLatin1String("Name=") << guiName << endl - << QLatin1String("GenericName=") << QLatin1String("File Synchronizer") << endl - << QLatin1String("Exec=") << QCoreApplication::applicationFilePath() << endl - << QLatin1String("Terminal=") << "false" << endl - << QLatin1String("Icon=") << appName.toLower() << endl // always use lowercase for icons - << QLatin1String("Categories=") << QLatin1String("Network") << endl - << QLatin1String("Type=") << QLatin1String("Application") << endl - << QLatin1String("StartupNotify=") << "false" << endl - << QLatin1String("X-GNOME-Autostart-enabled=") << "true" << endl - ; - } else { - if (!QFile::remove(desktopFileLocation)) { - qDebug() << "Could not remove autostart desktop file"; - } - } -} diff --git a/src/mirall/utility_win.cpp b/src/mirall/utility_win.cpp deleted file mode 100644 index 90aac54d7..000000000 --- a/src/mirall/utility_win.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) by Daniel Molkentin <danimo@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; version 2 of the License. - * - * 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 <shlobj.h> -#include <winbase.h> -#include <windows.h> - -static const char runPathC[] = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"; - -static void setupFavLink_private(const QString &folder) -{ - // Windows Explorer: Place under "Favorites" (Links) - wchar_t path[MAX_PATH]; - SHGetSpecialFolderPath(0, path, CSIDL_PROFILE, FALSE); - QString profile = QDir::fromNativeSeparators(QString::fromWCharArray(path)); - QDir folderDir(QDir::fromNativeSeparators(folder)); - QString linkName = profile+QLatin1String("/Links/") + folderDir.dirName() + QLatin1String(".lnk"); - if (!QFile::link(folder, linkName)) - qDebug() << Q_FUNC_INFO << "linking" << folder << "to" << linkName << "failed!"; -} - -bool hasLaunchOnStartup_private(const QString &appName) -{ - QString runPath = QLatin1String(runPathC); - QSettings settings(runPath, QSettings::NativeFormat); - return settings.contains(appName); -} - -void setLaunchOnStartup_private(const QString &appName, const QString& guiName, bool enable) -{ - Q_UNUSED(guiName); - QString runPath = QLatin1String(runPathC); - QSettings settings(runPath, QSettings::NativeFormat); - if (enable) { - settings.setValue(appName, QCoreApplication::applicationFilePath().replace('/','\\')); - } else { - settings.remove(appName); - } -} diff --git a/src/mirall/version.h.in b/src/mirall/version.h.in deleted file mode 100644 index 29740f11a..000000000 --- a/src/mirall/version.h.in +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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. - */ - -#ifndef VERSION_H -#define VERSION_H - -#define MIRALL_STRINGIFY(s) MIRALL_TOSTRING(s) -#define MIRALL_TOSTRING(s) #s - -/* MIRALL version */ -#define MIRALL_VERSION_MAJOR @MIRALL_VERSION_MAJOR@ -#define MIRALL_VERSION_MINOR @MIRALL_VERSION_MINOR@ -#define MIRALL_VERSION_PATCH @MIRALL_VERSION_PATCH@ -#define MIRALL_VERSION_BUILD @MIRALL_VERSION_BUILD@ - -#define MIRALL_VERSION @MIRALL_VERSION@ -#define MIRALL_VERSION_FULL @MIRALL_VERSION_FULL@ - -#define MIRALL_VERSION_STRING "@MIRALL_VERSION_STRING@" - -#endif // VERSION_H |