File indexing completed on 2025-03-02 04:55:47

0001 /*
0002   This file is part of libkldap.
0003   SPDX-FileCopyrightText: 2004-2006 Szombathelyi György <gyurco@freemail.hu>
0004 
0005   SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "ldapurl.h"
0009 
0010 #include "ldap_core_debug.h"
0011 
0012 using namespace KLDAPCore;
0013 
0014 class Q_DECL_HIDDEN LdapUrl::LdapUrlPrivate
0015 {
0016 public:
0017     LdapUrlPrivate()
0018         : m_scope(Base)
0019     {
0020     }
0021 
0022     QMap<QString, Extension> m_extensions;
0023     QStringList m_attributes;
0024     Scope m_scope;
0025     QString m_filter;
0026 };
0027 
0028 LdapUrl::LdapUrl()
0029     : d(new LdapUrlPrivate)
0030 {
0031 }
0032 
0033 LdapUrl::LdapUrl(const QUrl &_url)
0034     : QUrl(_url)
0035     , d(new LdapUrlPrivate)
0036 {
0037     parseQuery();
0038 }
0039 
0040 LdapUrl::LdapUrl(const LdapUrl &that)
0041     : QUrl(that)
0042     , d(new LdapUrlPrivate)
0043 {
0044     *d = *that.d;
0045 }
0046 
0047 LdapUrl &LdapUrl::operator=(const LdapUrl &that)
0048 {
0049     if (this == &that) {
0050         return *this;
0051     }
0052 
0053     QUrl::operator=(that);
0054     *d = *that.d;
0055 
0056     return *this;
0057 }
0058 
0059 LdapUrl::~LdapUrl() = default;
0060 
0061 void LdapUrl::setDn(const LdapDN &dn)
0062 {
0063     const QString tmp = dn.toString();
0064     if (tmp.startsWith(QLatin1Char('/'))) {
0065         setPath(tmp);
0066     } else {
0067         setPath(QLatin1Char('/') + tmp);
0068     }
0069 }
0070 
0071 LdapDN LdapUrl::dn() const
0072 {
0073     QString tmp = path();
0074     if (tmp.startsWith(QLatin1Char('/'))) {
0075         tmp = tmp.mid(1);
0076     }
0077     const LdapDN tmpDN(tmp);
0078     return tmpDN;
0079 }
0080 
0081 QStringList LdapUrl::attributes() const
0082 {
0083     return d->m_attributes;
0084 }
0085 
0086 void LdapUrl::setAttributes(const QStringList &attributes)
0087 {
0088     d->m_attributes = attributes;
0089     updateQuery();
0090 }
0091 
0092 LdapUrl::Scope LdapUrl::scope() const
0093 {
0094     return d->m_scope;
0095 }
0096 
0097 void LdapUrl::setScope(Scope scope)
0098 {
0099     d->m_scope = scope;
0100     updateQuery();
0101 }
0102 
0103 QString LdapUrl::filter() const
0104 {
0105     return d->m_filter;
0106 }
0107 
0108 void LdapUrl::setFilter(const QString &filter)
0109 {
0110     d->m_filter = filter;
0111     updateQuery();
0112 }
0113 
0114 bool LdapUrl::hasExtension(const QString &key) const
0115 {
0116     return d->m_extensions.contains(key);
0117 }
0118 
0119 LdapUrl::Extension LdapUrl::extension(const QString &key) const
0120 {
0121     QMap<QString, Extension>::const_iterator it;
0122 
0123     it = d->m_extensions.constFind(key);
0124     if (it != d->m_extensions.constEnd()) {
0125         return *it;
0126     } else {
0127         Extension ext;
0128         ext.value = QLatin1StringView("");
0129         ext.critical = false;
0130         return ext;
0131     }
0132 }
0133 
0134 QString LdapUrl::extension(const QString &key, bool &critical) const
0135 {
0136     const Extension ext = extension(key);
0137     critical = ext.critical;
0138     return ext.value;
0139 }
0140 
0141 void LdapUrl::setExtension(const QString &key, const LdapUrl::Extension &ext)
0142 {
0143     d->m_extensions[key] = ext;
0144     updateQuery();
0145 }
0146 
0147 void LdapUrl::setExtension(const QString &key, const QString &value, bool critical)
0148 {
0149     Extension ext;
0150     ext.value = value;
0151     ext.critical = critical;
0152     setExtension(key, ext);
0153 }
0154 
0155 void LdapUrl::setExtension(const QString &key, int value, bool critical)
0156 {
0157     Extension ext;
0158     ext.value = QString::number(value);
0159     ext.critical = critical;
0160     setExtension(key, ext);
0161 }
0162 
0163 void LdapUrl::removeExtension(const QString &key)
0164 {
0165     d->m_extensions.remove(key);
0166     updateQuery();
0167 }
0168 
0169 void LdapUrl::updateQuery()
0170 {
0171     QMap<QString, Extension>::const_iterator it;
0172     QString q(QLatin1Char('?'));
0173 
0174     // set the attributes to query
0175     if (!d->m_attributes.isEmpty()) {
0176         q += d->m_attributes.join(QLatin1Char(','));
0177     }
0178 
0179     // set the scope
0180     q += QLatin1Char('?');
0181     switch (d->m_scope) {
0182     case Sub:
0183         q += QStringLiteral("sub");
0184         break;
0185     case One:
0186         q += QStringLiteral("one");
0187         break;
0188     case Base:
0189         q += QStringLiteral("base");
0190         break;
0191     }
0192 
0193     // set the filter
0194     q += QLatin1Char('?');
0195     if (d->m_filter != QLatin1StringView("(objectClass=*)") && !d->m_filter.isEmpty()) {
0196         q += QLatin1StringView(toPercentEncoding(d->m_filter));
0197     }
0198 
0199     // set the extensions
0200     q += QLatin1Char('?');
0201     for (it = d->m_extensions.constBegin(); it != d->m_extensions.constEnd(); ++it) {
0202         if (it.value().critical) {
0203             q += QLatin1Char('!');
0204         }
0205         q += it.key();
0206         if (!it.value().value.isEmpty()) {
0207             q += QLatin1Char('=') + QLatin1StringView(toPercentEncoding(it.value().value));
0208         }
0209         q += QLatin1Char(',');
0210     }
0211     while (q.endsWith(QLatin1Char('?')) || q.endsWith(QLatin1Char(','))) {
0212         q.remove(q.length() - 1, 1);
0213     }
0214 
0215     setQuery(q);
0216     qCDebug(LDAP_LOG) << "LDAP URL updateQuery():" << toDisplayString();
0217 }
0218 
0219 void LdapUrl::parseQuery()
0220 {
0221     Extension ext;
0222     QStringList extensions;
0223     QString q = query(QUrl::FullyEncoded);
0224     // remove first ?
0225     if (q.startsWith(QLatin1Char('?'))) {
0226         q.remove(0, 1);
0227     }
0228 
0229     // split into a list
0230     const QStringList url_items = q.split(QLatin1Char('?'));
0231 
0232     d->m_attributes.clear();
0233     d->m_scope = Base;
0234     d->m_filter = QStringLiteral("(objectClass=*)");
0235     d->m_extensions.clear();
0236 
0237     int i = 0;
0238     QStringList::const_iterator end(url_items.constEnd());
0239     for (QStringList::const_iterator it = url_items.constBegin(); it != end; ++it, i++) {
0240         switch (i) {
0241         case 0:
0242             d->m_attributes = (*it).split(QLatin1Char(','), Qt::SkipEmptyParts);
0243             break;
0244         case 1:
0245             if ((*it) == QLatin1StringView("sub")) {
0246                 d->m_scope = Sub;
0247             } else if ((*it) == QLatin1StringView("one")) {
0248                 d->m_scope = One;
0249             }
0250             break;
0251         case 2:
0252             d->m_filter = fromPercentEncoding((*it).toLatin1());
0253             break;
0254         case 3:
0255             extensions = (*it).split(QLatin1Char(','), Qt::SkipEmptyParts);
0256             break;
0257         }
0258     }
0259 
0260     QString name;
0261     QString value;
0262     QStringList::const_iterator end2(extensions.constEnd());
0263     for (QStringList::const_iterator it = extensions.constBegin(); it != end2; ++it) {
0264         ext.critical = false;
0265         name = fromPercentEncoding((*it).section(QLatin1Char('='), 0, 0).toLatin1()).toLower();
0266         value = fromPercentEncoding((*it).section(QLatin1Char('='), 1).toLatin1());
0267         if (name.startsWith(QLatin1Char('!'))) {
0268             ext.critical = true;
0269             name.remove(0, 1);
0270         }
0271         qCDebug(LDAP_LOG) << "LdapUrl extensions name=" << name << "value:" << value;
0272         ext.value = value.replace(QLatin1StringView("%2"), QLatin1StringView(","));
0273         setExtension(name, ext);
0274     }
0275 }