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.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Apr 21 18:44:44 2004 by doxygen 1.3.6-20040222 written by Dimitri van Heesch, © 1997-2003