ldapdn.cpp 4.57 KB
Newer Older
1
/*
Allen Winter's avatar
Allen Winter committed
2
  This file is part of libkldap.
3
4
5
  SPDX-FileCopyrightText: 2006 Sean Harmer <sh@theharmers.co.uk>

  SPDX-License-Identifier: LGPL-2.0-or-later
6
7
8
9
*/

#include "ldapdn.h"

Laurent Montel's avatar
Laurent Montel committed
10
#include "ldap_debug.h"
Laurent Montel's avatar
Laurent Montel committed
11
12
#include <QRegularExpression>
#include <algorithm>
13
14
15

using namespace KLDAP;

16
class Q_DECL_HIDDEN LdapDN::LdapDNPrivate
17
{
Laurent Montel's avatar
Laurent Montel committed
18
public:
Laurent Montel's avatar
Laurent Montel committed
19
20
    LdapDNPrivate()
        : m_dn()
Laurent Montel's avatar
Laurent Montel committed
21
22
23
24
25
26
    {
    }

    ~LdapDNPrivate()
    {
    }
27

Laurent Montel's avatar
Laurent Montel committed
28
    bool isValidRDNString(const QString &rdn) const;
Sergio Martins's avatar
Sergio Martins committed
29
    QStringList splitOnNonEscapedChar(const QString &rdn, QChar ch) const;
Tobias Koenig's avatar
Tobias Koenig committed
30

Allen Winter's avatar
Allen Winter committed
31
    QString m_dn;
32
33
};

Laurent Montel's avatar
Laurent Montel committed
34
bool LdapDN::LdapDNPrivate::isValidRDNString(const QString &rdn) const
Tobias Koenig's avatar
Tobias Koenig committed
35
{
Laurent Montel's avatar
Laurent Montel committed
36
    qCDebug(LDAP_LOG) << "Testing rdn:" << rdn;
Tobias Koenig's avatar
Tobias Koenig committed
37

Laurent Montel's avatar
Laurent Montel committed
38
39
40
41
42
43
44
45
46
47
48
    // If it is a muli-valued rdn, split it into its constituent parts
    const QStringList rdnParts = splitOnNonEscapedChar(rdn, QLatin1Char('+'));
    const int rdnPartsSize(rdnParts.size());
    if (rdnPartsSize > 1) {
        for (int i = 0; i < rdnPartsSize; i++) {
            if (!isValidRDNString(rdnParts.at(i))) {
                return false;
            }
        }
        return true;
    }
49
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 2)
50
51
    const QVector<QStringRef> components = rdn.splitRef(QLatin1Char('='));
#else
Laurent Montel's avatar
Laurent Montel committed
52
    // Split the rdn into the attribute name and value parts
Tobias Junghans's avatar
Tobias Junghans committed
53
    const auto components = QStringView(rdn).split(QLatin1Char('='));
54
#endif
Laurent Montel's avatar
Laurent Montel committed
55
56
    // We should have exactly two parts
    if (components.size() != 2) {
Allen Winter's avatar
Allen Winter committed
57
        return false;
Tobias Koenig's avatar
Tobias Koenig committed
58
    }
Laurent Montel's avatar
Laurent Montel committed
59

Allen Winter's avatar
Allen Winter committed
60
    return true;
Laurent Montel's avatar
Laurent Montel committed
61
}
Tobias Koenig's avatar
Tobias Koenig committed
62

Sergio Martins's avatar
Sergio Martins committed
63
QStringList LdapDN::LdapDNPrivate::splitOnNonEscapedChar(const QString &str, QChar ch) const
Laurent Montel's avatar
Laurent Montel committed
64
65
66
67
68
69
70
71
72
{
    QStringList strParts;
    int index = 0;
    int searchFrom = 0;
    int strPartStartIndex = 0;
    while ((index = str.indexOf(ch, searchFrom)) != -1) {
        const QChar prev = str[std::max(0, index - 1)];
        if (prev != QLatin1Char('\\')) {
            // Found a component of a multi-valued RDN
Laurent Montel's avatar
Laurent Montel committed
73
            // qCDebug(LDAP_LOG) << "Found" << ch << "at index" << index;
Laurent Montel's avatar
Laurent Montel committed
74
            QString tmp = str.mid(strPartStartIndex, index - strPartStartIndex);
Laurent Montel's avatar
Laurent Montel committed
75
            // qCDebug(LDAP_LOG) << "Adding part:" << tmp;
Laurent Montel's avatar
Laurent Montel committed
76
77
78
79
80
81
            strParts.append(tmp);
            strPartStartIndex = index + 1;
        }

        searchFrom = index + 1;
    }
Tobias Koenig's avatar
Tobias Koenig committed
82

Laurent Montel's avatar
Laurent Montel committed
83
84
    // Add on the part after the last found delimeter
    QString tmp = str.mid(strPartStartIndex);
Laurent Montel's avatar
Laurent Montel committed
85
    // qCDebug(LDAP_LOG) << "Adding part:" << tmp;
Laurent Montel's avatar
Laurent Montel committed
86
    strParts.append(tmp);
Tobias Koenig's avatar
Tobias Koenig committed
87

Laurent Montel's avatar
Laurent Montel committed
88
    return strParts;
Allen Winter's avatar
Allen Winter committed
89
}
Tobias Koenig's avatar
Tobias Koenig committed
90

