• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

libkdepim

  • sources
  • kde-4.12
  • kdepim
  • libkdepim
  • ldap
ldapclientsearch.cpp
Go to the documentation of this file.
1 /* kldapclient.cpp - LDAP access
2  * Copyright (C) 2002 Klarälvdalens Datakonsult AB
3  *
4  * Author: Steffen Hansen <hansen@kde.org>
5  *
6  * Ported to KABC by Daniel Molkentin <molkentin@kde.org>
7  *
8  * Copyright (C) 2013 Laurent Montel <montel@kde.org>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB. If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25 
26 #include "ldapclientsearch.h"
27 #include "ldapclientsearchconfig.h"
28 
29 #include "ldapclient.h"
30 #include "ldapsession.h"
31 #include "ldapqueryjob.h"
32 
33 #include <kldap/ldapobject.h>
34 #include <kldap/ldapserver.h>
35 #include <kldap/ldapurl.h>
36 #include <kldap/ldif.h>
37 
38 #include <KConfig>
39 #include <KConfigGroup>
40 #include <KDebug>
41 #include <KDirWatch>
42 #include <KProtocolInfo>
43 #include <KStandardDirs>
44 #include <kio/job.h>
45 
46 #include <QtCore/QPointer>
47 #include <QtCore/QTimer>
48 
49 
50 using namespace KLDAP;
51 
52 class LdapClientSearch::Private
53 {
54  public:
55  Private( LdapClientSearch *qq )
56  : q( qq ),
57  mActiveClients( 0 ),
58  mNoLDAPLookup( false )
59  {
60  mClientSearchConfig = new LdapClientSearchConfig;
61  }
62 
63  ~Private()
64  {
65  delete mClientSearchConfig;
66  }
67 
68  struct ResultObject {
69  const LdapClient *client;
70  KLDAP::LdapObject object;
71  };
72 
73  void readWeighForClient( LdapClient *client, const KConfigGroup &config, int clientNumber );
74  void readConfig();
75  void finish();
76  void makeSearchData( QStringList &ret, LdapResult::List &resList );
77 
78  void slotLDAPResult( const KLDAP::LdapClient &client, const KLDAP::LdapObject& );
79  void slotLDAPError( const QString& );
80  void slotLDAPDone();
81  void slotDataTimer();
82  void slotFileChanged( const QString& );
83 
84  LdapClientSearch *q;
85  QList<LdapClient*> mClients;
86  QString mSearchText;
87  QTimer mDataTimer;
88  int mActiveClients;
89  bool mNoLDAPLookup;
90  QList<ResultObject> mResults;
91  QString mConfigFile;
92  LdapClientSearchConfig *mClientSearchConfig;
93 };
94 
95 LdapClientSearch::LdapClientSearch( QObject *parent )
96  : QObject( parent ), d( new Private( this ) )
97 {
98 #ifndef Q_OS_WINCE
99 // There is no KSycoca on WinCE so this would always fail
100  if ( !KProtocolInfo::isKnownProtocol( KUrl( "ldap://localhost" ) ) ) {
101  d->mNoLDAPLookup = true;
102  return;
103  }
104 #endif
105 
106  d->readConfig();
107  connect( KDirWatch::self(), SIGNAL(dirty(QString)), this,
108  SLOT(slotFileChanged(QString)) );
109 }
110 
111 LdapClientSearch::~LdapClientSearch()
112 {
113  delete d;
114 }
115 
116 void LdapClientSearch::Private::readWeighForClient( LdapClient *client, const KConfigGroup &config,
117  int clientNumber )
118 {
119  const int completionWeight = config.readEntry( QString::fromLatin1( "SelectedCompletionWeight%1" ).arg( clientNumber ), -1 );
120  if ( completionWeight != -1 ) {
121  client->setCompletionWeight( completionWeight );
122  }
123 }
124 
125 void LdapClientSearch::updateCompletionWeights()
126 {
127  KConfigGroup config( KLDAP::LdapClientSearchConfig::config(), "LDAP" );
128  for ( int i = 0; i < d->mClients.size(); ++i ) {
129  d->readWeighForClient( d->mClients[ i ], config, i );
130  }
131 }
132 
133 QList<LdapClient*> LdapClientSearch::clients() const
134 {
135  return d->mClients;
136 }
137 
138 void LdapClientSearch::Private::readConfig()
139 {
140  q->cancelSearch();
141  qDeleteAll( mClients );
142  mClients.clear();
143 
144  // stolen from KAddressBook
145  KConfigGroup config( KLDAP::LdapClientSearchConfig::config(), "LDAP" );
146  const int numHosts = config.readEntry( "NumSelectedHosts", 0 );
147  if ( !numHosts ) {
148  mNoLDAPLookup = true;
149  } else {
150  for ( int j = 0; j < numHosts; ++j ) {
151  LdapClient *ldapClient = new LdapClient( j, q );
152  KLDAP::LdapServer server;
153  mClientSearchConfig->readConfig( server, config, j, true );
154  if ( !server.host().isEmpty() ) {
155  mNoLDAPLookup = false;
156  }
157  ldapClient->setServer( server );
158 
159  readWeighForClient( ldapClient, config, j );
160 
161  QStringList attrs;
162  attrs << QLatin1String("cn") << QLatin1String("mail") << QLatin1String("givenname") << QLatin1String("sn");
163  ldapClient->setAttributes( attrs );
164 
165  q->connect( ldapClient, SIGNAL(result(KLDAP::LdapClient,KLDAP::LdapObject)),
166  q, SLOT(slotLDAPResult(KLDAP::LdapClient,KLDAP::LdapObject)) );
167  q->connect( ldapClient, SIGNAL(done()),
168  q, SLOT(slotLDAPDone()) );
169  q->connect( ldapClient, SIGNAL(error(QString)),
170  q, SLOT(slotLDAPError(QString)) );
171 
172  mClients.append( ldapClient );
173  }
174 
175  q->connect( &mDataTimer, SIGNAL(timeout()), SLOT(slotDataTimer()) );
176  }
177  mConfigFile = KStandardDirs::locateLocal( "config", QLatin1String("kabldaprc") );
178  KDirWatch::self()->addFile( mConfigFile );
179 }
180 
181 void LdapClientSearch::Private::slotFileChanged( const QString &file )
182 {
183  if ( file == mConfigFile ) {
184  readConfig();
185  }
186 }
187 
188 void LdapClientSearch::startSearch( const QString &txt )
189 {
190  if ( d->mNoLDAPLookup ) {
191  return;
192  }
193 
194  cancelSearch();
195 
196  int pos = txt.indexOf( QLatin1Char('\"') );
197  if ( pos >= 0 ) {
198  ++pos;
199  const int pos2 = txt.indexOf( QLatin1Char('\"'), pos );
200  if ( pos2 >= 0 ) {
201  d->mSearchText = txt.mid( pos, pos2 - pos );
202  } else {
203  d->mSearchText = txt.mid( pos );
204  }
205  } else {
206  d->mSearchText = txt;
207  }
208 
209  /* The reasoning behind this filter is:
210  * If it's a person, or a distlist, show it, even if it doesn't have an email address.
211  * If it's not a person, or a distlist, only show it if it has an email attribute.
212  * This allows both resource accounts with an email address which are not a person and
213  * person entries without an email address to show up, while still not showing things
214  * like structural entries in the ldap tree. */
215 
216 #if 0
217  const QString filter = QString::fromLatin1( "&(|(objectclass=person)(objectclass=groupOfNames)(mail=*))"
218  "(|(cn=%1*)(mail=%1*)(mail=*@%1*)(givenName=%1*)(sn=%1*))" ).arg( d->mSearchText );
219 #endif
220  //Fix bug 323272 "Exchange doesn't like any queries beginning with *."
221  const QString filter = QString::fromLatin1( "&(|(objectclass=person)(objectclass=groupOfNames)(mail=*))"
222  "(|(cn=%1*)(mail=%1*)(givenName=%1*)(sn=%1*))" ).arg( d->mSearchText );
223 
224  QList<LdapClient*>::Iterator it;
225  QList<LdapClient*>::Iterator end(d->mClients.end());
226  for ( it = d->mClients.begin(); it != end; ++it ) {
227  (*it)->startQuery( filter );
228  kDebug(5300) <<"LdapClientSearch::startSearch()" << filter;
229  ++d->mActiveClients;
230  }
231 }
232 
233 void LdapClientSearch::cancelSearch()
234 {
235  QList<LdapClient*>::Iterator it;
236  QList<LdapClient*>::Iterator end(d->mClients.end());
237  for ( it = d->mClients.begin(); it != end; ++it ) {
238  (*it)->cancelQuery();
239  }
240 
241  d->mActiveClients = 0;
242  d->mResults.clear();
243 }
244 
245 void LdapClientSearch::Private::slotLDAPResult( const LdapClient &client,
246  const KLDAP::LdapObject &obj )
247 {
248  ResultObject result;
249  result.client = &client;
250  result.object = obj;
251 
252  mResults.append( result );
253  if ( !mDataTimer.isActive() ) {
254  mDataTimer.setSingleShot( true );
255  mDataTimer.start( 500 );
256  }
257 }
258 
259 void LdapClientSearch::Private::slotLDAPError( const QString& )
260 {
261  slotLDAPDone();
262 }
263 
264 void LdapClientSearch::Private::slotLDAPDone()
265 {
266  if ( --mActiveClients > 0 ) {
267  return;
268  }
269 
270  finish();
271 }
272 
273 void LdapClientSearch::Private::slotDataTimer()
274 {
275  QStringList lst;
276  LdapResult::List reslist;
277  makeSearchData( lst, reslist );
278  if ( !lst.isEmpty() ) {
279  emit q->searchData( lst );
280  }
281  if ( !reslist.isEmpty() ) {
282  emit q->searchData( reslist );
283  }
284 }
285 
286 void LdapClientSearch::Private::finish()
287 {
288  mDataTimer.stop();
289 
290  slotDataTimer(); // emit final bunch of data
291  emit q->searchDone();
292 }
293 
294 void LdapClientSearch::Private::makeSearchData( QStringList &ret, LdapResult::List &resList )
295 {
296 
297  QList< ResultObject >::ConstIterator it1;
298  QList< ResultObject >::ConstIterator end1(mResults.constEnd());
299  for ( it1 = mResults.constBegin(); it1 != end1; ++it1 ) {
300  QString name, mail, givenname, sn;
301  QStringList mails;
302  bool isDistributionList = false;
303  bool wasCN = false;
304  bool wasDC = false;
305 
306  //kDebug(5300) <<"\n\nLdapClientSearch::makeSearchData()";
307 
308  KLDAP::LdapAttrMap::ConstIterator it2;
309  for ( it2 = (*it1).object.attributes().constBegin();
310  it2 != (*it1).object.attributes().constEnd(); ++it2 ) {
311  QByteArray val = (*it2).first();
312  int len = val.size();
313  if ( len > 0 && '\0' == val[len-1] ) {
314  --len;
315  }
316  const QString tmp = QString::fromUtf8( val, len );
317  //kDebug(5300) <<" key: \"" << it2.key() <<"\" value: \"" << tmp <<"\"";
318  if ( it2.key() == QLatin1String("cn") ) {
319  name = tmp;
320  if ( mail.isEmpty() ) {
321  mail = tmp;
322  } else {
323  if ( wasCN ) {
324  mail.prepend( QLatin1String(".") );
325  } else {
326  mail.prepend( QLatin1String("@") );
327  }
328  mail.prepend( tmp );
329  }
330  wasCN = true;
331  } else if ( it2.key() == QLatin1String("dc") ) {
332  if ( mail.isEmpty() ) {
333  mail = tmp;
334  } else {
335  if ( wasDC ) {
336  mail.append( QLatin1String(".") );
337  } else {
338  mail.append( QLatin1String("@") );
339  }
340  mail.append( tmp );
341  }
342  wasDC = true;
343  } else if ( it2.key() == QLatin1String("mail") ) {
344  mail = tmp;
345  KLDAP::LdapAttrValue::ConstIterator it3 = it2.value().constBegin();
346  for ( ; it3 != it2.value().constEnd(); ++it3 ) {
347  mails.append( QString::fromUtf8( (*it3).data(), (*it3).size() ) );
348  }
349  } else if ( it2.key() == QLatin1String("givenName") ) {
350  givenname = tmp;
351  } else if ( it2.key() == QLatin1String("sn") ) {
352  sn = tmp;
353  } else if ( it2.key() == QLatin1String("objectClass") &&
354  (tmp == QLatin1String("groupOfNames") || tmp == QLatin1String("kolabGroupOfNames")) ) {
355  isDistributionList = true;
356  }
357  }
358 
359  if ( mails.isEmpty() ) {
360  if ( !mail.isEmpty() ) {
361  mails.append( mail );
362  }
363  if ( isDistributionList ) {
364  //kDebug(5300) <<"\n\nLdapClientSearch::makeSearchData() found a list:" << name;
365  ret.append( name );
366  // following lines commented out for bugfixing kolab issue #177:
367  //
368  // Unlike we thought previously we may NOT append the server name here.
369  //
370  // The right server is found by the SMTP server instead: Kolab users
371  // must use the correct SMTP server, by definition.
372  //
373  //mail = (*it1).client->base().simplified();
374  //mail.replace( ",dc=", ".", false );
375  //if( mail.startsWith("dc=", false) )
376  // mail.remove(0, 3);
377  //mail.prepend( '@' );
378  //mail.prepend( name );
379  //mail = name;
380  } else {
381  continue; // nothing, bad entry
382  }
383  } else if ( name.isEmpty() ) {
384  ret.append( mail );
385  } else {
386  ret.append( QString::fromLatin1( "%1 <%2>" ).arg( name ).arg( mail ) );
387  }
388 
389  LdapResult sr;
390  sr.clientNumber = (*it1).client->clientNumber();
391  sr.completionWeight = (*it1).client->completionWeight();
392  sr.name = name;
393  sr.email = mails;
394  resList.append( sr );
395  }
396 
397  mResults.clear();
398 }
399 
400 bool LdapClientSearch::isAvailable() const
401 {
402  return !d->mNoLDAPLookup;
403 }
404 
405 #include "ldapclientsearch.moc"
KLDAP::LdapClientSearch::isAvailable
bool isAvailable() const
Returns whether LDAP search is possible at all.
Definition: ldapclientsearch.cpp:400
KLDAP::LdapResult::clientNumber
int clientNumber
The client the contact comes from (used for sorting in a ldap-only lookup).
Definition: ldapclientsearch.h:53
ldapclientsearch.h
KLDAP::LdapClientSearch
Definition: ldapclientsearch.h:60
ldapsession.h
KLDAP::LdapClientSearch::cancelSearch
void cancelSearch()
Cancels the currently running search query.
Definition: ldapclientsearch.cpp:233
KLDAP::LdapResult
Describes the result returned by an LdapClientSearch query.
Definition: ldapclientsearch.h:44
QObject
KLDAP::LdapResult::name
QString name
The full name of the contact.
Definition: ldapclientsearch.h:51
KLDAP::LdapClientSearch::clients
QList< LdapClient * > clients() const
Returns the list of configured LDAP clients.
Definition: ldapclientsearch.cpp:133
ldapclient.h
ldapclientsearchconfig.h
KLDAP::LdapClient::setAttributes
void setAttributes(const QStringList &attributes)
Sets the LDAP attributes that should be returned in the query result.
Definition: ldapclient.cpp:125
KLDAP::LdapClientSearch::LdapClientSearch
LdapClientSearch(QObject *parent=0)
Creates a new ldap client search object.
Definition: ldapclientsearch.cpp:95
KLDAP::LdapClientSearch::startSearch
void startSearch(const QString &query)
Starts the LDAP search on all configured LDAP clients with the given search query.
Definition: ldapclientsearch.cpp:188
KLDAP::LdapClient::setServer
void setServer(const KLDAP::LdapServer &server)
Sets the LDAP server information that shall be used by this client.
Definition: ldapclient.cpp:110
KLDAP::LdapClientSearch::~LdapClientSearch
~LdapClientSearch()
Destroys the ldap client search object.
Definition: ldapclientsearch.cpp:111
KLDAP::LdapClient::setCompletionWeight
void setCompletionWeight(int weight)
Sets the completion weight of this client.
Definition: ldapclient.cpp:317
KLDAP::LdapResult::email
QStringList email
The list of emails of the contact.
Definition: ldapclientsearch.h:52
KLDAP::LdapClient
An object that represents a configured LDAP server.
Definition: ldapclient.h:48
KLDAP::LdapClientSearch::updateCompletionWeights
void updateCompletionWeights()
Updates the completion weights for the configured LDAP clients from the configuration file...
Definition: ldapclientsearch.cpp:125
KLDAP::LdapResult::completionWeight
int completionWeight
The weight of the contact (used for sorting in a completion list).
Definition: ldapclientsearch.h:54
QList
ldapqueryjob.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:58:03 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

libkdepim

Skip menu "libkdepim"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal