kabc Library API Documentation

resourceldap.cpp

00001 /* 00002 This file is part of libkabc. 00003 Copyright (c) 2002 Tobias Koenig <tokoe@kde.org> 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., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, USA. 00019 */ 00020 00021 #include <kdebug.h> 00022 #include <kglobal.h> 00023 #include <klineedit.h> 00024 #include <klocale.h> 00025 #include <kconfig.h> 00026 #include <kstringhandler.h> 00027 00028 #include <stdlib.h> 00029 00030 #include "resourceldap.h" 00031 #include "resourceldapconfig.h" 00032 00033 using namespace KABC; 00034 00035 void addModOp( LDAPMod ***pmods, const QString &attr, const QString &value ); 00036 00037 ResourceLDAP::ResourceLDAP( const KConfig *config ) 00038 : Resource( config ), mLdap( 0 ) 00039 { 00040 if ( config ) { 00041 QMap<QString, QString> attrList; 00042 QStringList attributes = config->readListEntry( "LdapAttributes" ); 00043 for ( uint pos = 0; pos < attributes.count(); pos += 2 ) 00044 attrList.insert( attributes[ pos ], attributes[ pos + 1 ] ); 00045 00046 init( config->readEntry( "LdapUser" ), 00047 KStringHandler::obscure( config->readEntry( "LdapPassword" ) ), 00048 config->readEntry( "LdapDn" ), 00049 config->readEntry( "LdapHost" ), 00050 config->readNumEntry( "LdapPort", 389 ), 00051 config->readEntry( "LdapFilter" ), 00052 config->readBoolEntry( "LdapAnonymous" ), 00053 attrList ); 00054 } else { 00055 init( "", "", "", "", 389, "", true, QMap<QString, QString>() ); 00056 } 00057 } 00058 00059 ResourceLDAP::ResourceLDAP( const QString &user, const QString &passwd, 00060 const QString &dn, const QString &host, 00061 int port, const QString &filter, bool anonymous, 00062 const QMap<QString, QString> &attributes ) 00063 : Resource( 0 ), mLdap( 0 ) 00064 { 00065 init( user, passwd, dn, host, port, filter, anonymous, attributes ); 00066 } 00067 00068 void ResourceLDAP::init( const QString &user, const QString &passwd, 00069 const QString &dn, const QString &host, 00070 int port, const QString &filter, bool anonymous, 00071 const QMap<QString, QString> &attributes ) 00072 { 00073 mUser = user; 00074 mPassword = passwd; 00075 mDn = dn; 00076 mHost = host; 00077 mPort = port; 00078 mFilter = filter; 00079 mAnonymous = anonymous; 00080 00087 if ( attributes.count() == 0 ) { 00088 mAttributes.insert( "commonName", "cn" ); 00089 mAttributes.insert( "formattedName", "displayName" ); 00090 mAttributes.insert( "familyName", "sn" ); 00091 mAttributes.insert( "givenName", "givenName" ); 00092 mAttributes.insert( "mail", "mail" ); 00093 mAttributes.insert( "mailAlias", "" ); 00094 mAttributes.insert( "phoneNumber", "telephoneNumber" ); 00095 mAttributes.insert( "uid", "uid" ); 00096 } else { 00097 mAttributes = attributes; 00098 } 00099 } 00100 00101 void ResourceLDAP::writeConfig( KConfig *config ) 00102 { 00103 Resource::writeConfig( config ); 00104 00105 config->writeEntry( "LdapUser", mUser ); 00106 config->writeEntry( "LdapPassword", KStringHandler::obscure( mPassword ) ); 00107 config->writeEntry( "LdapDn", mDn ); 00108 config->writeEntry( "LdapHost", mHost ); 00109 config->writeEntry( "LdapPort", mPort ); 00110 config->writeEntry( "LdapFilter", mFilter ); 00111 config->writeEntry( "LdapAnonymous", mAnonymous ); 00112 00113 QStringList attributes; 00114 QMap<QString, QString>::Iterator it; 00115 for ( it = mAttributes.begin(); it != mAttributes.end(); ++it ) 00116 attributes << it.key() << it.data(); 00117 00118 config->writeEntry( "LdapAttributes", attributes ); 00119 } 00120 00121 Ticket *ResourceLDAP::requestSaveTicket() 00122 { 00123 if ( !addressBook() ) { 00124 kdDebug(5700) << "no addressbook" << endl; 00125 return 0; 00126 } 00127 00128 return createTicket( this ); 00129 } 00130 00131 void ResourceLDAP::releaseSaveTicket( Ticket *ticket ) 00132 { 00133 delete ticket; 00134 } 00135 00136 bool ResourceLDAP::doOpen() 00137 { 00138 if ( mLdap ) 00139 return false; 00140 00141 if ( !mPort ) 00142 mPort = 389; 00143 00144 mLdap = ldap_init( mHost.local8Bit(), mPort ); 00145 if ( !mLdap ) { 00146 addressBook()->error( i18n( "Unable to connect to server '%1' on port '%2'" ).arg( mHost ).arg( mPort ) ); 00147 return false; 00148 } 00149 00150 if ( !mUser.isEmpty() && !mAnonymous ) { 00151 if ( ldap_simple_bind_s( mLdap, mUser.local8Bit(), mPassword.local8Bit() ) != LDAP_SUCCESS ) { 00152 addressBook()->error( i18n( "Unable to bind to server '%1'" ).arg( mHost ) ); 00153 return false; 00154 } 00155 00156 kdDebug(5700) << "ResourceLDAP: bind to server successfully" << endl; 00157 } else { 00158 if ( ldap_simple_bind_s( mLdap, NULL, NULL ) != LDAP_SUCCESS ) { 00159 addressBook()->error( i18n( "Unable to bind anonymously to server '%1'" ).arg( mHost ) ); 00160 return false; 00161 } 00162 00163 kdDebug( 5700 ) << "ResourceLDAP: bind anonymously to server successfully" << endl; 00164 } 00165 00166 int deref = LDAP_DEREF_ALWAYS; 00167 if ( ldap_set_option( mLdap, LDAP_OPT_DEREF, (void *) &deref ) != LDAP_OPT_SUCCESS ) { 00168 kdDebug(5700) << "ResourceLDAP: can't set 'deref' option" << endl; 00169 return false; 00170 } 00171 00172 if ( ldap_set_option( mLdap, LDAP_OPT_REFERRALS, LDAP_OPT_ON ) != LDAP_OPT_SUCCESS ) { 00173 kdDebug(5700) << "ResourceLDAP: can't set 'referrals' option" << endl; 00174 return false; 00175 } 00176 00177 return true; 00178 } 00179 00180 void ResourceLDAP::doClose() 00181 { 00182 if ( ldap_unbind_s( mLdap ) != LDAP_SUCCESS ) { 00183 kdDebug(5700) << "ResourceLDAP: can't unbind from server" << endl; 00184 return; 00185 } 00186 00187 mLdap = 0; 00188 } 00189 00190 bool ResourceLDAP::load() 00191 { 00192 LDAPMessage *res; 00193 LDAPMessage *msg; 00194 BerElement *track; 00195 char *names; 00196 char **values; 00197 00198 char **LdapSearchAttr = new char*[ mAttributes.count() + 1 ]; 00199 00200 QMap<QString, QString>::Iterator it; 00201 int i = 0; 00202 for ( it = mAttributes.begin(); it != mAttributes.end(); ++it ) { 00203 if ( !it.data().isEmpty() ) { 00204 unsigned int len = it.data().utf8().length(); 00205 LdapSearchAttr[ i ] = new char[ len+1 ]; 00206 memcpy( LdapSearchAttr[ i ], it.data().utf8(), len ); 00207 LdapSearchAttr[ i ][ len ] = 0; 00208 ++i; 00209 } 00210 } 00211 LdapSearchAttr[ i ] = 0; 00212 00213 QString filter = mFilter; 00214 if ( filter.isEmpty() ) 00215 filter = "cn=*"; 00216 00217 int result; 00218 if ( ( result = ldap_search_s( mLdap, mDn.local8Bit(), LDAP_SCOPE_SUBTREE, QString( "(%1)" ).arg( filter ).local8Bit(), 00219 LdapSearchAttr, 0, &res ) != LDAP_SUCCESS ) ) { 00220 addressBook()->error( i18n( "Unable to search on server '%1': %2" ) 00221 .arg( mHost ) 00222 .arg( ldap_err2string( result ) ) ); 00223 00224 for ( i = 0; LdapSearchAttr[ i ]; ++i ) 00225 delete [] LdapSearchAttr[ i ]; 00226 delete [] LdapSearchAttr; 00227 00228 return false; 00229 } 00230 00231 for ( msg = ldap_first_entry( mLdap, res ); msg; msg = ldap_next_entry( mLdap, msg ) ) { 00232 Addressee addr; 00233 addr.setResource( this ); 00234 for ( names = ldap_first_attribute( mLdap, msg, &track ); names; names = ldap_next_attribute( mLdap, msg, track ) ) { 00235 values = ldap_get_values( mLdap, msg, names ); 00236 for ( int i = 0; i < ldap_count_values( values ); ++i ) { 00237 QString name = QString::fromUtf8( names ).lower(); 00238 QString value = QString::fromUtf8( values[ i ] ); 00239 00240 if ( name == mAttributes[ "commonName" ].lower() ) { 00241 if ( !addr.formattedName().isEmpty() ) { 00242 QString fn = addr.formattedName(); 00243 addr.setNameFromString( value ); 00244 addr.setFormattedName( fn ); 00245 } else 00246 addr.setNameFromString( value ); 00247 } else if ( name == mAttributes[ "formattedName" ].lower() ) { 00248 addr.setFormattedName( value ); 00249 } else if ( name == mAttributes[ "givenName" ].lower() ) { 00250 addr.setGivenName( value ); 00251 } else if ( name == mAttributes[ "mail" ].lower() ) { 00252 addr.insertEmail( value, true ); 00253 } else if ( name == mAttributes[ "mailAlias" ].lower() ) { 00254 addr.insertEmail( value, false ); 00255 } else if ( name == mAttributes[ "phoneNumber" ].lower() ) { 00256 PhoneNumber phone; 00257 phone.setNumber( value ); 00258 addr.insertPhoneNumber( phone ); 00259 break; // read only the home number 00260 } else if ( name == mAttributes[ "familyName" ].lower() ) { 00261 addr.setFamilyName( value ); 00262 } else if ( name == mAttributes[ "uid" ].lower() ) { 00263 addr.setUid( value ); 00264 } 00265 } 00266 ldap_value_free( values ); 00267 } 00268 ber_free( track, 0 ); 00269 00270 addressBook()->insertAddressee( addr ); 00271 } 00272 00273 ldap_msgfree( res ); 00274 00275 for ( i = 0; LdapSearchAttr[ i ]; ++i ) 00276 delete [] LdapSearchAttr[ i ]; 00277 delete [] LdapSearchAttr; 00278 00279 return true; 00280 } 00281 00282 bool ResourceLDAP::asyncLoad() 00283 { 00284 bool ok = load(); 00285 if ( !ok ) 00286 emit loadingError( this, i18n( "Loading resource '%1' failed!" ) 00287 .arg( resourceName() ) ); 00288 else 00289 emit loadingFinished( this ); 00290 00291 return ok; 00292 } 00293 00294 bool ResourceLDAP::save( Ticket* ) 00295 { 00296 AddressBook::Iterator it; 00297 for ( it = addressBook()->begin(); it != addressBook()->end(); ++it ) { 00298 if ( (*it).resource() == this && (*it).changed() ) { 00299 LDAPMod **mods = NULL; 00300 00301 addModOp( &mods, "objectClass", "organizationalPerson" ); 00302 addModOp( &mods, "objectClass", "person" ); 00303 addModOp( &mods, "objectClass", "Top" ); 00304 addModOp( &mods, mAttributes[ "commonName" ].utf8(), (*it).assembledName() ); 00305 addModOp( &mods, mAttributes[ "formattedName" ].utf8(), (*it).formattedName() ); 00306 addModOp( &mods, mAttributes[ "givenName" ].utf8(), (*it).givenName() ); 00307 addModOp( &mods, mAttributes[ "familyName" ].utf8(), (*it).familyName() ); 00308 addModOp( &mods, mAttributes[ "uid" ].utf8(), (*it).uid() ); 00309 00310 QStringList emails = (*it).emails(); 00311 QStringList::ConstIterator mailIt; 00312 bool first = true; 00313 for ( mailIt = emails.begin(); mailIt != emails.end(); ++mailIt ) { 00314 if ( first ) { 00315 addModOp( &mods, mAttributes[ "mail" ].utf8(), (*mailIt) ); 00316 first = false; 00317 } else 00318 addModOp( &mods, mAttributes[ "mailAlias" ].utf8(), (*mailIt) ); 00319 } 00320 00321 PhoneNumber number = (*it).phoneNumber( PhoneNumber::Home ); 00322 addModOp( &mods, mAttributes[ "phoneNumber" ].utf8(), number.number() ); 00323 00324 QString dn = "cn=" + (*it).assembledName() + "," + mDn; 00325 00326 int retval; 00327 if ( (retval = ldap_add_s( mLdap, dn.local8Bit(), mods )) != LDAP_SUCCESS ) 00328 addressBook()->error( i18n( "Unable to modify '%1' on server '%2'" ).arg( (*it).uid() ).arg( mHost ) ); 00329 00330 ldap_mods_free( mods, 1 ); 00331 00332 // mark as unchanged 00333 (*it).setChanged( false ); 00334 } 00335 } 00336 00337 return true; 00338 } 00339 00340 bool ResourceLDAP::asyncSave( Ticket *ticket ) 00341 { 00342 bool ok = save( ticket ); 00343 if ( !ok ) 00344 emit savingError( this, i18n( "Saving resource '%1' failed!" ) 00345 .arg( resourceName() ) ); 00346 else 00347 emit savingFinished( this ); 00348 00349 return ok; 00350 } 00351 00352 void ResourceLDAP::removeAddressee( const Addressee &addr ) 00353 { 00354 LDAPMessage *res; 00355 LDAPMessage *msg; 00356 00357 QString filter = QString( "(&(uid=%1)(%2))" ).arg( addr.uid() ).arg( mFilter ); 00358 00359 kdDebug(5700) << "ldap:removeAddressee" << filter << endl; 00360 00361 ldap_search_s( mLdap, mDn.local8Bit(), LDAP_SCOPE_SUBTREE, filter.local8Bit(), 00362 0, 0, &res ); 00363 00364 bool ok = true; 00365 for ( msg = ldap_first_entry( mLdap, res ); msg; msg = ldap_next_entry( mLdap, msg ) ) { 00366 char *dn = ldap_get_dn( mLdap, msg ); 00367 kdDebug(5700) << "found " << dn << endl; 00368 if ( ldap_delete_s( mLdap, dn ) != LDAP_SUCCESS ) { 00369 addressBook()->error( i18n( "Unable to delete '%1' on server '%2'" ).arg( dn ).arg( mHost ) ); 00370 ok = false; 00371 } 00372 00373 ldap_memfree( dn ); 00374 } 00375 00376 ldap_msgfree( res ); 00377 00378 if ( ok ) 00379 mAddrMap.erase( addr.uid() ); 00380 } 00381 00382 void ResourceLDAP::setUser( const QString &user ) 00383 { 00384 mUser = user; 00385 } 00386 00387 QString ResourceLDAP::user() const 00388 { 00389 return mUser; 00390 } 00391 00392 void ResourceLDAP::setPassword( const QString &password ) 00393 { 00394 mPassword = password; 00395 } 00396 00397 QString ResourceLDAP::password() const 00398 { 00399 return mPassword; 00400 } 00401 00402 void ResourceLDAP::setDn( const QString &dn ) 00403 { 00404 mDn = dn; 00405 } 00406 00407 QString ResourceLDAP::dn() const 00408 { 00409 return mDn; 00410 } 00411 00412 void ResourceLDAP::setHost( const QString &host ) 00413 { 00414 mHost = host; 00415 } 00416 00417 QString ResourceLDAP::host() const 00418 { 00419 return mHost; 00420 } 00421 00422 void ResourceLDAP::setPort( int port ) 00423 { 00424 mPort = port; 00425 } 00426 00427 int ResourceLDAP::port() const 00428 { 00429 return mPort; 00430 } 00431 00432 void ResourceLDAP::setFilter( const QString &filter ) 00433 { 00434 mFilter = filter; 00435 } 00436 00437 QString ResourceLDAP::filter() const 00438 { 00439 return mFilter; 00440 } 00441 00442 void ResourceLDAP::setIsAnonymous( bool value ) 00443 { 00444 mAnonymous = value; 00445 } 00446 00447 bool ResourceLDAP::isAnonymous() const 00448 { 00449 return mAnonymous; 00450 } 00451 00452 void ResourceLDAP::setAttributes( const QMap<QString, QString> &attributes ) 00453 { 00454 mAttributes = attributes; 00455 } 00456 00457 QMap<QString, QString> ResourceLDAP::attributes() const 00458 { 00459 return mAttributes; 00460 } 00461 00462 void addModOp( LDAPMod ***pmods, const QString &attr, const QString &value ) 00463 { 00464 if ( value.isNull() ) 00465 return; 00466 00467 LDAPMod **mods; 00468 00469 mods = *pmods; 00470 00471 uint i = 0; 00472 if ( mods != 0 ) 00473 for ( ; mods[ i ] != 0; ++i ); 00474 00475 if (( mods = (LDAPMod **)realloc( mods, (i + 2) * sizeof( LDAPMod * ))) == 0 ) { 00476 kdError() << "ResourceLDAP: realloc" << endl; 00477 return; 00478 } 00479 00480 *pmods = mods; 00481 mods[ i + 1 ] = 0; 00482 00483 mods[ i ] = new LDAPMod; 00484 00485 mods[ i ]->mod_op = 0; 00486 mods[ i ]->mod_type = strdup( attr.utf8() ); 00487 mods[ i ]->mod_values = new char*[ 2 ]; 00488 mods[ i ]->mod_values[ 0 ] = strdup( value.utf8() ); 00489 mods[ i ]->mod_values[ 1 ] = 0; 00490 } 00491
KDE Logo
This file is part of the documentation for kabc Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 16 17:23:26 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003