29 #include <tqtextstream.h>
32 #include <tdeabc/ldapurl.h>
33 #include <tdeabc/ldif.h>
34 #include <tdeapplication.h>
35 #include <tdeconfig.h>
37 #include <kdirwatch.h>
39 #include <kprotocolinfo.h>
40 #include <kstandarddirs.h>
41 #include <kstaticdeleter.h>
43 #include "ldapclient.h"
47 TDEConfig *KPIM::LdapSearch::s_config = 0L;
48 static KStaticDeleter<TDEConfig> configDeleter;
50 TQString LdapObject::toString()
const
52 TQString result = TQString::fromLatin1(
"\ndn: %1\n" ).arg( dn );
53 for ( LdapAttrMap::ConstIterator it = attrs.begin(); it != attrs.end(); ++it ) {
54 TQString attr = it.key();
55 for ( LdapAttrValue::ConstIterator it2 = (*it).begin(); it2 != (*it).end(); ++it2 ) {
56 result += TQString::fromUtf8( TDEABC::LDIF::assembleLine( attr, *it2, 76 ) ) +
"\n";
63 void LdapObject::clear()
66 objectClass = TQString();
70 void LdapObject::assign(
const LdapObject& that )
72 if ( &that !=
this ) {
79 LdapClient::LdapClient(
int clientNumber, TQObject* parent,
const char* name )
80 : TQObject( parent, name ), mJob( 0 ), mActive( false ), mReportObjectClass( false )
83 mClientNumber = clientNumber;
84 mCompletionWeight = 50 - mClientNumber;
87 LdapClient::~LdapClient()
96 for ( TQStringList::Iterator it = mAttrs.begin(); it != mAttrs.end(); ++it )
97 if( (*it).lower() ==
"objectclass" ){
98 mReportObjectClass =
true;
101 mAttrs <<
"objectClass";
102 mReportObjectClass =
false;
110 url.setProtocol( ( mServer.security() == LdapServer::SSL ) ?
"ldaps" :
"ldap" );
111 if ( mServer.auth() != LdapServer::Anonymous ) {
112 url.setUser( mServer.user() );
113 url.setPass( mServer.pwdBindDN() );
115 url.setHost( mServer.host() );
116 url.setPort( mServer.port() );
117 url.setExtension(
"x-ver", TQString::number( mServer.version() ) );
118 url.setDn( mServer.baseDN() );
119 url.setDn( mServer.baseDN() );
120 if ( mServer.security() == LdapServer::TLS ) url.setExtension(
"x-tls",
"" );
121 if ( mServer.auth() == LdapServer::SASL ) {
122 url.setExtension(
"x-sasl",
"" );
123 if ( !mServer.bindDN().isEmpty() ) url.setExtension(
"x-bindname", mServer.bindDN() );
124 if ( !mServer.mech().isEmpty() ) url.setExtension(
"x-mech", mServer.mech() );
126 if ( mServer.timeLimit() != 0 ) url.setExtension(
"x-timelimit",
127 TQString::number( mServer.timeLimit() ) );
128 if ( mServer.sizeLimit() != 0 ) url.setExtension(
"x-sizelimit",
129 TQString::number( mServer.sizeLimit() ) );
131 url.setAttributes( mAttrs );
132 url.setScope( mScope ==
"one" ? TDEABC::LDAPUrl::One : TDEABC::LDAPUrl::Sub );
133 url.setFilter(
"("+filter+
")" );
135 kdDebug(5300) <<
"LdapClient: Doing query: " << url.prettyURL() << endl;
139 mJob = TDEIO::get( url,
false,
false );
140 connect( mJob, TQ_SIGNAL( data( TDEIO::Job*,
const TQByteArray& ) ),
141 this, TQ_SLOT( slotData( TDEIO::Job*,
const TQByteArray& ) ) );
142 connect( mJob, TQ_SIGNAL( infoMessage( TDEIO::Job*,
const TQString& ) ),
143 this, TQ_SLOT( slotInfoMessage( TDEIO::Job*,
const TQString& ) ) );
144 connect( mJob, TQ_SIGNAL(
result( TDEIO::Job* ) ),
145 this, TQ_SLOT( slotDone() ) );
158 void LdapClient::slotData( TDEIO::Job*,
const TQByteArray& data )
163 void LdapClient::slotInfoMessage( TDEIO::Job*,
const TQString & )
168 void LdapClient::slotDone()
173 for ( TQValueList<LdapObject>::Iterator it = mObjects.begin(); it != mObjects.end(); ++it ) {
174 tqDebug( (*it).toString().latin1() );
177 int err = mJob->error();
178 if ( err && err != TDEIO::ERR_USER_CANCELED ) {
179 emit
error( mJob->errorString() );
184 void LdapClient::startParseLDIF()
186 mCurrentObject.clear();
187 mLdif.startParsing();
190 void LdapClient::endParseLDIF()
194 void LdapClient::finishCurrentObject()
196 mCurrentObject.dn = mLdif.dn();
197 const TQString sClass( mCurrentObject.objectClass.lower() );
198 if( sClass ==
"groupofnames" || sClass ==
"kolabgroupofnames" ){
199 LdapAttrMap::ConstIterator it = mCurrentObject.attrs.find(
"mail");
200 if( it == mCurrentObject.attrs.end() ){
204 TQStringList lMail = TQStringList::split(
",dc=", mCurrentObject.dn);
205 const int n = lMail.count();
207 if( lMail.first().lower().startsWith(
"cn=") ){
208 sMail = lMail.first().simplifyWhiteSpace().mid(3);
211 for(
int i=1; i<n; ++i){
212 sMail.append( lMail[i] );
216 mCurrentObject.attrs[
"mail"].append( sMail.utf8() );
221 mCurrentObject.client =
this;
222 emit
result( mCurrentObject );
223 mCurrentObject.clear();
226 void LdapClient::parseLDIF(
const TQByteArray& data )
230 mLdif.setLDIF( data );
235 TDEABC::LDIF::ParseVal ret;
238 ret = mLdif.nextItem();
240 case TDEABC::LDIF::Item:
244 TQByteArray value = mLdif.val().copy();
245 bool bIsObjectClass = name.lower() ==
"objectclass";
247 mCurrentObject.objectClass = TQString::fromUtf8( value, value.size() );
248 if( mReportObjectClass || !bIsObjectClass )
249 mCurrentObject.attrs[ name ].append( value );
253 case TDEABC::LDIF::EndEntry:
254 finishCurrentObject();
259 }
while ( ret != TDEABC::LDIF::MoreData );
262 int LdapClient::clientNumber()
const
264 return mClientNumber;
267 int LdapClient::completionWeight()
const
269 return mCompletionWeight;
272 void LdapClient::setCompletionWeight(
int weight )
274 mCompletionWeight = weight;
277 void LdapSearch::readConfig( LdapServer &server, TDEConfig *config,
int j,
bool active )
280 if ( active ) prefix =
"Selected";
281 TQString host = config->readEntry( prefix + TQString(
"Host%1" ).arg( j ),
"" ).stripWhiteSpace();
282 if ( !host.isEmpty() )
283 server.setHost( host );
285 int port = config->readNumEntry( prefix + TQString(
"Port%1" ).arg( j ), 389 );
286 server.setPort( port );
288 TQString base = config->readEntry( prefix + TQString(
"Base%1" ).arg( j ),
"" ).stripWhiteSpace();
289 if ( !base.isEmpty() )
290 server.setBaseDN( base );
292 TQString user = config->readEntry( prefix + TQString(
"User%1" ).arg( j ) ).stripWhiteSpace();
293 if ( !user.isEmpty() )
294 server.setUser( user );
296 TQString bindDN = config->readEntry( prefix + TQString(
"Bind%1" ).arg( j ) ).stripWhiteSpace();
297 if ( !bindDN.isEmpty() )
298 server.setBindDN( bindDN );
300 TQString pwdBindDN = config->readEntry( prefix + TQString(
"PwdBind%1" ).arg( j ) );
301 if ( !pwdBindDN.isEmpty() )
302 server.setPwdBindDN( pwdBindDN );
304 server.setTimeLimit( config->readNumEntry( prefix + TQString(
"TimeLimit%1" ).arg( j ) ) );
305 server.setSizeLimit( config->readNumEntry( prefix + TQString(
"SizeLimit%1" ).arg( j ) ) );
306 server.setVersion( config->readNumEntry( prefix + TQString(
"Version%1" ).arg( j ), 3 ) );
307 server.setSecurity( config->readNumEntry( prefix + TQString(
"Security%1" ).arg( j ) ) );
308 server.setAuth( config->readNumEntry( prefix + TQString(
"Auth%1" ).arg( j ) ) );
309 server.setMech( config->readEntry( prefix + TQString(
"Mech%1" ).arg( j ) ) );
312 void LdapSearch::writeConfig(
const LdapServer &server, TDEConfig *config,
int j,
bool active )
315 if ( active ) prefix =
"Selected";
316 config->writeEntry( prefix + TQString(
"Host%1" ).arg( j ), server.host() );
317 config->writeEntry( prefix + TQString(
"Port%1" ).arg( j ), server.port() );
318 config->writeEntry( prefix + TQString(
"Base%1" ).arg( j ), server.baseDN() );
319 config->writeEntry( prefix + TQString(
"User%1" ).arg( j ), server.user() );
320 config->writeEntry( prefix + TQString(
"Bind%1" ).arg( j ), server.bindDN() );
321 config->writeEntry( prefix + TQString(
"PwdBind%1" ).arg( j ), server.pwdBindDN() );
322 config->writeEntry( prefix + TQString(
"TimeLimit%1" ).arg( j ), server.timeLimit() );
323 config->writeEntry( prefix + TQString(
"SizeLimit%1" ).arg( j ), server.sizeLimit() );
324 config->writeEntry( prefix + TQString(
"Version%1" ).arg( j ), server.version() );
325 config->writeEntry( prefix + TQString(
"Security%1" ).arg( j ), server.security() );
326 config->writeEntry( prefix + TQString(
"Auth%1" ).arg( j ), server.auth() );
327 config->writeEntry( prefix + TQString(
"Mech%1" ).arg( j ), server.mech() );
330 TDEConfig* LdapSearch::config()
333 configDeleter.setObject( s_config,
new TDEConfig(
"kabldaprc",
false,
false ) );
339 LdapSearch::LdapSearch()
340 : mActiveClients( 0 ), mNoLDAPLookup( false )
342 if ( !KProtocolInfo::isKnownProtocol( KURL(
"ldap://localhost") ) ) {
343 mNoLDAPLookup =
true;
348 connect(KDirWatch::self(), TQ_SIGNAL(dirty (
const TQString&)),
this,
349 TQ_SLOT(slotFileChanged(
const TQString&)));
352 void LdapSearch::readWeighForClient(
LdapClient *client, TDEConfig *config,
int clientNumber )
354 const int completionWeight = config->readNumEntry( TQString(
"SelectedCompletionWeight%1" ).arg( clientNumber ), -1 );
355 if ( completionWeight != -1 )
356 client->setCompletionWeight( completionWeight );
359 void LdapSearch::updateCompletionWeights()
361 TDEConfig *config = KPIM::LdapSearch::config();
362 config->setGroup(
"LDAP" );
363 for ( uint i = 0; i < mClients.size(); i++ ) {
364 readWeighForClient( mClients[i], config, i );
368 void LdapSearch::readConfig()
371 TQValueList< LdapClient* >::Iterator it;
372 for ( it = mClients.begin(); it != mClients.end(); ++it )
377 TDEConfig *config = KPIM::LdapSearch::config();
378 config->setGroup(
"LDAP" );
379 int numHosts = config->readUnsignedNumEntry(
"NumSelectedHosts");
381 mNoLDAPLookup =
true;
383 for (
int j = 0; j < numHosts; j++ ) {
386 readConfig( server, config, j,
true );
387 if ( !server.host().isEmpty() ) mNoLDAPLookup =
false;
388 ldapClient->setServer( server );
390 readWeighForClient( ldapClient, config, j );
394 attrs <<
"cn" <<
"mail" <<
"givenname" <<
"sn" <<
"objectClass";
399 connect( ldapClient, TQ_SIGNAL( done() ),
400 this, TQ_SLOT( slotLDAPDone() ) );
401 connect( ldapClient, TQ_SIGNAL( error(
const TQString& ) ),
402 this, TQ_SLOT( slotLDAPError(
const TQString& ) ) );
404 mClients.append( ldapClient );
407 connect( &mDataTimer, TQ_SIGNAL( timeout() ), TQ_SLOT( slotDataTimer() ) );
409 mConfigFile = locateLocal(
"config",
"kabldaprc" );
410 KDirWatch::self()->addFile( mConfigFile );
413 void LdapSearch::slotFileChanged(
const TQString& file )
415 if ( file == mConfigFile )
419 void LdapSearch::startSearch(
const TQString& txt )
426 int pos = txt.find(
'\"' );
430 int pos2 = txt.find(
'\"', pos );
432 mSearchText = txt.mid( pos , pos2 - pos );
434 mSearchText = txt.mid( pos );
444 TQString filter = TQString(
"&(|(objectclass=person)(objectclass=groupOfNames)(mail=*))(|(cn=%1*)(mail=%2*)(mail=*@%3*)(givenName=%4*)(sn=%5*))" )
445 .arg( mSearchText ).arg( mSearchText ).arg( mSearchText ).arg( mSearchText ).arg( mSearchText );
447 TQValueList< LdapClient* >::Iterator it;
448 for ( it = mClients.begin(); it != mClients.end(); ++it ) {
449 (*it)->startQuery( filter );
450 kdDebug(5300) <<
"LdapSearch::startSearch() " << filter << endl;
455 void LdapSearch::cancelSearch()
457 TQValueList< LdapClient* >::Iterator it;
458 for ( it = mClients.begin(); it != mClients.end(); ++it )
459 (*it)->cancelQuery();
467 mResults.append( obj );
468 if ( !mDataTimer.isActive() )
469 mDataTimer.start( 500,
true );
472 void LdapSearch::slotLDAPError(
const TQString& )
477 void LdapSearch::slotLDAPDone()
479 if ( --mActiveClients > 0 )
485 void LdapSearch::slotDataTimer()
488 LdapResultList reslist;
489 makeSearchData( lst, reslist );
490 if ( !lst.isEmpty() )
492 if ( !reslist.isEmpty() )
496 void LdapSearch::finish()
504 void LdapSearch::makeSearchData( TQStringList& ret, LdapResultList& resList )
506 TQString search_text_upper = mSearchText.upper();
508 TQValueList< KPIM::LdapObject >::ConstIterator it1;
509 for ( it1 = mResults.begin(); it1 != mResults.end(); ++it1 ) {
510 TQString name, mail, givenname, sn;
512 bool isDistributionList =
false;
518 LdapAttrMap::ConstIterator it2;
519 for ( it2 = (*it1).attrs.begin(); it2 != (*it1).attrs.end(); ++it2 ) {
520 TQByteArray val = (*it2).first();
521 int len = val.size();
522 if( len > 0 &&
'\0' == val[len-1] )
524 const TQString tmp = TQString::fromUtf8( val, len );
526 if ( it2.key() ==
"cn" ) {
538 }
else if ( it2.key() ==
"dc" ) {
549 }
else if( it2.key() ==
"mail" ) {
551 LdapAttrValue::ConstIterator it3 = it2.data().begin();
552 for ( ; it3 != it2.data().end(); ++it3 ) {
553 mails.append( TQString::fromUtf8( (*it3).data(), (*it3).size() ) );
555 }
else if( it2.key() ==
"givenName" )
557 else if( it2.key() ==
"sn" )
559 else if( it2.key() ==
"objectClass" &&
560 (tmp ==
"groupOfNames" || tmp ==
"kolabGroupOfNames") ) {
561 isDistributionList =
true;
565 if( mails.isEmpty()) {
566 if ( !mail.isEmpty() ) mails.append( mail );
567 if( isDistributionList ) {
588 }
else if ( name.isEmpty() ) {
593 ret.append( TQString(
"%1 <%2>" ).arg( name ).arg( mail ) );
601 resList.append( sr );
607 bool LdapSearch::isAvailable()
const
609 return !mNoLDAPLookup;
613 #include "ldapclient.moc"
void result(const KPIM::LdapObject &)
void setAttrs(const TQStringList &attrs)
TQStringList attrs() const
void error(const TQString &)
void startQuery(const TQString &filter)
void searchData(const TQStringList &)
Results, assembled as "Full Name <email>" (This signal can be emitted many times)
TDEPIM classes for drag and drop of mails.
Structure describing one result returned by a LDAP query.
int completionWeight
for sorting in a completion list
int clientNumber
for sorting in a ldap-only lookup