00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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;
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
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