Changeset View
Changeset View
Standalone View
Standalone View
libkdepim/job/personsearchjob.cpp
Show All 14 Lines | /* | ||||
with this program; if not, write to the Free Software Foundation, Inc., | with this program; if not, write to the Free Software Foundation, Inc., | ||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
As a special exception, permission is given to link this program | As a special exception, permission is given to link this program | ||||
with any edition of Qt, and distribute the resulting executable, | with any edition of Qt, and distribute the resulting executable, | ||||
without including the source code for Qt in the source distribution. | without including the source code for Qt in the source distribution. | ||||
*/ | */ | ||||
#include "personsearchjob.h" | #include "personsearchjob.h" | ||||
#include <ldap/ldapclient.h> | |||||
#include <Akonadi/EntityDisplayAttribute> | #include <Akonadi/EntityDisplayAttribute> | ||||
#include <Akonadi/CollectionModifyJob> | #include <Akonadi/CollectionModifyJob> | ||||
#include <Akonadi/CollectionFetchJob> | #include <Akonadi/CollectionFetchJob> | ||||
#include <Akonadi/CollectionFetchScope> | #include <Akonadi/CollectionFetchScope> | ||||
#include <KLDAP/LdapServer> | |||||
#include <KLDAP/LdapSearch> | |||||
#include <KLocale> | #include <KLocale> | ||||
#include <baloo/pim/collectionquery.h> | #include <baloo/pim/collectionquery.h> | ||||
#include <akonadi/collectionidentificationattribute.h> | #include <akonadi/collectionidentificationattribute.h> | ||||
class ExpandGroupJob : public QObject | |||||
{ | |||||
Q_OBJECT | |||||
public: | |||||
ExpandGroupJob(const KLDAP::LdapObject &groupObject, const KLDAP::LdapServer &server, const QStringList& attributes); | |||||
virtual ~ExpandGroupJob(); | |||||
typedef QSharedPointer<ExpandGroupJob> Ptr; | |||||
virtual void start(); | |||||
const QString &groupName() const; | |||||
Q_SIGNALS: | |||||
void groupMembers(const QString groupName, const QList<KLDAP::LdapObject> &objects); | |||||
private Q_SLOTS: | |||||
void groupResult(KLDAP::LdapSearch *ldapSearch, KLDAP::LdapObject object); | |||||
void onResult(KLDAP::LdapSearch *); | |||||
private: | |||||
void searchNext(KLDAP::LdapSearch *ldapSearch); | |||||
KLDAP::LdapConnection mConnection; | |||||
KLDAP::LdapAttrValue mGroupMembersDN; | |||||
QString mGroupName; | |||||
QStringList mAttributes; | |||||
QList<KLDAP::LdapObject> mResults; | |||||
}; | |||||
ExpandGroupJob::ExpandGroupJob(const KLDAP::LdapObject &groupObject, const KLDAP::LdapServer &server, const QStringList &attributes) | |||||
: QObject() | |||||
, mConnection(server) | |||||
, mAttributes(attributes) | |||||
, mGroupMembersDN(groupObject.values(QLatin1String("uniqueMember"))) | |||||
, mGroupName(QString::fromUtf8(groupObject.value(QLatin1String("cn")))) | |||||
{ | |||||
} | |||||
ExpandGroupJob::~ExpandGroupJob() | |||||
{ | |||||
mConnection.close(); | |||||
} | |||||
void ExpandGroupJob::start() | |||||
{ | |||||
mConnection.connect(); | |||||
KLDAP::LdapSearch *search(new KLDAP::LdapSearch(mConnection)); | |||||
connect(search, SIGNAL(data(KLDAP::LdapSearch*,KLDAP::LdapObject)), SLOT(groupResult(KLDAP::LdapSearch*,KLDAP::LdapObject))); | |||||
connect(search, SIGNAL(result(KLDAP::LdapSearch*)), SLOT(onResult(KLDAP::LdapSearch*))); | |||||
searchNext(search); | |||||
} | |||||
const QString &ExpandGroupJob::groupName() const | |||||
{ | |||||
return mGroupName; | |||||
} | |||||
void ExpandGroupJob::groupResult(KLDAP::LdapSearch *ldapSearch, KLDAP::LdapObject object) | |||||
{ | |||||
mResults << object; | |||||
} | |||||
void ExpandGroupJob::onResult(KLDAP::LdapSearch *ldapSearch) | |||||
{ | |||||
if (mGroupMembersDN.isEmpty()) { | |||||
emit groupMembers(groupName(), mResults); | |||||
} else { | |||||
searchNext(ldapSearch); | |||||
} | |||||
} | |||||
void ExpandGroupJob::searchNext(KLDAP::LdapSearch *ldapSearch) | |||||
{ | |||||
ldapSearch->search(KLDAP::LdapDN(QString::fromLatin1(mGroupMembersDN.takeFirst())), KLDAP::LdapUrl::Base, QString(), mAttributes); | |||||
} | |||||
PersonSearchJob::PersonSearchJob(const QString& searchString, QObject* parent) | PersonSearchJob::PersonSearchJob(const QString& searchString, QObject* parent) | ||||
: KJob(parent), | : KJob(parent), | ||||
mSearchString(searchString) | mSearchString(searchString) | ||||
{ | { | ||||
QStringList attrs = mLdapSearch.attributes(); | |||||
attrs.append(QLatin1String("uniqueMember")); | |||||
mLdapSearch.setAttributes(attrs); | |||||
connect(&mLdapSearch, SIGNAL(searchData(const QList<KLDAP::LdapResultObject> &)), | connect(&mLdapSearch, SIGNAL(searchData(const QList<KLDAP::LdapResultObject> &)), | ||||
SLOT(onLDAPSearchData(const QList<KLDAP::LdapResultObject> &))); | SLOT(onLDAPSearchData(const QList<KLDAP::LdapResultObject> &))); | ||||
connect(&mLdapSearch, SIGNAL(searchDone()), | connect(&mLdapSearch, SIGNAL(searchDone()), | ||||
SLOT(onLDAPSearchDone())); | SLOT(onLDAPSearchDone())); | ||||
} | } | ||||
PersonSearchJob::~PersonSearchJob() | PersonSearchJob::~PersonSearchJob() | ||||
{ | { | ||||
mLdapSearch.cancelSearch(); | mLdapSearch.cancelSearch(); | ||||
} | } | ||||
bool PersonSearchJob::kill(KJob::KillVerbosity verbosity) | bool PersonSearchJob::kill(KJob::KillVerbosity verbosity) | ||||
{ | { | ||||
Q_FOREACH(ExpandGroupJob::Ptr job, mExpandGroupJobs) { | |||||
disconnect(job.data()); | |||||
} | |||||
mExpandGroupJobs.clear(); | |||||
mLdapSearch.cancelSearch(); | mLdapSearch.cancelSearch(); | ||||
return KJob::kill(verbosity); | return KJob::kill(verbosity); | ||||
} | } | ||||
void PersonSearchJob::start() | void PersonSearchJob::start() | ||||
{ | { | ||||
Baloo::PIM::CollectionQuery query; | Baloo::PIM::CollectionQuery query; | ||||
query.setNamespace(QStringList() << QLatin1String("usertoplevel")); | query.setNamespace(QStringList() << QLatin1String("usertoplevel")); | ||||
query.nameMatches(mSearchString); | query.nameMatches(mSearchString); | ||||
query.setLimit(200); | query.setLimit(200); | ||||
Baloo::PIM::ResultIterator it = query.exec(); | Baloo::PIM::ResultIterator it = query.exec(); | ||||
Akonadi::Collection::List collections; | Akonadi::Collection::List collections; | ||||
while (it.next()) { | while (it.next()) { | ||||
collections << Akonadi::Collection(it.id()); | collections << Akonadi::Collection(it.id()); | ||||
} | } | ||||
kDebug() << "Found persons " << collections.size(); | kDebug() << "Found persons " << collections.size(); | ||||
mCollectionSearchDone = false; | mCollectionSearchDone = false; | ||||
mLdapSearchDone = false; | mLdapSearchDone = false; | ||||
if (collections.isEmpty()) { | if (collections.isEmpty()) { | ||||
//We didn't find anything | //We didn't find anything | ||||
mCollectionSearchDone = true; | mCollectionSearchDone = true; | ||||
} | } | ||||
Q_FOREACH(ExpandGroupJob::Ptr job, mExpandGroupJobs) { | |||||
disconnect(job.data()); | |||||
} | |||||
mExpandGroupJobs.clear(); | |||||
mLdapSearch.startSearch(QLatin1String("*") + mSearchString); | mLdapSearch.startSearch(QLatin1String("*") + mSearchString); | ||||
if (!collections.isEmpty()) { | if (!collections.isEmpty()) { | ||||
Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob(collections, Akonadi::CollectionFetchJob::Base, this); | Akonadi::CollectionFetchJob *fetchJob = new Akonadi::CollectionFetchJob(collections, Akonadi::CollectionFetchJob::Base, this); | ||||
fetchJob->fetchScope().setAncestorRetrieval(Akonadi::CollectionFetchScope::All); | fetchJob->fetchScope().setAncestorRetrieval(Akonadi::CollectionFetchScope::All); | ||||
fetchJob->fetchScope().setListFilter(Akonadi::CollectionFetchScope::NoFilter); | fetchJob->fetchScope().setListFilter(Akonadi::CollectionFetchScope::NoFilter); | ||||
connect(fetchJob, SIGNAL(collectionsReceived(Akonadi::Collection::List)), this, SLOT(onCollectionsReceived(Akonadi::Collection::List))); | connect(fetchJob, SIGNAL(collectionsReceived(Akonadi::Collection::List)), this, SLOT(onCollectionsReceived(Akonadi::Collection::List))); | ||||
connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(onCollectionsFetched(KJob*))); | connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(onCollectionsFetched(KJob*))); | ||||
} | } | ||||
//The IMAP resource should add a "Person" attribute to the collections in the person namespace, | //The IMAP resource should add a "Person" attribute to the collections in the person namespace, | ||||
//the ldap query can then be used to update the name (entitydisplayattribute) for the person. | //the ldap query can then be used to update the name (entitydisplayattribute) for the person. | ||||
} | } | ||||
bool PersonSearchJob::isGroup(KLDAP::LdapObject object) const | |||||
{ | |||||
const KLDAP::LdapAttrValue objectClasses = object.values(QLatin1String("objectClass")); | |||||
if (objectClasses.contains(QLatin1String("groupofuniquenames").latin1()) | |||||
|| objectClasses.contains(QLatin1String("kolabgroupofuniquenames").latin1())) { | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
void PersonSearchJob::onGroupFound(QString name, QList< KLDAP::LdapObject > members) | |||||
{ | |||||
Q_ASSERT(mExpandGroupJobs.contains(name)); | |||||
ExpandGroupJob::Ptr job = mExpandGroupJobs.take(name); | |||||
Q_ASSERT(job); | |||||
QList<Person> persons; | |||||
Q_FOREACH(const KLDAP::LdapObject &item, members) { | |||||
Person person; | |||||
person.group = name; | |||||
person.name = QString::fromUtf8(item.value(QLatin1String("cn"))); | |||||
person.mail = QString::fromUtf8(item.value(QLatin1String("mail"))); | |||||
const int depth = item.dn().depth(); | |||||
for ( int i = 0; i < depth; ++i ) { | |||||
const QString rdnStr = item.dn().rdnString(i); | |||||
if ( rdnStr.startsWith(QLatin1String("ou="), Qt::CaseInsensitive) ) { | |||||
person.ou = rdnStr.mid(3); | |||||
break; | |||||
} | |||||
} | |||||
const QStringList &parts = person.mail.split(QLatin1Char('@')); | |||||
if (parts.count() == 2) { | |||||
const QString &uid = parts.at(0); | |||||
person.uid = uid; | |||||
if (mMatches.contains(uid)) { | |||||
const Person &p = mMatches.value(uid); | |||||
if (p.mail != person.mail ) { | |||||
if (p.rootCollection > -1) { | |||||
person.rootCollection = p.rootCollection; | |||||
person.updateDisplayName = p.updateDisplayName; | |||||
updatePersonCollection(person); | |||||
mMatches.insert(uid, person); | |||||
} else { | |||||
kWarning() << "That should not happen: we found two times persons with the same uid ("<< uid << "), but differnet name:" << p.name << "vs" << person.name; | |||||
} | |||||
} | |||||
} else { //New person found | |||||
mMatches.insert(uid, person); | |||||
persons << person; | |||||
} | |||||
} else { | |||||
kWarning() << item.dn().toString() << ": invalid email address" << person.mail; | |||||
} | |||||
} | |||||
if (persons.count() > 0) { | |||||
emit personsFound(persons); | |||||
} | |||||
onLDAPSearchDone(); | |||||
} | |||||
void PersonSearchJob::onLDAPSearchData(const QList< KLDAP::LdapResultObject > &list) | void PersonSearchJob::onLDAPSearchData(const QList< KLDAP::LdapResultObject > &list) | ||||
{ | { | ||||
QList<Person> persons; | QList<Person> persons; | ||||
Q_FOREACH(const KLDAP::LdapResultObject &item, list) { | Q_FOREACH(const KLDAP::LdapResultObject &item, list) { | ||||
if (isGroup(item.object)) { | |||||
ExpandGroupJob::Ptr job(new ExpandGroupJob(item.object, item.client->server(), mLdapSearch.attributes())); | |||||
connect(job.data(), SIGNAL(groupMembers(QString,QList<KLDAP::LdapObject>)), SLOT(onGroupFound(QString,QList<KLDAP::LdapObject>))); | |||||
if (mExpandGroupJobs.contains(job->groupName())) { | |||||
ExpandGroupJob::Ptr j2 = mExpandGroupJobs.take(job->groupName()); | |||||
disconnect(j2.data()); | |||||
j2->deleteLater(); | |||||
} | |||||
mExpandGroupJobs.insert(job->groupName(), job); | |||||
job->start(); | |||||
continue; | |||||
} | |||||
Person person; | Person person; | ||||
person.name = QString::fromUtf8(item.object.value(QLatin1String("cn"))); | person.name = QString::fromUtf8(item.object.value(QLatin1String("cn"))); | ||||
person.mail = QString::fromUtf8(item.object.value(QLatin1String("mail"))); | person.mail = QString::fromUtf8(item.object.value(QLatin1String("mail"))); | ||||
const int depth = item.object.dn().depth(); | const int depth = item.object.dn().depth(); | ||||
for ( int i = 0; i < depth; ++i ) { | for ( int i = 0; i < depth; ++i ) { | ||||
const QString rdnStr = item.object.dn().rdnString(i); | const QString rdnStr = item.object.dn().rdnString(i); | ||||
if ( rdnStr.startsWith(QLatin1String("ou="), Qt::CaseInsensitive) ) { | if ( rdnStr.startsWith(QLatin1String("ou="), Qt::CaseInsensitive) ) { | ||||
Show All 27 Lines | void PersonSearchJob::onLDAPSearchData(const QList< KLDAP::LdapResultObject > &list) | ||||
} | } | ||||
if (persons.count() > 0) { | if (persons.count() > 0) { | ||||
emit personsFound(persons); | emit personsFound(persons); | ||||
} | } | ||||
} | } | ||||
void PersonSearchJob::onLDAPSearchDone() | void PersonSearchJob::onLDAPSearchDone() | ||||
{ | { | ||||
if (mExpandGroupJobs.count() > 0) { | |||||
return; | |||||
} | |||||
mLdapSearchDone = true; | mLdapSearchDone = true; | ||||
if (mCollectionSearchDone) { | if (mCollectionSearchDone) { | ||||
emitResult(); | emitResult(); | ||||
} | } | ||||
} | } | ||||
void PersonSearchJob::onCollectionsReceived(const Akonadi::Collection::List &list) | void PersonSearchJob::onCollectionsReceived(const Akonadi::Collection::List &list) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 103 Lines • ▼ Show 20 Lines | if (attr) { | ||||
person.updateDisplayName = true; | person.updateDisplayName = true; | ||||
} | } | ||||
} | } | ||||
kDebug() << "modified person to" << person.uid << person.name << person.rootCollection; | kDebug() << "modified person to" << person.uid << person.name << person.rootCollection; | ||||
mMatches.insert(person.uid, person); | mMatches.insert(person.uid, person); | ||||
emit personUpdate(person); | emit personUpdate(person); | ||||
} | } | ||||
#include "personsearchjob.moc" | |||||
No newline at end of file |