diff options
71 files changed, 4297 insertions, 1515 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index bead19e97..54c89b58e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,7 @@ endif() #### #### find libs -find_package(Qt4 4.7.0 COMPONENTS QtCore QtGui QtXml QtNetwork QtTest REQUIRED ) +find_package(Qt4 4.7.0 COMPONENTS QtCore QtGui QtXml QtNetwork QtTest QtWebkit REQUIRED ) if( UNIX AND NOT APPLE ) # Fdo notifications find_package(Qt4 4.7.0 COMPONENTS QtDBus REQUIRED ) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 90b585e06..0ad1f6c70 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,8 +16,6 @@ set(synclib_NAME ${APPLICATION_SHORTNAME}sync) set(mirall_UI mirall/folderwizardsourcepage.ui mirall/folderwizardtargetpage.ui -mirall/owncloudsetuppage_ng.ui -mirall/owncloudwizardresultpage.ui mirall/sslerrordialog.ui mirall/settingsdialog.ui mirall/generalsettings.ui @@ -26,6 +24,11 @@ mirall/accountsettings.ui mirall/ignorelisteditor.ui mirall/fileitemdialog.ui mirall/itemprogressdialog.ui +wizard/owncloudsetupnocredspage.ui +wizard/owncloudhttpcredspage.ui +wizard/owncloudwizardresultpage.ui +wizard/owncloudshibbolethcredspage.ui +wizard/owncloudadvancedsetuppage.ui ) set(3rdparty_SRC @@ -68,7 +71,6 @@ set(libsync_SRCS mirall/syncresult.cpp mirall/networklocation.cpp mirall/mirallconfigfile.cpp - mirall/credentialstore.cpp mirall/csyncthread.cpp mirall/fileutils.cpp mirall/theme.cpp @@ -78,8 +80,20 @@ set(libsync_SRCS mirall/utility.cpp mirall/connectionvalidator.cpp mirall/progressdispatcher.cpp + mirall/mirallaccessmanager.cpp + creds/dummycredentials.cpp + creds/httpcredentials.cpp + creds/credentialsfactory.cpp + creds/http/credentialstore.cpp + creds/http/httpconfigfile.cpp + creds/shibbolethcredentials.cpp + creds/shibboleth/shibbolethaccessmanager.cpp + creds/shibboleth/shibbolethcookiejar.cpp + creds/shibboleth/shibbolethwebview.cpp + creds/shibboleth/shibbolethrefresher.cpp ) -set(libsync_HEADERS + +set(libsync_HEADERS mirall/folderman.h mirall/folder.h mirall/folderwatcher.h @@ -87,10 +101,21 @@ set(libsync_HEADERS mirall/theme.h mirall/owncloudtheme.h mirall/owncloudinfo.h - mirall/credentialstore.h mirall/logger.h mirall/connectionvalidator.h mirall/progressdispatcher.h + mirall/mirallaccessmanager.h + creds/abstractcredentials.h + creds/dummycredentials.h + creds/httpcredentials.h + creds/credentialsfactory.h + creds/http/credentialstore.h + creds/http/httpconfigfile.h + creds/shibbolethcredentials.h + creds/shibboleth/shibbolethaccessmanager.h + creds/shibboleth/shibbolethcookiejar.h + creds/shibboleth/shibbolethwebview.h + creds/shibboleth/shibbolethrefresher.h ) IF( INOTIFY_FOUND ) @@ -153,7 +178,13 @@ set(mirall_SRCS mirall/systray.cpp mirall/folderwizard.cpp mirall/folderstatusmodel.cpp - mirall/owncloudwizard.cpp + wizard/owncloudwizard.cpp + wizard/owncloudsetuppage.cpp + wizard/owncloudhttpcredspage.cpp + wizard/owncloudwizardresultpage.cpp + wizard/owncloudwizardcommon.cpp + wizard/owncloudshibbolethcredspage.cpp + wizard/owncloudadvancedsetuppage.cpp mirall/owncloudsetupwizard.cpp mirall/updatedetector.cpp mirall/occinfo.cpp @@ -173,7 +204,13 @@ set(mirall_HEADERS mirall/systray.h mirall/folderwizard.h mirall/owncloudsetupwizard.h - mirall/owncloudwizard.h + wizard/owncloudwizard.h + wizard/owncloudsetuppage.h + wizard/owncloudhttpcredspage.h + wizard/owncloudwizardresultpage.h + wizard/owncloudwizardcommon.h + wizard/owncloudshibbolethcredspage.h + wizard/owncloudadvancedsetuppage.h mirall/folderstatusmodel.h mirall/updatedetector.h mirall/sslerrordialog.h diff --git a/src/creds/abstractcredentials.h b/src/creds/abstractcredentials.h new file mode 100644 index 000000000..1e589ddae --- /dev/null +++ b/src/creds/abstractcredentials.h @@ -0,0 +1,47 @@ +/* + * 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_CREDS_ABSTRACT_CREDENTIALS_H +#define MIRALL_CREDS_ABSTRACT_CREDENTIALS_H + +#include <QObject> + +#include <csync.h> + +class QNetworkAccessManager; + +namespace Mirall +{ + +class AbstractCredentials : public QObject +{ + Q_OBJECT + +public: + // No need for virtual destructor - QObject already has one. + virtual void syncContextPreInit(CSYNC* ctx) = 0; + virtual void syncContextPreStart(CSYNC* ctx) = 0; + virtual bool changed(AbstractCredentials* credentials) const = 0; + 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; + +Q_SIGNALS: + void fetched(); +}; + +} // ns Mirall + +#endif diff --git a/src/creds/credentialsfactory.cpp b/src/creds/credentialsfactory.cpp new file mode 100644 index 000000000..72cc252a6 --- /dev/null +++ b/src/creds/credentialsfactory.cpp @@ -0,0 +1,43 @@ +/* + * 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 <QString> + +#include "creds/httpcredentials.h" +#include "creds/dummycredentials.h" +#include "creds/shibbolethcredentials.h" + +namespace Mirall +{ + +namespace CredentialsFactory +{ + +AbstractCredentials* create(const QString& type) +{ + // empty string might happen for old version of configuration + if (type == "http" || type == "") { + return new HttpCredentials; + } else if (type == "dummy") { + return new DummyCredentials; + } else if (type == "shibboleth") { + return new ShibbolethCredentials; + } else { + qWarning("Unknown credentials type: %s", qPrintable(type)); + return new DummyCredentials; + } +} + +} // ns CredentialsFactory + +} // ns Mirall diff --git a/src/creds/credentialsfactory.h b/src/creds/credentialsfactory.h new file mode 100644 index 000000000..a34f94b77 --- /dev/null +++ b/src/creds/credentialsfactory.h @@ -0,0 +1,32 @@ +/* + * 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_CREDS_CREDENTIALS_FACTORY_H +#define MIRALL_CREDS_CREDENTIALS_FACTORY_H + +class AbstractCredentials; +class QString; + +namespace Mirall +{ + +namespace CredentialsFactory +{ + +AbstractCredentials* create(const QString& type); + +} // ns CredentialsFactory + +} // ns Mirall + +#endif diff --git a/src/creds/dummycredentials.cpp b/src/creds/dummycredentials.cpp new file mode 100644 index 000000000..6857d3218 --- /dev/null +++ b/src/creds/dummycredentials.cpp @@ -0,0 +1,56 @@ +/* + * 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 "creds/dummycredentials.h" +#include "mirall/mirallaccessmanager.h" + +namespace Mirall +{ + +void DummyCredentials::syncContextPreInit(CSYNC*) +{} + +void DummyCredentials::syncContextPreStart(CSYNC*) +{} + +bool DummyCredentials::changed(AbstractCredentials* credentials) const +{ + DummyCredentials* dummy(dynamic_cast< DummyCredentials* >(credentials)); + + return dummy == 0; +} + +QString DummyCredentials::authType() const +{ + return QString::fromLatin1("dummy"); +} + +QNetworkAccessManager* DummyCredentials::getQNAM() const +{ + return new MirallAccessManager; +} + +bool DummyCredentials::ready() const +{ + return true; +} + +void DummyCredentials::fetch() +{ + Q_EMIT(fetched()); +} + +void DummyCredentials::persistForUrl(const QString&) +{} + +} // ns Mirall diff --git a/src/creds/dummycredentials.h b/src/creds/dummycredentials.h new file mode 100644 index 000000000..bd234699b --- /dev/null +++ b/src/creds/dummycredentials.h @@ -0,0 +1,39 @@ +/* + * 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_CREDS_DUMMY_CREDENTIALS_H +#define MIRALL_CREDS_DUMMY_CREDENTIALS_H + +#include "creds/abstractcredentials.h" + +namespace Mirall +{ + +class DummyCredentials : public AbstractCredentials +{ + Q_OBJECT + +public: + void syncContextPreInit(CSYNC* ctx); + void syncContextPreStart(CSYNC* ctx); + bool changed(AbstractCredentials* credentials) const; + QString authType() const; + QNetworkAccessManager* getQNAM() const; + bool ready() const; + void fetch(); + void persistForUrl(const QString& url); +}; + +} // ns Mirall + +#endif diff --git a/src/mirall/credentialstore.cpp b/src/creds/http/credentialstore.cpp index 503483eff..19229514b 100644 --- a/src/mirall/credentialstore.cpp +++ b/src/creds/http/credentialstore.cpp @@ -16,8 +16,8 @@ #include "config.h" -#include "mirall/credentialstore.h" -#include "mirall/mirallconfigfile.h" +#include "creds/http/credentialstore.h" +#include "creds/http/httpconfigfile.h" #include "mirall/theme.h" #ifdef WITH_QTKEYCHAIN @@ -68,11 +68,11 @@ CredentialStore::CredState CredentialStore::state() void CredentialStore::fetchCredentials() { - MirallConfigFile cfgFile; + HttpConfigFile cfgFile; bool ok = false; QString pwd; - _user = cfgFile.ownCloudUser(); + _user = cfgFile.user(); _url = cfgFile.ownCloudUrl(); QString key = keyChainKey(_url); @@ -88,8 +88,9 @@ void CredentialStore::fetchCredentials() case CredentialStore::Settings: { /* Read from config file. */ _state = Fetching; - if( cfgFile.ownCloudPasswordExists() ) { - pwd = cfgFile.ownCloudPasswd(); + cfgFile.fixupOldPassword(); + if( cfgFile.passwordExists() ) { + pwd = cfgFile.password(); ok = true; } else { ok = false; @@ -255,21 +256,21 @@ void CredentialStore::setCredentials( const QString& url, const QString& user, void CredentialStore::saveCredentials( ) { - MirallConfigFile cfgFile; + HttpConfigFile cfgFile; QString key = keyChainKey(_url); if( key.isNull() ) { qDebug() << "Error: Can not save credentials, URL is zero!"; return; } #ifdef WITH_QTKEYCHAIN - WritePasswordJob *job = NULL; #endif + cfgFile.setUser(_user); switch( _type ) { - case CredentialStore::KeyChain: + case CredentialStore::KeyChain: { #ifdef WITH_QTKEYCHAIN + WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName()); // Set password in KeyChain - job = new WritePasswordJob(Theme::instance()->appName()); job->setKey( key ); job->setTextData(_passwd); @@ -278,9 +279,10 @@ void CredentialStore::saveCredentials( ) _state = AsyncWriting; job->start(); #endif + } break; case CredentialStore::Settings: - cfgFile.writePassword( _passwd ); + cfgFile.setPassword( _passwd ); reset(); break; default: @@ -309,8 +311,8 @@ void CredentialStore::slotKeyChainWriteFinished( QKeychain::Job *job ) } else { qDebug() << "Successfully stored password for user " << _user; // Try to remove password formerly stored in the config file. - MirallConfigFile cfgFile; - cfgFile.clearPasswordFromConfig(); + HttpConfigFile cfgFile; + cfgFile.removePassword(); _state = NotFetched; } } else { diff --git a/src/mirall/credentialstore.h b/src/creds/http/credentialstore.h index 2732e603c..2732e603c 100644 --- a/src/mirall/credentialstore.h +++ b/src/creds/http/credentialstore.h diff --git a/src/creds/http/httpconfigfile.cpp b/src/creds/http/httpconfigfile.cpp new file mode 100644 index 000000000..e1e7a734b --- /dev/null +++ b/src/creds/http/httpconfigfile.cpp @@ -0,0 +1,81 @@ +/* + * 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 "creds/http/httpconfigfile.h" + +namespace Mirall +{ + +namespace +{ + +const char userC[] = "user"; +const char passwdC[] = "passwd"; +const char oldPasswdC[] = "password"; + +} // ns + +QString HttpConfigFile::user() const +{ + return retrieveData(QString(), QLatin1String(userC)).toString(); +} + +void HttpConfigFile::setUser(const QString& user) +{ + storeData(QString(), QLatin1String(userC), QVariant(user)); +} + +QString HttpConfigFile::password() const +{ + const QVariant passwd(retrieveData(QString(), QLatin1String(passwdC))); + + if (passwd.isValid()) { + return QString::fromUtf8(QByteArray::fromBase64(passwd.toByteArray())); + } + + return QString(); +} + +void HttpConfigFile::setPassword(const QString& password) +{ + QByteArray pwdba = password.toUtf8(); + storeData( QString(), QLatin1String(passwdC), QVariant(pwdba.toBase64()) ); + removeOldPassword(); +} + +bool HttpConfigFile::passwordExists() const +{ + return dataExists(QString(), QLatin1String(passwdC)); +} + +void HttpConfigFile::removePassword() +{ + removeOldPassword(); + removeData(QString(), QLatin1String(passwdC)); +} + +void HttpConfigFile::fixupOldPassword() +{ + const QString old(QString::fromLatin1(oldPasswdC)); + + if (dataExists(QString(), old)) { + setPassword(retrieveData(QString(), old).toString()); + } +} + +void HttpConfigFile::removeOldPassword() +{ + removeData(QString(), QLatin1String(oldPasswdC)); +} + +} // ns Mirall diff --git a/src/creds/http/httpconfigfile.h b/src/creds/http/httpconfigfile.h new file mode 100644 index 000000000..2e690054f --- /dev/null +++ b/src/creds/http/httpconfigfile.h @@ -0,0 +1,40 @@ +/* + * 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_CREDS_HTTP_CONFIG_FILE_H +#define MIRALL_CREDS_HTTP_CONFIG_FILE_H + +#include "mirall/mirallconfigfile.h" + +namespace Mirall +{ + +class HttpConfigFile : public MirallConfigFile +{ +public: + QString user() const; + void setUser(const QString& user); + + QString password() const; + void setPassword(const QString& password); + bool passwordExists() const; + void removePassword(); + void fixupOldPassword(); + +private: + void removeOldPassword(); +}; + +} // ns Mirall + +#endif diff --git a/src/creds/httpcredentials.cpp b/src/creds/httpcredentials.cpp new file mode 100644 index 000000000..5105b2a1e --- /dev/null +++ b/src/creds/httpcredentials.cpp @@ -0,0 +1,252 @@ +/* + * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> + * Copyright (C) by Klaas Freitag <freitag@kde.org> + * 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 <QMutex> + +#include "creds/httpcredentials.h" +#include "mirall/owncloudinfo.h" +#include "mirall/mirallconfigfile.h" +#include "mirall/mirallaccessmanager.h" +#include "mirall/utility.h" +#include "creds/http/credentialstore.h" + +namespace Mirall +{ + +namespace +{ + +int getauth(const char *prompt, + char *buf, + size_t len, + int /*echo*/, + int /*verify*/, + void */*userdata*/) +{ + int re = 0; + QMutex mutex; + MirallConfigFile cfg; + HttpCredentials* http_credentials = dynamic_cast< HttpCredentials* > (cfg.getCredentials()); + + if (!http_credentials) { + qDebug() << "Not a HTTP creds instance!"; + return -1; + } + + QString qPrompt = QString::fromLatin1( prompt ).trimmed(); + QString user = http_credentials->user(); + QString pwd = http_credentials->password(); + + if( qPrompt == QLatin1String("Enter your username:") ) { + // qDebug() << "OOO Username requested!"; + QMutexLocker locker( &mutex ); + qstrncpy( buf, user.toUtf8().constData(), len ); + } else if( qPrompt == QLatin1String("Enter your password:") ) { + QMutexLocker locker( &mutex ); + // qDebug() << "OOO Password requested!"; + qstrncpy( buf, pwd.toUtf8().constData(), len ); + } else { + if( qPrompt.startsWith( QLatin1String("There are problems with the SSL certificate:"))) { + // SSL is requested. If the program came here, the SSL check was done by mirall + // It needs to be checked if the chain is still equal to the one which + // was verified by the user. + QRegExp regexp("fingerprint: ([\\w\\d:]+)"); + bool certOk = false; + + int pos = 0; + + // This is the set of certificates which QNAM accepted, so we should accept + // them as well + QList<QSslCertificate> certs = ownCloudInfo::instance()->certificateChain(); + + while (!certOk && (pos = regexp.indexIn(qPrompt, 1+pos)) != -1) { + QString neon_fingerprint = regexp.cap(1); + + foreach( const QSslCertificate& c, certs ) { + QString verified_shasum = Utility::formatFingerprint(c.digest(QCryptographicHash::Sha1).toHex()); + qDebug() << "SSL Fingerprint from neon: " << neon_fingerprint << " compared to verified: " << verified_shasum; + if( verified_shasum == neon_fingerprint ) { + certOk = true; + break; + } + } + } + // certOk = false; DEBUG setting, keep disabled! + if( !certOk ) { // Problem! + qstrcpy( buf, "no" ); + re = -1; + } else { + qstrcpy( buf, "yes" ); // Certificate is fine! + } + } else { + qDebug() << "Unknown prompt: <" << prompt << ">"; + re = -1; + } + } + return re; +} + +} // ns + +HttpCredentials::HttpCredentials() + : _user(), + _password(), + _ready(false), + _attempts() +{} + +HttpCredentials::HttpCredentials(const QString& user, const QString& password) + : _user(user), + _password(password), + _ready(true) +{} + +void HttpCredentials::syncContextPreInit (CSYNC* ctx) +{ + csync_set_auth_callback (ctx, getauth); +} + +void HttpCredentials::syncContextPreStart (CSYNC* ctx) +{ + // TODO: This should not 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 remove this code and keep it in + // csyncthread code (or folder code, git remembers). + QList<QNetworkCookie> cookies(ownCloudInfo::instance()->getLastAuthCookies()); + QString cookiesAsString; + + // Stuff cookies inside csync, then we can avoid the intermediate HTTP 401 reply + // when https://github.com/owncloud/core/pull/4042 is merged. + foreach(QNetworkCookie c, cookies) { + cookiesAsString += c.name(); + cookiesAsString += '='; + cookiesAsString += c.value(); + cookiesAsString += "; "; + } + + csync_set_module_property(ctx, "session_key", cookiesAsString.toLatin1().data()); +} + +bool HttpCredentials::changed(AbstractCredentials* credentials) const +{ + HttpCredentials* other(dynamic_cast< HttpCredentials* >(credentials)); + + if (!other || other->user() != this->user()) { + return true; + } + + return false; +} + +QString HttpCredentials::authType() const +{ + return QString::fromLatin1("http"); +} + +QString HttpCredentials::user() const +{ + return _user; +} + +QString HttpCredentials::password() const +{ + return _password; +} + +QNetworkAccessManager* HttpCredentials::getQNAM() const +{ + MirallAccessManager* qnam = new MirallAccessManager; + + connect( qnam, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), + this, SLOT(slotAuthentication(QNetworkReply*,QAuthenticator*))); + + return qnam; +} + +bool HttpCredentials::ready() const +{ + return _ready; +} + +void HttpCredentials::fetch() +{ + if (_ready) { + Q_EMIT fetched(); + } else { + // TODO: merge CredentialStore into HttpCredentials? + CredentialStore* store(CredentialStore::instance()); + connect(store, SIGNAL(fetchCredentialsFinished(bool)), + this, SLOT(slotCredentialsFetched(bool))); + store->fetchCredentials(); + } +} + +void HttpCredentials::persistForUrl(const QString& url) +{ + CredentialStore* store(CredentialStore::instance()); + store->setCredentials(url, _user, _password); + store->saveCredentials(); +} + +void HttpCredentials::slotCredentialsFetched(bool ok) +{ + _ready = ok; + if (_ready) { + CredentialStore* store(CredentialStore::instance()); + _user = store->user(); + _password = store->password(); + } + Q_EMIT fetched(); +} + +void HttpCredentials::slotAuthentication(QNetworkReply* reply, QAuthenticator* authenticator) +{ + if( !(authenticator && reply) ) return; + + qDebug() << "Authenticating request for " << reply->url(); + + if (_attempts.contains(reply)) { + ++_attempts[reply]; + } else { + connect(reply, SIGNAL(finished()), + this, SLOT(slotReplyFinished())); + _attempts[reply] = 1; + } + // TODO: Replace it with something meaningful... + //if( reply->url().toString().startsWith( webdavUrl( _connection ) ) ) { + if (_attempts[reply] > 1) { + qDebug() << "Too many attempts to authenticate. Stop request."; + reply->close(); + } else { + authenticator->setUser( _user ); + authenticator->setPassword( _password ); + } + //} else { + // qDebug() << "WRN: attempt to authenticate to different url - closing."; + // reply->close(); + //} +} + +void HttpCredentials::slotReplyFinished() +{ + QNetworkReply* reply = qobject_cast< QNetworkReply* >(sender()); + + disconnect(reply, SIGNAL(finished()), + this, SLOT(slotReplyFinished())); + _attempts.remove (reply); +} + +} // ns Mirall diff --git a/src/creds/httpcredentials.h b/src/creds/httpcredentials.h new file mode 100644 index 000000000..07d52640e --- /dev/null +++ b/src/creds/httpcredentials.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> + * Copyright (C) by Klaas Freitag <freitag@kde.org> + * 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. + */ + +#ifndef MIRALL_CREDS_HTTP_CREDENTIALS_H +#define MIRALL_CREDS_HTTP_CREDENTIALS_H + +#include <QMap> + +#include "creds/abstractcredentials.h" + +class QNetworkReply; +class QAuthenticator; + +namespace Mirall +{ + +class HttpCredentials : public AbstractCredentials +{ + Q_OBJECT + +public: + HttpCredentials(); + HttpCredentials(const QString& user, const QString& password); + + void syncContextPreInit(CSYNC* ctx); + void syncContextPreStart(CSYNC* ctx); + bool changed(AbstractCredentials* credentials) const; + QString authType() const; + QNetworkAccessManager* getQNAM() const; + bool ready() const; + void fetch(); + void persistForUrl(const QString& url); + + QString user() const; + QString password() const; + +private Q_SLOTS: + void slotCredentialsFetched(bool); + void slotAuthentication(QNetworkReply*, QAuthenticator*); + void slotReplyFinished(); + +private: + QString _user; + QString _password; + bool _ready; + QMap<QNetworkReply*, int> _attempts; +}; + +} // ns Mirall + +#endif diff --git a/src/creds/shibboleth/shibbolethaccessmanager.cpp b/src/creds/shibboleth/shibbolethaccessmanager.cpp new file mode 100644 index 000000000..5e9d1cf16 --- /dev/null +++ b/src/creds/shibboleth/shibbolethaccessmanager.cpp @@ -0,0 +1,55 @@ +/* + * 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 <QDebug> +#include <QNetworkRequest> + +#include "creds/shibboleth/shibbolethaccessmanager.h" + +namespace Mirall +{ + +ShibbolethAccessManager::ShibbolethAccessManager(const QNetworkCookie& cookie, QObject* parent) + : MirallAccessManager (parent), + _cookie(cookie) +{} + +QNetworkReply* ShibbolethAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData) +{ + if (!_cookie.name().isEmpty()) { + QNetworkCookieJar* jar(cookieJar()); + QUrl url(request.url()); + QList<QNetworkCookie> cookies; + + Q_FOREACH(const QNetworkCookie& cookie, jar->cookiesForUrl(url)) { + if (!cookie.name().startsWith("_shibsession_")) { + cookies << cookie; + } + } + + cookies << _cookie; + jar->setCookiesFromUrl(cookies, url); + } + + qDebug() << "Creating a request to " << request.url().toString() << " with shibboleth cookie:" << _cookie.name(); + + return MirallAccessManager::createRequest (op, request, outgoingData); +} + +void ShibbolethAccessManager::setCookie(const QNetworkCookie& cookie) +{ + qDebug() << "Got new shibboleth cookie:" << cookie.name(); + _cookie = cookie; +} + +} // ns Mirall diff --git a/src/creds/shibboleth/shibbolethaccessmanager.h b/src/creds/shibboleth/shibbolethaccessmanager.h new file mode 100644 index 000000000..e6ee4d25e --- /dev/null +++ b/src/creds/shibboleth/shibbolethaccessmanager.h @@ -0,0 +1,43 @@ +/* + * 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_WIZARD_SHIBBOLETH_ACCESS_MANAGER_H +#define MIRALL_WIZARD_SHIBBOLETH_ACCESS_MANAGER_H + +#include <QNetworkCookie> + +#include "mirall/mirallaccessmanager.h" + +namespace Mirall +{ + +class ShibbolethAccessManager : public MirallAccessManager +{ + Q_OBJECT + +public: + ShibbolethAccessManager(const QNetworkCookie& cookie, QObject* parent = 0); + +public Q_SLOTS: + void setCookie(const QNetworkCookie& cookie); + +protected: + QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData = 0); + +private: + QNetworkCookie _cookie; +}; + +} // ns Mirall + +#endif diff --git a/src/creds/shibboleth/shibbolethcookiejar.cpp b/src/creds/shibboleth/shibbolethcookiejar.cpp new file mode 100644 index 000000000..ad86d6ca6 --- /dev/null +++ b/src/creds/shibboleth/shibbolethcookiejar.cpp @@ -0,0 +1,34 @@ +/* + * 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 "creds/shibboleth/shibbolethcookiejar.h" + +namespace Mirall +{ + +ShibbolethCookieJar::ShibbolethCookieJar (QObject* parent) + : QNetworkCookieJar (parent) +{} + +bool ShibbolethCookieJar::setCookiesFromUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url) +{ + if (QNetworkCookieJar::setCookiesFromUrl (cookieList, url)) { + Q_EMIT newCookiesForUrl (cookieList, url); + + return true; + } + + return false; +} + +} // ns Mirall diff --git a/src/creds/shibboleth/shibbolethcookiejar.h b/src/creds/shibboleth/shibbolethcookiejar.h new file mode 100644 index 000000000..4e4459ba5 --- /dev/null +++ b/src/creds/shibboleth/shibbolethcookiejar.h @@ -0,0 +1,41 @@ +/* + * 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_WIZARD_SHIBBOLETH_COOKIE_JAR_H +#define MIRALL_WIZARD_SHIBBOLETH_COOKIE_JAR_H + +#include <QNetworkCookieJar> +#include <QList> + +class QUrl; +class QNetworkCookie; + +namespace Mirall +{ + +class ShibbolethCookieJar : public QNetworkCookieJar +{ + Q_OBJECT + +public: + ShibbolethCookieJar (QObject* parent = 0); + + virtual bool setCookiesFromUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url); + +Q_SIGNALS: + void newCookiesForUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url); +}; + +} // ns Mirall + +#endif diff --git a/src/creds/shibboleth/shibbolethrefresher.cpp b/src/creds/shibboleth/shibbolethrefresher.cpp new file mode 100644 index 000000000..3f5e00466 --- /dev/null +++ b/src/creds/shibboleth/shibbolethrefresher.cpp @@ -0,0 +1,52 @@ +/* + * 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 <QEventLoop> + +#include "creds/shibboleth/shibbolethrefresher.h" +#include "creds/shibbolethcredentials.h" + +namespace Mirall +{ + +ShibbolethRefresher::ShibbolethRefresher(ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent) + : QObject(parent), + _creds(creds), + _csync_ctx(csync_ctx) +{} + +void ShibbolethRefresher::refresh() +{ + QEventLoop loop; + + connect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)), + this, SLOT(onInvalidatedAndFetched(QByteArray))); + connect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)), + &loop, SLOT(quit())); + QMetaObject::invokeMethod(_creds, "invalidateAndFetch", Qt::QueuedConnection); + loop.exec(); + disconnect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)), + &loop, SLOT(quit())); +} + +void ShibbolethRefresher::onInvalidatedAndFetched(const QByteArray& cookies) +{ + // "cookies" is const and its data() return const void*. We want just void*. + QByteArray myCookies(cookies); + + disconnect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)), + this, SLOT(onInvalidatedAndFetched(QByteArray))); + csync_set_module_property(_csync_ctx, "session_key", myCookies.data()); +} + +} // ns Mirall diff --git a/src/creds/shibboleth/shibbolethrefresher.h b/src/creds/shibboleth/shibbolethrefresher.h new file mode 100644 index 000000000..39d2ef55c --- /dev/null +++ b/src/creds/shibboleth/shibbolethrefresher.h @@ -0,0 +1,47 @@ +/* + * 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_CREDS_SHIBBOLETH_REFRESHER_H +#define MIRALL_CREDS_SHIBBOLETH_REFRESHER_H + +#include <QObject> + +#include <csync.h> + +class QByteArray; + +namespace Mirall +{ + +class ShibbolethCredentials; + +class ShibbolethRefresher : public QObject +{ + Q_OBJECT + +public: + ShibbolethRefresher(ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent = 0); + + void refresh(); + +private Q_SLOTS: + void onInvalidatedAndFetched(const QByteArray& cookieData); + +private: + ShibbolethCredentials* _creds; + CSYNC* _csync_ctx; +}; + +} // ns Mirall + +#endif diff --git a/src/creds/shibboleth/shibbolethwebview.cpp b/src/creds/shibboleth/shibbolethwebview.cpp new file mode 100644 index 000000000..5b39afde7 --- /dev/null +++ b/src/creds/shibboleth/shibbolethwebview.cpp @@ -0,0 +1,52 @@ +/* + * 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 <QNetworkCookie> +#include <QWebFrame> +#include <QWebPage> + +#include "creds/shibboleth/shibbolethcookiejar.h" +#include "creds/shibboleth/shibbolethwebview.h" +#include "mirall/mirallaccessmanager.h" + +namespace Mirall +{ + +ShibbolethWebView::ShibbolethWebView(const QUrl& url, QWidget* parent) + : QWebView(parent) +{ + MirallAccessManager* nm = new MirallAccessManager(this); + ShibbolethCookieJar* jar = new ShibbolethCookieJar(this); + QWebPage* page = new QWebPage(this); + + connect (jar, SIGNAL (newCookiesForUrl (QList<QNetworkCookie>, QUrl)), + this, SLOT (onNewCookiesForUrl (QList<QNetworkCookie>, QUrl))); + + nm->setCookieJar(jar); + page->setNetworkAccessManager(nm); + page->mainFrame ()->load (url); + this->setPage (page); +} + +void ShibbolethWebView::onNewCookiesForUrl (const QList<QNetworkCookie>& cookieList, const QUrl& /*url*/) +{ + Q_FOREACH (const QNetworkCookie& cookie, cookieList) { + if (cookie.name().startsWith ("_shibsession_")) { + Q_EMIT shibbolethCookieReceived (cookie); + + return; + } + } +} + +} // ns Mirall diff --git a/src/creds/shibboleth/shibbolethwebview.h b/src/creds/shibboleth/shibbolethwebview.h new file mode 100644 index 000000000..9fc1179b9 --- /dev/null +++ b/src/creds/shibboleth/shibbolethwebview.h @@ -0,0 +1,42 @@ +/* + * 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_WIZARD_SHIBBOLETH_WEB_VIEW_H +#define MIRALL_WIZARD_SHIBBOLETH_WEB_VIEW_H + +#include <QList> +#include <QWebView> + +class QNetworkCookie; +class QUrl; + +namespace Mirall +{ + +class ShibbolethWebView : public QWebView +{ + Q_OBJECT + +public: + ShibbolethWebView(const QUrl& url, QWidget* parent = 0); + +Q_SIGNALS: + void shibbolethCookieReceived (const QNetworkCookie& cookie); + +private Q_SLOTS: + void onNewCookiesForUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url); +}; + +} // ns Mirall + +#endif diff --git a/src/creds/shibbolethcredentials.cpp b/src/creds/shibbolethcredentials.cpp new file mode 100644 index 000000000..2e2eb01b8 --- /dev/null +++ b/src/creds/shibbolethcredentials.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (C) by Krzesimir Nowak <krzesimir@endocode.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; 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 "creds/shibbolethcredentials.h" +#include "creds/shibboleth/shibbolethaccessmanager.h" +#include "creds/shibboleth/shibbolethwebview.h" +#include "creds/shibboleth/shibbolethrefresher.h" +#include "mirall/owncloudinfo.h" +#include "mirall/mirallconfigfile.h" +#include "mirall/csyncthread.h" + +namespace Mirall +{ + +namespace +{ + +int shibboleth_redirect_callback(CSYNC* csync_ctx, + const char* uri) +{ + if (!csync_ctx || !uri) { + return 1; + } + + const QString qurl(QString::fromLatin1(uri)); + QRegExp shibbolethyWords ("SAML|wayf"); + + shibbolethyWords.setCaseSensitivity (Qt::CaseInsensitive); + if (!qurl.contains(shibbolethyWords)) { + return 1; + } + + QMutex mutex; + QMutexLocker locker(&mutex); + MirallConfigFile cfg; + ShibbolethCredentials* creds = dynamic_cast< ShibbolethCredentials* > (cfg.getCredentials()); + + if (!creds) { + qDebug() << "Not a Shibboleth creds instance!"; + return 1; + } + + ShibbolethRefresher refresher(creds, csync_ctx); + + // blocks + refresher.refresh(); + + return 0; +} + +} // ns + +ShibbolethCredentials::ShibbolethCredentials() + : _shibCookie(), + _ready(false), + _browser(0) +{} + +ShibbolethCredentials::ShibbolethCredentials(const QNetworkCookie& cookie) + : _shibCookie(cookie), + _ready(true), + _browser(0) +{} + +void ShibbolethCredentials::syncContextPreInit(CSYNC*) +{} + +QByteArray ShibbolethCredentials::prepareCookieData() const +{ + QString cookiesAsString; + // TODO: This should not 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 just append shibboleth + // cookies to the "session_key" value and set it in csync module. + QList<QNetworkCookie> cookies(ownCloudInfo::instance()->getLastAuthCookies()); + QMap<QString, QString> uniqueCookies; + + cookies << _shibCookie; + // Stuff cookies inside csync, then we can avoid the intermediate HTTP 401 reply + // when https://github.com/owncloud/core/pull/4042 is merged. + foreach(QNetworkCookie c, cookies) { + const QString cookieName(c.name()); + + if (cookieName.startsWith("_shibsession_")) { + continue; + } + uniqueCookies.insert(cookieName, c.value()); + } + + uniqueCookies.insert(_shibCookie.name(), _shibCookie.value()); + foreach(const QString& cookieName, uniqueCookies.keys()) { + cookiesAsString += cookieName; + cookiesAsString += '='; + cookiesAsString += uniqueCookies[cookieName]; + cookiesAsString += "; "; + } + + return cookiesAsString.toLatin1(); +} + +void ShibbolethCredentials::syncContextPreStart (CSYNC* ctx) +{ + typedef int (*csync_owncloud_redirect_callback_t)(CSYNC* ctx, const char* uri); + + csync_owncloud_redirect_callback_t cb = shibboleth_redirect_callback; + + csync_set_module_property(ctx, "session_key", prepareCookieData().data()); + csync_set_module_property(ctx, "redirect_callback", &cb); +} + +bool ShibbolethCredentials::changed(AbstractCredentials* credentials) const +{ + ShibbolethCredentials* other(dynamic_cast< ShibbolethCredentials* >(credentials)); + + if (!other || other->cookie() != this->cookie()) { + return true; + } + + return false; +} + +QString ShibbolethCredentials::authType() const +{ + return QString::fromLatin1("shibboleth"); +} + +QNetworkCookie ShibbolethCredentials::cookie() const +{ + return _shibCookie; +} + +QNetworkAccessManager* ShibbolethCredentials::getQNAM() const +{ + ShibbolethAccessManager* qnam(new ShibbolethAccessManager(_shibCookie)); + + connect(this, SIGNAL(newCookie(QNetworkCookie)), + qnam, SLOT(setCookie(QNetworkCookie))); + return qnam; +} + +bool ShibbolethCredentials::ready() const +{ + return _ready; +} + +void ShibbolethCredentials::fetch() +{ + if (_ready) { + Q_EMIT fetched(); + } else { + MirallConfigFile cfg; + + _browser = new ShibbolethWebView(QUrl(cfg.ownCloudUrl())); + connect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie)), + this, SLOT(onShibbolethCookieReceived(QNetworkCookie))); + _browser->show (); + } +} + +void ShibbolethCredentials::persistForUrl(const QString& /*url*/) +{ + // nothing to do here, we don't store session cookies. +} + +void ShibbolethCredentials::onShibbolethCookieReceived(const QNetworkCookie& cookie) +{ + _browser->hide(); + disconnect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie)), + this, SLOT(onShibbolethCookieReceived(QNetworkCookie))); + _browser->deleteLater(); + _browser = 0; + _ready = true; + _shibCookie = cookie; + Q_EMIT newCookie(_shibCookie); + Q_EMIT fetched(); +} + +void ShibbolethCredentials::invalidateAndFetch() +{ + _ready = false; + connect (this, SIGNAL(fetched()), + this, SLOT(onFetched())); + fetch(); +} + +void ShibbolethCredentials::onFetched() +{ + disconnect (this, SIGNAL(fetched()), + this, SLOT(onFetched())); + + Q_EMIT invalidatedAndFetched(prepareCookieData()); +} + +} // ns Mirall diff --git a/src/creds/shibbolethcredentials.h b/src/creds/shibbolethcredentials.h new file mode 100644 index 000000000..27c4692ba --- /dev/null +++ b/src/creds/shibbolethcredentials.h @@ -0,0 +1,66 @@ +/* + * 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_CREDS_SHIBBOLETH_CREDENTIALS_H +#define MIRALL_CREDS_SHIBBOLETH_CREDENTIALS_H + +#include <QNetworkCookie> + +#include "creds/abstractcredentials.h" + +namespace Mirall +{ + +class ShibbolethWebView; + +class ShibbolethCredentials : public AbstractCredentials +{ +Q_OBJECT + +public: + ShibbolethCredentials(); + ShibbolethCredentials(const QNetworkCookie& cookie); + + void syncContextPreInit(CSYNC* ctx); + void syncContextPreStart(CSYNC* ctx); + bool changed(AbstractCredentials* credentials) const; + QString authType() const; + QNetworkAccessManager* getQNAM() const; + bool ready() const; + void fetch(); + void persistForUrl(const QString& url); + + QNetworkCookie cookie() const; + +public Q_SLOTS: + void invalidateAndFetch(); + +private Q_SLOTS: + void onShibbolethCookieReceived(const QNetworkCookie& cookie); + void onFetched(); + +Q_SIGNALS: + void newCookie(const QNetworkCookie& cookie); + void invalidatedAndFetched(const QByteArray& cookieData); + +private: + QByteArray prepareCookieData() const; + + QNetworkCookie _shibCookie; + bool _ready; + ShibbolethWebView* _browser; +}; + +} // ns Mirall + +#endif diff --git a/src/mirall/accountsettings.cpp b/src/mirall/accountsettings.cpp index 788ebf39f..495d92300 100644 --- a/src/mirall/accountsettings.cpp +++ b/src/mirall/accountsettings.cpp @@ -18,7 +18,6 @@ #include "mirall/theme.h" #include "mirall/folderman.h" #include "mirall/owncloudinfo.h" -#include "mirall/credentialstore.h" #include "mirall/folderwizard.h" #include "mirall/folderstatusmodel.h" #include "mirall/utility.h" @@ -426,8 +425,7 @@ void AccountSettings::slotOCInfo( const QString& url, const QString& versionStr, qDebug() << "#-------# oC found on " << url; /* enable the open button */ ui->connectLabel->setOpenExternalLinks(true); - ui->connectLabel->setText( tr("Connected to <a href=\"%1\">%1</a> as <i>%2</i>.") - .arg(url).arg( CredentialStore::instance()->user()) ); + ui->connectLabel->setText( tr("Connected to <a href=\"%1\">%1</a>.").arg(url) ); ui->connectLabel->setToolTip( tr("Version: %1 (%2)").arg(versionStr).arg(version)); ui->_ButtonAdd->setEnabled(true); @@ -576,6 +574,12 @@ void AccountSettings::slotSetProgress(const QString& folder, const Progress::Inf } timer->start(5000); break; + case Progress::Invalid: + case Progress::Download: + case Progress::Upload: + case Progress::Inactive: + case Progress::Error: + break; } QString fileProgressString; diff --git a/src/mirall/application.cpp b/src/mirall/application.cpp index 56f14f617..77896e398 100644 --- a/src/mirall/application.cpp +++ b/src/mirall/application.cpp @@ -30,7 +30,6 @@ #include "mirall/theme.h" #include "mirall/mirallconfigfile.h" #include "mirall/updatedetector.h" -#include "mirall/credentialstore.h" #include "mirall/logger.h" #include "mirall/settingsdialog.h" #include "mirall/itemprogressdialog.h" @@ -38,6 +37,8 @@ #include "mirall/inotify.h" #include "mirall/connectionvalidator.h" +#include "creds/abstractcredentials.h" + #if defined(Q_OS_WIN) #include <windows.h> #endif @@ -160,7 +161,7 @@ Application::Application(int &argc, char **argv) : setupSystemTray(); slotSetupProxy(); - int cnt = folderMan->setupFolders(); + folderMan->setupFolders(); // startup procedure. QTimer::singleShot( 0, this, SLOT( slotCheckConnection() )); @@ -193,13 +194,41 @@ void Application::slotStartUpdateDetector() void Application::slotCheckConnection() { + if( checkConfigExists(false) ) { + MirallConfigFile cfg; + AbstractCredentials* credentials(cfg.getCredentials()); + + if (! credentials->ready()) { + connect( credentials, SIGNAL(fetched()), + this, SLOT(slotCredentialsFetched())); + credentials->fetch(); + } else { + runValidator(); + } + } else { + // the call to checkConfigExists opens the setup wizard + // if the config does not exist. Nothing to do here. + } +} + +void Application::slotCredentialsFetched() +{ + MirallConfigFile cfg; + AbstractCredentials* credentials(cfg.getCredentials()); + + disconnect(credentials, SIGNAL(fetched()), + this, SLOT(slotCredentialsFetched())); + runValidator(); +} + +void Application::runValidator() +{ _conValidator = new ConnectionValidator(); connect( _conValidator, SIGNAL(connectionResult(ConnectionValidator::Status)), this, SLOT(slotConnectionValidatorResult(ConnectionValidator::Status)) ); _conValidator->checkConnection(); } - void Application::slotConnectionValidatorResult(ConnectionValidator::Status status) { qDebug() << "Connection Validator Result: " << _conValidator->statusString(status); @@ -221,6 +250,8 @@ void Application::slotConnectionValidatorResult(ConnectionValidator::Status stat computeOverallSyncStatus(); setupContextMenu(); + } else if( status == ConnectionValidator::NotConfigured ) { + // this can not happen, it should be caught in first step of startup. } else { // What else? } @@ -608,21 +639,25 @@ void Application::slotTrayClicked( QSystemTrayIcon::ActivationReason reason ) // Linux, not on Mac. They want a menu entry. #if defined Q_WS_WIN || defined Q_WS_X11 if( reason == QSystemTrayIcon::Trigger ) { - slotCheckConfig(); + checkConfigExists(true); // start settings if config is existing. } #endif } -void Application::slotCheckConfig() +bool Application::checkConfigExists(bool openSettings) { // if no config file is there, start the configuration wizard. MirallConfigFile cfgFile; if( cfgFile.exists() ) { - slotSettings(); + if( openSettings ) { + slotSettings(); + } + return true; } else { qDebug() << "No configured folders yet, starting setup wizard"; OwncloudSetupWizard::runWizard(this, SLOT(slotownCloudWizardDone(int))); + return false; } } @@ -706,7 +741,7 @@ void Application::parseOptions(const QStringList &options) //parse options; if help or bad option exit while (it.hasNext()) { QString option = it.next(); - if (option == QLatin1String("--help") || option == QLatin1String("-h")) { + if (option == QLatin1String("--help") || option == QLatin1String("-h")) { setHelp(); break; } else if (option == QLatin1String("--logwindow") || @@ -743,7 +778,7 @@ void Application::parseOptions(const QStringList &options) setHelp(); break; } - } + } } void Application::computeOverallSyncStatus() diff --git a/src/mirall/application.h b/src/mirall/application.h index 46e381619..65557a58e 100644 --- a/src/mirall/application.h +++ b/src/mirall/application.h @@ -68,6 +68,7 @@ protected: void setupContextMenu(); void setupLogBrowser(); void enterNextLogFile(); + bool checkConfigExists(bool openSettings); //folders have to be disabled while making config changes void computeOverallSyncStatus(); @@ -83,7 +84,6 @@ signals: protected slots: void slotFoldersChanged(); - void slotCheckConfig(); void slotSettings(); void slotItemProgressDialog(); void slotParseOptions( const QString& ); @@ -105,10 +105,13 @@ protected slots: void slotProgressSyncProblem(const QString& folder, const Progress::SyncProblem &problem); void slotDisplayIdle(); void slotHelp(); + void slotShowRecentChanges(); + void slotCredentialsFetched(); private: void setHelp(); void raiseDialog( QWidget* ); void rebuildRecentMenus(); + void runValidator(); Systray *_tray; QAction *_actionOpenoC; diff --git a/src/mirall/connectionvalidator.cpp b/src/mirall/connectionvalidator.cpp index 0d2536f0d..3c49efac1 100644 --- a/src/mirall/connectionvalidator.cpp +++ b/src/mirall/connectionvalidator.cpp @@ -17,7 +17,6 @@ #include "mirall/owncloudinfo.h" #include "mirall/mirallconfigfile.h" #include "mirall/theme.h" -#include "mirall/credentialstore.h" namespace Mirall { @@ -28,7 +27,8 @@ ConnectionValidator::ConnectionValidator(QObject *parent) : } ConnectionValidator::ConnectionValidator(const QString& connection, QObject *parent) - :_connection(connection) + : QObject(parent), + _connection(connection) { ownCloudInfo::instance()->setCustomConfigHandle(_connection); } @@ -93,7 +93,7 @@ void ConnectionValidator::checkConnection() } } -void ConnectionValidator::slotStatusFound( const QString& url, const QString& versionStr, const QString& version, const QString& edition) +void ConnectionValidator::slotStatusFound( const QString& url, const QString& versionStr, const QString& version, const QString& /*edition*/) { // status.php was found. qDebug() << "** Application: ownCloud found: " << url << " with version " << versionStr << "(" << version << ")"; @@ -115,7 +115,7 @@ void ConnectionValidator::slotStatusFound( const QString& url, const QString& ve return; } - QTimer::singleShot( 0, this, SLOT( slotFetchCredentials() )); + QTimer::singleShot( 0, this, SLOT( slotCheckAuthentication() )); } // status.php could not be loaded. @@ -133,50 +133,6 @@ void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply) } -void ConnectionValidator::slotFetchCredentials() -{ - if( _connection.isEmpty() ) { - connect( CredentialStore::instance(), SIGNAL(fetchCredentialsFinished(bool)), - this, SLOT(slotCredentialsFetched(bool)) ); - CredentialStore::instance()->fetchCredentials(); - } else { - // Pull credentials from Mirall config. - slotCredentialsFetched( true ); - } -} - -void ConnectionValidator::slotCredentialsFetched( bool ok ) -{ - qDebug() << "Credentials successfully fetched: " << ok; - disconnect( CredentialStore::instance(), SIGNAL(fetchCredentialsFinished(bool)) ); - - if( ! ok ) { - Status stat; - _errors << tr("Error: Could not retrieve the password!"); - _errors << CredentialStore::instance()->errorMessage(); - stat = CredentialError; - - qDebug() << "Could not fetch credentials" << _errors; - - emit connectionResult( stat ); - } else { - QString user, pwd; - if( _connection.isEmpty() ) { - user = CredentialStore::instance()->user(); - pwd = CredentialStore::instance()->password(); - } else { - // in case of reconfiguration, the _connection is set. - MirallConfigFile cfg(_connection); - user = cfg.ownCloudUser(); - pwd = cfg.ownCloudPasswd(); - } - ownCloudInfo::instance()->setCredentials( user, pwd ); - - // Credential fetched ok. - QTimer::singleShot( 0, this, SLOT( slotCheckAuthentication() )); - } -} - void ConnectionValidator::slotCheckAuthentication() { connect( ownCloudInfo::instance(), SIGNAL(ownCloudDirExists(QString,QNetworkReply*)), @@ -190,7 +146,6 @@ void ConnectionValidator::slotCheckAuthentication() void ConnectionValidator::slotAuthCheck( const QString& ,QNetworkReply *reply ) { - bool ok = true; Status stat = Connected; if( reply->error() == QNetworkReply::AuthenticationRequiredError || @@ -198,7 +153,6 @@ void ConnectionValidator::slotAuthCheck( const QString& ,QNetworkReply *reply ) qDebug() << "******** Password is wrong!"; _errors << "The provided credentials are wrong."; stat = CredentialsWrong; - ok = false; } // disconnect from ownCloud Info signals @@ -206,7 +160,6 @@ void ConnectionValidator::slotAuthCheck( const QString& ,QNetworkReply *reply ) this,SLOT(slotAuthCheck(QString,QNetworkReply*))); emit connectionResult( stat ); - } diff --git a/src/mirall/connectionvalidator.h b/src/mirall/connectionvalidator.h index 51237ed4e..93998eb3f 100644 --- a/src/mirall/connectionvalidator.h +++ b/src/mirall/connectionvalidator.h @@ -58,8 +58,6 @@ protected slots: void slotStatusFound( const QString&, const QString&, const QString&, const QString& ); void slotNoStatusFound(QNetworkReply *); - void slotFetchCredentials(); - void slotCredentialsFetched( bool ); void slotCheckAuthentication(); void slotAuthCheck( const QString& ,QNetworkReply * ); diff --git a/src/mirall/csyncthread.cpp b/src/mirall/csyncthread.cpp index fffe127d5..245152102 100644 --- a/src/mirall/csyncthread.cpp +++ b/src/mirall/csyncthread.cpp @@ -18,6 +18,7 @@ #include "mirall/theme.h" #include "mirall/logger.h" #include "mirall/owncloudinfo.h" +#include "creds/abstractcredentials.h" #ifdef Q_OS_WIN #include <windows.h> @@ -338,21 +339,28 @@ void CSyncThread::startSync() csync_set_module_property(_csync_ctx, "csync_context", _csync_ctx); csync_set_userdata(_csync_ctx, this); - 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.toAscii().data()); - } + // 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. + cfg.getCredentials()->syncContextPreStart(_csync_ctx); + // 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 ); + + qDebug() << "#### Update start #################################################### >>"; if( csync_update(_csync_ctx) < 0 ) { handleSyncError(_csync_ctx, "csync_update"); @@ -361,7 +369,7 @@ void CSyncThread::startSync() qDebug() << "<<#### Update end ###########################################################"; if( csync_reconcile(_csync_ctx) < 0 ) { - handleSyncError(_csync_ctx, "cysnc_reconcile"); + handleSyncError(_csync_ctx, "csync_reconcile"); return; } @@ -481,10 +489,4 @@ void CSyncThread::cb_progress( CSYNC_PROGRESS *progress, void *userdata ) } -void CSyncThread::setLastAuthCookies(QList<QNetworkCookie> c) -{ - _lastAuthCookies = c; -} - - -} +} // ns Mirall diff --git a/src/mirall/csyncthread.h b/src/mirall/csyncthread.h index 40a376035..14d8e0dd3 100644 --- a/src/mirall/csyncthread.h +++ b/src/mirall/csyncthread.h @@ -44,8 +44,6 @@ public: Q_INVOKABLE void startSync(); - void setLastAuthCookies(QList<QNetworkCookie> c); - signals: void fileReceived( const QString& ); void fileRemoved( const QString& ); @@ -87,9 +85,7 @@ private: bool _hasFiles; // true if there is at least one file that is not ignored or removed - QList<QNetworkCookie> _lastAuthCookies; - - friend class CSyncRunScopeHelper; + friend struct CSyncRunScopeHelper; }; } diff --git a/src/mirall/fileutils.h b/src/mirall/fileutils.h index e074585ad..117cf6c05 100644 --- a/src/mirall/fileutils.h +++ b/src/mirall/fileutils.h @@ -25,7 +25,7 @@ class FileUtils public: enum SubFolderListOption { SubFolderNoOptions = 0x0, - SubFolderRecursive = 0x1, + SubFolderRecursive = 0x1 }; Q_DECLARE_FLAGS(SubFolderListOptions, SubFolderListOption) diff --git a/src/mirall/folder.cpp b/src/mirall/folder.cpp index 16fe8c1a1..6eb3312ae 100644 --- a/src/mirall/folder.cpp +++ b/src/mirall/folder.cpp @@ -21,8 +21,7 @@ #include "mirall/syncresult.h" #include "mirall/logger.h" #include "mirall/owncloudinfo.h" -#include "mirall/credentialstore.h" -#include "mirall/utility.h" +#include "creds/abstractcredentials.h" #include <QDebug> #include <QTimer> @@ -34,17 +33,18 @@ namespace Mirall { -void csyncLogCatcher(CSYNC *ctx, - int verbosity, - const char *function, +void csyncLogCatcher(CSYNC */*ctx*/, + int /*verbosity*/, + const char */*function*/, const char *buffer, - void *userdata) + void */*userdata*/) { Logger::instance()->csyncLog( QString::fromUtf8(buffer) ); } Folder::Folder(const QString &alias, const QString &path, const QString& secondPath, QObject *parent) : QObject(parent) + , _pollTimer(new QTimer(this)) , _path(path) , _secondPath(secondPath) , _alias(alias) @@ -95,7 +95,7 @@ bool Folder::init() csync_enable_conflictcopys(_csync_ctx); setIgnoredFiles(); - csync_set_auth_callback( _csync_ctx, getauth ); + cfgFile.getCredentials()->syncContextPreInit(_csync_ctx); if( csync_init( _csync_ctx ) < 0 ) { qDebug() << "Could not initialize csync!" << csync_get_error(_csync_ctx) << csync_get_error_string(_csync_ctx); @@ -214,7 +214,7 @@ SyncResult Folder::syncResult() const return _syncResult; } -void Folder::evaluateSync(const QStringList &pathList) +void Folder::evaluateSync(const QStringList &/*pathList*/) { if( !_enabled ) { qDebug() << "*" << alias() << "sync skipped, disabled!"; @@ -402,70 +402,6 @@ const char* Folder::proxyTypeToCStr(QNetworkProxy::ProxyType type) } } -int Folder::getauth(const char *prompt, - char *buf, - size_t len, - int echo, - int verify, - void *userdata - ) -{ - int re = 0; - QMutex mutex; - - QString qPrompt = QString::fromLatin1( prompt ).trimmed(); - QString user = CredentialStore::instance()->user(); - QString pwd = CredentialStore::instance()->password(); - - if( qPrompt == QLatin1String("Enter your username:") ) { - // qDebug() << "OOO Username requested!"; - QMutexLocker locker( &mutex ); - qstrncpy( buf, user.toUtf8().constData(), len ); - } else if( qPrompt == QLatin1String("Enter your password:") ) { - QMutexLocker locker( &mutex ); - // qDebug() << "OOO Password requested!"; - qstrncpy( buf, pwd.toUtf8().constData(), len ); - } else { - if( qPrompt.startsWith( QLatin1String("There are problems with the SSL certificate:"))) { - // SSL is requested. If the program came here, the SSL check was done by mirall - // It needs to be checked if the chain is still equal to the one which - // was verified by the user. - QRegExp regexp("fingerprint: ([\\w\\d:]+)"); - bool certOk = false; - - int pos = 0; - - // This is the set of certificates which QNAM accepted, so we should accept - // them as well - QList<QSslCertificate> certs = ownCloudInfo::instance()->certificateChain(); - - while (!certOk && (pos = regexp.indexIn(qPrompt, 1+pos)) != -1) { - QString neon_fingerprint = regexp.cap(1); - - foreach( const QSslCertificate& c, certs ) { - QString verified_shasum = Utility::formatFingerprint(c.digest(QCryptographicHash::Sha1).toHex()); - qDebug() << "SSL Fingerprint from neon: " << neon_fingerprint << " compared to verified: " << verified_shasum; - if( verified_shasum == neon_fingerprint ) { - certOk = true; - break; - } - } - } - // certOk = false; DEBUG setting, keep disabled! - if( !certOk ) { // Problem! - qstrcpy( buf, "no" ); - re = -1; - } else { - qstrcpy( buf, "yes" ); // Certificate is fine! - } - } else { - qDebug() << "Unknown prompt: <" << prompt << ">"; - re = -1; - } - } - return re; -} - void Folder::startSync(const QStringList &pathList) { Q_UNUSED(pathList) @@ -503,7 +439,6 @@ void Folder::startSync(const QStringList &pathList) _thread->setPriority(QThread::LowPriority); setIgnoredFiles(); _csync = new CSyncThread( _csync_ctx ); - _csync->setLastAuthCookies(ownCloudInfo::instance()->getLastAuthCookies()); _csync->moveToThread(_thread); diff --git a/src/mirall/folder.h b/src/mirall/folder.h index c89be8f84..966711c70 100644 --- a/src/mirall/folder.h +++ b/src/mirall/folder.h @@ -185,13 +185,6 @@ protected: void setIgnoredFiles(); void setProxy(); - static int getauth(const char *prompt, - char *buf, - size_t len, - int echo, - int verify, - void *userdata - ); const char* proxyTypeToCStr(QNetworkProxy::ProxyType type); /** diff --git a/src/mirall/folderstatusmodel.cpp b/src/mirall/folderstatusmodel.cpp index 3c9188097..bc2403c96 100644 --- a/src/mirall/folderstatusmodel.cpp +++ b/src/mirall/folderstatusmodel.cpp @@ -26,9 +26,9 @@ FolderStatusModel::FolderStatusModel() } -Qt::ItemFlags FolderStatusModel::flags ( const QModelIndex& ) +Qt::ItemFlags FolderStatusModel::flags ( const QModelIndex& ) const { - return Qt::ItemIsSelectable; + return Qt::ItemIsSelectable | Qt::ItemIsEnabled; } QVariant FolderStatusModel::data(const QModelIndex &index, int role) const @@ -296,7 +296,7 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem & painter->restore(); } -bool FolderStatusDelegate::editorEvent ( QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index ) +bool FolderStatusDelegate::editorEvent ( QEvent * /*event*/, QAbstractItemModel * /*model*/, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/ ) { return false; } diff --git a/src/mirall/folderstatusmodel.h b/src/mirall/folderstatusmodel.h index 7e490a297..7db24f698 100644 --- a/src/mirall/folderstatusmodel.h +++ b/src/mirall/folderstatusmodel.h @@ -24,7 +24,7 @@ class FolderStatusModel : public QStandardItemModel { public: FolderStatusModel(); - virtual Qt::ItemFlags flags( const QModelIndex& ); + virtual Qt::ItemFlags flags( const QModelIndex& ) const; QVariant data(const QModelIndex &index, int role) const; }; diff --git a/src/mirall/folderwatcher_inotify.cpp b/src/mirall/folderwatcher_inotify.cpp index 7ed79d969..4257efb36 100644 --- a/src/mirall/folderwatcher_inotify.cpp +++ b/src/mirall/folderwatcher_inotify.cpp @@ -78,7 +78,7 @@ void FolderWatcherPrivate::slotAddFolderRecursive(const QString &path) qDebug() << " `-> and" << subdirs << "subdirectories"; } -void FolderWatcherPrivate::slotINotifyEvent(int mask, int cookie, const QString &path) +void FolderWatcherPrivate::slotINotifyEvent(int mask, int /*cookie*/, const QString &path) { int lastMask = _lastMask; QString lastPath = _lastPath; diff --git a/src/mirall/inotify.cpp b/src/mirall/inotify.cpp index 8395f7462..126a1d57e 100644 --- a/src/mirall/inotify.cpp +++ b/src/mirall/inotify.cpp @@ -47,7 +47,7 @@ INotify::INotify(QObject *parent, int mask) _buffer = (char *) malloc(_buffer_size); } -void INotify::slotActivated(int fd) +void INotify::slotActivated(int /*fd*/) { int len; struct inotify_event* event; @@ -82,7 +82,7 @@ void INotify::slotActivated(int fd) // reset counter i = 0; // while there are enough events in the buffer - while(i + sizeof(struct inotify_event) < len) { + 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 diff --git a/src/mirall/logbrowser.cpp b/src/mirall/logbrowser.cpp index fbdcebada..2ddf41710 100644 --- a/src/mirall/logbrowser.cpp +++ b/src/mirall/logbrowser.cpp @@ -57,8 +57,8 @@ LogWidget::LogWidget(QWidget *parent) LogBrowser::LogBrowser(QWidget *parent) : QDialog(parent), _logWidget( new LogWidget(parent) ), - _logstream(0), - _doFileFlush(false) + _doFileFlush(false), + _logstream(0) { setObjectName("LogBrowser"); // for save/restoreGeometry() setWindowTitle(tr("Log Output")); diff --git a/src/mirall/mirallaccessmanager.cpp b/src/mirall/mirallaccessmanager.cpp new file mode 100644 index 000000000..1e627bd10 --- /dev/null +++ b/src/mirall/mirallaccessmanager.cpp @@ -0,0 +1,34 @@ +/* + * 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 "mirall/mirallaccessmanager.h" +#include "mirall/utility.h" + +namespace Mirall +{ + +MirallAccessManager::MirallAccessManager(QObject* parent) + : QNetworkAccessManager (parent) +{} + +QNetworkReply* MirallAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData) +{ + QNetworkRequest newRequest(request); + + newRequest.setRawHeader( QByteArray("User-Agent"), Utility::userAgentString()); + return QNetworkAccessManager::createRequest (op, newRequest, outgoingData); +} + +} // ns Mirall diff --git a/src/mirall/mirallaccessmanager.h b/src/mirall/mirallaccessmanager.h new file mode 100644 index 000000000..a8dcbab30 --- /dev/null +++ b/src/mirall/mirallaccessmanager.h @@ -0,0 +1,35 @@ +/* + * 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 <QNetworkAccessManager> + +namespace Mirall +{ + +class MirallAccessManager : public QNetworkAccessManager +{ + Q_OBJECT + +public: + MirallAccessManager(QObject* parent = 0); + +protected: + QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest& request, QIODevice* outgoingData = 0); +}; + +} // ns Mirall + +#endif diff --git a/src/mirall/mirallconfigfile.cpp b/src/mirall/mirallconfigfile.cpp index 21817c944..81a7c5671 100644 --- a/src/mirall/mirallconfigfile.cpp +++ b/src/mirall/mirallconfigfile.cpp @@ -18,8 +18,8 @@ #include "mirall/owncloudinfo.h" #include "mirall/owncloudtheme.h" #include "mirall/theme.h" -#include "mirall/credentialstore.h" - +#include "creds/abstractcredentials.h" +#include "creds/credentialsfactory.h" #include <QtCore> #include <QtGui> @@ -29,8 +29,7 @@ namespace Mirall { static const char urlC[] = "url"; -static const char userC[] = "user"; -static const char passwdC[] = "passwd"; +static const char authTypeC[] = "authType"; static const char caCertsKeyC[] = "CaCertificates"; static const char remotePollIntervalC[] = "remotePollInterval"; @@ -57,11 +56,29 @@ static const char maxLogLinesC[] = "Logging/maxLogLines"; QString MirallConfigFile::_oCVersion; QString MirallConfigFile::_confDir = QString::null; bool MirallConfigFile::_askedUser = false; +QMap< QString, MirallConfigFile::SharedCreds > MirallConfigFile::credentialsPerConfig; MirallConfigFile::MirallConfigFile( const QString& appendix ) :_customHandle(appendix) { QSettings::setDefaultFormat(QSettings::IniFormat); + if (! credentialsPerConfig.contains(_customHandle)) { + QString con( _customHandle ); + if( _customHandle.isEmpty() ) con = defaultConnection(); + + const QString config = configFile(); + qDebug() << "Loading config: " << config; + + QSettings settings(config, QSettings::IniFormat); + settings.setIniCodec("UTF-8"); + settings.beginGroup( con ); + + QString type = settings.value( QLatin1String(authTypeC) ).toString(); + + qDebug() << "Getting credentials of type " << type << " for " << _customHandle; + + credentialsPerConfig.insert(_customHandle, SharedCreds(CredentialsFactory::create (type))); + } } void MirallConfigFile::setConfDir(const QString &value) @@ -77,30 +94,30 @@ void MirallConfigFile::setConfDir(const QString &value) bool MirallConfigFile::optionalDesktopNotifications() const { - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); return settings.value(QLatin1String(optionalDesktopNoficationsC), true).toBool(); } void MirallConfigFile::setOptionalDesktopNotifications(bool show) { - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); settings.setValue(QLatin1String(optionalDesktopNoficationsC), show); settings.sync(); } QString MirallConfigFile::seenVersion() const { - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); return settings.value(QLatin1String(seenVersionC)).toString(); } void MirallConfigFile::setSeenVersion(const QString &version) { - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); settings.setValue(QLatin1String(seenVersionC), version); settings.sync(); } @@ -108,8 +125,8 @@ void MirallConfigFile::setSeenVersion(const QString &version) void MirallConfigFile::saveGeometry(QWidget *w) { Q_ASSERT(!w->objectName().isNull()); - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); settings.beginGroup(w->objectName()); settings.setValue(QLatin1String(geometryC), w->saveGeometry()); settings.sync(); @@ -122,9 +139,10 @@ void MirallConfigFile::restoreGeometry(QWidget *w) QString MirallConfigFile::configPath() const { - QString dir = _confDir; - if( _confDir.isEmpty() ) + if( _confDir.isEmpty() ) { _confDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation); + } + QString dir = _confDir; if( !dir.endsWith(QLatin1Char('/')) ) dir.append(QLatin1Char('/')); return dir; @@ -176,13 +194,13 @@ QString MirallConfigFile::configFile() const if( qApp->applicationName().isEmpty() ) { qApp->setApplicationName( Theme::instance()->appNameGUI() ); } - QString dir = configPath() + Theme::instance()->configFileName(); + QString file = configPath() + Theme::instance()->configFileName(); if( !_customHandle.isEmpty() ) { - dir.append( QLatin1Char('_')); - dir.append( _customHandle ); - qDebug() << " OO Custom config file in use: " << dir; + file.append( QLatin1Char('_')); + file.append( _customHandle ); + qDebug() << __PRETTY_FUNCTION__ << " OO Custom config file in use: " << file; } - return dir; + return file; } bool MirallConfigFile::exists() @@ -201,8 +219,8 @@ bool MirallConfigFile::connectionExists( const QString& conn ) QString con = conn; if( conn.isEmpty() ) con = defaultConnection(); - QSettings settings( configFile(), QSettings::IniFormat); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); settings.beginGroup(conn); return settings.contains( QLatin1String(urlC) ); @@ -211,87 +229,80 @@ bool MirallConfigFile::connectionExists( const QString& conn ) void MirallConfigFile::writeOwncloudConfig( const QString& connection, const QString& url, - const QString& user, - const QString& passwd ) + AbstractCredentials* credentials) { const QString file = configFile(); qDebug() << "*** writing mirall config to " << file; - QSettings settings( file, QSettings::IniFormat); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); settings.beginGroup( connection ); settings.setValue( QLatin1String(urlC), url ); - settings.setValue( QLatin1String(userC), user ); - - -#ifdef WITH_QTKEYCHAIN - // Password is stored to QtKeyChain now by default in CredentialStore - // The CredentialStore calls clearPasswordFromConfig after the creds - // were successfully wiritten to delete the passwd entry from config. - qDebug() << "Going to delete the password from settings file."; -#endif - writePassword( passwd ); - + settings.setValue(QLatin1String(authTypeC), credentials->authType()); + credentialsPerConfig.insert(_customHandle, SharedCreds(credentials)); settings.sync(); // check the perms, only read-write for the owner. QFile::setPermissions( file, QFile::ReadOwner|QFile::WriteOwner ); // Store credentials temporar until the config is finalized. - ownCloudInfo::instance()->setCredentials( user, passwd, _customHandle ); + //ownCloudInfo::instance()->setCredentials( user, passwd, _customHandle ); } -// This method is called after the password was successfully stored into the -// QKeyChain in CredentialStore. -void MirallConfigFile::clearPasswordFromConfig( const QString& connection ) +void MirallConfigFile::storeData(const QString& group, const QString& key, const QVariant& value) { - const QString file = configFile(); - QString con( defaultConnection() ); - if( !connection.isEmpty() ) - con = connection; + const QString con(group.isEmpty() ? defaultConnection() : group); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); - QSettings settings( file, QSettings::IniFormat); - settings.setIniCodec( "UTF-8" ); - settings.beginGroup( con ); - settings.remove(QLatin1String(passwdC)); - // old key name - settings.remove(QLatin1String("password")); + settings.beginGroup(con); + settings.setValue(key, value); settings.sync(); } -bool MirallConfigFile::writePassword( const QString& passwd, const QString& connection ) +QVariant MirallConfigFile::retrieveData(const QString& group, const QString& key) const { - const QString file = configFile(); - QString pwd( passwd ); - QString con( defaultConnection() ); - if( !connection.isEmpty() ) - con = connection; + const QString con(group.isEmpty() ? defaultConnection() : group); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); - QSettings settings( file, QSettings::IniFormat); - settings.setIniCodec( "UTF-8" ); + settings.beginGroup(con); + return settings.value(key); +} - // store password into settings file. - settings.beginGroup( con ); - QByteArray pwdba = pwd.toUtf8(); - settings.setValue( QLatin1String(passwdC), QVariant(pwdba.toBase64()) ); - settings.sync(); +void MirallConfigFile::removeData(const QString& group, const QString& key) +{ + const QString con(group.isEmpty() ? defaultConnection() : group); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); - return true; + 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.setIniCodec("UTF-8"); + + settings.beginGroup(con); + return settings.contains(key); } QByteArray MirallConfigFile::caCerts( ) { - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); return settings.value( QLatin1String(caCertsKeyC) ).toByteArray(); } void MirallConfigFile::setCaCerts( const QByteArray & certs ) { - const QString file = configFile(); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); - QSettings settings( file, QSettings::IniFormat); settings.setIniCodec( "UTF-8" ); settings.setValue( QLatin1String(caCertsKeyC), certs ); settings.sync(); @@ -306,6 +317,7 @@ void MirallConfigFile::removeConnection( const QString& connection ) qDebug() << " removing the config file for connection " << con; // Currently its just removing the entire config file + // TODO: Eh? Shouldn't it try to load a file under configFile() and set it to INI? QSettings settings; settings.setIniCodec( "UTF-8" ); settings.beginGroup( con ); @@ -323,8 +335,8 @@ QString MirallConfigFile::ownCloudUrl( const QString& connection) const QString con( connection ); if( connection.isEmpty() ) con = defaultConnection(); - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); settings.beginGroup( con ); QString url = settings.value( QLatin1String(urlC) ).toString(); @@ -332,22 +344,7 @@ QString MirallConfigFile::ownCloudUrl( const QString& connection) const if( ! url.endsWith(QLatin1Char('/'))) url.append(QLatin1String("/")); } - return url; -} - -QString MirallConfigFile::ownCloudUser( const QString& connection ) const -{ - QString con( connection ); - if( connection.isEmpty() ) con = defaultConnection(); - - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); - settings.beginGroup( con ); - - QString user = settings.value( QLatin1String("user") ).toString(); - // qDebug() << "Returning configured owncloud user: " << user; - - return user; + return url; } int MirallConfigFile::remotePollInterval( const QString& connection ) const @@ -355,8 +352,8 @@ int MirallConfigFile::remotePollInterval( const QString& connection ) const QString con( connection ); if( connection.isEmpty() ) con = defaultConnection(); - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); settings.beginGroup( con ); int remoteInterval = settings.value( QLatin1String(remotePollIntervalC), DEFAULT_REMOTE_POLL_INTERVAL ).toInt(); @@ -376,57 +373,13 @@ void MirallConfigFile::setRemotePollInterval(int interval, const QString &connec qDebug() << "Remote Poll interval of " << interval << " is below fife seconds."; return; } - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); settings.beginGroup( con ); settings.setValue(QLatin1String(remotePollIntervalC), interval ); settings.sync(); } -bool MirallConfigFile::ownCloudPasswordExists( const QString& connection ) const -{ - QString con( connection ); - if( connection.isEmpty() ) con = defaultConnection(); - - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); - settings.beginGroup( con ); - - bool rc = false; - if( settings.contains(QLatin1String(passwdC)) ) { - rc = true; - } - return rc; -} - -QString MirallConfigFile::ownCloudPasswd( const QString& connection ) const -{ - QString con( connection ); - if( connection.isEmpty() ) con = defaultConnection(); - - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); - settings.beginGroup( con ); - - QByteArray pwdba = settings.value(QLatin1String(passwdC)).toByteArray(); - if( !pwdba.isEmpty() ) { - return QString::fromUtf8( QByteArray::fromBase64(pwdba) ); - } - - // check the password entry, cleartext from before - // read it and convert to base64, delete the cleartext entry. - QString p = settings.value(QLatin1String("password")).toString(); - - if( ! p.isEmpty() ) { - // its there, save base64-encoded and delete. - pwdba = p.toUtf8(); - settings.setValue( QLatin1String(passwdC), QVariant(pwdba.toBase64()) ); - settings.remove( QLatin1String("password") ); - settings.sync(); - } - return p; -} - QString MirallConfigFile::ownCloudVersion() const { return _oCVersion; @@ -444,8 +397,8 @@ bool MirallConfigFile::ownCloudSkipUpdateCheck( const QString& connection ) cons QString con( connection ); if( connection.isEmpty() ) con = defaultConnection(); - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); settings.beginGroup( con ); bool skipIt = settings.value( QLatin1String(skipUpdateCheckC), false ).toBool(); @@ -458,8 +411,8 @@ void MirallConfigFile::setOwnCloudSkipUpdateCheck( bool skip, const QString& con QString con( connection ); if( connection.isEmpty() ) con = defaultConnection(); - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); settings.beginGroup( con ); settings.setValue( QLatin1String(skipUpdateCheckC), QVariant(skip) ); @@ -469,15 +422,15 @@ void MirallConfigFile::setOwnCloudSkipUpdateCheck( bool skip, const QString& con int MirallConfigFile::maxLogLines() const { - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); return settings.value( QLatin1String(maxLogLinesC), DEFAULT_MAX_LOG_LINES ).toInt(); } void MirallConfigFile::setMaxLogLines( int lines ) { - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); settings.setValue(QLatin1String(maxLogLinesC), lines); settings.sync(); } @@ -505,6 +458,8 @@ void MirallConfigFile::acceptCustomConfig() QString srcConfig = configFile(); // this considers the custom handle + credentialsPerConfig.insert(QString(), credentialsPerConfig[_customHandle]); + credentialsPerConfig.remove(_customHandle); _customHandle.clear(); QString targetConfig = configFile(); QString targetBak = targetConfig + QLatin1String(".bak"); @@ -526,17 +481,7 @@ void MirallConfigFile::acceptCustomConfig() } QFile::remove( targetBak ); - // inform the credential store about the password change. - QString url = ownCloudUrl(); - QString user = ownCloudUser(); - QString pwd = ownCloudPasswd(); - - if( pwd.isEmpty() ) { - qDebug() << "Password is empty, skipping to write cred store."; - } else { - CredentialStore::instance()->setCredentials(url, user, pwd); - CredentialStore::instance()->saveCredentials(); - } + credentialsPerConfig[QString()]->persistForUrl(ownCloudUrl()); } void MirallConfigFile::setProxyType(int proxyType, @@ -545,8 +490,8 @@ void MirallConfigFile::setProxyType(int proxyType, const QString& user, const QString& pass) { - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); settings.setValue(QLatin1String(proxyTypeC), proxyType); @@ -564,8 +509,8 @@ void MirallConfigFile::setProxyType(int proxyType, QVariant MirallConfigFile::getValue(const QString& param, const QString& group, const QVariant& defaultValue) const { - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); if (!group.isEmpty()) settings.beginGroup(group); @@ -574,8 +519,8 @@ QVariant MirallConfigFile::getValue(const QString& param, const QString& group, void MirallConfigFile::setValue(const QString& key, const QVariant &value) { - QSettings settings( configFile(), QSettings::IniFormat ); - settings.setIniCodec( "UTF-8" ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); settings.setValue(key, value); } @@ -653,14 +598,21 @@ void MirallConfigFile::setDownloadLimit(int kbytes) bool MirallConfigFile::monoIcons() const { - QSettings settings( configFile(), QSettings::IniFormat ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); return settings.value(QLatin1String(monoIconsC), false).toBool(); } void MirallConfigFile::setMonoIcons(bool useMonoIcons) { - QSettings settings( configFile(), QSettings::IniFormat ); + QSettings settings(configFile(), QSettings::IniFormat); + settings.setIniCodec("UTF-8"); settings.setValue(QLatin1String(monoIconsC), useMonoIcons); } +AbstractCredentials* MirallConfigFile::getCredentials() const +{ + return credentialsPerConfig[_customHandle].data(); +} + } diff --git a/src/mirall/mirallconfigfile.h b/src/mirall/mirallconfigfile.h index e2707fd3d..fe24d9ca0 100644 --- a/src/mirall/mirallconfigfile.h +++ b/src/mirall/mirallconfigfile.h @@ -15,6 +15,7 @@ #ifndef MIRALLCONFIGFILE_H #define MIRALLCONFIGFILE_H +#include <QSharedPointer> #include <QString> #include <QVariant> @@ -22,12 +23,10 @@ class QWidget; namespace Mirall { +class AbstractCredentials; + class MirallConfigFile { - /* let only CredentialStore read the password from the file. All other classes - * should work with CredentialStore to get the credentials. */ - friend class CredentialStore; - friend class ConnectionValidator; public: MirallConfigFile( const QString& appendix = QString() ); @@ -44,12 +43,12 @@ public: void writeOwncloudConfig( const QString& connection, const QString& url, - const QString& user, - const QString& passwd ); + AbstractCredentials* credentials); + + AbstractCredentials* getCredentials() const; void removeConnection( const QString& connection = QString() ); - QString ownCloudUser( const QString& connection = QString() ) const; QString ownCloudUrl( const QString& connection = QString() ) const; // the certs do not depend on a connection. @@ -117,11 +116,10 @@ public: void restoreGeometry(QWidget *w); protected: - // these classes can only be access from CredentialStore as a friend class. - bool ownCloudPasswordExists( const QString& connection = QString() ) const; - QString ownCloudPasswd( const QString& connection = QString() ) const; - void clearPasswordFromConfig( const QString& connect = QString() ); - bool writePassword( const QString& passwd, const QString& connection = QString() ); + 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, @@ -129,9 +127,12 @@ private: void setValue(const QString& key, const QVariant &value); private: + typedef QSharedPointer< AbstractCredentials > SharedCreds; + static bool _askedUser; static QString _oCVersion; static QString _confDir; + static QMap< QString, SharedCreds > credentialsPerConfig; QString _customHandle; }; diff --git a/src/mirall/owncloudinfo.cpp b/src/mirall/owncloudinfo.cpp index e31a7d609..296598e83 100644 --- a/src/mirall/owncloudinfo.cpp +++ b/src/mirall/owncloudinfo.cpp @@ -15,8 +15,8 @@ #include "mirall/owncloudinfo.h" #include "mirall/mirallconfigfile.h" #include "mirall/theme.h" -#include "mirall/utility.h" #include "mirall/logger.h" +#include "creds/abstractcredentials.h" #include <QtCore> #include <QtGui> @@ -50,14 +50,14 @@ ownCloudInfo::ownCloudInfo() : QObject(0), _manager(0), _authAttempts(0), - _lastQuotaTotalBytes(0), - _lastQuotaUsedBytes(0) + _lastQuotaUsedBytes(0), + _lastQuotaTotalBytes(0) { _connection = Theme::instance()->appName(); connect(this, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(guiLog(QString,QString))); - setNetworkAccessManager( new QNetworkAccessManager( this ) ); - + // this will set credentials specific qnam + setCustomConfigHandle(QString()); } void ownCloudInfo::setNetworkAccessManager( QNetworkAccessManager* qnam ) @@ -72,13 +72,7 @@ void ownCloudInfo::setNetworkAccessManager( QNetworkAccessManager* qnam ) connect( _manager, SIGNAL( sslErrors(QNetworkReply*, QList<QSslError>)), this, SIGNAL(sslFailed(QNetworkReply*, QList<QSslError>)) ); - // The authenticationRequired signal is not handled because the creds are set - // in the request header. - connect( _manager, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), - this, SLOT(slotAuthentication(QNetworkReply*,QAuthenticator*))); - _certsUntrusted = false; - } ownCloudInfo::~ownCloudInfo() @@ -90,6 +84,8 @@ void ownCloudInfo::setCustomConfigHandle( const QString& handle ) _configHandle = handle; _authAttempts = 0; // allow a couple of tries again. resetSSLUntrust(); + MirallConfigFile cfg(_configHandle); + setNetworkAccessManager (cfg.getCredentials()->getQNAM()); } bool ownCloudInfo::isConfigured() @@ -311,42 +307,6 @@ void ownCloudInfo::slotGetDirectoryListingFinished() reply->deleteLater(); } -// FIXME: remove this later, once the new connection dialog has settled. -void ownCloudInfo::slotAuthentication( QNetworkReply *reply, QAuthenticator *auth ) -{ - if( !(auth && reply) ) return; - QString configHandle; - - // an empty config handle is ok for the default config. - if( _configHandleMap.contains(reply) ) { - configHandle = _configHandleMap[reply]; - qDebug() << "Auth: Have a custom config handle: " << configHandle; - } - - qDebug() << "Auth request to me and I am " << this; - _authAttempts++; - qDebug() << "Authenticating request for " << reply->url(); - if( reply->url().toString().startsWith( webdavUrl( _connection ) ) ) { - QString con = configHandle; - if( con.isEmpty() ) con = DEFAULT_CONNECTION; - if( _credentials.contains(con)) { - oCICredentials creds = _credentials.value(con); - - auth->setUser( creds.user ); - auth->setPassword( creds.passwd ); - } else { - qDebug() << "Unable to get Credentials, not set!"; - reply->close(); - } - } else { - qDebug() << "WRN: attempt to authenticate to different url - attempt " <<_authAttempts; - } - if( _authAttempts > 1) { - qDebug() << "Too many attempts to authenticate. Stop request."; - reply->close(); - } -} - QList<QNetworkCookie> ownCloudInfo::getLastAuthCookies() { QUrl url = QUrl( webdavUrl(_connection)); @@ -483,8 +443,8 @@ void ownCloudInfo::slotReplyFinished() // get version out edition = val; } else if(key == QLatin1String("installed")) { - // Silently ignoring "installed = true" information - } else { + // Silently ignoring "installed = true" information + } else { qDebug() << "Unknown info from ownCloud status.php: "<< key << "=" << val; } } @@ -560,30 +520,11 @@ void ownCloudInfo::slotError( QNetworkReply::NetworkError err) } } -void ownCloudInfo::setCredentials( const QString& user, const QString& passwd, - const QString& configHandle ) -{ - QString con( configHandle ); - if( configHandle.isEmpty() ) - con = DEFAULT_CONNECTION; - - if( _credentials.contains(con) ) { - qDebug() << "Overwriting credentials for connection " << con; - } - - oCICredentials creds; - creds.user = user; - creds.passwd = passwd; - creds.connection = con; - _credentials[con] = creds; -} - // ============================================================================ void ownCloudInfo::setupHeaders( QNetworkRequest & req, quint64 size ) { QUrl url( req.url() ); qDebug() << "Setting up host header: " << url.host(); - req.setRawHeader( QByteArray("User-Agent"), Utility::userAgentString()); if (size) { req.setHeader( QNetworkRequest::ContentLengthHeader, size); @@ -612,4 +553,4 @@ QString ownCloudInfo::webdavUrl(const QString &connection) return url; } -} +} // ns Mirall diff --git a/src/mirall/owncloudinfo.h b/src/mirall/owncloudinfo.h index 03b171e30..be11e7177 100644 --- a/src/mirall/owncloudinfo.h +++ b/src/mirall/owncloudinfo.h @@ -21,12 +21,6 @@ namespace Mirall { -typedef struct { - QString user; - QString passwd; - QString connection; -} oCICredentials; - class ownCloudInfo : public QObject { Q_OBJECT @@ -102,13 +96,6 @@ public: QList<QSslCertificate> certificateChain() const; /** - * Store credentials for a given connection. Empty connection parameter - * means "default connection". - */ - void setCredentials( const QString&, const QString&, - const QString& configHandle = QString::null ); - - /** * returns the owncloud webdav url. * It may be different from the one in the config if there was a HTTP redirection * The returned URL is guaranteed to end in a forward slash ('/') @@ -136,7 +123,6 @@ signals: protected slots: void slotReplyFinished( ); void slotError( QNetworkReply::NetworkError ); - void slotAuthentication( QNetworkReply*, QAuthenticator *); void slotMkdirFinished(); void slotGetQuotaFinished(); @@ -166,7 +152,6 @@ private: QList<QSslCertificate> _certificateChain; bool _certsUntrusted; int _authAttempts; - QMap<QString, oCICredentials> _credentials; QMutex _certChainMutex; int _redirectCount; qint64 _lastQuotaUsedBytes; @@ -174,6 +159,6 @@ private: QString _lastEtag; }; -}; +} // ns Mirall #endif // OWNCLOUDINFO_H diff --git a/src/mirall/owncloudsetupwizard.cpp b/src/mirall/owncloudsetupwizard.cpp index 506a16c29..a95dbfee0 100644 --- a/src/mirall/owncloudsetupwizard.cpp +++ b/src/mirall/owncloudsetupwizard.cpp @@ -1,5 +1,6 @@ /* - * Copyright (C) by Klaas Freitag <freitag@kde.org> + * 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 @@ -12,36 +13,44 @@ * 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/owncloudinfo.h" #include "mirall/folderman.h" -#include "mirall/credentialstore.h" #include "mirall/utility.h" +#include "mirall/mirallaccessmanager.h" +#include "creds/abstractcredentials.h" +#include "creds/dummycredentials.h" namespace Mirall { -OwncloudSetupWizard::OwncloudSetupWizard(QObject *parent ) : +OwncloudSetupWizard::OwncloudSetupWizard(QObject* parent) : QObject( parent ), - _mkdirRequestReply(0), - _checkInstallationRequest(0) + _ocWizard(new OwncloudWizard), + _mkdirRequestReply(), + _checkInstallationRequest(), + _checkRemoteFolderRequest(), + _configHandle(), + _remoteFolder() { - _ocWizard = new OwncloudWizard(); - + 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))); connect( _ocWizard, SIGNAL(finished(int)),this,SLOT(slotAssistantFinished(int))); connect( _ocWizard, SIGNAL(clearPendingRequests()), this, SLOT(slotClearPendingRequests())); - - _ocWizard->setWindowTitle( tr("%1 Connection Wizard").arg( Theme::instance()->appNameGUI() ) ); } OwncloudSetupWizard::~OwncloudSetupWizard() @@ -49,10 +58,6 @@ OwncloudSetupWizard::~OwncloudSetupWizard() _ocWizard->deleteLater(); } -OwncloudWizard *OwncloudSetupWizard::wizard() { - return _ocWizard; -} - void OwncloudSetupWizard::runWizard(QObject* obj, const char* amember, QWidget *parent) { OwncloudSetupWizard *wiz = new OwncloudSetupWizard(parent); @@ -67,14 +72,10 @@ void OwncloudSetupWizard::startWizard() MirallConfigFile cfgFile; // Fill the entry fields with existing values. QString url = cfgFile.ownCloudUrl(); - QString user = cfgFile.ownCloudUser(); - bool configExists = !( url.isEmpty() || user.isEmpty() ); + //QString user = cfgFile.ownCloudUser(); + bool configExists = !( url.isEmpty()/* || user.isEmpty()*/ ); _ocWizard->setConfigExists( configExists ); - if( !user.isEmpty() ) { - _ocWizard->setOCUser( user ); - } - if( !url.isEmpty() ) { _ocWizard->setOCUrl( url ); } @@ -85,13 +86,13 @@ void OwncloudSetupWizard::startWizard() QString localFolder = Theme::instance()->defaultClientFolder(); // if its a relative path, prepend with users home dir, otherwise use as absolute path - if( !localFolder.startsWith(QLatin1Char('/')) ) { - localFolder = QDir::homePath() + QDir::separator() + Theme::instance()->defaultClientFolder(); + if( !QDir(localFolder).isAbsolute() ) { + localFolder = QDir::homePath() + QDir::separator() + localFolder; } _ocWizard->setProperty("localFolder", localFolder); _ocWizard->setRemoteFolder(_remoteFolder); - _ocWizard->setStartId(OwncloudWizard::Page_oCSetup); + _ocWizard->setStartId(WizardCommon::Page_ServerSetup); _ocWizard->restart(); @@ -102,121 +103,13 @@ void OwncloudSetupWizard::startWizard() _ocWizard->raise(); } - -// Method executed when the user ends the wizard, either with 'accept' or 'reject'. -// accept the custom config to be the main one if Accepted. -void OwncloudSetupWizard::slotAssistantFinished( int result ) -{ - MirallConfigFile cfg( _configHandle ); - FolderMan *folderMan = FolderMan::instance(); - - if( result == QDialog::Rejected ) { - // the old config remains valid. Remove the temporary one. - cfg.cleanupCustomConfig(); - qDebug() << "Rejected the new config, use the old!"; - } else if( result == QDialog::Accepted ) { - qDebug() << "Config Changes were accepted!"; - - // go through all folders and remove the journals if the server changed. - MirallConfigFile prevCfg; - QUrl prevUrl( prevCfg.ownCloudUrl() ); - QUrl newUrl( cfg.ownCloudUrl() ); - - bool urlHasChanged = (prevUrl.host() != newUrl.host() || - prevUrl.port() != newUrl.port() || - prevUrl.path() != newUrl.path()); - - // if the user changed, its also a changed url. - if( prevCfg.ownCloudUser() != cfg.ownCloudUser() ) { - urlHasChanged = true; - qDebug() << "The User has changed, same as url change."; - } - - const QString localFolder = _ocWizard->localFolder(); - bool acceptCfg = true; - - if( urlHasChanged ) { - // first terminate sync jobs. - folderMan->terminateSyncProcess(); - - folderMan->unloadAllFolders(); - - bool startFromScratch = _ocWizard->field( "OCSyncFromScratch" ).toBool(); - if( startFromScratch ) { - // first try to rename (backup) the current local dir. - bool renameOk = false; - while( !renameOk ) { - renameOk = folderMan->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 ) { - renameOk = true; - acceptCfg = false; - } - } - } - } - } - // save the user credentials and afterwards clear the cred store. - if( acceptCfg ) { - cfg.acceptCustomConfig(); - } - - // Now write the resulting folder definition if folder names are set. - if( acceptCfg && urlHasChanged ) { - 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)); - } else { - // url is unchanged. Only the password was changed. - if( acceptCfg ) { - qDebug() << "Only password was changed, no changes to folder configuration."; - } else { - qDebug() << "User interrupted change of configuration."; - } - } - } - - // clear the custom config handle - _configHandle.clear(); - ownCloudInfo::instance()->setCustomConfigHandle( QString::null ); - - // notify others. - emit ownCloudWizardDone( result ); -} - -void OwncloudSetupWizard::slotConnectToOCUrl( const QString& url ) -{ - qDebug() << "Connect to url: " << url; - _ocWizard->setField(QLatin1String("OCUrl"), url ); - _ocWizard->appendToConfigurationLog(tr("Trying to connect to %1 at %2...") - .arg( Theme::instance()->appNameGUI() ).arg(url) ); - testOwnCloudConnect(); -} - -void OwncloudSetupWizard::slotClearPendingRequests() -{ - qDebug() << "Pending request: " << _mkdirRequestReply; - if( _mkdirRequestReply && _mkdirRequestReply->isRunning() ) { - qDebug() << "ABORTing pending mkdir request."; - _mkdirRequestReply->abort(); - } - if( _checkInstallationRequest && _checkInstallationRequest->isRunning() ) { - qDebug() << "ABORTing pending check installation request."; - _checkInstallationRequest->abort(); - } - if( _checkRemoteFolderRequest && _checkRemoteFolderRequest->isRunning() ) { - qDebug() << "ABORTing pending remote folder check request."; - _checkRemoteFolderRequest->abort(); - } -} - -void OwncloudSetupWizard::testOwnCloudConnect() +void OwncloudSetupWizard::slotDetermineAuthType(const QString& serverUrl) { + QString url(serverUrl); + qDebug() << "Connect to url: " << url; + _ocWizard->setField(QLatin1String("OCUrl"), url ); + _ocWizard->appendToConfigurationLog(tr("Trying to connect to %1 at %2 to determine authentication type...") + .arg( Theme::instance()->appNameGUI() ).arg(url) ); // write a temporary config. QDateTime now = QDateTime::currentDateTime(); @@ -230,7 +123,6 @@ void OwncloudSetupWizard::testOwnCloudConnect() _configHandle = now.toString(QLatin1String("MMddyyhhmmss")); MirallConfigFile cfgFile( _configHandle ); - QString url = _ocWizard->field(QLatin1String("OCUrl")).toString(); if( url.isEmpty() ) return; if( !( url.startsWith(QLatin1String("https://")) || url.startsWith(QLatin1String("http://"))) ) { qDebug() << "url does not start with a valid protocol, assuming https."; @@ -240,50 +132,94 @@ void OwncloudSetupWizard::testOwnCloudConnect() } cfgFile.writeOwncloudConfig( Theme::instance()->appName(), url, - _ocWizard->field(QLatin1String("OCUser")).toString(), - _ocWizard->field(QLatin1String("OCPasswd")).toString() ); + new DummyCredentials); + ownCloudInfo* info(ownCloudInfo::instance()); // If there is already a config, take its proxy config. - if( ownCloudInfo::instance()->isConfigured() ) { + if( info->isConfigured() ) { MirallConfigFile prevCfg; cfgFile.setProxyType( prevCfg.proxyType(), prevCfg.proxyHostName(), prevCfg.proxyPort(), prevCfg.proxyNeedsAuth(), prevCfg.proxyUser(), prevCfg.proxyPassword() ); } - // now start ownCloudInfo to check the connection. - ownCloudInfo* info = ownCloudInfo::instance(); info->setCustomConfigHandle( _configHandle ); if( info->isConfigured() ) { // reset the SSL Untrust flag to let the SSL dialog appear again. info->resetSSLUntrust(); connect(info, SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)), - SLOT(slotOwnCloudFound(QString,QString,QString,QString))); + SLOT(slotOwnCloudFoundAuth(QString,QString,QString,QString))); connect(info, SIGNAL(noOwncloudFound(QNetworkReply*)), - SLOT(slotNoOwnCloudFound(QNetworkReply*))); + SLOT(slotNoOwnCloudFoundAuth(QNetworkReply*))); _checkInstallationRequest = info->checkInstallation(); } else { qDebug() << " ownCloud seems not to be configured, can not start test connect."; } } -void OwncloudSetupWizard::slotOwnCloudFound( const QString& url, const QString& infoString, const QString& version, const QString& ) +void OwncloudSetupWizard::slotOwnCloudFoundAuth( const QString& url, const QString& infoString, const QString& version, const QString& ) { disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)), - this, SLOT(slotOwnCloudFound(QString,QString,QString,QString))); + this, SLOT(slotOwnCloudFoundAuth(QString,QString,QString,QString))); disconnect(ownCloudInfo::instance(), SIGNAL(noOwncloudFound(QNetworkReply*)), - this, SLOT(slotNoOwnCloudFound(QNetworkReply*))); + this, SLOT(slotNoOwnCloudFoundAuth(QNetworkReply*))); _ocWizard->appendToConfigurationLog(tr("<font color=\"green\">Successfully connected to %1: %2 version %3 (%4)</font><br/><br/>") .arg( url ).arg(Theme::instance()->appNameGUI()).arg(infoString).arg(version)); - // enable the finish button. - _ocWizard->button( QWizard::FinishButton )->setEnabled( true ); + MirallAccessManager* nm = new MirallAccessManager(this); + // TODO: We should get this path from owncloud info. + QNetworkReply* reply = nm->get (QNetworkRequest (url + "/remote.php/webdav/")); - // start the local folder creation - setupLocalSyncFolder(); + connect (reply, SIGNAL(finished()), + this, SLOT(slotAuthCheckReplyFinished())); + + nm->setProperty ("mirallRedirs", QVariant (0)); } -void OwncloudSetupWizard::slotNoOwnCloudFound( QNetworkReply *err ) +void OwncloudSetupWizard::slotAuthCheckReplyFinished() +{ + QNetworkReply* reply = qobject_cast< QNetworkReply* > (sender ()); + QUrl redirection = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + QNetworkAccessManager* nm = reply->manager (); + const int redirCount = nm->property ("mirallRedirs").toInt(); + + if (redirCount > 10) { + redirection.clear (); + } + + disconnect (reply, SIGNAL(finished()), + this, SLOT(slotAuthCheckReplyFinished())); + if ((reply->error () == QNetworkReply::AuthenticationRequiredError) || redirection.isEmpty()) { + reply->deleteLater(); + nm->deleteLater(); + _ocWizard->setAuthType (WizardCommon::HttpCreds); + } else if (redirection.toString().endsWith ("/remote.php/webdav/")) { + QNetworkReply* newReply = nm->get (QNetworkRequest(redirection)); + + connect (newReply, SIGNAL(error(QNetworkReply::NetworkError)), + this, SLOT(slotAuthCheckReplyError(QNetworkReply::NetworkError))); + connect (newReply, SIGNAL(finished()), + this, SLOT(slotAuthCheckReplyFinished(QNetworkReply::NetworkError))); + reply->deleteLater(); + + nm->setProperty ("mirallRedirs", QVariant(redirCount + 1)); + } else { + QRegExp shibbolethyWords ("SAML|wayf"); + + shibbolethyWords.setCaseSensitivity (Qt::CaseInsensitive); + if (redirection.toString ().contains (shibbolethyWords)) { + _ocWizard->setAuthType(WizardCommon::Shibboleth); + } else { + // TODO: Send an error. + // eh? + _ocWizard->setAuthType (WizardCommon::HttpCreds); + } + reply->deleteLater(); + nm->deleteLater(); + } +} + +void OwncloudSetupWizard::slotNoOwnCloudFoundAuth( QNetworkReply *err ) { disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)), this, SLOT(slotOwnCloudFound(QString,QString,QString,QString))); @@ -296,17 +232,86 @@ void OwncloudSetupWizard::slotNoOwnCloudFound( QNetworkReply *err ) // remove the config file again MirallConfigFile cfgFile( _configHandle ); cfgFile.cleanupCustomConfig(); - finalizeSetup( false ); } -void OwncloudSetupWizard::setupLocalSyncFolder() +void OwncloudSetupWizard::slotConnectToOCUrl( const QString& url ) +{ + qDebug() << "Connect to url: " << url; + _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() +{ + // write a temporary config. + QDateTime now = QDateTime::currentDateTime(); + + // remove a possibly existing custom config. + if( ! _configHandle.isEmpty() ) { + // remove the old config file. + MirallConfigFile oldConfig( _configHandle ); + oldConfig.cleanupCustomConfig(); + } + + _configHandle = now.toString(QLatin1String("MMddyyhhmmss")); + + MirallConfigFile cfgFile( _configHandle ); + QString url = _ocWizard->field(QLatin1String("OCUrl")).toString(); + if( url.isEmpty() ) return; + if( !( url.startsWith(QLatin1String("https://")) || url.startsWith(QLatin1String("http://"))) ) { + qDebug() << "url does not start with a valid protocol, assuming https."; + url.prepend(QLatin1String("https://")); + // FIXME: give a hint about the auto completion + _ocWizard->setOCUrl(url); + } + cfgFile.writeOwncloudConfig( Theme::instance()->appName(), + url, + _ocWizard->getCredentials()); + + ownCloudInfo* info(ownCloudInfo::instance()); + info->setCustomConfigHandle( _configHandle ); + // If there is already a config, take its proxy config. + if( info->isConfigured() ) { + MirallConfigFile prevCfg; + cfgFile.setProxyType( prevCfg.proxyType(), prevCfg.proxyHostName(), prevCfg.proxyPort(), + prevCfg.proxyNeedsAuth(), prevCfg.proxyUser(), prevCfg.proxyPassword() ); + } + + connect( info,SIGNAL(ownCloudDirExists(QString,QNetworkReply*)), + this,SLOT(slotConnectionCheck(QString,QNetworkReply*))); + + qDebug() << "# checking for authentication settings."; + _checkRemoteFolderRequest = info->getWebDAVPath(_remoteFolder ); // this call needs to be authenticated. + // continue in slotConnectionCheck +} + +void OwncloudSetupWizard::slotConnectionCheck(const QString&, QNetworkReply* reply) +{ + // disconnect from ownCloud Info signals + disconnect(ownCloudInfo::instance(), SIGNAL(ownCloudDirExists(QString,QNetworkReply*)), + this, SLOT(slotConnectionCheck(QString,QNetworkReply*))); + + 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) { - const QString localFolder = _ocWizard->property("localFolder").toString(); qDebug() << "Setup local sync folder for new oC connection " << localFolder; - QDir fi( localFolder ); + const QDir fi( localFolder ); // FIXME: Show problems with local folder properly. - bool localFolderOk = 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. @@ -327,18 +332,19 @@ void OwncloudSetupWizard::setupLocalSyncFolder() } if( localFolderOk ) { - checkRemoteFolder(); + checkRemoteFolder(remoteFolder); } } -void OwncloudSetupWizard::checkRemoteFolder() +void OwncloudSetupWizard::checkRemoteFolder(const QString& remoteFolder) { - connect( ownCloudInfo::instance(),SIGNAL(ownCloudDirExists(QString,QNetworkReply*)), + ownCloudInfo* info(ownCloudInfo::instance()); + connect( info,SIGNAL(ownCloudDirExists(QString,QNetworkReply*)), this,SLOT(slotAuthCheckReply(QString,QNetworkReply*))); - qDebug() << "# checking for authentication settings."; - ownCloudInfo::instance()->setCustomConfigHandle(_configHandle); - _checkRemoteFolderRequest = ownCloudInfo::instance()->getWebDAVPath(_remoteFolder ); // this call needs to be authenticated. + qDebug() << "# checking for existence of remote folder."; + info->setCustomConfigHandle(_configHandle); + _checkRemoteFolderRequest = info->getWebDAVPath(remoteFolder); // this call needs to be authenticated. // continue in slotAuthCheckReply } @@ -354,22 +360,12 @@ void OwncloudSetupWizard::slotAuthCheckReply( const QString&, QNetworkReply *rep if( errId == QNetworkReply::NoError ) { qDebug() << "******** Remote folder found, all cool!"; - } else if( errId == QNetworkReply::AuthenticationRequiredError ) { // returned if the user is wrong. - qDebug() << "******** Password is wrong!"; - error = tr("The given credentials do not authenticate."); - ok = false; - } else if( errId == QNetworkReply::OperationCanceledError ) { - // the username was wrong and ownCloudInfo was closing the request after a couple of auth tries. - qDebug() << "******** Username or password is wrong!"; - error = tr("Username or password is wrong!"); - ok = false; } else if( errId == QNetworkReply::ContentNotFoundError ) { - // FIXME try to create the remote folder! - if( !createRemoteFolder() ) { + if( createRemoteFolder() ) { + return; // Finish here, the mkdir request will go on. + } else { error = tr("The remote folder could not be accessed!"); ok = false; - } else { - return; // Finish here, the mkdir request will go on. } } else { error = tr("Error: %1").arg(reply->errorString()); @@ -378,8 +374,6 @@ void OwncloudSetupWizard::slotAuthCheckReply( const QString&, QNetworkReply *rep if( !ok ) { _ocWizard->displayError(error); - } else { - _ocWizard->setRemoteFolder( _remoteFolder ); } finalizeSetup( ok ); @@ -390,10 +384,11 @@ bool OwncloudSetupWizard::createRemoteFolder() if( _remoteFolder.isEmpty() ) return false; _ocWizard->appendToConfigurationLog( tr("creating folder on ownCloud: %1" ).arg( _remoteFolder )); - connect(ownCloudInfo::instance(), SIGNAL(webdavColCreated(QNetworkReply::NetworkError)), + ownCloudInfo* info(ownCloudInfo::instance()); + connect(info, SIGNAL(webdavColCreated(QNetworkReply::NetworkError)), this, SLOT(slotCreateRemoteFolderFinished(QNetworkReply::NetworkError))); - _mkdirRequestReply = ownCloudInfo::instance()->mkdirRequest( _remoteFolder ); + _mkdirRequestReply = info->mkdirRequest( _remoteFolder ); return (_mkdirRequestReply != NULL); } @@ -448,13 +443,119 @@ void OwncloudSetupWizard::finalizeSetup( bool success ) + tr("Successfully connected to %1!") .arg(Theme::instance()->appNameGUI()) + QLatin1String("</b></font></p>")); + _ocWizard->successfulStep(); } else { _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>")); } - _ocWizard->successfullyConnected(success); } +// Method executed when the user ends the wizard, either with 'accept' or 'reject'. +// accept the custom config to be the main one if Accepted. +void OwncloudSetupWizard::slotAssistantFinished( int result ) +{ + MirallConfigFile cfg( _configHandle ); + FolderMan *folderMan = FolderMan::instance(); + + if( result == QDialog::Rejected ) { + // the old config remains valid. Remove the temporary one. + cfg.cleanupCustomConfig(); + qDebug() << "Rejected the new config, use the old!"; + } else if( result == QDialog::Accepted ) { + AbstractCredentials* credentials(_ocWizard->getCredentials()); + + qDebug() << "Config Changes were accepted!"; + + // go through all folders and remove the journals if the server changed. + MirallConfigFile prevCfg; + QUrl prevUrl( prevCfg.ownCloudUrl() ); + QUrl newUrl( cfg.ownCloudUrl() ); + AbstractCredentials* oldCredentials(prevCfg.getCredentials()); + + bool urlHasChanged = (prevUrl.host() != newUrl.host() || + prevUrl.port() != newUrl.port() || + prevUrl.path() != newUrl.path()); + + // if the user changed, its also a changed url. + if(credentials->changed(oldCredentials)) { + urlHasChanged = true; + qDebug() << "The User has changed, same as url change."; + } + + const QString localFolder = _ocWizard->localFolder(); + bool acceptCfg = true; + + if( urlHasChanged ) { + // first terminate sync jobs. + folderMan->terminateSyncProcess(); + + folderMan->unloadAllFolders(); + + bool startFromScratch = _ocWizard->field( "OCSyncFromScratch" ).toBool(); + if( startFromScratch ) { + // first try to rename (backup) the current local dir. + bool renameOk = false; + while( !renameOk ) { + renameOk = folderMan->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 ) { + renameOk = true; + acceptCfg = false; + } + } + } + } + } + // save the user credentials and afterwards clear the cred store. + if( acceptCfg ) { + cfg.acceptCustomConfig(); + } + + // Now write the resulting folder definition if folder names are set. + if( acceptCfg && urlHasChanged ) { + 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)); + } else { + // url is unchanged. Only the password was changed. + if( acceptCfg ) { + qDebug() << "Only password was changed, no changes to folder configuration."; + } else { + qDebug() << "User interrupted change of configuration."; + } + } + } + + // clear the custom config handle + _configHandle.clear(); + ownCloudInfo::instance()->setCustomConfigHandle( QString::null ); + + // notify others. + emit ownCloudWizardDone( result ); } + +void OwncloudSetupWizard::slotClearPendingRequests() +{ + qDebug() << "Pending request: " << _mkdirRequestReply; + if( _mkdirRequestReply && _mkdirRequestReply->isRunning() ) { + qDebug() << "ABORTing pending mkdir request."; + _mkdirRequestReply->abort(); + } + if( _checkInstallationRequest && _checkInstallationRequest->isRunning() ) { + qDebug() << "ABORTing pending check installation request."; + _checkInstallationRequest->abort(); + } + if( _checkRemoteFolderRequest && _checkRemoteFolderRequest->isRunning() ) { + qDebug() << "ABORTing pending remote folder check request."; + _checkRemoteFolderRequest->abort(); + } +} + +} // ns Mirall diff --git a/src/mirall/owncloudsetupwizard.h b/src/mirall/owncloudsetupwizard.h index 3fd70766e..2fe1acf4b 100644 --- a/src/mirall/owncloudsetupwizard.h +++ b/src/mirall/owncloudsetupwizard.h @@ -21,81 +21,54 @@ #include <QNetworkReply> #include <QPointer> -#include "mirall/owncloudwizard.h" #include "mirall/theme.h" namespace Mirall { -class SiteCopyFolder; -class SyncResult; -class ownCloudInfo; +class OwncloudWizard; class OwncloudSetupWizard : public QObject { Q_OBJECT public: - explicit OwncloudSetupWizard(QObject *parent = 0 ); - - ~OwncloudSetupWizard(); - - /** - * @intro wether or not to show the intro wizard page - */ - void startWizard(); - - void installServer(); - - bool isBusy(); - - void writeOwncloudConfig(); - - /** - * returns the configured owncloud url if its already configured, otherwise an empty - * string. - */ - - void setupLocalSyncFolder(); - - OwncloudWizard *wizard(); - /** Run the wizard */ static void runWizard(QObject *obj, const char* amember, QWidget *parent = 0 ); signals: - // issued if the oC Setup process (owncloud-admin) is finished. - void ownCloudSetupFinished( bool ); // overall dialog close signal. - void ownCloudWizardDone( int ); + void ownCloudWizardDone( int ); -public slots: +private slots: + void slotDetermineAuthType(const QString&); + void slotOwnCloudFoundAuth(const QString&, const QString&, const QString&, const QString&); + void slotAuthCheckReplyFinished(); + void slotNoOwnCloudFoundAuth(QNetworkReply*); -protected slots: - // wizard dialog signals - void slotConnectToOCUrl( const QString& ); + void slotConnectToOCUrl(const QString&); + void slotConnectionCheck(const QString&, QNetworkReply*); -private slots: - void slotOwnCloudFound( const QString&, const QString&, const QString&, const QString& ); - void slotNoOwnCloudFound( QNetworkReply* ); - void slotCreateRemoteFolderFinished( QNetworkReply::NetworkError ); + void slotCreateLocalAndRemoteFolders(const QString&, const QString&); + void slotAuthCheckReply(const QString&, QNetworkReply*); + void slotCreateRemoteFolderFinished(QNetworkReply::NetworkError); void slotAssistantFinished( int ); void slotClearPendingRequests(); - void slotAuthCheckReply( const QString&, QNetworkReply * ); -private: - bool createRemoteFolder(); - void checkRemoteFolder(); - void finalizeSetup( bool ); +private: + explicit OwncloudSetupWizard(QObject *parent = 0 ); + ~OwncloudSetupWizard(); - /* Start a request to the newly installed ownCloud to check the connection */ + void startWizard(); void testOwnCloudConnect(); + void checkRemoteFolder(const QString& remoteFolder); + bool createRemoteFolder(); + void finalizeSetup( bool ); - OwncloudWizard *_ocWizard; + OwncloudWizard* _ocWizard; QPointer<QNetworkReply> _mkdirRequestReply; QPointer<QNetworkReply> _checkInstallationRequest; QPointer<QNetworkReply> _checkRemoteFolderRequest; - - QString _configHandle; - QString _remoteFolder; + QString _configHandle; + QString _remoteFolder; }; } diff --git a/src/mirall/owncloudwizard.cpp b/src/mirall/owncloudwizard.cpp deleted file mode 100644 index 68fc05ba2..000000000 --- a/src/mirall/owncloudwizard.cpp +++ /dev/null @@ -1,627 +0,0 @@ -/* - * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> - * 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/owncloudwizard.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/theme.h" - -#include "QProgressIndicator.h" - -#include <QtCore> -#include <QtGui> - -#include <stdlib.h> - -namespace Mirall -{ - -void setupCustomMedia( QVariant variant, QLabel *label ) -{ - if( !label ) return; - - QPixmap pix = variant.value<QPixmap>(); - if( !pix.isNull() ) { - label->setPixmap(pix); - label->setAlignment( Qt::AlignTop | Qt::AlignRight ); - label->setVisible(true); - } else { - QString str = variant.toString(); - if( !str.isEmpty() ) { - label->setText( str ); - label->setTextFormat( Qt::RichText ); - label->setVisible(true); - label->setOpenExternalLinks(true); - } - } -} - -// ====================================================================== - -OwncloudSetupPage::OwncloudSetupPage() -{ - _ui.setupUi(this); - - Theme *theme = Theme::instance(); - setTitle( tr("<font color=\"%1\" size=\"5\">Connect to %2</font>") - .arg(theme->wizardHeaderTitleColor().name()).arg( theme->appNameGUI())); - setSubTitle( tr("<font color=\"%1\">Enter user credentials</font>") - .arg(theme->wizardHeaderTitleColor().name())); - - registerField( QLatin1String("OCUrl"), _ui.leUrl ); - registerField( QLatin1String("OCUser"), _ui.leUsername ); - registerField( QLatin1String("OCPasswd"), _ui.lePassword); - registerField( QLatin1String("OCSyncFromScratch"), _ui.cbSyncFromScratch); - - _ui.errorLabel->setVisible(true); - _ui.advancedBox->setVisible(false); - - _progressIndi = new QProgressIndicator; - _ui.resultLayout->addWidget( _progressIndi ); - _progressIndi->setVisible(false); - _ui.resultLayout->setEnabled(false); - - // Error label - QString style = QLatin1String("border: 1px solid #eed3d7; border-radius: 5px; padding: 3px;" - "background-color: #f2dede; color: #b94a48;"); - - - _ui.errorLabel->setStyleSheet( style ); - _ui.errorLabel->setWordWrap(true); - _ui.errorLabel->setVisible(false); - - _checking = false; - - setupCustomization(); - - connect(_ui.leUrl, SIGNAL(textChanged(QString)), SLOT(slotUrlChanged(QString))); - connect( _ui.leUsername, SIGNAL(textChanged(QString)), this, SLOT(slotUserChanged(QString))); - - connect( _ui.lePassword, SIGNAL(textChanged(QString)), this, SIGNAL(completeChanged())); - connect( _ui.leUsername, SIGNAL(textChanged(QString)), this, SIGNAL(completeChanged())); - connect( _ui.cbAdvanced, SIGNAL(stateChanged (int)), SLOT(slotToggleAdvanced(int))); - connect( _ui.pbSelectLocalFolder, SIGNAL(clicked()), SLOT(slotSelectFolder())); -} - -OwncloudSetupPage::~OwncloudSetupPage() -{ - delete _progressIndi; -} - -void OwncloudSetupPage::slotToggleAdvanced(int state) -{ - _ui.advancedBox->setVisible( state == Qt::Checked ); - slotHandleUserInput(); - QSize size = wizard()->sizeHint(); - // need to substract header for some reason - size -= QSize(0, 63); - - wizard()->setMinimumSize(size); - wizard()->resize(size); -} - -void OwncloudSetupPage::setOCUser( const QString & user ) -{ - _ocUser = user; - _ui.leUsername->setText(user); -} - -void OwncloudSetupPage::setServerUrl( const QString& newUrl ) -{ - _oCUrl = newUrl; - if( _oCUrl.isEmpty() ) { - _ui.leUrl->clear(); - return; - } - - _ui.leUrl->setText( _oCUrl ); -} - -void OwncloudSetupPage::setupCustomization() -{ - // set defaults for the customize labels. - _ui.topLabel->hide(); - _ui.bottomLabel->hide(); - - Theme *theme = Theme::instance(); - QVariant variant = theme->customMedia( Theme::oCSetupTop ); - if( !variant.isNull() ) { - setupCustomMedia( variant, _ui.topLabel ); - } - - variant = theme->customMedia( Theme::oCSetupBottom ); - setupCustomMedia( variant, _ui.bottomLabel ); - - QString fixUrl = theme->overrideServerUrl(); - if( !fixUrl.isEmpty() ) { - _ui.label_2->hide(); - setServerUrl( fixUrl ); - _ui.leUrl->setEnabled( false ); - _ui.leUrl->hide(); - } -} - -void OwncloudSetupPage::slotUserChanged(const QString& user ) -{ - slotHandleUserInput(); -} - -// slot hit from textChanged of the url entry field. -void OwncloudSetupPage::slotUrlChanged(const QString& ocUrl) -{ - slotHandleUserInput(); - -#if 0 - QString url = ocUrl; - bool visible = false; - - if (url.startsWith(QLatin1String("https://"))) { - _ui.urlLabel->setPixmap( QPixmap(":/mirall/resources/security-high.png")); - _ui.urlLabel->setToolTip(tr("This url is secure. You can use it.")); - visible = true; - } - if (url.startsWith(QLatin1String("http://"))) { - _ui.urlLabel->setPixmap( QPixmap(":/mirall/resources/security-low.png")); - _ui.urlLabel->setToolTip(tr("This url is NOT secure. You should not use it.")); - visible = true; - } -#endif -} - -bool OwncloudSetupPage::isComplete() const -{ - if( _ui.leUrl->text().isEmpty() ) return false; - if( _checking ) return false; - - return !( _ui.lePassword->text().isEmpty() || _ui.leUsername->text().isEmpty() ); -} - -void OwncloudSetupPage::initializePage() -{ - _connected = false; - _checking = false; - _multipleFoldersExist = false; - - // call to init label - slotHandleUserInput(); - - if( _configExists ) { - _ui.lePassword->setFocus(); - } else { - _ui.leUrl->setFocus(); - } -} - -bool OwncloudSetupPage::urlHasChanged() -{ - bool change = false; - const QChar slash('/'); - - QUrl currentUrl( url() ); - QUrl initialUrl( _oCUrl ); - - QString currentPath = currentUrl.path(); - QString initialPath = initialUrl.path(); - - // add a trailing slash. - if( ! currentPath.endsWith( slash )) currentPath += slash; - if( ! initialPath.endsWith( slash )) initialPath += slash; - - if( currentUrl.host() != initialUrl.host() || - currentUrl.port() != initialUrl.port() || - currentPath != initialPath ) { - change = true; - } - - if( !change) { // no change yet, check the user. - QString user = _ui.leUsername->text().simplified(); - if( user != _ocUser ) change = true; - } - - return change; -} - -// Called if the user changes the user- or url field. Adjust the texts and -// evtl. warnings on the dialog. -void OwncloudSetupPage::slotHandleUserInput() -{ - // if the url has not changed, return. - if( ! urlHasChanged() ) { - // disable the advanced button as nothing has changed. - _ui.cbAdvanced->setEnabled(false); - _ui.advancedBox->setEnabled(false); - } else { - // Enable advanced stuff for new connection configuration. - _ui.cbAdvanced->setEnabled(true); - _ui.advancedBox->setEnabled(true); - } - - const QString locFolder = localFolder(); - - // check if the local folder exists. If so, and if its not empty, show a warning. - QDir dir( locFolder ); - QStringList entries = dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot); - - QString t; - - if( !urlHasChanged() && _configExists ) { - // This is the password change mode: No change to the url and a config - // to an ownCloud exists. - t = tr("Change the Password for your configured account."); - } else { - // Complete new setup. - _ui.pbSelectLocalFolder->setText(QDir::toNativeSeparators(locFolder)); - - if( _remoteFolder.isEmpty() || _remoteFolder == QLatin1String("/") ) { - t = tr("Your entire account will be synced to the local folder '%1'.") - .arg(QDir::toNativeSeparators(locFolder)); - } else { - t = tr("%1 folder '%2' is synced to local folder '%3'") - .arg(Theme::instance()->appName()).arg(_remoteFolder) - .arg(QDir::toNativeSeparators(locFolder)); - } - - if ( _multipleFoldersExist ) { - t += tr("<p><small><strong>Warning:</strong> You currently have multiple folders " - "configured. If you continue with the current settings, the folder configurations " - "will be discarded and a single root folder sync will be created!</small></p>"); - } - - if( entries.count() > 0) { - // the directory is not empty - if (!_ui.cbAdvanced->isChecked()) { - t += tr("<p><small><strong>Warning:</strong> The local directory is not empty. " - "Pick a resolution in the advanced settings!</small></p>"); - } - _ui.resolutionWidget->setVisible(true); - } else { - // the dir is empty, which means that there is no problem. - _ui.resolutionWidget->setVisible(false); - } - } - - _ui.syncModeLabel->setText(t); - _ui.syncModeLabel->setFixedHeight(_ui.syncModeLabel->sizeHint().height()); -} - -int OwncloudSetupPage::nextId() const -{ - return OwncloudWizard::Page_Result; -} - -QString OwncloudSetupPage::url() const -{ - QString url = _ui.leUrl->text().simplified(); - return url; -} - -QString OwncloudSetupPage::localFolder() const -{ - QString folder = wizard()->property("localFolder").toString(); - return folder; -} - -void OwncloudSetupPage::setConnected( bool comp ) -{ - _connected = comp; - _ui.resultLayout->setEnabled(true); - _progressIndi->setVisible(false); - _progressIndi->stopAnimation(); -} - -bool OwncloudSetupPage::validatePage() -{ - bool re = false; - - if( ! _connected) { - setErrorString(QString::null); - _checking = true; - _ui.resultLayout->setEnabled(true); - _progressIndi->setVisible(true); - _progressIndi->startAnimation(); - emit completeChanged(); - - emit connectToOCUrl( url() ); - return false; - } else { - // connecting is running - stopSpinner(); - _checking = false; - emit completeChanged(); - return true; - } -} - -void OwncloudSetupPage::setErrorString( const QString& err ) -{ - if( err.isEmpty()) { - _ui.errorLabel->setVisible(false); - } else { - _ui.errorLabel->setVisible(true); - _ui.errorLabel->setText(err); - } - _checking = false; - emit completeChanged(); - stopSpinner(); -} - -void OwncloudSetupPage::stopSpinner() -{ - _ui.resultLayout->setEnabled(false); - _progressIndi->setVisible(false); - _progressIndi->stopAnimation(); -} - -OwncloudSetupPage::SyncMode OwncloudSetupPage::syncMode() -{ - return BoxMode; -} - -void OwncloudSetupPage::setRemoteFolder( const QString& remoteFolder ) -{ - if( !remoteFolder.isEmpty() ) { - _remoteFolder = remoteFolder; - } -} - -void OwncloudSetupPage::setMultipleFoldersExist(bool exist) -{ - _multipleFoldersExist = exist; -} - -void OwncloudSetupPage::slotSelectFolder() -{ - - QString dir = QFileDialog::getExistingDirectory(0, tr("Local Sync Folder"), QDir::homePath()); - if( !dir.isEmpty() ) { - _ui.pbSelectLocalFolder->setText(dir); - wizard()->setProperty("localFolder", dir); - slotHandleUserInput(); - } -} - -OwncloudSetupPage::SyncMode OwncloudWizard::syncMode() -{ - return _setupPage->syncMode(); - return OwncloudSetupPage::BoxMode; -} - -void OwncloudWizard::setMultipleFoldersExist(bool exist) -{ - _setupPage->setMultipleFoldersExist(exist); -} - -void OwncloudSetupPage::setConfigExists( bool config ) -{ - _configExists = config; - - if (config == true) { - setSubTitle( tr("<font color=\"%1\">Change your user credentials</font>") - .arg(Theme::instance()->wizardHeaderTitleColor().name())); - } -} - -// ====================================================================== - -OwncloudWizardResultPage::OwncloudWizardResultPage() -{ - _ui.setupUi(this); - // no fields to register. - - Theme *theme = Theme::instance(); - setTitle( tr("<font color=\"%1\" size=\"5\">Everything set up!</font>") - .arg(theme->wizardHeaderTitleColor().name())); - // required to show header in QWizard's modern style - setSubTitle( QLatin1String(" ") ); - - _ui.pbOpenLocal->setText("Open local folder"); - _ui.pbOpenServer->setText(tr("Open %1").arg(Theme::instance()->appNameGUI())); - - _ui.pbOpenLocal->setIcon(QIcon(":/mirall/resources/folder-sync.png")); - _ui.pbOpenLocal->setText(tr("Open Local Folder")); - _ui.pbOpenLocal->setIconSize(QSize(48, 48)); - connect(_ui.pbOpenLocal, SIGNAL(clicked()), SLOT(slotOpenLocal())); - - _ui.pbOpenLocal->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - - QIcon appIcon = theme->applicationIcon(); - _ui.pbOpenServer->setIcon(appIcon.pixmap(48)); - _ui.pbOpenServer->setText(tr("Open %1").arg(theme->appNameGUI())); - _ui.pbOpenServer->setIconSize(QSize(48, 48)); - _ui.pbOpenServer->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - connect(_ui.pbOpenServer, SIGNAL(clicked()), SLOT(slotOpenServer())); - setupCustomization(); -} - -OwncloudWizardResultPage::~OwncloudWizardResultPage() -{ -} - -void OwncloudWizardResultPage::setComplete(bool complete) -{ - _complete = complete; - emit completeChanged(); -} - -bool OwncloudWizardResultPage::isComplete() const -{ - return _complete; -} - -void OwncloudWizardResultPage::initializePage() -{ - const QString localFolder = wizard()->property("localFolder").toString(); - QString text; - if( _remoteFolder == QLatin1String("/") || _remoteFolder.isEmpty() ) { - text = tr("Your entire account is synced to the local folder <i>%1</i>") - .arg(QDir::toNativeSeparators(localFolder)); - } else { - text = tr("ownCloud folder <i>%1</i> is synced to local folder <i>%2</i>") - .arg(_remoteFolder).arg(QDir::toNativeSeparators(localFolder)); - } - _ui.localFolderLabel->setText( text ); - -} - -void OwncloudWizardResultPage::setRemoteFolder(const QString &remoteFolder) -{ - _remoteFolder = remoteFolder; -} - -void OwncloudWizardResultPage::setupCustomization() -{ - // set defaults for the customize labels. - _ui.topLabel->setText( QString::null ); - _ui.topLabel->hide(); - - QVariant variant = Theme::instance()->customMedia( Theme::oCSetupResultTop ); - setupCustomMedia( variant, _ui.topLabel ); -} - -// ====================================================================== - -/** - * Folder wizard itself - */ - -OwncloudWizard::OwncloudWizard(QWidget *parent) - : QWizard(parent), - _configExists(false) -{ - _setupPage = new OwncloudSetupPage; - _resultPage = new OwncloudWizardResultPage; - setPage(Page_oCSetup, _setupPage ); - setPage(Page_Result, _resultPage ); - - // note: start Id is set by the calling class depending on if the - // welcome text is to be shown or not. - setWizardStyle( QWizard::ModernStyle ); - - connect( this, SIGNAL(currentIdChanged(int)), SLOT(slotCurrentPageChanged(int))); - - connect( _setupPage, SIGNAL(connectToOCUrl(QString)), SIGNAL(connectToOCUrl(QString))); - - - Theme *theme = Theme::instance(); - setWizardStyle(QWizard::ModernStyle); - setPixmap( QWizard::BannerPixmap, theme->wizardHeaderBanner() ); - setPixmap( QWizard::LogoPixmap, theme->wizardHeaderLogo() ); - setOption( QWizard::NoBackButtonOnStartPage ); - setOption( QWizard::NoBackButtonOnLastPage ); - setOption( QWizard::NoCancelButton ); - setTitleFormat(Qt::RichText); - setSubTitleFormat(Qt::RichText); -} - -QString OwncloudWizard::localFolder() const -{ - return(_setupPage->localFolder()); -} - -QString OwncloudWizard::ocUrl() const -{ - QString url = field("OCUrl").toString().simplified(); - return url; -} - -void OwncloudWizard::enableFinishOnResultWidget(bool enable) -{ - _resultPage->setComplete(enable); -} - -void OwncloudWizard::setRemoteFolder( const QString& remoteFolder ) -{ - _setupPage->setRemoteFolder( remoteFolder ); - _resultPage->setRemoteFolder( remoteFolder ); -} - -void OwncloudWizard::showConnectInfo( const QString& msg ) -{ - if( _setupPage ) { - _setupPage->setErrorString( msg ); - } -} - -void OwncloudWizard::successfullyConnected(bool enable) -{ - _setupPage->setConnected( enable ); - - if( enable ) { - next(); - } -} - -void OwncloudWizard::slotCurrentPageChanged( int id ) -{ - qDebug() << "Current Wizard page changed to " << id; - - if( id == Page_oCSetup ) { - setButtonText( QWizard::NextButton, tr("Connect...") ); - emit clearPendingRequests(); - _setupPage->initializePage(); - - } - - if( id == Page_Result ) { - appendToConfigurationLog( QString::null ); - } -} - -void OwncloudWizard::displayError( const QString& msg ) -{ - _setupPage->setErrorString( msg ); -} - -void OwncloudWizard::appendToConfigurationLog( const QString& msg, LogType type ) -{ - _setupLog << msg; - qDebug() << "Setup-Log: " << msg; -} - -void OwncloudWizard::setOCUrl( const QString& url ) -{ - _setupPage->setServerUrl( url ); -} - -void OwncloudWizard::setOCUser( const QString& user ) -{ - _oCUser = user; - _setupPage->setOCUser( user ); -} - -void OwncloudWizard::setConfigExists( bool config ) -{ - _configExists = config; - _setupPage->setConfigExists( config ); -} - -bool OwncloudWizard::configExists() -{ - return _configExists; -} - -void OwncloudWizardResultPage::slotOpenLocal() -{ - const QString localFolder = wizard()->property("localFolder").toString(); - QDesktopServices::openUrl(QUrl::fromLocalFile(localFolder)); -} - -void OwncloudWizardResultPage::slotOpenServer() -{ - QUrl url = field("OCUrl").toUrl(); - qDebug() << Q_FUNC_INFO << url; - QDesktopServices::openUrl(url); -} - - -} // end namespace diff --git a/src/mirall/owncloudwizard.h b/src/mirall/owncloudwizard.h deleted file mode 100644 index ceccf1209..000000000 --- a/src/mirall/owncloudwizard.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> - * 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 MIRALL_OWNCLOUDWIZARD_H -#define MIRALL_OWNCLOUDWIZARD_H - -#include <QWizard> - -#include "ui_owncloudsetuppage_ng.h" -#include "ui_owncloudwizardresultpage.h" - -class QLabel; -class QVariant; -class QProgressIndicator; - -namespace Mirall { - -class OwncloudSetupPage; -class OwncloudWizardResultPage; - -class OwncloudSetupPage: public QWizardPage -{ - Q_OBJECT -public: - OwncloudSetupPage(); - ~OwncloudSetupPage(); - - enum SyncMode { - SelectiveMode, - BoxMode - }; - - virtual bool isComplete() const; - virtual void initializePage(); - virtual int nextId() const; - void setServerUrl( const QString& ); - void setOCUser( const QString& ); - void setAllowPasswordStorage( bool ); - bool validatePage(); - QString url() const; - QString localFolder() const; - void setConnected(bool complete); - void setRemoteFolder( const QString& remoteFolder); - void setMultipleFoldersExist( bool exist ); - - SyncMode syncMode(); - -public slots: - void setErrorString( const QString& ); - void setConfigExists( bool ); - void stopSpinner(); - -protected slots: - void slotUrlChanged(const QString&); - void slotUserChanged(const QString&); - - void setupCustomization(); - void slotToggleAdvanced(int state); - void slotSelectFolder(); - -signals: - void connectToOCUrl( const QString& ); - -protected: - void updateFoldersInfo(); - -private slots: - void slotHandleUserInput(); - -private: - bool urlHasChanged(); - - Ui_OwncloudSetupPage _ui; - QString _oCUrl; - QString _ocUser; - bool _connected; - bool _checking; - bool _configExists; - bool _multipleFoldersExist; - - QProgressIndicator *_progressIndi; - QButtonGroup *_selectiveSyncButtons; - QString _remoteFolder; -}; - -class OwncloudWizard: public QWizard -{ - Q_OBJECT -public: - - enum { - Page_oCSetup, - Page_Result - }; - - enum LogType { - LogPlain, - LogParagraph - }; - - OwncloudWizard(QWidget *parent = 0); - - void setOCUrl( const QString& ); - void setOCUser( const QString& ); - - void setupCustomMedia( QVariant, QLabel* ); - QString ocUrl() const; - QString localFolder() const; - - void enableFinishOnResultWidget(bool enable); - - void displayError( const QString& ); - OwncloudSetupPage::SyncMode syncMode(); - void setMultipleFoldersExist( bool ); - void setConfigExists( bool ); - bool configExists(); - -public slots: - void setRemoteFolder( const QString& ); - void appendToConfigurationLog( const QString& msg, LogType type = LogParagraph ); - void slotCurrentPageChanged( int ); - - void showConnectInfo( const QString& ); - void successfullyConnected(bool); - -signals: - void clearPendingRequests(); - void connectToOCUrl( const QString& ); - -private: - OwncloudSetupPage *_setupPage; - OwncloudWizardResultPage *_resultPage; - - QString _configFile; - QString _oCUser; - QStringList _setupLog; - bool _configExists; -}; - - -/** - * page to ask for the type of Owncloud to connect to - */ - -/** - * page to display the install result - */ -class OwncloudWizardResultPage : public QWizardPage -{ - Q_OBJECT -public: - OwncloudWizardResultPage(); - ~OwncloudWizardResultPage(); - - bool isComplete() const; - void initializePage(); - void setRemoteFolder( const QString& remoteFolder); - -public slots: - void setComplete(bool complete); - -protected slots: - void slotOpenLocal(); - void slotOpenServer(); - -protected: - void setupCustomization(); - -private: - QString _localFolder; - QString _remoteFolder; - bool _complete; - - Ui_OwncloudWizardResultPage _ui; -}; - -} // ns Mirall - -#endif diff --git a/src/mirall/syncresult.cpp b/src/mirall/syncresult.cpp index 93e303069..6884e05c9 100644 --- a/src/mirall/syncresult.cpp +++ b/src/mirall/syncresult.cpp @@ -58,9 +58,9 @@ QString SyncResult::statusString() const case SetupError: re = QLatin1String("SetupError"); break; - case SyncPrepare: - re = QLatin1String("SyncPrepare"); - break; + case SyncPrepare: + re = QLatin1String("SyncPrepare"); + break; case Unavailable: re = QLatin1String("Not availabe"); break; diff --git a/src/mirall/systray.h b/src/mirall/systray.h index a3aaefa03..85e2a86cb 100644 --- a/src/mirall/systray.h +++ b/src/mirall/systray.h @@ -26,4 +26,4 @@ public: void showMessage(const QString & title, const QString & message, MessageIcon icon = Information, int millisecondsTimeoutHint = 10000); }; -#endif //SYSTRAY_H
\ No newline at end of file +#endif //SYSTRAY_H diff --git a/src/mirall/updatedetector.cpp b/src/mirall/updatedetector.cpp index 20bde3cdd..628463db3 100644 --- a/src/mirall/updatedetector.cpp +++ b/src/mirall/updatedetector.cpp @@ -18,6 +18,7 @@ #include "mirall/mirallconfigfile.h" #include "mirall/occinfo.h" #include "mirall/utility.h" +#include "mirall/mirallaccessmanager.h" #include <QtCore> #include <QtNetwork> @@ -28,7 +29,7 @@ namespace Mirall { UpdateDetector::UpdateDetector(QObject *parent) : QObject(parent) - , _accessManager( new QNetworkAccessManager(this)) + , _accessManager(new MirallAccessManager(this)) { } diff --git a/src/wizard/abstractcredswizardpage.h b/src/wizard/abstractcredswizardpage.h new file mode 100644 index 000000000..0579f0c05 --- /dev/null +++ b/src/wizard/abstractcredswizardpage.h @@ -0,0 +1,32 @@ +/* + * 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_WIZARD_ABSTRACT_CREDS_WIZARD_PAGE_H +#define MIRALL_WIZARD_ABSTRACT_CREDS_WIZARD_PAGE_H + +#include <QWizardPage> + +namespace Mirall +{ + +class AbstractCredentials; + +class AbstractCredentialsWizardPage : public QWizardPage +{ +public: + virtual AbstractCredentials* getCredentials() const = 0; +}; + +} // ns Mirall + +#endif diff --git a/src/wizard/owncloudadvancedsetuppage.cpp b/src/wizard/owncloudadvancedsetuppage.cpp new file mode 100644 index 000000000..36c025cb6 --- /dev/null +++ b/src/wizard/owncloudadvancedsetuppage.cpp @@ -0,0 +1,249 @@ +/* + * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> + * 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 <QDir> +#include <QFileDialog> +#include <QUrl> + +#include "QProgressIndicator.h" + +#include "wizard/owncloudwizard.h" +#include "wizard/owncloudwizardcommon.h" +#include "wizard/owncloudadvancedsetuppage.h" +#include "mirall/theme.h" +#include "mirall/mirallconfigfile.h" +#include "creds/abstractcredentials.h" + +namespace Mirall +{ + +OwncloudAdvancedSetupPage::OwncloudAdvancedSetupPage() + : QWizardPage(), + _ui(), + _checking(false), + _created(false), + _configExists(false), + _multipleFoldersExist(false), + _progressIndi(new QProgressIndicator (this)), + _oldLocalFolder(), + _remoteFolder() +{ + _ui.setupUi(this); + + Theme *theme = Theme::instance(); + setTitle(WizardCommon::titleTemplate().arg(tr("Connect to %1").arg(theme->appNameGUI()))); + setSubTitle(WizardCommon::subTitleTemplate().arg(tr("Setup local folder options"))); + + registerField( QLatin1String("OCSyncFromScratch"), _ui.cbSyncFromScratch); + + _ui.resultLayout->addWidget( _progressIndi ); + stopSpinner(); + setupCustomization(); + + connect( _ui.pbSelectLocalFolder, SIGNAL(clicked()), SLOT(slotSelectFolder())); +} + +void OwncloudAdvancedSetupPage::setupCustomization() +{ + // set defaults for the customize labels. + _ui.topLabel->hide(); + _ui.bottomLabel->hide(); + + Theme *theme = Theme::instance(); + QVariant variant = theme->customMedia( Theme::oCSetupTop ); + if( !variant.isNull() ) { + WizardCommon::setupCustomMedia( variant, _ui.topLabel ); + } + + variant = theme->customMedia( Theme::oCSetupBottom ); + WizardCommon::setupCustomMedia( variant, _ui.bottomLabel ); +} + +bool OwncloudAdvancedSetupPage::isComplete() const +{ + return !_checking; +} + +void OwncloudAdvancedSetupPage::initializePage() +{ + WizardCommon::initErrorLabel(_ui.errorLabel); + + _checking = false; + _multipleFoldersExist = false; + _oldLocalFolder = localFolder(); + + // call to init label + updateStatus(); + + // TODO: focus + _ui.pbSelectLocalFolder->setFocus(); +} + +// Called if the user changes the user- or url field. Adjust the texts and +// evtl. warnings on the dialog. +void OwncloudAdvancedSetupPage::updateStatus() +{ + const QString locFolder = localFolder(); + // check if the local folder exists. If so, and if its not empty, show a warning. + QString t; + + _ui.pbSelectLocalFolder->setText(QDir::toNativeSeparators(locFolder)); + if (dataChanged()) { + if( _remoteFolder.isEmpty() || _remoteFolder == QLatin1String("/") ) { + t = tr("Your entire account will be synced to the local folder '%1'.") + .arg(QDir::toNativeSeparators(locFolder)); + } else { + t = tr("%1 folder '%2' is synced to local folder '%3'") + .arg(Theme::instance()->appName()).arg(_remoteFolder) + .arg(QDir::toNativeSeparators(locFolder)); + } + + if ( _multipleFoldersExist ) { + t += tr("<p><small><strong>Warning:</strong> You currently have multiple folders " + "configured. If you continue with the current settings, the folder configurations " + "will be discarded and a single root folder sync will be created!</small></p>"); + } + + const bool dirNotEmpty(QDir(locFolder).entryList(QDir::AllEntries | QDir::NoDotAndDotDot).count() > 0); + if(dirNotEmpty) { + t += tr("<p><small><strong>Warning:</strong> The local directory is not empty. " + "Pick a resolution!</small></p>"); + } + _ui.resolutionWidget->setVisible(dirNotEmpty); + } else { + _ui.resolutionWidget->setVisible(false); + } + + _ui.syncModeLabel->setText(t); + _ui.syncModeLabel->setFixedHeight(_ui.syncModeLabel->sizeHint().height()); +} + +bool OwncloudAdvancedSetupPage::dataChanged() +{ + OwncloudWizard* ocWizard(dynamic_cast< OwncloudWizard* >(wizard())); + + if (!ocWizard) { + return false; + } + + MirallConfigFile cfgFile; + const QString url(field("OCUrl").toString()); + AbstractCredentials* newCredentials(ocWizard->getCredentials()); + AbstractCredentials* oldCredentials(cfgFile.getCredentials()); + 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)); +} + +void OwncloudAdvancedSetupPage::startSpinner() +{ + _ui.resultLayout->setEnabled(true); + _progressIndi->setVisible(true); + _progressIndi->startAnimation(); +} + +void OwncloudAdvancedSetupPage::stopSpinner() +{ + _ui.resultLayout->setEnabled(false); + _progressIndi->setVisible(false); + _progressIndi->stopAnimation(); +} + +int OwncloudAdvancedSetupPage::nextId() const +{ + return WizardCommon::Page_Result; +} + +QString OwncloudAdvancedSetupPage::localFolder() const +{ + QString folder = wizard()->property("localFolder").toString(); + return folder; +} + +bool OwncloudAdvancedSetupPage::validatePage() +{ + if(!_created) { + setErrorString(QString::null); + _checking = true; + startSpinner(); + emit completeChanged(); + + emit createLocalAndRemoteFolders(localFolder(), _remoteFolder); + return false; + } else { + // connecting is running + _checking = false; + emit completeChanged(); + stopSpinner(); + return true; + } +} + +void OwncloudAdvancedSetupPage::setErrorString( const QString& err ) +{ + if( err.isEmpty()) { + _ui.errorLabel->setVisible(false); + } else { + _ui.errorLabel->setVisible(true); + _ui.errorLabel->setText(err); + } + _checking = false; + emit completeChanged(); +} + +void OwncloudAdvancedSetupPage::directoriesCreated() +{ + _checking = false; + _created = true; + stopSpinner(); + emit completeChanged(); +} + +void OwncloudAdvancedSetupPage::setRemoteFolder( const QString& remoteFolder ) +{ + if( !remoteFolder.isEmpty() ) { + _remoteFolder = remoteFolder; + } +} + +void OwncloudAdvancedSetupPage::setMultipleFoldersExist(bool exist) +{ + _multipleFoldersExist = exist; +} + +void OwncloudAdvancedSetupPage::slotSelectFolder() +{ + QString dir = QFileDialog::getExistingDirectory(0, tr("Local Sync Folder"), QDir::homePath()); + if( !dir.isEmpty() ) { + _ui.pbSelectLocalFolder->setText(dir); + wizard()->setProperty("localFolder", dir); + updateStatus(); + } +} + +void OwncloudAdvancedSetupPage::setConfigExists(bool config) +{ + _configExists = config; + + if (config == true) { + setSubTitle(WizardCommon::subTitleTemplate().arg(tr("Update advanced setup"))); + } +} + +} // ns Mirall diff --git a/src/wizard/owncloudadvancedsetuppage.h b/src/wizard/owncloudadvancedsetuppage.h new file mode 100644 index 000000000..66b8de273 --- /dev/null +++ b/src/wizard/owncloudadvancedsetuppage.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> + * 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. + */ + +#ifndef MIRALL_OWNCLOUD_ADVANCED_SETUP_PAGE_H +#define MIRALL_OWNCLOUD_ADVANCED_SETUP_PAGE_H + +#include <QWizard> + +#include "wizard/owncloudwizardcommon.h" +#include "ui_owncloudadvancedsetuppage.h" + +class QProgressIndicator; + +namespace Mirall { + +class OwncloudAdvancedSetupPage: public QWizardPage +{ + Q_OBJECT +public: + OwncloudAdvancedSetupPage(); + + virtual bool isComplete() const; + virtual void initializePage(); + virtual int nextId() const; + bool validatePage(); + QString localFolder() const; + void setRemoteFolder( const QString& remoteFolder); + void setMultipleFoldersExist( bool exist ); + void directoriesCreated(); + void setConfigExists(bool config); + +signals: + void createLocalAndRemoteFolders(const QString&, const QString&); + +public slots: + void setErrorString( const QString& ); + +private slots: + void slotSelectFolder(); + +private: + void setupCustomization(); + void updateStatus(); + bool dataChanged(); + void startSpinner(); + void stopSpinner(); + + Ui_OwncloudAdvancedSetupPage _ui; + bool _checking; + bool _created; + bool _configExists; + bool _multipleFoldersExist; + QProgressIndicator* _progressIndi; + QString _oldLocalFolder; + QString _remoteFolder; +}; + +} // ns Mirall + +#endif diff --git a/src/wizard/owncloudadvancedsetuppage.ui b/src/wizard/owncloudadvancedsetuppage.ui new file mode 100644 index 000000000..9b8cd12cf --- /dev/null +++ b/src/wizard/owncloudadvancedsetuppage.ui @@ -0,0 +1,267 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>OwncloudAdvancedSetupPage</class> + <widget class="QWidget" name="OwncloudAdvancedSetupPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>821</width> + <height>647</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <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> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>13</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QFormLayout" name="advancedBox"> + <property name="sizeConstraint"> + <enum>QLayout::SetMinimumSize</enum> + </property> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Local Folder</string> + </property> + <property name="buddy"> + <cstring>pbSelectLocalFolder</cstring> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QPushButton" name="pbSelectLocalFolder"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>pbSelectLocalFolder</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QWidget" name="resolutionWidget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QFormLayout" name="formLayout_2"> + <property name="sizeConstraint"> + <enum>QLayout::SetMinimumSize</enum> + </property> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::ExpandingFieldsGrow</enum> + </property> + <item row="0" column="0" colspan="2"> + <widget class="QRadioButton" name="radioButton"> + <property name="text"> + <string>&Keep local data</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <spacer name="horizontalSpacer_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="label_6"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><small>Syncs your existing data to new location.</small></string> + </property> + <property name="scaledContents"> + <bool>false</bool> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="indent"> + <number>0</number> + </property> + </widget> + </item> + <item row="2" column="0" colspan="2"> + <widget class="QRadioButton" name="cbSyncFromScratch"> + <property name="toolTip"> + <string><html><head/><body><p>If this box is checked, existing content in the local directory will be erased to start a clean sync from the server.</p><p>Do not check this if the local content should be uploaded to the servers directory.</p></body></html></string> + </property> + <property name="text"> + <string>&Start a clean sync</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="3" column="0"> + <spacer name="horizontalSpacer_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="3" column="1"> + <widget class="QLabel" name="label_5"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string><small>Erases the contents of the local folder before syncing using the new settings.</small></string> + </property> + <property name="scaledContents"> + <bool>false</bool> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="indent"> + <number>0</number> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QLabel" name="errorLabel"> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="syncModeLabel"> + <property name="text"> + <string>Status message</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="resultLayout"/> + </item> + <item> + <widget class="QLabel" name="bottomLabel"> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/wizard/owncloudhttpcredspage.cpp b/src/wizard/owncloudhttpcredspage.cpp new file mode 100644 index 000000000..fc832bc37 --- /dev/null +++ b/src/wizard/owncloudhttpcredspage.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> + * 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 "QProgressIndicator.h" + +#include "wizard/owncloudhttpcredspage.h" +#include "mirall/theme.h" +#include "wizard/owncloudwizardcommon.h" +#include "creds/httpcredentials.h" +#include "mirall/mirallconfigfile.h" + +namespace Mirall +{ + +OwncloudHttpCredsPage::OwncloudHttpCredsPage() + : AbstractCredentialsWizardPage(), + _ui(), + _connected(false), + _checking(false), + _configExists(false), + _progressIndi(new QProgressIndicator (this)) +{ + _ui.setupUi(this); + + registerField( QLatin1String("OCUser*"), _ui.leUsername); + registerField( QLatin1String("OCPasswd*"), _ui.lePassword); + + setTitle(WizardCommon::titleTemplate().arg(tr("Connect to %1").arg(Theme::instance()->appNameGUI()))); + setSubTitle(WizardCommon::subTitleTemplate().arg(tr("Enter user credentials"))); + + _ui.resultLayout->addWidget( _progressIndi ); + stopSpinner(); + setupCustomization(); +} + +void OwncloudHttpCredsPage::setupCustomization() +{ + // set defaults for the customize labels. + _ui.topLabel->hide(); + _ui.bottomLabel->hide(); + + Theme *theme = Theme::instance(); + QVariant variant = theme->customMedia( Theme::oCSetupTop ); + if( !variant.isNull() ) { + WizardCommon::setupCustomMedia( variant, _ui.topLabel ); + } + + variant = theme->customMedia( Theme::oCSetupBottom ); + WizardCommon::setupCustomMedia( variant, _ui.bottomLabel ); +} + +void OwncloudHttpCredsPage::initializePage() +{ + WizardCommon::initErrorLabel(_ui.errorLabel); + MirallConfigFile cfgFile; + HttpCredentials* httpCreds(dynamic_cast< HttpCredentials* >(cfgFile.getCredentials())); + + if (httpCreds) { + const QString user = httpCreds->user(); + + if (!user.isEmpty()) { + _ui.leUsername->setText(user); + } + } + _ui.leUsername->setFocus(); +} + +void OwncloudHttpCredsPage::cleanupPage() +{ + _ui.leUsername->clear(); + _ui.lePassword->clear(); +} + +bool OwncloudHttpCredsPage::validatePage() +{ + if (_ui.leUsername->text().isEmpty() || _ui.lePassword->text().isEmpty()) { + return false; + } + + if (!_connected) { + _ui.errorLabel->setVisible(false); + _checking = true; + startSpinner(); + emit completeChanged(); + emit connectToOCUrl(field("OCUrl").toString().simplified()); + + return false; + } else { + _checking = false; + emit completeChanged(); + stopSpinner(); + return true; + } + return true; +} + +int OwncloudHttpCredsPage::nextId() const +{ + return WizardCommon::Page_AdvancedSetup; +} + +void OwncloudHttpCredsPage::setConnected( bool comp ) +{ + _connected = comp; + stopSpinner (); +} + +void OwncloudHttpCredsPage::startSpinner() +{ + _ui.resultLayout->setEnabled(true); + _progressIndi->setVisible(true); + _progressIndi->startAnimation(); +} + +void OwncloudHttpCredsPage::stopSpinner() +{ + _ui.resultLayout->setEnabled(false); + _progressIndi->setVisible(false); + _progressIndi->stopAnimation(); +} + +void OwncloudHttpCredsPage::setErrorString(const QString& err) +{ + if( err.isEmpty()) { + _ui.errorLabel->setVisible(false); + } else { + _ui.errorLabel->setVisible(true); + _ui.errorLabel->setText(err); + } + _checking = false; + emit completeChanged(); + stopSpinner(); +} + +AbstractCredentials* OwncloudHttpCredsPage::getCredentials() const +{ + return new HttpCredentials(_ui.leUsername->text(), _ui.lePassword->text()); +} + +void OwncloudHttpCredsPage::setConfigExists(bool config) +{ + _configExists = config; + + if (config == true) { + setSubTitle(WizardCommon::subTitleTemplate().arg(tr("Update user credentials"))); + } +} + +} // ns Mirall diff --git a/src/wizard/owncloudhttpcredspage.h b/src/wizard/owncloudhttpcredspage.h new file mode 100644 index 000000000..1e6a71098 --- /dev/null +++ b/src/wizard/owncloudhttpcredspage.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> + * 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. + */ + +#ifndef MIRALL_OWNCLOUD_HTTP_CREDS_PAGE_H +#define MIRALL_OWNCLOUD_HTTP_CREDS_PAGE_H + +#include "wizard/abstractcredswizardpage.h" + +#include "ui_owncloudhttpcredspage.h" + +class QProgressIndicator; + +namespace Mirall { + +class OwncloudHttpCredsPage : public AbstractCredentialsWizardPage +{ + Q_OBJECT +public: + OwncloudHttpCredsPage(); + + AbstractCredentials* getCredentials() const; + + void initializePage(); + void cleanupPage(); + bool validatePage(); + int nextId() const; + void setConnected(bool connected); + void setErrorString( const QString& err ); + void setConfigExists(bool config); + +Q_SIGNALS: + void connectToOCUrl(const QString&); + +private: + void startSpinner(); + void stopSpinner(); + void setupCustomization(); + + Ui_OwncloudHttpCredsPage _ui; + bool _connected; + bool _checking; + bool _configExists; + QProgressIndicator* _progressIndi; +}; + +} // ns Mirall + +#endif diff --git a/src/wizard/owncloudhttpcredspage.ui b/src/wizard/owncloudhttpcredspage.ui new file mode 100644 index 000000000..35f539a25 --- /dev/null +++ b/src/wizard/owncloudhttpcredspage.ui @@ -0,0 +1,130 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>OwncloudHttpCredsPage</class> + <widget class="QWidget" name="OwncloudHttpCredsPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>350</width> + <height>196</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="1" column="0"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>48</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1"> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>&Username</string> + </property> + <property name="buddy"> + <cstring>leUsername</cstring> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>&Password</string> + </property> + <property name="buddy"> + <cstring>lePassword</cstring> + </property> + </widget> + </item> + <item row="2" column="0" colspan="2"> + <widget class="QLabel" name="errorLabel"> + <property name="text"> + <string>Error Label</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="leUsername"/> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="lePassword"> + <property name="echoMode"> + <enum>QLineEdit::Password</enum> + </property> + </widget> + </item> + </layout> + </item> + <item row="2" column="1"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>68</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="2"> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>48</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="3" column="1"> + <layout class="QHBoxLayout" name="resultLayout"/> + </item> + <item row="0" column="0" colspan="3"> + <widget class="QLabel" name="topLabel"> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </item> + <item row="4" column="0" colspan="3"> + <widget class="QLabel" name="bottomLabel"> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </item> + </layout> + <zorder>horizontalSpacer</zorder> + <zorder>verticalSpacer</zorder> + <zorder>horizontalSpacer_2</zorder> + <zorder>horizontalLayoutWidget</zorder> + <zorder>topLabel</zorder> + <zorder>bottomLabel</zorder> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/wizard/owncloudsetupnocredspage.ui b/src/wizard/owncloudsetupnocredspage.ui new file mode 100644 index 000000000..76008d744 --- /dev/null +++ b/src/wizard/owncloudsetupnocredspage.ui @@ -0,0 +1,120 @@ +<?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>478</width> + <height>461</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <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> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Server &Address</string> + </property> + <property name="buddy"> + <cstring>leUrl</cstring> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="Utils::FancyLineEdit" name="leUrl"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Enter the url of the ownCloud you want to connect to (without http or https).</string> + </property> + <property name="placeholderText"> + <string>https://...</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QLabel" name="errorLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Error Label</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <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> + <layout class="QHBoxLayout" name="resultLayout"> + <property name="spacing"> + <number>0</number> + </property> + </layout> + </item> + <item> + <widget class="QLabel" name="bottomLabel"> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>Utils::FancyLineEdit</class> + <extends>QLineEdit</extends> + <header location="global">fancylineedit.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/src/wizard/owncloudsetuppage.cpp b/src/wizard/owncloudsetuppage.cpp new file mode 100644 index 000000000..3dea12f96 --- /dev/null +++ b/src/wizard/owncloudsetuppage.cpp @@ -0,0 +1,234 @@ +/* + * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> + * 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 <QDir> +#include <QFileDialog> +#include <QUrl> + +#include "QProgressIndicator.h" + +#include "wizard/owncloudwizardcommon.h" +#include "wizard/owncloudsetuppage.h" +#include "mirall/theme.h" + +namespace Mirall +{ + +OwncloudSetupPage::OwncloudSetupPage() + : QWizardPage(), + _ui(), + _oCUrl(), + _ocUser(), + _authTypeKnown(false), + _checking(false), + _authType(WizardCommon::HttpCreds), + _progressIndi(new QProgressIndicator (this)) +{ + _ui.setupUi(this); + + Theme *theme = Theme::instance(); + setTitle(WizardCommon::titleTemplate().arg(tr("Connect to %1").arg(theme->appNameGUI()))); + setSubTitle(WizardCommon::subTitleTemplate().arg(tr("Setup ownCloud server"))); + + registerField( QLatin1String("OCUrl*"), _ui.leUrl ); + + _ui.resultLayout->addWidget( _progressIndi ); + stopSpinner(); + + setupCustomization(); + + connect(_ui.leUrl, SIGNAL(textChanged(QString)), SLOT(slotUrlChanged(QString))); +} + +void OwncloudSetupPage::setServerUrl( const QString& newUrl ) +{ + _oCUrl = newUrl; + if( _oCUrl.isEmpty() ) { + _ui.leUrl->clear(); + return; + } + + _ui.leUrl->setText( _oCUrl ); +} + +void OwncloudSetupPage::setupCustomization() +{ + // set defaults for the customize labels. + _ui.topLabel->hide(); + _ui.bottomLabel->hide(); + + Theme *theme = Theme::instance(); + QVariant variant = theme->customMedia( Theme::oCSetupTop ); + if( !variant.isNull() ) { + WizardCommon::setupCustomMedia( variant, _ui.topLabel ); + } + + variant = theme->customMedia( Theme::oCSetupBottom ); + WizardCommon::setupCustomMedia( variant, _ui.bottomLabel ); + + QString fixUrl = theme->overrideServerUrl(); + if( !fixUrl.isEmpty() ) { + _ui.label_2->hide(); + setServerUrl( fixUrl ); + _ui.leUrl->setEnabled( false ); + _ui.leUrl->hide(); + } +} + +// slot hit from textChanged of the url entry field. +void OwncloudSetupPage::slotUrlChanged(const QString& /*ocUrl*/) +{ +#if 0 + QString url = ocUrl; + bool visible = false; + + if (url.startsWith(QLatin1String("https://"))) { + _ui.urlLabel->setPixmap( QPixmap(":/mirall/resources/security-high.png")); + _ui.urlLabel->setToolTip(tr("This url is secure. You can use it.")); + visible = true; + } + if (url.startsWith(QLatin1String("http://"))) { + _ui.urlLabel->setPixmap( QPixmap(":/mirall/resources/security-low.png")); + _ui.urlLabel->setToolTip(tr("This url is NOT secure. You should not use it.")); + visible = true; + } +#endif +} + +bool OwncloudSetupPage::isComplete() const +{ + return !_ui.leUrl->text().isEmpty() && !_checking; +} + +void OwncloudSetupPage::initializePage() +{ + WizardCommon::initErrorLabel(_ui.errorLabel); + + _authTypeKnown = false; + _checking = false; + + // URL entry is disabled when url is overriden by theme. In that + // case we just check the server type and switch to second page + // immediately. + if (_ui.leUrl->isEnabled()) { + _ui.leUrl->setFocus(); + } else { + validatePage(); + } +} + +bool OwncloudSetupPage::urlHasChanged() +{ + bool change = false; + const QChar slash('/'); + + QUrl currentUrl( url() ); + QUrl initialUrl( _oCUrl ); + + QString currentPath = currentUrl.path(); + QString initialPath = initialUrl.path(); + + // add a trailing slash. + if( ! currentPath.endsWith( slash )) currentPath += slash; + if( ! initialPath.endsWith( slash )) initialPath += slash; + + if( currentUrl.host() != initialUrl.host() || + currentUrl.port() != initialUrl.port() || + currentPath != initialPath ) { + change = true; + } + + return change; +} + +int OwncloudSetupPage::nextId() const +{ + if (_authType == WizardCommon::HttpCreds) { + return WizardCommon::Page_HttpCreds; + } else { + return WizardCommon::Page_ShibbolethCreds; + } +} + +QString OwncloudSetupPage::url() const +{ + QString url = _ui.leUrl->text().simplified(); + return url; +} + +bool OwncloudSetupPage::validatePage() +{ + if( ! _authTypeKnown) { + setErrorString(QString::null); + _checking = true; + startSpinner (); + emit completeChanged(); + + emit determineAuthType(url()); + return false; + } else { + // connecting is running + stopSpinner(); + _checking = false; + emit completeChanged(); + return true; + } +} + +void OwncloudSetupPage::setAuthType (WizardCommon::AuthType type) +{ + _authTypeKnown = true; + _authType = type; + stopSpinner(); +} + +void OwncloudSetupPage::setErrorString( const QString& err ) +{ + if( err.isEmpty()) { + _ui.errorLabel->setVisible(false); + } else { + _ui.errorLabel->setVisible(true); + _ui.errorLabel->setText(err); + } + _checking = false; + emit completeChanged(); + stopSpinner(); +} + +void OwncloudSetupPage::startSpinner() +{ + _ui.resultLayout->setEnabled(true); + _progressIndi->setVisible(true); + _progressIndi->startAnimation(); +} + +void OwncloudSetupPage::stopSpinner() +{ + _ui.resultLayout->setEnabled(false); + _progressIndi->setVisible(false); + _progressIndi->stopAnimation(); +} + +void OwncloudSetupPage::setConfigExists( bool config ) +{ + _configExists = config; + + if (config == true) { + setSubTitle(WizardCommon::subTitleTemplate().arg(tr("Update ownCloud server"))); + } +} + +} // ns Mirall diff --git a/src/wizard/owncloudsetuppage.h b/src/wizard/owncloudsetuppage.h new file mode 100644 index 000000000..8d343cd60 --- /dev/null +++ b/src/wizard/owncloudsetuppage.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> + * 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. + */ + +#ifndef MIRALL_OWNCLOUD_SETUP_PAGE_H +#define MIRALL_OWNCLOUD_SETUP_PAGE_H + +#include <QWizard> + +#include "wizard/owncloudwizardcommon.h" +#include "ui_owncloudsetupnocredspage.h" + +class QLabel; +class QVariant; +class QProgressIndicator; + +namespace Mirall { + +class OwncloudSetupPage: public QWizardPage +{ + Q_OBJECT +public: + OwncloudSetupPage(); + + virtual bool isComplete() const; + virtual void initializePage(); + virtual int nextId() const; + void setServerUrl( const QString& ); + void setAllowPasswordStorage( bool ); + bool validatePage(); + QString url() const; + QString localFolder() const; + void setRemoteFolder( const QString& remoteFolder); + void setMultipleFoldersExist( bool exist ); + void setAuthType(WizardCommon::AuthType type); + +public slots: + void setErrorString( const QString& ); + void setConfigExists( bool ); + void startSpinner(); + void stopSpinner(); + +protected slots: + void slotUrlChanged(const QString&); + + void setupCustomization(); + +signals: + void determineAuthType(const QString&); + +private: + bool urlHasChanged(); + + Ui_OwncloudSetupPage _ui; + QString _oCUrl; + QString _ocUser; + bool _authTypeKnown; + bool _checking; + bool _configExists; + bool _multipleFoldersExist; + WizardCommon::AuthType _authType; + + QProgressIndicator* _progressIndi; + QButtonGroup* _selectiveSyncButtons; + QString _remoteFolder; +}; + +} // ns Mirall + +#endif diff --git a/src/wizard/owncloudshibbolethcredspage.cpp b/src/wizard/owncloudshibbolethcredspage.cpp new file mode 100644 index 000000000..544eba996 --- /dev/null +++ b/src/wizard/owncloudshibbolethcredspage.cpp @@ -0,0 +1,164 @@ +/* + * 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 "wizard/owncloudshibbolethcredspage.h" +#include "mirall/theme.h" +#include "wizard/owncloudwizardcommon.h" +#include "creds/shibbolethcredentials.h" +#include "creds/shibboleth/shibbolethwebview.h" + +namespace Mirall +{ + +OwncloudShibbolethCredsPage::OwncloudShibbolethCredsPage() + : AbstractCredentialsWizardPage(), + _ui(), + _stage(INITIAL_STEP), + _browser(0), + _cookie() +{ + _ui.setupUi(this); + + setTitle(WizardCommon::titleTemplate().arg(tr("Connect to %1").arg(Theme::instance()->appNameGUI()))); + setSubTitle(WizardCommon::subTitleTemplate().arg(tr("Process through Shibboleth form"))); + + setupCustomization(); +} + +void OwncloudShibbolethCredsPage::setupCustomization() +{ + // set defaults for the customize labels. + _ui.topLabel->hide(); + _ui.bottomLabel->hide(); + + Theme *theme = Theme::instance(); + QVariant variant = theme->customMedia( Theme::oCSetupTop ); + if( !variant.isNull() ) { + WizardCommon::setupCustomMedia( variant, _ui.topLabel ); + } + + variant = theme->customMedia( Theme::oCSetupBottom ); + WizardCommon::setupCustomMedia( variant, _ui.bottomLabel ); +} + +bool OwncloudShibbolethCredsPage::isComplete() const +{ + return _stage == GOT_COOKIE; +} + +void OwncloudShibbolethCredsPage::initializePage() +{ + WizardCommon::initErrorLabel(_ui.errorLabel); + _browser = new ShibbolethWebView(QUrl(field("OCUrl").toString().simplified())); + + _browser->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + connect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie)), + this, SLOT(onShibbolethCookieReceived(QNetworkCookie))); + + //_ui.contentLayout->insertWidget(0, _browser); + _browser->show(); + _browser->setFocus(); + wizard()->hide(); + _ui.infoLabel->show(); + _ui.infoLabel->setText(tr("Please follow the steps on displayed page above")); + _stage = INITIAL_STEP; + _cookie = QNetworkCookie(); +} + +void OwncloudShibbolethCredsPage::disposeBrowser(bool later) +{ + if (_browser) { + _browser->hide(); + disconnect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie)), + this, SLOT(onShibbolethCookieReceived(QNetworkCookie))); + if (later) { + _browser->deleteLater(); + } else { + delete _browser; + } + _browser = 0; + } +} + +void OwncloudShibbolethCredsPage::cleanupPage() +{ + disposeBrowser(false); +} + +bool OwncloudShibbolethCredsPage::validatePage() +{ + switch (_stage) { + case INITIAL_STEP: + return false; + + case GOT_COOKIE: + _stage = CHECKING; + emit completeChanged(); + emit connectToOCUrl(field("OCUrl").toString().simplified()); + return false; + + case CHECKING: + return false; + + case CONNECTED: + return true; + } + + return false; +} + +int OwncloudShibbolethCredsPage::nextId() const +{ + return WizardCommon::Page_AdvancedSetup; +} + +void OwncloudShibbolethCredsPage::setConnected( bool comp ) +{ + if (comp) { + _stage = CONNECTED; + } else { + // sets stage to INITIAL + initializePage(); + } + emit completeChanged(); + wizard()->show(); +} + +void OwncloudShibbolethCredsPage::setErrorString(const QString& err) +{ + if( err.isEmpty()) { + _ui.errorLabel->setVisible(false); + } else { + initializePage(); + _ui.errorLabel->setVisible(true); + _ui.errorLabel->setText(err); + } + emit completeChanged(); +} + +AbstractCredentials* OwncloudShibbolethCredsPage::getCredentials() const +{ + return new ShibbolethCredentials(_cookie); +} + +void OwncloudShibbolethCredsPage::onShibbolethCookieReceived(const QNetworkCookie& cookie) +{ + disposeBrowser(true); + _stage = GOT_COOKIE; + _cookie = cookie; + _ui.infoLabel->setText("Please click \"Connect\" to check received Shibboleth session."); + emit completeChanged(); + validatePage(); +} + +} // ns Mirall diff --git a/src/wizard/owncloudshibbolethcredspage.h b/src/wizard/owncloudshibbolethcredspage.h new file mode 100644 index 000000000..d7d2bca79 --- /dev/null +++ b/src/wizard/owncloudshibbolethcredspage.h @@ -0,0 +1,68 @@ +/* + * 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_OWNCLOUD_SHIBBOLETH_CREDS_PAGE_H +#define MIRALL_OWNCLOUD_SHIBBOLETH_CREDS_PAGE_H + +#include <QNetworkCookie> + +#include "wizard/abstractcredswizardpage.h" + +#include "ui_owncloudshibbolethcredspage.h" + +namespace Mirall { + +class ShibbolethWebView; + +class OwncloudShibbolethCredsPage : public AbstractCredentialsWizardPage +{ + Q_OBJECT +public: + OwncloudShibbolethCredsPage(); + + AbstractCredentials* getCredentials() const; + + bool isComplete() const; + void initializePage(); + void cleanupPage(); + bool validatePage(); + int nextId() const; + void setConnected(bool connected); + void setErrorString(const QString& err); + +Q_SIGNALS: + void connectToOCUrl(const QString&); + +private Q_SLOTS: + void onShibbolethCookieReceived(const QNetworkCookie& cookie); + +private: + enum Stage { + INITIAL_STEP, + GOT_COOKIE, + CHECKING, + CONNECTED + }; + + void setupCustomization(); + void disposeBrowser(bool later); + + Ui_OwncloudShibbolethCredsPage _ui; + Stage _stage; + ShibbolethWebView* _browser; + QNetworkCookie _cookie; +}; + +} // ns Mirall + +#endif diff --git a/src/wizard/owncloudshibbolethcredspage.ui b/src/wizard/owncloudshibbolethcredspage.ui new file mode 100644 index 000000000..6c86c32b5 --- /dev/null +++ b/src/wizard/owncloudshibbolethcredspage.ui @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>OwncloudShibbolethCredsPage</class> + <widget class="QWidget" name="OwncloudShibbolethCredsPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>640</width> + <height>451</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="sizeConstraint"> + <enum>QLayout::SetMaximumSize</enum> + </property> + <item> + <widget class="QLabel" name="topLabel"> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <layout class="QVBoxLayout" name="contentLayout"> + <item> + <widget class="QLabel" name="errorLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Error Label</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="infoLabel"> + <property name="text"> + <string>info label</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>17</width> + <height>38</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="bottomLabel"> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/wizard/owncloudwizard.cpp b/src/wizard/owncloudwizard.cpp new file mode 100644 index 000000000..95f4223d5 --- /dev/null +++ b/src/wizard/owncloudwizard.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> + * 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 "wizard/owncloudwizard.h" +#include "mirall/mirallconfigfile.h" +#include "mirall/theme.h" +#include "wizard/owncloudsetuppage.h" +#include "wizard/owncloudhttpcredspage.h" +#include "wizard/owncloudshibbolethcredspage.h" +#include "wizard/owncloudadvancedsetuppage.h" +#include "wizard/owncloudwizardresultpage.h" + +#include "QProgressIndicator.h" + +#include <QtCore> +#include <QtGui> + +#include <stdlib.h> + +namespace Mirall +{ + +OwncloudWizard::OwncloudWizard(QWidget *parent) + : QWizard(parent), + _setupPage(new OwncloudSetupPage), + _httpCredsPage(new OwncloudHttpCredsPage), + _shibbolethCredsPage(new OwncloudShibbolethCredsPage), + _advancedSetupPage(new OwncloudAdvancedSetupPage), + _resultPage(new OwncloudWizardResultPage), + _credentialsPage(0), + _configFile(), + _oCUser(), + _setupLog(), + _configExists(false) +{ + setPage(WizardCommon::Page_ServerSetup, _setupPage ); + setPage(WizardCommon::Page_HttpCreds, _httpCredsPage); + setPage(WizardCommon::Page_ShibbolethCreds, _shibbolethCredsPage); + setPage(WizardCommon::Page_AdvancedSetup, _advancedSetupPage); + setPage(WizardCommon::Page_Result, _resultPage ); + + // note: start Id is set by the calling class depending on if the + // welcome text is to be shown or not. + setWizardStyle( QWizard::ModernStyle ); + + connect( this, SIGNAL(currentIdChanged(int)), SLOT(slotCurrentPageChanged(int))); + connect( _setupPage, SIGNAL(determineAuthType(QString)), SIGNAL(determineAuthType(QString))); + connect( _httpCredsPage, SIGNAL(connectToOCUrl(QString)), SIGNAL(connectToOCUrl(QString))); + connect( _shibbolethCredsPage, SIGNAL(connectToOCUrl(QString)), SIGNAL(connectToOCUrl(QString))); + connect( _advancedSetupPage, SIGNAL(createLocalAndRemoteFolders(QString, QString)), + SIGNAL(createLocalAndRemoteFolders(QString, QString))); + + Theme *theme = Theme::instance(); + setWindowTitle( tr("%1 Connection Wizard").arg(theme->appNameGUI())); + setWizardStyle(QWizard::ModernStyle); + setPixmap( QWizard::BannerPixmap, theme->wizardHeaderBanner() ); + setPixmap( QWizard::LogoPixmap, theme->wizardHeaderLogo() ); + setOption( QWizard::NoBackButtonOnStartPage ); + setOption( QWizard::NoBackButtonOnLastPage ); + setOption( QWizard::NoCancelButton ); + setTitleFormat(Qt::RichText); + setSubTitleFormat(Qt::RichText); +} + +void OwncloudWizard::setMultipleFoldersExist(bool exist) +{ + _advancedSetupPage->setMultipleFoldersExist(exist); +} + +QString OwncloudWizard::localFolder() const +{ + return(_advancedSetupPage->localFolder()); +} + +QString OwncloudWizard::ocUrl() const +{ + QString url = field("OCUrl").toString().simplified(); + return url; +} + +void OwncloudWizard::enableFinishOnResultWidget(bool enable) +{ + _resultPage->setComplete(enable); +} + +void OwncloudWizard::setRemoteFolder( const QString& remoteFolder ) +{ + _advancedSetupPage->setRemoteFolder( remoteFolder ); + _resultPage->setRemoteFolder( remoteFolder ); +} + +void OwncloudWizard::successfulStep() +{ + const int id(currentId()); + + switch (id) { + case WizardCommon::Page_HttpCreds: + _httpCredsPage->setConnected(true); + break; + + case WizardCommon::Page_ShibbolethCreds: + _shibbolethCredsPage->setConnected(true); + break; + + case WizardCommon::Page_AdvancedSetup: + _advancedSetupPage->directoriesCreated(); + break; + + case WizardCommon::Page_ServerSetup: + case WizardCommon::Page_Result: + qWarning("Should not happen at this stage."); + break; + } + + next(); +} + +void OwncloudWizard::setAuthType(WizardCommon::AuthType type) +{ + _setupPage->setAuthType(type); + if (type == WizardCommon::Shibboleth) { + _credentialsPage = _shibbolethCredsPage; + } else { + _credentialsPage = _httpCredsPage; + } + next(); +} + +// TODO: update this function +void OwncloudWizard::slotCurrentPageChanged( int id ) +{ + qDebug() << "Current Wizard page changed to " << id; + + if( id == WizardCommon::Page_ServerSetup ) { + setButtonText( QWizard::NextButton, tr("Connect...") ); + emit clearPendingRequests(); + _setupPage->initializePage(); + } + + if( id == WizardCommon::Page_Result ) { + appendToConfigurationLog( QString::null ); + } +} + +void OwncloudWizard::displayError( const QString& msg ) +{ + switch (currentId()) { + case WizardCommon::Page_ServerSetup: + _setupPage->setErrorString( msg ); + break; + + case WizardCommon::Page_HttpCreds: + _httpCredsPage->setErrorString(msg); + break; + + case WizardCommon::Page_ShibbolethCreds: + _shibbolethCredsPage->setErrorString(msg); + break; + + case WizardCommon::Page_AdvancedSetup: + _advancedSetupPage->setErrorString(msg); + break; + } +} + +void OwncloudWizard::appendToConfigurationLog( const QString& msg, LogType /*type*/ ) +{ + _setupLog << msg; + qDebug() << "Setup-Log: " << msg; +} + +void OwncloudWizard::setOCUrl( const QString& url ) +{ + _setupPage->setServerUrl( url ); +} + +void OwncloudWizard::setConfigExists( bool config ) +{ + _configExists = config; + _setupPage->setConfigExists( config ); + _httpCredsPage->setConfigExists(config); + _advancedSetupPage->setConfigExists(config); +} + +bool OwncloudWizard::configExists() +{ + return _configExists; +} + +AbstractCredentials* OwncloudWizard::getCredentials() const +{ + if (_credentialsPage) { + return _credentialsPage->getCredentials(); + } + + return 0; +} + + +} // end namespace diff --git a/src/wizard/owncloudwizard.h b/src/wizard/owncloudwizard.h new file mode 100644 index 000000000..cac61be9c --- /dev/null +++ b/src/wizard/owncloudwizard.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> + * 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. + */ + +#ifndef MIRALL_OWNCLOUD_WIZARD_H +#define MIRALL_OWNCLOUD_WIZARD_H + +#include <QWizard> + +#include "wizard/owncloudwizardcommon.h" + +namespace Mirall { + +class OwncloudSetupPage; +class OwncloudHttpCredsPage; +class OwncloudShibbolethCredsPage; +class OwncloudAdvancedSetupPage; +class OwncloudWizardResultPage; +class AbstractCredentials; +class AbstractCredentialsWizardPage; + +class OwncloudWizard: public QWizard +{ + Q_OBJECT +public: + + enum LogType { + LogPlain, + LogParagraph + }; + + OwncloudWizard(QWidget *parent = 0); + + void setOCUrl( const QString& ); + + void setupCustomMedia( QVariant, QLabel* ); + QString ocUrl() const; + QString localFolder() const; + + void enableFinishOnResultWidget(bool enable); + + void displayError( const QString& ); + void setMultipleFoldersExist( bool ); + void setConfigExists( bool ); + bool configExists(); + void successfulStep(); + void setAuthType(WizardCommon::AuthType type); + AbstractCredentials* getCredentials() const; + +public slots: + void setRemoteFolder( const QString& ); + void appendToConfigurationLog( const QString& msg, LogType type = LogParagraph ); + void slotCurrentPageChanged( int ); + +signals: + void clearPendingRequests(); + void determineAuthType(const QString&); + void connectToOCUrl( const QString& ); + void createLocalAndRemoteFolders(const QString&, const QString&); + +private: + OwncloudSetupPage* _setupPage; + OwncloudHttpCredsPage* _httpCredsPage; + OwncloudShibbolethCredsPage* _shibbolethCredsPage; + OwncloudAdvancedSetupPage* _advancedSetupPage; + OwncloudWizardResultPage* _resultPage; + AbstractCredentialsWizardPage* _credentialsPage; + + QString _configFile; + QString _oCUser; + QStringList _setupLog; + bool _configExists; +}; + +} // ns Mirall + +#endif diff --git a/src/wizard/owncloudwizardcommon.cpp b/src/wizard/owncloudwizardcommon.cpp new file mode 100644 index 000000000..dfe454411 --- /dev/null +++ b/src/wizard/owncloudwizardcommon.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> + * 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 <QLabel> +#include <QPixmap> +#include <QVariant> + +#include "wizard/owncloudwizardcommon.h" +#include "mirall/theme.h" + +namespace Mirall +{ + +namespace WizardCommon +{ + +void setupCustomMedia( const QVariant& variant, QLabel *label ) +{ + if( !label ) return; + + QPixmap pix = variant.value<QPixmap>(); + if( !pix.isNull() ) { + label->setPixmap(pix); + label->setAlignment( Qt::AlignTop | Qt::AlignRight ); + label->setVisible(true); + } else { + QString str = variant.toString(); + if( !str.isEmpty() ) { + label->setText( str ); + label->setTextFormat( Qt::RichText ); + label->setVisible(true); + label->setOpenExternalLinks(true); + } + } +} + +QString titleTemplate() +{ + return QString::fromLatin1("<font color=\"%1\" size=\"5\">").arg(Theme::instance()->wizardHeaderTitleColor().name()) + QString::fromLatin1("%1</font>"); +} + +QString subTitleTemplate() +{ + return QString::fromLatin1("<font color=\"%1\">").arg(Theme::instance()->wizardHeaderTitleColor().name()) + QString::fromLatin1("%1</font>"); +} + +void initErrorLabel(QLabel* errorLabel) +{ + QString style = QLatin1String("border: 1px solid #eed3d7; border-radius: 5px; padding: 3px;" + "background-color: #f2dede; color: #b94a48;"); + + errorLabel->setStyleSheet(style); + errorLabel->setWordWrap(true); + errorLabel->setVisible(false); +} + +} // ns WizardCommon + +} // ns Mirall diff --git a/src/wizard/owncloudwizardcommon.h b/src/wizard/owncloudwizardcommon.h new file mode 100644 index 000000000..83a548497 --- /dev/null +++ b/src/wizard/owncloudwizardcommon.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> + * 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. + */ + +#ifndef MIRALL_OWNCLOUD_WIZARD_COMMON_H +#define MIRALL_OWNCLOUD_WIZARD_COMMON_H + +class QVariant; +class QLabel; + +namespace Mirall +{ + +namespace WizardCommon +{ + +void setupCustomMedia( const QVariant& variant, QLabel *label ); +QString titleTemplate(); +QString subTitleTemplate(); +void initErrorLabel(QLabel* errorLabel); + +enum AuthType { + HttpCreds, + Shibboleth +}; + +enum SyncMode { + SelectiveMode, + BoxMode +}; + +enum Pages { + Page_ServerSetup, + Page_HttpCreds, + Page_ShibbolethCreds, + Page_AdvancedSetup, + Page_Result +}; + +} // ns WizardCommon + +} // ns Mirall + +#endif // MIRALL_OWNCLOUD_WIZARD_COMMON_H diff --git a/src/wizard/owncloudwizardresultpage.cpp b/src/wizard/owncloudwizardresultpage.cpp new file mode 100644 index 000000000..62f6faf62 --- /dev/null +++ b/src/wizard/owncloudwizardresultpage.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> + * 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 <QDebug> +#include <QDesktopServices> +#include <QDir> +#include <QUrl> + +#include "wizard/owncloudwizardresultpage.h" +#include "wizard/owncloudwizardcommon.h" +#include "mirall/theme.h" + +namespace Mirall +{ + +OwncloudWizardResultPage::OwncloudWizardResultPage() + : QWizardPage(), + _localFolder(), + _remoteFolder(), + _complete(false), + _ui() +{ + _ui.setupUi(this); + // no fields to register. + + setTitle(WizardCommon::subTitleTemplate().arg(tr("Everything set up!"))); + // required to show header in QWizard's modern style + setSubTitle( QLatin1String(" ") ); + + _ui.pbOpenLocal->setText(tr("Open Local Folder")); + _ui.pbOpenLocal->setIcon(QIcon(":/mirall/resources/folder-sync.png")); + _ui.pbOpenLocal->setIconSize(QSize(48, 48)); + _ui.pbOpenLocal->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + connect(_ui.pbOpenLocal, SIGNAL(clicked()), SLOT(slotOpenLocal())); + + Theme* theme = Theme::instance(); + QIcon appIcon = theme->applicationIcon(); + _ui.pbOpenServer->setText(tr("Open %1").arg(theme->appNameGUI())); + _ui.pbOpenServer->setIcon(appIcon.pixmap(48)); + _ui.pbOpenServer->setIconSize(QSize(48, 48)); + _ui.pbOpenServer->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + connect(_ui.pbOpenServer, SIGNAL(clicked()), SLOT(slotOpenServer())); + setupCustomization(); +} + +OwncloudWizardResultPage::~OwncloudWizardResultPage() +{} + +void OwncloudWizardResultPage::setComplete(bool complete) +{ + _complete = complete; + emit completeChanged(); +} + +bool OwncloudWizardResultPage::isComplete() const +{ + return _complete; +} + +void OwncloudWizardResultPage::initializePage() +{ + const QString localFolder = wizard()->property("localFolder").toString(); + QString text; + if( _remoteFolder == QLatin1String("/") || _remoteFolder.isEmpty() ) { + text = tr("Your entire account is synced to the local folder <i>%1</i>") + .arg(QDir::toNativeSeparators(localFolder)); + } else { + text = tr("ownCloud folder <i>%1</i> is synced to local folder <i>%2</i>") + .arg(_remoteFolder).arg(QDir::toNativeSeparators(localFolder)); + } + _ui.localFolderLabel->setText( text ); + +} + +void OwncloudWizardResultPage::setRemoteFolder(const QString &remoteFolder) +{ + _remoteFolder = remoteFolder; +} + +void OwncloudWizardResultPage::setupCustomization() +{ + // set defaults for the customize labels. + _ui.topLabel->setText( QString::null ); + _ui.topLabel->hide(); + + QVariant variant = Theme::instance()->customMedia( Theme::oCSetupResultTop ); + WizardCommon::setupCustomMedia( variant, _ui.topLabel ); +} + +void OwncloudWizardResultPage::slotOpenLocal() +{ + const QString localFolder = wizard()->property("localFolder").toString(); + QDesktopServices::openUrl(QUrl::fromLocalFile(localFolder)); +} + +void OwncloudWizardResultPage::slotOpenServer() +{ + QUrl url = field("OCUrl").toUrl(); + qDebug() << Q_FUNC_INFO << url; + QDesktopServices::openUrl(url); +} + +} // ns Mirall diff --git a/src/wizard/owncloudwizardresultpage.h b/src/wizard/owncloudwizardresultpage.h new file mode 100644 index 000000000..0ae7a6679 --- /dev/null +++ b/src/wizard/owncloudwizardresultpage.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org> + * 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. + */ + +#ifndef MIRALL_OWNCLOUD_WIZARD_RESULT_PAGE_H +#define MIRALL_OWNCLOUD_WIZARD_RESULT_PAGE_H + +#include <QWizardPage> + +#include "ui_owncloudwizardresultpage.h" + +namespace Mirall { + +class OwncloudWizardResultPage : public QWizardPage +{ + Q_OBJECT +public: + OwncloudWizardResultPage(); + ~OwncloudWizardResultPage(); + + bool isComplete() const; + void initializePage(); + void setRemoteFolder( const QString& remoteFolder); + +public slots: + void setComplete(bool complete); + +protected slots: + void slotOpenLocal(); + void slotOpenServer(); + +protected: + void setupCustomization(); + +private: + QString _localFolder; + QString _remoteFolder; + bool _complete; + + Ui_OwncloudWizardResultPage _ui; +}; + +} // ns Mirall + +#endif diff --git a/src/mirall/owncloudwizardresultpage.ui b/src/wizard/owncloudwizardresultpage.ui index 917900971..917900971 100644 --- a/src/mirall/owncloudwizardresultpage.ui +++ b/src/wizard/owncloudwizardresultpage.ui |