File indexing completed on 2024-06-16 04:52:28
0001 /* 0002 Copyright (c) 2010 Tobias Koenig <tokoe@kde.org> 0003 0004 This program is free software; you can redistribute it and/or modify 0005 it under the terms of the GNU General Public License as published by 0006 the Free Software Foundation; either version 2 of the License, or 0007 (at your option) any later version. 0008 0009 This program is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0012 GNU General Public License for more details. 0013 0014 You should have received a copy of the GNU General Public License 0015 along with this program; if not, write to the Free Software 0016 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 0017 */ 0018 0019 #include "utils.h" 0020 0021 #include "enums.h" 0022 0023 #include "davitem.h" 0024 #include "davmanager.h" 0025 #include "davprotocolbase.h" 0026 #include "davurl.h" 0027 0028 #include <QColor> 0029 #include <QtCore/QByteArray> 0030 #include <QtCore/QDateTime> 0031 #include <QtCore/QString> 0032 0033 #include "libkdav2_debug.h" 0034 0035 using namespace KDAV2; 0036 0037 QDomElement Utils::firstChildElementNS(const QDomElement &parent, const QString &namespaceUri, const QString &tagName) 0038 { 0039 for (QDomNode child = parent.firstChild(); !child.isNull(); child = child.nextSibling()) { 0040 if (child.isElement()) { 0041 const QDomElement elt = child.toElement(); 0042 if (tagName.isEmpty() || (elt.tagName() == tagName && elt.namespaceURI() == namespaceUri)) { 0043 return elt; 0044 } 0045 } 0046 } 0047 0048 return QDomElement(); 0049 } 0050 0051 QDomElement Utils::nextSiblingElementNS(const QDomElement &element, const QString &namespaceUri, const QString &tagName) 0052 { 0053 for (QDomNode sib = element.nextSibling(); !sib.isNull(); sib = sib.nextSibling()) { 0054 if (sib.isElement()) { 0055 const QDomElement elt = sib.toElement(); 0056 if (tagName.isEmpty() || (elt.tagName() == tagName && elt.namespaceURI() == namespaceUri)) { 0057 return elt; 0058 } 0059 } 0060 } 0061 0062 return QDomElement(); 0063 } 0064 0065 Privileges Utils::extractPrivileges(const QDomElement &element) 0066 { 0067 Privileges final = None; 0068 QDomElement privElement = firstChildElementNS(element, QStringLiteral("DAV:"), QStringLiteral("privilege")); 0069 0070 while (!privElement.isNull()) { 0071 QDomElement child = privElement.firstChildElement(); 0072 0073 while (!child.isNull()) { 0074 final |= parsePrivilege(child); 0075 child = child.nextSiblingElement(); 0076 } 0077 0078 privElement = Utils::nextSiblingElementNS(privElement, QStringLiteral("DAV:"), QStringLiteral("privilege")); 0079 } 0080 0081 return final; 0082 } 0083 0084 Privileges Utils::parsePrivilege(const QDomElement &element) 0085 { 0086 Privileges final = None; 0087 0088 if (!element.childNodes().isEmpty()) { 0089 // This is an aggregate privilege, parse each of its children 0090 QDomElement child = element.firstChildElement(); 0091 while (!child.isNull()) { 0092 final |= parsePrivilege(child); 0093 child = child.nextSiblingElement(); 0094 } 0095 } else { 0096 // This is a normal privilege 0097 const QString privname = element.localName(); 0098 0099 if (privname == QLatin1String("read")) { 0100 final |= KDAV2::Read; 0101 } else if (privname == QLatin1String("write")) { 0102 final |= KDAV2::Write; 0103 } else if (privname == QLatin1String("write-properties")) { 0104 final |= KDAV2::WriteProperties; 0105 } else if (privname == QLatin1String("write-content")) { 0106 final |= KDAV2::WriteContent; 0107 } else if (privname == QLatin1String("unlock")) { 0108 final |= KDAV2::Unlock; 0109 } else if (privname == QLatin1String("read-acl")) { 0110 final |= KDAV2::ReadAcl; 0111 } else if (privname == QLatin1String("read-current-user-privilege-set")) { 0112 final |= KDAV2::ReadCurrentUserPrivilegeSet; 0113 } else if (privname == QLatin1String("write-acl")) { 0114 final |= KDAV2::WriteAcl; 0115 } else if (privname == QLatin1String("bind")) { 0116 final |= KDAV2::Bind; 0117 } else if (privname == QLatin1String("unbind")) { 0118 final |= KDAV2::Unbind; 0119 } else if (privname == QLatin1String("all")) { 0120 final |= KDAV2::All; 0121 } 0122 } 0123 0124 return final; 0125 } 0126 0127 QLatin1String Utils::protocolName(Protocol protocol) 0128 { 0129 QLatin1String protocolName(""); 0130 0131 switch (protocol) { 0132 case KDAV2::CalDav: 0133 protocolName = QLatin1String("CalDav"); 0134 break; 0135 case KDAV2::CardDav: 0136 protocolName = QLatin1String("CardDav"); 0137 break; 0138 case KDAV2::GroupDav: 0139 protocolName = QLatin1String("GroupDav"); 0140 break; 0141 } 0142 0143 return protocolName; 0144 } 0145 0146 Protocol Utils::protocolByName(const QString &name) 0147 { 0148 Protocol protocol = KDAV2::CalDav; 0149 0150 if (name == QLatin1String("CalDav")) { 0151 protocol = KDAV2::CalDav; 0152 } else if (name == QLatin1String("CardDav")) { 0153 protocol = KDAV2::CardDav; 0154 } else if (name == QLatin1String("GroupDav")) { 0155 protocol = KDAV2::GroupDav; 0156 } else { 0157 qCCritical(KDAV2_LOG) << "Unexpected protocol name : " << name; 0158 } 0159 0160 return protocol; 0161 } 0162 0163 QString Utils::createUniqueId() 0164 { 0165 qint64 time = QDateTime::currentMSecsSinceEpoch() / 1000; 0166 int r = qrand() % 1000; 0167 QString id = QLatin1String("R") + QString::number(r); 0168 QString uid = QString::number(time) + QLatin1String(".") + id; 0169 return uid; 0170 } 0171 0172 QString Utils::contactsMimeType(Protocol protocol) 0173 { 0174 QString ret; 0175 0176 if (protocol == KDAV2::CardDav) { 0177 ret = QStringLiteral("text/vcard"); 0178 } else if (protocol == KDAV2::GroupDav) { 0179 ret = QStringLiteral("text/x-vcard"); 0180 } 0181 0182 return ret; 0183 } 0184 0185 bool Utils::extractCollection(const QDomElement &response, DavUrl davUrl, DavCollection &collection) 0186 { 0187 QDomElement propstatElement; 0188 0189 // check for the valid propstat, without giving up on first error 0190 { 0191 const QDomNodeList propstats = 0192 response.elementsByTagNameNS(QStringLiteral("DAV:"), QStringLiteral("propstat")); 0193 for (int i = 0; i < propstats.length(); ++i) { 0194 const QDomElement propstatCandidate = propstats.item(i).toElement(); 0195 const QDomElement statusElement = Utils::firstChildElementNS( 0196 propstatCandidate, QStringLiteral("DAV:"), QStringLiteral("status")); 0197 if (statusElement.text().contains(QStringLiteral("200"))) { 0198 propstatElement = propstatCandidate; 0199 } 0200 } 0201 } 0202 0203 if (propstatElement.isNull()) { 0204 return false; 0205 } 0206 0207 // extract url 0208 const QDomElement hrefElement = 0209 Utils::firstChildElementNS(response, QStringLiteral("DAV:"), QStringLiteral("href")); 0210 0211 if (hrefElement.isNull()) { 0212 return false; 0213 } 0214 0215 0216 QString href = hrefElement.text(); 0217 if (!href.endsWith(QLatin1Char('/'))) { 0218 href.append(QLatin1Char('/')); 0219 } 0220 0221 QUrl url = davUrl.url(); 0222 url.setUserInfo(QString()); 0223 if (href.startsWith(QLatin1Char('/'))) { 0224 // href is only a path, use request url to complete 0225 url.setPath(href, QUrl::TolerantMode); 0226 } else { 0227 // href is a complete url 0228 url = QUrl::fromUserInput(href); 0229 } 0230 0231 // extract display name 0232 const QDomElement propElement = 0233 Utils::firstChildElementNS(propstatElement, QStringLiteral("DAV:"), QStringLiteral("prop")); 0234 const QDomElement displaynameElement = 0235 Utils::firstChildElementNS(propElement, QStringLiteral("DAV:"), QStringLiteral("displayname")); 0236 const QString displayName = displaynameElement.text(); 0237 0238 // Extract CTag 0239 const QDomElement CTagElement = Utils::firstChildElementNS( 0240 propElement, QStringLiteral("http://calendarserver.org/ns/"), QStringLiteral("getctag")); 0241 QString CTag; 0242 if (!CTagElement.isNull()) { 0243 CTag = CTagElement.text(); 0244 } 0245 0246 // extract calendar color if provided 0247 const QDomElement colorElement = Utils::firstChildElementNS( 0248 propElement, QStringLiteral("http://apple.com/ns/ical/"), QStringLiteral("calendar-color")); 0249 QColor color; 0250 if (!colorElement.isNull()) { 0251 QString colorValue = colorElement.text(); 0252 if(colorValue[0] == '#' && colorValue.size() == 9) { 0253 // Put the alpha part at the beginning for Qt: 0254 // Qt wants #AARRGGBB instead of #RRGGBBAA 0255 colorValue = QStringLiteral("#") + colorValue.right(2) + colorValue.mid(1, 6); 0256 } 0257 0258 if (QColor::isValidColor(colorValue)) { 0259 color.setNamedColor(colorValue); 0260 } 0261 } 0262 0263 // extract allowed content types 0264 const DavCollection::ContentTypes contentTypes = 0265 DavManager::self()->davProtocol(davUrl.protocol())->collectionContentTypes(propstatElement); 0266 0267 auto _url = url; 0268 _url.setUserInfo(davUrl.url().userInfo()); 0269 collection = DavCollection(DavUrl(_url, davUrl.protocol()), displayName, contentTypes); 0270 0271 collection.setCTag(CTag); 0272 if (color.isValid()) { 0273 collection.setColor(color); 0274 } 0275 0276 // extract privileges 0277 const QDomElement currentPrivsElement = Utils::firstChildElementNS( 0278 propElement, QStringLiteral("DAV:"), QStringLiteral("current-user-privilege-set")); 0279 if (currentPrivsElement.isNull()) { 0280 // Assume that we have all privileges 0281 collection.setPrivileges(KDAV2::All); 0282 } else { 0283 Privileges privileges = Utils::extractPrivileges(currentPrivsElement); 0284 collection.setPrivileges(privileges); 0285 } 0286 0287 qCDebug(KDAV2_LOG) << url.toDisplayString() << "PRIVS: " << collection.privileges(); 0288 0289 return true; 0290 }