diff --git a/src/mirall/owncloudinfo.cpp b/src/mirall/owncloudinfo.cpp deleted file mode 100644 index fe498d5b2..000000000 --- a/src/mirall/owncloudinfo.cpp +++ /dev/null @@ -1,561 +0,0 @@ -/* - * Copyright (C) by Klaas Freitag - * - * 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/owncloudinfo.h" -#include "mirall/mirallconfigfile.h" -#include "mirall/theme.h" -#include "mirall/logger.h" -#include "creds/abstractcredentials.h" - -#include "json.h" - -#include -#include -#include - -#define DEFAULT_CONNECTION QLatin1String("default"); -static const char WEBDAV_PATH[] = "remote.php/webdav/"; - -namespace Mirall -{ - -ownCloudInfo *ownCloudInfo::_instance = 0; - -ownCloudInfo* ownCloudInfo::instance() -{ - static QMutex mutex; - if (!_instance) - { - mutex.lock(); - - if (!_instance) { - _instance = new ownCloudInfo; - } - mutex.unlock(); - } - - return _instance; -} - -ownCloudInfo::ownCloudInfo() : - QObject(0), - _manager(0), - _authAttempts(0), - _lastQuotaUsedBytes(0), - _lastQuotaTotalBytes(0) -{ - _connection = Theme::instance()->appName(); - connect(this, SIGNAL(guiLog(QString,QString)), - Logger::instance(), SIGNAL(guiLog(QString,QString))); - // this will set credentials specific qnam - setCustomConfigHandle(QString()); -} - -void ownCloudInfo::setNetworkAccessManager( QNetworkAccessManager* qnam ) -{ - delete _manager; - qnam->setParent( this ); - _manager = qnam; - - MirallConfigFile cfg( _configHandle ); - QSslSocket::addDefaultCaCertificates(QSslCertificate::fromData(cfg.caCerts())); - - connect( _manager, SIGNAL( sslErrors(QNetworkReply*, QList)), - this, SIGNAL(sslFailed(QNetworkReply*, QList)) ); - - _certsUntrusted = false; -} - -ownCloudInfo::~ownCloudInfo() -{ -} - -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() -{ - MirallConfigFile cfgFile( _configHandle ); - return cfgFile.connectionExists( _connection ); -} - -QNetworkReply *ownCloudInfo::checkInstallation() -{ - _redirectCount = 0; - MirallConfigFile cfgFile( _configHandle ); - QUrl url ( cfgFile.ownCloudUrl( _connection ) + QLatin1String("status.php") ); - /* No authentication required for this. */ - return getRequest(url); -} - -QNetworkReply* ownCloudInfo::getWebDAVPath( const QString& path ) -{ - _redirectCount = 0; - QUrl url ( webdavUrl( _connection ) + path ); - QNetworkReply *reply = getRequest(url); - _directories[reply] = path; - return reply; -} -QNetworkReply* ownCloudInfo::simpleGetRequest( const QUrl& url ) -{ - qDebug() << "Get Request to " << url; - - QNetworkRequest request; - request.setUrl( url ); - setupHeaders( request, 0 ); - - return _manager->get( request ); -} - -QNetworkReply* ownCloudInfo::getRequest( const QUrl& url ) -{ - - QNetworkReply *reply = simpleGetRequest(url); - - connect( reply, SIGNAL(finished()), SLOT(slotReplyFinished())); - - if( !_configHandle.isEmpty() ) { - qDebug() << "Setting config handle " << _configHandle; - _configHandleMap[reply] = _configHandle; - } - - connect( reply, SIGNAL( error(QNetworkReply::NetworkError )), - this, SLOT(slotError( QNetworkReply::NetworkError ))); - return reply; -} - -QNetworkReply* ownCloudInfo::mkdirRequest( const QString& dir ) -{ - qDebug() << "OCInfo Making dir " << dir; - _authAttempts = 0; - QNetworkRequest req; -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - QUrl url( webdavUrl(_connection) ); - // ensure #, ? and co are interpreted as part of the path and nothing else - url.setEncodedPath(url.encodedPath()+QUrl::toPercentEncoding(dir, "/")); -#else - QUrl url(webdavUrl(_connection)); - url.setPath(url.path(QUrl::FullyEncoded)+QUrl::toPercentEncoding(dir, "/")); -#endif - req.setUrl( url ); - QNetworkReply *reply = davRequest("MKCOL", req, 0); - - // remember the confighandle used for this request - if( ! _configHandle.isEmpty() ) - qDebug() << "Setting config handle " << _configHandle; - _configHandleMap[reply] = _configHandle; - - if( reply->error() != QNetworkReply::NoError ) { - qDebug() << "mkdir request network error: " << reply->errorString(); - } - - connect( reply, SIGNAL(finished()), SLOT(slotMkdirFinished()) ); - connect( reply, SIGNAL( error(QNetworkReply::NetworkError )), - this, SLOT(slotError(QNetworkReply::NetworkError ))); - return reply; -} - -QNetworkReply* ownCloudInfo::getQuotaRequest( const QString& dir ) -{ - QNetworkRequest req; - req.setUrl( QUrl( webdavUrl(_connection) + QUrl::toPercentEncoding(dir, "/") ) ); - req.setRawHeader("Depth", "0"); - QByteArray xml("\n" - "\n" - " \n" - " \n" - " \n" - " " - " \n" - "\n"); - QBuffer *buf = new QBuffer; - buf->setData(xml); - buf->open(QIODevice::ReadOnly); - QNetworkReply *reply = davRequest("PROPFIND", req, buf); - buf->setParent(reply); - - if( reply->error() != QNetworkReply::NoError ) { - qDebug() << "getting quota: request network error: " << reply->errorString(); - } - - connect( reply, SIGNAL( finished()), SLOT(slotGetQuotaFinished()) ); - connect( reply, SIGNAL( error(QNetworkReply::NetworkError)), - this, SLOT( slotError(QNetworkReply::NetworkError))); - return reply; -} -QNetworkReply* ownCloudInfo::getDirectoryListing( const QString& dir ) -{ - QNetworkRequest req; - QUrl url( webdavUrl(_connection) ); - // ensure #, ? and co are interpreted as part of the path and nothing else - url.setPath(url.path() + dir ); - req.setUrl( url ); - req.setRawHeader("Depth", "1"); - QByteArray xml("\n" - "\n" - " \n" - " \n" - " \n" - "\n"); - QBuffer *buf = new QBuffer; - buf->setData(xml); - buf->open(QIODevice::ReadOnly); - QNetworkReply *reply = davRequest("PROPFIND", req, buf); - buf->setParent(reply); - - if( reply->error() != QNetworkReply::NoError ) { - qDebug() << "getting quota: request network error: " << reply->errorString(); - } - - connect( reply, SIGNAL( finished()), SLOT(slotGetDirectoryListingFinished()) ); - connect( reply, SIGNAL( error(QNetworkReply::NetworkError)), - this, SLOT( slotError(QNetworkReply::NetworkError))); - return reply; -} - - -void ownCloudInfo::slotMkdirFinished() -{ - QNetworkReply *reply = qobject_cast(sender()); - - if( ! reply ) { - qDebug() << "ownCloudInfo: Reply empty!"; - return; - } - - emit webdavColCreated( reply->error() ); - qDebug() << "mkdir slot hit with status: " << reply->error(); - if( _configHandleMap.contains( reply ) ) { - _configHandleMap.remove( reply ); - } - - reply->deleteLater(); -} - -void ownCloudInfo::slotGetQuotaFinished() -{ - bool ok = false; - QNetworkReply *reply = qobject_cast(sender()); - int http_result_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - - if (http_result_code == 207) { - // Parse DAV response - QXmlStreamReader reader(reply); - reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:")); - - qint64 quotaUsedBytes = 0; - qint64 quotaAvailableBytes = 0; - QString etag; - - while (!reader.atEnd()) { - QXmlStreamReader::TokenType type = reader.readNext(); - if (type == QXmlStreamReader::StartElement && - reader.namespaceUri() == QLatin1String("DAV:")) { - QString name = reader.name().toString(); - if (name == QLatin1String("quota-used-bytes")) { - quotaUsedBytes = reader.readElementText().toLongLong(&ok); - if (!ok) quotaUsedBytes = 0; - } else if (name == QLatin1String("quota-available-bytes")) { - quotaAvailableBytes = reader.readElementText().toLongLong(&ok); - if (!ok) quotaAvailableBytes = 0; - } else if (name == QLatin1String("getetag")) { - etag = reader.readElementText(); - } - } - } - - qint64 total = quotaUsedBytes + quotaAvailableBytes; - - _lastQuotaTotalBytes = total; - _lastQuotaUsedBytes = quotaUsedBytes; - emit quotaUpdated(total, quotaUsedBytes); - _lastEtag = etag; - } else { - qDebug() << "Quota request *not* successful, http result code is " << http_result_code; - _lastQuotaTotalBytes = 0; - _lastQuotaUsedBytes = 0; - } - - reply->deleteLater(); -} - -void ownCloudInfo::slotGetDirectoryListingFinished() -{ - QNetworkReply *reply = qobject_cast(sender()); - - if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 207) { - // Parse DAV response - QXmlStreamReader reader(reply); - reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:")); - - QStringList folders; - QString currentItem; - - while (!reader.atEnd()) { - QXmlStreamReader::TokenType type = reader.readNext(); - if (type == QXmlStreamReader::StartElement && - reader.namespaceUri() == QLatin1String("DAV:")) { - QString name = reader.name().toString(); - if (name == QLatin1String("href")) { - currentItem = reader.readElementText(); - } else if (name == QLatin1String("collection") && - !currentItem.isEmpty()) { - folders.append(QUrl::fromEncoded(currentItem.toLatin1()).path()); - currentItem.clear(); - } - } - } - emit directoryListingUpdated(folders); - } - - reply->deleteLater(); -} - -QList ownCloudInfo::getLastAuthCookies() -{ - QUrl url = QUrl( webdavUrl(_connection)); - QList cookies = _manager->cookieJar()->cookiesForUrl(url); - return cookies; -} - -QString ownCloudInfo::configHandle(QNetworkReply *reply) -{ - QString configHandle; - if( _configHandleMap.contains(reply) ) { - configHandle = _configHandleMap[reply]; - } - return configHandle; -} - -QList ownCloudInfo::certificateChain() const -{ - QMutexLocker lock(const_cast(&_certChainMutex)); - return _certificateChain; -} - -// -// There have been problems with the finish-signal coming from the networkmanager. -// To avoid that, the reply-signals were connected and the data is taken from the -// sender() method. -// -void ownCloudInfo::slotReplyFinished() -{ - QNetworkReply *reply = qobject_cast(sender()); - QSslConfiguration sslConfig = reply->sslConfiguration(); - if (!sslConfig.isNull()) { - QMutexLocker lock(&_certChainMutex); - _certificateChain = sslConfig.peerCertificateChain(); - } - - if( ! reply ) { - qDebug() << "ownCloudInfo: Reply empty!"; - return; - } - - // Detect redirect url - QUrl possibleRedirUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); - /* We'll deduct if the redirection is valid in the redirectUrl function */ - - - if (!possibleRedirUrl.isEmpty() && _redirectCount++ > 10) { - // Are we in a redirect loop - qDebug() << "Redirect loop while redirecting to" << possibleRedirUrl; - possibleRedirUrl.clear(); - } - - if(!possibleRedirUrl.isEmpty()) { - QString configHandle; - - qDebug() << "Redirected to " << possibleRedirUrl; - - // We'll do another request to the redirection url. - // an empty config handle is ok for the default config. - if( _configHandleMap.contains(reply) ) { - configHandle = _configHandleMap[reply]; - qDebug() << "Redirect: Have a custom config handle: " << configHandle; - } - - QString path = _directories[reply]; - if (path.isEmpty()) { - path = QLatin1String("status.php"); - } else { - path.prepend( QLatin1String(WEBDAV_PATH) ); - } - qDebug() << "This path was redirected: " << path; - - QString newUrl = possibleRedirUrl.toString(); - if( !path.isEmpty() && newUrl.endsWith( path )) { - // cut off the trailing path - newUrl.chop( path.length() ); - _urlRedirectedTo = newUrl; - qDebug() << "Updated url to" << newUrl; - getRequest( possibleRedirUrl ); - } else { - qDebug() << "WRN: Path is not part of the redirect URL. NO redirect."; - } - reply->deleteLater(); - _directories.remove(reply); - _configHandleMap.remove(reply); - return; - } - - const QString url = reply->url().toString(); - QString plainUrl(url); - plainUrl.remove( QLatin1String("/status.php")); - - if( url.endsWith( QLatin1String("status.php")) ) { - // it was a call to status.php - if( reply->error() == QNetworkReply::NoError && reply->size() == 0 ) { - // This seems to be a bit strange behaviour of QNetworkAccessManager. - // It calls the finised slot multiple times but only the first read wins. - // That happend when the code connected the finished signal of the manager. - // It did not happen when the code connected to the reply finish signal. - qDebug() << "WRN: NetworkReply with not content but also no error! " << reply; - reply->deleteLater(); - return; - } - - bool success = false; - QVariantMap status = QtJson::parse(QString::fromUtf8(reply->readAll()), success).toMap(); - // empty or invalid response - if (!success || status.isEmpty()) { - qDebug() << "status.php from server is not valid JSON!"; - reply->deleteLater(); - } - - qDebug() << "status.php returns: " << status << " " << reply->error() << " Reply: " << reply; - if( status.contains("installed") - && status.contains("version") - && status.contains("versionstring") ) { - -// bool installed = status.value("installed").toBool(); - QString version = status.value("version").toString(); - QString versionStr = status.value("versionstring").toString(); - QString edition = status.value("edition").toString(); - - emit ownCloudInfoFound( plainUrl, versionStr, version, edition ); - } else { - qDebug() << "No proper answer on " << url; - - emit noOwncloudFound( reply ); - } - } else { - // it was a general GET request. - QString dir(QLatin1String("unknown")); - if( _directories.contains(reply) ) { - dir = _directories[reply]; - } - - emit ownCloudDirExists( dir, reply ); - } - reply->deleteLater(); - _directories.remove(reply); - _configHandleMap.remove(reply); -} - -void ownCloudInfo::resetSSLUntrust() -{ - _certsUntrusted = false; -} - -void ownCloudInfo::setCertsUntrusted(bool donttrust) -{ - _certsUntrusted = donttrust; -} - -bool ownCloudInfo::certsUntrusted() -{ - return _certsUntrusted; -} - -void ownCloudInfo::slotError( QNetworkReply::NetworkError err) -{ - QNetworkReply *reply = qobject_cast(sender()); - - qDebug() << "ownCloudInfo Network Error" - << err << ":" << reply->errorString(); - - switch (err) { - case QNetworkReply::ProxyConnectionRefusedError: - emit guiLog(tr("Proxy Refused Connection "), - tr("The configured proxy has refused the connection. " - "Please check the proxy settings.")); - break; - case QNetworkReply::ProxyConnectionClosedError: - emit guiLog(tr("Proxy Closed Connection"), - tr("The configured proxy has closed the connection. " - "Please check the proxy settings.")); - break; - case QNetworkReply::ProxyNotFoundError: - emit guiLog(tr("Proxy Not Found"), - tr("The configured proxy could not be found. " - "Please check the proxy settings.")); - break; - case QNetworkReply::ProxyAuthenticationRequiredError: - emit guiLog(tr("Proxy Authentication Error"), - tr("The configured proxy requires login but the proxy credentials " - "are invalid. Please check the proxy settings.")); - break; - case QNetworkReply::ProxyTimeoutError: - emit guiLog(tr("Proxy Connection Timed Out"), - tr("The connection to the configured proxy has timed out.")); - break; - default: - break; - } -} - -// ============================================================================ -void ownCloudInfo::setupHeaders( QNetworkRequest & req, quint64 size ) -{ - QUrl url( req.url() ); - qDebug() << "Setting up host header: " << url.host(); - - if (size) { - req.setHeader( QNetworkRequest::ContentLengthHeader, size); - req.setHeader( QNetworkRequest::ContentTypeHeader, QLatin1String("text/xml; charset=utf-8")); - } -} - -QNetworkReply* ownCloudInfo::davRequest(const QByteArray& reqVerb, QNetworkRequest& req, QIODevice *data) -{ - setupHeaders(req, quint64(data ? data->size() : 0)); - return _manager->sendCustomRequest(req, reqVerb, data ); -} - -QString ownCloudInfo::webdavUrl(const QString &connection) -{ - QString url; - - if (!_urlRedirectedTo.isEmpty()) { - url = _urlRedirectedTo.toString(); - } else { - MirallConfigFile cfgFile(_configHandle ); - url = cfgFile.ownCloudUrl( connection ); - } - url.append( QLatin1String( WEBDAV_PATH ) ); - if (!url.endsWith('/')) url.append('/'); - return url; -} - -/*************************************************************************************/ - - -} // ns Mirall diff --git a/src/mirall/owncloudinfo.h b/src/mirall/owncloudinfo.h deleted file mode 100644 index 46cfa489c..000000000 --- a/src/mirall/owncloudinfo.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) by Klaas Freitag - * - * 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 OWNCLOUDINFO_H -#define OWNCLOUDINFO_H - -#include -#include - -namespace Mirall -{ - -class ownCloudInfo : public QObject -{ - Q_OBJECT -public: - - static ownCloudInfo *instance(); - - bool isConfigured(); - - /** - * call status.php - */ - QNetworkReply* checkInstallation(); - - /** - * convenience: GET request to the WebDAV server. - */ - QNetworkReply* getWebDAVPath( const QString& ); - - /** - * There is a global flag here if the user once decided against trusting the - * SSL connection. This method resets it so that the ssl dialog is shown again. - */ - void resetSSLUntrust(); - - /** - * Set wether or not to trust errorneus SSL certificates - */ - void setCertsUntrusted(bool donttrust); - - /** - * Do we trust the certificate?. - */ - bool certsUntrusted(); - - /** - * Set a NetworkAccessManager to be used - * - * This method will take ownership of the NetworkAccessManager, so you can just - * set it initially and forget about its memory management. - */ - void setNetworkAccessManager( QNetworkAccessManager *qnam ); - - /** - * Create a collection via owncloud. Provide a relative path. - */ - QNetworkReply* mkdirRequest( const QString& ); - - /** - * Retrieve quota for a path. Provide a relative path. - */ - QNetworkReply* getQuotaRequest( const QString& ); - - /** - * provide collections in a directory via owncloud. Provide a relative path. - */ - QNetworkReply* getDirectoryListing( const QString& dir ); - - /** - * Use a custom ownCloud configuration file identified by handle - */ - void setCustomConfigHandle( const QString& ); - - /** - * Accessor to the config handle. - */ - QString configHandle(QNetworkReply *reply = 0); - - /** - * Certificate chain of the connection est. with ownCloud. - * Empty if the connection is HTTP-based - */ - QList certificateChain() const; - - /** - * 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 ('/') - */ - QString webdavUrl(const QString& connection = QString()); - - qint64 lastQuotaUsedBytes() const { return _lastQuotaUsedBytes; } - qint64 lastQuotaTotalBytes() const { return _lastQuotaTotalBytes; } - QString lastEtag() const { return _lastEtag; } - - QList getLastAuthCookies(); - -signals: - // result signal with url- and version string. - void ownCloudInfoFound( const QString&, const QString&, const QString&, const QString& ); - void noOwncloudFound( QNetworkReply* ); - void ownCloudDirExists( const QString&, QNetworkReply* ); - - void webdavColCreated( QNetworkReply::NetworkError ); - void sslFailed( QNetworkReply *reply, QList errors ); - void guiLog( const QString& title, const QString& content ); - void quotaUpdated( qint64 total, qint64 quotaUsedBytes ); - void directoryListingUpdated(const QStringList &directories); - -protected slots: - void slotReplyFinished( ); - void slotError( QNetworkReply::NetworkError ); - - void slotMkdirFinished(); - void slotGetQuotaFinished(); - void slotGetDirectoryListingFinished(); - -private: - explicit ownCloudInfo(); - - /** - * a general GET request to the ownCloud WebDAV. - */ - QNetworkReply* getRequest( const QUrl &url); - QNetworkReply* simpleGetRequest( const QUrl &url); - QNetworkReply* davRequest(const QByteArray&, QNetworkRequest&, QIODevice* ); - - ~ownCloudInfo(); - - void setupHeaders(QNetworkRequest &req, quint64 size ); - - static ownCloudInfo *_instance; - - QNetworkAccessManager *_manager; - QString _connection; - QString _configHandle; - QUrl _urlRedirectedTo; - QHash _directories; - QHash _configHandleMap; - QList _certificateChain; - bool _certsUntrusted; - int _authAttempts; - QMutex _certChainMutex; - int _redirectCount; - qint64 _lastQuotaUsedBytes; - qint64 _lastQuotaTotalBytes; - QString _lastEtag; - - friend class AbstractNetworkJob; -}; - - - -} // ns Mirall - -#endif // OWNCLOUDINFO_H