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
00026 #include <stdlib.h>
00027
00028 #include "resourceconfigwidget.h"
00029 #include "resourceldap.h"
00030 #include "resourceldapconfig.h"
00031
00032 using namespace KABC;
00033
00034 extern "C"
00035 {
00036 ResourceConfigWidget *config_widget( QWidget *parent ) {
00037 KGlobal::locale()->insertCatalogue("kabc_ldap");
00038 return new ResourceLDAPConfig( parent, "ResourceLDAPConfig" );
00039 }
00040
00041 Resource *resource( AddressBook *ab, const KConfig *config ) {
00042 KGlobal::locale()->insertCatalogue("kabc_ldap");
00043 return new ResourceLDAP( ab, config );
00044 }
00045 }
00046
00047 void addModOp( LDAPMod ***pmods, const QString &attr, const QString &value );
00048
00049 ResourceLDAP::ResourceLDAP( AddressBook *ab, const KConfig *config )
00050 : Resource( ab )
00051 {
00052 mLdap = 0;
00053
00054 mUser = config->readEntry( "LdapUser" );
00055 mPassword = cryptStr( config->readEntry( "LdapPassword" ) );
00056 mDn = config->readEntry( "LdapDn" );
00057 mHost = config->readEntry( "LdapHost" );
00058 mPort = config->readEntry( "LdapPort" );
00059 mFilter = config->readEntry( "LdapFilter" );
00060 mAnonymous = config->readBoolEntry( "LdapAnonymous" );
00061 }
00062
00063 ResourceLDAP::ResourceLDAP( AddressBook *ab, const QString &user,
00064 const QString &password, const QString &dn,
00065 const QString &host, const QString &port, const QString &filter,
00066 const bool anonymous )
00067 : Resource( ab )
00068 {
00069 mLdap = 0;
00070
00071 mUser = user;
00072 mPassword = password;
00073 mDn = dn;
00074 mHost = host;
00075 mPort = port;
00076 mFilter = filter;
00077 mAnonymous = anonymous;
00078 }
00079
00080 Ticket *ResourceLDAP::requestSaveTicket()
00081 {
00082 if ( !addressBook() ) {
00083 kdDebug(5700) << "no addressbook" << endl;
00084 return 0;
00085 }
00086
00087 return createTicket( this );
00088 }
00089
00090 bool ResourceLDAP::open()
00091 {
00092 if ( mLdap )
00093 return false;
00094
00095 if ( mPort.isEmpty() )
00096 mPort = "389";
00097
00098 mLdap = ldap_init( mHost.local8Bit(), mPort.toInt() );
00099 if ( !mLdap ) {
00100 addressBook()->error( i18n( "Unable to connect to server '%1' on port '%2'" ).arg( mHost ).arg( mPort ) );
00101 return false;
00102 }
00103
00104 if ( !mUser.isEmpty() && !mAnonymous ) {
00105 if ( ldap_simple_bind_s( mLdap, mUser.local8Bit(), mPassword.local8Bit() ) != LDAP_SUCCESS ) {
00106 addressBook()->error( i18n( "Unable to bind to server '%1'" ).arg( mHost ) );
00107 return false;
00108 }
00109
00110 kdDebug(5700) << "ResourceLDAP: bind to server successfully" << endl;
00111 }
00112
00113 int deref = LDAP_DEREF_ALWAYS;
00114 if ( ldap_set_option( mLdap, LDAP_OPT_DEREF, (void *) &deref ) != LDAP_OPT_SUCCESS ) {
00115 kdDebug(5700) << "ResourceLDAP: can't set 'deref' option" << endl;
00116 return false;
00117 }
00118
00119 if ( ldap_set_option( mLdap, LDAP_OPT_REFERRALS, LDAP_OPT_ON ) != LDAP_OPT_SUCCESS ) {
00120 kdDebug(5700) << "ResourceLDAP: can't set 'referrals' option" << endl;
00121 return false;
00122 }
00123
00124 return true;
00125 }
00126
00127 void ResourceLDAP::close()
00128 {
00129 if ( ldap_unbind_s( mLdap ) != LDAP_SUCCESS ) {
00130 kdDebug(5700) << "ResourceLDAP: can't unbind from server" << endl;
00131 return;
00132 }
00133
00134 mLdap = 0;
00135 }
00136
00137 bool ResourceLDAP::load()
00138 {
00139 LDAPMessage *res;
00140 LDAPMessage *msg;
00141 BerElement *track;
00142 char *names;
00143 char **values;
00144
00145 const char *LdapSearchAttr[ 9 ] = {
00146 "cn",
00147 "display-name",
00148 "givenname",
00149 "mail",
00150 "mailalias",
00151 "phoneNumber",
00152 "sn",
00153 "uid",
00154 0 };
00155
00156 if ( ldap_search_s( mLdap, mDn.local8Bit(), LDAP_SCOPE_SUBTREE, QString( "(%1)" ).arg( mFilter ).local8Bit(),
00157 (char **)LdapSearchAttr, 0, &res ) != LDAP_SUCCESS ) {
00158 addressBook()->error( i18n( "Unable to search on server '%1'" ).arg( mHost ) );
00159 return false;
00160 }
00161
00162 for ( msg = ldap_first_entry( mLdap, res ); msg; msg = ldap_next_entry( mLdap, msg ) ) {
00163 Addressee addr;
00164 addr.setResource( this );
00165 for ( names = ldap_first_attribute( mLdap, msg, &track ); names; names = ldap_next_attribute( mLdap, msg, track ) ) {
00166 values = ldap_get_values( mLdap, msg, names );
00167 for ( int i = 0; i < ldap_count_values( values ); ++i ) {
00168 QString name = QString::fromUtf8( names );
00169 QString value = QString::fromUtf8( values[ i ] );
00170
00171 if ( name == "cn" ) {
00172 if ( !addr.formattedName().isEmpty() ) {
00173 QString fn = addr.formattedName();
00174 addr.setNameFromString( value );
00175 addr.setFormattedName( fn );
00176 } else
00177 addr.setNameFromString( value );
00178 continue;
00179 }
00180 if ( name == "display-name" ) {
00181 addr.setFormattedName( value );
00182 continue;
00183 }
00184 if ( name == "givenname" ) {
00185 addr.setGivenName( value );
00186 continue;
00187 }
00188 if ( name == "mail" ) {
00189 addr.insertEmail( value, true );
00190 continue;
00191 }
00192 if ( name == "mailalias" ) {
00193 addr.insertEmail( value, false );
00194 continue;
00195 }
00196 if ( name == "phoneNumber" ) {
00197 PhoneNumber phone;
00198 phone.setNumber( value );
00199 addr.insertPhoneNumber( phone );
00200 break;
00201 }
00202 if ( name == "sn" ) {
00203 addr.setFamilyName( value );
00204 continue;
00205 }
00206 if ( name == "uid" ) {
00207 addr.setUid( value );
00208 continue;
00209 }
00210 }
00211 ldap_value_free( values );
00212 }
00213 ber_free( track, 0 );
00214
00215 addressBook()->insertAddressee( addr );
00216 }
00217
00218 ldap_msgfree( res );
00219
00220 return true;
00221 }
00222
00223 bool ResourceLDAP::save( Ticket * )
00224 {
00225 AddressBook::Iterator it;
00226 for ( it = addressBook()->begin(); it != addressBook()->end(); ++it ) {
00227 if ( (*it).resource() == this && (*it).changed() ) {
00228 LDAPMod **mods = NULL;
00229
00230 addModOp( &mods, "objectClass", "organizationalPerson" );
00231 addModOp( &mods, "objectClass", "person" );
00232 addModOp( &mods, "objectClass", "Top" );
00233 addModOp( &mods, "cn", (*it).assembledName() );
00234 addModOp( &mods, "display-name", (*it).formattedName() );
00235 addModOp( &mods, "givenname", (*it).givenName() );
00236 addModOp( &mods, "sn", (*it).familyName() );
00237 addModOp( &mods, "uid", (*it).uid() );
00238
00239 QStringList emails = (*it).emails();
00240 QStringList::ConstIterator mailIt;
00241 bool first = true;
00242 for ( mailIt = emails.begin(); mailIt != emails.end(); ++mailIt ) {
00243 if ( first ) {
00244 addModOp( &mods, "mail", (*mailIt) );
00245 first = false;
00246 } else
00247 addModOp( &mods, "mailalias", (*mailIt) );
00248 }
00249
00250 PhoneNumber number = (*it).phoneNumber( PhoneNumber::Home );
00251 addModOp( &mods, "phoneNumber", number.number() );
00252
00253 QString dn = "cn=" + (*it).assembledName() + "," + mDn;
00254
00255 int retval;
00256 if ( (retval = ldap_add_s( mLdap, dn.local8Bit(), mods )) != LDAP_SUCCESS )
00257 addressBook()->error( i18n( "Unable to modify '%1' on server '%2'" ).arg( (*it).uid() ).arg( mHost ) );
00258
00259 ldap_mods_free( mods, 1 );
00260
00261
00262 (*it).setChanged( false );
00263 }
00264 }
00265
00266 return true;
00267 }
00268
00269 void ResourceLDAP::removeAddressee( const Addressee &addr )
00270 {
00271 LDAPMessage *res;
00272 LDAPMessage *msg;
00273
00274 QString filter = QString( "(&(uid=%1)(%2))" ).arg( addr.uid() ).arg( mFilter );
00275
00276 kdDebug(5700) << "ldap:removeAddressee" << filter << endl;
00277
00278 ldap_search_s( mLdap, mDn.local8Bit(), LDAP_SCOPE_SUBTREE, filter.local8Bit(),
00279 0, 0, &res );
00280
00281 for ( msg = ldap_first_entry( mLdap, res ); msg; msg = ldap_next_entry( mLdap, msg ) ) {
00282 char *dn = ldap_get_dn( mLdap, msg );
00283 kdDebug(5700) << "found " << dn << endl;
00284 if ( ldap_delete_s( mLdap, dn ) != LDAP_SUCCESS )
00285 addressBook()->error( i18n( "Unable to delete '%1' on server '%2'" ).arg( dn ).arg( mHost ) );
00286 ldap_memfree( dn );
00287 }
00288
00289 ldap_msgfree( res );
00290 }
00291
00292 QString ResourceLDAP::identifier() const
00293 {
00294 return mHost + "_" + mPort + "_" + mDn + "_" + mFilter;
00295 }
00296
00297 void addModOp( LDAPMod ***pmods, const QString &attr, const QString &value )
00298 {
00299 if ( value.isNull() )
00300 return;
00301
00302 LDAPMod **mods;
00303
00304 mods = *pmods;
00305
00306 uint i = 0;
00307 if ( mods != 0 )
00308 for ( ; mods[ i ] != 0; ++i );
00309
00310 if (( mods = (LDAPMod **)realloc( mods, (i + 2) * sizeof( LDAPMod * ))) == 0 ) {
00311 kdError() << "ResourceLDAP: realloc" << endl;
00312 return;
00313 }
00314
00315 *pmods = mods;
00316 mods[ i + 1 ] = 0;
00317
00318 mods[ i ] = new LDAPMod;
00319
00320 mods[ i ]->mod_op = 0;
00321 mods[ i ]->mod_type = strdup( attr.utf8() );
00322 mods[ i ]->mod_values = new char*[2];
00323 mods[ i ]->mod_values[0] = strdup( value.utf8() );
00324 mods[ i ]->mod_values[1] = 0;
00325 }