ldapclient.cpp
/* kldapclient.cpp - LDAP access
* Copyright (C) 2002 Klarälvdalens Datakonsult AB
*
* Author: Steffen Hansen <hansen@kde.org>
*
* Ported to KABC by Daniel Molkentin <molkentin@kde.org>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <qfile.h>
#include <qimage.h>
#include <qlabel.h>
#include <qpixmap.h>
#include <qtextstream.h>
#include <qurl.h>
#include <kapplication.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kmdcodec.h>
#include <kprotocolinfo.h>
#include "ldapclient.h"
#include "ldif.h"
#include "ldapurl.h"
using namespace KABC;
class LdapClient::LdapClientPrivate{
public:
QString bindDN;
QString pwdBindDN;
LDIF ldif;
};
QString LdapObject::toString() const
{
QString result = QString::fromLatin1( "\ndn: %1\n" ).arg( dn );
for ( LdapAttrMap::ConstIterator it = attrs.begin(); it != attrs.end(); ++it ) {
QString attr = it.key();
for ( LdapAttrValue::ConstIterator it2 = (*it).begin(); it2 != (*it).end(); ++it2 ) {
result += QString::fromUtf8( LDIF::assembleLine( attr, *it2, 76 ) ) + "\n";
}
}
return result;
}
void LdapObject::clear()
{
dn = QString::null;
attrs.clear();
}
void LdapObject::assign( const LdapObject& that )
{
if ( &that != this ) {
dn = that.dn;
attrs = that.attrs;
client = that.client;
}
}
LdapClient::LdapClient( QObject* parent, const char* name )
: QObject( parent, name ), mJob( 0 ), mActive( false )
{
d = new LdapClientPrivate;
}
LdapClient::~LdapClient()
{
cancelQuery();
delete d; d = 0;
}
void LdapClient::setHost( const QString& host )
{
mHost = host;
}
void LdapClient::setPort( const QString& port )
{
mPort = port;
}
void LdapClient::setBase( const QString& base )
{
mBase = base;
}
void LdapClient::setBindDN( const QString& bindDN )
{
d->bindDN = bindDN;
}
void LdapClient::setPwdBindDN( const QString& pwdBindDN )
{
d->pwdBindDN = pwdBindDN;
}
void LdapClient::setAttrs( const QStringList& attrs )
{
mAttrs = attrs;
}
void LdapClient::startQuery( const QString& filter )
{
cancelQuery();
LDAPUrl url;
url.setProtocol( "ldap" );
url.setUser( d->bindDN );
url.setPass( d->pwdBindDN );
url.setHost( mHost );
url.setPort( mPort.toUInt() );
url.setDn( mBase );
url.setAttributes( mAttrs );
url.setScope( mScope == "one" ? LDAPUrl::One : LDAPUrl::Sub );
url.setFilter( "("+filter+")" );
kdDebug(5700) << "Doing query: " << url.prettyURL() << endl;
startParseLDIF();
mActive = true;
mJob = KIO::get( url, false, false );
connect( mJob, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
this, SLOT( slotData( KIO::Job*, const QByteArray& ) ) );
connect( mJob, SIGNAL( infoMessage( KIO::Job*, const QString& ) ),
this, SLOT( slotInfoMessage( KIO::Job*, const QString& ) ) );
connect( mJob, SIGNAL( result( KIO::Job* ) ),
this, SLOT( slotDone() ) );
}
void LdapClient::cancelQuery()
{
if ( mJob ) {
mJob->kill();
mJob = 0;
}
mActive = false;
}
void LdapClient::slotData( KIO::Job*, const QByteArray& data )
{
#ifndef NDEBUG // don't create the QString
// QString str( data );
// kdDebug(5700) << "LdapClient: Got \"" << str << "\"\n";
#endif
parseLDIF( data );
}
void LdapClient::slotInfoMessage( KIO::Job*, const QString & )
{
//qDebug("Job said \"%s\"", info.latin1());
}
void LdapClient::slotDone()
{
endParseLDIF();
mActive = false;
#if 0
for ( QValueList<LdapObject>::Iterator it = mObjects.begin(); it != mObjects.end(); ++it ) {
qDebug( (*it).toString().latin1() );
}
#endif
int err = mJob->error();
if ( err && err != KIO::ERR_USER_CANCELED ) {
emit error( KIO::buildErrorString( err, QString("%1:%2").arg( mHost ).arg( mPort ) ) );
}
emit done();
}
void LdapClient::startParseLDIF()
{
mCurrentObject.clear();
mLastAttrName = 0;
mLastAttrValue = 0;
mIsBase64 = false;
d->ldif.startParsing();
}
void LdapClient::endParseLDIF()
{
}
void LdapClient::parseLDIF( const QByteArray& data )
{
if ( data.size() ) {
d->ldif.setLDIF( data );
} else {
d->ldif.endLDIF();
}
LDIF::ParseVal ret;
QString name;
do {
ret = d->ldif.nextItem();
switch ( ret ) {
case LDIF::Item:
{
name = d->ldif.attr();
// Must make a copy! QByteArray is explicitely shared
QByteArray value = d->ldif.val().copy();
mCurrentObject.attrs[ name ].append( value );
break;
}
case LDIF::EndEntry:
mCurrentObject.dn = d->ldif.dn();
mCurrentObject.client = this;
emit result( mCurrentObject );
mCurrentObject.clear();
break;
default:
break;
}
} while ( ret != LDIF::MoreData );
}
QString LdapClient::bindDN() const
{
return d->bindDN;
}
QString LdapClient::pwdBindDN() const
{
return d->pwdBindDN;
}
LdapSearch::LdapSearch()
: mActiveClients( 0 ), mNoLDAPLookup( false )
{
if ( !KProtocolInfo::isKnownProtocol( KURL("ldap://localhost") ) ) {
mNoLDAPLookup = true;
return;
}
// stolen from KAddressBook
KConfig config( "kabldaprc", true );
config.setGroup( "LDAP" );
int numHosts = config.readUnsignedNumEntry( "NumSelectedHosts");
if ( !numHosts ) {
mNoLDAPLookup = true;
return;
} else {
for ( int j = 0; j < numHosts; j++ ) {
LdapClient* ldapClient = new LdapClient( this );
QString host = config.readEntry( QString( "SelectedHost%1" ).arg( j ), "" ).stripWhiteSpace();
if ( !host.isEmpty() )
ldapClient->setHost( host );
QString port = QString::number( config.readUnsignedNumEntry( QString( "SelectedPort%1" ).arg( j ) ) );
if ( !port.isEmpty() )
ldapClient->setPort( port );
QString base = config.readEntry( QString( "SelectedBase%1" ).arg( j ), "" ).stripWhiteSpace();
if ( !base.isEmpty() )
ldapClient->setBase( base );
QString bindDN = config.readEntry( QString( "SelectedBind%1" ).arg( j ) ).stripWhiteSpace();
if ( !bindDN.isEmpty() )
ldapClient->setBindDN( bindDN );
QString pwdBindDN = config.readEntry( QString( "SelectedPwdBind%1" ).arg( j ) );
if ( !pwdBindDN.isEmpty() )
ldapClient->setPwdBindDN( pwdBindDN );
QStringList attrs;
attrs << "cn" << "mail" << "givenname" << "sn";
ldapClient->setAttrs( attrs );
connect( ldapClient, SIGNAL( result( const KABC::LdapObject& ) ),
this, SLOT( slotLDAPResult( const KABC::LdapObject& ) ) );
connect( ldapClient, SIGNAL( done() ),
this, SLOT( slotLDAPDone() ) );
connect( ldapClient, SIGNAL( error( const QString& ) ),
this, SLOT( slotLDAPError( const QString& ) ) );
mClients.append( ldapClient );
}
}
connect( &mDataTimer, SIGNAL( timeout() ), SLOT( slotDataTimer() ) );
}
void LdapSearch::startSearch( const QString& txt )
{
if ( mNoLDAPLookup )
return;
cancelSearch();
int pos = txt.find( '\"' );
if( pos >= 0 )
{
++pos;
int pos2 = txt.find( '\"', pos );
if( pos2 >= 0 )
mSearchText = txt.mid( pos , pos2 - pos );
else
mSearchText = txt.mid( pos );
} else
mSearchText = txt;
QString filter = QString( "|(cn=%1*)(mail=%2*)(givenName=%3*)(sn=%4*)" )
.arg( mSearchText ).arg( mSearchText ).arg( mSearchText ).arg( mSearchText );
QValueList< LdapClient* >::Iterator it;
for ( it = mClients.begin(); it != mClients.end(); ++it ) {
(*it)->startQuery( filter );
++mActiveClients;
}
}
void LdapSearch::cancelSearch()
{
QValueList< LdapClient* >::Iterator it;
for ( it = mClients.begin(); it != mClients.end(); ++it )
(*it)->cancelQuery();
mActiveClients = 0;
mResults.clear();
}
void LdapSearch::slotLDAPResult( const KABC::LdapObject& obj )
{
mResults.append( obj );
if ( !mDataTimer.isActive() )
mDataTimer.start( 500, true );
}
void LdapSearch::slotLDAPError( const QString& )
{
slotLDAPDone();
}
void LdapSearch::slotLDAPDone()
{
if ( --mActiveClients > 0 )
return;
finish();
}
void LdapSearch::slotDataTimer()
{
QStringList lst;
LdapResultList reslist;
makeSearchData( lst, reslist );
if ( !lst.isEmpty() )
emit searchData( lst );
if ( !reslist.isEmpty() )
emit searchData( reslist );
}
void LdapSearch::finish()
{
mDataTimer.stop();
slotDataTimer(); // emit final bunch of data
emit searchDone();
}
void LdapSearch::makeSearchData( QStringList& ret, LdapResultList& resList )
{
QString search_text_upper = mSearchText.upper();
QValueList< KABC::LdapObject >::ConstIterator it1;
for ( it1 = mResults.begin(); it1 != mResults.end(); ++it1 ) {
QString name, mail, givenname, sn;
LdapAttrMap::ConstIterator it2;
for ( it2 = (*it1).attrs.begin(); it2 != (*it1).attrs.end(); ++it2 ) {
QString tmp = QString::fromUtf8( (*it2).first(), (*it2).first().size() );
if ( it2.key() == "cn" )
name = tmp; // TODO loop?
else if( it2.key() == "mail" )
mail = tmp;
else if( it2.key() == "givenName" )
givenname = tmp;
else if( it2.key() == "sn" )
sn = tmp;
}
if( mail.isEmpty())
continue; // nothing, bad entry
else if ( name.isEmpty() )
ret.append( mail );
else {
kdDebug(5700) << "<" << name << "><" << mail << ">" << endl;
ret.append( QString( "%1 <%2>" ).arg( name ).arg( mail ) );
}
LdapResult sr;
sr.clientNumber = mClients.findIndex( (*it1).client );
sr.name = name;
sr.email = mail;
resList.append( sr );
}
mResults.clear();
}
bool LdapSearch::isAvailable() const
{
return !mNoLDAPLookup;
}
#include "ldapclient.moc"
KURL
KURL::setPass
void setPass(const QString &_txt)
KABC::LDAPUrl::setAttributes
void setAttributes(const QStringList &attributes)
Sets the attributes part of the LDAP Url.
Definition: ldapurl.h:69
KURL::setProtocol
void setProtocol(const QString &_txt)
KABC::LdapObject
This class is internal.
Definition: ldapclient.h:49
KURL::prettyURL
QString prettyURL(int _trailing=0) const
KABC::LdapResult
Structure describing one result returned by a LDAP query.
Definition: ldapclient.h:192
KABC::LDIF::assembleLine
static QCString assembleLine(const QString &fieldname, const QByteArray &value, uint linelen=0, bool url=false)
Assembles fieldname and value into a valid LDIF line, BASE64 encodes the value if neccessary and opti...
Definition: ldif.cpp:37
KABC::LdapClient
This class is internal.
Definition: ldapclient.h:85
KABC::LdapClient::setHost
void setHost(const QString &host)
Definition: ldapclient.cpp:91
KABC::LdapClient::setPwdBindDN
void setPwdBindDN(const QString &pwdBindDN)
Definition: ldapclient.cpp:111
KABC::LdapClient::cancelQuery
void cancelQuery()
Definition: ldapclient.cpp:149
kdDebug
kdbgstream kdDebug(int area=0)
KABC::LDAPUrl
LDAPUrl.
Definition: ldapurl.h:42
KABC::LdapClient::result
void result(const KABC::LdapObject &)
KABC::LDIF
LDIF.
Definition: ldif.h:40
KStdAction::mail
KAction * mail(const QObject *recvr, const char *slot, KActionCollection *parent, const char *name=0)
KABC::LdapSearch::searchData
void searchData(const QStringList &)
Results, assembled as "Full Name <email>" (This signal can be emitted many times) ...
KABC::LdapClient::setPort
void setPort(const QString &port)
Definition: ldapclient.cpp:96
KABC::LdapClient::setBase
void setBase(const QString &base)
Definition: ldapclient.cpp:101
KABC::LDAPUrl::setDn
void setDn(const QString &dn)
Sets the the dn part of the LDAP Url.
Definition: ldapurl.cpp:47
KABC::LdapResult::clientNumber
int clientNumber
for sorting
Definition: ldapclient.h:195
KABC::LdapResult::name
QString name
full name
Definition: ldapclient.h:193
KURL::setHost
void setHost(const QString &_txt)
KABC::LDAPUrl::setFilter
void setFilter(QString filter)
Sets the filter part of the LDAP Url.
Definition: ldapurl.h:80
KABC::LdapClient::done
void done()
KConfig
KABC::LdapClient::setAttrs
void setAttrs(const QStringList &attrs)
Definition: ldapclient.cpp:116
KURL::setUser
void setUser(const QString &_txt)
KABC::LDAPUrl::setScope
void setScope(Scope scope)
Sets the scope part of the LDAP Url.
Definition: ldapurl.h:75
endl
kndbgstream & endl(kndbgstream &s)
KURL::setPort
void setPort(unsigned short int _p)
KABC::LdapClient::startQuery
void startQuery(const QString &filter)
Definition: ldapclient.cpp:121
KABC::LdapClient::error
void error(const QString &)
KABC::LdapResult::email
QString email
email
Definition: ldapclient.h:194
KStdAccel::name
QString name(StdAccel id)
KABC::LdapClient::setBindDN
void setBindDN(const QString &bindDN)
Definition: ldapclient.cpp:106

KDE Home | KDE Accessibility Home | Description of Access Keys