/* 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 <tqfile.h> #include <tqimage.h> #include <tqlabel.h> #include <tqpixmap.h> #include <tqtextstream.h> #include <tqurl.h> #include <tdeapplication.h> #include <tdeconfig.h> #include <kdebug.h> #include <kmdcodec.h> #include <kprotocolinfo.h> #include "ldapclient.h" #include "ldif.h" #include "ldapurl.h" using namespace TDEABC; class LdapClient::LdapClientPrivate{ public: TQString bindDN; TQString pwdBindDN; LDIF ldif; }; TQString LdapObject::toString() const { TQString result = TQString::fromLatin1( "\ndn: %1\n" ).arg( dn ); for ( LdapAttrMap::ConstIterator it = attrs.begin(); it != attrs.end(); ++it ) { TQString attr = it.key(); for ( LdapAttrValue::ConstIterator it2 = (*it).begin(); it2 != (*it).end(); ++it2 ) { result += TQString::fromUtf8( LDIF::assembleLine( attr, *it2, 76 ) ) + "\n"; } } return result; } void LdapObject::clear() { dn = TQString::null; attrs.clear(); } void LdapObject::assign( const LdapObject& that ) { if ( &that != this ) { dn = that.dn; attrs = that.attrs; client = that.client; } } LdapClient::LdapClient( TQObject* parent, const char* name ) : TQObject( parent, name ), mJob( 0 ), mActive( false ) { d = new LdapClientPrivate; } LdapClient::~LdapClient() { cancelQuery(); delete d; d = 0; } void LdapClient::setHost( const TQString& host ) { mHost = host; } void LdapClient::setPort( const TQString& port ) { mPort = port; } void LdapClient::setBase( const TQString& base ) { mBase = base; } void LdapClient::setBindDN( const TQString& bindDN ) { d->bindDN = bindDN; } void LdapClient::setPwdBindDN( const TQString& pwdBindDN ) { d->pwdBindDN = pwdBindDN; } void LdapClient::setAttrs( const TQStringList& attrs ) { mAttrs = attrs; } void LdapClient::startQuery( const TQString& 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 = TDEIO::get( url, false, false ); connect( mJob, TQT_SIGNAL( data( TDEIO::Job*, const TQByteArray& ) ), this, TQT_SLOT( slotData( TDEIO::Job*, const TQByteArray& ) ) ); connect( mJob, TQT_SIGNAL( infoMessage( TDEIO::Job*, const TQString& ) ), this, TQT_SLOT( slotInfoMessage( TDEIO::Job*, const TQString& ) ) ); connect( mJob, TQT_SIGNAL( result( TDEIO::Job* ) ), this, TQT_SLOT( slotDone() ) ); } void LdapClient::cancelQuery() { if ( mJob ) { mJob->kill(); mJob = 0; } mActive = false; } void LdapClient::slotData( TDEIO::Job*, const TQByteArray& data ) { #ifndef NDEBUG // don't create the QString // TQString str( data ); // kdDebug(5700) << "LdapClient: Got \"" << str << "\"\n"; #endif parseLDIF( data ); } void LdapClient::slotInfoMessage( TDEIO::Job*, const TQString & ) { //tqDebug("Job said \"%s\"", info.latin1()); } void LdapClient::slotDone() { endParseLDIF(); mActive = false; #if 0 for ( TQValueList<LdapObject>::Iterator it = mObjects.begin(); it != mObjects.end(); ++it ) { tqDebug( (*it).toString().latin1() ); } #endif int err = mJob->error(); if ( err && err != TDEIO::ERR_USER_CANCELED ) { emit error( TDEIO::buildErrorString( err, TQString("%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 TQByteArray& data ) { if ( data.size() ) { d->ldif.setLDIF( data ); } else { d->ldif.endLDIF(); } LDIF::ParseVal ret; TQString name; do { ret = d->ldif.nextItem(); switch ( ret ) { case LDIF::Item: { name = d->ldif.attr(); // Must make a copy! TQByteArray is explicitely shared TQByteArray 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 ); } TQString LdapClient::bindDN() const { return d->bindDN; } TQString LdapClient::pwdBindDN() const { return d->pwdBindDN; } LdapSearch::LdapSearch() : mActiveClients( 0 ), mNoLDAPLookup( false ) { if ( !KProtocolInfo::isKnownProtocol( KURL("ldap://localhost") ) ) { mNoLDAPLookup = true; return; } // stolen from KAddressBook TDEConfig 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 ); TQString host = config.readEntry( TQString( "SelectedHost%1" ).arg( j ), "" ).stripWhiteSpace(); if ( !host.isEmpty() ) ldapClient->setHost( host ); TQString port = TQString::number( config.readUnsignedNumEntry( TQString( "SelectedPort%1" ).arg( j ) ) ); if ( !port.isEmpty() ) ldapClient->setPort( port ); TQString base = config.readEntry( TQString( "SelectedBase%1" ).arg( j ), "" ).stripWhiteSpace(); if ( !base.isEmpty() ) ldapClient->setBase( base ); TQString bindDN = config.readEntry( TQString( "SelectedBind%1" ).arg( j ) ).stripWhiteSpace(); if ( !bindDN.isEmpty() ) ldapClient->setBindDN( bindDN ); TQString pwdBindDN = config.readEntry( TQString( "SelectedPwdBind%1" ).arg( j ) ); if ( !pwdBindDN.isEmpty() ) ldapClient->setPwdBindDN( pwdBindDN ); TQStringList attrs; attrs << "cn" << "mail" << "givenname" << "sn"; ldapClient->setAttrs( attrs ); connect( ldapClient, TQT_SIGNAL( result( const TDEABC::LdapObject& ) ), this, TQT_SLOT( slotLDAPResult( const TDEABC::LdapObject& ) ) ); connect( ldapClient, TQT_SIGNAL( done() ), this, TQT_SLOT( slotLDAPDone() ) ); connect( ldapClient, TQT_SIGNAL( error( const TQString& ) ), this, TQT_SLOT( slotLDAPError( const TQString& ) ) ); mClients.append( ldapClient ); } } connect( &mDataTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( slotDataTimer() ) ); } void LdapSearch::startSearch( const TQString& 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; TQString filter = TQString( "|(cn=%1*)(mail=%2*)(givenName=%3*)(sn=%4*)" ) .arg( mSearchText ).arg( mSearchText ).arg( mSearchText ).arg( mSearchText ); TQValueList< LdapClient* >::Iterator it; for ( it = mClients.begin(); it != mClients.end(); ++it ) { (*it)->startQuery( filter ); ++mActiveClients; } } void LdapSearch::cancelSearch() { TQValueList< LdapClient* >::Iterator it; for ( it = mClients.begin(); it != mClients.end(); ++it ) (*it)->cancelQuery(); mActiveClients = 0; mResults.clear(); } void LdapSearch::slotLDAPResult( const TDEABC::LdapObject& obj ) { mResults.append( obj ); if ( !mDataTimer.isActive() ) mDataTimer.start( 500, true ); } void LdapSearch::slotLDAPError( const TQString& ) { slotLDAPDone(); } void LdapSearch::slotLDAPDone() { if ( --mActiveClients > 0 ) return; finish(); } void LdapSearch::slotDataTimer() { TQStringList 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( TQStringList& ret, LdapResultList& resList ) { TQString search_text_upper = mSearchText.upper(); TQValueList< TDEABC::LdapObject >::ConstIterator it1; for ( it1 = mResults.begin(); it1 != mResults.end(); ++it1 ) { TQString name, mail, givenname, sn; LdapAttrMap::ConstIterator it2; for ( it2 = (*it1).attrs.begin(); it2 != (*it1).attrs.end(); ++it2 ) { TQString tmp = TQString::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( TQString( "%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"