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 52 static void setDefaultResourceId(KCoreConfigSkeleton *settings,
const QString &value)
54 KConfigSkeletonItem *item = settings->findItem(QLatin1String(
"DefaultResourceId"));
56 item->setProperty(value);
59 static QString defaultResourceId(KCoreConfigSkeleton *settings)
61 const KConfigSkeletonItem *item = settings->findItem(QLatin1String(
"DefaultResourceId"));
63 return item->property().toString();
66 static QString dbusServiceName()
68 QString service = QString::fromLatin1(
"org.kde.pim.SpecialCollections");
75 static 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());
102 class Akonadi::ResourceScanJob::Private
107 void fetchResult(KJob *job);
113 KCoreConfigSkeleton *mSettings;
120 ResourceScanJob::Private::Private(KCoreConfigSkeleton *settings,
ResourceScanJob *qq)
122 , mSettings(settings)
126 void 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()) {
157 q->setError(Unknown);
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*)));
223 class 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;
245 DefaultResourceJobPrivate::DefaultResourceJobPrivate(KCoreConfigSkeleton *settings,
DefaultResourceJob *qq)
247 , mSettings(settings)
248 , mResourceWasPreexisting(true )
249 , mPendingModifyJobs(0)
253 void 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;
267 q->setResourceId(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*)));
303 void 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*)));
380 void DefaultResourceJobPrivate::resourceSyncResult(KJob *job)
383 kWarning() << job->errorText();
389 kDebug() <<
"Fetching maildir collections.";
392 QObject::connect(fetchJob, SIGNAL(result(KJob*)), q, SLOT(collectionFetchResult(KJob*)));
395 void 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) {
468 q->setResourceId(defaultResourceId(mSettings));
469 q->ResourceScanJob::doStart();
473 void 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();
490 q->setResourceId(defaultResourceId(mSettings));
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();
536 void DefaultResourceJob::slotResult(KJob *job)
539 kWarning() << job->errorText();
541 if (!d->mResourceWasPreexisting) {
545 kDebug() <<
"Removing resource" << resource.
identifier();
550 Job::slotResult(job);
555 class Akonadi::GetLockJob::Private
561 void serviceOwnerChanged(
const QString &name,
const QString &oldOwner,
562 const QString &newOwner);
566 QTimer *mSafetyTimer;
575 void 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()));
602 void 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();
613 void 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))
632 void 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 that modifies a collection in the Akonadi storage.
AgentType type() const
Returns the agent type of this instance.
QList< AgentInstance > List
Describes a list of agent instances.
void setNameForTypeMap(const QMap< QByteArray, QString > &map)
Sets the map of special collection types to display names.
bool AKONADI_TESTS_EXPORT releaseLock()
Releases the SpecialCollectionsRequestJob lock that was obtained through GetLockJob.
static QString instanceIdentifier()
Returns the identifier of the Akonadi instance we are connected to.
GetLockJob(QObject *parent=0)
Creates a new GetLockJob.
AgentInstance instance() const
Returns the AgentInstance object of the newly created agent instance.
CollectionFetchScope & fetchScope()
Returns the collection fetch scope.
void setResource(const QString &resource)
Sets a resource filter, that is only collections owned by the specified resource are retrieved...
Represents a collection of PIM items.
Job that fetches collections from the Akonadi storage.
void setDefaultResourceOptions(const QVariantMap &options)
Sets the configuration options that shall be applied to the new resource that is created if the reque...
void setIncludeStatistics(bool include)
Sets whether collection statistics should be included in the retrieved results.
An Attribute that stores the special collection type of a collection.
virtual void doStart()
This method must be reimplemented in the concrete jobs.
Base class for all actions in the Akonadi storage.
void removeInstance(const AgentInstance &instance)
Removes the given agent instance.
QString identifier() const
Returns the unique identifier of the agent instance.
Collection::List collections() const
Returns the list of fetched collection.
~ResourceScanJob()
Destroys this ResourceScanJob.
void reconfigure() const
Tell the agent that its configuration has been changed remotely via D-Bus.
Job that synchronizes a resource.
ResourceScanJob(const QString &resourceId, KCoreConfigSkeleton *settings, QObject *parent=0)
Creates a new ResourceScanJob.
A representation of an agent type.
AgentInstance instance(const QString &identifier) const
Returns the agent instance with the given identifier or an invalid agent instance if the identifier d...
void setIconName(const QString &name)
Sets the icon name for the default icon.
static Collection root()
Returns the root collection.
QString resourceId() const
Returns the resource ID of the resource being scanned.
void setDisplayName(const QString &name)
Sets the name that should be used for display.
AgentType type(const QString &identifier) const
Returns the agent type with the given identifier or an invalid agent type if the identifier does not ...
void setName(const QString &name)
Sets the user visible name of the agent instance.
Akonadi::Collection::List specialCollections() const
Returns all the collections of this resource which have a SpecialCollectionAttribute.
Job for creating new agent instances.
Akonadi::Collection rootResourceCollection() const
Returns the root collection of the resource being scanned.
void setCollectionType(const QByteArray &type)
Sets the special collections type of the collection.
void setIconForTypeMap(const QMap< QByteArray, QString > &map)
Sets the map of special collection types to icon names.
FreeBusyManager::Singleton.
bool isValid() const
Returns whether the agent instance object is valid.
void setResourceId(const QString &resourceId)
Sets the resource ID of the resource to scan.
QString name() const
Returns the user visible name of the agent instance.
static AgentManager * self()
Returns the global instance of the agent manager.
A representation of an agent instance.
void setDefaultResourceType(const QString &type)
Sets the type of the resource that shall be created if the requested special collection does not exis...
AgentInstance::List instances() const
Returns the list of all available agent instances.
void setTypes(const QList< QByteArray > &types)
Sets the list of well known special collection types.
QString identifier() const
Returns the unique identifier of the agent type.
~GetLockJob()
Destroys the GetLockJob.
virtual void doStart()
This method must be reimplemented in the concrete jobs.
List all sub-collections.
QList< Collection > List
Describes a list of collections.
Attribute that stores the properties that are used to display an entity.
static bool hasInstanceIdentifier()
Returns true if we are connected to a non-default Akonadi server instance.
~DefaultResourceJob()
Destroys the DefaultResourceJob.
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...
void start()
Starts the instance creation.
DefaultResourceJob(KCoreConfigSkeleton *settings, QObject *parent=0)
Creates a new DefaultResourceJob.
bool isValid() const
Returns whether the entity is valid.