ldapdn.cpp
00001 /* 00002 This file is part of libkldap. 00003 Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "ldapdn.h" 00022 00023 #include <algorithm> 00024 00025 #include <kdebug.h> 00026 00027 using namespace KLDAP; 00028 00029 class LdapDN::LdapDNPrivate 00030 { 00031 public: 00032 LdapDNPrivate() : m_dn() {} 00033 ~LdapDNPrivate() {} 00034 00035 bool isValidRDNString( const QString &rdn ) const; 00036 QStringList splitOnNonEscapedChar( const QString &rdn, const QChar &ch ) const; 00037 00038 QString m_dn; 00039 }; 00040 00041 bool LdapDN::LdapDNPrivate::isValidRDNString( const QString &rdn ) const 00042 { 00043 kDebug() << "Testing rdn:" << rdn; 00044 00045 // If it is a muli-valued rdn, split it into its constituent parts 00046 const QStringList rdnParts = splitOnNonEscapedChar( rdn, QChar( '+' ) ); 00047 const int rdnPartsSize( rdnParts.size() ); 00048 if ( rdnPartsSize > 1 ) { 00049 for ( int i = 0; i < rdnPartsSize; i++ ) { 00050 if ( !isValidRDNString( rdnParts.at( i ) ) ) { 00051 return false; 00052 } 00053 } 00054 return true; 00055 } 00056 00057 // Split the rdn into the attribute name and value parts 00058 QStringList components = rdn.split( '=' ); 00059 00060 // We should have exactly two parts 00061 if ( components.size() != 2 ) { 00062 return false; 00063 } 00064 00065 return true; 00066 } 00067 00068 QStringList LdapDN::LdapDNPrivate::splitOnNonEscapedChar( const QString &str, 00069 const QChar &ch ) const 00070 { 00071 QStringList strParts; 00072 int index = 0; 00073 int searchFrom = 0; 00074 int strPartStartIndex = 0; 00075 while ( ( index = str.indexOf( ch, searchFrom ) ) != -1 ) { 00076 const QChar prev = str[std::max( 0, index - 1 )]; 00077 if ( prev != QChar( '\\' ) ) { 00078 // Found a component of a multi-valued RDN 00079 //kDebug() << "Found" << ch << "at index" << index; 00080 QString tmp = str.mid( strPartStartIndex, index - strPartStartIndex ); 00081 //kDebug() << "Adding part:" << tmp; 00082 strParts.append( tmp ); 00083 strPartStartIndex = index + 1; 00084 } 00085 00086 searchFrom = index + 1; 00087 } 00088 00089 // Add on the part after the last found delimeter 00090 QString tmp = str.mid( strPartStartIndex ); 00091 //kDebug() << "Adding part:" << tmp; 00092 strParts.append( tmp ); 00093 00094 return strParts; 00095 } 00096 00097 LdapDN::LdapDN() 00098 : d( new LdapDNPrivate ) 00099 { 00100 00101 } 00102 00103 LdapDN::LdapDN( const QString &dn ) 00104 : d( new LdapDNPrivate ) 00105 { 00106 d->m_dn = dn; 00107 } 00108 00109 LdapDN::LdapDN( const LdapDN &that ) 00110 : d( new LdapDNPrivate ) 00111 { 00112 *d = *that.d; 00113 } 00114 00115 LdapDN &LdapDN::operator=( const LdapDN &that ) 00116 { 00117 if ( this == &that ) { 00118 return *this; 00119 } 00120 00121 *d = *that.d; 00122 return *this; 00123 } 00124 00125 LdapDN::~LdapDN() 00126 { 00127 delete d; 00128 } 00129 00130 void LdapDN::clear() 00131 { 00132 d->m_dn.clear(); 00133 } 00134 00135 bool LdapDN::isEmpty() const 00136 { 00137 return d->m_dn.isEmpty(); 00138 } 00139 00140 QString LdapDN::toString() const 00141 { 00142 return d->m_dn; 00143 } 00144 00145 QString LdapDN::toString( int depth ) const 00146 { 00147 QStringList rdns = d->splitOnNonEscapedChar( d->m_dn, QChar( ',' ) ); 00148 if ( depth >= rdns.size() ) { 00149 return QString(); 00150 } 00151 00152 // Construct a DN down to the requested depth 00153 QString dn; 00154 for ( int i = depth; i >= 0; i-- ) { 00155 dn += rdns.at( rdns.size() - 1 - i ) + QString( "," ); 00156 kDebug() << "dn =" << dn; 00157 } 00158 dn = dn.left( dn.length() - 1 ); // Strip off the extraneous comma 00159 00160 return dn; 00161 } 00162 00163 QString LdapDN::rdnString() const 00164 { 00166 QStringList rdns = d->splitOnNonEscapedChar( d->m_dn, QChar( ',' ) ); 00167 return rdns.at( 0 ); 00168 } 00169 00170 QString LdapDN::rdnString( int depth ) const 00171 { 00172 QStringList rdns = d->splitOnNonEscapedChar( d->m_dn, QChar( ',' ) ); 00173 if ( depth >= rdns.size() ) { 00174 return QString(); 00175 } 00176 return rdns.at( rdns.size() - 1 - depth ); 00177 } 00178 00179 bool LdapDN::isValid() const 00180 { 00181 kDebug() << "Testing dn:" << d->m_dn; 00182 00183 // Break the string into rdn's 00184 const QStringList rdns = d->splitOnNonEscapedChar( d->m_dn, QChar( ',' ) ); 00185 00186 // Test to see if each rdn is valid 00187 const int rdnsSize( rdns.size() ); 00188 for ( int i = 0; i < rdnsSize; i++ ) { 00189 if ( !d->isValidRDNString( rdns.at( i ) ) ) { 00190 return false; 00191 } 00192 } 00193 00194 return true; 00195 } 00196 00197 int LdapDN::depth() const 00198 { 00199 QStringList rdns = d->splitOnNonEscapedChar( d->m_dn, QChar( ',' ) ); 00200 return rdns.size(); 00201 } 00202 00203 bool LdapDN::operator == ( const LdapDN &rhs ) const 00204 { 00205 return d->m_dn == rhs.d->m_dn; 00206 } 00207 00208 bool LdapDN::operator != ( const LdapDN &rhs ) const 00209 { 00210 return d->m_dn != rhs.d->m_dn; 00211 }