Libkdav2

davitemslistjob.cpp
1/*
2 Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*/
18
19#include "davitemslistjob.h"
20
21#include "daverror.h"
22#include "davmanager.h"
23#include "davprotocolbase.h"
24#include "davurl.h"
25#include "utils.h"
26#include "davjob.h"
27
28#include <QtCore/QBuffer>
29#include <QtCore/QDebug>
30
31using namespace KDAV2;
32
33class DavItemsListJobPrivate {
34public:
35 DavItemsListJobPrivate(const DavUrl &url);
36
37 DavUrl mUrl;
38 QStringList mMimeTypes;
39 QString mRangeStart;
40 QString mRangeEnd;
41 DavItem::List mItems;
42 QSet<QString> mSeenUrls; // to prevent events duplication with some servers
43 uint mSubJobCount;
44};
45
46DavItemsListJobPrivate::DavItemsListJobPrivate(const DavUrl &url)
47 : mUrl(url)
48 , mSubJobCount(0)
49{
50}
51
52
54 : DavJobBase(parent)
55 , d(std::unique_ptr<DavItemsListJobPrivate>(new DavItemsListJobPrivate(url)))
56{
57}
58
59DavItemsListJob::~DavItemsListJob()
60{
61}
62
64{
65 d->mMimeTypes = types;
66}
67
69{
70 d->mRangeStart = start;
71 d->mRangeEnd = end;
72}
73
75{
76 const DavProtocolBase *protocol = DavManager::self()->davProtocol(d->mUrl.protocol());
77 Q_ASSERT(protocol);
78 QVectorIterator<XMLQueryBuilder::Ptr> it(protocol->itemsQueries());
79
80 while (it.hasNext()) {
81 XMLQueryBuilder::Ptr builder = it.next();
82 if (!d->mRangeStart.isEmpty()) {
83 builder->setParameter(QStringLiteral("start"), d->mRangeStart);
84 }
85 if (!d->mRangeEnd.isEmpty()) {
86 builder->setParameter(QStringLiteral("end"), d->mRangeEnd);
87 }
88
89 const QDomDocument props = builder->buildQuery();
90 const QString mimeType = builder->mimeType();
91
92 if (d->mMimeTypes.isEmpty() || d->mMimeTypes.contains(mimeType)) {
93 ++d->mSubJobCount;
94 const auto url = d->mUrl.url();
95 auto job = protocol->useReport() ?
96 DavManager::self()->createReportJob(url, props) :
98 job->setProperty("itemsMimeType", mimeType);
99 connect(job, &DavJob::result, this, &DavItemsListJob::davJobFinished);
100 }
101 }
102
103 if (d->mSubJobCount == 0) {
104 setError(ERR_ITEMLIST_NOMIMETYPE);
105 setErrorTextFromDavError();
106 emitResult();
107 }
108}
109
111{
112 return d->mItems;
113}
114
115void DavItemsListJob::davJobFinished(KJob *job)
116{
117 auto davJob = static_cast<DavJob*>(job);
118 if (davJob->error()) {
119 setErrorFromJob(davJob);
120 } else {
121 /*
122 * Extract data from a document like the following:
123 *
124 * <multistatus xmlns="DAV:">
125 * <response xmlns="DAV:">
126 * <href xmlns="DAV:">/caldav.php/test1.user/home/KOrganizer-166749289.780.ics</href>
127 * <propstat xmlns="DAV:">
128 * <prop xmlns="DAV:">
129 * <getetag xmlns="DAV:">"b4bbea0278f4f63854c4167a7656024a"</getetag>
130 * </prop>
131 * <status xmlns="DAV:">HTTP/1.1 200 OK</status>
132 * </propstat>
133 * </response>
134 * <response xmlns="DAV:">
135 * <href xmlns="DAV:">/caldav.php/test1.user/home/KOrganizer-399416366.464.ics</href>
136 * <propstat xmlns="DAV:">
137 * <prop xmlns="DAV:">
138 * <getetag xmlns="DAV:">"52eb129018398a7da4f435b2bc4c6cd5"</getetag>
139 * </prop>
140 * <status xmlns="DAV:">HTTP/1.1 200 OK</status>
141 * </propstat>
142 * </response>
143 * </multistatus>
144 */
145
146 const QString itemsMimeType = job->property("itemsMimeType").toString();
147 const QDomDocument document = davJob->response();
148 const QDomElement documentElement = document.documentElement();
149
150 QDomElement responseElement = Utils::firstChildElementNS(documentElement, QStringLiteral("DAV:"), QStringLiteral("response"));
151 while (!responseElement.isNull()) {
152
153 QDomElement propstatElement;
154
155 // check for the valid propstat, without giving up on first error
156 {
157 const QDomNodeList propstats = responseElement.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("propstat"));
158 for (int i = 0; i < propstats.length(); ++i) {
159 const QDomElement propstatCandidate = propstats.item(i).toElement();
160 const QDomElement statusElement = Utils::firstChildElementNS(propstatCandidate, QStringLiteral("DAV:"), QStringLiteral("status"));
161 if (statusElement.text().contains(QStringLiteral("200"))) {
162 propstatElement = propstatCandidate;
163 }
164 }
165 }
166
167 if (propstatElement.isNull()) {
168 responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
169 continue;
170 }
171
172 const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop"));
173
174 // check whether it is a dav collection ...
175 const QDomElement resourcetypeElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("resourcetype"));
176 if (!responseElement.isNull()) {
177 const QDomElement collectionElement = Utils::firstChildElementNS(resourcetypeElement, QStringLiteral("DAV:"), QStringLiteral("collection"));
178 if (!collectionElement.isNull()) {
179 responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
180 continue;
181 }
182 }
183
184 // ... if not it is an item
185 DavItem item;
186 item.setContentType(itemsMimeType);
187
188 // extract path
189 const QDomElement hrefElement = Utils::firstChildElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("href"));
190 const QString href = hrefElement.text();
191
192 QUrl url = davJob->url();
193 url.setUserInfo(QString());
194 if (href.startsWith(QLatin1Char('/'))) {
195 // href is only a path, use request url to complete
196 url.setPath(href, QUrl::TolerantMode);
197 } else {
198 // href is a complete url
199 url = QUrl::fromUserInput(href);
200 }
201
202 QString itemUrl = url.toDisplayString();
203 if (d->mSeenUrls.contains(itemUrl)) {
204 responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
205 continue;
206 }
207
208 d->mSeenUrls << itemUrl;
209 auto _url = url;
210 _url.setUserInfo(d->mUrl.url().userInfo());
211 item.setUrl(DavUrl(_url, d->mUrl.protocol()));
212
213 // extract etag
214 const QDomElement getetagElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("getetag"));
215
216 item.setEtag(getetagElement.text());
217
218 d->mItems << item;
219
220 responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response"));
221 }
222 }
223
224 if (--d->mSubJobCount == 0) {
225 emitResult();
226 }
227}
228
A helper class to store information about DAV resources.
Definition davitem.h:52
void setEtag(const QString &etag)
Sets the etag of the item.
Definition davitem.cpp:109
void setUrl(const DavUrl &url)
Sets the url that identifies the item.
Definition davitem.cpp:79
void setContentType(const QString &type)
Sets the content type of the item.
Definition davitem.cpp:89
void setTimeRange(const QString &start, const QString &end)
Sets the start and end time to list items for.
void setContentMimeTypes(const QStringList &types)
Limits the mime types of the items requested.
DavItem::List items() const
Returns the list of items seen including identifier url and etag information.
DavItemsListJob(const DavUrl &url, QObject *parent=nullptr)
Creates a new dav items list job.
void start() override
Starts the job.
base class for the jobs used by the resource.
Definition davjobbase.h:38
void setErrorFromJob(DavJob *, ErrorNumber jobErrorCode=ERR_PROBLEM_WITH_REQUEST)
Set the error of this job from a failed DavJob (executed by this job).
DavJob * createPropFindJob(const QUrl &url, const QDomDocument &document, const QString &depth=QStringLiteral("1"))
Returns a preconfigured DAV PROPFIND job.
static DavManager * self()
Returns the global instance of the DAV manager.
DavJob * createReportJob(const QUrl &url, const QDomDocument &document, const QString &depth=QStringLiteral("1"))
Returns a preconfigured DAV REPORT job.
const DavProtocolBase * davProtocol(Protocol protocol)
Returns the DAV protocol dialect object for the given DAV protocol.
Base class for various DAV groupware dialects.
virtual bool useReport() const =0
Returns whether the dav protocol dialect supports the REPORT command to query all resources of a coll...
virtual QVector< XMLQueryBuilder::Ptr > itemsQueries() const =0
Returns a list of XML documents that represent DAV queries to list all available DAV resources inside...
A helper class to combine url and protocol of a DAV url.
Definition davurl.h:36
void emitResult()
void result(KJob *job)
void setError(int errorCode)
Q_SCRIPTABLE Q_NOREPLY void start()
QDomElement KPIMKDAV2_EXPORT firstChildElementNS(const QDomElement &parent, const QString &namespaceUri, const QString &tagName)
Returns the first child element of parent that has the given tagName and is part of the namespaceUri.
Definition utils.cpp:37
QDomElement KPIMKDAV2_EXPORT nextSiblingElementNS(const QDomElement &element, const QString &namespaceUri, const QString &tagName)
Returns the next sibling element of element that has the given tagName and is part of the namespaceUr...
Definition utils.cpp:51
QDomElement documentElement() const const
QDomNodeList elementsByTagNameNS(const QString &nsURI, const QString &localName) const const
QString text() const const
bool isNull() const const
QDomElement toElement() const const
QDomNode item(int index) const const
int length() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QVariant property(const char *name) const const
bool setProperty(const char *name, QVariant &&value)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
TolerantMode
QUrl fromUserInput(const QString &userInput, const QString &workingDirectory, UserInputResolutionOptions options)
void setPath(const QString &path, ParsingMode mode)
void setUserInfo(const QString &userInfo, ParsingMode mode)
QString toDisplayString(FormattingOptions options) const const
QString url(FormattingOptions options) const const
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:32:58 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.