File indexing completed on 2024-05-05 16:58:23

0001 /*
0002  *  SPDX-FileCopyrightText: 2015 Martin Klapetek <mklapetek@kde.org>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "owncloudcontroller.h"
0008 
0009 #include <KIO/DavJob>
0010 #include <KIO/Job>
0011 #include <KLocalizedString>
0012 #include <kio/global.h>
0013 
0014 #include <QDebug>
0015 #include <QDomDocument>
0016 #include <QJsonDocument>
0017 #include <QJsonObject>
0018 #include <QString>
0019 
0020 #include "../cloudurls.h"
0021 
0022 OwncloudController::OwncloudController(QObject *parent)
0023     : QObject(parent)
0024     , m_errorMessage(QString())
0025     , m_isWorking(false)
0026 {
0027 }
0028 
0029 OwncloudController::~OwncloudController()
0030 {
0031 }
0032 
0033 void OwncloudController::checkServer(const QString &username, const QString &password, const QString &path)
0034 {
0035     m_errorMessage.clear();
0036     Q_EMIT errorMessageChanged();
0037 
0038     m_username = username;
0039     m_password = password;
0040 
0041     checkServer(createStatusUrl(path));
0042 }
0043 
0044 void OwncloudController::checkServer(const QUrl &url)
0045 {
0046     qDebug() << "Checking for ownCloud instance at" << url;
0047     setWorking(true);
0048     KIO::TransferJob *job = KIO::get(url, KIO::NoReload, KIO::HideProgressInfo);
0049     job->setUiDelegate(nullptr);
0050     connect(job, SIGNAL(data(KIO::Job *, QByteArray)), SLOT(dataReceived(KIO::Job *, QByteArray)));
0051     connect(job, SIGNAL(finished(KJob *)), this, SLOT(fileChecked(KJob *)));
0052 }
0053 
0054 void OwncloudController::figureOutServer(const QUrl &url)
0055 {
0056     if (/*url == QLatin1String("/") ||*/ url.isEmpty()) {
0057         serverCheckResult(false);
0058         return;
0059     }
0060 
0061     m_json.clear();
0062 
0063     qDebug() << "Received url to figure out:" << url;
0064     // This needs 2x up cause first it just removes the status.php
0065     // and only the second call actually moves up
0066     QUrl urlUp = KIO::upUrl(KIO::upUrl(url));
0067     urlUp.setPath(urlUp.path() + QLatin1Char('/') + QStringLiteral("status.php"));
0068 
0069     if (urlUp != url) {
0070         checkServer(urlUp.adjusted(QUrl::NormalizePathSegments));
0071     } else {
0072         serverCheckResult(false);
0073     }
0074 }
0075 
0076 void OwncloudController::dataReceived(KIO::Job *job, const QByteArray &data)
0077 {
0078     Q_UNUSED(job);
0079     m_json.append(data);
0080 }
0081 
0082 void OwncloudController::fileChecked(KJob *job)
0083 {
0084     KIO::TransferJob *kJob = qobject_cast<KIO::TransferJob *>(job);
0085     if (kJob->error()) {
0086         qDebug() << job->errorString();
0087         qDebug() << job->errorText();
0088         figureOutServer(kJob->url());
0089         return;
0090     }
0091 
0092     QJsonDocument parser = QJsonDocument::fromJson(m_json);
0093     QJsonObject map = parser.object();
0094     if (!map.contains(QStringLiteral("version"))) {
0095         figureOutServer(kJob->url());
0096         qDebug() << "No json";
0097         return;
0098     }
0099 
0100     m_server = kJob->url().adjusted(QUrl::RemoveFilename).toString();
0101     qDebug() << "ownCloud appears to be running at the specified URL";
0102     serverCheckResult(true);
0103 }
0104 
0105 void OwncloudController::setWorking(bool start)
0106 {
0107     if (start == m_isWorking) {
0108         return;
0109     }
0110 
0111     m_isWorking = start;
0112     Q_EMIT isWorkingChanged();
0113 }
0114 
0115 void OwncloudController::serverCheckResult(bool result)
0116 {
0117     if (!result) {
0118         m_errorMessage = i18n("Unable to connect to ownCloud at the given server URL. Please check the server URL.");
0119         setWorking(false);
0120     } else {
0121         m_errorMessage.clear();
0122 
0123         qDebug() << "Server URL ok, checking auth...";
0124 
0125         m_json.clear();
0126 
0127         QUrl url(m_server);
0128 
0129         url.setUserName(m_username);
0130         url.setPassword(m_password);
0131 
0132         if (!url.path().endsWith(QLatin1String("/"))) {
0133             url.setPath(url.path() + QLatin1Char('/'));
0134         }
0135 
0136         url.setPath(url.path() + QLatin1String("remote.php/webdav"));
0137 
0138         // Send a basic PROPFIND command to test access
0139         const QString requestStr = QStringLiteral(
0140             "<d:propfind xmlns:d=\"DAV:\">"
0141             "<d:prop>"
0142             "<d:current-user-principal />"
0143             "</d:prop>"
0144             "</d:propfind>");
0145 
0146         KIO::DavJob *job = KIO::davPropFind(url, QDomDocument(requestStr).toString(), QStringLiteral("1"), KIO::HideProgressInfo);
0147         connect(job, SIGNAL(finished(KJob *)), this, SLOT(authCheckResult(KJob *)));
0148         connect(job, SIGNAL(data(KIO::Job *, QByteArray)), SLOT(dataReceived(KIO::Job *, QByteArray)));
0149 
0150         QVariantMap metadata{
0151             {QStringLiteral("cookies"), QStringLiteral("none")},
0152             {QStringLiteral("no-cache"), true},
0153         };
0154 
0155         job->setMetaData(metadata);
0156         job->setUiDelegate(nullptr);
0157         job->start();
0158     }
0159 
0160     Q_EMIT errorMessageChanged();
0161 }
0162 
0163 void OwncloudController::authCheckResult(KJob *job)
0164 {
0165     if (job->error()) {
0166         qDebug() << job->errorString();
0167         qDebug() << job->errorText();
0168     }
0169 
0170     KIO::DavJob *kJob = qobject_cast<KIO::DavJob *>(job);
0171     qDebug() << "Auth job finished, received error page:" << kJob->isErrorPage();
0172 
0173     if (kJob->isErrorPage()) {
0174         m_errorMessage = i18n("Unable to authenticate using the provided username and password");
0175     } else {
0176         m_errorMessage.clear();
0177     }
0178 
0179     Q_EMIT errorMessageChanged();
0180 
0181     if (!kJob->isErrorPage()) {
0182         m_state = Services;
0183         Q_EMIT stateChanged();
0184     }
0185 
0186     setWorking(false);
0187 }
0188 
0189 bool OwncloudController::isWorking()
0190 {
0191     return m_isWorking;
0192 }
0193 
0194 QString OwncloudController::errorMessage() const
0195 {
0196     return m_errorMessage;
0197 }
0198 
0199 void OwncloudController::finish(const QStringList &disabledServices)
0200 {
0201     QVariantMap data;
0202     data.insert(QStringLiteral("server"), m_server);
0203 
0204     for (const QString &service : disabledServices) {
0205         data.insert(QStringLiteral("__service/") + service, false);
0206     }
0207 
0208     QUrl serverUrl(m_server);
0209 
0210     QUrl carddavUrl(serverUrl.adjusted(QUrl::StripTrailingSlash));
0211     carddavUrl.setPath(carddavUrl.path() + QStringLiteral("/remote.php/carddav/addressbooks/%1").arg(m_username));
0212 
0213     QUrl webdavUrl(serverUrl.adjusted(QUrl::StripTrailingSlash));
0214     webdavUrl.setPath(webdavUrl.path() + QStringLiteral("/remote.php/webdav"));
0215 
0216     data.insert(QStringLiteral("carddavUrl"), carddavUrl);
0217     data.insert(QStringLiteral("dav/host"), carddavUrl.host());
0218     data.insert(QStringLiteral("dav/storagePath"), webdavUrl.path());
0219 
0220     Q_EMIT wizardFinished(m_username, m_password, data);
0221 }
0222 
0223 void OwncloudController::cancel()
0224 {
0225     Q_EMIT wizardCancelled();
0226 }
0227 
0228 QVariantList OwncloudController::availableServices() const
0229 {
0230     // TODO Find a way to not hardcode this
0231     return {QVariant::fromValue(Service{QStringLiteral("owncloud-storage"), i18n("Storage"), i18n("Storage integration")})};
0232 }