File indexing completed on 2024-11-17 04:44:01
0001 /* 0002 Copyright (c) 2018 Christian Mollekopf <mollekopf@kolabsys.com> 0003 0004 This program is free software; you can redistribute it and/or modify 0005 it under the terms of the GNU General Public License as published by 0006 the Free Software Foundation; either version 2 of the License, or 0007 (at your option) any later version. 0008 0009 This program is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0012 GNU General Public License for more details. 0013 0014 You should have received a copy of the GNU General Public License 0015 along with this program; if not, write to the Free Software 0016 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 0017 */ 0018 0019 #include "davdiscoveryjob.h" 0020 0021 #include "libkdav2_debug.h" 0022 #include "davmanager.h" 0023 #include "davprotocolbase.h" 0024 #include "daverror.h" 0025 #include "utils.h" 0026 #include "davjob.h" 0027 0028 using namespace KDAV2; 0029 0030 DavDiscoveryJob::DavDiscoveryJob(const DavUrl &davUrl, const QString &wellKnownSuffix, QObject *parent) 0031 : DavJobBase(parent), mUrl(davUrl) 0032 { 0033 auto url = davUrl.url(); 0034 if (!url.toString().contains("/.well-known/")) { 0035 url.setPath(url.path() + "/.well-known/" + wellKnownSuffix); 0036 mUrl.setUrl(url); 0037 } 0038 } 0039 0040 void DavDiscoveryJob::start() 0041 { 0042 QDomDocument document; 0043 0044 QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind")); 0045 document.appendChild(propfindElement); 0046 0047 QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); 0048 propfindElement.appendChild(propElement); 0049 0050 propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("current-user-principal"))); 0051 propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("principal-URL"))); 0052 0053 DavJob *job = DavManager::self()->createPropFindJob(mUrl.url(), document, QStringLiteral("0")); 0054 connect(job, &DavJob::result, this, &DavDiscoveryJob::davJobFinished); 0055 } 0056 0057 QUrl DavDiscoveryJob::url() const 0058 { 0059 return mUrl.url(); 0060 } 0061 0062 void DavDiscoveryJob::davJobFinished(KJob *job) 0063 { 0064 DavJob *davJob = static_cast<DavJob*>(job); 0065 0066 if (davJob->error()) { 0067 //Retry on the root uri on 404, otherwise fail 0068 if (davJob->httpStatusCode() == 404 && davJob->url().path() != QStringLiteral("/")) { 0069 auto url = mUrl.url(); 0070 url.setPath("/"); 0071 mUrl.setUrl(url); 0072 qCDebug(KDAV2_LOG) << "Retrying on root url" << url; 0073 start(); 0074 return; 0075 } 0076 setErrorFromJob(davJob); 0077 emitResult(); 0078 return; 0079 } 0080 mUrl.setUrl(davJob->url()); 0081 0082 const QDomDocument document = davJob->response(); 0083 const QDomElement multistatusElement = document.documentElement(); 0084 0085 0086 const QString principalHref = [&] { 0087 QDomElement responseElement = Utils::firstChildElementNS(multistatusElement, QStringLiteral("DAV:"), QStringLiteral("response")); 0088 while (!responseElement.isNull()) { 0089 0090 const QDomElement propstatElement = [&] { 0091 // check for the valid propstat, without giving up on first error 0092 const QDomNodeList propstats = responseElement.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("propstat")); 0093 for (int i = 0; i < propstats.length(); ++i) { 0094 const QDomElement propstatCandidate = propstats.item(i).toElement(); 0095 const QDomElement statusElement = Utils::firstChildElementNS(propstatCandidate, QStringLiteral("DAV:"), QStringLiteral("status")); 0096 if (statusElement.text().contains(QLatin1String("200"))) { 0097 return propstatCandidate; 0098 } 0099 } 0100 return QDomElement{}; 0101 }(); 0102 0103 if (propstatElement.isNull()) { 0104 responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); 0105 continue; 0106 } 0107 0108 // extract home sets 0109 const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); 0110 0111 // Trying to get the principal url, given either by current-user-principal or principal-URL 0112 QDomElement urlHolder = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("current-user-principal")); 0113 if (urlHolder.isNull()) { 0114 urlHolder = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("principal-URL")); 0115 } 0116 0117 if (!urlHolder.isNull()) { 0118 // Getting the href that will be used for the next round 0119 const QDomElement hrefElement = Utils::firstChildElementNS(urlHolder, QStringLiteral("DAV:"), QStringLiteral("href")); 0120 if (!hrefElement.isNull()) { 0121 return hrefElement.text(); 0122 } 0123 } 0124 0125 responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); 0126 } 0127 return QString{}; 0128 }(); 0129 0130 QUrl principalUrl(mUrl.url()); 0131 0132 if (principalHref.startsWith(QLatin1Char('/'))) { 0133 // principalHref is only a path, use request url to complete 0134 principalUrl.setPath(principalHref, QUrl::TolerantMode); 0135 } else { 0136 // href is a complete url 0137 principalUrl = QUrl::fromUserInput(principalHref); 0138 principalUrl.setUserName(mUrl.url().userName()); 0139 principalUrl.setPassword(mUrl.url().password()); 0140 } 0141 0142 mUrl.setUrl(principalUrl); 0143 emitResult(); 0144 }