Libkdav2

caldavprotocol.cpp
1 /*
2  Copyright (c) 2009 Grégory Oestreicher <[email protected]>
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 
28 using namespace KDAV2;
29 
30 class CaldavCollectionQueryBuilder : public XMLQueryBuilder
31 {
32 public:
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 
59 static 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 
112 class CaldavListEventQueryBuilder : public XMLQueryBuilder
113 {
114 public:
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 
126 class CaldavListTodoQueryBuilder : public XMLQueryBuilder
127 {
128 public:
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 
140 class CaldavListJournalQueryBuilder : public XMLQueryBuilder
141 {
142 public:
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 
154 class CaldavMultigetQueryBuilder : public XMLQueryBuilder
155 {
156 public:
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 
192 CaldavProtocol::CaldavProtocol()
193 {
194 }
195 
196 bool CaldavProtocol::supportsPrincipals() const
197 {
198  return true;
199 }
200 
201 bool CaldavProtocol::supportsCTags() const
202 {
203  return true;
204 }
205 
206 bool CaldavProtocol::useReport() const
207 {
208  return true;
209 }
210 
211 bool CaldavProtocol::useMultiget() const
212 {
213  return true;
214 }
215 
216 QString CaldavProtocol::principalHomeSet() const
217 {
218  return QStringLiteral("calendar-home-set");
219 }
220 
221 QString CaldavProtocol::principalHomeSetNS() const
222 {
223  return QStringLiteral("urn:ietf:params:xml:ns:caldav");
224 }
225 
226 XMLQueryBuilder::Ptr CaldavProtocol::collectionsQuery() const
227 {
228  return XMLQueryBuilder::Ptr(new CaldavCollectionQueryBuilder());
229 }
230 
231 QString 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 
239 QVector<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 
248 XMLQueryBuilder::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 
255 QString CaldavProtocol::responseNamespace() const
256 {
257  return QStringLiteral("urn:ietf:params:xml:ns:caldav");
258 }
259 
260 QString CaldavProtocol::dataTagName() const
261 {
262  return QStringLiteral("calendar-data");
263 }
264 
265 DavCollection::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 }
QDomAttr createAttribute(const QString &name)
void setValue(const QString &v)
QDomNode appendChild(const QDomNode &newChild)
std::optional< QSqlQuery > query(const QString &queryStatement)
QString attribute(const QString &name, const QString &defValue) const const
QDomElement createElementNS(const QString &nsURI, const QString &qName)
QUrl fromUserInput(const QString &userInput)
QString toString(QUrl::FormattingOptions options) const const
The collection can contain todo DAV resources.
Definition: davcollection.h:62
PartitionTable::TableType type
bool isEmpty() const const
bool isEmpty() const const
The collection can contain free/busy information.
Definition: davcollection.h:64
The collection can contain journal DAV resources.
Definition: davcollection.h:65
QDomText createTextNode(const QString &value)
QString toLower() const const
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
bool isNull() const const
QDomAttr setAttributeNode(const QDomAttr &newAttr)
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
The collection can contain event DAV resources.
Definition: davcollection.h:61
The collection can contain anything calendar-related.
Definition: davcollection.h:66
QString mimeType(Type)
Base class for XML query builders.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu Jan 27 2022 23:10:33 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.