7#include "specialcollectionshelperjobs_p.h"
9#include "servermanager.h"
10#include "specialcollectionattribute.h"
11#include <QDBusConnection>
13#include "agentinstance.h"
14#include "agentinstancecreatejob.h"
15#include "agentmanager.h"
16#include "collectionfetchjob.h"
17#include "collectionfetchscope.h"
18#include "collectionmodifyjob.h"
19#include "entitydisplayattribute.h"
20#include "resourcesynchronizationjob.h"
22#include "akonadicore_debug.h"
24#include <KCoreConfigSkeleton>
25#include <KLocalizedString>
27#include <QDBusConnectionInterface>
28#include <QDBusInterface>
29#include <QDBusServiceWatcher>
34#define LOCK_WAIT_TIMEOUT_SECONDS 30
55 const QString service = QStringLiteral(
"org.kde.pim.SpecialCollections");
65 for (
int i = 0; i < metaObject->
methodCount(); ++i) {
68 metaMethod = metaObject->
method(i);
77 if (argTypes.
count() != 1) {
89class Akonadi::ResourceScanJobPrivate
92 ResourceScanJobPrivate(KCoreConfigSkeleton *settings, ResourceScanJob *qq);
94 void fetchResult(KJob *job);
96 ResourceScanJob *
const q;
100 KCoreConfigSkeleton *mSettings =
nullptr;
103 Collection mRootCollection;
107ResourceScanJobPrivate::ResourceScanJobPrivate(
KCoreConfigSkeleton *settings, ResourceScanJob *qq)
109 , mSettings(settings)
113void ResourceScanJobPrivate::fetchResult(
KJob *job)
116 qCWarning(AKONADICORE_LOG) << job->
errorText();
120 auto fetchJob = qobject_cast<CollectionFetchJob *>(job);
123 Q_ASSERT(!mRootCollection.isValid());
124 Q_ASSERT(mSpecialCollections.isEmpty());
126 for (
const Collection &collection : lstCols) {
128 if (mRootCollection.isValid()) {
129 qCWarning(AKONADICORE_LOG) <<
"Resource has more than one root collection. I don't know what to do.";
131 mRootCollection = collection;
135 if (collection.hasAttribute<SpecialCollectionAttribute>()) {
136 mSpecialCollections.append(collection);
140 qCDebug(AKONADICORE_LOG) <<
"Fetched root collection" << mRootCollection.id() <<
"and" << mSpecialCollections.
count() <<
"local folders"
141 <<
"(total" << fetchJob->collections().count() <<
"collections).";
143 if (!mRootCollection.isValid()) {
144 q->setError(ResourceScanJob::Unknown);
145 q->setErrorText(
i18n(
"Could not fetch root collection of resource %1.", mResourceId));
154ResourceScanJob::ResourceScanJob(
const QString &resourceId, KCoreConfigSkeleton *settings, QObject *parent)
156 , d(new ResourceScanJobPrivate(settings, this))
158 setResourceId(resourceId);
161ResourceScanJob::~ResourceScanJob() =
default;
163QString ResourceScanJob::resourceId()
const
165 return d->mResourceId;
168void ResourceScanJob::setResourceId(
const QString &resourceId)
170 d->mResourceId = resourceId;
175 return d->mRootCollection;
180 return d->mSpecialCollections;
183void ResourceScanJob::doStart()
185 if (d->mResourceId.isEmpty()) {
186 if (!qobject_cast<DefaultResourceJob *>(
this)) {
187 qCCritical(AKONADICORE_LOG) <<
"No resource ID given.";
189 setErrorText(
i18n(
"No resource ID given."));
196 fetchJob->fetchScope().setResource(d->mResourceId);
197 fetchJob->fetchScope().setIncludeStatistics(
true);
209class Akonadi::DefaultResourceJobPrivate
212 DefaultResourceJobPrivate(KCoreConfigSkeleton *settings, DefaultResourceJob *qq);
214 void tryFetchResource();
215 void resourceCreateResult(KJob *job);
216 void resourceSyncResult(KJob *job);
217 void collectionFetchResult(KJob *job);
218 void collectionModifyResult(KJob *job);
220 DefaultResourceJob *
const q;
221 KCoreConfigSkeleton *mSettings =
nullptr;
222 QVariantMap mDefaultResourceOptions;
223 QList<QByteArray> mKnownTypes;
224 QMap<QByteArray, QString> mNameForTypeMap;
225 QMap<QByteArray, QString> mIconForTypeMap;
226 QString mDefaultResourceType;
227 int mPendingModifyJobs = 0;
228 bool mResourceWasPreexisting =
true;
231DefaultResourceJobPrivate::DefaultResourceJobPrivate(
KCoreConfigSkeleton *settings, DefaultResourceJob *qq)
233 , mSettings(settings)
234 , mPendingModifyJobs(0)
235 , mResourceWasPreexisting(true )
239void DefaultResourceJobPrivate::tryFetchResource()
244 const QString resourceId = defaultResourceId(mSettings);
246 qCDebug(AKONADICORE_LOG) <<
"Read defaultResourceId" << resourceId <<
"from config.";
249 if (resource.isValid()) {
251 mResourceWasPreexisting =
true;
252 qCDebug(AKONADICORE_LOG) <<
"Found resource" << resourceId;
253 q->setResourceId(resourceId);
256 fetchJob->fetchScope().setResource(resourceId);
257 fetchJob->fetchScope().setIncludeStatistics(
true);
259 collectionFetchResult(job);
266 for (
const AgentInstance &resourceInstance : resources) {
267 if (resourceInstance.type().identifier() == mDefaultResourceType) {
268 if (resourceInstance.name() == mDefaultResourceOptions.value(QStringLiteral(
"Name")).
toString()) {
270 setDefaultResourceId(mSettings, resourceInstance.identifier());
272 mResourceWasPreexisting =
true;
273 qCDebug(AKONADICORE_LOG) <<
"Found resource" << resourceInstance.identifier();
274 q->setResourceId(resourceInstance.identifier());
275 q->ResourceScanJob::doStart();
282 mResourceWasPreexisting =
false;
283 qCDebug(AKONADICORE_LOG) <<
"Creating maildir resource.";
285 auto job =
new AgentInstanceCreateJob(type, q);
287 resourceCreateResult(job);
293void DefaultResourceJobPrivate::resourceCreateResult(KJob *job)
296 qCWarning(AKONADICORE_LOG) << job->
errorText();
298 q->setError(job->
error());
308 auto createJob = qobject_cast<AgentInstanceCreateJob *>(job);
310 agent = createJob->instance();
311 setDefaultResourceId(mSettings, agent.
identifier());
312 qCDebug(AKONADICORE_LOG) <<
"Created maildir resource with id" << defaultResourceId(mSettings);
315 const QString defaultId = defaultResourceId(mSettings);
319 agent.setName(mDefaultResourceOptions.value(QStringLiteral(
"Name")).
toString());
322 QDBusInterface conf(service, QStringLiteral(
"/Settings"), QString());
324 if (!conf.isValid()) {
326 q->setErrorText(
i18n(
"Invalid resource identifier '%1'", defaultId));
331 QMap<QString, QVariant>::const_iterator it = mDefaultResourceOptions.cbegin();
332 const QMap<QString, QVariant>::const_iterator itEnd = mDefaultResourceOptions.cend();
333 for (; it != itEnd; ++it) {
334 if (it.key() == QLatin1StringView(
"Name")) {
338 const QString methodName = QStringLiteral(
"set%1").arg(it.key());
339 const QMetaType::Type argType = argumentType(conf.metaObject(), methodName);
342 q->setErrorText(
i18n(
"Failed to configure default resource via D-Bus."));
347 QDBusReply<void> reply = conf.call(methodName, it.value());
350 q->setErrorText(
i18n(
"Failed to configure default resource via D-Bus."));
356 conf.call(QStringLiteral(
"save"));
363 auto syncJob =
new ResourceSynchronizationJob(agent, q);
365 resourceSyncResult(job);
371void DefaultResourceJobPrivate::resourceSyncResult(KJob *job)
374 qCWarning(AKONADICORE_LOG) << job->
errorText();
380 qCDebug(AKONADICORE_LOG) <<
"Fetching maildir collections.";
382 fetchJob->fetchScope().setResource(defaultResourceId(mSettings));
384 collectionFetchResult(job);
388void DefaultResourceJobPrivate::collectionFetchResult(KJob *job)
391 qCWarning(AKONADICORE_LOG) << job->
errorText();
396 auto fetchJob = qobject_cast<CollectionFetchJob *>(job);
400 qCDebug(AKONADICORE_LOG) <<
"Fetched" << collections.
count() <<
"collections.";
404 Collection resourceCollection;
405 for (
const Collection &collection : collections) {
407 resourceCollection = collection;
408 toRecover.
append(collection);
413 if (!resourceCollection.isValid()) {
415 q->setErrorText(
i18n(
"Failed to fetch the resource collection."));
421 for (
const Collection &collection : std::as_const(collections)) {
422 if (collection.parentCollection() == resourceCollection) {
423 toRecover.
append(collection);
427 QHash<QString, QByteArray> typeForName;
428 for (
const QByteArray &type : std::as_const(mKnownTypes)) {
429 const QString
displayName = mNameForTypeMap.value(type);
435 Q_ASSERT(mPendingModifyJobs == 0);
436 for (Collection collection : std::as_const(toRecover)) {
437 if (collection.hasAttribute<SpecialCollectionAttribute>()) {
442 const QString
name = collection.displayName();
443 const QByteArray
type = typeForName.
value(name);
445 if (!
type.isEmpty()) {
446 qCDebug(AKONADICORE_LOG) <<
"Recovering collection" <<
name;
447 setCollectionAttributes(collection, type, mNameForTypeMap, mIconForTypeMap);
449 auto modifyJob =
new CollectionModifyJob(collection, q);
451 collectionModifyResult(job);
453 mPendingModifyJobs++;
455 qCDebug(AKONADICORE_LOG) <<
"Searching for names: " << typeForName.
keys();
456 qCDebug(AKONADICORE_LOG) <<
"Unknown collection name" <<
name <<
"-- not recovering.";
460 if (mPendingModifyJobs == 0) {
462 q->setResourceId(defaultResourceId(mSettings));
463 q->ResourceScanJob::doStart();
467void DefaultResourceJobPrivate::collectionModifyResult(KJob *job)
470 qCWarning(AKONADICORE_LOG) << job->
errorText();
475 Q_ASSERT(mPendingModifyJobs > 0);
476 mPendingModifyJobs--;
477 qCDebug(AKONADICORE_LOG) <<
"pendingModifyJobs now" << mPendingModifyJobs;
478 if (mPendingModifyJobs == 0) {
480 qCDebug(AKONADICORE_LOG) <<
"Writing defaultResourceId" << defaultResourceId(mSettings) <<
"to config.";
484 q->setResourceId(defaultResourceId(mSettings));
485 q->ResourceScanJob::doStart();
489DefaultResourceJob::DefaultResourceJob(KCoreConfigSkeleton *settings, QObject *parent)
490 : ResourceScanJob(QString(), settings, parent)
491 , d(new DefaultResourceJobPrivate(settings, this))
495DefaultResourceJob::~DefaultResourceJob() =
default;
497void DefaultResourceJob::setDefaultResourceType(
const QString &type)
499 d->mDefaultResourceType =
type;
502void DefaultResourceJob::setDefaultResourceOptions(
const QVariantMap &options)
504 d->mDefaultResourceOptions = options;
509 d->mKnownTypes = types;
514 d->mNameForTypeMap =
map;
519 d->mIconForTypeMap =
map;
522void DefaultResourceJob::doStart()
524 d->tryFetchResource();
527void DefaultResourceJob::slotResult(
KJob *job)
530 qCWarning(AKONADICORE_LOG) << job->
errorText();
532 if (!d->mResourceWasPreexisting) {
536 qCDebug(AKONADICORE_LOG) <<
"Removing resource" << resource.
identifier();
541 Job::slotResult(job);
546class Akonadi::GetLockJobPrivate
549 explicit GetLockJobPrivate(GetLockJob *qq);
555 QTimer *mSafetyTimer =
nullptr;
558GetLockJobPrivate::GetLockJobPrivate(GetLockJob *qq)
560 , mSafetyTimer(nullptr)
564void GetLockJobPrivate::doStart()
573 if (gotIt && !alreadyLocked) {
580 mSafetyTimer->stop();
585 mSafetyTimer =
new QTimer(q);
586 mSafetyTimer->setSingleShot(
true);
587 mSafetyTimer->setInterval(LOCK_WAIT_TIMEOUT_SECONDS * 1000);
588 mSafetyTimer->start();
595void GetLockJobPrivate::timeout()
597 qCWarning(AKONADICORE_LOG) <<
"Timeout trying to get lock. Check who has acquired the name" << dbusServiceName() <<
"on DBus, using qdbus or qdbusviewer.";
599 q->setErrorText(
i18n(
"Timeout trying to get lock."));
603GetLockJob::GetLockJob(QObject *parent)
605 , d(new GetLockJobPrivate(this))
609GetLockJob::~GetLockJob() =
default;
611void GetLockJob::start()
626 attr->setDisplayName(nameForType.
value(type));
637bool Akonadi::releaseLock()
642#include "moc_specialcollectionshelperjobs_p.cpp"
Represents one agent instance and takes care of communication with it.
QString identifier() const
Set/get the unique identifier of this AgentInstance.
QList< AgentInstance > List
Describes a list of agent instances.
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.
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.
Job that fetches collections from the Akonadi storage.
@ Recursive
List all sub-collections.
@ Display
Only retrieve collections for display, taking the local preference and enabled into account.
Represents a collection of PIM items.
void addAttribute(Attribute *attribute)
Adds an attribute to the collection.
static Collection root()
Returns the root collection.
QList< Collection > List
Describes a list of collections.
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.
Base class for all actions in the Akonadi storage.
static QString agentServiceName(ServiceAgentType agentType, const QString &identifier)
Returns the namespaced D-Bus service name for an agent of type agentType with agent identifier identi...
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.
virtual void setProperty(const QVariant &p)=0
virtual QVariant property() const=0
KConfigSkeletonItem * findItem(const QString &name) const
virtual Q_SCRIPTABLE void start()=0
QString errorText() const
QString i18n(const char *text, const TYPE &arg...)
AKONADI_CALENDAR_EXPORT QString displayName(Akonadi::ETMCalendar *calendar, const Akonadi::Collection &collection)
Helper integration between Akonadi and Qt.
char * toString(const EngineQuery &query)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
QString name(StandardAction id)
bool isEmpty() const const
QDBusConnectionInterface * interface() const const
bool registerService(const QString &serviceName)
QDBusConnection sessionBus()
bool unregisterService(const QString &serviceName)
QDBusReply< bool > isServiceRegistered(const QString &serviceName) const const
bool isValid() const const
void serviceUnregistered(const QString &serviceName)
QList< Key > keys() const const
T value(const Key &key) const const
void append(QList< T > &&value)
qsizetype count() const const
T value(const Key &key, const T &defaultValue) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QString fromLatin1(QByteArrayView str)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QString toString() const const