File indexing completed on 2024-06-16 04:52:28
0001 /* 0002 Copyright (c) 2010 Tobias Koenig <tokoe@kde.org> 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 "davitemslistjob.h" 0020 0021 #include "daverror.h" 0022 #include "davmanager.h" 0023 #include "davprotocolbase.h" 0024 #include "davurl.h" 0025 #include "utils.h" 0026 #include "davjob.h" 0027 0028 #include <QtCore/QBuffer> 0029 #include <QtCore/QDebug> 0030 0031 using namespace KDAV2; 0032 0033 class DavItemsListJobPrivate { 0034 public: 0035 DavItemsListJobPrivate(const DavUrl &url); 0036 0037 DavUrl mUrl; 0038 QStringList mMimeTypes; 0039 QString mRangeStart; 0040 QString mRangeEnd; 0041 DavItem::List mItems; 0042 QSet<QString> mSeenUrls; // to prevent events duplication with some servers 0043 uint mSubJobCount; 0044 }; 0045 0046 DavItemsListJobPrivate::DavItemsListJobPrivate(const DavUrl &url) 0047 : mUrl(url) 0048 , mSubJobCount(0) 0049 { 0050 } 0051 0052 0053 DavItemsListJob::DavItemsListJob(const DavUrl &url, QObject *parent) 0054 : DavJobBase(parent) 0055 , d(std::unique_ptr<DavItemsListJobPrivate>(new DavItemsListJobPrivate(url))) 0056 { 0057 } 0058 0059 DavItemsListJob::~DavItemsListJob() 0060 { 0061 } 0062 0063 void DavItemsListJob::setContentMimeTypes(const QStringList &types) 0064 { 0065 d->mMimeTypes = types; 0066 } 0067 0068 void DavItemsListJob::setTimeRange(const QString &start, const QString &end) 0069 { 0070 d->mRangeStart = start; 0071 d->mRangeEnd = end; 0072 } 0073 0074 void DavItemsListJob::start() 0075 { 0076 const DavProtocolBase *protocol = DavManager::self()->davProtocol(d->mUrl.protocol()); 0077 Q_ASSERT(protocol); 0078 QVectorIterator<XMLQueryBuilder::Ptr> it(protocol->itemsQueries()); 0079 0080 while (it.hasNext()) { 0081 XMLQueryBuilder::Ptr builder = it.next(); 0082 if (!d->mRangeStart.isEmpty()) { 0083 builder->setParameter(QStringLiteral("start"), d->mRangeStart); 0084 } 0085 if (!d->mRangeEnd.isEmpty()) { 0086 builder->setParameter(QStringLiteral("end"), d->mRangeEnd); 0087 } 0088 0089 const QDomDocument props = builder->buildQuery(); 0090 const QString mimeType = builder->mimeType(); 0091 0092 if (d->mMimeTypes.isEmpty() || d->mMimeTypes.contains(mimeType)) { 0093 ++d->mSubJobCount; 0094 const auto url = d->mUrl.url(); 0095 auto job = protocol->useReport() ? 0096 DavManager::self()->createReportJob(url, props) : 0097 DavManager::self()->createPropFindJob(url, props); 0098 job->setProperty("itemsMimeType", mimeType); 0099 connect(job, &DavJob::result, this, &DavItemsListJob::davJobFinished); 0100 } 0101 } 0102 0103 if (d->mSubJobCount == 0) { 0104 setError(ERR_ITEMLIST_NOMIMETYPE); 0105 setErrorTextFromDavError(); 0106 emitResult(); 0107 } 0108 } 0109 0110 DavItem::List DavItemsListJob::items() const 0111 { 0112 return d->mItems; 0113 } 0114 0115 void DavItemsListJob::davJobFinished(KJob *job) 0116 { 0117 auto davJob = static_cast<DavJob*>(job); 0118 if (davJob->error()) { 0119 setErrorFromJob(davJob); 0120 } else { 0121 /* 0122 * Extract data from a document like the following: 0123 * 0124 * <multistatus xmlns="DAV:"> 0125 * <response xmlns="DAV:"> 0126 * <href xmlns="DAV:">/caldav.php/test1.user/home/KOrganizer-166749289.780.ics</href> 0127 * <propstat xmlns="DAV:"> 0128 * <prop xmlns="DAV:"> 0129 * <getetag xmlns="DAV:">"b4bbea0278f4f63854c4167a7656024a"</getetag> 0130 * </prop> 0131 * <status xmlns="DAV:">HTTP/1.1 200 OK</status> 0132 * </propstat> 0133 * </response> 0134 * <response xmlns="DAV:"> 0135 * <href xmlns="DAV:">/caldav.php/test1.user/home/KOrganizer-399416366.464.ics</href> 0136 * <propstat xmlns="DAV:"> 0137 * <prop xmlns="DAV:"> 0138 * <getetag xmlns="DAV:">"52eb129018398a7da4f435b2bc4c6cd5"</getetag> 0139 * </prop> 0140 * <status xmlns="DAV:">HTTP/1.1 200 OK</status> 0141 * </propstat> 0142 * </response> 0143 * </multistatus> 0144 */ 0145 0146 const QString itemsMimeType = job->property("itemsMimeType").toString(); 0147 const QDomDocument document = davJob->response(); 0148 const QDomElement documentElement = document.documentElement(); 0149 0150 QDomElement responseElement = Utils::firstChildElementNS(documentElement, QStringLiteral("DAV:"), QStringLiteral("response")); 0151 while (!responseElement.isNull()) { 0152 0153 QDomElement propstatElement; 0154 0155 // check for the valid propstat, without giving up on first error 0156 { 0157 const QDomNodeList propstats = responseElement.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("propstat")); 0158 for (int i = 0; i < propstats.length(); ++i) { 0159 const QDomElement propstatCandidate = propstats.item(i).toElement(); 0160 const QDomElement statusElement = Utils::firstChildElementNS(propstatCandidate, QStringLiteral("DAV:"), QStringLiteral("status")); 0161 if (statusElement.text().contains(QStringLiteral("200"))) { 0162 propstatElement = propstatCandidate; 0163 } 0164 } 0165 } 0166 0167 if (propstatElement.isNull()) { 0168 responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); 0169 continue; 0170 } 0171 0172 const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); 0173 0174 // check whether it is a dav collection ... 0175 const QDomElement resourcetypeElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("resourcetype")); 0176 if (!responseElement.isNull()) { 0177 const QDomElement collectionElement = Utils::firstChildElementNS(resourcetypeElement, QStringLiteral("DAV:"), QStringLiteral("collection")); 0178 if (!collectionElement.isNull()) { 0179 responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); 0180 continue; 0181 } 0182 } 0183 0184 // ... if not it is an item 0185 DavItem item; 0186 item.setContentType(itemsMimeType); 0187 0188 // extract path 0189 const QDomElement hrefElement = Utils::firstChildElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("href")); 0190 const QString href = hrefElement.text(); 0191 0192 QUrl url = davJob->url(); 0193 url.setUserInfo(QString()); 0194 if (href.startsWith(QLatin1Char('/'))) { 0195 // href is only a path, use request url to complete 0196 url.setPath(href, QUrl::TolerantMode); 0197 } else { 0198 // href is a complete url 0199 url = QUrl::fromUserInput(href); 0200 } 0201 0202 QString itemUrl = url.toDisplayString(); 0203 if (d->mSeenUrls.contains(itemUrl)) { 0204 responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); 0205 continue; 0206 } 0207 0208 d->mSeenUrls << itemUrl; 0209 auto _url = url; 0210 _url.setUserInfo(d->mUrl.url().userInfo()); 0211 item.setUrl(DavUrl(_url, d->mUrl.protocol())); 0212 0213 // extract etag 0214 const QDomElement getetagElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("getetag")); 0215 0216 item.setEtag(getetagElement.text()); 0217 0218 d->mItems << item; 0219 0220 responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); 0221 } 0222 } 0223 0224 if (--d->mSubJobCount == 0) { 0225 emitResult(); 0226 } 0227 } 0228