Akonadi

akonadicontrol/agentmanager.cpp
1/***************************************************************************
2 * SPDX-FileCopyrightText: 2006 Tobias Koenig <tokoe@kde.org> *
3 * SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org> *
4 * *
5 * SPDX-License-Identifier: LGPL-2.0-or-later *
6 ***************************************************************************/
7
8#include "agentmanager.h"
9
10#include "agentbrokeninstance.h"
11#include "agentmanageradaptor.h"
12#include "agentmanagerinternaladaptor.h"
13#include "agentprocessinstance.h"
14#include "agentserverinterface.h"
15#include "agentthreadinstance.h"
16#include "akonadicontrol_debug.h"
17#include "preprocessor_manager.h"
18#include "processcontrol.h"
19#include "resource_manager.h"
20#include "serverinterface.h"
21
22#include "private/dbus_p.h"
23#include "private/instance_p.h"
24#include "private/protocol_p.h"
25#include "private/standarddirs_p.h"
26
27#include "shared/akapplication.h"
28
29#include <QCoreApplication>
30#include <QDBusConnection>
31#include <QDir>
32#include <QScopedPointer>
33#include <QSettings>
34
36using namespace std::chrono_literals;
37
38static const bool enableAgentServerDefault = false;
39
40class StorageProcessControl : public Akonadi::ProcessControl
41{
43public:
44 explicit StorageProcessControl(const QStringList &args)
45 {
49 });
50 start(QStringLiteral("akonadiserver"), args, RestartOnCrash);
51 }
52
53 ~StorageProcessControl() override
54 {
55 setCrashPolicy(ProcessControl::StopOnCrash);
56 org::freedesktop::Akonadi::Server serverIface(Akonadi::DBus::serviceName(Akonadi::DBus::Server),
57 QStringLiteral("/Server"),
59 serverIface.quit();
60 }
61};
62
63class AgentServerProcessControl : public Akonadi::ProcessControl
64{
66public:
67 explicit AgentServerProcessControl(const QStringList &args)
68 {
70 qCCritical(AKONADICONTROL_LOG) << "Failed to start AgentServer!";
71 });
72 start(QStringLiteral("akonadi_agent_server"), args, RestartOnCrash);
73 }
74
75 ~AgentServerProcessControl() override
76 {
77 setCrashPolicy(ProcessControl::StopOnCrash);
78 org::freedesktop::Akonadi::AgentServer agentServerIface(Akonadi::DBus::serviceName(Akonadi::DBus::AgentServer),
79 QStringLiteral("/AgentServer"),
81 this);
82 agentServerIface.quit();
83 }
84};
85
86AgentManager::AgentManager(bool verbose, QObject *parent)
87 : QObject(parent)
88 , mAgentServer(nullptr)
89 , mVerbose(verbose)
90{
91 new AgentManagerAdaptor(this);
93 QDBusConnection::sessionBus().registerObject(QStringLiteral("/AgentManager"), this);
94
95 connect(QDBusConnection::sessionBus().interface(), &QDBusConnectionInterface::serviceOwnerChanged, this, &AgentManager::serviceOwnerChanged);
96
97 if (QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Server))) {
98 qFatal("akonadiserver already running!");
99 }
100
101 const QSettings settings(Akonadi::StandardDirs::agentsConfigFile(Akonadi::StandardDirs::ReadOnly), QSettings::IniFormat);
102 mAgentServerEnabled = settings.value(QStringLiteral("AgentServer/Enabled"), enableAgentServerDefault).toBool();
103
105 if (Akonadi::Instance::hasIdentifier()) {
106 serviceArgs << QStringLiteral("--instance") << Akonadi::Instance::identifier();
107 }
108 if (verbose) {
109 serviceArgs << QStringLiteral("--verbose");
110 }
111
112 mStorageController = std::unique_ptr<Akonadi::ProcessControl>(new StorageProcessControl(serviceArgs));
113
114 if (mAgentServerEnabled) {
115 mAgentServer = std::unique_ptr<Akonadi::ProcessControl>(new AgentServerProcessControl(serviceArgs));
116 }
117}
118
119void AgentManager::continueStartup()
120{
121 // prevent multiple calls in case the server has to be restarted
122 static bool first = true;
123 if (!first) {
124 return;
125 }
126
127 first = false;
128
129 readPluginInfos();
130 for (const AgentType &info : std::as_const(mAgents)) {
131 Q_EMIT agentTypeAdded(info.identifier);
132 }
133
134 load();
135 for (const AgentType &info : std::as_const(mAgents)) {
136 ensureAutoStart(info);
137 }
138
139 // register the real service name once everything is up an running
140 if (!QDBusConnection::sessionBus().registerService(Akonadi::DBus::serviceName(Akonadi::DBus::Control))) {
141 // besides a race with an older Akonadi server I have no idea how we could possibly get here...
142 qFatal("Unable to register service as %s despite having the lock. Error was: %s",
143 qPrintable(Akonadi::DBus::serviceName(Akonadi::DBus::Control)),
144 qPrintable(QDBusConnection::sessionBus().lastError().message()));
145 }
146 qCInfo(AKONADICONTROL_LOG) << "Akonadi server is now operational.";
147}
148
153
155{
156 for (const AgentInstance::Ptr &instance : std::as_const(mAgentInstances)) {
157 instance->quit();
158 }
159 mAgentInstances.clear();
160
161 mStorageController.reset();
162 mStorageController.reset();
163}
164
166{
167 return mAgents.keys();
168}
169
171{
172 if (!checkAgentExists(identifier)) {
173 return QString();
174 }
175
176 return mAgents.value(identifier).name;
177}
178
180{
181 if (!checkAgentExists(identifier)) {
182 return QString();
183 }
184
185 return mAgents.value(identifier).comment;
186}
187
189{
190 if (!checkAgentExists(identifier)) {
191 return QString();
192 }
193
194 const AgentType info = mAgents.value(identifier);
195 if (!info.icon.isEmpty()) {
196 return info.icon;
197 }
198
199 return QStringLiteral("application-x-executable");
200}
201
203{
204 if (!checkAgentExists(identifier)) {
205 return QStringList();
206 }
207
208 return mAgents.value(identifier).mimeTypes;
209}
210
212{
213 if (!checkAgentExists(identifier)) {
214 return QStringList();
215 }
216 return mAgents.value(identifier).capabilities;
217}
218
220{
221 if (!checkAgentExists(identifier)) {
222 return QVariantMap();
223 }
224
225 return mAgents.value(identifier).custom;
226}
227
229{
230 switch (info.launchMethod) {
231 case AgentType::Server:
233 case AgentType::Launcher: // Fall through
234 case AgentType::Process:
236 default:
237 Q_ASSERT_X(false, "AgentManger::createAgentInstance", "Unhandled AgentType::LaunchMethod case");
238 }
239
240 return AgentInstance::Ptr();
241}
242
244{
245 if (!checkAgentExists(identifier)) {
246 return QString();
247 }
248
249 const AgentType agentInfo = mAgents[identifier];
250 mAgents[identifier].instanceCounter++;
251
252 const auto instance = createAgentInstance(agentInfo);
253 if (agentInfo.capabilities.contains(AgentType::CapabilityUnique)) {
254 instance->setIdentifier(identifier);
255 } else {
256 instance->setIdentifier(QStringLiteral("%1_%2").arg(identifier, QString::number(agentInfo.instanceCounter)));
257 }
258
259 const QString instanceIdentifier = instance->identifier();
260 if (mAgentInstances.contains(instanceIdentifier)) {
261 qCWarning(AKONADICONTROL_LOG) << "Cannot create another instance of agent" << identifier;
262 return QString();
263 }
264
265 // Return from this dbus call before we do the next. Otherwise dbus brakes for
266 // this process.
267 if (calledFromDBus()) {
268 connection().send(message().createReply(instanceIdentifier));
269 }
270
271 if (!instance->start(agentInfo)) {
272 return QString();
273 }
274
275 mAgentInstances.insert(instanceIdentifier, instance);
276 registerAgentAtServer(instanceIdentifier, agentInfo);
277 save();
278
279 return instanceIdentifier;
280}
281
283{
284 const auto instance = mAgentInstances.value(identifier);
285 if (!instance) {
286 qCWarning(AKONADICONTROL_LOG) << Q_FUNC_INFO << "Agent instance with identifier" << identifier << "does not exist";
287 return;
288 }
289
290 if (instance->hasAgentInterface()) {
291 instance->cleanup();
292 } else {
293 qCWarning(AKONADICONTROL_LOG) << "Agent instance" << identifier << "has no interface!";
294 }
295
296 mAgentInstances.remove(identifier);
297
298 save();
299
300 org::freedesktop::Akonadi::ResourceManager resmanager(Akonadi::DBus::serviceName(Akonadi::DBus::Server),
301 QStringLiteral("/ResourceManager"),
303 this);
304 resmanager.removeResourceInstance(instance->identifier());
305
306 // Kill the preprocessor instance, if any.
307 org::freedesktop::Akonadi::PreprocessorManager preProcessorManager(Akonadi::DBus::serviceName(Akonadi::DBus::Server),
308 QStringLiteral("/PreprocessorManager"),
310 this);
311
312 preProcessorManager.unregisterInstance(instance->identifier());
313
314 if (instance->hasAgentInterface()) {
315 qCDebug(AKONADICONTROL_LOG) << "AgentManager::removeAgentInstance: calling instance->quit()";
316 instance->quit();
317 } else {
318 qCWarning(AKONADICONTROL_LOG) << "Agent instance" << identifier << "has no interface!";
319 }
320
321 Q_EMIT agentInstanceRemoved(identifier);
322}
323
325{
326 const AgentInstance::Ptr agent = mAgentInstances.value(identifier);
327 if (!agent) {
328 qCWarning(AKONADICONTROL_LOG) << "Agent instance with identifier" << identifier << "does not exist";
329 return QString();
330 }
331
332 return agent->agentType();
333}
334
336{
337 return mAgentInstances.keys();
338}
339
340int AgentManager::agentInstanceStatus(const QString &identifier) const
341{
342 if (!checkInstance(identifier)) {
343 return 2;
344 }
345
346 return mAgentInstances.value(identifier)->status();
347}
348
350{
351 if (!checkInstance(identifier)) {
352 return QString();
353 }
354
355 return mAgentInstances.value(identifier)->statusMessage();
356}
357
358uint AgentManager::agentInstanceProgress(const QString &identifier) const
359{
360 if (!checkInstance(identifier)) {
361 return 0;
362 }
363
364 return mAgentInstances.value(identifier)->progress();
365}
366
368{
369 Q_UNUSED(identifier)
370
371 return QString();
372}
373
374void AgentManager::agentInstanceConfigure(const QString &identifier, qlonglong windowId)
375{
376 if (!checkAgentInterfaces(identifier, QStringLiteral("agentInstanceConfigure"))) {
377 return;
378 }
379
380 mAgentInstances.value(identifier)->configure(windowId);
381}
382
384{
385 if (!checkInstance(identifier)) {
386 return false;
387 }
388
389 return mAgentInstances.value(identifier)->isOnline();
390}
391
392void AgentManager::setAgentInstanceOnline(const QString &identifier, bool state)
393{
394 if (!checkAgentInterfaces(identifier, QStringLiteral("setAgentInstanceOnline"))) {
395 return;
396 }
397
398 mAgentInstances.value(identifier)->statusInterface()->setOnline(state);
399}
400
401// resource specific methods //
402void AgentManager::setAgentInstanceName(const QString &identifier, const QString &name)
403{
404 if (!checkResourceInterface(identifier, QStringLiteral("setAgentInstanceName"))) {
405 return;
406 }
407
408 mAgentInstances.value(identifier)->resourceInterface()->setName(name);
409}
410
412{
413 if (!checkInstance(identifier)) {
414 return QString();
415 }
416
417 const AgentInstance::Ptr instance = mAgentInstances.value(identifier);
418 if (!instance->resourceName().isEmpty()) {
419 return instance->resourceName();
420 }
421
422 if (!checkAgentExists(instance->agentType())) {
423 return QString();
424 }
425
426 return mAgents.value(instance->agentType()).name;
427}
428
430{
431 if (!checkResourceInterface(identifier, QStringLiteral("agentInstanceSynchronize"))) {
432 return;
433 }
434
435 mAgentInstances.value(identifier)->resourceInterface()->synchronize();
436}
437
439{
440 if (!checkResourceInterface(identifier, QStringLiteral("agentInstanceSynchronizeCollectionTree"))) {
441 return;
442 }
443
444 mAgentInstances.value(identifier)->resourceInterface()->synchronizeCollectionTree();
445}
446
447void AgentManager::agentInstanceSynchronizeCollection(const QString &identifier, qint64 collection)
448{
449 agentInstanceSynchronizeCollection(identifier, collection, false);
450}
451
452void AgentManager::agentInstanceSynchronizeCollection(const QString &identifier, qint64 collection, bool recursive)
453{
454 if (!checkResourceInterface(identifier, QStringLiteral("agentInstanceSynchronizeCollection"))) {
455 return;
456 }
457
458 mAgentInstances.value(identifier)->resourceInterface()->synchronizeCollection(collection, recursive);
459}
460
462{
463 if (!checkResourceInterface(identifier, QStringLiteral("agentInstanceSynchronizeTags"))) {
464 return;
465 }
466
467 mAgentInstances.value(identifier)->resourceInterface()->synchronizeTags();
468}
469
471{
472 if (!checkResourceInterface(identifier, QStringLiteral("agentInstanceSynchronizeRelations"))) {
473 return;
474 }
475
476 mAgentInstances.value(identifier)->resourceInterface()->synchronizeRelations();
477}
478
480{
481 if (!checkInstance(identifier)) {
482 return;
483 }
484
485 mAgentInstances.value(identifier)->restartWhenIdle();
486}
487
488void AgentManager::updatePluginInfos()
489{
490 const QHash<QString, AgentType> oldInfos = mAgents;
491 readPluginInfos();
492
493 for (const AgentType &oldInfo : oldInfos) {
494 if (!mAgents.contains(oldInfo.identifier)) {
495 Q_EMIT agentTypeRemoved(oldInfo.identifier);
496 }
497 }
498
499 for (const AgentType &newInfo : std::as_const(mAgents)) {
500 if (!oldInfos.contains(newInfo.identifier)) {
501 Q_EMIT agentTypeAdded(newInfo.identifier);
502 ensureAutoStart(newInfo);
503 }
504 }
505}
506
507void AgentManager::readPluginInfos()
508{
509 mAgents.clear();
510
511 const QStringList pathList = pluginInfoPathList();
512
513 for (const QString &path : pathList) {
514 const QDir directory(path, QStringLiteral("*.desktop"));
515 readPluginInfos(directory);
516 }
517}
518
519void AgentManager::readPluginInfos(const QDir &directory)
520{
521 const QStringList files = directory.entryList();
522 qCDebug(AKONADICONTROL_LOG) << "PLUGINS: " << directory.canonicalPath();
523 qCDebug(AKONADICONTROL_LOG) << "PLUGINS: " << files;
524
525 for (int i = 0; i < files.count(); ++i) {
526 const QString fileName = directory.absoluteFilePath(files[i]);
527
528 AgentType agentInfo;
529 if (agentInfo.load(fileName, this)) {
530 if (mAgents.contains(agentInfo.identifier)) {
531 qCWarning(AKONADICONTROL_LOG) << "Duplicated agent identifier" << agentInfo.identifier << "from file" << fileName;
532 continue;
533 }
534
535 const QString disableAutostart = akGetEnv("AKONADI_DISABLE_AGENT_AUTOSTART");
536 if (!disableAutostart.isEmpty()) {
537 qCDebug(AKONADICONTROL_LOG) << "Autostarting of agents is disabled.";
538 agentInfo.capabilities.removeOne(AgentType::CapabilityAutostart);
539 }
540
541 if (!mAgentServerEnabled && agentInfo.launchMethod == AgentType::Server) {
542 agentInfo.launchMethod = AgentType::Launcher;
543 }
544
545 if (agentInfo.launchMethod == AgentType::Process) {
546 const QString executable = Akonadi::StandardDirs::findExecutable(agentInfo.exec);
547 if (executable.isEmpty()) {
548 qCWarning(AKONADICONTROL_LOG) << "Executable" << agentInfo.exec << "for agent" << agentInfo.identifier << "could not be found!";
549 continue;
550 }
551 }
552
553 qCDebug(AKONADICONTROL_LOG) << "PLUGINS inserting: " << agentInfo.identifier << agentInfo.instanceCounter << agentInfo.capabilities;
554 mAgents.insert(agentInfo.identifier, agentInfo);
555 }
556 }
557}
558
559QStringList AgentManager::pluginInfoPathList()
560{
561 return Akonadi::StandardDirs::locateAllResourceDirs(QStringLiteral("akonadi/agents"));
562}
563
564void AgentManager::load()
565{
566 org::freedesktop::Akonadi::ResourceManager resmanager(Akonadi::DBus::serviceName(Akonadi::DBus::Server),
567 QStringLiteral("/ResourceManager"),
569 this);
570 const QStringList knownResources = resmanager.resourceInstances();
571
572 QSettings file(Akonadi::StandardDirs::agentsConfigFile(Akonadi::StandardDirs::ReadOnly), QSettings::IniFormat);
573 file.beginGroup(QStringLiteral("Instances"));
574 const QStringList entries = file.childGroups();
575 for (int i = 0; i < entries.count(); ++i) {
576 const QString instanceIdentifier = entries[i];
577
578 if (mAgentInstances.contains(instanceIdentifier)) {
579 qCWarning(AKONADICONTROL_LOG) << "Duplicated instance identifier" << instanceIdentifier << "found in agentsrc";
580 continue;
581 }
582
583 file.beginGroup(entries[i]);
584
585 const QString agentType = file.value(QStringLiteral("AgentType")).toString();
586 const auto typeIter = mAgents.constFind(agentType);
587 if (typeIter == mAgents.cend() || typeIter->exec.isEmpty()) {
588 qCWarning(AKONADICONTROL_LOG) << "Reference to unknown agent type" << agentType << "in agentsrc, creating a fake entry.";
589 if (typeIter == mAgents.cend()) {
590 AgentType type;
591 type.identifier = type.name = agentType;
592 mAgents.insert(type.identifier, type);
593 }
594
595 auto brokenInstance = AgentInstance::Ptr{new Akonadi::AgentBrokenInstance{agentType, *this}};
596 brokenInstance->setIdentifier(instanceIdentifier);
597 mAgentInstances.insert(instanceIdentifier, brokenInstance);
598 file.endGroup();
599 continue;
600 }
601
602 const AgentType &type = *typeIter;
603
604 // recover if the db has been deleted in the meantime or got otherwise corrupted
605 if (!knownResources.contains(instanceIdentifier) && type.capabilities.contains(AgentType::CapabilityResource)) {
606 qCDebug(AKONADICONTROL_LOG) << "Recovering instance" << instanceIdentifier << "after database loss";
607 registerAgentAtServer(instanceIdentifier, type);
608 }
609
610 const AgentInstance::Ptr instance = createAgentInstance(type);
611 instance->setIdentifier(instanceIdentifier);
612 if (instance->start(type)) {
613 mAgentInstances.insert(instanceIdentifier, instance);
614 }
615
616 file.endGroup();
617 }
618
619 file.endGroup();
620}
621
622void AgentManager::save()
623{
624 QSettings file(Akonadi::StandardDirs::agentsConfigFile(Akonadi::StandardDirs::WriteOnly), QSettings::IniFormat);
625
626 for (const AgentType &info : std::as_const(mAgents)) {
627 info.save(&file);
628 }
629
630 file.beginGroup(QStringLiteral("Instances"));
631 file.remove(QString());
632 for (const AgentInstance::Ptr &instance : std::as_const(mAgentInstances)) {
633 file.beginGroup(instance->identifier());
634 file.setValue(QStringLiteral("AgentType"), instance->agentType());
635 file.endGroup();
636 }
637
638 file.endGroup();
639}
640
641void AgentManager::serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
642{
644 // This is called by the D-Bus server when a service comes up, goes down or changes ownership for some reason
645 // and this is where we "hook up" our different Agent interfaces.
646
647 // Ignore DBus address name (e.g. :1.310)
648 if (name.startsWith(QLatin1Char(':'))) {
649 return;
650 }
651
652 // Ignore services belonging to another Akonadi instance
653 const auto parsedInstance = Akonadi::DBus::parseInstanceIdentifier(name);
654 const auto currentInstance = Akonadi::Instance::hasIdentifier() ? std::optional<QString>(Akonadi::Instance::identifier()) : std::nullopt;
656 return;
657 }
658
659 qCDebug(AKONADICONTROL_LOG) << "Service" << name << "owner changed from" << oldOwner << "to" << newOwner;
660
661 if ((name == Akonadi::DBus::serviceName(Akonadi::DBus::Server) || name == Akonadi::DBus::serviceName(Akonadi::DBus::AgentServer)) && !newOwner.isEmpty()) {
662 if (QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Server))
663 && (!mAgentServer || QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::AgentServer)))) {
664 // server is operational, start agents
665 continueStartup();
666 }
667 }
668
669 const auto service = Akonadi::DBus::parseAgentServiceName(name);
670 if (!service.has_value()) {
671 return;
672 }
673 switch (service->agentType) {
674 case Akonadi::DBus::Agent: {
675 // An agent service went up or down
676 if (newOwner.isEmpty()) {
677 return; // It went down: we don't care here.
678 }
679
680 if (!mAgentInstances.contains(service->identifier)) {
681 return;
682 }
683
684 const AgentInstance::Ptr instance = mAgentInstances.value(service->identifier);
685 const bool restarting = instance->hasAgentInterface();
686 if (!instance->obtainAgentInterface()) {
687 return;
688 }
689
690 Q_ASSERT(mAgents.contains(instance->agentType()));
691 const bool isResource = mAgents.value(instance->agentType()).capabilities.contains(AgentType::CapabilityResource);
692
693 if (!restarting && (!isResource || instance->hasResourceInterface())) {
694 Q_EMIT agentInstanceAdded(service->identifier);
695 }
696
697 break;
698 }
699 case Akonadi::DBus::Resource: {
700 // A resource service went up or down
701 if (newOwner.isEmpty()) {
702 return; // It went down: we don't care here.
703 }
704
705 if (!mAgentInstances.contains(service->identifier)) {
706 return;
707 }
708
709 const AgentInstance::Ptr instance = mAgentInstances.value(service->identifier);
710 const bool restarting = instance->hasResourceInterface();
711 if (!instance->obtainResourceInterface()) {
712 return;
713 }
714
715 if (!restarting && instance->hasAgentInterface()) {
716 Q_EMIT agentInstanceAdded(service->identifier);
717 }
718
719 break;
720 }
721 case Akonadi::DBus::Preprocessor: {
722 // A preprocessor service went up or down
723
724 // If the preprocessor is going up then the org.freedesktop.Akonadi.Agent.* interface
725 // should be already up (as it's registered before the preprocessor one).
726 // So if we don't know about the preprocessor as agent instance
727 // then it's not our preprocessor.
728
729 // If the preprocessor is going down then either the agent interface already
730 // went down (and it has been already unregistered on the manager side)
731 // or it's still registered as agent and WE have to unregister it.
732 // The order of interface deletions depends on Qt but we handle both cases.
733
734 // Check if we "know" about it.
735 qCDebug(AKONADICONTROL_LOG) << "Preprocessor " << service->identifier << " is going up or down...";
736
737 if (!mAgentInstances.contains(service->identifier)) {
738 qCDebug(AKONADICONTROL_LOG) << "But it isn't registered as agent... not mine (anymore?)";
739 return; // not our agent (?)
740 }
741
742 org::freedesktop::Akonadi::PreprocessorManager preProcessorManager(Akonadi::DBus::serviceName(Akonadi::DBus::Server),
743 QStringLiteral("/PreprocessorManager"),
745 this);
746
747 if (!preProcessorManager.isValid()) {
748 qCWarning(AKONADICONTROL_LOG) << "Could not connect to PreprocessorManager via D-Bus:" << preProcessorManager.lastError().message();
749 } else {
750 if (newOwner.isEmpty()) {
751 // The preprocessor went down. Unregister it on server side.
752
753 preProcessorManager.unregisterInstance(service->identifier);
754
755 } else {
756 // The preprocessor went up. Register it on server side.
757
758 if (!mAgentInstances.value(service->identifier)->obtainPreprocessorInterface()) {
759 // Hm.. couldn't hook up its preprocessor interface..
760 // Make sure we don't have it in the preprocessor chain
761 qCWarning(AKONADICONTROL_LOG) << "Couldn't obtain preprocessor interface for instance" << service->identifier;
762
763 preProcessorManager.unregisterInstance(service->identifier);
764 return;
765 }
766
767 qCDebug(AKONADICONTROL_LOG) << "Registering preprocessor instance" << service->identifier;
768
769 // Add to the preprocessor chain
770 preProcessorManager.registerInstance(service->identifier);
771 }
772 }
773
774 break;
775 }
776 default:
777 break;
778 }
779}
780
781bool AgentManager::checkInstance(const QString &identifier) const
782{
783 if (!mAgentInstances.contains(identifier)) {
784 qCWarning(AKONADICONTROL_LOG) << "Agent instance with identifier " << identifier << " does not exist";
785 return false;
786 }
787
788 return true;
789}
790
791bool AgentManager::checkResourceInterface(const QString &identifier, const QString &method) const
792{
793 if (!checkInstance(identifier)) {
794 return false;
795 }
796
797 if (!mAgents[mAgentInstances[identifier]->agentType()].capabilities.contains(QLatin1StringView("Resource"))) {
798 return false;
799 }
800
801 if (!mAgentInstances[identifier]->hasResourceInterface()) {
802 qCWarning(AKONADICONTROL_LOG) << QLatin1StringView("AgentManager::") + method << " Agent instance " << identifier << " has no resource interface!";
803 return false;
804 }
805
806 return true;
807}
808
809bool AgentManager::checkAgentExists(const QString &identifier) const
810{
811 if (!mAgents.contains(identifier)) {
812 qCWarning(AKONADICONTROL_LOG) << "Agent instance " << identifier << " does not exist.";
813 return false;
814 }
815
816 return true;
817}
818
819bool AgentManager::checkAgentInterfaces(const QString &identifier, const QString &method) const
820{
821 if (!checkInstance(identifier)) {
822 return false;
823 }
824
825 if (!mAgentInstances.value(identifier)->hasAgentInterface()) {
826 qCWarning(AKONADICONTROL_LOG) << "Agent instance (" << method << ") " << identifier << " has no agent interface.";
827 return false;
828 }
829
830 return true;
831}
832
833void AgentManager::ensureAutoStart(const AgentType &info)
834{
835 if (!info.capabilities.contains(AgentType::CapabilityAutostart)) {
836 return; // no an autostart agent
837 }
838
839 org::freedesktop::Akonadi::AgentServer agentServer(Akonadi::DBus::serviceName(Akonadi::DBus::AgentServer),
840 QStringLiteral("/AgentServer"),
842 this);
843
844 if (mAgentInstances.contains(info.identifier) || (agentServer.isValid() && agentServer.started(info.identifier))) {
845 return; // already running
846 }
847
848 const AgentInstance::Ptr instance = createAgentInstance(info);
849 instance->setIdentifier(info.identifier);
850 if (instance->start(info)) {
851 mAgentInstances.insert(instance->identifier(), instance);
852 registerAgentAtServer(instance->identifier(), info);
853 save();
854 }
855}
856
857void AgentManager::agentExeChanged(const QString &fileName)
858{
859 if (!QFile::exists(fileName)) {
860 return;
861 }
862
863 for (const AgentType &type : std::as_const(mAgents)) {
864 if (fileName.endsWith(type.exec)) {
865 for (const AgentInstance::Ptr &instance : std::as_const(mAgentInstances)) {
866 if (instance->agentType() == type.identifier) {
867 instance->restartWhenIdle();
868 }
869 }
870 }
871 }
872}
873
874void AgentManager::registerAgentAtServer(const QString &agentIdentifier, const AgentType &type)
875{
876 if (type.capabilities.contains(AgentType::CapabilityResource)) {
878 new org::freedesktop::Akonadi::ResourceManager(Akonadi::DBus::serviceName(Akonadi::DBus::Server),
879 QStringLiteral("/ResourceManager"),
881 this));
882 resmanager->addResourceInstance(agentIdentifier, type.capabilities);
883 }
884}
885
886void AgentManager::addSearch(const QString &query, const QString &queryLanguage, qint64 resultCollectionId)
887{
888 qCDebug(AKONADICONTROL_LOG) << "AgentManager::addSearch" << query << queryLanguage << resultCollectionId;
889 for (const AgentInstance::Ptr &instance : std::as_const(mAgentInstances)) {
890 const AgentType type = mAgents.value(instance->agentType());
891 if (type.capabilities.contains(AgentType::CapabilitySearch) && instance->searchInterface()) {
892 instance->searchInterface()->addSearch(query, queryLanguage, resultCollectionId);
893 }
894 }
895}
896
897void AgentManager::removeSearch(quint64 resultCollectionId)
898{
899 qCDebug(AKONADICONTROL_LOG) << "AgentManager::removeSearch" << resultCollectionId;
900 for (const AgentInstance::Ptr &instance : std::as_const(mAgentInstances)) {
901 const AgentType type = mAgents.value(instance->agentType());
902 if (type.capabilities.contains(AgentType::CapabilitySearch) && instance->searchInterface()) {
903 instance->searchInterface()->removeSearch(resultCollectionId);
904 }
905 }
906}
907
908#include "agentmanager.moc"
909
910#include "moc_agentmanager.cpp"
bool agentInstanceOnline(const QString &identifier)
Returns if the agent instance identifier is in online mode.
void setAgentInstanceName(const QString &identifier, const QString &name)
Sets the name of the agent instance with the given identifier.
QString agentInstanceStatusMessage(const QString &identifier) const
Returns the i18n'ed description of the current status of the agent with the given identifier.
void agentInstanceAdded(const QString &agentIdentifier)
This signal is emitted whenever a new agent instance was created.
void agentTypeAdded(const QString &agentType)
This signal is emitted whenever a new agent type was installed on the system.
QStringList agentInstances() const
Returns the list of identifiers of configured instances.
QString agentInstanceName(const QString &identifier) const
Returns the name of the agent instance with the given identifier.
QStringList agentTypes() const
Returns the list of identifiers of all available agent types.
void removeAgentInstance(const QString &identifier)
Removes the agent with the given identifier.
void agentInstanceSynchronizeCollectionTree(const QString &identifier)
Trigger a synchronization of the collection tree by the given resource agent.
AgentManager(bool verbose, QObject *parent=nullptr)
Creates a new agent manager.
QString agentInstanceProgressMessage(const QString &identifier) const
Returns the i18n'ed description of the current progress of the agent with the given identifier.
uint agentInstanceProgress(const QString &identifier) const
Returns the current progress of the agent with the given identifier in percentage.
void agentInstanceSynchronizeCollection(const QString &identifier, qint64 collection)
Trigger a synchronization of the given collection by its owning resource agent.
void removeSearch(quint64 resultCollectionId)
Removes a persistent search for the given result collection.
QVariantMap agentCustomProperties(const QString &identifier) const
Returns a list of Custom added properties of the agent type for the given identifier.
QStringList agentMimeTypes(const QString &identifier) const
Returns a list of supported mimetypes of the agent type for the given identifier.
QString agentInstanceType(const QString &identifier)
Returns the type of the agent instance with the given identifier.
void agentInstanceSynchronizeRelations(const QString &identifier)
Trigger a synchronization of relations by the given resource agent.
void agentInstanceSynchronizeTags(const QString &identifier)
Trigger a synchronization of tags by the given resource agent.
void agentInstanceRemoved(const QString &agentIdentifier)
This signal is emitted whenever an agent instance was removed.
QString agentComment(const QString &identifier) const
Returns the i18n'ed comment of the agent type for the given identifier.
QStringList agentCapabilities(const QString &identifier) const
Returns a list of supported capabilities of the agent type for the given identifier.
QString agentName(const QString &identifier) const
Returns the i18n'ed name of the agent type for the given identifier.
void addSearch(const QString &query, const QString &queryLanguage, qint64 resultCollectionId)
Add a persistent search to remote search agents.
void setAgentInstanceOnline(const QString &identifier, bool state)
Sets agent instance identifier to online or offline mode.
void agentInstanceConfigure(const QString &identifier, qlonglong windowId)
Triggers the agent instance with the given identifier to show its configuration dialog.
void restartAgentInstance(const QString &identifier)
Restarts the agent instance identifier.
void cleanup()
Called by the crash handler and dtor to terminate the child processes.
~AgentManager() override
Destroys the agent manager.
void agentTypeRemoved(const QString &agentType)
This signal is emitted whenever an agent type was removed from the system.
QString agentIcon(const QString &identifier) const
Returns the icon name of the agent type for the given identifier.
int agentInstanceStatus(const QString &identifier) const
Returns the current status code of the agent with the given identifier.
QString createAgentInstance(const QString &identifier)
Creates a new agent of the given agent type identifier.
void agentInstanceSynchronize(const QString &identifier)
Triggers the agent instance with the given identifier to start synchronization.
This class starts and observes a process.
void setCrashPolicy(CrashPolicy policy)
Sets the crash policy.
void start()
Starts the process with the previously set application and arguments.
void unableToStart()
Emitted if the process could not be started since it terminated too often.
void setShutdownTimeout(std::chrono::milliseconds timeout)
Sets the time (in msecs) we wait for the process to shut down before we send terminate/kill signals.
Capabilities capabilities()
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
QString name(StandardShortcut id)
A glue between Qt and the standard library.
void exit(int returnCode)
QCoreApplication * instance()
bool registerObject(const QString &path, QObject *object, RegisterOptions options)
bool send(const QDBusMessage &message) const const
QDBusConnection sessionBus()
void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
bool calledFromDBus() const const
QDBusConnection connection() const const
const QDBusMessage & message() const const
QString absoluteFilePath(const QString &fileName) const const
QString canonicalPath() const const
QStringList entryList(Filters filters, SortFlags sort) const const
bool exists() const const
const_iterator cend() const const
void clear()
const_iterator constFind(const Key &key) const const
bool contains(const Key &key) const const
iterator insert(const Key &key, const T &value)
QList< Key > keys() const const
T value(const Key &key) const const
qsizetype count() const const
Q_EMITQ_EMIT
Q_OBJECTQ_OBJECT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T qobject_cast(QObject *object)
QVariant value(QAnyStringView key) const const
QSharedPointer< T > create(Args &&... args)
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString number(double n, char format, int precision)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
bool toBool() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:38 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.