20#include "specialcollectionshelperjobs_p.h"
22#include "dbusconnectionpool.h"
23#include "specialcollectionattribute_p.h"
24#include "specialcollections.h"
25#include "servermanager.h"
27#include <akonadi/agentinstance.h>
28#include <akonadi/agentinstancecreatejob.h>
29#include <akonadi/agentmanager.h>
30#include <akonadi/collectionfetchjob.h>
31#include <akonadi/collectionfetchscope.h>
32#include <akonadi/collectionmodifyjob.h>
33#include <akonadi/entitydisplayattribute.h>
34#include <akonadi/resourcesynchronizationjob.h>
37#include <KLocalizedString>
38#include <kcoreconfigskeleton.h>
40#include <QtDBus/QDBusConnectionInterface>
41#include <QtDBus/QDBusInterface>
42#include <QtDBus/QDBusServiceWatcher>
43#include <QtCore/QMetaMethod>
44#include <QtCore/QTime>
45#include <QtCore/QTimer>
47#define LOCK_WAIT_TIMEOUT_SECONDS 30
52static void setDefaultResourceId(KCoreConfigSkeleton *settings,
const QString &value)
54 KConfigSkeletonItem *item = settings->findItem(QLatin1String(
"DefaultResourceId"));
56 item->setProperty(value);
59static QString defaultResourceId(KCoreConfigSkeleton *settings)
61 const KConfigSkeletonItem *item = settings->findItem(QLatin1String(
"DefaultResourceId"));
63 return item->property().toString();
66static QString dbusServiceName()
68 QString service = QString::fromLatin1(
"org.kde.pim.SpecialCollections");
75static QVariant::Type argumentType(
const QMetaObject *mo,
const QString &method)
78 for (
int i = 0; i < mo->methodCount(); ++i) {
79 const QString signature = QString::fromLatin1(mo->method(i).signature());
80 if (signature.startsWith(method)) {
86 return QVariant::Invalid;
89 const QList<QByteArray> argTypes = m.parameterTypes();
90 if (argTypes.count() != 1) {
91 return QVariant::Invalid;
94 return QVariant::nameToType(argTypes.first());
102class Akonadi::ResourceScanJob::Private
107 void fetchResult(KJob *job);
113 KCoreConfigSkeleton *mSettings;
120ResourceScanJob::Private::Private(KCoreConfigSkeleton *settings,
ResourceScanJob *qq)
122 , mSettings(settings)
126void ResourceScanJob::Private::fetchResult(KJob *job)
129 kWarning() << job->errorText();
136 Q_ASSERT(!mRootCollection.
isValid());
137 Q_ASSERT(mSpecialCollections.isEmpty());
140 if (mRootCollection.
isValid()) {
141 kWarning() <<
"Resource has more than one root collection. I don't know what to do.";
143 mRootCollection = collection;
148 mSpecialCollections.append(collection);
152 kDebug() <<
"Fetched root collection" << mRootCollection.
id()
153 <<
"and" << mSpecialCollections.count() <<
"local folders"
154 <<
"(total" << fetchJob->
collections().count() <<
"collections).";
156 if (!mRootCollection.
isValid()) {
158 q->setErrorText(i18n(
"Could not fetch root collection of resource %1.", mResourceId));
169 , d(new Private(settings, this))
181 return d->mResourceId;
191 return d->mRootCollection;
196 return d->mSpecialCollections;
201 if (d->mResourceId.isEmpty()) {
202 if(!qobject_cast<DefaultResourceJob *>(
this)) {
203 kError() <<
"No resource ID given.";
205 setErrorText(i18n(
"No resource ID given."));
215 connect(fetchJob, SIGNAL(result(KJob*)),
this, SLOT(fetchResult(KJob*)));
223class Akonadi::DefaultResourceJobPrivate
228 void tryFetchResource();
229 void resourceCreateResult(KJob *job);
230 void resourceSyncResult(KJob *job);
231 void collectionFetchResult(KJob *job);
232 void collectionModifyResult(KJob *job);
235 KCoreConfigSkeleton *mSettings;
236 bool mResourceWasPreexisting;
237 int mPendingModifyJobs;
238 QString mDefaultResourceType;
239 QVariantMap mDefaultResourceOptions;
240 QList<QByteArray> mKnownTypes;
241 QMap<QByteArray, QString> mNameForTypeMap;
242 QMap<QByteArray, QString> mIconForTypeMap;
245DefaultResourceJobPrivate::DefaultResourceJobPrivate(KCoreConfigSkeleton *settings,
DefaultResourceJob *qq)
247 , mSettings(settings)
248 , mResourceWasPreexisting(true )
249 , mPendingModifyJobs(0)
253void DefaultResourceJobPrivate::tryFetchResource()
256 mSettings->readConfig();
258 const QString resourceId = defaultResourceId(mSettings);
260 kDebug() <<
"Read defaultResourceId" << resourceId <<
"from config.";
265 mResourceWasPreexisting =
true;
266 kDebug() <<
"Found resource" << resourceId;
272 q->connect(fetchJob, SIGNAL(result(KJob*)), q, SLOT(collectionFetchResult(KJob*)));
280 if (resource.
name() == mDefaultResourceOptions.value(QLatin1String(
"Name")).toString()) {
282 setDefaultResourceId(mSettings, resource.
identifier());
283 mSettings->writeConfig();
284 mResourceWasPreexisting =
true;
285 kDebug() <<
"Found resource" << resource.
identifier();
287 q->ResourceScanJob::doStart();
294 mResourceWasPreexisting =
false;
295 kDebug() <<
"Creating maildir resource.";
298 QObject::connect(job, SIGNAL(result(KJob*)), q, SLOT(resourceCreateResult(KJob*)));
303void DefaultResourceJobPrivate::resourceCreateResult(KJob *job)
306 kWarning() << job->errorText();
308 q->setError(job->error());
309 q->setErrorText(job->errorText());
321 setDefaultResourceId(mSettings, agent.
identifier());
322 kDebug() <<
"Created maildir resource with id" << defaultResourceId(mSettings);
325 const QString defaultId = defaultResourceId(mSettings);
329 agent.
setName(mDefaultResourceOptions.value(QLatin1String(
"Name")).toString());
331 QDBusInterface conf(QString::fromLatin1(
"org.freedesktop.Akonadi.Resource.") + defaultId,
332 QString::fromLatin1(
"/Settings"), QString());
334 if (!conf.isValid()) {
336 q->setErrorText(i18n(
"Invalid resource identifier '%1'", defaultId));
341 QMapIterator<QString, QVariant> it(mDefaultResourceOptions);
342 while (it.hasNext()) {
345 if (it.key() == QLatin1String(
"Name")) {
349 const QString methodName = QString::fromLatin1(
"set%1").arg(it.key());
350 const QVariant::Type argType = argumentType(conf.metaObject(), methodName);
351 if (argType == QVariant::Invalid) {
353 q->setErrorText(i18n(
"Failed to configure default resource via D-Bus."));
358 QDBusReply<void> reply = conf.call(methodName, it.value());
359 if (!reply.isValid()) {
361 q->setErrorText(i18n(
"Failed to configure default resource via D-Bus."));
367 conf.call(QLatin1String(
"writeConfig"));
375 QObject::connect(syncJob, SIGNAL(result(KJob*)), q, SLOT(resourceSyncResult(KJob*)));
380void DefaultResourceJobPrivate::resourceSyncResult(KJob *job)
383 kWarning() << job->errorText();
389 kDebug() <<
"Fetching maildir collections.";
392 QObject::connect(fetchJob, SIGNAL(result(KJob*)), q, SLOT(collectionFetchResult(KJob*)));
395void DefaultResourceJobPrivate::collectionFetchResult(KJob *job)
398 kWarning() << job->errorText();
407 kDebug() <<
"Fetched" << collections.count() <<
"collections.";
412 foreach (
const Collection &collection, collections) {
414 resourceCollection = collection;
415 toRecover.append(collection);
420 if (!resourceCollection.
isValid()) {
422 q->setErrorText(i18n(
"Failed to fetch the resource collection."));
428 foreach (
const Collection &collection, collections) {
429 if (collection.parentCollection() == resourceCollection) {
430 toRecover.append(collection);
434 QHash<QString, QByteArray> typeForName;
435 foreach (
const QByteArray &type, mKnownTypes) {
436 const QString displayName = mNameForTypeMap.value(type);
437 typeForName[displayName] = type;
442 Q_ASSERT(mPendingModifyJobs == 0);
450 const QString name = collection.displayName();
451 const QByteArray type = typeForName.value(name);
453 if (!type.isEmpty()) {
454 kDebug() <<
"Recovering collection" << name;
458 QObject::connect(modifyJob, SIGNAL(result(KJob*)), q, SLOT(collectionModifyResult(KJob*)));
459 mPendingModifyJobs++;
461 kDebug() <<
"Searching for names: " << typeForName.keys();
462 kDebug() <<
"Unknown collection name" << name <<
"-- not recovering.";
466 if (mPendingModifyJobs == 0) {
469 q->ResourceScanJob::doStart();
473void DefaultResourceJobPrivate::collectionModifyResult(KJob *job)
476 kWarning() << job->errorText();
481 Q_ASSERT(mPendingModifyJobs > 0);
482 mPendingModifyJobs--;
483 kDebug() <<
"pendingModifyJobs now" << mPendingModifyJobs;
484 if (mPendingModifyJobs == 0) {
486 kDebug() <<
"Writing defaultResourceId" << defaultResourceId(mSettings) <<
"to config.";
487 mSettings->writeConfig();
491 q->ResourceScanJob::doStart();
497 , d(new DefaultResourceJobPrivate(settings, this))
508 d->mDefaultResourceType = type;
513 d->mDefaultResourceOptions = options;
518 d->mKnownTypes = types;
523 d->mNameForTypeMap = map;
528 d->mIconForTypeMap = map;
533 d->tryFetchResource();
536void DefaultResourceJob::slotResult(KJob *job)
539 kWarning() << job->errorText();
541 if (!d->mResourceWasPreexisting) {
545 kDebug() <<
"Removing resource" << resource.
identifier();
550 Job::slotResult(job);
555class Akonadi::GetLockJob::Private
561 void serviceOwnerChanged(
const QString &name,
const QString &oldOwner,
562 const QString &newOwner);
566 QTimer *mSafetyTimer;
575void GetLockJob::Private::doStart()
580 QDBusConnection bus = DBusConnectionPool::threadConnection();
581 const bool alreadyLocked = bus.interface()->isServiceRegistered(dbusServiceName());
582 const bool gotIt = bus.registerService(dbusServiceName());
584 if (gotIt && !alreadyLocked) {
588 QDBusServiceWatcher *watcher =
new QDBusServiceWatcher(dbusServiceName(), DBusConnectionPool::threadConnection(),
589 QDBusServiceWatcher::WatchForOwnerChange, q);
591 connect(watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)),
592 q, SLOT(serviceOwnerChanged(QString,QString,QString)));
594 mSafetyTimer =
new QTimer(q);
595 mSafetyTimer->setSingleShot(
true);
596 mSafetyTimer->setInterval(LOCK_WAIT_TIMEOUT_SECONDS * 1000);
597 mSafetyTimer->start();
598 connect(mSafetyTimer, SIGNAL(timeout()), q, SLOT(timeout()));
602void GetLockJob::Private::serviceOwnerChanged(
const QString &name,
const QString &oldOwner,
const QString &newOwner)
604 if (newOwner.isEmpty()) {
605 const bool gotIt = DBusConnectionPool::threadConnection().registerService(dbusServiceName());
607 mSafetyTimer->stop();
613void GetLockJob::Private::timeout()
615 kWarning() <<
"Timeout trying to get lock. Check who has acquired the name" << dbusServiceName() <<
"on DBus, using qdbus or qdbusviewer.";
617 q->setErrorText(i18n(
"Timeout trying to get lock."));
623 , d(new Private(this))
632void GetLockJob::start()
634 QTimer::singleShot(0,
this, SLOT(doStart()));
638 const QMap<QByteArray, QString> &nameForType,
639 const QMap<QByteArray, QString> &iconForType)
645 collection.addAttribute(attr);
651 collection.addAttribute(attr);
657 return DBusConnectionPool::threadConnection().unregisterService(dbusServiceName());
660#include "moc_specialcollectionshelperjobs_p.cpp"
Job for creating new agent instances.
void start()
Starts the instance creation.
AgentInstance instance() const
Returns the AgentInstance object of the newly created agent instance.
A representation of an agent instance.
QString identifier() const
Returns the unique identifier of the agent instance.
bool isValid() const
Returns whether the agent instance object is valid.
AgentType type() const
Returns the agent type of this instance.
QList< AgentInstance > List
Describes a list of agent instances.
void setName(const QString &name)
Sets the user visible name of the agent instance.
void reconfigure() const
Tell the agent that its configuration has been changed remotely via D-Bus.
QString name() const
Returns the user visible name of the agent instance.
AgentType type(const QString &identifier) const
Returns the agent type with the given identifier or an invalid agent type if the identifier does not ...
static AgentManager * self()
Returns the global instance of the agent manager.
void removeInstance(const AgentInstance &instance)
Removes the given agent instance.
AgentInstance instance(const QString &identifier) const
Returns the agent instance with the given identifier or an invalid agent instance if the identifier d...
AgentInstance::List instances() const
Returns the list of all available agent instances.
A representation of an agent type.
QString identifier() const
Returns the unique identifier of the agent type.
Job that fetches collections from the Akonadi storage.
CollectionFetchScope & fetchScope()
Returns the collection fetch scope.
@ Recursive
List all sub-collections.
Collection::List collections() const
Returns the list of fetched collection.
void setIncludeStatistics(bool include)
Sets whether collection statistics should be included in the retrieved results.
void setResource(const QString &resource)
Sets a resource filter, that is only collections owned by the specified resource are retrieved.
Job that modifies a collection in the Akonadi storage.
Represents a collection of PIM items.
static Collection root()
Returns the root collection.
QList< Collection > List
Describes a list of collections.
~DefaultResourceJob()
Destroys the DefaultResourceJob.
DefaultResourceJob(KCoreConfigSkeleton *settings, QObject *parent=0)
Creates a new DefaultResourceJob.
void setNameForTypeMap(const QMap< QByteArray, QString > &map)
Sets the map of special collection types to display names.
virtual void doStart()
This method must be reimplemented in the concrete jobs.
void setDefaultResourceType(const QString &type)
Sets the type of the resource that shall be created if the requested special collection does not exis...
void setTypes(const QList< QByteArray > &types)
Sets the list of well known special collection types.
void setIconForTypeMap(const QMap< QByteArray, QString > &map)
Sets the map of special collection types to icon names.
void setDefaultResourceOptions(const QVariantMap &options)
Sets the configuration options that shall be applied to the new resource that is created if the reque...
Attribute that stores the properties that are used to display an entity.
void setIconName(const QString &name)
Sets the icon name for the default icon.
void setDisplayName(const QString &name)
Sets the name that should be used for display.
bool isValid() const
Returns whether the entity is valid.
Id id() const
Returns the unique identifier of the entity.
~GetLockJob()
Destroys the GetLockJob.
GetLockJob(QObject *parent=0)
Creates a new GetLockJob.
Base class for all actions in the Akonadi storage.
void setResourceId(const QString &resourceId)
Sets the resource ID of the resource to scan.
~ResourceScanJob()
Destroys this ResourceScanJob.
QString resourceId() const
Returns the resource ID of the resource being scanned.
virtual void doStart()
This method must be reimplemented in the concrete jobs.
ResourceScanJob(const QString &resourceId, KCoreConfigSkeleton *settings, QObject *parent=0)
Creates a new ResourceScanJob.
Akonadi::Collection::List specialCollections() const
Returns all the collections of this resource which have a SpecialCollectionAttribute.
Akonadi::Collection rootResourceCollection() const
Returns the root collection of the resource being scanned.
Job that synchronizes a resource.
static bool hasInstanceIdentifier()
Returns true if we are connected to a non-default Akonadi server instance.
static QString instanceIdentifier()
Returns the identifier of the Akonadi instance we are connected to.
An Attribute that stores the special collection type of a collection.
void setCollectionType(const QByteArray &type)
Sets the special collections type of the collection.
FreeBusyManager::Singleton.
bool AKONADI_TESTS_EXPORT releaseLock()
Releases the SpecialCollectionsRequestJob lock that was obtained through GetLockJob.
void setCollectionAttributes(Akonadi::Collection &col, const QByteArray &type, const QMap< QByteArray, QString > &nameForType, const QMap< QByteArray, QString > &iconForType)
Sets on col the required attributes of SpecialCollection type type These are a SpecialCollectionAttri...