1/*
2 A temporary copy to break dependency to KLDAP
3
4 This file is part of libkldap.
5 Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21*/
22
23#include "ldapdn_p.h"
24
25#include <algorithm>
26
27#include <kdebug.h>
28
29class LdapDN::LdapDNPrivate
30{
31 public:
32 LdapDNPrivate() : m_dn() {}
33 ~LdapDNPrivate() {}
34
35 bool isValidRDNString( const QString &rdn ) const;
36 QStringList splitOnNonEscapedChar( const QString &rdn, const QChar &ch ) const;
37
38 QString m_dn;
39};
40
41bool LdapDN::LdapDNPrivate::isValidRDNString( const QString &rdn ) const
42{
43 kDebug() << "Testing rdn:" << rdn;
44
45 // If it is a muli-valued rdn, split it into its constituent parts
46 QStringList rdnParts = splitOnNonEscapedChar( rdn, QLatin1Char( '+' ) );
47 if ( rdnParts.size() > 1 ) {
48 for ( int i = 0; i < rdnParts.size(); i++ ) {
49 if ( !isValidRDNString( rdnParts.at( i ) ) ) {
50 return false;
51 }
52 }
53 return true;
54 }
55
56 // Split the rdn into the attribute name and value parts
57 const QStringList components = rdn.split( QLatin1Char( '=' ) );
58
59 // We should have exactly two parts
60 if ( components.size() != 2 ) {
61 return false;
62 }
63
64 return true;
65}
66
67QStringList LdapDN::LdapDNPrivate::splitOnNonEscapedChar( const QString &str,
68 const QChar &ch ) const
69{
70 QStringList strParts;
71 int index = 0;
72 int searchFrom = 0;
73 int strPartStartIndex = 0;
74 while ( ( index = str.indexOf( ch, searchFrom ) ) != -1 ) {
75 const QChar prev = str[std::max( 0, index - 1 )];
76 if ( prev != QLatin1Char( '\\' ) ) {
77 // Found a component of a multi-valued RDN
78 //kDebug() << "Found" << ch << "at index" << index;
79 QString tmp = str.mid( strPartStartIndex, index - strPartStartIndex );
80 //kDebug() << "Adding part:" << tmp;
81 strParts.append( tmp );
82 strPartStartIndex = index + 1;
83 }
84
85 searchFrom = index + 1;
86 }
87
88 // Add on the part after the last found delimeter
89 QString tmp = str.mid( strPartStartIndex );
90 //kDebug() << "Adding part:" << tmp;
91 strParts.append( tmp );
92
93 return strParts;
94}
95
96LdapDN::LdapDN()
97 : d( new LdapDNPrivate )
98{
99
100}
101
102LdapDN::LdapDN( const QString &dn )
103 : d( new LdapDNPrivate )
104{
105 d->m_dn = dn;
106}
107
108LdapDN::LdapDN( const LdapDN &that )
109 : d( new LdapDNPrivate )
110{
111 *d = *that.d;
112}
113
114LdapDN &LdapDN::operator=( const LdapDN &that )
115{
116 if ( this == &that ) {
117 return *this;
118 }
119
120 *d = *that.d;
121 return *this;
122}
123
124LdapDN::~LdapDN()
125{
126 delete d;
127}
128
129void LdapDN::clear()
130{
131 d->m_dn.clear();
132}
133
134bool LdapDN::isEmpty() const
135{
136 return d->m_dn.isEmpty();
137}
138
139QString LdapDN::toString() const
140{
141 return d->m_dn;
142}
143
144QString LdapDN::toString( int depth ) const
145{
146 QStringList rdns = d->splitOnNonEscapedChar( d->m_dn, QLatin1Char( ',' ) );
147 if ( depth >= rdns.size() ) {
148 return QString();
149 }
150
151 // Construct a DN down to the requested depth
152 QString dn;
153 for ( int i = depth; i >= 0; i-- ) {
154 dn += rdns.at( rdns.size() - 1 - i ) + QLatin1Char( ',' );
155 kDebug() << "dn =" << dn;
156 }
157 dn = dn.left( dn.length() - 1 ); // Strip off the extraneous comma
158
159 return dn;
160}
161
162QString LdapDN::rdnString() const
163{
164 /** \TODO We should move this into the d pointer as we calculate rdns quite a lot */
165 QStringList rdns = d->splitOnNonEscapedChar( d->m_dn, QLatin1Char( ',' ) );
166 return rdns.at( 0 );
167}
168
169QString LdapDN::rdnString( int depth ) const
170{
171 QStringList rdns = d->splitOnNonEscapedChar( d->m_dn, QLatin1Char( ',' ) );
172 if ( depth >= rdns.size() ) {
173 return QString();
174 }
175 return rdns.at( rdns.size() - 1 - depth );
176}
177
178bool LdapDN::isValid() const
179{
180 kDebug() << "Testing dn:" << d->m_dn;
181
182 // Break the string into rdn's
183 QStringList rdns = d->splitOnNonEscapedChar( d->m_dn, QLatin1Char( ',' ) );
184
185 // Test to see if each rdn is valid
186 for ( int i = 0; i < rdns.size(); i++ ) {
187 if ( !d->isValidRDNString( rdns.at( i ) ) ) {
188 return false;
189 }
190 }
191
192 return true;
193}
194
195int LdapDN::depth() const
196{
197 QStringList rdns = d->splitOnNonEscapedChar( d->m_dn, QLatin1Char( ',' ) );
198 return rdns.size();
199}
200
201bool LdapDN::operator == ( const LdapDN &rhs ) const
202{
203 return d->m_dn == rhs.d->m_dn;
204}
205
206bool LdapDN::operator != ( const LdapDN &rhs ) const
207{
208 return d->m_dn != rhs.d->m_dn;
209}
210