# kabc Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# 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 #include <kmdcodec.h>
    00024 #include <qpixmap.h>
    00025 #include <qimage.h>
    00026 #include <qlabel.h>
    00027 #include <qfile.h>
    00028
    00029 #include <kprotocolinfo.h>
    00030 #include <kconfig.h>
    00031 #include <kapplication.h>
    00032
    00033 #include <kdebug.h>
    00034
    00035 #include "ldapclient.h"
    00036
    00037 using namespace KABC;
    00038
    00039 QString LdapObject::toString() const
    00040 {
    00041   QString result = QString::fromLatin1( "\ndn: %1\n" ).arg( dn );
    00042   for ( LdapAttrMap::ConstIterator it = attrs.begin(); it != attrs.end(); ++it ) {
    00043     QString attr = it.key();
    00044     for ( LdapAttrValue::ConstIterator it2 = (*it).begin(); it2 != (*it).end(); ++it2 ) {
    00045       if ( attr == "jpegPhoto" ) {
    00046         QByteArray buf = *it2;
    00047 #if 0
    00048         qDebug( "Trying to load image from buf with size %d", (*it2).size() );
    00049         QPixmap pix;
    00050         pix.loadFromData( buf, "JPEG" );
    00051         qDebug( "Image loaded successfully" );
    00052         QLabel* l = new QLabel( 0 );
    00053         QFile f( "tmp.jpg" );
    00054         f.open( IO_WriteOnly );
    00055         f.writeBlock( buf );
    00056         f.close();
    00057         //l->setPixmap( QPixmap("tmp.jpg") );
    00058         //l->show();
    00059 #endif
    00060       } else {
    00061         result += QString("%1: %2\n").arg( attr).arg( *it2 );
    00062       }
    00063     }
    00064   }
    00065
    00066   return result;
    00067 }
    00068
    00069 void LdapObject::clear()
    00070 {
    00071   dn = QString::null;
    00072   attrs.clear();
    00073 }
    00074
    00075 void LdapObject::assign( const LdapObject& that )
    00076 {
    00077   if ( &that != this ) {
    00078     dn = that.dn;
    00079     attrs = that.attrs;
    00080   }
    00081 }
    00082
    00083 LdapClient::LdapClient( QObject* parent, const char* name )
    00084   : QObject( parent, name ), mJob( 0 ), mActive( false )
    00085 {
    00086 }
    00087
    00088 LdapClient::~LdapClient()
    00089 {
    00090   cancelQuery();
    00091 }
    00092
    00093 void LdapClient::setHost( const QString& host )
    00094 {
    00095   mHost = host;
    00096 }
    00097
    00098 void LdapClient::setPort( const QString& port )
    00099 {
    00100   mPort = port;
    00101 }
    00102
    00103 void LdapClient::setBase( const QString& base )
    00104 {
    00105   mBase = base;
    00106 }
    00107
    00108 void LdapClient::setAttrs( const QStringList& attrs )
    00109 {
    00110   mAttrs = attrs;
    00111 }
    00112
    00113 void LdapClient::startQuery( const QString& filter )
    00114 {
    00115   cancelQuery();
    00116   QString query;
    00117   if ( mScope.isEmpty() )
    00118     mScope = "sub";
    00119
    00120   QString host = mHost;
    00121   if ( !mPort.isEmpty() ) {
    00122     host += ':';
    00123     host += mPort;
    00124   }
    00125
    00126   if ( mAttrs.empty() ) {
    00127     query = QString("ldap://%1/%2?*?%3?(%4)").arg( host ).arg( mBase ).arg( mScope ).arg( filter );
    00128   } else {
    00129     query = QString("ldap://%1/%2?%3?%4?(%5)").arg( host ).arg( mBase )
    00130       .arg( mAttrs.join(",") ).arg( mScope ).arg( filter );
    00131   }
    00132   kdDebug(5700) << "Doing query" << query.latin1() << endl;
    00133
    00134   startParseLDIF();
    00135   mActive = true;
    00136   mJob = KIO::get( KURL( query ), false, false );
    00137   connect( mJob, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
    00138            this, SLOT( slotData( KIO::Job*, const QByteArray& ) ) );
    00139   connect( mJob, SIGNAL( infoMessage( KIO::Job*, const QString& ) ),
    00140            this, SLOT( slotInfoMessage( KIO::Job*, const QString& ) ) );
    00141   connect( mJob, SIGNAL( result( KIO::Job* ) ),
    00142            this, SLOT( slotDone() ) );
    00143 }
    00144
    00145 void LdapClient::cancelQuery()
    00146 {
    00147   if ( mJob ) {
    00148     mJob->kill();
    00149     mJob = 0;
    00150   }
    00151
    00152   mActive = false;
    00153 }
    00154
    00155 void LdapClient::slotData( KIO::Job*, const QByteArray& data )
    00156 {
    00157 #ifndef NDEBUG // don't create the QString
    00158   QString str( data );
    00159   kdDebug(5700) << "Got \"" << str.latin1() << "\"\n";
    00160 #endif
    00161   parseLDIF( data );
    00162 }
    00163
    00164 void LdapClient::slotInfoMessage( KIO::Job*, const QString & )
    00165 {
    00166   //qDebug("Job said \"%s\"", info.latin1());
    00167 }
    00168
    00169 void LdapClient::slotDone()
    00170 {
    00171   endParseLDIF();
    00172   mActive = false;
    00173 #if 0
    00174   for ( QValueList<LdapObject>::Iterator it = mObjects.begin(); it != mObjects.end(); ++it ) {
    00175     qDebug( (*it).toString().latin1() );
    00176   }
    00177 #endif
    00178   int err = mJob->error();
    00179   if ( err ) {
    00180     emit error( KIO::buildErrorString( err, QString("%1:%2").arg( mHost ).arg( mPort ) ) );
    00181   }
    00182   emit done();
    00183 }
    00184
    00185 void LdapClient::startParseLDIF()
    00186 {
    00187   mCurrentObject.clear();
    00188   mLastAttrName  = 0;
    00189   mLastAttrValue = 0;
    00190   mIsBase64 = false;
    00191 }
    00192
    00193 void LdapClient::endParseLDIF()
    00194 {
    00195   if ( !mCurrentObject.dn.isEmpty() ) {
    00196     if ( !mLastAttrName.isNull() && !mLastAttrValue.isNull() ) {
    00197       if ( mIsBase64 ) {
    00198         QByteArray out;
    00199         KCodecs::base64Decode( mLastAttrValue, out );
    00200         //qDebug("_lastAttrValue=\"%s\", output length %d", _lastAttrValue.data(), out.size());
    00201         mCurrentObject.attrs[ mLastAttrName ].append( out );
    00202       } else {
    00203         mCurrentObject.attrs[ mLastAttrName ].append( mLastAttrValue );
    00204       }
    00205     }
    00206     emit result( mCurrentObject );
    00207   }
    00208 }
    00209
    00210 void LdapClient::parseLDIF( const QByteArray& data )
    00211 {
    00212   //qDebug("%s", data.data());
    00213   if ( data.isNull() || data.isEmpty() )
    00214     return;
    00215   mBuf += QCString( data, data.size() + 1 ); // collect data in buffer
    00216   int nl;
    00217   while ( (nl = mBuf.find('\n')) != -1 ) {
    00218     // Run through it line by line
    00219     /* FIXME(steffen): This could be a problem
    00220     * with "no newline at end of file" input
    00221     */
    00222     QCString line = mBuf.left( nl );
    00223     if ( mBuf.length() > (unsigned int)(nl+1) )
    00224       mBuf = mBuf.mid( nl+1 );
    00225     else
    00226       mBuf = "";
    00227
    00228     if ( line.length() > 0 ) {
    00229       if ( line[ 0 ] == '#' ) { // comment
    00230         continue;
    00231       } else if ( line[ 0 ] == ' ' || line[ 0 ] == '\t' ) { // continuation of last line
    00232         line = line.stripWhiteSpace();
    00233         //qDebug("Adding \"%s\"", line.data() );
    00234         mLastAttrValue += line;
    00235         continue;
    00236       }
    00237     } else
    00238       continue;
    00239
    00240     int colon = line.find(':');
    00241     if ( colon != -1 ) { // Found new attribute
    00242       if ( mLastAttrName == "dn" ) { // New object, store the current
    00243         if ( !mCurrentObject.dn.isNull() ) {
    00244           emit result( mCurrentObject );
    00245           mCurrentObject.clear();
    00246         }
    00247         mCurrentObject.dn = mLastAttrValue;
    00248         mLastAttrValue = 0;
    00249         mLastAttrName  = 0;
    00250       } else if ( !mLastAttrName.isEmpty() ) {
    00251         // Store current value, take care of decoding
    00252         if ( mIsBase64 ) {
    00253           QByteArray out;
    00254           KCodecs::base64Decode( mLastAttrValue, out );
    00255           //qDebug("_lastAttrValue=\"%s\", output length %d", _lastAttrValue.data(), out.size());
    00256           mCurrentObject.attrs[ mLastAttrName ].append( out );
    00257         } else {
    00258           mCurrentObject.attrs[ mLastAttrName ].append( mLastAttrValue );
    00259         }
    00260       }
    00261
    00262       mLastAttrName  = line.left( colon ).stripWhiteSpace();
    00263       //qDebug("Found attr %s", _lastAttrName.data() );
    00264       ++colon;
    00265       if ( line[colon] == ':' ) {
    00266         mIsBase64 = true;
    00267         //qDebug("BASE64");
    00268         ++colon;
    00269       } else {
    00270         //qDebug("UTF8");
    00271         mIsBase64 = false;
    00272       }
    00273
    00274       mLastAttrValue = line.mid( colon ).stripWhiteSpace();
    00275     }
    00276   }
    00277 }
    00278
    00279 LdapSearch::LdapSearch()
    00280     : mActiveClients( 0 ), mNoLDAPLookup( false )
    00281 {
    00282   if ( !KProtocolInfo::isKnownProtocol( KURL("ldap://localhost") ) ) {
    00283     mNoLDAPLookup = true;
    00284     return;
    00285   }
    00286
    00287   // stolen from KAddressBook
    00288   KConfig config( "kaddressbookrc", true );
    00289   config.setGroup( "LDAP" );
    00290   int numHosts = config.readUnsignedNumEntry( "NumSelectedHosts");
    00291   if ( !numHosts ) {
    00292     mNoLDAPLookup = true;
    00293     return;
    00294   } else {
    00295     for ( int j = 0; j < numHosts; j++ ) {
    00296       LdapClient* ldapClient = new LdapClient( this );
    00297
    00298       QString host =  config.readEntry( QString( "SelectedHost%1" ).arg( j ), "" ).stripWhiteSpace();
    00299       if ( host != "" )
    00300         ldapClient->setHost( host );
    00301
    00302       QString port = QString::number( config.readUnsignedNumEntry( QString( "SelectedPort%1" ).arg( j ) ) );
    00303       if ( !port.isEmpty() )
    00304         ldapClient->setPort( port );
    00305
    00306       QString base = config.readEntry( QString( "SelectedBase%1" ).arg( j ), "" ).stripWhiteSpace();
    00307       if ( base != "" )
    00308         ldapClient->setBase( base );
    00309
    00310       QStringList attrs;
    00311       attrs << "cn" << "mail" << "givenname" << "sn";
    00312       ldapClient->setAttrs( attrs );
    00313
    00314       connect( ldapClient, SIGNAL( result( const KABC::LdapObject& ) ),
    00315                this, SLOT( slotLDAPResult( const KABC::LdapObject& ) ) );
    00316       connect( ldapClient, SIGNAL( done() ),
    00317                this, SLOT( slotLDAPDone() ) );
    00318       connect( ldapClient, SIGNAL( error( const QString& ) ),
    00319                this, SLOT( slotLDAPError( const QString& ) ) );
    00320
    00321       mClients.append( ldapClient );
    00322     }
    00323   }
    00324
    00325   connect( &mDataTimer, SIGNAL( timeout() ), SLOT( slotDataTimer() ) );
    00326 }
    00327
    00328 void LdapSearch::startSearch( const QString& txt )
    00329 {
    00330   if ( mNoLDAPLookup )
    00331     return;
    00332
    00333   cancelSearch();
    00334   int pos = txt.find( '\"' );
    00335   if( pos >= 0 )
    00336   {
    00337     ++pos;
    00338     int pos2 = txt.find( '\"', pos );
    00339     if( pos2 >= 0 )
    00340         mSearchText = txt.mid( pos , pos2 - pos );
    00341     else
    00342         mSearchText = txt.mid( pos );
    00343   } else
    00344     mSearchText = txt;
    00345
    00346   QString filter = QString( "|(cn=%1*)(mail=%2*)(givenName=%3*)(sn=%4*)" )
    00347       .arg( mSearchText ).arg( mSearchText ).arg( mSearchText ).arg( mSearchText );
    00348
    00349   QValueList< LdapClient* >::Iterator it;
    00350   for ( it = mClients.begin(); it != mClients.end(); ++it ) {
    00351     (*it)->startQuery( filter );
    00352     ++mActiveClients;
    00353   }
    00354 }
    00355
    00356 void LdapSearch::cancelSearch()
    00357 {
    00358   QValueList< LdapClient* >::Iterator it;
    00359   for ( it = mClients.begin(); it != mClients.end(); ++it )
    00360     (*it)->cancelQuery();
    00361
    00362   mActiveClients = 0;
    00363   mResults.clear();
    00364 }
    00365
    00366 void LdapSearch::slotLDAPResult( const KABC::LdapObject& obj )
    00367 {
    00368   mResults.append( obj );
    00369   if ( !mDataTimer.isActive() )
    00370     mDataTimer.start( 500, true );
    00371 }
    00372
    00373 void LdapSearch::slotLDAPError( const QString& )
    00374 {
    00375   slotLDAPDone();
    00376 }
    00377
    00378 void LdapSearch::slotLDAPDone()
    00379 {
    00380   if ( --mActiveClients > 0 )
    00381     return;
    00382
    00383   finish();
    00384 }
    00385
    00386 void LdapSearch::slotDataTimer()
    00387 {
    00388   emit searchData( makeSearchData() );
    00389 }
    00390
    00391 void LdapSearch::finish()
    00392 {
    00393   mDataTimer.stop();
    00394
    00395   emit searchData( makeSearchData() );
    00396   emit searchDone();
    00397 }
    00398
    00399 QStringList LdapSearch::makeSearchData()
    00400 {
    00401   QStringList ret;
    00402   QString search_text_upper = mSearchText.upper();
    00403
    00404   QValueList< KABC::LdapObject >::ConstIterator it1;
    00405   for ( it1 = mResults.begin(); it1 != mResults.end(); ++it1 ) {
    00406     QString name, mail, givenname, sn;
    00407
    00408     LdapAttrMap::ConstIterator it2;
    00409     for ( it2 = (*it1).attrs.begin(); it2 != (*it1).attrs.end(); ++it2 ) {
    00410       if ( it2.key() == "cn" )
    00411         name = QString( "%1" ).arg( (*it2).first() ); // TODO loop?
    00412       else if( it2.key() == "mail" )
    00413         mail = QString( "%1" ).arg( (*it2).first() );
    00414             else if( it2.key() == "givenName" )
    00415         givenname = QString( "%1" ).arg( (*it2).first() );
    00416             else if( it2.key() == "sn" )
    00417         sn = QString( "%1" ).arg( (*it2).first() );
    00418     }
    00419
    00420     if( mail.isEmpty())
    00421         ; // nothing, bad entry
    00422     else if ( name.isEmpty() )
    00423       ret.append( mail );
    00424     else {
    00425         kdDebug() << "<" << name << "><" << mail << ">" << endl;
    00426       ret.append( QString( "%1 <%2>" ).arg( name ).arg( mail ) );
    00427       // this sucks
    00428       if ( givenname.upper().startsWith( search_text_upper ) )
    00429         ret.append( QString( "$$%1$%2 <%3>" ).arg( givenname ).arg( name ).arg( mail ) );
    00430       if ( sn.upper().startsWith( search_text_upper ) )
    00431         ret.append( QString( "$$%1$%2 <%3>" ).arg( sn ).arg( name ).arg( mail ) );
    00432     }
    00433   }
    00434
    00435   mResults.clear();
    00436
    00437   return ret;
    00438 }
    00439
    00440 bool LdapSearch::isAvailable() const
    00441 {
    00442   return !mNoLDAPLookup;
    00443 }
    00444
    00445 #include "ldapclient.moc"

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:29:20 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001