diff --git a/src/common/davcollectionsfetchjob.cpp b/src/common/davcollectionsfetchjob.cpp index 05ce338..7fe566f 100644 --- a/src/common/davcollectionsfetchjob.cpp +++ b/src/common/davcollectionsfetchjob.cpp @@ -1,375 +1,375 @@ /* Copyright (c) 2010 Tobias Koenig This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "davcollectionsfetchjob.h" #include "davjobbase_p.h" #include "davmanager.h" #include "davmanager_p.h" #include "davprincipalhomesetsfetchjob.h" -#include "davprotocolbase.h" +#include "davprotocolbase_p.h" #include "utils.h" #include "daverror.h" #include "libkdav_debug.h" #include #include #include #include #include using namespace KDAV; namespace KDAV { class DavCollectionsFetchJobPrivate : public DavJobBasePrivate { public: DavUrl mUrl; DavCollection::List mCollections; uint mSubJobCount = 0; }; } DavCollectionsFetchJob::DavCollectionsFetchJob(const DavUrl &url, QObject *parent) : DavJobBase(new DavCollectionsFetchJobPrivate, parent) { Q_D(DavCollectionsFetchJob); d->mUrl = url; } void DavCollectionsFetchJob::start() { Q_D(DavCollectionsFetchJob); if (DavManagerPrivate::davProtocol(d->mUrl.protocol())->supportsPrincipals()) { DavPrincipalHomeSetsFetchJob *job = new DavPrincipalHomeSetsFetchJob(d->mUrl); connect(job, &DavPrincipalHomeSetsFetchJob::result, this, &DavCollectionsFetchJob::principalFetchFinished); job->start(); } else { doCollectionsFetch(d->mUrl.url()); } } DavCollection::List DavCollectionsFetchJob::collections() const { Q_D(const DavCollectionsFetchJob); return d->mCollections; } DavUrl DavCollectionsFetchJob::davUrl() const { Q_D(const DavCollectionsFetchJob); return d->mUrl; } void DavCollectionsFetchJob::doCollectionsFetch(const QUrl &url) { Q_D(DavCollectionsFetchJob); ++d->mSubJobCount; const QDomDocument collectionQuery = DavManagerPrivate::davProtocol(d->mUrl.protocol())->collectionsQuery()->buildQuery(); KIO::DavJob *job = DavManager::self()->createPropFindJob(url, collectionQuery); connect(job, &KIO::DavJob::result, this, &DavCollectionsFetchJob::collectionsFetchFinished); job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); } void DavCollectionsFetchJob::principalFetchFinished(KJob *job) { Q_D(DavCollectionsFetchJob); const DavPrincipalHomeSetsFetchJob *davJob = qobject_cast(job); if (davJob->error()) { if (davJob->latestResponseCode()) { // If we have a HTTP response code then this may mean that // the URL was not a principal URL. Retry as if it were a calendar URL. qCDebug(KDAV_LOG) << job->errorText(); doCollectionsFetch(d->mUrl.url()); } else { // Just give up here. setDavError(davJob->davError()); setErrorTextFromDavError(); emitResult(); } return; } const QStringList homeSets = davJob->homeSets(); qCDebug(KDAV_LOG) << "Found " << homeSets.size() << " homesets"; qCDebug(KDAV_LOG) << homeSets; if (homeSets.isEmpty()) { // Same as above, retry as if it were a calendar URL. doCollectionsFetch(d->mUrl.url()); return; } for (const QString &homeSet : homeSets) { QUrl url = d->mUrl.url(); if (homeSet.startsWith(QLatin1Char('/'))) { // homeSet is only a path, use request url to complete url.setPath(homeSet, QUrl::TolerantMode); } else { // homeSet is a complete url QUrl tmpUrl(homeSet); tmpUrl.setUserName(url.userName()); tmpUrl.setPassword(url.password()); url = tmpUrl; } doCollectionsFetch(url); } } void DavCollectionsFetchJob::collectionsFetchFinished(KJob *job) { Q_D(DavCollectionsFetchJob); KIO::DavJob *davJob = qobject_cast(job); const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode")); const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx if (davJob->error() || (responseCode >= 400 && responseCode < 600)) { if (davJob->url() != d->mUrl.url()) { // Retry as if the initial URL was a calendar URL. // We can end up here when retrieving a homeset on // which a PROPFIND resulted in an error doCollectionsFetch(d->mUrl.url()); --d->mSubJobCount; return; } setLatestResponseCode(responseCode); setError(ERR_PROBLEM_WITH_REQUEST); setJobErrorText(davJob->errorText()); setJobError(davJob->error()); setErrorTextFromDavError(); } else { // For use in the collectionDiscovered() signal QUrl _jobUrl = d->mUrl.url(); _jobUrl.setUserInfo(QString()); const QString jobUrl = _jobUrl.toDisplayString(); // Validate that we got a valid PROPFIND response QDomElement rootElement = davJob->response().documentElement(); if (rootElement.tagName().compare(QLatin1String("multistatus"), Qt::CaseInsensitive) != 0) { setError(ERR_COLLECTIONFETCH); setErrorTextFromDavError(); subjobFinished(); return; } QByteArray resp(davJob->response().toByteArray()); QBuffer buffer(&resp); buffer.open(QIODevice::ReadOnly); QXmlQuery xquery; if (!xquery.setFocus(&buffer)) { setError(ERR_COLLECTIONFETCH_XQUERY_SETFOCUS); setErrorTextFromDavError(); subjobFinished(); return; } xquery.setQuery(DavManagerPrivate::davProtocol(d->mUrl.protocol())->collectionsXQuery()); if (!xquery.isValid()) { setError(ERR_COLLECTIONFETCH_XQUERY_INVALID); setErrorTextFromDavError(); subjobFinished(); return; } QString responsesStr; xquery.evaluateTo(&responsesStr); responsesStr.prepend(QLatin1String("")); responsesStr.append(QLatin1String("")); QDomDocument document; if (!document.setContent(responsesStr, true)) { setError(ERR_COLLECTIONFETCH); setErrorTextFromDavError(); subjobFinished(); return; } if (!error()) { /* * Extract information from a document like the following: * * * * /caldav.php/test1.user/home/ * * * * * * * * * * * * * * * Test1 User * * * * * * 12345 * * HTTP/1.1 200 OK * * * */ const QDomElement responsesElement = document.documentElement(); QDomElement responseElement = Utils::firstChildElementNS(responsesElement, QStringLiteral("DAV:"), QStringLiteral("response")); while (!responseElement.isNull()) { QDomElement propstatElement; // check for the valid propstat, without giving up on first error { const QDomNodeList propstats = responseElement.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("propstat")); for (int i = 0; i < propstats.length(); ++i) { const QDomElement propstatCandidate = propstats.item(i).toElement(); const QDomElement statusElement = Utils::firstChildElementNS(propstatCandidate, QStringLiteral("DAV:"), QStringLiteral("status")); if (statusElement.text().contains(QLatin1String("200"))) { propstatElement = propstatCandidate; } } } if (propstatElement.isNull()) { responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); continue; } // extract url const QDomElement hrefElement = Utils::firstChildElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("href")); if (hrefElement.isNull()) { responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); continue; } QString href = hrefElement.text(); if (!href.endsWith(QLatin1Char('/'))) { href.append(QLatin1Char('/')); } QUrl url = davJob->url(); url.setUserInfo(QString()); if (href.startsWith(QLatin1Char('/'))) { // href is only a path, use request url to complete url.setPath(href, QUrl::TolerantMode); } else { // href is a complete url url = QUrl::fromUserInput(href); } // don't add this resource if it has already been detected bool alreadySeen = false; for (const DavCollection &seen : qAsConst(d->mCollections)) { if (seen.url().toDisplayString() == url.toDisplayString()) { alreadySeen = true; } } if (alreadySeen) { responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); continue; } // extract display name const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); const QDomElement displaynameElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("displayname")); const QString displayName = displaynameElement.text(); // Extract CTag const QDomElement CTagElement = Utils::firstChildElementNS(propElement, QStringLiteral("http://calendarserver.org/ns/"), QStringLiteral("getctag")); QString CTag; if (!CTagElement.isNull()) { CTag = CTagElement.text(); } // extract calendar color if provided const QDomElement colorElement = Utils::firstChildElementNS(propElement, QStringLiteral("http://apple.com/ns/ical/"), QStringLiteral("calendar-color")); QColor color; if (!colorElement.isNull()) { QString colorValue = colorElement.text(); if (QColor::isValidColor(colorValue)) { // Color is either #RRGGBBAA or #RRGGBB but QColor expects #AARRGGBB // so we put the AA in front if the string's length is 9. if (colorValue.size() == 9) { QString fixedColorValue = QStringLiteral("#") + colorValue.mid(7, 2) + colorValue.mid(1, 6); color.setNamedColor(fixedColorValue); } else { color.setNamedColor(colorValue); } } } // extract allowed content types const DavCollection::ContentTypes contentTypes = DavManagerPrivate::davProtocol(d->mUrl.protocol())->collectionContentTypes(propstatElement); auto _url = url; _url.setUserInfo(d->mUrl.url().userInfo()); DavCollection collection(DavUrl(_url, d->mUrl.protocol()), displayName, contentTypes); collection.setCTag(CTag); if (color.isValid()) { collection.setColor(color); } // extract privileges const QDomElement currentPrivsElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("current-user-privilege-set")); if (currentPrivsElement.isNull()) { // Assume that we have all privileges collection.setPrivileges(KDAV::All); } else { Privileges privileges = Utils::extractPrivileges(currentPrivsElement); collection.setPrivileges(privileges); } qCDebug(KDAV_LOG) << url.toDisplayString() << "PRIVS: " << collection.privileges(); d->mCollections << collection; Q_EMIT collectionDiscovered(d->mUrl.protocol(), url.toDisplayString(), jobUrl); responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); } } } subjobFinished(); } void DavCollectionsFetchJob::subjobFinished() { Q_D(DavCollectionsFetchJob); if (--d->mSubJobCount == 0) { emitResult(); } } diff --git a/src/common/davitemsfetchjob.cpp b/src/common/davitemsfetchjob.cpp index 68d83fb..aa73835 100644 --- a/src/common/davitemsfetchjob.cpp +++ b/src/common/davitemsfetchjob.cpp @@ -1,179 +1,179 @@ /* Copyright (c) 2010 Grégory Oestreicher Based on DavItemsListJob which is copyright (c) 2010 Tobias Koenig This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "davitemsfetchjob.h" #include "davjobbase_p.h" #include "davmanager.h" #include "davmanager_p.h" -#include "davmultigetprotocol.h" +#include "davmultigetprotocol_p.h" #include "utils.h" #include "daverror.h" #include #include using namespace KDAV; namespace KDAV { class DavItemsFetchJobPrivate : public DavJobBasePrivate { public: DavUrl mCollectionUrl; QStringList mUrls; QMap mItems; }; } DavItemsFetchJob::DavItemsFetchJob(const DavUrl &collectionUrl, const QStringList &urls, QObject *parent) : DavJobBase(new DavItemsFetchJobPrivate, parent) { Q_D(DavItemsFetchJob); d->mCollectionUrl = collectionUrl; d->mUrls = urls; } void DavItemsFetchJob::start() { Q_D(DavItemsFetchJob); const DavMultigetProtocol *protocol = dynamic_cast(DavManagerPrivate::davProtocol(d->mCollectionUrl.protocol())); if (!protocol) { setError(ERR_NO_MULTIGET); setErrorTextFromDavError(); emitResult(); return; } const QDomDocument report = protocol->itemsReportQuery(d->mUrls)->buildQuery(); KIO::DavJob *job = DavManager::self()->createReportJob(d->mCollectionUrl.url(), report, QStringLiteral("0")); job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); connect(job, &KIO::DavJob::result, this, &DavItemsFetchJob::davJobFinished); } DavItem::List DavItemsFetchJob::items() const { Q_D(const DavItemsFetchJob); DavItem::List values; values.reserve(d->mItems.size()); for (const auto &value : qAsConst(d->mItems)) { values << value; } return values; } DavItem DavItemsFetchJob::item(const QString &url) const { Q_D(const DavItemsFetchJob); return d->mItems.value(url); } void DavItemsFetchJob::davJobFinished(KJob *job) { Q_D(DavItemsFetchJob); KIO::DavJob *davJob = qobject_cast(job); const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode")); const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx if (davJob->error() || (responseCode >= 400 && responseCode < 600)) { setLatestResponseCode(responseCode); setError(ERR_PROBLEM_WITH_REQUEST); setJobErrorText(davJob->errorText()); setJobError(davJob->error()); setErrorTextFromDavError(); emitResult(); return; } const DavMultigetProtocol *protocol = static_cast(DavManagerPrivate::davProtocol(d->mCollectionUrl.protocol())); const QDomDocument document = davJob->response(); const QDomElement documentElement = document.documentElement(); QDomElement responseElement = Utils::firstChildElementNS(documentElement, QStringLiteral("DAV:"), QStringLiteral("response")); while (!responseElement.isNull()) { QDomElement propstatElement = Utils::firstChildElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("propstat")); if (propstatElement.isNull()) { responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); continue; } // Check for errors const QDomElement statusElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("status")); if (!statusElement.text().contains(QLatin1String("200"))) { responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); continue; } const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); DavItem item; // extract path const QDomElement hrefElement = Utils::firstChildElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("href")); const QString href = hrefElement.text(); QUrl url = davJob->url(); if (href.startsWith(QLatin1Char('/'))) { // href is only a path, use request url to complete url.setPath(href, QUrl::TolerantMode); } else { // href is a complete url url = QUrl::fromUserInput(href); } auto _url = url; _url.setUserInfo(d->mCollectionUrl.url().userInfo()); item.setUrl(DavUrl(_url, d->mCollectionUrl.protocol())); // extract etag const QDomElement getetagElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("getetag")); item.setEtag(getetagElement.text()); // extract content const QDomElement dataElement = Utils::firstChildElementNS(propElement, protocol->responseNamespace(), protocol->dataTagName()); if (dataElement.isNull()) { responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); continue; } const QByteArray data = dataElement.firstChild().toText().data().toUtf8(); if (data.isEmpty()) { responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); continue; } item.setData(data); d->mItems.insert(item.url().toDisplayString(), item); responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); } emitResult(); } diff --git a/src/common/davitemslistjob.cpp b/src/common/davitemslistjob.cpp index d2b7796..b99660f 100644 --- a/src/common/davitemslistjob.cpp +++ b/src/common/davitemslistjob.cpp @@ -1,266 +1,266 @@ /* Copyright (c) 2010 Tobias Koenig This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "davitemslistjob.h" #include "davjobbase_p.h" #include "daverror.h" #include "davmanager.h" #include "davmanager_p.h" -#include "davprotocolbase.h" +#include "davprotocolbase_p.h" #include "davurl.h" #include "utils.h" #include "etagcache.h" #include #include using namespace KDAV; namespace KDAV { class DavItemsListJobPrivate : public DavJobBasePrivate { public: DavUrl mUrl; std::shared_ptr mEtagCache; QStringList mMimeTypes; QString mRangeStart; QString mRangeEnd; DavItem::List mItems; QSet mSeenUrls; // to prevent events duplication with some servers DavItem::List mChangedItems; QStringList mDeletedItems; uint mSubJobCount = 0; }; } DavItemsListJob::DavItemsListJob(const DavUrl &url, const std::shared_ptr &cache, QObject *parent) : DavJobBase(new DavItemsListJobPrivate, parent) { Q_D(DavItemsListJob); d->mUrl = url; d->mEtagCache = cache; } DavItemsListJob::~DavItemsListJob() = default; void DavItemsListJob::setContentMimeTypes(const QStringList &types) { Q_D(DavItemsListJob); d->mMimeTypes = types; } void DavItemsListJob::setTimeRange(const QString &start, const QString &end) { Q_D(DavItemsListJob); d->mRangeStart = start; d->mRangeEnd = end; } void DavItemsListJob::start() { Q_D(DavItemsListJob); const DavProtocolBase *protocol = DavManagerPrivate::davProtocol(d->mUrl.protocol()); Q_ASSERT(protocol); QVectorIterator it(protocol->itemsQueries()); while (it.hasNext()) { XMLQueryBuilder::Ptr builder = it.next(); if (!d->mRangeStart.isEmpty()) { builder->setParameter(QStringLiteral("start"), d->mRangeStart); } if (!d->mRangeEnd.isEmpty()) { builder->setParameter(QStringLiteral("end"), d->mRangeEnd); } const QDomDocument props = builder->buildQuery(); const QString mimeType = builder->mimeType(); if (d->mMimeTypes.isEmpty() || d->mMimeTypes.contains(mimeType)) { ++d->mSubJobCount; if (protocol->useReport()) { KIO::DavJob *job = DavManager::self()->createReportJob(d->mUrl.url(), props); job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); job->setProperty("davType", QStringLiteral("report")); job->setProperty("itemsMimeType", mimeType); connect(job, &KIO::DavJob::result, this, &DavItemsListJob::davJobFinished); } else { KIO::DavJob *job = DavManager::self()->createPropFindJob(d->mUrl.url(), props); job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); job->setProperty("davType", QStringLiteral("propFind")); job->setProperty("itemsMimeType", mimeType); connect(job, &KIO::DavJob::result, this, &DavItemsListJob::davJobFinished); } } } if (d->mSubJobCount == 0) { setError(ERR_ITEMLIST_NOMIMETYPE); setErrorTextFromDavError(); emitResult(); } } DavItem::List DavItemsListJob::items() const { Q_D(const DavItemsListJob); return d->mItems; } DavItem::List DavItemsListJob::changedItems() const { Q_D(const DavItemsListJob); return d->mChangedItems; } QStringList DavItemsListJob::deletedItems() const { Q_D(const DavItemsListJob); return d->mDeletedItems; } void DavItemsListJob::davJobFinished(KJob *job) { Q_D(DavItemsListJob); KIO::DavJob *davJob = qobject_cast(job); const int responseCode = davJob->queryMetaData(QStringLiteral("responsecode")).isEmpty() ? 0 : davJob->queryMetaData(QStringLiteral("responsecode")).toInt(); // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx if (davJob->error() || (responseCode >= 400 && responseCode < 600)) { setLatestResponseCode(responseCode); setError(ERR_PROBLEM_WITH_REQUEST); setJobErrorText(davJob->errorText()); setJobError(davJob->error()); setErrorTextFromDavError(); } else { /* * Extract data from a document like the following: * * * * /caldav.php/test1.user/home/KOrganizer-166749289.780.ics * * * "b4bbea0278f4f63854c4167a7656024a" * * HTTP/1.1 200 OK * * * * /caldav.php/test1.user/home/KOrganizer-399416366.464.ics * * * "52eb129018398a7da4f435b2bc4c6cd5" * * HTTP/1.1 200 OK * * * */ const QString itemsMimeType = job->property("itemsMimeType").toString(); const QDomDocument document = davJob->response(); const QDomElement documentElement = document.documentElement(); QDomElement responseElement = Utils::firstChildElementNS(documentElement, QStringLiteral("DAV:"), QStringLiteral("response")); while (!responseElement.isNull()) { QDomElement propstatElement; // check for the valid propstat, without giving up on first error { const QDomNodeList propstats = responseElement.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("propstat")); for (int i = 0; i < propstats.length(); ++i) { const QDomElement propstatCandidate = propstats.item(i).toElement(); const QDomElement statusElement = Utils::firstChildElementNS(propstatCandidate, QStringLiteral("DAV:"), QStringLiteral("status")); if (statusElement.text().contains(QLatin1String("200"))) { propstatElement = propstatCandidate; } } } if (propstatElement.isNull()) { responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); continue; } const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); // check whether it is a dav collection ... const QDomElement resourcetypeElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("resourcetype")); if (!responseElement.isNull()) { const QDomElement collectionElement = Utils::firstChildElementNS(resourcetypeElement, QStringLiteral("DAV:"), QStringLiteral("collection")); if (!collectionElement.isNull()) { responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); continue; } } // ... if not it is an item DavItem item; item.setContentType(itemsMimeType); // extract path const QDomElement hrefElement = Utils::firstChildElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("href")); const QString href = hrefElement.text(); QUrl url = davJob->url(); url.setUserInfo(QString()); if (href.startsWith(QLatin1Char('/'))) { // href is only a path, use request url to complete url.setPath(href, QUrl::TolerantMode); } else { // href is a complete url url = QUrl::fromUserInput(href); } QString itemUrl = url.toDisplayString(); if (d->mSeenUrls.contains(itemUrl)) { responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); continue; } d->mSeenUrls << itemUrl; auto _url = url; _url.setUserInfo(d->mUrl.url().userInfo()); item.setUrl(DavUrl(_url, d->mUrl.protocol())); // extract etag const QDomElement getetagElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("getetag")); item.setEtag(getetagElement.text()); d->mItems << item; if (d->mEtagCache->etagChanged(itemUrl, item.etag())) { d->mChangedItems << item; } responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); } } QSet removed = d->mEtagCache->urls().toSet(); removed.subtract(d->mSeenUrls); d->mDeletedItems = removed.toList(); if (--d->mSubJobCount == 0) { emitResult(); } } diff --git a/src/common/davmanager.cpp b/src/common/davmanager.cpp index eb5c2db..cd3f540 100644 --- a/src/common/davmanager.cpp +++ b/src/common/davmanager.cpp @@ -1,107 +1,107 @@ /* Copyright (c) 2010 Tobias Koenig This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "davmanager.h" #include "davmanager_p.h" -#include "protocols/caldavprotocol.h" -#include "protocols/carddavprotocol.h" -#include "protocols/groupdavprotocol.h" +#include "protocols/caldavprotocol_p.h" +#include "protocols/carddavprotocol_p.h" +#include "protocols/groupdavprotocol_p.h" #include #include "libkdav_debug.h" #include #include using namespace KDAV; DavManager::DavManager() : d(new DavManagerPrivate) { } DavManager::~DavManager() = default; DavManager *DavManager::self() { static DavManager sSelf; return &sSelf; } KIO::DavJob *DavManager::createPropFindJob(const QUrl &url, const QDomDocument &document, const QString &depth) const { KIO::DavJob *job = KIO::davPropFind(url, document, depth, KIO::HideProgressInfo | KIO::DefaultFlags); // workaround needed, Depth: header doesn't seem to be correctly added const QString header = QLatin1String("Content-Type: text/xml\r\nDepth: ") + depth; job->addMetaData(QStringLiteral("customHTTPHeader"), header); job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); job->setProperty("extraDavDepth", QVariant::fromValue(depth)); return job; } KIO::DavJob *DavManager::createReportJob(const QUrl &url, const QDomDocument &document, const QString &depth) const { KIO::DavJob *job = KIO::davReport(url, document.toString(), depth, KIO::HideProgressInfo | KIO::DefaultFlags); // workaround needed, Depth: header doesn't seem to be correctly added const QString header = QLatin1String("Content-Type: text/xml\r\nDepth: ") + depth; job->addMetaData(QStringLiteral("customHTTPHeader"), header); job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); job->setProperty("extraDavDepth", QVariant::fromValue(depth)); return job; } KIO::DavJob *DavManager::createPropPatchJob(const QUrl &url, const QDomDocument &document) const { KIO::DavJob *job = KIO::davPropPatch(url, document, KIO::HideProgressInfo | KIO::DefaultFlags); const QString header = QStringLiteral("Content-Type: text/xml"); job->addMetaData(QStringLiteral("customHTTPHeader"), header); job->addMetaData(QStringLiteral("cookies"), QStringLiteral("none")); job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); return job; } const DavProtocolBase *DavManagerPrivate::davProtocol(Protocol protocol) { const auto d = DavManagerPrivate::get(DavManager::self()); if (!d->mProtocols[protocol]) { switch (protocol) { case KDAV::CalDav: d->mProtocols[KDAV::CalDav].reset(new CaldavProtocol()); break; case KDAV::CardDav: d->mProtocols[KDAV::CardDav].reset(new CarddavProtocol()); break; case KDAV::GroupDav: d->mProtocols[KDAV::GroupDav].reset(new GroupdavProtocol()); break; default: qCCritical(KDAV_LOG) << "Unknown protocol: " << static_cast(protocol); return nullptr; } } return d->mProtocols[protocol].get(); } diff --git a/src/common/davmultigetprotocol.cpp b/src/common/davmultigetprotocol.cpp index 0704b5d..beaf771 100644 --- a/src/common/davmultigetprotocol.cpp +++ b/src/common/davmultigetprotocol.cpp @@ -1,25 +1,25 @@ /* Copyright (c) 2010 Grégory Oestreicher This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "davmultigetprotocol.h" +#include "davmultigetprotocol_p.h" using namespace KDAV; DavMultigetProtocol::~DavMultigetProtocol() { } diff --git a/src/common/davmultigetprotocol.h b/src/common/davmultigetprotocol_p.h similarity index 98% rename from src/common/davmultigetprotocol.h rename to src/common/davmultigetprotocol_p.h index ad8caa5..429572e 100644 --- a/src/common/davmultigetprotocol.h +++ b/src/common/davmultigetprotocol_p.h @@ -1,56 +1,56 @@ /* Copyright (c) 2010 Grégory Oestreicher This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDAV_DAVMULTIGETPROTOCOL_H #define KDAV_DAVMULTIGETPROTOCOL_H #include "kpimkdav_export.h" -#include "davprotocolbase.h" +#include "davprotocolbase_p.h" namespace KDAV { /** * @short Base class for protocols that implement multiget capabilities */ class DavMultigetProtocol : public DavProtocolBase { public: /** * Destroys the DAV protocol */ virtual ~DavMultigetProtocol(); /** * Returns the XML document that represents a MULTIGET DAV query to * list all DAV resources with the given @p urls. */ virtual XMLQueryBuilder::Ptr itemsReportQuery(const QStringList &urls) const = 0; /** * Returns the namespace used by protocol-specific elements found in responses. */ virtual QString responseNamespace() const = 0; /** * Returns the tag name of data elements found in responses. */ virtual QString dataTagName() const = 0; }; } #endif diff --git a/src/common/davprincipalhomesetsfetchjob.cpp b/src/common/davprincipalhomesetsfetchjob.cpp index 782edd9..43c100c 100644 --- a/src/common/davprincipalhomesetsfetchjob.cpp +++ b/src/common/davprincipalhomesetsfetchjob.cpp @@ -1,243 +1,243 @@ /* Copyright (c) 2010 Grégory Oestreicher This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "davprincipalhomesetsfetchjob.h" #include "davjobbase_p.h" #include "davmanager.h" -#include "davprotocolbase.h" +#include "davprotocolbase_p.h" #include "daverror.h" #include "protocolinfo.h" #include "utils.h" #include #include using namespace KDAV; namespace KDAV { class DavPrincipalHomeSetsFetchJobPrivate : public DavJobBasePrivate { public: DavUrl mUrl; QStringList mHomeSets; }; } DavPrincipalHomeSetsFetchJob::DavPrincipalHomeSetsFetchJob(const DavUrl &url, QObject *parent) : DavJobBase(new DavPrincipalHomeSetsFetchJobPrivate, parent) { Q_D(DavPrincipalHomeSetsFetchJob); d->mUrl = url; } void DavPrincipalHomeSetsFetchJob::start() { fetchHomeSets(false); } void DavPrincipalHomeSetsFetchJob::fetchHomeSets(bool homeSetsOnly) { Q_D(DavPrincipalHomeSetsFetchJob); QDomDocument document; QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind")); document.appendChild(propfindElement); QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); propfindElement.appendChild(propElement); const QString homeSet = ProtocolInfo::principalHomeSet(d->mUrl.protocol()); const QString homeSetNS = ProtocolInfo::principalHomeSetNS(d->mUrl.protocol()); propElement.appendChild(document.createElementNS(homeSetNS, homeSet)); if (!homeSetsOnly) { propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("current-user-principal"))); propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("principal-URL"))); } KIO::DavJob *job = DavManager::self()->createPropFindJob(d->mUrl.url(), document, QStringLiteral("0")); job->addMetaData(QStringLiteral("PropagateHttpHeader"), QStringLiteral("true")); connect(job, &KIO::DavJob::result, this, &DavPrincipalHomeSetsFetchJob::davJobFinished); } QStringList DavPrincipalHomeSetsFetchJob::homeSets() const { Q_D(const DavPrincipalHomeSetsFetchJob); return d->mHomeSets; } void DavPrincipalHomeSetsFetchJob::davJobFinished(KJob *job) { Q_D(DavPrincipalHomeSetsFetchJob); KIO::DavJob *davJob = qobject_cast(job); const QString responseCodeStr = davJob->queryMetaData(QStringLiteral("responsecode")); const int responseCode = responseCodeStr.isEmpty() ? 0 : responseCodeStr.toInt(); // KIO::DavJob does not set error() even if the HTTP status code is a 4xx or a 5xx if (davJob->error() || (responseCode >= 400 && responseCode < 600)) { QString err; if (davJob->error() && davJob->error() != KIO::ERR_SLAVE_DEFINED) { err = KIO::buildErrorString(davJob->error(), davJob->errorText()); } else { err = davJob->errorText(); } setLatestResponseCode(responseCode); setError(ERR_PROBLEM_WITH_REQUEST); setJobErrorText(davJob->errorText()); setJobError(davJob->error()); setErrorTextFromDavError(); emitResult(); return; } /* * Extract information from a document like the following (if no homeset is defined) : * * * * /dav/ * * HTTP/1.1 200 OK * * * /principals/users/gdacoin/ * * * * * HTTP/1.1 404 Not Found * * * * * * * * * Or like this (if the homeset is defined): * * * * * /principals/users/greg%40kamago.net/ * * * * /greg%40kamago.net/ * * * HTTP/1.1 200 OK * * * */ const QString homeSet = ProtocolInfo::principalHomeSet(d->mUrl.protocol()); const QString homeSetNS = ProtocolInfo::principalHomeSetNS(d->mUrl.protocol()); QString nextRoundHref; // The content of the href element that will be used if no homeset was found. // This is either given by current-user-principal or by principal-URL. const QDomDocument document = davJob->response(); const QDomElement multistatusElement = document.documentElement(); QDomElement responseElement = Utils::firstChildElementNS(multistatusElement, QStringLiteral("DAV:"), QStringLiteral("response")); while (!responseElement.isNull()) { QDomElement propstatElement; // check for the valid propstat, without giving up on first error { const QDomNodeList propstats = responseElement.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("propstat")); for (int i = 0; i < propstats.length(); ++i) { const QDomElement propstatCandidate = propstats.item(i).toElement(); const QDomElement statusElement = Utils::firstChildElementNS(propstatCandidate, QStringLiteral("DAV:"), QStringLiteral("status")); if (statusElement.text().contains(QLatin1String("200"))) { propstatElement = propstatCandidate; } } } if (propstatElement.isNull()) { responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); continue; } // extract home sets const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); const QDomElement homeSetElement = Utils::firstChildElementNS(propElement, homeSetNS, homeSet); if (!homeSetElement.isNull()) { QDomElement hrefElement = Utils::firstChildElementNS(homeSetElement, QStringLiteral("DAV:"), QStringLiteral("href")); while (!hrefElement.isNull()) { const QString href = hrefElement.text(); if (!d->mHomeSets.contains(href)) { d->mHomeSets << href; } hrefElement = Utils::nextSiblingElementNS(hrefElement, QStringLiteral("DAV:"), QStringLiteral("href")); } } else { // Trying to get the principal url, given either by current-user-principal or principal-URL QDomElement urlHolder = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("current-user-principal")); if (urlHolder.isNull()) { urlHolder = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("principal-URL")); } if (!urlHolder.isNull()) { // Getting the href that will be used for the next round QDomElement hrefElement = Utils::firstChildElementNS(urlHolder, QStringLiteral("DAV:"), QStringLiteral("href")); if (!hrefElement.isNull()) { nextRoundHref = hrefElement.text(); } } } responseElement = Utils::nextSiblingElementNS(responseElement, QStringLiteral("DAV:"), QStringLiteral("response")); } /* * Now either we got one or more homesets, or we got an href for the next round * or nothing can be found by this job. * If we have homesets, we're done here and can notify the caller. * Else we must ensure that we have an href for the next round. */ if (!d->mHomeSets.isEmpty() || nextRoundHref.isEmpty()) { emitResult(); } else { QUrl nextRoundUrl(d->mUrl.url()); if (nextRoundHref.startsWith(QLatin1Char('/'))) { // nextRoundHref is only a path, use request url to complete nextRoundUrl.setPath(nextRoundHref, QUrl::TolerantMode); } else { // href is a complete url nextRoundUrl = QUrl::fromUserInput(nextRoundHref); nextRoundUrl.setUserName(d->mUrl.url().userName()); nextRoundUrl.setPassword(d->mUrl.url().password()); } d->mUrl.setUrl(nextRoundUrl); // And one more round, fetching only homesets fetchHomeSets(true); } } diff --git a/src/common/davprotocolbase.cpp b/src/common/davprotocolbase.cpp index fdee204..352bb6c 100644 --- a/src/common/davprotocolbase.cpp +++ b/src/common/davprotocolbase.cpp @@ -1,55 +1,55 @@ /* Copyright (c) 2009 Grégory Oestreicher This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "davprotocolbase.h" +#include "davprotocolbase_p.h" #include using namespace KDAV; XMLQueryBuilder::~XMLQueryBuilder() { } void XMLQueryBuilder::setParameter(const QString &key, const QVariant &value) { mParameters[key] = value; } QVariant XMLQueryBuilder::parameter(const QString &key) const { QVariant ret; if (mParameters.contains(key)) { ret = mParameters.value(key); } return ret; } DavProtocolBase::~DavProtocolBase() { } QString DavProtocolBase::principalHomeSet() const { return QString(); } QString DavProtocolBase::principalHomeSetNS() const { return QString(); } diff --git a/src/common/davprotocolbase.h b/src/common/davprotocolbase_p.h similarity index 100% rename from src/common/davprotocolbase.h rename to src/common/davprotocolbase_p.h diff --git a/src/common/protocolinfo.cpp b/src/common/protocolinfo.cpp index cae3ea8..9750796 100644 --- a/src/common/protocolinfo.cpp +++ b/src/common/protocolinfo.cpp @@ -1,37 +1,37 @@ /* Copyright (c) 2019 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "protocolinfo.h" #include "davmanager_p.h" -#include "davprotocolbase.h" +#include "davprotocolbase_p.h" using namespace KDAV; bool ProtocolInfo::useMultiget(KDAV::Protocol protocol) { return DavManagerPrivate::davProtocol(protocol)->useMultiget(); } QString ProtocolInfo::principalHomeSet(KDAV::Protocol protocol) { return DavManagerPrivate::davProtocol(protocol)->principalHomeSet(); } QString ProtocolInfo::principalHomeSetNS(KDAV::Protocol protocol) { return DavManagerPrivate::davProtocol(protocol)->principalHomeSetNS(); } diff --git a/src/common/utils.cpp b/src/common/utils.cpp index 5daa284..f9ac063 100644 --- a/src/common/utils.cpp +++ b/src/common/utils.cpp @@ -1,180 +1,180 @@ /* Copyright (c) 2010 Tobias Koenig This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "utils.h" #include "enums.h" #include "davitem.h" #include "davmanager.h" -#include "davprotocolbase.h" +#include "davprotocolbase_p.h" #include #include #include "libkdav_debug.h" using namespace KDAV; QDomElement Utils::firstChildElementNS(const QDomElement &parent, const QString &namespaceUri, const QString &tagName) { for (QDomNode child = parent.firstChild(); !child.isNull(); child = child.nextSibling()) { if (child.isElement()) { const QDomElement elt = child.toElement(); if (tagName.isEmpty() || (elt.tagName() == tagName && elt.namespaceURI() == namespaceUri)) { return elt; } } } return QDomElement(); } QDomElement Utils::nextSiblingElementNS(const QDomElement &element, const QString &namespaceUri, const QString &tagName) { for (QDomNode sib = element.nextSibling(); !sib.isNull(); sib = sib.nextSibling()) { if (sib.isElement()) { const QDomElement elt = sib.toElement(); if (tagName.isEmpty() || (elt.tagName() == tagName && elt.namespaceURI() == namespaceUri)) { return elt; } } } return QDomElement(); } Privileges Utils::extractPrivileges(const QDomElement &element) { Privileges final = None; QDomElement privElement = firstChildElementNS(element, QStringLiteral("DAV:"), QStringLiteral("privilege")); while (!privElement.isNull()) { QDomElement child = privElement.firstChildElement(); while (!child.isNull()) { final |= parsePrivilege(child); child = child.nextSiblingElement(); } privElement = Utils::nextSiblingElementNS(privElement, QStringLiteral("DAV:"), QStringLiteral("privilege")); } return final; } Privileges Utils::parsePrivilege(const QDomElement &element) { Privileges final = None; if (!element.childNodes().isEmpty()) { // This is an aggregate privilege, parse each of its children QDomElement child = element.firstChildElement(); while (!child.isNull()) { final |= parsePrivilege(child); child = child.nextSiblingElement(); } } else { // This is a normal privilege const QString privname = element.localName(); if (privname == QLatin1String("read")) { final |= KDAV::Read; } else if (privname == QLatin1String("write")) { final |= KDAV::Write; } else if (privname == QLatin1String("write-properties")) { final |= KDAV::WriteProperties; } else if (privname == QLatin1String("write-content")) { final |= KDAV::WriteContent; } else if (privname == QLatin1String("unlock")) { final |= KDAV::Unlock; } else if (privname == QLatin1String("read-acl")) { final |= KDAV::ReadAcl; } else if (privname == QLatin1String("read-current-user-privilege-set")) { final |= KDAV::ReadCurrentUserPrivilegeSet; } else if (privname == QLatin1String("write-acl")) { final |= KDAV::WriteAcl; } else if (privname == QLatin1String("bind")) { final |= KDAV::Bind; } else if (privname == QLatin1String("unbind")) { final |= KDAV::Unbind; } else if (privname == QLatin1String("all")) { final |= KDAV::All; } } return final; } QLatin1String Utils::protocolName(Protocol protocol) { QLatin1String protocolName(""); switch (protocol) { case KDAV::CalDav: protocolName = QLatin1String("CalDav"); break; case KDAV::CardDav: protocolName = QLatin1String("CardDav"); break; case KDAV::GroupDav: protocolName = QLatin1String("GroupDav"); break; } return protocolName; } Protocol Utils::protocolByName(const QString &name) { Protocol protocol = KDAV::CalDav; if (name == QLatin1String("CalDav")) { protocol = KDAV::CalDav; } else if (name == QLatin1String("CardDav")) { protocol = KDAV::CardDav; } else if (name == QLatin1String("GroupDav")) { protocol = KDAV::GroupDav; } else { qCCritical(KDAV_LOG) << "Unexpected protocol name : " << name; } return protocol; } QString Utils::createUniqueId() { const qint64 time = QDateTime::currentMSecsSinceEpoch() / 1000; const int r = qrand() % 1000; const QString id = QLatin1Char('R') + QString::number(r); const QString uid = QString::number(time) + QLatin1Char('.') + id; return uid; } QString Utils::contactsMimeType(Protocol protocol) { QString ret; if (protocol == KDAV::CardDav) { ret = QStringLiteral("text/vcard"); } else if (protocol == KDAV::GroupDav) { ret = QStringLiteral("text/x-vcard"); } return ret; } diff --git a/src/protocols/caldavprotocol.cpp b/src/protocols/caldavprotocol.cpp index 0c0c222..f7e8087 100644 --- a/src/protocols/caldavprotocol.cpp +++ b/src/protocols/caldavprotocol.cpp @@ -1,422 +1,422 @@ /* Copyright (c) 2009 Grégory Oestreicher This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "caldavprotocol.h" +#include "caldavprotocol_p.h" #include "common/utils.h" #include #include #include using namespace KDAV; class CaldavCollectionQueryBuilder : public XMLQueryBuilder { public: QDomDocument buildQuery() const override { QDomDocument document; QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind")); document.appendChild(propfindElement); QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); propfindElement.appendChild(propElement); propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("displayname"))); propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype"))); propElement.appendChild(document.createElementNS(QStringLiteral("http://apple.com/ns/ical/"), QStringLiteral("calendar-color"))); propElement.appendChild(document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("supported-calendar-component-set"))); propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("current-user-privilege-set"))); propElement.appendChild(document.createElementNS(QStringLiteral("http://calendarserver.org/ns/"), QStringLiteral("getctag"))); return document; } QString mimeType() const override { return QString(); } }; class CaldavListEventQueryBuilder : public XMLQueryBuilder { public: QDomDocument buildQuery() const override { QString startTime = parameter(QStringLiteral("start")).toString(); QString endTime = parameter(QStringLiteral("end")).toString(); QDomDocument document; QDomElement queryElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("calendar-query")); document.appendChild(queryElement); QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); queryElement.appendChild(propElement); QDomElement getetagElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("getetag")); propElement.appendChild(getetagElement); QDomElement getRTypeElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype")); propElement.appendChild(getRTypeElement); QDomElement filterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("filter")); queryElement.appendChild(filterElement); QDomElement compfilterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp-filter")); QDomAttr nameAttribute = document.createAttribute(QStringLiteral("name")); nameAttribute.setValue(QStringLiteral("VCALENDAR")); compfilterElement.setAttributeNode(nameAttribute); filterElement.appendChild(compfilterElement); QDomElement subcompfilterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp-filter")); nameAttribute = document.createAttribute(QStringLiteral("name")); nameAttribute.setValue(QStringLiteral("VEVENT")); subcompfilterElement.setAttributeNode(nameAttribute); if (!startTime.isEmpty() || !endTime.isEmpty()) { QDomElement timeRangeElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("time-range")); if (!startTime.isEmpty()) { QDomAttr startAttribute = document.createAttribute(QStringLiteral("start")); startAttribute.setValue(startTime); timeRangeElement.setAttributeNode(startAttribute); } if (!endTime.isEmpty()) { QDomAttr endAttribute = document.createAttribute(QStringLiteral("end")); endAttribute.setValue(endTime); timeRangeElement.setAttributeNode(endAttribute); } subcompfilterElement.appendChild(timeRangeElement); } compfilterElement.appendChild(subcompfilterElement); return document; } QString mimeType() const override { return QStringLiteral("application/x-vnd.akonadi.calendar.event"); } }; class CaldavListTodoQueryBuilder : public XMLQueryBuilder { public: QDomDocument buildQuery() const override { QString startTime = parameter(QStringLiteral("start")).toString(); QString endTime = parameter(QStringLiteral("end")).toString(); QDomDocument document; QDomElement queryElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("calendar-query")); document.appendChild(queryElement); QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); queryElement.appendChild(propElement); QDomElement getetagElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("getetag")); propElement.appendChild(getetagElement); QDomElement getRTypeElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype")); propElement.appendChild(getRTypeElement); QDomElement filterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("filter")); queryElement.appendChild(filterElement); QDomElement compfilterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp-filter")); QDomAttr nameAttribute = document.createAttribute(QStringLiteral("name")); nameAttribute.setValue(QStringLiteral("VCALENDAR")); compfilterElement.setAttributeNode(nameAttribute); filterElement.appendChild(compfilterElement); QDomElement subcompfilterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp-filter")); nameAttribute = document.createAttribute(QStringLiteral("name")); nameAttribute.setValue(QStringLiteral("VTODO")); subcompfilterElement.setAttributeNode(nameAttribute); if (!startTime.isEmpty() || !endTime.isEmpty()) { QDomElement timeRangeElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("time-range")); if (!startTime.isEmpty()) { QDomAttr startAttribute = document.createAttribute(QStringLiteral("start")); startAttribute.setValue(startTime); timeRangeElement.setAttributeNode(startAttribute); } if (!endTime.isEmpty()) { QDomAttr endAttribute = document.createAttribute(QStringLiteral("end")); endAttribute.setValue(endTime); timeRangeElement.setAttributeNode(endAttribute); } subcompfilterElement.appendChild(timeRangeElement); } compfilterElement.appendChild(subcompfilterElement); return document; } QString mimeType() const override { return QStringLiteral("application/x-vnd.akonadi.calendar.todo"); } }; class CaldavListJournalQueryBuilder : public XMLQueryBuilder { public: QDomDocument buildQuery() const override { QString startTime = parameter(QStringLiteral("start")).toString(); QString endTime = parameter(QStringLiteral("end")).toString(); QDomDocument document; QDomElement queryElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("calendar-query")); document.appendChild(queryElement); QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); queryElement.appendChild(propElement); QDomElement getetagElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("getetag")); propElement.appendChild(getetagElement); QDomElement getRTypeElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype")); propElement.appendChild(getRTypeElement); QDomElement filterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("filter")); queryElement.appendChild(filterElement); QDomElement compfilterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp-filter")); QDomAttr nameAttribute = document.createAttribute(QStringLiteral("name")); nameAttribute.setValue(QStringLiteral("VCALENDAR")); compfilterElement.setAttributeNode(nameAttribute); filterElement.appendChild(compfilterElement); QDomElement subcompfilterElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp-filter")); nameAttribute = document.createAttribute(QStringLiteral("name")); nameAttribute.setValue(QStringLiteral("VJOURNAL")); subcompfilterElement.setAttributeNode(nameAttribute); if (!startTime.isEmpty() || !endTime.isEmpty()) { QDomElement timeRangeElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("time-range")); if (!startTime.isEmpty()) { QDomAttr startAttribute = document.createAttribute(QStringLiteral("start")); startAttribute.setValue(startTime); timeRangeElement.setAttributeNode(startAttribute); } if (!endTime.isEmpty()) { QDomAttr endAttribute = document.createAttribute(QStringLiteral("end")); endAttribute.setValue(endTime); timeRangeElement.setAttributeNode(endAttribute); } subcompfilterElement.appendChild(timeRangeElement); } compfilterElement.appendChild(subcompfilterElement); return document; } QString mimeType() const override { return QStringLiteral("application/x-vnd.akonadi.calendar.journal"); } }; class CaldavMultigetQueryBuilder : public XMLQueryBuilder { public: QDomDocument buildQuery() const override { QDomDocument document; const QStringList urls = parameter(QStringLiteral("urls")).toStringList(); if (urls.isEmpty()) { return document; } QDomElement multigetElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("calendar-multiget")); document.appendChild(multigetElement); QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); multigetElement.appendChild(propElement); propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("getetag"))); propElement.appendChild(document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("calendar-data"))); for (const QString &url : urls) { QDomElement hrefElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("href")); const QUrl pathUrl = QUrl::fromUserInput(url); const QDomText textNode = document.createTextNode(pathUrl.toString()); hrefElement.appendChild(textNode); multigetElement.appendChild(hrefElement); } return document; } QString mimeType() const override { return QString(); } }; CaldavProtocol::CaldavProtocol() { } bool CaldavProtocol::supportsPrincipals() const { return true; } bool CaldavProtocol::useReport() const { return true; } bool CaldavProtocol::useMultiget() const { return true; } QString CaldavProtocol::principalHomeSet() const { return QStringLiteral("calendar-home-set"); } QString CaldavProtocol::principalHomeSetNS() const { return QStringLiteral("urn:ietf:params:xml:ns:caldav"); } XMLQueryBuilder::Ptr CaldavProtocol::collectionsQuery() const { return XMLQueryBuilder::Ptr(new CaldavCollectionQueryBuilder()); } QString CaldavProtocol::collectionsXQuery() const { //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:']" ); 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:']")); return query; } QVector CaldavProtocol::itemsQueries() const { QVector ret; ret << XMLQueryBuilder::Ptr(new CaldavListEventQueryBuilder()); ret << XMLQueryBuilder::Ptr(new CaldavListTodoQueryBuilder()); ret << XMLQueryBuilder::Ptr(new CaldavListJournalQueryBuilder()); return ret; } XMLQueryBuilder::Ptr CaldavProtocol::itemsReportQuery(const QStringList &urls) const { XMLQueryBuilder::Ptr ret(new CaldavMultigetQueryBuilder()); ret->setParameter(QStringLiteral("urls"), urls); return ret; } QString CaldavProtocol::responseNamespace() const { return QStringLiteral("urn:ietf:params:xml:ns:caldav"); } QString CaldavProtocol::dataTagName() const { return QStringLiteral("calendar-data"); } DavCollection::ContentTypes CaldavProtocol::collectionContentTypes(const QDomElement &propstatElement) const { /* * Extract the content type information from a propstat like the following * * * * * * * * * * * * * * * Test1 User * * HTTP/1.1 200 OK * */ const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); const QDomElement supportedcomponentElement = Utils::firstChildElementNS(propElement, QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("supported-calendar-component-set")); DavCollection::ContentTypes contentTypes; QDomElement compElement = Utils::firstChildElementNS(supportedcomponentElement, QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp")); /* * Assign the content-type if the server didn't return anything. * According to RFC4791, §5.2.3: * In the absence of this property, the server MUST accept all * component types, and the client can assume that all component * types are accepted. */ if (compElement.isNull()) { contentTypes |= DavCollection::Calendar; contentTypes |= DavCollection::Events; contentTypes |= DavCollection::Todos; contentTypes |= DavCollection::FreeBusy; contentTypes |= DavCollection::Journal; } while (!compElement.isNull()) { const QString type = compElement.attribute(QStringLiteral("name")).toLower(); if (type == QLatin1String("vcalendar")) { contentTypes |= DavCollection::Calendar; } else if (type == QLatin1String("vevent")) { contentTypes |= DavCollection::Events; } else if (type == QLatin1String("vtodo")) { contentTypes |= DavCollection::Todos; } else if (type == QLatin1String("vfreebusy")) { contentTypes |= DavCollection::FreeBusy; } else if (type == QLatin1String("vjournal")) { contentTypes |= DavCollection::Journal; } compElement = Utils::nextSiblingElementNS(compElement, QStringLiteral("urn:ietf:params:xml:ns:caldav"), QStringLiteral("comp")); } return contentTypes; } diff --git a/src/protocols/caldavprotocol.h b/src/protocols/caldavprotocol_p.h similarity index 97% rename from src/protocols/caldavprotocol.h rename to src/protocols/caldavprotocol_p.h index 7fda826..25da727 100644 --- a/src/protocols/caldavprotocol.h +++ b/src/protocols/caldavprotocol_p.h @@ -1,43 +1,43 @@ /* Copyright (c) 2009 Grégory Oestreicher This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDAV_CALDAVPROTOCOL_H #define KDAV_CALDAVPROTOCOL_H -#include "common/davmultigetprotocol.h" +#include "common/davmultigetprotocol_p.h" class CaldavProtocol : public KDAV::DavMultigetProtocol { public: CaldavProtocol(); Q_REQUIRED_RESULT bool supportsPrincipals() const override; Q_REQUIRED_RESULT bool useReport() const override; Q_REQUIRED_RESULT bool useMultiget() const override; Q_REQUIRED_RESULT QString principalHomeSet() const override; Q_REQUIRED_RESULT QString principalHomeSetNS() const override; Q_REQUIRED_RESULT KDAV::XMLQueryBuilder::Ptr collectionsQuery() const override; Q_REQUIRED_RESULT QString collectionsXQuery() const override; Q_REQUIRED_RESULT QVector itemsQueries() const override; Q_REQUIRED_RESULT KDAV::XMLQueryBuilder::Ptr itemsReportQuery(const QStringList &urls) const override; Q_REQUIRED_RESULT QString responseNamespace() const override; Q_REQUIRED_RESULT QString dataTagName() const override; Q_REQUIRED_RESULT KDAV::DavCollection::ContentTypes collectionContentTypes(const QDomElement &propstat) const override; }; #endif diff --git a/src/protocols/carddavprotocol.cpp b/src/protocols/carddavprotocol.cpp index 9449ace..6de4751 100644 --- a/src/protocols/carddavprotocol.cpp +++ b/src/protocols/carddavprotocol.cpp @@ -1,187 +1,187 @@ /* Copyright (c) 2010 Tobias Koenig This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "carddavprotocol.h" +#include "carddavprotocol_p.h" #include #include #include using namespace KDAV; class CarddavCollectionQueryBuilder : public XMLQueryBuilder { public: QDomDocument buildQuery() const override { QDomDocument document; QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind")); document.appendChild(propfindElement); QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); propfindElement.appendChild(propElement); propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("displayname"))); propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype"))); propElement.appendChild(document.createElementNS(QStringLiteral("http://calendarserver.org/ns/"), QStringLiteral("getctag"))); return document; } QString mimeType() const override { return QString(); } }; class CarddavListItemsQueryBuilder : public XMLQueryBuilder { public: QDomDocument buildQuery() const override { QDomDocument document; QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind")); document.appendChild(propfindElement); QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); propfindElement.appendChild(propElement); propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("displayname"))); propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype"))); propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("getetag"))); return document; } QString mimeType() const override { return QStringLiteral("text/directory"); } }; class CarddavMultigetQueryBuilder : public XMLQueryBuilder { public: QDomDocument buildQuery() const override { QDomDocument document; const QStringList urls = parameter(QStringLiteral("urls")).toStringList(); if (urls.isEmpty()) { return document; } QDomElement multigetElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:carddav"), QStringLiteral("addressbook-multiget")); document.appendChild(multigetElement); QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); multigetElement.appendChild(propElement); propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("getetag"))); QDomElement addressDataElement = document.createElementNS(QStringLiteral("urn:ietf:params:xml:ns:carddav"), QStringLiteral("address-data")); addressDataElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("allprop"))); propElement.appendChild(addressDataElement); for (const QString &url : urls) { QDomElement hrefElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("href")); const QUrl pathUrl = QUrl::fromUserInput(url); const QDomText textNode = document.createTextNode(pathUrl.toString()); hrefElement.appendChild(textNode); multigetElement.appendChild(hrefElement); } return document; } QString mimeType() const override { return QString(); } }; CarddavProtocol::CarddavProtocol() { } bool CarddavProtocol::supportsPrincipals() const { return true; } bool CarddavProtocol::useReport() const { return false; } bool CarddavProtocol::useMultiget() const { return true; } QString CarddavProtocol::principalHomeSet() const { return QStringLiteral("addressbook-home-set"); } QString CarddavProtocol::principalHomeSetNS() const { return QStringLiteral("urn:ietf:params:xml:ns:carddav"); } XMLQueryBuilder::Ptr CarddavProtocol::collectionsQuery() const { return XMLQueryBuilder::Ptr(new CarddavCollectionQueryBuilder()); } QString CarddavProtocol::collectionsXQuery() const { const QString query(QStringLiteral("//*[local-name()='addressbook' and namespace-uri()='urn:ietf:params:xml:ns:carddav']/ancestor::*[local-name()='response' and namespace-uri()='DAV:']")); return query; } QVector CarddavProtocol::itemsQueries() const { QVector ret; ret << XMLQueryBuilder::Ptr(new CarddavListItemsQueryBuilder()); return ret; } XMLQueryBuilder::Ptr CarddavProtocol::itemsReportQuery(const QStringList &urls) const { XMLQueryBuilder::Ptr ret(new CarddavMultigetQueryBuilder()); ret->setParameter(QStringLiteral("urls"), urls); return ret; } QString CarddavProtocol::responseNamespace() const { return QStringLiteral("urn:ietf:params:xml:ns:carddav"); } QString CarddavProtocol::dataTagName() const { return QStringLiteral("address-data"); } DavCollection::ContentTypes CarddavProtocol::collectionContentTypes(const QDomElement &) const { return DavCollection::Contacts; } diff --git a/src/protocols/carddavprotocol.h b/src/protocols/carddavprotocol_p.h similarity index 97% rename from src/protocols/carddavprotocol.h rename to src/protocols/carddavprotocol_p.h index 1eaf98a..8c851b3 100644 --- a/src/protocols/carddavprotocol.h +++ b/src/protocols/carddavprotocol_p.h @@ -1,43 +1,43 @@ /* Copyright (c) 2010 Tobias Koenig This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDAV_CARDDAVPROTOCOL_H #define KDAV_CARDDAVPROTOCOL_H -#include "common/davmultigetprotocol.h" +#include "common/davmultigetprotocol_p.h" class CarddavProtocol : public KDAV::DavMultigetProtocol { public: CarddavProtocol(); Q_REQUIRED_RESULT bool supportsPrincipals() const override; Q_REQUIRED_RESULT bool useReport() const override; Q_REQUIRED_RESULT bool useMultiget() const override; Q_REQUIRED_RESULT QString principalHomeSet() const override; Q_REQUIRED_RESULT QString principalHomeSetNS() const override; Q_REQUIRED_RESULT KDAV::XMLQueryBuilder::Ptr collectionsQuery() const override; Q_REQUIRED_RESULT QString collectionsXQuery() const override; Q_REQUIRED_RESULT QVector itemsQueries() const override; Q_REQUIRED_RESULT KDAV::XMLQueryBuilder::Ptr itemsReportQuery(const QStringList &urls) const override; Q_REQUIRED_RESULT QString responseNamespace() const override; Q_REQUIRED_RESULT QString dataTagName() const override; Q_REQUIRED_RESULT KDAV::DavCollection::ContentTypes collectionContentTypes(const QDomElement &propstat) const override; }; #endif diff --git a/src/protocols/groupdavprotocol.cpp b/src/protocols/groupdavprotocol.cpp index 5294398..b11a526 100644 --- a/src/protocols/groupdavprotocol.cpp +++ b/src/protocols/groupdavprotocol.cpp @@ -1,153 +1,153 @@ /* Copyright (c) 2009 Grégory Oestreicher This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "groupdavprotocol.h" +#include "groupdavprotocol_p.h" #include "common/utils.h" #include using namespace KDAV; class GroupdavCollectionQueryBuilder : public XMLQueryBuilder { public: QDomDocument buildQuery() const override { QDomDocument document; QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind")); document.appendChild(propfindElement); QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); propfindElement.appendChild(propElement); propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("displayname"))); propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype"))); return document; } QString mimeType() const override { return QString(); } }; class GroupdavItemQueryBuilder : public XMLQueryBuilder { public: QDomDocument buildQuery() const override { QDomDocument document; QDomElement propfindElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("propfind")); document.appendChild(propfindElement); QDomElement propElement = document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("prop")); propfindElement.appendChild(propElement); propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("displayname"))); propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("resourcetype"))); propElement.appendChild(document.createElementNS(QStringLiteral("DAV:"), QStringLiteral("getetag"))); return document; } QString mimeType() const override { return QString(); } }; GroupdavProtocol::GroupdavProtocol() { } bool GroupdavProtocol::supportsPrincipals() const { return false; } bool GroupdavProtocol::useReport() const { return false; } bool GroupdavProtocol::useMultiget() const { return false; } XMLQueryBuilder::Ptr GroupdavProtocol::collectionsQuery() const { return XMLQueryBuilder::Ptr(new GroupdavCollectionQueryBuilder()); } QString GroupdavProtocol::collectionsXQuery() const { const QString query(QStringLiteral( "//*[(local-name()='vevent-collection' or local-name()='vtodo-collection' or local-name()='vcard-collection') and namespace-uri()='http://groupdav.org/']/ancestor::*[local-name()='response' and namespace-uri()='DAV:']")); return query; } QVector GroupdavProtocol::itemsQueries() const { QVector ret; ret << XMLQueryBuilder::Ptr(new GroupdavItemQueryBuilder()); return ret; } DavCollection::ContentTypes GroupdavProtocol::collectionContentTypes(const QDomElement &propstatElement) const { /* * Extract the content type information from a propstat like the following * * * HTTP/1.1 200 OK * * Tasks * * * * * Sat, 30 Jan 2010 17:52:41 -0100 * * */ const QDomElement propElement = Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); const QDomElement resourcetypeElement = Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("resourcetype")); DavCollection::ContentTypes contentTypes; if (!Utils::firstChildElementNS(resourcetypeElement, QStringLiteral("http://groupdav.org/"), QStringLiteral("vevent-collection")).isNull()) { contentTypes |= DavCollection::Events; } if (!Utils::firstChildElementNS(resourcetypeElement, QStringLiteral("http://groupdav.org/"), QStringLiteral("vtodo-collection")).isNull()) { contentTypes |= DavCollection::Todos; } if (!Utils::firstChildElementNS(resourcetypeElement, QStringLiteral("http://groupdav.org/"), QStringLiteral("vcard-collection")).isNull()) { contentTypes |= DavCollection::Contacts; } return contentTypes; } diff --git a/src/protocols/groupdavprotocol.h b/src/protocols/groupdavprotocol_p.h similarity index 97% rename from src/protocols/groupdavprotocol.h rename to src/protocols/groupdavprotocol_p.h index e89ad9f..98756ea 100644 --- a/src/protocols/groupdavprotocol.h +++ b/src/protocols/groupdavprotocol_p.h @@ -1,38 +1,38 @@ /* Copyright (c) 2009 Grégory Oestreicher This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef GROUPDAVPROTOCOL_H #define GROUPDAVPROTOCOL_H -#include "common/davprotocolbase.h" +#include "common/davprotocolbase_p.h" class GroupdavProtocol : public KDAV::DavProtocolBase { public: GroupdavProtocol(); Q_REQUIRED_RESULT bool supportsPrincipals() const override; Q_REQUIRED_RESULT bool useReport() const override; Q_REQUIRED_RESULT bool useMultiget() const override; Q_REQUIRED_RESULT KDAV::XMLQueryBuilder::Ptr collectionsQuery() const override; Q_REQUIRED_RESULT QString collectionsXQuery() const override; Q_REQUIRED_RESULT QVector itemsQueries() const override; Q_REQUIRED_RESULT KDAV::DavCollection::ContentTypes collectionContentTypes(const QDomElement &propstat) const override; }; #endif