kabc Library API Documentation

ldapclient.cpp

00001 /* kldapclient.cpp - LDAP access
00002  *      Copyright (C) 2002 Klarälvdalens Datakonsult AB
00003  *
00004  *      Author: Steffen Hansen <hansen@kde.org>
00005  *
00006  *      Ported to KABC by Daniel Molkentin <molkentin@kde.org>
00007  *
00008  * This file is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This file is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
00021  */
00022 
00023 
00024 
00025 #include <qfile.h>
00026 #include <qimage.h>
00027 #include <qlabel.h>
00028 #include <qpixmap.h>
00029 #include <qtextstream.h>
00030 #include <qurl.h>
00031 
00032 #include <kapplication.h>
00033 #include <kconfig.h>
00034 #include <kdebug.h>
00035 #include <kmdcodec.h>
00036 #include <kprotocolinfo.h>
00037 
00038 #include "ldapclient.h"
00039 #include "ldif.h"
00040 #include "ldapurl.h"
00041 
00042 using namespace KABC;
00043 
00044 class LdapClient::LdapClientPrivate{
00045 public:
00046   QString bindDN;
00047   QString pwdBindDN;
00048   LDIF ldif;
00049 };
00050 
00051 QString LdapObject::toString() const
00052 {
00053   QString result = QString::fromLatin1( "\ndn: %1\n" ).arg( dn );
00054   for ( LdapAttrMap::ConstIterator it = attrs.begin(); it != attrs.end(); ++it ) {
00055     QString attr = it.key();
00056     for ( LdapAttrValue::ConstIterator it2 = (*it).begin(); it2 != (*it).end(); ++it2 ) {
00057       result += QString::fromUtf8( LDIF::assembleLine( attr, *it2, 76 ) ) + "\n";
00058     }
00059   }
00060 
00061   return result;
00062 }
00063 
00064 void LdapObject::clear()
00065 {
00066   dn = QString::null;
00067   attrs.clear();
00068 }
00069 
00070 void LdapObject::assign( const LdapObject& that )
00071 {
00072   if ( &that != this ) {
00073     dn = that.dn;
00074     attrs = that.attrs;
00075     client = that.client;
00076   }
00077 }
00078 
00079 LdapClient::LdapClient( QObject* parent, const char* name )
00080   : QObject( parent, name ), mJob( 0 ), mActive( false )
00081 {
00082   d = new LdapClientPrivate;
00083 }
00084 
00085 LdapClient::~LdapClient()
00086 {
00087   cancelQuery();
00088   delete d; d = 0;
00089 }
00090 
00091 void LdapClient::setHost( const QString& host )
00092 {
00093   mHost = host;
00094 }
00095 
00096 void LdapClient::setPort( const QString& port )
00097 {
00098   mPort = port;
00099 }
00100 
00101 void LdapClient::setBase( const QString& base )
00102 {
00103   mBase = base;
00104 }
00105 
00106 void LdapClient::setBindDN( const QString& bindDN )
00107 {
00108   d->bindDN = bindDN;
00109 }
00110 
00111 void LdapClient::setPwdBindDN( const QString& pwdBindDN )
00112 {
00113   d->pwdBindDN = pwdBindDN;
00114 }
00115 
00116 void LdapClient::setAttrs( const QStringList& attrs )
00117 {
00118   mAttrs = attrs;
00119 }
00120 
00121 void LdapClient::startQuery( const QString& filter )
00122 {
00123   cancelQuery();
00124   LDAPUrl url;
00125 
00126   url.setProtocol( "ldap" );
00127   url.setUser( d->bindDN );
00128   url.setPass( d->pwdBindDN );
00129   url.setHost( mHost );
00130   url.setPort( mPort.toUInt() );
00131   url.setDn( mBase );
00132   url.setAttributes( mAttrs );
00133   url.setScope( mScope == "one" ? LDAPUrl::One : LDAPUrl::Sub );
00134   url.setFilter( "("+filter+")" );
00135 
00136   kdDebug(5700) << "Doing query: " << url.prettyURL() << endl;
00137 
00138   startParseLDIF();
00139   mActive = true;
00140   mJob = KIO::get( url, false, false );
00141   connect( mJob, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
00142            this, SLOT( slotData( KIO::Job*, const QByteArray& ) ) );
00143   connect( mJob, SIGNAL( infoMessage( KIO::Job*, const QString& ) ),
00144            this, SLOT( slotInfoMessage( KIO::Job*, const QString& ) ) );
00145   connect( mJob, SIGNAL( result( KIO::Job* ) ),
00146            this, SLOT( slotDone() ) );
00147 }
00148 
00149 void LdapClient::cancelQuery()
00150 {
00151   if ( mJob ) {
00152     mJob->kill();
00153     mJob = 0;
00154   }
00155 
00156   mActive = false;
00157 }
00158 
00159 void LdapClient::slotData( KIO::Job*, const QByteArray& data )
00160 {
00161 #ifndef NDEBUG // don't create the QString
00162 //  QString str( data );
00163 //  kdDebug(5700) << "LdapClient: Got \"" << str << "\"\n";
00164 #endif
00165   parseLDIF( data );
00166 }
00167 
00168 void LdapClient::slotInfoMessage( KIO::Job*, const QString & )
00169 {
00170   //qDebug("Job said \"%s\"", info.latin1());
00171 }
00172 
00173 void LdapClient::slotDone()
00174 {
00175   endParseLDIF();
00176   mActive = false;
00177 #if 0
00178   for ( QValueList<LdapObject>::Iterator it = mObjects.begin(); it != mObjects.end(); ++it ) {
00179     qDebug( (*it).toString().latin1() );
00180   }
00181 #endif
00182   int err = mJob->error();
00183   if ( err && err != KIO::ERR_USER_CANCELED ) {
00184     emit error( KIO::buildErrorString( err, QString("%1:%2").arg( mHost ).arg( mPort ) ) );
00185   }
00186   emit done();
00187 }
00188 
00189 void LdapClient::startParseLDIF()
00190 {
00191   mCurrentObject.clear();
00192   mLastAttrName  = 0;
00193   mLastAttrValue = 0;
00194   mIsBase64 = false;
00195   d->ldif.startParsing();
00196 }
00197 
00198 void LdapClient::endParseLDIF()
00199 {
00200 }
00201 
00202 void LdapClient::parseLDIF( const QByteArray& data )
00203 {
00204   if ( data.size() ) {
00205     d->ldif.setLDIF( data );
00206   } else {
00207     d->ldif.endLDIF();
00208   }
00209 
00210   LDIF::ParseVal ret;
00211   QString name;
00212   QByteArray value;
00213   do {
00214     ret = d->ldif.nextItem();
00215     switch ( ret ) {
00216       case LDIF::Item:
00217         name = d->ldif.attr();
00218         value = d->ldif.val();
00219         mCurrentObject.attrs[ name ].append( value );
00220         break;
00221      case LDIF::EndEntry:
00222         mCurrentObject.dn = d->ldif.dn();
00223         mCurrentObject.client = this;
00224         emit result( mCurrentObject );
00225         mCurrentObject.clear();
00226         break;
00227       default:
00228         break;
00229     }
00230   } while ( ret != LDIF::MoreData );
00231 }
00232 
00233 QString LdapClient::bindDN() const
00234 {
00235   return d->bindDN;
00236 }
00237 
00238 QString LdapClient::pwdBindDN() const
00239 {
00240   return d->pwdBindDN;
00241 }
00242 
00243 LdapSearch::LdapSearch()
00244     : mActiveClients( 0 ), mNoLDAPLookup( false )
00245 {
00246   if ( !KProtocolInfo::isKnownProtocol( KURL("ldap://localhost") ) ) {
00247     mNoLDAPLookup = true;
00248     return;
00249   }
00250 
00251   // stolen from KAddressBook
00252   KConfig config( "kabldaprc", true );
00253   config.setGroup( "LDAP" );
00254   int numHosts = config.readUnsignedNumEntry( "NumSelectedHosts");
00255   if ( !numHosts ) {
00256     mNoLDAPLookup = true;
00257     return;
00258   } else {
00259     for ( int j = 0; j < numHosts; j++ ) {
00260       LdapClient* ldapClient = new LdapClient( this );
00261 
00262       QString host =  config.readEntry( QString( "SelectedHost%1" ).arg( j ), "" ).stripWhiteSpace();
00263       if ( !host.isEmpty() )
00264         ldapClient->setHost( host );
00265 
00266       QString port = QString::number( config.readUnsignedNumEntry( QString( "SelectedPort%1" ).arg( j ) ) );
00267       if ( !port.isEmpty() )
00268         ldapClient->setPort( port );
00269 
00270       QString base = config.readEntry( QString( "SelectedBase%1" ).arg( j ), "" ).stripWhiteSpace();
00271       if ( !base.isEmpty() )
00272         ldapClient->setBase( base );
00273 
00274       QString bindDN = config.readEntry( QString( "SelectedBind%1" ).arg( j ) ).stripWhiteSpace();
00275       if ( !bindDN.isEmpty() )
00276         ldapClient->setBindDN( bindDN );
00277 
00278       QString pwdBindDN = config.readEntry( QString( "SelectedPwdBind%1" ).arg( j ) );
00279       if ( !pwdBindDN.isEmpty() )
00280         ldapClient->setPwdBindDN( pwdBindDN );
00281 
00282       QStringList attrs;
00283       attrs << "cn" << "mail" << "givenname" << "sn";
00284       ldapClient->setAttrs( attrs );
00285 
00286       connect( ldapClient, SIGNAL( result( const KABC::LdapObject& ) ),
00287                this, SLOT( slotLDAPResult( const KABC::LdapObject& ) ) );
00288       connect( ldapClient, SIGNAL( done() ),
00289                this, SLOT( slotLDAPDone() ) );
00290       connect( ldapClient, SIGNAL( error( const QString& ) ),
00291                this, SLOT( slotLDAPError( const QString& ) ) );
00292 
00293       mClients.append( ldapClient );
00294     }
00295   }
00296 
00297   connect( &mDataTimer, SIGNAL( timeout() ), SLOT( slotDataTimer() ) );
00298 }
00299 
00300 void LdapSearch::startSearch( const QString& txt )
00301 {
00302   if ( mNoLDAPLookup )
00303     return;
00304 
00305   cancelSearch();
00306 
00307   int pos = txt.find( '\"' );
00308   if( pos >= 0 )
00309   {
00310     ++pos;
00311     int pos2 = txt.find( '\"', pos );
00312     if( pos2 >= 0 )
00313         mSearchText = txt.mid( pos , pos2 - pos );
00314     else
00315         mSearchText = txt.mid( pos );
00316   } else
00317     mSearchText = txt;
00318 
00319   QString filter = QString( "|(cn=%1*)(mail=%2*)(givenName=%3*)(sn=%4*)" )
00320       .arg( mSearchText ).arg( mSearchText ).arg( mSearchText ).arg( mSearchText );
00321 
00322   QValueList< LdapClient* >::Iterator it;
00323   for ( it = mClients.begin(); it != mClients.end(); ++it ) {
00324     (*it)->startQuery( filter );
00325     ++mActiveClients;
00326   }
00327 }
00328 
00329 void LdapSearch::cancelSearch()
00330 {
00331   QValueList< LdapClient* >::Iterator it;
00332   for ( it = mClients.begin(); it != mClients.end(); ++it )
00333     (*it)->cancelQuery();
00334 
00335   mActiveClients = 0;
00336   mResults.clear();
00337 }
00338 
00339 void LdapSearch::slotLDAPResult( const KABC::LdapObject& obj )
00340 {
00341   mResults.append( obj );
00342   if ( !mDataTimer.isActive() )
00343     mDataTimer.start( 500, true );
00344 }
00345 
00346 void LdapSearch::slotLDAPError( const QString& )
00347 {
00348   slotLDAPDone();
00349 }
00350 
00351 void LdapSearch::slotLDAPDone()
00352 {
00353   if ( --mActiveClients > 0 )
00354     return;
00355 
00356   finish();
00357 }
00358 
00359 void LdapSearch::slotDataTimer()
00360 {
00361   QStringList lst;
00362   LdapResultList reslist;
00363   makeSearchData( lst, reslist );
00364   if ( !lst.isEmpty() )
00365     emit searchData( lst );
00366   if ( !reslist.isEmpty() )
00367     emit searchData( reslist );
00368 }
00369 
00370 void LdapSearch::finish()
00371 {
00372   mDataTimer.stop();
00373 
00374   slotDataTimer(); // emit final bunch of data
00375   emit searchDone();
00376 }
00377 
00378 void LdapSearch::makeSearchData( QStringList& ret, LdapResultList& resList )
00379 {
00380   QString search_text_upper = mSearchText.upper();
00381 
00382   QValueList< KABC::LdapObject >::ConstIterator it1;
00383   for ( it1 = mResults.begin(); it1 != mResults.end(); ++it1 ) {
00384     QString name, mail, givenname, sn;
00385 
00386     LdapAttrMap::ConstIterator it2;
00387     for ( it2 = (*it1).attrs.begin(); it2 != (*it1).attrs.end(); ++it2 ) {
00388       QString tmp = QString::fromUtf8( (*it2).first(), (*it2).first().size() );
00389       if ( it2.key() == "cn" )
00390         name = tmp; // TODO loop?
00391       else if( it2.key() == "mail" )
00392         mail = tmp;
00393       else if( it2.key() == "givenName" )
00394         givenname = tmp;
00395       else if( it2.key() == "sn" )
00396         sn = tmp;
00397     }
00398 
00399     if( mail.isEmpty())
00400       continue; // nothing, bad entry
00401     else if ( name.isEmpty() )
00402       ret.append( mail );
00403     else {
00404       kdDebug(5700) << "<" << name << "><" << mail << ">" << endl;
00405       ret.append( QString( "%1 <%2>" ).arg( name ).arg( mail ) );
00406     }
00407 
00408     LdapResult sr;
00409     sr.clientNumber = mClients.findIndex( (*it1).client );
00410     sr.name = name;
00411     sr.email = mail;
00412     resList.append( sr );
00413   }
00414 
00415   mResults.clear();
00416 }
00417 
00418 bool LdapSearch::isAvailable() const
00419 {
00420   return !mNoLDAPLookup;
00421 }
00422 
00423 
00424 
00425 #include "ldapclient.moc"
KDE Logo
This file is part of the documentation for kabc Library Version 3.3.90.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 30 10:21:07 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003