91
LdapDN::LdapDN()
Laurent Montel's avatar
Laurent Montel committed
92
    : d(new LdapDNPrivate)
93
94
95
{
}

Laurent Montel's avatar
Laurent Montel committed
96
97
LdapDN::LdapDN(const QString &dn)
    : d(new LdapDNPrivate)
98
{
Laurent Montel's avatar
Laurent Montel committed
99
    d->m_dn = dn;
100
101
}

Laurent Montel's avatar
Laurent Montel committed
102
103
LdapDN::LdapDN(const LdapDN &that)
    : d(new LdapDNPrivate)
104
{
Laurent Montel's avatar
Laurent Montel committed
105
    *d = *that.d;
106
107
}

Laurent Montel's avatar
Laurent Montel committed
108
LdapDN &LdapDN::operator=(const LdapDN &that)
109
{
Laurent Montel's avatar
Laurent Montel committed
110
111
112
    if (this == &that) {
        return *this;
    }
113

Laurent Montel's avatar
Laurent Montel committed
114
115
    *d = *that.d;
    return *this;
116
117
118
119
}

LdapDN::~LdapDN()
{
Laurent Montel's avatar
Laurent Montel committed
120
    delete d;
121
122
123
124
}

void LdapDN::clear()
{
Laurent Montel's avatar
Laurent Montel committed
125
    d->m_dn.clear();
126
127
128
129
}

bool LdapDN::isEmpty() const
{
Laurent Montel's avatar
Laurent Montel committed
130
    return d->m_dn.isEmpty();
131
132
133
134
}

QString LdapDN::toString() const
{
Laurent Montel's avatar
Laurent Montel committed
135
    return d->m_dn;
136
137
}

Laurent Montel's avatar
Laurent Montel committed
138
QString LdapDN::toString(int depth) const
139
{
Laurent Montel's avatar
Laurent Montel committed
140
    const QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(','));
Laurent Montel's avatar
Laurent Montel committed
141
142
143
    if (depth >= rdns.size()) {
        return QString();
    }
144

Laurent Montel's avatar
Laurent Montel committed
145
146
147
148
    // Construct a DN down to the requested depth
    QString dn;
    for (int i = depth; i >= 0; i--) {
        dn += rdns.at(rdns.size() - 1 - i) + QLatin1Char(',');
Laurent Montel's avatar
Laurent Montel committed
149
        qCDebug(LDAP_LOG) << "dn =" << dn;
Laurent Montel's avatar
Laurent Montel committed
150
    }
Laurent Montel's avatar
Laurent Montel committed
151
    dn.chop(1); // Strip off the extraneous comma
152

Laurent Montel's avatar
Laurent Montel committed
153
    return dn;
154
155
156
157
}

QString LdapDN::rdnString() const
{
Laurent Montel's avatar
Laurent Montel committed
158
    /** \TODO We should move this into the d pointer as we calculate rdns quite a lot */
Laurent Montel's avatar
Laurent Montel committed
159
    const QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(','));
Laurent Montel's avatar
Laurent Montel committed
160
    return rdns.at(0);
161
162
}

Laurent Montel's avatar
Laurent Montel committed
163
QString LdapDN::rdnString(int depth) const
164
{
Laurent Montel's avatar
Laurent Montel committed
165
    const QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(','));
Laurent Montel's avatar
Laurent Montel committed
166
167
168
169
    if (depth >= rdns.size()) {
        return QString();
    }
    return rdns.at(rdns.size() - 1 - depth);
170
171
172
173
}

bool LdapDN::isValid() const
{
Laurent Montel's avatar
Laurent Montel committed
174
    qCDebug(LDAP_LOG) << "Testing dn:" << d->m_dn;
175

Laurent Montel's avatar
Laurent Montel committed
176
177
    // Break the string into rdn's
    const QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(','));
178

Laurent Montel's avatar
Laurent Montel committed
179
180
181
182
183
184
    // Test to see if each rdn is valid
    const int rdnsSize(rdns.size());
    for (int i = 0; i < rdnsSize; i++) {
        if (!d->isValidRDNString(rdns.at(i))) {
            return false;
        }
185
186
    }

Laurent Montel's avatar
Laurent Montel committed
187
    return true;
188
189
190
191
}

int LdapDN::depth() const
{
Laurent Montel's avatar
Laurent Montel committed
192
    const QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(','));
Laurent Montel's avatar
Laurent Montel committed
193
    return rdns.size();
194
}
195

Laurent Montel's avatar
Laurent Montel committed
196
bool LdapDN::operator==(const LdapDN &rhs) const
197
{
Laurent Montel's avatar
Laurent Montel committed
198
    return d->m_dn == rhs.d->m_dn;
199
200
}

Laurent Montel's avatar
Laurent Montel committed
201
bool LdapDN::operator!=(const LdapDN &rhs) const
202
{
Laurent Montel's avatar
Laurent Montel committed
203
    return d->m_dn != rhs.d->m_dn;
204
}