00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00067
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
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
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
00246
if ( data.isEmpty() )
00247
return;
00248 mBuf +=
QCString( data, data.size() + 1 );
00249
int nl;
00250
while ( (nl = mBuf.find(
'\n')) != -1 ) {
00251
00252
00253
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 ] ==
'#' ) {
00263
continue;
00264 }
else if ( line[ 0 ] ==
' ' || line[ 0 ] ==
'\t' ) {
00265 line = line.
stripWhiteSpace();
00266
00267 mLastAttrValue += line;
00268
continue;
00269 }
00270 }
else
00271
continue;
00272
00273
int colon = line.
find(
':');
00274
if ( colon != -1 ) {
00275
if ( mLastAttrName ==
"dn" ) {
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
00285
if ( mIsBase64 ) {
00286
QByteArray out;
00287
KCodecs::base64Decode( mLastAttrValue, out );
00288
00289 mCurrentObject.attrs[ mLastAttrName ].append( out );
00290 }
else {
00291 mCurrentObject.attrs[ mLastAttrName ].append( mLastAttrValue );
00292 }
00293 }
00294
00295 mLastAttrName = line.
left( colon ).stripWhiteSpace();
00296
00297 ++colon;
00298
if ( line[colon] ==
':' ) {
00299 mIsBase64 =
true;
00300
00301 ++colon;
00302 }
else {
00303
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
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 ) ).stripWhiteSpace();
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;
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 ;
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
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"