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