From b9aad1f15dc600e4dbe4c62d3fcced6363188ba3 Mon Sep 17 00:00:00 2001 From: zautrix Date: Sat, 26 Jun 2004 19:01:18 +0000 Subject: Initial revision --- (limited to 'kabc/plugins/ldap/resourceldap.cpp') diff --git a/kabc/plugins/ldap/resourceldap.cpp b/kabc/plugins/ldap/resourceldap.cpp new file mode 100644 index 0000000..1c54f63 --- a/dev/null +++ b/kabc/plugins/ldap/resourceldap.cpp @@ -0,0 +1,444 @@ +/* + This file is part of libkabc. + Copyright (c) 2002 Tobias Koenig + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/* +Enhanced Version of the file for platform independent KDE tools. +Copyright (c) 2004 Ulf Schenk + +$Id$ +*/ + +#include +#include +#include +#include +#include +#include + +#include + +#include "resourceldap.h" +#include "resourceldapconfig.h" + +using namespace KABC; + +extern "C" +{ + void *init_kabc_ldap() + { + qDebug("resourceldap.cpp : init_kabc_ldap has to be changed"); +//US return new KRES::PluginFactory(); + } +} + +void addModOp( LDAPMod ***pmods, const QString &attr, const QString &value ); + + +ResourceLDAP::ResourceLDAP( const KConfig *config ) + : Resource( config ), mPort( 389 ), mLdap( 0 ) +{ + KConfig *cfg = (KConfig *)config; + if ( cfg ) { + mUser = cfg->readEntry( "LdapUser" ); + mPassword = KStringHandler::obscure( cfg->readEntry( "LdapPassword" ) ); + mDn = cfg->readEntry( "LdapDn" ); + mHost = cfg->readEntry( "LdapHost" ); + mPort = cfg->readNumEntry( "LdapPort", 389 ); + mFilter = cfg->readEntry( "LdapFilter" ); + mAnonymous = cfg->readBoolEntry( "LdapAnonymous" ); + + QStringList attributes = cfg->readListEntry( "LdapAttributes" ); + for ( uint pos = 0; pos < attributes.count(); pos += 2 ) + mAttributes.insert( attributes[ pos ], attributes[ pos + 1 ] ); + } + + /** + If you want to add new attributes, append them here, add a + translation string in the ctor of AttributesDialog and + handle them in the load() method below. + These are the default values from + */ + if ( mAttributes.count() == 0 ) { + mAttributes.insert( "commonName", "cn" ); + mAttributes.insert( "formattedName", "displayName" ); + mAttributes.insert( "familyName", "sn" ); + mAttributes.insert( "givenName", "givenName" ); + mAttributes.insert( "mail", "mail" ); + mAttributes.insert( "mailAlias", "" ); + mAttributes.insert( "phoneNumber", "telephoneNumber" ); + mAttributes.insert( "uid", "uid" ); + } +} + +void ResourceLDAP::writeConfig( KConfig *config ) +{ + Resource::writeConfig( config ); + + config->writeEntry( "LdapUser", mUser ); + config->writeEntry( "LdapPassword", KStringHandler::obscure( mPassword ) ); + config->writeEntry( "LdapDn", mDn ); + config->writeEntry( "LdapHost", mHost ); + config->writeEntry( "LdapPort", mPort ); + config->writeEntry( "LdapFilter", mFilter ); + config->writeEntry( "LdapAnonymous", mAnonymous ); + + QStringList attributes; + QMap::Iterator it; + for ( it = mAttributes.begin(); it != mAttributes.end(); ++it ) + attributes << it.key() << it.data(); + + config->writeEntry( "LdapAttributes", attributes ); +} + +Ticket *ResourceLDAP::requestSaveTicket() +{ + if ( !addressBook() ) { + kdDebug(5700) << "no addressbook" << endl; + return 0; + } + + return createTicket( this ); +} + +bool ResourceLDAP::doOpen() +{ + if ( mLdap ) + return false; + + if ( !mPort ) + mPort = 389; + + mLdap = ldap_init( mHost.local8Bit(), mPort ); + if ( !mLdap ) { + addressBook()->error( i18n( "Unable to connect to server '%1' on port '%2'" ).arg( mHost ).arg( mPort ) ); + return false; + } + + if ( !mUser.isEmpty() && !mAnonymous ) { + if ( ldap_simple_bind_s( mLdap, mUser.local8Bit(), mPassword.local8Bit() ) != LDAP_SUCCESS ) { + addressBook()->error( i18n( "Unable to bind to server '%1'" ).arg( mHost ) ); + return false; + } + + kdDebug(5700) << "ResourceLDAP: bind to server successfully" << endl; + } else { + if ( ldap_simple_bind_s( mLdap, NULL, NULL ) != LDAP_SUCCESS ) { + addressBook()->error( i18n( "Unable to bind anonymously to server '%1'" ).arg( mHost ) ); + return false; + } + + kdDebug( 5700 ) << "ResourceLDAP: bind anonymously to server successfully" << endl; + } + + int deref = LDAP_DEREF_ALWAYS; + if ( ldap_set_option( mLdap, LDAP_OPT_DEREF, (void *) &deref ) != LDAP_OPT_SUCCESS ) { + kdDebug(5700) << "ResourceLDAP: can't set 'deref' option" << endl; + return false; + } + + if ( ldap_set_option( mLdap, LDAP_OPT_REFERRALS, LDAP_OPT_ON ) != LDAP_OPT_SUCCESS ) { + kdDebug(5700) << "ResourceLDAP: can't set 'referrals' option" << endl; + return false; + } + + return true; +} + +void ResourceLDAP::doClose() +{ + if ( ldap_unbind_s( mLdap ) != LDAP_SUCCESS ) { + kdDebug(5700) << "ResourceLDAP: can't unbind from server" << endl; + return; + } + + mLdap = 0; +} + +bool ResourceLDAP::load() +{ + LDAPMessage *res; + LDAPMessage *msg; + BerElement *track; + char *names; + char **values; + + char **LdapSearchAttr = new char*[ mAttributes.count() + 1 ]; + + QMap::Iterator it; + int i = 0; + for ( it = mAttributes.begin(); it != mAttributes.end(); ++it ) { + if ( !it.data().isEmpty() ) { + unsigned int len = it.data().utf8().length(); + LdapSearchAttr[ i ] = new char[ len+1 ]; + memcpy( LdapSearchAttr[ i ], it.data().utf8(), len ); + LdapSearchAttr[ i ][ len ] = 0; + ++i; + } + } + LdapSearchAttr[ i ] = 0; + + QString filter = mFilter; + if ( filter.isEmpty() ) + filter = "cn=*"; + + int result; + if ( ( result = ldap_search_s( mLdap, mDn.local8Bit(), LDAP_SCOPE_SUBTREE, QString( "(%1)" ).arg( filter ).local8Bit(), + LdapSearchAttr, 0, &res ) != LDAP_SUCCESS ) ) { + addressBook()->error( i18n( "Unable to search on server '%1': %2" ) + .arg( mHost ) + .arg( ldap_err2string( result ) ) ); + + for ( i = 0; LdapSearchAttr[ i ]; ++i ) + delete [] LdapSearchAttr[ i ]; + delete [] LdapSearchAttr; + + return false; + } + + for ( msg = ldap_first_entry( mLdap, res ); msg; msg = ldap_next_entry( mLdap, msg ) ) { + Addressee addr; + addr.setResource( this ); + for ( names = ldap_first_attribute( mLdap, msg, &track ); names; names = ldap_next_attribute( mLdap, msg, track ) ) { + values = ldap_get_values( mLdap, msg, names ); + for ( int i = 0; i < ldap_count_values( values ); ++i ) { + QString name = QString::fromUtf8( names ).lower(); + QString value = QString::fromUtf8( values[ i ] ); + + if ( name == mAttributes[ "commonName" ].lower() ) { + if ( !addr.formattedName().isEmpty() ) { + QString fn = addr.formattedName(); + addr.setNameFromString( value ); + addr.setFormattedName( fn ); + } else + addr.setNameFromString( value ); + } else if ( name == mAttributes[ "formattedName" ].lower() ) { + addr.setFormattedName( value ); + } else if ( name == mAttributes[ "givenName" ].lower() ) { + addr.setGivenName( value ); + } else if ( name == mAttributes[ "mail" ].lower() ) { + addr.insertEmail( value, true ); + } else if ( name == mAttributes[ "mailAlias" ].lower() ) { + addr.insertEmail( value, false ); + } else if ( name == mAttributes[ "phoneNumber" ].lower() ) { + PhoneNumber phone; + phone.setNumber( value ); + addr.insertPhoneNumber( phone ); + break; // read only the home number + } else if ( name == mAttributes[ "familyName" ].lower() ) { + addr.setFamilyName( value ); + } else if ( name == mAttributes[ "uid" ].lower() ) { + addr.setUid( value ); + } + } + ldap_value_free( values ); + } + ber_free( track, 0 ); + + addressBook()->insertAddressee( addr ); + } + + ldap_msgfree( res ); + + for ( i = 0; LdapSearchAttr[ i ]; ++i ) + delete [] LdapSearchAttr[ i ]; + delete [] LdapSearchAttr; + + return true; +} + +bool ResourceLDAP::save( Ticket * ) +{ + AddressBook::Iterator it; + for ( it = addressBook()->begin(); it != addressBook()->end(); ++it ) { + if ( (*it).resource() == this && (*it).changed() ) { + LDAPMod **mods = NULL; + + addModOp( &mods, "objectClass", "organizationalPerson" ); + addModOp( &mods, "objectClass", "person" ); + addModOp( &mods, "objectClass", "Top" ); + addModOp( &mods, mAttributes[ "commonName" ].utf8(), (*it).assembledName() ); + addModOp( &mods, mAttributes[ "formattedName" ].utf8(), (*it).formattedName() ); + addModOp( &mods, mAttributes[ "givenName" ].utf8(), (*it).givenName() ); + addModOp( &mods, mAttributes[ "familyName" ].utf8(), (*it).familyName() ); + addModOp( &mods, mAttributes[ "uid" ].utf8(), (*it).uid() ); + + QStringList emails = (*it).emails(); + QStringList::ConstIterator mailIt; + bool first = true; + for ( mailIt = emails.begin(); mailIt != emails.end(); ++mailIt ) { + if ( first ) { + addModOp( &mods, mAttributes[ "mail" ].utf8(), (*mailIt) ); + first = false; + } else + addModOp( &mods, mAttributes[ "mailAlias" ].utf8(), (*mailIt) ); + } + + PhoneNumber number = (*it).phoneNumber( PhoneNumber::Home ); + addModOp( &mods, mAttributes[ "phoneNumber" ].utf8(), number.number() ); + + QString dn = "cn=" + (*it).assembledName() + "," + mDn; + + int retval; + if ( (retval = ldap_add_s( mLdap, dn.local8Bit(), mods )) != LDAP_SUCCESS ) + addressBook()->error( i18n( "Unable to modify '%1' on server '%2'" ).arg( (*it).uid() ).arg( mHost ) ); + + ldap_mods_free( mods, 1 ); + + // mark as unchanged + (*it).setChanged( false ); + } + } + + return true; +} + +void ResourceLDAP::removeAddressee( const Addressee &addr ) +{ + LDAPMessage *res; + LDAPMessage *msg; + + QString filter = QString( "(&(uid=%1)(%2))" ).arg( addr.uid() ).arg( mFilter ); + + kdDebug(5700) << "ldap:removeAddressee" << filter << endl; + + ldap_search_s( mLdap, mDn.local8Bit(), LDAP_SCOPE_SUBTREE, filter.local8Bit(), + 0, 0, &res ); + + for ( msg = ldap_first_entry( mLdap, res ); msg; msg = ldap_next_entry( mLdap, msg ) ) { + char *dn = ldap_get_dn( mLdap, msg ); + kdDebug(5700) << "found " << dn << endl; + if ( ldap_delete_s( mLdap, dn ) != LDAP_SUCCESS ) + addressBook()->error( i18n( "Unable to delete '%1' on server '%2'" ).arg( dn ).arg( mHost ) ); + ldap_memfree( dn ); + } + + ldap_msgfree( res ); +} + +void ResourceLDAP::setUser( const QString &user ) +{ + mUser = user; +} + +QString ResourceLDAP::user() const +{ + return mUser; +} + +void ResourceLDAP::setPassword( const QString &password ) +{ + mPassword = password; +} + +QString ResourceLDAP::password() const +{ + return mPassword; +} + +void ResourceLDAP::setDn( const QString &dn ) +{ + mDn = dn; +} + +QString ResourceLDAP::dn() const +{ + return mDn; +} + +void ResourceLDAP::setHost( const QString &host ) +{ + mHost = host; +} + +QString ResourceLDAP::host() const +{ + return mHost; +} + +void ResourceLDAP::setPort( int port ) +{ + mPort = port; +} + +int ResourceLDAP::port() const +{ + return mPort; +} + +void ResourceLDAP::setFilter( const QString &filter ) +{ + mFilter = filter; +} + +QString ResourceLDAP::filter() const +{ + return mFilter; +} + +void ResourceLDAP::setIsAnonymous( bool value ) +{ + mAnonymous = value; +} + +bool ResourceLDAP::isAnonymous() const +{ + return mAnonymous; +} + +void ResourceLDAP::setAttributes( const QMap &attributes ) +{ + mAttributes = attributes; +} + +QMap ResourceLDAP::attributes() const +{ + return mAttributes; +} + +void addModOp( LDAPMod ***pmods, const QString &attr, const QString &value ) +{ + if ( value.isNull() ) + return; + + LDAPMod **mods; + + mods = *pmods; + + uint i = 0; + if ( mods != 0 ) + for ( ; mods[ i ] != 0; ++i ); + + if (( mods = (LDAPMod **)realloc( mods, (i + 2) * sizeof( LDAPMod * ))) == 0 ) { + kdError() << "ResourceLDAP: realloc" << endl; + return; + } + + *pmods = mods; + mods[ i + 1 ] = 0; + + mods[ i ] = new LDAPMod; + + mods[ i ]->mod_op = 0; + mods[ i ]->mod_type = strdup( attr.utf8() ); + mods[ i ]->mod_values = new char*[ 2 ]; + mods[ i ]->mod_values[ 0 ] = strdup( value.utf8() ); + mods[ i ]->mod_values[ 1 ] = 0; +} + -- cgit v0.9.0.2