diff --git a/src/creds/abstractcredentials.h b/src/creds/abstractcredentials.h index 1e589ddae..95f01108e 100644 --- a/src/creds/abstractcredentials.h +++ b/src/creds/abstractcredentials.h @@ -19,9 +19,9 @@ #include class QNetworkAccessManager; - namespace Mirall { +class Account; class AbstractCredentials : public QObject { @@ -35,8 +35,9 @@ public: virtual QString authType() const = 0; virtual QNetworkAccessManager* getQNAM() const = 0; virtual bool ready() const = 0; - virtual void fetch() = 0; - virtual void persistForUrl(const QString& url) = 0; + virtual void fetch(Account *account) = 0; + virtual void persist(Account *account) = 0; + Q_SIGNALS: void fetched(); diff --git a/src/creds/dummycredentials.cpp b/src/creds/dummycredentials.cpp index 6857d3218..6fedd9dbf 100644 --- a/src/creds/dummycredentials.cpp +++ b/src/creds/dummycredentials.cpp @@ -45,12 +45,12 @@ bool DummyCredentials::ready() const return true; } -void DummyCredentials::fetch() +void DummyCredentials::fetch(Account*) { Q_EMIT(fetched()); } -void DummyCredentials::persistForUrl(const QString&) +void DummyCredentials::persist(Account*) {} } // ns Mirall diff --git a/src/creds/dummycredentials.h b/src/creds/dummycredentials.h index bd234699b..7775691d1 100644 --- a/src/creds/dummycredentials.h +++ b/src/creds/dummycredentials.h @@ -30,8 +30,8 @@ public: QString authType() const; QNetworkAccessManager* getQNAM() const; bool ready() const; - void fetch(); - void persistForUrl(const QString& url); + void fetch(Account*); + void persist(Account*); }; } // ns Mirall diff --git a/src/creds/http/credentialstore.cpp b/src/creds/http/credentialstore.cpp index 537129804..ad87c16c6 100644 --- a/src/creds/http/credentialstore.cpp +++ b/src/creds/http/credentialstore.cpp @@ -60,8 +60,9 @@ void CredentialStore::fetchCredentials() bool ok = false; QString pwd; - _user = cfgFile.user(); - _url = cfgFile.ownCloudUrl(); +// ### +// _url = url; +// _user = user; QString key = keyChainKey(_url); diff --git a/src/creds/http/credentialstore.h b/src/creds/http/credentialstore.h index 836c396a3..4c73a12af 100644 --- a/src/creds/http/credentialstore.h +++ b/src/creds/http/credentialstore.h @@ -60,6 +60,7 @@ public: KeyChain }; + explicit CredentialStore(QObject *parent = 0); QString password( ) const; QString user( ) const; @@ -109,7 +110,6 @@ protected slots: void slotKeyChainWriteFinished( QKeychain::Job* ); private: - explicit CredentialStore(QObject *parent = 0); void deleteKeyChainCredential( const QString& ); QString keyChainKey( const QString& ) const; diff --git a/src/creds/httpcredentials.cpp b/src/creds/httpcredentials.cpp index 08f7e2226..79bd1b08c 100644 --- a/src/creds/httpcredentials.cpp +++ b/src/creds/httpcredentials.cpp @@ -17,14 +17,19 @@ #include #include #include +#include + +#include #include "mirall/account.h" #include "mirall/mirallaccessmanager.h" #include "mirall/utility.h" +#include "mirall/theme.h" #include "creds/credentialscommon.h" -#include "creds/http/credentialstore.h" #include "creds/httpcredentials.h" +using namespace QKeychain; + namespace Mirall { @@ -66,6 +71,8 @@ int getauth(const char *prompt, return re; } +const char userC[] = "user"; + } // ns class HttpCredentialsAccessManager : public MirallAccessManager { @@ -77,7 +84,7 @@ protected: QByteArray credHash = QByteArray(_cred->user().toUtf8()+":"+_cred->password().toUtf8()).toBase64(); QNetworkRequest req(request); req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash); - return MirallAccessManager::createRequest(op, req, outgoingData);\ + return MirallAccessManager::createRequest(op, req, outgoingData); } private: const HttpCredentials *_cred; @@ -94,9 +101,6 @@ HttpCredentials::HttpCredentials(const QString& user, const QString& password) _password(password), _ready(true) { - _store = new CredentialStore(this); - connect(store, SIGNAL(fetchCredentialsFinished(bool)), - this, SLOT(slotCredentialsFetched(bool))); } void HttpCredentials::syncContextPreInit (CSYNC* ctx) @@ -166,30 +170,60 @@ bool HttpCredentials::ready() const return _ready; } -void HttpCredentials::fetch() +void HttpCredentials::fetch(Account *account) { + _user = account->credentialSetting(QLatin1String(userC)).toString(); if (_ready) { Q_EMIT fetched(); } else { - // TODO: merge CredentialStore into HttpCredentials? - _store->fetchCredentials(); + ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName()); + job->setSettings(account->settingsWithGroup(Theme::instance()->appName())); + job->setInsecureFallback(true); + job->setKey(keychainKey(account->url().toString(), _user)); + connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*))); + job->start(); } } -void HttpCredentials::persistForUrl(const QString& url) +void HttpCredentials::slotReadJobDone(QKeychain::Job *job) { - _store->setCredentials(url, _user, _password); - _store->saveCredentials(); + ReadPasswordJob *readJob = static_cast(job); + delete readJob->settings(); + _password = readJob->textData(); + QKeychain::Error error = job->error(); + switch (error) { + case NoError: + Q_EMIT fetched(); + break; + default: + // ### retry with insecure storage + qDebug() << "Error while reading password" << job->errorString(); + } + } -void HttpCredentials::slotCredentialsFetched(bool ok) +void HttpCredentials::persist(Account *account) { - _ready = ok; - if (_ready) { - _user = _store->user(); - _password = _store->password(); + QString user = account->credentialSetting(QLatin1String(userC)).toString(); + account->setCredentialSetting(QLatin1String(userC), _user); + WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName()); + job->setSettings(account->settingsWithGroup(Theme::instance()->appName())); + job->setInsecureFallback(true); + connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteJobDone(QKeychain::Job*))); + job->setKey(keychainKey(account->url().toString(), user)); + job->setTextData(_password); + job->start(); +} + +void HttpCredentials::slotWriteJobDone(QKeychain::Job *job) +{ + delete job->settings(); + switch (job->error()) { + case NoError: + break; + default: + qDebug() << "Error while writing password" << job->errorString(); } - Q_EMIT fetched(); } void HttpCredentials::slotAuthentication(QNetworkReply* reply, QAuthenticator* authenticator) @@ -202,12 +236,24 @@ void HttpCredentials::slotAuthentication(QNetworkReply* reply, QAuthenticator* a reply->close(); } -void HttpCredentials::slotReplyFinished() +QString HttpCredentials::keychainKey(const QString &url, const QString &user) { - QNetworkReply* reply = qobject_cast< QNetworkReply* >(sender()); + QString u(url); + if( u.isEmpty() ) { + qDebug() << "Empty url in keyChain, error!"; + return QString::null; + } + if( user.isEmpty() ) { + qDebug() << "Error: User is emty!"; + return QString::null; + } - disconnect(reply, SIGNAL(finished()), - this, SLOT(slotReplyFinished())); + if( !u.endsWith(QChar('/')) ) { + u.append(QChar('/')); + } + + QString key = user+QLatin1Char(':')+u; + return key; } } // ns Mirall diff --git a/src/creds/httpcredentials.h b/src/creds/httpcredentials.h index 0b348803f..e4b213b85 100644 --- a/src/creds/httpcredentials.h +++ b/src/creds/httpcredentials.h @@ -24,11 +24,13 @@ class QNetworkReply; class QAuthenticator; +namespace QKeychain { + class Job; +} + namespace Mirall { -class CredentialStore; - class HttpCredentials : public AbstractCredentials { Q_OBJECT @@ -43,19 +45,19 @@ public: QString authType() const; QNetworkAccessManager* getQNAM() const; bool ready() const; - void fetch(); - void persistForUrl(const QString& url); + void fetch(Account *account); + void persist(Account *account); QString user() const; QString password() const; private Q_SLOTS: - void slotCredentialsFetched(bool); void slotAuthentication(QNetworkReply*, QAuthenticator*); - void slotReplyFinished(); + void slotReadJobDone(QKeychain::Job*); + void slotWriteJobDone(QKeychain::Job*); private: - CredentialStore *_store; + static QString keychainKey(const QString &url, const QString &user); QString _user; QString _password; bool _ready; diff --git a/src/creds/shibbolethcredentials.cpp b/src/creds/shibbolethcredentials.cpp index 0ef41b1e2..08ff99aa4 100644 --- a/src/creds/shibbolethcredentials.cpp +++ b/src/creds/shibbolethcredentials.cpp @@ -65,7 +65,9 @@ int shibboleth_redirect_callback(CSYNC* csync_ctx, } // ns ShibbolethCredentials::ShibbolethCredentials() - : _shibCookie(), + : AbstractCredentials(), + _url(), + _shibCookie(), _ready(false), _browser(0), _otherCookies() @@ -163,14 +165,16 @@ bool ShibbolethCredentials::ready() const return _ready; } -void ShibbolethCredentials::fetch() +void ShibbolethCredentials::fetch(Account *account) { if (_ready) { Q_EMIT fetched(); } else { ShibbolethConfigFile cfg; - - _browser = new ShibbolethWebView(QUrl(cfg.ownCloudUrl()), cfg.createCookieJar()); + if (account) { + _url = account->url(); + } + _browser = new ShibbolethWebView(_url, cfg.createCookieJar()); connect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie)), this, SLOT(onShibbolethCookieReceived(QNetworkCookie))); connect(_browser, SIGNAL(viewHidden()), @@ -179,7 +183,7 @@ void ShibbolethCredentials::fetch() } } -void ShibbolethCredentials::persistForUrl(const QString& /*url*/) +void ShibbolethCredentials::persist(Account* /*account*/) { ShibbolethConfigFile cfg; @@ -219,7 +223,10 @@ void ShibbolethCredentials::invalidateAndFetch() _ready = false; connect (this, SIGNAL(fetched()), this, SLOT(onFetched())); - fetch(); + // small hack to support the ShibbolethRefresher hack + // we already rand fetch() with a valid account object, + // and hence know the url on refresh + fetch(0); } void ShibbolethCredentials::onFetched() diff --git a/src/creds/shibbolethcredentials.h b/src/creds/shibbolethcredentials.h index 7ea433949..408e9c74d 100644 --- a/src/creds/shibbolethcredentials.h +++ b/src/creds/shibbolethcredentials.h @@ -40,8 +40,8 @@ public: QString authType() const; QNetworkAccessManager* getQNAM() const; bool ready() const; - void fetch(); - void persistForUrl(const QString& url); + void fetch(Account *account); + void persist(Account *account); QNetworkCookie cookie() const; @@ -58,6 +58,7 @@ Q_SIGNALS: void invalidatedAndFetched(const QByteArray& cookieData); private: + QUrl _url; QByteArray prepareCookieData() const; void disposeBrowser(); diff --git a/src/mirall/account.cpp b/src/mirall/account.cpp index 592f02655..201e6cc93 100644 --- a/src/mirall/account.cpp +++ b/src/mirall/account.cpp @@ -14,6 +14,7 @@ #include "mirall/account.h" #include "mirall/theme.h" #include "mirall/mirallconfigfile.h" +#include "mirall/networkjobs.h" #include "creds/abstractcredentials.h" #include "creds/credentialsfactory.h" @@ -58,22 +59,32 @@ Account::Account(AbstractSslErrorHandler *sslErrorHandler, QObject *parent) , _credentials(0) , _treatSslErrorsAsFailure(false) , _sslErrorHandler(0) + , _lastQuotaTotalBytes(0) + , _lastQuotaUsedBytes(0) { setSslErrorHandler(sslErrorHandler); } -void Account::save(QSettings &settings) +Account::~Account() { - settings.beginGroup(Theme::instance()->appName()); - settings.setValue(QLatin1String(urlC), _url); +} + +void Account::save() +{ + QScopedPointer settings(settingsWithGroup(Theme::instance()->appName())); + settings->setValue(QLatin1String(urlC), _url.toString()); if (_credentials) { - settings.setValue(QLatin1String(authTypeC), _credentials->authType()); + _credentials->persist(this); + Q_FOREACH(QString key, _settingsMap.keys()) { + settings->setValue(key, _settingsMap.value(key)); + } + settings->setValue(QLatin1String(authTypeC), _credentials->authType()); } // ### TODO port away from ConfigFile MirallConfigFile cfg; qDebug() << "Saving " << approvedCerts().count() << " unknown certs."; QByteArray certs; - foreach( const QSslCertificate& cert, approvedCerts() ) { + Q_FOREACH( const QSslCertificate& cert, approvedCerts() ) { certs += cert.toPem() + '\n'; } if (!certs.isEmpty()) { @@ -81,24 +92,23 @@ void Account::save(QSettings &settings) } } -Account* Account::restore(QSettings &settings) +Account* Account::restore() { - QString groupName = Theme::instance()->appName(); - if (settings.childGroups().contains(groupName)) { - MirallConfigFile cfg; + QScopedPointer settings(settingsWithGroup(Theme::instance()->appName())); + if (!settings->childKeys().isEmpty()) { Account *acc = new Account; + MirallConfigFile cfg; acc->setApprovedCerts(QSslCertificate::fromData(cfg.caCerts())); - settings.beginGroup(groupName); - acc->setUrl(settings.value(QLatin1String(urlC)).toUrl()); - acc->setCredentials(CredentialsFactory::create(QLatin1String(urlC))); - + acc->setUrl(settings->value(QLatin1String(urlC)).toUrl()); + acc->setCredentials(CredentialsFactory::create(settings->value(QLatin1String(authTypeC)).toString())); + Q_FOREACH(QString key, settings->childKeys()) { + acc->_settingsMap.insert(key, settings->value(key)); + } return acc; - } else { - return 0; } + return 0; } - static bool isEqualExceptProtocol(const QUrl &url1, const QUrl &url2) { return (url1.host() != url2.host() || @@ -215,6 +225,35 @@ QUrl Account::concatUrlPath(const QUrl &url, const QString &concatPath) return tmpUrl; } +QSettings *Account::settingsWithGroup(const QString& group) +{ + MirallConfigFile cfg; + QSettings *settings = new QSettings(cfg.configFile(), QSettings::IniFormat); + 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); + } +} + void Account::slotHandleErrors(QNetworkReply *reply , QList errors) { qDebug() << "SSL-Warnings happened for url " << reply->url().toString(); @@ -238,4 +277,17 @@ void Account::slotHandleErrors(QNetworkReply *reply , QList errors) } } +void Account::slotCheckQuota() +{ + CheckQuotaJob *job = new CheckQuotaJob(this, "/", this); + connect(job, SIGNAL(quotaRetrieved(qint64,qint64)), SLOT(slotUpdateLastQuota(qint64,qint64))); + connect(job, SIGNAL(quotaRetrieved(qint64,qint64)), SIGNAL(q(qint64,qint64))); +} + +void Account::slotUpdateLastQuota(qint64 total, qint64 used) +{ + _lastQuotaTotalBytes = total; + _lastQuotaUsedBytes = used; +} + } // namespace Mirall diff --git a/src/mirall/account.h b/src/mirall/account.h index 07c6a03bc..ca2d57d45 100644 --- a/src/mirall/account.h +++ b/src/mirall/account.h @@ -62,15 +62,17 @@ public: static QString davPath() { return "remote.php/webdav/"; } Account(AbstractSslErrorHandler *sslErrorHandler = 0, QObject *parent = 0); + ~Account(); + /** * Saves the account to a given settings file */ - void save(QSettings &settings); + void save(); /** * Creates an account object from from a given settings file. */ - static Account* restore(QSettings &settings); + static Account* restore(); /** * @brief Creates a minimal account object * @@ -114,14 +116,30 @@ public: QList approvedCerts() const { return _approvedCerts; } void setApprovedCerts(const QList certs); + // pluggable handler void setSslErrorHandler(AbstractSslErrorHandler *handler); + // static helper function static QUrl concatUrlPath(const QUrl &url, const QString &concatPath); + static QSettings* settingsWithGroup(const QString &group); + + // to be called by credentials only + QVariant credentialSetting(const QString& key) const; + void setCredentialSetting(const QString& key, const QVariant &value); + + qint64 lastQuotaTotalBytes() const { return _lastQuotaTotalBytes; } + qint64 lastQuotaUsedBytes() const { return _lastQuotaUsedBytes; } protected slots: void slotHandleErrors(QNetworkReply*,QList); + void slotCheckQuota(); + void slotUpdateLastQuota(qint64 total, qint64 used); + +signals: + void quotaUpdated(qint64 total, qint64 used); private: + QMap _settingsMap; QNetworkAccessManager *_am; QList _caCerts; QUrl _url; @@ -130,6 +148,8 @@ private: QList _certificateChain; bool _treatSslErrorsAsFailure; QScopedPointer _sslErrorHandler; + qint64 _lastQuotaTotalBytes; + qint64 _lastQuotaUsedBytes; }; } diff --git a/src/mirall/accountsettings.cpp b/src/mirall/accountsettings.cpp index 1fcde1a7f..fce8ff66d 100644 --- a/src/mirall/accountsettings.cpp +++ b/src/mirall/accountsettings.cpp @@ -38,6 +38,8 @@ #include #include +#include "mirall/account.h" + namespace Mirall { static const char progressBarStyleC[] = @@ -53,7 +55,8 @@ static const char progressBarStyleC[] = AccountSettings::AccountSettings(QWidget *parent) : QWidget(parent), ui(new Ui::AccountSettings), - _wasDisabledBefore(false) + _wasDisabledBefore(false), + _account(AccountManager::instance()->account()) { ui->setupUi(this); @@ -90,18 +93,13 @@ AccountSettings::AccountSettings(QWidget *parent) : QColor color = palette().highlight().color(); ui->quotaProgressBar->setStyleSheet(QString::fromLatin1(progressBarStyleC).arg(color.name())); - -// ### TODO: merge with etag job when porting? -// ownCloudInfo *ocInfo = ownCloudInfo::instance(); -// slotUpdateQuota(ocInfo->lastQuotaTotalBytes(), ocInfo->lastQuotaUsedBytes()); -// connect(ocInfo, SIGNAL(quotaUpdated(qint64,qint64)), SLOT(slotUpdateQuota(qint64,qint64))); - ui->connectLabel->setWordWrap( true ); + ui->quotaLabel->setWordWrap( true ); + + // ### TODO: + slotOnlineStateChanged(); setFolderList(FolderMan::instance()->map()); - - // ### TODO - //slotCheckConnection(); } void AccountSettings::slotFolderActivated( const QModelIndex& indx ) @@ -358,24 +356,6 @@ void AccountSettings::showConnectionLabel( const QString& message, const QString } } -// void AccountSettings::slotCheckConnection() -// { -// if( ownCloudInfo::instance()->isConfigured() ) { -// connect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(const QString&, const QString&, const QString&, const QString&)), -// this, SLOT(slotOCInfo( const QString&, const QString&, const QString&, const QString& ))); -// connect(ownCloudInfo::instance(), SIGNAL(noOwncloudFound(QNetworkReply*)), -// this, SLOT(slotOCInfoFail(QNetworkReply*))); -// -// showConnectionLabel( tr("Checking %1 connection...").arg(Theme::instance()->appNameGUI())); -// qDebug() << "Check status.php from statusdialog."; -// ownCloudInfo::instance()->checkInstallation(); -// } else { -// // ownCloud is not yet configured. -// showConnectionLabel( tr("No %1 connection configured.").arg(Theme::instance()->appNameGUI()) ); -// ui->_buttonAdd->setEnabled( false); -// } -// } - void AccountSettings::setFolderList( const Folder::Map &folders ) { _model->clear(); @@ -503,56 +483,51 @@ void AccountSettings::slotUpdateFolderState( Folder *folder ) } else { // the dialog is not visible. } -<<<<<<< HEAD - // ### TODO - //slotCheckConnection(); -} // showConnectionLabel( tr("Connected to %2.").arg(url, safeUrl.toString()), // tr("Version: %1 (%2)").arg(versionStr).arg(version) ); // ui->_ButtonAdd->setEnabled(true); -======= - slotCheckConnection(); + // ### TODO +// slotCheckConnection(); } -void AccountSettings::slotOCInfo( const QString& url, const QString& versionStr, const QString& version, const QString& ) -{ -#ifdef Q_OS_WIN32 - // work around a bug in QDesktopServices on Win32, see i-net - QString filePath = url; +//void AccountSettings::slotOCInfo( const QString& url, const QString& versionStr, const QString& version, const QString& ) +//{ +//#ifdef Q_OS_WIN32 +// // work around a bug in QDesktopServices on Win32, see i-net +// QString filePath = url; - if (filePath.startsWith("\\\\") || filePath.startsWith("//")) - _OCUrl.setUrl(QDir::toNativeSeparators(filePath)); - else - _OCUrl = QUrl::fromLocalFile(filePath); -#else - _OCUrl = QUrl::fromLocalFile(url); -#endif +// if (filePath.startsWith("\\\\") || filePath.startsWith("//")) +// _OCUrl.setUrl(QDir::toNativeSeparators(filePath)); +// else +// _OCUrl = QUrl::fromLocalFile(filePath); +//#else +// _OCUrl = QUrl::fromLocalFile(url); +//#endif - qDebug() << "#-------# oC found on " << url; - /* enable the open button */ - ui->connectLabel->setOpenExternalLinks(true); - QUrl safeUrl(url); - safeUrl.setPassword(QString()); // Remove the password from the URL to avoid showing it in the UI - showConnectionLabel( tr("Connected to %2.").arg(url, safeUrl.toString()), - tr("Version: %1 (%2)").arg(versionStr).arg(version) ); - ui->_buttonAdd->setEnabled(true); +// qDebug() << "#-------# oC found on " << url; +// /* enable the open button */ +// ui->connectLabel->setOpenExternalLinks(true); +// QUrl safeUrl(url); +// safeUrl.setPassword(QString()); // Remove the password from the URL to avoid showing it in the UI +// showConnectionLabel( tr("Connected to %2.").arg(url, safeUrl.toString()), +// tr("Version: %1 (%2)").arg(versionStr).arg(version) ); +// ui->_buttonAdd->setEnabled(true); - disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(const QString&, const QString&, const QString&, const QString&)), - this, SLOT(slotOCInfo( const QString&, const QString&, const QString&, const QString& ))); - disconnect(ownCloudInfo::instance(), SIGNAL(noOwncloudFound(QNetworkReply*)), - this, SLOT(slotOCInfoFail(QNetworkReply*))); -} +// disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(const QString&, const QString&, const QString&, const QString&)), +// this, SLOT(slotOCInfo( const QString&, const QString&, const QString&, const QString& ))); +// disconnect(ownCloudInfo::instance(), SIGNAL(noOwncloudFound(QNetworkReply*)), +// this, SLOT(slotOCInfoFail(QNetworkReply*))); +//} -void AccountSettings::slotOCInfoFail( QNetworkReply *reply) -{ - QString errStr = tr("unknown problem."); - if( reply ) errStr = reply->errorString(); - - showConnectionLabel( tr("

