diff --git a/retrievegroupmembersjob.cpp b/retrievegroupmembersjob.cpp index 863963c..fc5b6a9 100644 --- a/retrievegroupmembersjob.cpp +++ b/retrievegroupmembersjob.cpp @@ -1,299 +1,301 @@ /* * Copyright (C) 2013 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "retrievegroupmembersjob.h" #include "ldapmapper.h" #include "settings.h" #include #include #include #include #include #include #include #include #include RetrieveGroupMembersJob::RetrieveGroupMembersJob(const QString &searchbase, const Akonadi::Collection& col, KLDAP::LdapConnection& connection, QObject* parent) : Job(parent), mFetchScope(LookupPayload), mLdapSearch(connection), mParentCollection(col), mTransaction(0), mSearchbase(searchbase), mSaveContactGroup(false) { Q_ASSERT(connection.handle()); connect( &mLdapSearch, SIGNAL(result(KLDAP::LdapSearch*)), this, SLOT(gotSearchResult(KLDAP::LdapSearch*)) ); connect( &mLdapSearch, SIGNAL(data(KLDAP::LdapSearch*,KLDAP::LdapObject)), this, SLOT(gotSearchData(KLDAP::LdapSearch*,KLDAP::LdapObject)) ); } void RetrieveGroupMembersJob::doStart() { kDebug(); Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob(mParentCollection, this); job->fetchScope().setFetchModificationTime(false); job->fetchScope().setCacheOnly(true); job->fetchScope().fetchFullPayload(false); connect(job, SIGNAL(itemsReceived(Akonadi::Item::List)), this, SLOT(localItemsReceived(Akonadi::Item::List))); connect(job, SIGNAL(result(KJob*)), this, SLOT(localFetchDone(KJob*))); mTime.start(); } void RetrieveGroupMembersJob::setFetchScope(RetrieveGroupMembersJob::FetchScope fetchScope) { mFetchScope = fetchScope; } void RetrieveGroupMembersJob::localItemsReceived(const Akonadi::Item::List &items) { kDebug() << items.size(); foreach (const Akonadi::Item &item, items) { kDebug() << item.remoteId() << item.remoteRevision(); if (mLocalItems.contains(item.remoteId())) { Akonadi::ItemDeleteJob *job = new Akonadi::ItemDeleteJob(item, transaction()); transaction()->setIgnoreJobFailure(job); continue; } mLocalItems.insert(item.remoteId(), item.remoteRevision()); mRemoteLocalIds.insert(item.remoteId(), item.id()); } } void RetrieveGroupMembersJob::localFetchDone(KJob *job) { kDebug(); if (job->error()) { kWarning() << "retrieval failed"; setError(KJob::UserDefinedError); emitResult(); return; } searchForGroup(); } void RetrieveGroupMembersJob::searchForGroup() { kDebug(); - const int ret = mLdapSearch.search( KLDAP::LdapDN(mSearchbase), KLDAP::LdapUrl::Sub, QString("%1=%2").arg(LDAPMapper::getAttribute(LDAPMapper::UniqueIdentifier)).arg(mParentCollection.remoteId()), QStringList() << "nsuniqueid" << "uniqueMember" << "cn"); + const int ret = mLdapSearch.search( KLDAP::LdapDN(mSearchbase), KLDAP::LdapUrl::Sub, + QString("%1=%2").arg(LDAPMapper::getAttribute(LDAPMapper::UniqueIdentifier)).arg(mParentCollection.remoteId()), + QStringList() << "nsuniqueid" << "uniqueMember" << "cn"); if (!ret) { kWarning() << mLdapSearch.errorString(); kWarning() << "retrieval failed"; setError(KJob::UserDefinedError); emitResult(); } } void RetrieveGroupMembersJob::searchForMember(const QString &memberDn) { kDebug(); const QStringList attributes = mFetchScope == FullPayload ? LDAPMapper::requestedFullPayloadAttributes() : LDAPMapper::requestedLookupPayloadAttributes(); const int ret = mLdapSearch.search( KLDAP::LdapDN(memberDn), KLDAP::LdapUrl::Base, QString(), attributes); if (!ret) { kWarning() << mLdapSearch.errorString(); kWarning() << "retrieval failed"; setError(KJob::UserDefinedError); emitResult(); } } bool RetrieveGroupMembersJob::getNextMember() { if (mGroupMembers.isEmpty()) { return false; } const QString member = mGroupMembers.takeFirst(); searchForMember(member); return true; } void RetrieveGroupMembersJob::gotSearchResult(KLDAP::LdapSearch *search) { Q_UNUSED( search ); kDebug() << search->isFinished(); if (search->error()) { kWarning() << search->error() << search->errorString(); switch (search->error()) { case KLDAP_SIZELIMIT_EXCEEDED: kWarning() << "Sizelimit exceeded"; break; default: kWarning() << "Unknown error"; } setError(KJob::UserDefinedError); done(); return; } if (getNextMember()) { return; } //only do the removal if we got all entires without anything missing Akonadi::Item::List toRemove; toRemove.reserve(mLocalItems.size()); QHash::const_iterator it = mLocalItems.constBegin(); for (; it != mLocalItems.constEnd(); it++) { kDebug() << mParentCollection.name() << "deleted " << it.key(); Akonadi::Item item; item.setRemoteId(it.key()); toRemove << item; } if (!toRemove.isEmpty()) { Akonadi::ItemDeleteJob *job = new Akonadi::ItemDeleteJob(toRemove, transaction()); transaction()->setIgnoreJobFailure(job); } if (!mTransaction) { // no jobs created here -> savegroup if (mSaveContactGroup) { saveContactGroup(); } else { done(); } } else { mTransaction->commit(); } } void RetrieveGroupMembersJob::gotSearchData(KLDAP::LdapSearch *search, const KLDAP::LdapObject &obj) { Q_UNUSED( search ); kWarning(); kDebug() << "Object:"; kDebug() << obj.toString(); if (obj.value("nsuniqueid") == mParentCollection.remoteId()) { foreach (const QByteArray &val, obj.values("uniqueMember")) { mGroupMembers << val; } kDebug() << "found members: " << mGroupMembers; KABC::ContactGroup group; group.setName(obj.value("cn")); //group.setEmail(obj.value("email")); mGroup = group; mGroupItem = Akonadi::Item(); mGroupItem.setRemoteId(LDAPMapper::getStableIdentifier(obj)); mGroupItem.setMimeType(KABC::ContactGroup::mimeType()); const QHash::iterator it = mLocalItems.find(mGroupItem.remoteId()); mSaveContactGroup = true; if (it != mLocalItems.end()) { const QHash::iterator uid = mRemoteLocalIds.find(mGroupItem.remoteId()); mGroupItem.setId(*uid); kDebug() << mGroupItem.remoteId() << mGroupItem.id(); if (*it == LDAPMapper::getTimestamp(obj)) { mSaveContactGroup = false; kDebug() << "skipping " << mGroupItem.remoteId(); } mLocalItems.erase(it); return; } } else { kDebug() << "got person: " << obj.dn().toString() << obj.value("nsuniqueid") << obj.value("modifyTimestamp"); Akonadi::Item item; item.setRemoteId(LDAPMapper::getStableIdentifier(obj)); item.setPayload(LDAPMapper::getAddressee(obj)); item.setMimeType(KABC::Addressee::mimeType()); item.setParentCollection(mParentCollection); item.setRemoteRevision(LDAPMapper::getTimestamp(obj)); const QHash::iterator it = mLocalItems.find(item.remoteId()); if (it != mLocalItems.end()) { const QHash::iterator uid = mRemoteLocalIds.find(item.remoteId()); KABC::ContactGroup::ContactReference reference; reference.setUid(QString::number(*uid)); mGroup.append(reference); if (*it == LDAPMapper::getTimestamp(obj)) { kDebug() << "skipping " << item.remoteId(); } else { kDebug() << "modification"; new Akonadi::ItemModifyJob(item, transaction()); } mLocalItems.erase(it); return; } //new item Akonadi::ItemCreateJob *job = new Akonadi::ItemCreateJob(item, mParentCollection, transaction()); connect(job, SIGNAL(result(KJob*)), SLOT(createdItem(KJob*))); } } void RetrieveGroupMembersJob::createdItem(KJob* job) { Akonadi::ItemCreateJob *itemjob =static_cast(job); if (!job->error()) { mSaveContactGroup = true; KABC::ContactGroup::ContactReference reference; reference.setUid(QString::number(itemjob->item().id())); mGroup.append(reference); } } Akonadi::TransactionSequence* RetrieveGroupMembersJob::transaction() { - if ( !mTransaction ) { - mTransaction= new Akonadi::TransactionSequence( this ); - mTransaction->setAutomaticCommittingEnabled( false ); - connect(mTransaction, SIGNAL(result(KJob*)), SLOT(transactionDone(KJob*)) ); + if (!mTransaction) { + mTransaction= new Akonadi::TransactionSequence(this); + mTransaction->setAutomaticCommittingEnabled(false); + connect(mTransaction, SIGNAL(result(KJob*)), SLOT(transactionDone(KJob*))); } return mTransaction; } void RetrieveGroupMembersJob::transactionDone (KJob* job) { - if ( job->error() ) { + if (job->error()) { return; // handled by base class } if (mSaveContactGroup) { saveContactGroup(); } else { done(); } } void RetrieveGroupMembersJob::saveContactGroup() { mGroupItem.setPayload(mGroup); if (mGroupItem.isValid()) { kDebug() << "modify"; Akonadi::ItemModifyJob *job = new Akonadi::ItemModifyJob(mGroupItem, this); connect(job, SIGNAL(result(KJob*)), SLOT(savedContactGroup(KJob*))); } else { kDebug() << "new"; Akonadi::ItemCreateJob::Job *job = new Akonadi::ItemCreateJob(mGroupItem, mParentCollection, this); connect(job, SIGNAL(result(KJob*)), SLOT(savedContactGroup(KJob*))); } } void RetrieveGroupMembersJob::savedContactGroup(KJob *job) { - if ( job->error() ) { + if (job->error()) { return; // handled by base class } done(); } void RetrieveGroupMembersJob::done() { kDebug() << "Done. Took " << mTime.elapsed()/1000.0 << " s"; emitResult(); } diff --git a/retrievegroupmembersjob.h b/retrievegroupmembersjob.h index 1dca472..c555a56 100644 --- a/retrievegroupmembersjob.h +++ b/retrievegroupmembersjob.h @@ -1,79 +1,79 @@ /* * Copyright (C) 2013 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef RETRIEVEGROUPMEMBERS_H #define RETRIEVEGROUPMEMBERS_H #include #include #include #include #include #include #include #include class RetrieveGroupMembersJob: public Akonadi::Job { Q_OBJECT public: enum FetchScope { LookupPayload, FullPayload }; explicit RetrieveGroupMembersJob(const QString &searchbase, const Akonadi::Collection &col, KLDAP::LdapConnection &connection, QObject* parent = 0); virtual void doStart(); - + void setFetchScope(FetchScope fetchScope); signals: void contactsRetrieved(const Akonadi::Item::List &); - + private Q_SLOTS: void gotSearchResult(KLDAP::LdapSearch *search); void gotSearchData(KLDAP::LdapSearch *search, const KLDAP::LdapObject &obj); void localFetchDone(KJob*); void localItemsReceived(const Akonadi::Item::List &); void transactionDone(KJob* job); void createdItem(KJob* job); void savedContactGroup(KJob* job); - + private: Akonadi::TransactionSequence *transaction(); void searchForGroup(); void searchForMember(const QString &memberDn); void done(); bool getNextMember(); void saveContactGroup(); FetchScope mFetchScope; KLDAP::LdapSearch mLdapSearch; Akonadi::Collection mParentCollection; QHash mLocalItems; QHash mRemoteLocalIds; Akonadi::TransactionSequence *mTransaction; QString mSearchbase; QTime mTime; QStringList mGroupMembers; Akonadi::Item mGroupItem; KABC::ContactGroup mGroup; bool mSaveContactGroup; }; #endif // RETRIEVEITEMSJOB_H diff --git a/retrievegroupsjob.cpp b/retrievegroupsjob.cpp index a042938..721c6b4 100644 --- a/retrievegroupsjob.cpp +++ b/retrievegroupsjob.cpp @@ -1,97 +1,98 @@ /* * Copyright (C) 2013 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "retrievegroupsjob.h" #include "ldapmapper.h" #include #include #include #include #include #include #include #include RetrieveGroupsJob::RetrieveGroupsJob(const QString &searchbase, const Akonadi::Collection& col, KLDAP::LdapConnection& connection, QObject* parent) : Job(parent), mLdapSearch(connection), mParentCollection(col), mSearchbase(searchbase) { Q_ASSERT(connection.handle()); connect( &mLdapSearch, SIGNAL(result(KLDAP::LdapSearch*)), this, SLOT(gotSearchResult(KLDAP::LdapSearch*)) ); connect( &mLdapSearch, SIGNAL(data(KLDAP::LdapSearch*,KLDAP::LdapObject)), this, SLOT(gotSearchData(KLDAP::LdapSearch*,KLDAP::LdapObject)) ); } void RetrieveGroupsJob::doStart() { - kDebug(); search(); } void RetrieveGroupsJob::search() { kDebug(); - const int ret = mLdapSearch.search( KLDAP::LdapDN(mSearchbase), KLDAP::LdapUrl::Sub, QLatin1String("(|(objectClass=groupofuniquenames)(objectClass=kolabgroupofuniquenames))"), QStringList() << "cn" << "nsuniqueid"); + const int ret = mLdapSearch.search( KLDAP::LdapDN(mSearchbase), KLDAP::LdapUrl::Sub, + QLatin1String("(|(objectClass=groupofuniquenames)(objectClass=kolabgroupofuniquenames))"), + QStringList() << "cn" << "nsuniqueid"); if (!ret) { kWarning() << mLdapSearch.errorString(); kWarning() << "retrieval failed"; setError(KJob::UserDefinedError); emitResult(); } } void RetrieveGroupsJob::gotSearchResult(KLDAP::LdapSearch *search) { Q_UNUSED( search ); kDebug() << search->isFinished(); if (search->error()) { kWarning() << search->error() << search->errorString(); switch (search->error()) { case KLDAP_SIZELIMIT_EXCEEDED: kWarning() << "Sizelimit exceeded"; break; default: kWarning() << "Unknown error"; } } else { kDebug() << mRetrievedCollections.size() << " groups retrieved"; } emitResult(); } void RetrieveGroupsJob::gotSearchData(KLDAP::LdapSearch *search, const KLDAP::LdapObject &obj) { Q_UNUSED( search ); kWarning(); kDebug() << "Object:"; kDebug() << obj.toString(); kDebug() << "got group: " << obj.dn().toString() << obj.value("nsuniqueid"); Akonadi::Collection col; col.setRemoteId(LDAPMapper::getStableIdentifier(obj)); col.setContentMimeTypes(QStringList() << KABC::Addressee::mimeType() << Akonadi::Collection::mimeType()); col.setParentCollection(mParentCollection); col.setName(obj.value("cn")); mRetrievedCollections << col; } Akonadi::Collection::List RetrieveGroupsJob::retrievedCollections() const { return mRetrievedCollections; } diff --git a/retrieveitemsjob.cpp b/retrieveitemsjob.cpp index 5b528bf..1c9358a 100644 --- a/retrieveitemsjob.cpp +++ b/retrieveitemsjob.cpp @@ -1,210 +1,210 @@ /* * Copyright (C) 2013 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "retrieveitemsjob.h" #include "ldapmapper.h" #include #include #include #include #include #include #include #include #include RetrieveItemsJob::RetrieveItemsJob(const QString &searchbase, const Akonadi::Collection& col, KLDAP::LdapConnection& connection, QObject* parent) : Job(parent), mFetchScope(LookupPayload), mLdapSearch(connection), mParentCollection(col), mTransaction(0), mSearchbase(searchbase) { Q_ASSERT(connection.handle()); connect( &mLdapSearch, SIGNAL(result(KLDAP::LdapSearch*)), this, SLOT(gotSearchResult(KLDAP::LdapSearch*)) ); connect( &mLdapSearch, SIGNAL(data(KLDAP::LdapSearch*,KLDAP::LdapObject)), this, SLOT(gotSearchData(KLDAP::LdapSearch*,KLDAP::LdapObject)) ); } void RetrieveItemsJob::doStart() { kDebug(); Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob(mParentCollection, this); job->fetchScope().setFetchModificationTime(false); job->fetchScope().setCacheOnly(true); job->fetchScope().fetchFullPayload(false); connect(job, SIGNAL(itemsReceived(Akonadi::Item::List)), this, SLOT(localItemsReceived(Akonadi::Item::List))); connect(job, SIGNAL(result(KJob*)), this, SLOT(localFetchDone(KJob*))); mTime.start(); } void RetrieveItemsJob::setFetchScope(RetrieveItemsJob::FetchScope fetchScope) { mFetchScope = fetchScope; } void RetrieveItemsJob::localItemsReceived(const Akonadi::Item::List &items) { kDebug() << items.size(); foreach (const Akonadi::Item &item, items) { kDebug() << item.remoteId() << item.remoteRevision(); mLocalItems.insert(item.remoteId(), item.remoteRevision()); } } void RetrieveItemsJob::localFetchDone(KJob *job) { kDebug(); if (job->error()) { kWarning() << "retrieval failed"; setError(KJob::UserDefinedError); emitResult(); return; } search(); } void RetrieveItemsJob::search() { kDebug(); const QStringList attributes = mFetchScope == FullPayload ? LDAPMapper::requestedFullPayloadAttributes() : LDAPMapper::requestedLookupPayloadAttributes(); const int ret = mLdapSearch.search( KLDAP::LdapDN(mSearchbase), KLDAP::LdapUrl::Sub, QLatin1String("objectClass=inetorgperson"), attributes); if (!ret) { kWarning() << mLdapSearch.errorString(); kWarning() << "retrieval failed"; setError(KJob::UserDefinedError); emitResult(); } } void RetrieveItemsJob::gotSearchResult(KLDAP::LdapSearch *search) { Q_UNUSED( search ); if (search->error()) { kWarning() << search->error() << search->errorString(); switch (search->error()) { case KLDAP_SIZELIMIT_EXCEEDED: kWarning() << "Sizelimit exceeded"; break; case KLDAP_ADMINLIMIT_EXCEEDED: kWarning() << "Administrative limit exceeded"; break; default: kWarning() << "Unknown error"; } } else { //only do the removal if we got all entires without anything missing Akonadi::Item::List toRemove; toRemove.reserve(mLocalItems.size()); QHash::const_iterator it = mLocalItems.constBegin(); for (; it != mLocalItems.constEnd(); it++) { kDebug() << "deleted " << it.key(); Akonadi::Item item; item.setRemoteId(it.key()); toRemove << item; } if (!toRemove.isEmpty()) { Akonadi::ItemDeleteJob *job = new Akonadi::ItemDeleteJob(toRemove, transaction()); transaction()->setIgnoreJobFailure(job); } if (!mMostRecentTimestamp.isEmpty()) { Akonadi::Collection col = mParentCollection; col.setRemoteRevision(mMostRecentTimestamp); Akonadi::CollectionModifyJob *job = new Akonadi::CollectionModifyJob(col, transaction()); transaction()->setIgnoreJobFailure(job); } } if (!mTransaction) { // no jobs created here -> done done(); } else { mTransaction->commit(); } } void RetrieveItemsJob::gotSearchData(KLDAP::LdapSearch *search, const KLDAP::LdapObject &obj) { Q_UNUSED( search ); kWarning(); kDebug() << "Object:"; kDebug() << obj.toString(); kDebug() << "got person: " << obj.dn().toString() << obj.value("nsuniqueid") << obj.value("modifyTimestamp"); updateMostRecentTimestamp(LDAPMapper::getTimestamp(obj)); Akonadi::Item item; item.setRemoteId(LDAPMapper::getStableIdentifier(obj)); item.setPayload(LDAPMapper::getAddressee(obj)); item.setMimeType(KABC::Addressee::mimeType()); item.setParentCollection(mParentCollection); item.setRemoteRevision(LDAPMapper::getTimestamp(obj)); const QHash::iterator it = mLocalItems.find(item.remoteId()); if (it != mLocalItems.end()) { if (*it == LDAPMapper::getTimestamp(obj)) { kDebug() << "skipping " << item.remoteId(); } else { kDebug() << "modification"; new Akonadi::ItemModifyJob(item, transaction()); } mLocalItems.erase(it); return; } //new item new Akonadi::ItemCreateJob(item, mParentCollection, transaction()); } Akonadi::TransactionSequence* RetrieveItemsJob::transaction() { - if ( !mTransaction ) { + if (!mTransaction) { mTransaction= new Akonadi::TransactionSequence( this ); mTransaction->setAutomaticCommittingEnabled( false ); connect(mTransaction, SIGNAL(result(KJob*)), SLOT(transactionDone(KJob*)) ); } return mTransaction; } void RetrieveItemsJob::transactionDone (KJob* job) { - if ( job->error() ) { + if (job->error()) { return; // handled by base class } done(); } void RetrieveItemsJob::done() { kDebug() << "Done. Took " << mTime.elapsed()/1000.0 << " s"; emitResult(); } void RetrieveItemsJob::updateMostRecentTimestamp(const QString ×tamp) { if (!timestamp.isEmpty()) { if (mMostRecentTimestamp.isEmpty() || mMostRecentTimestamp < timestamp) { mMostRecentTimestamp = timestamp; } } } diff --git a/updategroupjob.cpp b/updategroupjob.cpp index 67989c4..ece692f 100644 --- a/updategroupjob.cpp +++ b/updategroupjob.cpp @@ -1,265 +1,265 @@ /* * Copyright (C) 2014 Klaralvdalens Datakonsult AB * Author: Kevin Krammer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "updategroupjob.h" #include "incrementalupdatedata.h" #include "ldapmapper.h" #include #include #include #include #include #include #include UpdateGroupJob::UpdateGroupJob(const QString &searchBase, KLDAP::LdapConnection &connection, const Akonadi::Collection &collection, QObject *parent) : KJob(parent), mTransaction(0), mSearchbase(searchBase), mConnection(connection), mLdapSearch(connection), mCollection(collection), mPhase(ListMembers) { Q_ASSERT(connection.handle()); connect(&mLdapSearch, SIGNAL(result(KLDAP::LdapSearch*)), this, SLOT(gotSearchResult(KLDAP::LdapSearch*))); connect(&mLdapSearch, SIGNAL(data(KLDAP::LdapSearch*,KLDAP::LdapObject)), this, SLOT(gotSearchData(KLDAP::LdapSearch*,KLDAP::LdapObject))); // autostart like an Akonadi::Job QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection); } UpdateGroupJob::UpdateGroupJob(const GroupUpdate &updateData, const QString &searchBase, KLDAP::LdapConnection &connection, const Akonadi::Collection &collection, QObject *parent) : KJob(parent), mTransaction(0), mName(updateData.name), mTimestamp(updateData.timestamp), mSearchbase(searchBase), mConnection(connection), mLdapSearch(connection), mCollection(collection), mPhase(ListMembers) { Q_ASSERT(connection.handle()); connect(&mLdapSearch, SIGNAL(result(KLDAP::LdapSearch*)), this, SLOT(gotSearchResult(KLDAP::LdapSearch*))); connect(&mLdapSearch, SIGNAL(data(KLDAP::LdapSearch*,KLDAP::LdapObject)), this, SLOT(gotSearchData(KLDAP::LdapSearch*,KLDAP::LdapObject))); // autostart like an Akonadi::Job QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection); } void UpdateGroupJob::start() { if (!mName.isEmpty() || !mTimestamp.isEmpty()) { if (!mName.isEmpty()) { mCollection.setName(mName); } if (!mTimestamp.isEmpty()) { mCollection.setRemoteRevision(mTimestamp); } Akonadi::CollectionModifyJob *modifyJob = new Akonadi::CollectionModifyJob(mCollection, this); connect(modifyJob, SIGNAL(result(KJob*)), this, SLOT(collectionModifyDone(KJob*))); } else { fetchLocalItems(); } } void UpdateGroupJob::gotSearchResult(KLDAP::LdapSearch *search) { if (search->error()) { kWarning() << search->error() << search->errorString(); switch (search->error()) { case KLDAP_SIZELIMIT_EXCEEDED: kWarning() << "Sizelimit exceeded"; break; case KLDAP_ADMINLIMIT_EXCEEDED: kWarning() << "Administrative limit exceeded"; break; default: kWarning() << "Unknown error"; } setError(KJob::UserDefinedError); emitResult(); return; } switch (mPhase) { case ListMembers: processMembers(); break; case FetchMembers: if (!mTransaction) { // no jobs created here -> done emitResult(); } else { mTransaction->commit(); } break; } } void UpdateGroupJob::gotSearchData(KLDAP::LdapSearch *search, const KLDAP::LdapObject &obj) { Q_UNUSED(search); switch (mPhase) { case ListMembers: { // ignore all objects that are available as local items. // if they have an update, they will be updated by IncrementalUpdateJob // later on using UpdateItemJob on all collections foreach (const QByteArray &val, obj.values("uniqueMember")) { mNewMembers << val; } break; } case FetchMembers: { Akonadi::Item item; item.setRemoteId(LDAPMapper::getStableIdentifier(obj)); item.setPayload(LDAPMapper::getAddressee(obj)); item.setMimeType(KABC::Addressee::mimeType()); item.setParentCollection(mCollection); item.setRemoteRevision(LDAPMapper::getTimestamp(obj)); new Akonadi::ItemCreateJob(item, mCollection, transaction()); break; } } } void UpdateGroupJob::collectionModifyDone(KJob *job) { if (job->error()) { kWarning() << job->errorString(); // just failed the rename, lets still try to update the member list } fetchLocalItems(); } void UpdateGroupJob::retrieveMembersDone(KJob *job) { if (job->error()) { setError(KJob::UserDefinedError); } emitResult(); } void UpdateGroupJob::localFetchDone(KJob *job) { Akonadi::ItemFetchJob *fetchJob = static_cast(job); foreach (const Akonadi::Item &item, fetchJob->items()) { kDebug() << item.remoteId() << item.remoteRevision(); mLocalItems.insert(item.remoteId(), item); } searchForAllMembers(); } void UpdateGroupJob::transactionDone(KJob *job) { if ( job->error() ) { return; // handled by base class } emitResult(); } Akonadi::TransactionSequence *UpdateGroupJob::transaction() { - if ( !mTransaction ) { + if (!mTransaction) { mTransaction= new Akonadi::TransactionSequence( this ); mTransaction->setAutomaticCommittingEnabled( false ); connect(mTransaction, SIGNAL(result(KJob*)), SLOT(transactionDone(KJob*)) ); } return mTransaction; } void UpdateGroupJob::fetchLocalItems() { Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob(mCollection, this); job->fetchScope().setFetchModificationTime(false); job->fetchScope().setCacheOnly(true); job->fetchScope().fetchFullPayload(false); connect(job, SIGNAL(result(KJob*)), this, SLOT(localFetchDone(KJob*))); } void UpdateGroupJob::searchForAllMembers() { Q_ASSERT(mPhase == ListMembers); const int ret = mLdapSearch.search(KLDAP::LdapDN(mSearchbase), KLDAP::LdapUrl::Sub, QString("%1=%2").arg(LDAPMapper::getAttribute(LDAPMapper::UniqueIdentifier)).arg(mCollection.remoteId()), QStringList() << "uniqueMember"); if (!ret) { kWarning() << mLdapSearch.errorString(); kWarning() << "retrieval failed"; setError(KJob::UserDefinedError); emitResult(); } } void UpdateGroupJob::searchForMember(const QString &memberDn) { const int ret = mLdapSearch.search(KLDAP::LdapDN(memberDn), KLDAP::LdapUrl::Base, QString(), LDAPMapper::requestedFullPayloadAttributes()); if (!ret) { kWarning() << mLdapSearch.errorString(); kWarning() << "retrieval failed"; setError(KJob::UserDefinedError); emitResult(); } } void UpdateGroupJob::processMembers() { // all remaining local items are no longer members const Akonadi::Item::List toRemove = mLocalItems.values(); if (!toRemove.isEmpty()) { Akonadi::ItemDeleteJob *job = new Akonadi::ItemDeleteJob(toRemove, transaction()); transaction()->setIgnoreJobFailure(job); } mPhase = FetchMembers; processNewMember(); } void UpdateGroupJob::processNewMember() { if (mNewMembers.isEmpty()) { if (!mTransaction) { // no jobs created here -> done emitResult(); } else { mTransaction->commit(); } return; } const QString memberDn = mNewMembers.takeFirst(); searchForMember(memberDn); } diff --git a/updateitemjob.cpp b/updateitemjob.cpp index e1be71b..05f4a52 100644 --- a/updateitemjob.cpp +++ b/updateitemjob.cpp @@ -1,163 +1,162 @@ /* * Copyright (C) 2014 Klaralvdalens Datakonsult AB * Author: Kevin Krammer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "updateitemjob.h" #include "ldapmapper.h" #include #include #include #include #include UpdateItemJob::UpdateItemJob(const QString &ldapItemId, const QString &searchBase, KLDAP::LdapConnection &connection, const Akonadi::Collection::List &parentCollections, QObject *parent) : KJob(parent), mLdapItemId(ldapItemId), mSearchbase(searchBase), mLdapSearch(connection), mParentCollections(parentCollections) { Q_ASSERT(connection.handle()); connect(&mLdapSearch, SIGNAL(result(KLDAP::LdapSearch*)), this, SLOT(gotSearchResult(KLDAP::LdapSearch*))); connect(&mLdapSearch, SIGNAL(data(KLDAP::LdapSearch*,KLDAP::LdapObject)), this, SLOT(gotSearchData(KLDAP::LdapSearch*,KLDAP::LdapObject))); // autostart like an Akonadi::Job QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection); } void UpdateItemJob::start() { // TODO have IncrementalUpdateJob provide DN for item instead of searchbase const int ret = mLdapSearch.search(KLDAP::LdapDN(mSearchbase), KLDAP::LdapUrl::Sub, QLatin1String("nsuniqueid=") + mLdapItemId, LDAPMapper::requestedFullPayloadAttributes()); if (!ret) { kWarning() << mLdapSearch.errorString(); kWarning() << "retrieval failed"; setError(KJob::UserDefinedError); emitResult(); } } void UpdateItemJob::gotSearchResult(KLDAP::LdapSearch *search) { if (search->error()) { kWarning() << search->error() << search->errorString(); switch (search->error()) { case KLDAP_SIZELIMIT_EXCEEDED: kWarning() << "Sizelimit exceeded"; break; case KLDAP_ADMINLIMIT_EXCEEDED: kWarning() << "Administrative limit exceeded"; break; default: kWarning() << "Unknown error"; } setError(KJob::UserDefinedError); emitResult(); } else { processNextParentCollection(); } } void UpdateItemJob::gotSearchData(KLDAP::LdapSearch *search, const KLDAP::LdapObject &obj) { Q_UNUSED( search ); kWarning(); kDebug() << "Object:"; kDebug() << obj.toString(); kDebug() << "got person: " << obj.dn().toString() << obj.value("nsuniqueid") << obj.value("modifyTimestamp"); mItem.setRemoteId(LDAPMapper::getStableIdentifier(obj)); mItem.setPayload(LDAPMapper::getAddressee(obj)); mItem.setMimeType(KABC::Addressee::mimeType()); mItem.setRemoteRevision(LDAPMapper::getTimestamp(obj)); - mItem.setPayload(LDAPMapper::getAddressee(obj)); } void UpdateItemJob::localFetchDone(KJob *job) { const Akonadi::Collection parentCollection = job->property("parentCollection").value(); const Akonadi::Item::List items = static_cast(job)->items(); if (job->error() || items.isEmpty()) { // if there is no such item we are OK unless this is the top level collection. // in this case an update could mean a new item, so we create it if (parentCollection.parentCollection() == Akonadi::Collection::root()) { Akonadi::Item item = mItem; Akonadi::ItemCreateJob *createJob = new Akonadi::ItemCreateJob(item, parentCollection, this); connect(createJob, SIGNAL(result(KJob*)), this, SLOT(createJobDone(KJob*))); } else { processNextParentCollection(); } } else { Akonadi::Item item = mItem; item.setId(items.at(0).id()); Akonadi::ItemModifyJob *modifyJob = new Akonadi::ItemModifyJob(item, this); connect(modifyJob, SIGNAL(result(KJob*)), this, SLOT(modifyJobDone(KJob*))); } } void UpdateItemJob::createJobDone(KJob *job) { if (job->error()) { kWarning() << job->errorString(); // try to proceed as far as possible } processNextParentCollection(); } void UpdateItemJob::modifyJobDone(KJob *job) { if (job->error()) { kWarning() << job->errorString(); // try to proceed as far as possible } processNextParentCollection(); } void UpdateItemJob::processNextParentCollection() { if (mParentCollections.isEmpty()) { emitResult(); return; } const Akonadi::Collection parentCollection = mParentCollections.takeFirst(); Akonadi::Item item = mItem; item.setParentCollection(parentCollection); Akonadi::ItemFetchJob *fetchJob = new Akonadi::ItemFetchJob(item, this); fetchJob->fetchScope().setCacheOnly(true); fetchJob->setProperty("parentCollection", QVariant::fromValue(parentCollection)); connect(fetchJob, SIGNAL(result(KJob*)), this, SLOT(localFetchDone(KJob*))); }