Libkdav2

caldavprotocol.cpp
1/*
2 Copyright (c) 2009 Grégory Oestreicher <greg@kamago.net>
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 "caldavprotocol.h"
20#include "common/utils.h"
21
22#include <QtCore/QDateTime>
23#include <QtCore/QStringList>
24#include <QtCore/QUrl>
25#include <QtCore/QVariant>
26#include <QtXml/QDomDocument>
27
28using namespace KDAV2;
29
30class CaldavCollectionQueryBuilder : public XMLQueryBuilder
31{
32public:
33 QDomDocument buildQuery() const Q_DECL_OVERRIDE
34 {
35 QDomDocument document;
36
37 QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind"));
38 document.appendChild(propfindElement);
39
40 QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop"));
41 propfindElement.appendChild(propElement);
42
43 propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("displayname")));
44 propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype")));
45 propElement.appendChild(document.createElementNS(QStringLiteral("http://apple.com/ns/ical/"), QStringLiteral("calendar-color")));
46 propElement.appendChild(document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("supported-calendar-component-set")));
47 propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("current-user-privilege-set")));
48 propElement.appendChild(document.createElementNS(QStringLiteral("http://calendarserver.org/ns/"), QStringLiteral("getctag")));
49
50 return document;
51 }
52
53 QString mimeType() const Q_DECL_OVERRIDE
54 {
55 return QString();
56 }
57};
58
59static QDomDocument listQuery(const QString &typeFilter, const QString startTime, const QString &endTime)
60{
61 QDomDocument document;
62
63 QDomElement queryElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("calendar-query"));
64 document.appendChild(queryElement);
65
66 QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop"));
67 queryElement.appendChild(propElement);
68
69 QDomElement getetagElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("getetag"));
70 propElement.appendChild(getetagElement);
71
72 QDomElement getRTypeElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype"));
73 propElement.appendChild(getRTypeElement);
74
75 QDomElement filterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("filter"));
76 queryElement.appendChild(filterElement);
77
78 QDomElement compfilterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp-filter"));
79
80 QDomAttr nameAttribute = document.createAttribute(QStringLiteral("name"));
81 nameAttribute.setValue(QStringLiteral("VCALENDAR"));
82 compfilterElement.setAttributeNode(nameAttribute);
83 filterElement.appendChild(compfilterElement);
84
85 QDomElement subcompfilterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp-filter"));
86 nameAttribute = document.createAttribute(QStringLiteral("name"));
87 nameAttribute.setValue(typeFilter);
88 subcompfilterElement.setAttributeNode(nameAttribute);
89
90 if (!startTime.isEmpty() || !endTime.isEmpty()) {
91 QDomElement timeRangeElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("time-range"));
92
93 if (!startTime.isEmpty()) {
94 QDomAttr startAttribute = document.createAttribute(QStringLiteral("start"));
95 startAttribute.setValue(startTime);
96 timeRangeElement.setAttributeNode(startAttribute);
97 }
98
99 if (!endTime.isEmpty()) {
100 QDomAttr endAttribute = document.createAttribute(QStringLiteral("end"));
101 endAttribute.setValue(endTime);
102 timeRangeElement.setAttributeNode(endAttribute);
103 }
104
105 subcompfilterElement.appendChild(timeRangeElement);
106 }
107 compfilterElement.appendChild(subcompfilterElement);
108
109 return document;
110}
111
112class CaldavListEventQueryBuilder : public XMLQueryBuilder
113{
114public:
115 QDomDocument buildQuery() const Q_DECL_OVERRIDE
116 {
117 return listQuery(QLatin1String{"VEVENT"}, parameter(QStringLiteral("start")).toString(), parameter(QStringLiteral("end")).toString());
118 }
119
120 QString mimeType() const Q_DECL_OVERRIDE
121 {
122 return QStringLiteral("VEVENT");
123 }
124};
125
126class CaldavListTodoQueryBuilder : public XMLQueryBuilder
127{
128public:
129 QDomDocument buildQuery() const Q_DECL_OVERRIDE
130 {
131 return listQuery(QLatin1String{"VTODO"}, parameter(QStringLiteral("start")).toString(), parameter(QStringLiteral("end")).toString());
132 }
133
134 QString mimeType() const Q_DECL_OVERRIDE
135 {
136 return QStringLiteral("VTODO");
137 }
138};
139
140class CaldavListJournalQueryBuilder : public XMLQueryBuilder
141{
142public:
143 QDomDocument buildQuery() const Q_DECL_OVERRIDE
144 {
145 return listQuery(QLatin1String{"VJOURNAL"}, parameter(QStringLiteral("start")).toString(), parameter(QStringLiteral("end")).toString());
146 }
147
148 QString mimeType() const Q_DECL_OVERRIDE
149 {
150 return QStringLiteral("VJOURNAL");
151 }
152};
153
154class CaldavMultigetQueryBuilder : public XMLQueryBuilder
155{
156public:
157 QDomDocument buildQuery() const Q_DECL_OVERRIDE
158 {
159 QDomDocument document;
160 const QStringList urls = parameter(QStringLiteral("urls")).toStringList();
161 if (urls.isEmpty()) {
162 return document;
163 }
164
165 QDomElement multigetElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("calendar-multiget"));
166 document.appendChild(multigetElement);
167
168 QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop"));
169 multigetElement.appendChild(propElement);
170
171 propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("getetag")));
172 propElement.appendChild(document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("calendar-data")));
173
174 for (const QString &url : urls) {
175 QDomElement hrefElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("href"));
176 const QUrl pathUrl = QUrl::fromUserInput(url);
177 const QDomText textNode = document.createTextNode(pathUrl.toString());
178 hrefElement.appendChild(textNode);
179
180 multigetElement.appendChild(hrefElement);
181 }
182
183 return document;
184 }
185
186 QString mimeType() const Q_DECL_OVERRIDE
187 {
188 return QString();
189 }
190};
191
192CaldavProtocol::CaldavProtocol()
193{
194}
195
196bool CaldavProtocol::supportsPrincipals() const
197{
198 return true;
199}
200
201bool CaldavProtocol::supportsCTags() const
202{
203 return true;
204}
205
206bool CaldavProtocol::useReport() const
207{
208 return true;
209}
210
211bool CaldavProtocol::useMultiget() const
212{
213 return true;
214}
215
216QString CaldavProtocol::principalHomeSet() const
217{
218 return QStringLiteral("calendar-home-set");
219}
220
221QString CaldavProtocol::principalHomeSetNS() const
222{
223 return QStringLiteral("urn:ietf:params:xml:ns:caldav");
224}
225
226XMLQueryBuilder::Ptr CaldavProtocol::collectionsQuery() const
227{
228 return XMLQueryBuilder::Ptr(new CaldavCollectionQueryBuilder());
229}
230
231QString CaldavProtocol::collectionsXQuery() const
232{
233 //const QString query( "//*[local-name()='calendar' and namespace-uri()='urn:ietf:params:xml:ns:caldav']/ancestor::*[local-name()='prop' and namespace-uri()='DAV:']/*[local-name()='supported-calendar-component-set' and namespace-uri()='urn:ietf:params:xml:ns:caldav']/*[local-name()='comp' and namespace-uri()='urn:ietf:params:xml:ns:caldav' and (@name='VTODO' or @name='VEVENT')]/ancestor::*[local-name()='response' and namespace-uri()='DAV:']" );
234 const QString query(QStringLiteral("//*[local-name()='calendar' and namespace-uri()='urn:ietf:params:xml:ns:caldav']/ancestor::*[local-name()='prop' and namespace-uri()='DAV:']/ancestor::*[local-name()='response' and namespace-uri()='DAV:']"));
235
236 return query;
237}
238
239QVector<XMLQueryBuilder::Ptr> CaldavProtocol::itemsQueries() const
240{
242 ret << XMLQueryBuilder::Ptr(new CaldavListEventQueryBuilder());
243 ret << XMLQueryBuilder::Ptr(new CaldavListTodoQueryBuilder());
244 ret << XMLQueryBuilder::Ptr(new CaldavListJournalQueryBuilder());
245 return ret;
246}
247
248XMLQueryBuilder::Ptr CaldavProtocol::itemsReportQuery(const QStringList &urls) const
249{
250 XMLQueryBuilder::Ptr ret(new CaldavMultigetQueryBuilder());
251 ret->setParameter(QStringLiteral("urls"), urls);
252 return ret;
253}
254
255QString CaldavProtocol::responseNamespace() const
256{
257 return QStringLiteral("urn:ietf:params:xml:ns:caldav");
258}
259
260QString CaldavProtocol::dataTagName() const
261{
262 return QStringLiteral("calendar-data");
263}
264
265DavCollection::ContentTypes CaldavProtocol::collectionContentTypes(const QDomElement &propstatElement) const
266{
267 /*
268 * Extract the content type information from a propstat like the following
269 * <propstat xmlns="DAV:">
270 * <prop xmlns="DAV:">
271 * <C:supported-calendar-component-set xmlns:C="urn:ietf:params:xml:ns:caldav">
272 * <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VEVENT"/>
273 * <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VTODO"/>
274 * <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VJOURNAL"/>
275 * <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VTIMEZONE"/>
276 * <C:comp xmlns:C="urn:ietf:params:xml:ns:caldav" name="VFREEBUSY"/>
277 * </C:supported-calendar-component-set>
278 * <resourcetype xmlns="DAV:">
279 * <collection xmlns="DAV:"/>
280 * <C:calendar xmlns:C="urn:ietf:params:xml:ns:caldav"/>
281 * <C:schedule-calendar xmlns:C="urn:ietf:params:xml:ns:caldav"/>
282 * </resourcetype>
283 * <displayname xmlns="DAV:">Test1 User</displayname>
284 * </prop>
285 * <status xmlns="DAV:">HTTP/1.1 200 OK</status>
286 * </propstat>
287 */
288
289 const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop"));
290 const QDomElement supportedcomponentElement = Utils::firstChildElementNS(propElement, QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("supported-calendar-component-set"));
291
292 DavCollection::ContentTypes contentTypes;
293 QDomElement compElement = Utils::firstChildElementNS(supportedcomponentElement, QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp"));
294
295 /*
296 * Assign the content-type if the server didn't return anything.
297 * According to RFC4791, §5.2.3:
298 * In the absence of this property, the server MUST accept all
299 * component types, and the client can assume that all component
300 * types are accepted.
301 */
302 if (compElement.isNull()) {
303 contentTypes |= DavCollection::Calendar;
304 contentTypes |= DavCollection::Events;
305 contentTypes |= DavCollection::Todos;
306 contentTypes |= DavCollection::FreeBusy;
307 contentTypes |= DavCollection::Journal;
308 }
309
310 while (!compElement.isNull()) {
311 const QString type = compElement.attribute(QStringLiteral("name")).toLower();
312 if (type == QLatin1String("vcalendar")) {
313 contentTypes |= DavCollection::Calendar;
314 } else if (type == QLatin1String("vevent")) {
315 contentTypes |= DavCollection::Events;
316 } else if (type == QLatin1String("vtodo")) {
317 contentTypes |= DavCollection::Todos;
318 } else if (type == QLatin1String("vfreebusy")) {
319 contentTypes |= DavCollection::FreeBusy;
320 } else if (type == QLatin1String("vjournal")) {
321 contentTypes |= DavCollection::Journal;
322 }
323
324 compElement = Utils::nextSiblingElementNS(compElement, QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp"));
325 }
326
327 return contentTypes;
328}
@ Journal
The collection can contain journal DAV resources.
@ Todos
The collection can contain todo DAV resources.
@ FreeBusy
The collection can contain free/busy information.
@ Events
The collection can contain event DAV resources.
@ Calendar
The collection can contain anything calendar-related.
Base class for XML query builders.
Type type(const QSqlDatabase &db)
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
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
void setValue(const QString &v)
QDomAttr createAttribute(const QString &name)
QDomElement createElementNS(const QString &nsURI, const QString &qName)
QDomText createTextNode(const QString &value)
QString attribute(const QString &name, const QString &defValue) const const
QDomAttr setAttributeNode(const QDomAttr &newAttr)
QDomNode appendChild(const QDomNode &newChild)
bool isNull() const const
bool isEmpty() const const
bool isEmpty() const const
QString toLower() const const
QUrl fromUserInput(const QString &userInput, const QString &workingDirectory, UserInputResolutionOptions options)
QString toString(FormattingOptions options) const const
QString toString() const const
QStringList toStringList() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:28 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.