Failed to connect to %1: %2

").arg(Theme::instance()->appNameGUI()).arg(errStr) ); - ui->_buttonAdd->setEnabled( false); ->>>>>>> origin/master +//void AccountSettings::slotOCInfoFail( QNetworkReply *reply) +//{ +// QString errStr = tr("unknown problem."); +// if( reply ) errStr = reply->errorString(); +// showConnectionLabel( tr("

Failed to connect to %1: %2

").arg(Theme::instance()->appNameGUI()).arg(errStr) ); +// ui->_buttonAdd->setEnabled( false); +//} void AccountSettings::slotOpenOC() { @@ -793,6 +768,27 @@ void AccountSettings::slotIgnoreFilesEditor() } } +void AccountSettings::slotOnlineStateChanged(bool online) +{ + if (_account) { + connect(_account, SIGNAL(quotaUpdated(qint64,qint64)), SLOT(slotUpdateQuota(qint64,qint64)), Qt::UniqueConnection); + slotUpdateQuota(_account->lastQuotaTotalBytes(), _account->lastQuotaUsedBytes()); + if (online) { + QUrl safeUrl(_account->url()); + safeUrl.setPassword(QString()); // Remove the password from the URL to avoid showing it in the UI + showConnectionLabel( tr("Connected to %2.").arg(_account->url().toString(), safeUrl.toString()) + /*, tr("Version: %1 (%2)").arg(versionStr).arg(version) */ ); + ui->_buttonAdd->setEnabled(true); + } else { + showConnectionLabel( tr("Checking %1 connection...").arg(Theme::instance()->appNameGUI())); + } + } else { + // ownCloud is not yet configured. + showConnectionLabel( tr("No %1 connection configured.").arg(Theme::instance()->appNameGUI()) ); + ui->_buttonAdd->setEnabled( false); + } +} + void AccountSettings::slotInfoAboutCurrentFolder() { emit(openProtocol()); diff --git a/src/mirall/accountsettings.h b/src/mirall/accountsettings.h index 632dc950a..f8bf66887 100644 --- a/src/mirall/accountsettings.h +++ b/src/mirall/accountsettings.h @@ -38,6 +38,7 @@ class AccountSettings; class FolderMan; class IgnoreListEditor; +class Account; class AccountSettings : public QWidget { @@ -67,6 +68,7 @@ public slots: void slotUpdateQuota( qint64,qint64 ); void slotIgnoreFilesEditor(); + void slotOnlineStateChanged(bool online = true); void setGeneralErrors( const QStringList& errors ); @@ -97,6 +99,7 @@ private: QString _kindContext; QStringList _generalErrors; bool _wasDisabledBefore; + Account *_account; }; } // namespace Mirall diff --git a/src/mirall/application.cpp b/src/mirall/application.cpp index cbbe6461c..29c3afca7 100644 --- a/src/mirall/application.cpp +++ b/src/mirall/application.cpp @@ -114,9 +114,7 @@ Application::Application(int &argc, char **argv) : connect( this, SIGNAL(messageReceived(QString)), SLOT(slotParseOptions(QString))); - MirallConfigFile cfg; - QSettings settings(cfg.configFile(), QSettings::IniFormat); - Account *account = Account::restore(settings); + Account *account = Account::restore(); if (account) { account->setSslErrorHandler(new SslDialogErrorHandler); AccountManager::instance()->setAccount(account); @@ -137,6 +135,7 @@ Application::Application(int &argc, char **argv) : // connect(_networkMgr, SIGNAL(onlineStateChanged(bool)), SLOT(slotCheckConnection())); + MirallConfigFile cfg; _theme->setSystrayUseMonoIcons(cfg.monoIcons()); connect (_theme, SIGNAL(systrayUseMonoIconsChanged(bool)), SLOT(slotUseMonoIconsChanged(bool))); @@ -167,10 +166,8 @@ 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(); - MirallConfigFile cfg; - QSettings settings(cfg.configFile(), QSettings::IniFormat); if (account) { - account->save(settings); + account->save(); } _gui->slotShutdown(); _gui->deleteLater(); @@ -184,14 +181,14 @@ void Application::slotStartUpdateDetector() void Application::slotCheckConnection() { - if( _gui->checkConfigExists(false) ) { - MirallConfigFile cfg; - AbstractCredentials* credentials(cfg.getCredentials()); + if( _gui->checkAccountExists(false) ) { + Account *account = AccountManager::instance()->account(); + AbstractCredentials* credentials(account->credentials()); if (! credentials->ready()) { connect( credentials, SIGNAL(fetched()), this, SLOT(slotCredentialsFetched())); - credentials->fetch(); + credentials->fetch(account); } else { runValidator(); } @@ -203,10 +200,8 @@ void Application::slotCheckConnection() void Application::slotCredentialsFetched() { - MirallConfigFile cfg; - AbstractCredentials* credentials(cfg.getCredentials()); - - disconnect(credentials, SIGNAL(fetched()), + Account *account = AccountManager::instance()->account(); + disconnect(account->credentials(), SIGNAL(fetched()), this, SLOT(slotCredentialsFetched())); runValidator(); } diff --git a/src/mirall/connectionvalidator.cpp b/src/mirall/connectionvalidator.cpp index 414f2dba1..1cf28a988 100644 --- a/src/mirall/connectionvalidator.cpp +++ b/src/mirall/connectionvalidator.cpp @@ -22,12 +22,6 @@ namespace Mirall { -ConnectionValidator::ConnectionValidator(QObject *parent) : - QObject(parent) -{ - -} - ConnectionValidator::ConnectionValidator(Account *account, QObject *parent) : QObject(parent), _account(account), @@ -86,7 +80,7 @@ QString ConnectionValidator::statusString( Status stat ) const void ConnectionValidator::checkConnection() { - if( AccountManager::instance()->account() ) { + if( _account ) { CheckServerJob *checkJob = new CheckServerJob(_account, false, this); connect(checkJob, SIGNAL(instanceFound(QUrl,QVariantMap)), SLOT(slotStatusFound(QUrl,QVariantMap))); connect(checkJob, SIGNAL(networkError(QNetworkReply*)), SLOT(slotNoStatusFound(QNetworkReply*))); diff --git a/src/mirall/connectionvalidator.h b/src/mirall/connectionvalidator.h index abd84d742..355ec9c1b 100644 --- a/src/mirall/connectionvalidator.h +++ b/src/mirall/connectionvalidator.h @@ -27,7 +27,6 @@ class ConnectionValidator : public QObject { Q_OBJECT public: - explicit ConnectionValidator(QObject *parent = 0); explicit ConnectionValidator(Account *account, QObject *parent = 0); enum Status { diff --git a/src/mirall/networkjobs.cpp b/src/mirall/networkjobs.cpp index 5e76852f3..126d44179 100644 --- a/src/mirall/networkjobs.cpp +++ b/src/mirall/networkjobs.cpp @@ -60,8 +60,11 @@ void AbstractNetworkJob::setPath(const QString &path) _path = path; } -void AbstractNetworkJob::slotError() +void AbstractNetworkJob::slotError(QNetworkReply::NetworkError error) { + if (error == QNetworkReply::ContentAccessDenied) { + // ### ask for password, retry job, needs refactoring to use start() + } qDebug() << metaObject()->className() << "Error:" << _reply->errorString(); emit networkError(_reply); deleteLater(); @@ -71,7 +74,7 @@ void AbstractNetworkJob::setupConnections(QNetworkReply *reply) { connect(reply, SIGNAL(finished()), SLOT(slotFinished())); connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), - this, SLOT(slotError())); + this, SLOT(slotError(QNetworkReply::NetworkError))); } QNetworkReply* AbstractNetworkJob::davRequest(const QByteArray &verb, const QString &relPath, @@ -140,7 +143,6 @@ RequestEtagJob::RequestEtagJob(Account *account, const QString &path, QObject *p if( reply()->error() != QNetworkReply::NoError ) { qDebug() << "getting etag: request network error: " << reply()->errorString(); } - } void RequestEtagJob::slotFinished() @@ -312,6 +314,8 @@ void CheckServerJob::slotFinished() deleteLater(); } +/*********************************************************************************************/ + PropfindJob::PropfindJob(Account *account, const QString &path, QList properties, QObject *parent) @@ -379,6 +383,8 @@ void PropfindJob::slotFinished() deleteLater(); } +/*********************************************************************************************/ + EntityExistsJob::EntityExistsJob(Account *account, const QString &path, QObject *parent) : AbstractNetworkJob(account, path, parent) { @@ -391,4 +397,53 @@ void EntityExistsJob::slotFinished() emit exists(reply()); } +/*********************************************************************************************/ + +CheckQuotaJob::CheckQuotaJob(Account *account, const QString &path, QObject *parent) + : AbstractNetworkJob(account, path, parent) +{ + QNetworkRequest req; + req.setRawHeader("Depth", "0"); + QByteArray xml("\n" + "\n" + " \n" + " \n" + " \n" + " \n" + "\n"); + QBuffer *buf = new QBuffer; + buf->setData(xml); + buf->open(QIODevice::ReadOnly); + // assumes ownership + setReply(davRequest("PROPFIND", path, req, buf)); + buf->setParent(reply()); + setupConnections(reply()); +} + +void CheckQuotaJob::slotFinished() +{ + 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")) { + quotaAvailableBytes = reader.readElementText().toLongLong(); + } else if (name == QLatin1String("quota-used-bytes")) { + quotaUsedBytes = reader.readElementText().toLongLong(); + } + } + } + qint64 total = quotaUsedBytes + quotaAvailableBytes; + emit quotaRetrieved(total, quotaUsedBytes); + } + deleteLater(); +} + } // namespace Mirall diff --git a/src/mirall/networkjobs.h b/src/mirall/networkjobs.h index 796584143..5e0df2e24 100644 --- a/src/mirall/networkjobs.h +++ b/src/mirall/networkjobs.h @@ -63,7 +63,7 @@ protected: private slots: virtual void slotFinished() = 0; - void slotError(); + void slotError(QNetworkReply::NetworkError); private: QNetworkReply *_reply; @@ -101,7 +101,7 @@ private slots: }; /** - * @brief The CheckQuotaJob class + * @brief The PropfindJob class */ class PropfindJob : public AbstractNetworkJob { Q_OBJECT @@ -171,6 +171,21 @@ private slots: virtual void slotFinished(); }; +/** + * @brief The CheckQuota class + */ +class CheckQuotaJob : public AbstractNetworkJob { + Q_OBJECT +public: + explicit CheckQuotaJob(Account *account, const QString &path, QObject *parent = 0); + +signals: + void quotaRetrieved(qint64 totalBytes, qint64 availableBytes); + +private slots: + virtual void slotFinished(); +}; + } // namespace Mirall #endif // NETWORKJOBS_H diff --git a/src/mirall/owncloudgui.cpp b/src/mirall/owncloudgui.cpp index 49795262c..1c20a8c68 100644 --- a/src/mirall/owncloudgui.cpp +++ b/src/mirall/owncloudgui.cpp @@ -79,7 +79,7 @@ ownCloudGui::ownCloudGui(Application *parent) : } // This should rather be in application.... or rather in MirallConfigFile? -bool ownCloudGui::checkConfigExists(bool openSettings) +bool ownCloudGui::checkAccountExists(bool openSettings) { // if account is set up, start the configuration wizard. if( AccountManager::instance()->account() ) { @@ -100,7 +100,7 @@ void ownCloudGui::slotTrayClicked( QSystemTrayIcon::ActivationReason reason ) // Linux, not on Mac. They want a menu entry. #if !defined Q_OS_MAC if( reason == QSystemTrayIcon::Trigger ) { - checkConfigExists(true); // start settings if config is existing. + checkAccountExists(true); // start settings if config is existing. } #endif } @@ -477,8 +477,7 @@ void ownCloudGui::slotToggleLogBrowser() void ownCloudGui::slotOpenOwnCloud() { if (Account *account = AccountManager::instance()->account()) { - QString url = account->url(); - QDesktopServices::openUrl( url ); + QDesktopServices::openUrl(account->url()); } } diff --git a/src/mirall/owncloudgui.h b/src/mirall/owncloudgui.h index 70beb4d4b..c29cab544 100644 --- a/src/mirall/owncloudgui.h +++ b/src/mirall/owncloudgui.h @@ -39,7 +39,7 @@ public: void setupContextMenu(); void startupConnected(bool connected , const QStringList &fails); - bool checkConfigExists(bool openSettings); + bool checkAccountExists(bool openSettings); signals: void setupProxy(); diff --git a/src/mirall/owncloudsetupwizard.cpp b/src/mirall/owncloudsetupwizard.cpp index c3cca6aa2..7faa78747 100644 --- a/src/mirall/owncloudsetupwizard.cpp +++ b/src/mirall/owncloudsetupwizard.cpp @@ -53,8 +53,6 @@ OwncloudSetupWizard::OwncloudSetupWizard(QObject* parent) : Therefore Qt::QueuedConnection is required */ connect( _ocWizard, SIGNAL(basicSetupFinished(int)), this, SLOT(slotAssistantFinished(int)), Qt::QueuedConnection); - connect( _ocWizard, SIGNAL(clearPendingRequests()), - this, SLOT(slotClearPendingRequests())); } OwncloudSetupWizard::~OwncloudSetupWizard() @@ -80,14 +78,13 @@ void OwncloudSetupWizard::runWizard(QObject* obj, const char* amember, QWidget * void OwncloudSetupWizard::startWizard() { // ### - MirallConfigFile cfg; - QSettings settings(cfg.configFile(), QSettings::IniFormat); - Account *account = Account::restore(settings); + Account *account = Account::restore(); if (!account) { account = new Account(new SslDialogErrorHandler); account->setCredentials(CredentialsFactory::create("dummy")); } _ocWizard->setAccount(account); + _ocWizard->setOCUrl(account->url().toString()); _remoteFolder = Theme::instance()->defaultServerFolder(); // remoteFolder may be empty, which means / @@ -333,9 +330,7 @@ void OwncloudSetupWizard::replaceDefaultAccountWith(Account *newAccount) mgr->account()->deleteLater(); } mgr->setAccount(newAccount); - MirallConfigFile cfg; - QSettings settings(cfg.configFile(), QSettings::IniFormat); - newAccount->save(settings); + newAccount->save(); } // Method executed when the user ends the wizard, either with 'accept' or 'reject'. diff --git a/src/wizard/owncloudadvancedsetuppage.cpp b/src/wizard/owncloudadvancedsetuppage.cpp index 5657c30ed..b72328921 100644 --- a/src/wizard/owncloudadvancedsetuppage.cpp +++ b/src/wizard/owncloudadvancedsetuppage.cpp @@ -24,9 +24,11 @@ #include "wizard/owncloudwizard.h" #include "wizard/owncloudwizardcommon.h" #include "wizard/owncloudadvancedsetuppage.h" +#include "mirall/account.h" #include "mirall/theme.h" #include "mirall/mirallconfigfile.h" #include "creds/abstractcredentials.h" + namespace Mirall { @@ -135,21 +137,21 @@ void OwncloudAdvancedSetupPage::updateStatus() bool OwncloudAdvancedSetupPage::dataChanged() { OwncloudWizard* ocWizard(dynamic_cast< OwncloudWizard* >(wizard())); + Account *oldAccount = AccountManager::instance()->account(); - if (!ocWizard) { + if (!ocWizard || !oldAccount) { return false; } - MirallConfigFile cfgFile; const QString url(field("OCUrl").toString()); AbstractCredentials* newCredentials(ocWizard->getCredentials()); - AbstractCredentials* oldCredentials(cfgFile.getCredentials()); + AbstractCredentials* oldCredentials(oldAccount->credentials()); const bool differentCreds(oldCredentials->changed(newCredentials)); delete newCredentials; const QString newLocalFolder(QDir::toNativeSeparators(_ui.pbSelectLocalFolder->text())); const QString oldLocalFolder(QDir::toNativeSeparators(_oldLocalFolder)); - return ((url != cfgFile.ownCloudUrl()) || differentCreds || (oldLocalFolder != newLocalFolder)); + return ((url != oldAccount->url().toString()) || differentCreds || (oldLocalFolder != newLocalFolder)); } void OwncloudAdvancedSetupPage::startSpinner() diff --git a/src/wizard/owncloudhttpcredspage.cpp b/src/wizard/owncloudhttpcredspage.cpp index fc832bc37..1128a13cc 100644 --- a/src/wizard/owncloudhttpcredspage.cpp +++ b/src/wizard/owncloudhttpcredspage.cpp @@ -16,11 +16,13 @@ #include "QProgressIndicator.h" -#include "wizard/owncloudhttpcredspage.h" -#include "mirall/theme.h" -#include "wizard/owncloudwizardcommon.h" #include "creds/httpcredentials.h" +#include "mirall/theme.h" +#include "mirall/account.h" #include "mirall/mirallconfigfile.h" +#include "wizard/owncloudhttpcredspage.h" +#include "wizard/owncloudwizardcommon.h" +#include "wizard/owncloudwizard.h" namespace Mirall { @@ -65,12 +67,11 @@ void OwncloudHttpCredsPage::setupCustomization() void OwncloudHttpCredsPage::initializePage() { WizardCommon::initErrorLabel(_ui.errorLabel); - MirallConfigFile cfgFile; - HttpCredentials* httpCreds(dynamic_cast< HttpCredentials* >(cfgFile.getCredentials())); + OwncloudWizard* ocWizard = qobject_cast< OwncloudWizard* >(wizard()); + HttpCredentials *httpCreds = qobject_cast(ocWizard->account()->credentials()); if (httpCreds) { const QString user = httpCreds->user(); - if (!user.isEmpty()) { _ui.leUsername->setText(user); }