Akonadi

agentbase.cpp
1/*
2 SPDX-FileCopyrightText: 2006 Till Adam <adam@kde.org>
3 SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org>
4 SPDX-FileCopyrightText: 2007 Bruno Virlet <bruno.virlet@gmail.com>
5 SPDX-FileCopyrightText: 2008 Kevin Krammer <kevin.krammer@gmx.at>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "agentbase.h"
11#include "agentbase_p.h"
12
13#include "agentconfigurationdialog.h"
14#include "agentmanager.h"
15#include "akonadifull-version.h"
16#include "changerecorder.h"
17#include "controladaptor.h"
18#include "itemfetchjob.h"
19#include "monitor_p.h"
20#include "private/standarddirs_p.h"
21#include "servermanager_p.h"
22#include "session.h"
23#include "session_p.h"
24#include "statusadaptor.h"
25
26#include "akonadiagentbase_debug.h"
27
28#include <KAboutData>
29#include <KCrash>
30#include <KIconTheme>
31#include <KLocalizedString>
32#include <KStyleManager>
33
34#include <QCommandLineParser>
35#include <QNetworkInformation>
36#include <QPointer>
37#include <QSettings>
38#include <QTimer>
39
40#include <QStandardPaths>
41#include <signal.h>
42#include <stdlib.h>
43#include <strstream>
44#if defined __GLIBC__
45#include <malloc.h> // for dumping memory information
46#endif
47
48#ifdef Q_OS_WIN
49#include <Windows.h>
50#endif
51
52#include <chrono>
53#include <thread>
54
55using namespace Akonadi;
56using namespace std::chrono_literals;
57static AgentBase *sAgentBase = nullptr;
58
62
66
67void AgentBase::Observer::itemAdded(const Item &item, const Collection &collection)
68{
69 Q_UNUSED(item)
70 Q_UNUSED(collection)
71 if (sAgentBase) {
72 sAgentBase->d_ptr->changeProcessed();
73 }
74}
75
76void AgentBase::Observer::itemChanged(const Item &item, const QSet<QByteArray> &partIdentifiers)
77{
78 Q_UNUSED(item)
79 Q_UNUSED(partIdentifiers)
80 if (sAgentBase) {
81 sAgentBase->d_ptr->changeProcessed();
82 }
83}
84
86{
87 Q_UNUSED(item)
88 if (sAgentBase) {
89 sAgentBase->d_ptr->changeProcessed();
90 }
91}
92
94{
95 Q_UNUSED(collection)
96 Q_UNUSED(parent)
97 if (sAgentBase) {
98 sAgentBase->d_ptr->changeProcessed();
99 }
100}
101
103{
104 Q_UNUSED(collection)
105 if (sAgentBase) {
106 sAgentBase->d_ptr->changeProcessed();
107 }
108}
109
111{
112 Q_UNUSED(collection)
113 if (sAgentBase) {
114 sAgentBase->d_ptr->changeProcessed();
115 }
116}
117
119{
120 Q_UNUSED(item)
121 Q_UNUSED(source)
122 Q_UNUSED(dest)
123 if (sAgentBase) {
124 sAgentBase->d_ptr->changeProcessed();
125 }
126}
127
129{
130 Q_UNUSED(item)
131 Q_UNUSED(collection)
132 if (sAgentBase) {
133 // not implementation, let's disconnect the signal to enable optimizations in Monitor
134 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemLinked, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemLinked);
135 sAgentBase->d_ptr->changeProcessed();
136 }
137}
138
140{
141 Q_UNUSED(item)
142 Q_UNUSED(collection)
143 if (sAgentBase) {
144 // not implementation, let's disconnect the signal to enable optimizations in Monitor
145 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemUnlinked, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemUnlinked);
146 sAgentBase->d_ptr->changeProcessed();
147 }
148}
149
151{
152 Q_UNUSED(collection)
153 Q_UNUSED(source)
154 Q_UNUSED(dest)
155 if (sAgentBase) {
156 sAgentBase->d_ptr->changeProcessed();
157 }
158}
159
161{
162 Q_UNUSED(changedAttributes)
163 collectionChanged(collection);
164}
165
167{
168 Q_UNUSED(items)
169 Q_UNUSED(addedFlags)
170 Q_UNUSED(removedFlags)
171
172 if (sAgentBase) {
173 // not implementation, let's disconnect the signal to enable optimizations in Monitor
174 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsFlagsChanged, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsFlagsChanged);
175 sAgentBase->d_ptr->changeProcessed();
176 }
177}
178
179void AgentBase::ObserverV3::itemsMoved(const Akonadi::Item::List &items, const Collection &sourceCollection, const Collection &destinationCollection)
180{
181 Q_UNUSED(items)
182 Q_UNUSED(sourceCollection)
183 Q_UNUSED(destinationCollection)
184
185 if (sAgentBase) {
186 // not implementation, let's disconnect the signal to enable optimizations in Monitor
187 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsMoved, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsMoved);
188 sAgentBase->d_ptr->changeProcessed();
189 }
190}
191
193{
194 Q_UNUSED(items)
195
196 if (sAgentBase) {
197 // not implementation, let's disconnect the signal to enable optimizations in Monitor
198 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsRemoved, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsRemoved);
199 sAgentBase->d_ptr->changeProcessed();
200 }
201}
202
204{
205 Q_UNUSED(items)
206 Q_UNUSED(collection)
207
208 if (sAgentBase) {
209 // not implementation, let's disconnect the signal to enable optimizations in Monitor
210 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsLinked, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsLinked);
211 sAgentBase->d_ptr->changeProcessed();
212 }
213}
214
216{
217 Q_UNUSED(items)
218 Q_UNUSED(collection)
219
220 if (sAgentBase) {
221 // not implementation, let's disconnect the signal to enable optimizations in Monitor
222 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsUnlinked, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsUnlinked);
223 sAgentBase->d_ptr->changeProcessed();
224 }
225}
226
227AgentBase::TagObserver::TagObserver() = default;
228
229AgentBase::TagObserver::~TagObserver() = default;
230
231void AgentBase::TagObserver::tagAdded(const Akonadi::Tag &tag)
232{
233 Q_UNUSED(tag)
234 if (sAgentBase) {
235 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::tagAdded, sAgentBase->d_ptr.get(), &AgentBasePrivate::tagAdded);
236 sAgentBase->d_ptr->changeProcessed();
237 }
238}
239
240void AgentBase::TagObserver::tagChanged(const Akonadi::Tag &tag)
241{
242 Q_UNUSED(tag)
243 if (sAgentBase) {
244 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::tagChanged, sAgentBase->d_ptr.get(), &AgentBasePrivate::tagChanged);
245 sAgentBase->d_ptr->changeProcessed();
246 }
247}
248
249void AgentBase::TagObserver::tagRemoved(const Akonadi::Tag &tag)
250{
251 Q_UNUSED(tag)
252 if (sAgentBase) {
253 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::tagRemoved, sAgentBase->d_ptr.get(), &AgentBasePrivate::tagRemoved);
254 sAgentBase->d_ptr->changeProcessed();
255 }
256}
257
258void AgentBase::TagObserver::itemsTagsChanged(const Akonadi::Item::List &items, const QSet<Akonadi::Tag> &addedTags, const QSet<Akonadi::Tag> &removedTags)
259{
260 Q_UNUSED(items)
261 Q_UNUSED(addedTags)
262 Q_UNUSED(removedTags)
263
264 if (sAgentBase) {
265 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsTagsChanged, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsTagsChanged);
266 sAgentBase->d_ptr->changeProcessed();
267 }
268}
269/// @cond PRIVATE
270
271AgentBasePrivate::AgentBasePrivate(AgentBase *parent)
272 : q_ptr(parent)
273 , mStatusCode(AgentBase::Idle)
274 , mProgress(0)
275 , mNeedsNetwork(false)
276 , mOnline(false)
277 , mDesiredOnlineState(false)
278 , mPendingQuit(false)
279 , mSettings(nullptr)
280 , mChangeRecorder(nullptr)
281 , mTracer(nullptr)
282 , mObserver(nullptr)
283 , mPowerInterface(nullptr)
284 , mTemporaryOfflineTimer(nullptr)
285 , mEventLoopLocker(nullptr)
286{
287 Internal::setClientType(Internal::Agent);
288}
289
290AgentBasePrivate::~AgentBasePrivate()
291{
292 mChangeRecorder->setConfig(nullptr);
293 delete mSettings;
294}
295
296void AgentBasePrivate::init()
297{
298 Q_Q(AgentBase);
299 /**
300 * Create a default session for this process.
301 */
302 SessionPrivate::createDefaultSession(mId.toLatin1());
303
304 mTracer =
305 new org::freedesktop::Akonadi::Tracer(ServerManager::serviceName(ServerManager::Server), QStringLiteral("/tracing"), QDBusConnection::sessionBus(), q);
306
307 new Akonadi__ControlAdaptor(q);
308 new Akonadi__StatusAdaptor(q);
309 if (!QDBusConnection::sessionBus().registerObject(QStringLiteral("/"), q, QDBusConnection::ExportAdaptors)) {
310 Q_EMIT q->error(i18n("Unable to register object at dbus: %1", QDBusConnection::sessionBus().lastError().message()));
311 }
312
313 mSettings = new QSettings(ServerManager::agentConfigFilePath(mId), QSettings::IniFormat);
314
315 mChangeRecorder = new ChangeRecorder(q);
316 mChangeRecorder->setObjectName(QLatin1StringView("AgentBaseChangeRecorder"));
317 mChangeRecorder->ignoreSession(Session::defaultSession());
318 mChangeRecorder->itemFetchScope().setCacheOnly(true);
319 mChangeRecorder->setConfig(mSettings);
320
321 mDesiredOnlineState = mSettings->value(QLatin1StringView("Agent/DesiredOnlineState"), true).toBool();
322 mOnline = mDesiredOnlineState;
323
324 // reinitialize the status message now that online state is available
325 mStatusMessage = defaultReadyMessage();
326
327 mName = mSettings->value(QLatin1StringView("Agent/Name")).toString();
328 if (mName.isEmpty()) {
329 mName = mSettings->value(QLatin1StringView("Resource/Name")).toString();
330 if (!mName.isEmpty()) {
331 mSettings->remove(QLatin1StringView("Resource/Name"));
332 mSettings->setValue(QLatin1StringView("Agent/Name"), mName);
333 }
334 }
335
336 mActivities = mSettings->value(QLatin1StringView("Agent/Activities")).toStringList();
337 mActivitiesEnabled = mSettings->value(QLatin1StringView("Agent/ActivitiesEnabled"), false).toBool();
338 connect(mChangeRecorder, &Monitor::itemAdded, this, &AgentBasePrivate::itemAdded);
339 connect(mChangeRecorder, &Monitor::itemChanged, this, &AgentBasePrivate::itemChanged);
340 connect(mChangeRecorder, &Monitor::collectionAdded, this, &AgentBasePrivate::collectionAdded);
341 connect(mChangeRecorder,
342 qOverload<const Collection &>(&ChangeRecorder::collectionChanged),
343 this,
344 qOverload<const Collection &>(&AgentBasePrivate::collectionChanged));
345 connect(mChangeRecorder,
346 qOverload<const Collection &, const QSet<QByteArray> &>(&ChangeRecorder::collectionChanged),
347 this,
348 qOverload<const Collection &, const QSet<QByteArray> &>(&AgentBasePrivate::collectionChanged));
349 connect(mChangeRecorder, &Monitor::collectionMoved, this, &AgentBasePrivate::collectionMoved);
350 connect(mChangeRecorder, &Monitor::collectionRemoved, this, &AgentBasePrivate::collectionRemoved);
351 connect(mChangeRecorder, &Monitor::collectionSubscribed, this, &AgentBasePrivate::collectionSubscribed);
352 connect(mChangeRecorder, &Monitor::collectionUnsubscribed, this, &AgentBasePrivate::collectionUnsubscribed);
353
354 connect(q, qOverload<int, const QString &>(&AgentBase::status), this, &AgentBasePrivate::slotStatus);
355 connect(q, &AgentBase::percent, this, &AgentBasePrivate::slotPercent);
356 connect(q, &AgentBase::warning, this, &AgentBasePrivate::slotWarning);
357 connect(q, &AgentBase::error, this, &AgentBasePrivate::slotError);
358
359 mPowerInterface = new QDBusInterface(QStringLiteral("org.kde.Solid.PowerManagement"),
360 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/SuspendSession"),
361 QStringLiteral("org.kde.Solid.PowerManagement.Actions.SuspendSession"),
363 this);
364 if (mPowerInterface->isValid()) {
365 connect(mPowerInterface, SIGNAL(resumingFromSuspend()), this, SLOT(slotResumedFromSuspend())); // clazy:exclude=old-style-connect
366 } else {
367 delete mPowerInterface;
368 mPowerInterface = nullptr;
369 }
370
371 // Use reference counting to allow agents to finish internal jobs when the
372 // agent is stopped.
373 mEventLoopLocker = new QEventLoopLocker();
374
375 mResourceTypeName = AgentManager::self()->instance(mId).type().name();
376 setProgramName();
377
378 QTimer::singleShot(0s, q, [this] {
379 delayedInit();
380 });
381}
382
383void AgentBasePrivate::delayedInit()
384{
385 Q_Q(AgentBase);
386
387 const QString serviceId = ServerManager::agentServiceName(ServerManager::Agent, mId);
388 if (!QDBusConnection::sessionBus().registerService(serviceId)) {
389 qCCritical(AKONADIAGENTBASE_LOG) << "Unable to register service" << serviceId << "at dbus:" << QDBusConnection::sessionBus().lastError().message();
390 }
391 q->setOnlineInternal(mDesiredOnlineState);
392
394}
395
396void AgentBasePrivate::setProgramName()
397{
398 // ugly, really ugly, if you find another solution, change it and blame me for this code (Andras)
399 QString programName = mResourceTypeName;
400 if (!mName.isEmpty()) {
401 programName = i18nc("Name and type of Akonadi resource", "%1 of type %2", mName, mResourceTypeName);
402 }
403
405}
406
407void AgentBasePrivate::itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection)
408{
409 if (mObserver) {
410 mObserver->itemAdded(item, collection);
411 } else {
413 }
414}
415
416void AgentBasePrivate::itemChanged(const Akonadi::Item &item, const QSet<QByteArray> &partIdentifiers)
417{
418 if (mObserver) {
419 mObserver->itemChanged(item, partIdentifiers);
420 } else {
422 }
423}
424
425void AgentBasePrivate::itemMoved(const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &dest)
426{
427 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
428 if (mObserver) {
429 // inter-resource moves, requires we know which resources the source and destination are in though
430 if (!source.resource().isEmpty() && !dest.resource().isEmpty()) {
431 if (source.resource() != dest.resource()) {
432 if (source.resource() == q_ptr->identifier()) { // moved away from us
433 Akonadi::Item i(item);
434 i.setParentCollection(source);
435 mObserver->itemRemoved(i);
436 } else if (dest.resource() == q_ptr->identifier()) { // moved to us
437 mObserver->itemAdded(item, dest);
438 } else if (observer2) {
439 observer2->itemMoved(item, source, dest);
440 } else {
441 // not for us, not sure if we should get here at all
443 }
444 return;
445 }
446 }
447 // intra-resource move
448 if (observer2) {
449 observer2->itemMoved(item, source, dest);
450 } else {
451 // ### we cannot just call itemRemoved here as this will already trigger changeProcessed()
452 // so, just itemAdded() is good enough as no resource can have implemented intra-resource moves anyway
453 // without using ObserverV2
454 mObserver->itemAdded(item, dest);
455 // mObserver->itemRemoved( item );
456 }
457 }
458}
459
460void AgentBasePrivate::itemRemoved(const Akonadi::Item &item)
461{
462 if (mObserver) {
463 mObserver->itemRemoved(item);
464 } else {
466 }
467}
468
469void AgentBasePrivate::itemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection)
470{
471 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
472 if (observer2) {
473 observer2->itemLinked(item, collection);
474 } else {
476 }
477}
478
479void AgentBasePrivate::itemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection)
480{
481 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
482 if (observer2) {
483 observer2->itemUnlinked(item, collection);
484 } else {
486 }
487}
488
489void AgentBasePrivate::itemsFlagsChanged(const Akonadi::Item::List &items, const QSet<QByteArray> &addedFlags, const QSet<QByteArray> &removedFlags)
490{
491 auto observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver);
492 if (observer3) {
493 observer3->itemsFlagsChanged(items, addedFlags, removedFlags);
494 } else {
495 Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available");
496 }
497}
498
499void AgentBasePrivate::itemsMoved(const Akonadi::Item::List &items, const Akonadi::Collection &source, const Akonadi::Collection &destination)
500{
501 auto observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver);
502 if (observer3) {
503 observer3->itemsMoved(items, source, destination);
504 } else {
505 Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available");
506 }
507}
508
509void AgentBasePrivate::itemsRemoved(const Akonadi::Item::List &items)
510{
511 auto observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver);
512 if (observer3) {
513 observer3->itemsRemoved(items);
514 } else {
515 Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available");
516 }
517}
518
519void AgentBasePrivate::itemsLinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection)
520{
521 if (!mObserver) {
523 return;
524 }
525
526 auto observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver);
527 if (observer3) {
528 observer3->itemsLinked(items, collection);
529 } else {
530 Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available");
531 }
532}
533
534void AgentBasePrivate::itemsUnlinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection)
535{
536 if (!mObserver) {
538 return;
539 }
540
541 auto observer3 = dynamic_cast<AgentBase::ObserverV3 *>(mObserver);
542 if (observer3) {
543 observer3->itemsUnlinked(items, collection);
544 } else {
545 Q_ASSERT_X(false, Q_FUNC_INFO, "Batch slots must never be called when ObserverV3 is not available");
546 }
547}
548
549void AgentBasePrivate::tagAdded(const Akonadi::Tag &tag)
550{
551 if (auto tagObserver = dynamic_cast<AgentBase::TagObserver *>(mObserver); tagObserver) {
552 tagObserver->tagAdded(tag);
553 } else {
555 }
556}
557
558void AgentBasePrivate::tagChanged(const Akonadi::Tag &tag)
559{
560 if (auto tagObserver = dynamic_cast<AgentBase::TagObserver *>(mObserver); tagObserver) {
561 tagObserver->tagChanged(tag);
562 } else {
564 }
565}
566
567void AgentBasePrivate::tagRemoved(const Akonadi::Tag &tag)
568{
569 if (auto tagObserver = dynamic_cast<AgentBase::TagObserver *>(mObserver); tagObserver) {
570 tagObserver->tagRemoved(tag);
571 } else {
573 }
574}
575
576void AgentBasePrivate::itemsTagsChanged(const Akonadi::Item::List &items, const QSet<Akonadi::Tag> &addedTags, const QSet<Akonadi::Tag> &removedTags)
577{
578 if (auto tagObserver = dynamic_cast<AgentBase::TagObserver *>(mObserver); tagObserver) {
579 tagObserver->itemsTagsChanged(items, addedTags, removedTags);
580 } else {
582 }
583}
584
585void AgentBasePrivate::collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
586{
587 if (mObserver) {
588 mObserver->collectionAdded(collection, parent);
589 } else {
591 }
592}
593
594void AgentBasePrivate::collectionChanged(const Akonadi::Collection &collection)
595{
596 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
597 if (mObserver && observer2 == nullptr) { // For ObserverV2 we use the variant with the part identifiers
598 mObserver->collectionChanged(collection);
599 } else if (!mObserver) {
601 }
602}
603
604void AgentBasePrivate::collectionChanged(const Akonadi::Collection &collection, const QSet<QByteArray> &changedAttributes)
605{
606 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
607 if (observer2) {
608 observer2->collectionChanged(collection, changedAttributes);
609 } else {
611 }
612}
613
614void AgentBasePrivate::collectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &dest)
615{
616 auto observer2 = dynamic_cast<AgentBase::ObserverV2 *>(mObserver);
617 if (observer2) {
618 observer2->collectionMoved(collection, source, dest);
619 } else if (mObserver) {
620 // ### we cannot just call collectionRemoved here as this will already trigger changeProcessed()
621 // so, just collectionAdded() is good enough as no resource can have implemented intra-resource moves anyway
622 // without using ObserverV2
623 mObserver->collectionAdded(collection, dest);
624 } else {
626 }
627}
628
629void AgentBasePrivate::collectionRemoved(const Akonadi::Collection &collection)
630{
631 if (mObserver) {
632 mObserver->collectionRemoved(collection);
633 } else {
635 }
636}
637
638void AgentBasePrivate::collectionSubscribed(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
639{
640 Q_UNUSED(collection)
641 Q_UNUSED(parent)
643}
644
645void AgentBasePrivate::collectionUnsubscribed(const Akonadi::Collection &collection)
646{
647 Q_UNUSED(collection)
649}
650
651void AgentBasePrivate::changeProcessed()
652{
653 mChangeRecorder->changeProcessed();
654 QTimer::singleShot(0s, mChangeRecorder, &ChangeRecorder::replayNext);
655}
656
657void AgentBasePrivate::slotStatus(int status, const QString &message)
658{
659 mStatusMessage = message;
660 mStatusCode = 0;
661
662 switch (status) {
663 case AgentBase::Idle:
664 if (mStatusMessage.isEmpty()) {
665 mStatusMessage = defaultReadyMessage();
666 }
667
668 mStatusCode = 0;
669 break;
671 if (mStatusMessage.isEmpty()) {
672 mStatusMessage = defaultSyncingMessage();
673 }
674
675 mStatusCode = 1;
676 break;
678 if (mStatusMessage.isEmpty()) {
679 mStatusMessage = defaultErrorMessage();
680 }
681
682 mStatusCode = 2;
683 break;
684
686 if (mStatusMessage.isEmpty()) {
687 mStatusMessage = defaultUnconfiguredMessage();
688 }
689
690 mStatusCode = 3;
691 break;
692
693 default:
694 Q_ASSERT(!"Unknown status passed");
695 break;
696 }
697}
698
699void AgentBasePrivate::slotPercent(int progress)
700{
701 mProgress = progress;
702}
703
704void AgentBasePrivate::slotWarning(const QString &message)
705{
706 mTracer->warning(QStringLiteral("AgentBase(%1)").arg(mId), message);
707}
708
709void AgentBasePrivate::slotError(const QString &message)
710{
711 mTracer->error(QStringLiteral("AgentBase(%1)").arg(mId), message);
712}
713
714void AgentBasePrivate::slotNetworkStatusChange(bool isOnline)
715{
716 Q_UNUSED(isOnline)
717 Q_Q(AgentBase);
718 q->setOnlineInternal(mDesiredOnlineState);
719}
720
721void AgentBasePrivate::slotResumedFromSuspend()
722{
723 if (mNeedsNetwork) {
724 slotNetworkStatusChange(QNetworkInformation::instance()->reachability() != QNetworkInformation::Reachability::Online);
725 }
726}
727
728void AgentBasePrivate::slotTemporaryOfflineTimeout()
729{
730 Q_Q(AgentBase);
731 q->setOnlineInternal(true);
732}
733
734QString AgentBasePrivate::dumpNotificationListToString() const
735{
736 return mChangeRecorder->dumpNotificationListToString();
737}
738
739void AgentBasePrivate::dumpMemoryInfo() const
740{
741 // Send it to stdout, so we can debug user problems.
742 // since you have to explicitly call this
743 // it won't flood users with release builds.
744 QTextStream stream(stdout);
745 stream << dumpMemoryInfoToString();
746}
747
748QString AgentBasePrivate::dumpMemoryInfoToString() const
749{
750 // man mallinfo for more info
751 QString str;
752#if defined __GLIBC__
753 struct mallinfo mi;
754 mi = mallinfo();
755 QTextStream stream(&str);
756 stream << "Total non-mmapped bytes (arena): " << mi.arena << '\n'
757 << "# of free chunks (ordblks): " << mi.ordblks << '\n'
758 << "# of free fastbin blocks (smblks>: " << mi.smblks << '\n'
759 << "# of mapped regions (hblks): " << mi.hblks << '\n'
760 << "Bytes in mapped regions (hblkhd): " << mi.hblkhd << '\n'
761 << "Max. total allocated space (usmblks): " << mi.usmblks << '\n'
762 << "Free bytes held in fastbins (fsmblks):" << mi.fsmblks << '\n'
763 << "Total allocated space (uordblks): " << mi.uordblks << '\n'
764 << "Total free space (fordblks): " << mi.fordblks << '\n'
765 << "Topmost releasable block (keepcost): " << mi.keepcost << '\n';
766#else
767 str = QLatin1StringView("mallinfo() not supported");
768#endif
769 return str;
770}
771
772AgentBase::AgentBase(const QString &id)
773 : d_ptr(new AgentBasePrivate(this))
774{
775 sAgentBase = this;
776 d_ptr->mId = id;
777 d_ptr->init();
778}
779
780AgentBase::AgentBase(AgentBasePrivate *d, const QString &id)
781 : d_ptr(d)
782{
783 sAgentBase = this;
784 d_ptr->mId = id;
785 d_ptr->init();
786}
787
788AgentBase::~AgentBase() = default;
789
790void AgentBase::debugAgent(int argc, char **argv)
791{
792 Q_UNUSED(argc)
793#ifdef Q_OS_WIN
794 if (qEnvironmentVariableIsSet("AKONADI_DEBUG_WAIT")) {
795 if (QByteArray(argv[0]).endsWith(QByteArray(qgetenv("AKONADI_DEBUG_WAIT") + QByteArrayLiteral(".exe")))) {
796 while (!IsDebuggerPresent()) {
797 std::this_thread::sleep_for(std::chrono::milliseconds(100));
798 }
799 DebugBreak();
800 }
801 }
802#else
803 Q_UNUSED(argv)
804#endif
805}
806
807QString AgentBase::parseArguments(int argc, char **argv)
808{
809 Q_UNUSED(argc)
810
811 QCommandLineOption identifierOption(QStringLiteral("identifier"), i18nc("@info:shell", "Agent identifier"), QStringLiteral("argument"));
812 QCommandLineParser parser;
813 parser.addOption(identifierOption);
814 parser.addHelpOption();
815 parser.addVersionOption();
816 parser.process(*qApp);
817 parser.setApplicationDescription(i18n("Akonadi Agent"));
818
819 if (!parser.isSet(identifierOption)) {
820 qCDebug(AKONADIAGENTBASE_LOG) << "Identifier argument missing";
821 exit(1);
822 }
823
824 const QString identifier = parser.value(identifierOption);
825 if (identifier.isEmpty()) {
826 qCDebug(AKONADIAGENTBASE_LOG) << "Identifier argument is empty";
827 exit(1);
828 }
829
831 QCoreApplication::setApplicationVersion(QStringLiteral(AKONADI_FULL_VERSION));
832
833 const QFileInfo fi(QString::fromLocal8Bit(argv[0]));
834 // strip off full path and possible .exe suffix
835 const QString catalog = fi.baseName();
836
837 auto translator = new QTranslator(qApp);
838 if (translator->load(catalog)) {
840 } else {
841 delete translator;
842 }
843
844 return identifier;
845}
846
847/// @endcond
848
850{
853 KLocalizedString::setApplicationDomain(QByteArrayLiteral("libakonadi6"));
854 KAboutData::setApplicationData(r.aboutData());
855
857
858 return qApp->exec();
859}
860
862{
863 Q_D(const AgentBase);
864
865 return d->mStatusCode;
866}
867
869{
870 Q_D(const AgentBase);
871
872 return d->mStatusMessage;
873}
874
876{
877 Q_D(const AgentBase);
878
879 return d->mProgress;
880}
881
883{
884 Q_D(const AgentBase);
885
886 return d->mProgressMessage;
887}
888
890{
891 Q_D(const AgentBase);
892
893 return d->mOnline;
894}
895
896void AgentBase::setNeedsNetwork(bool needsNetwork)
897{
898 Q_D(AgentBase);
899 if (d->mNeedsNetwork == needsNetwork) {
900 return;
901 }
902
903 d->mNeedsNetwork = needsNetwork;
904 QNetworkInformation::loadBackendByFeatures(QNetworkInformation::Feature::Reachability);
906 d->slotNetworkStatusChange(reachability == QNetworkInformation::Reachability::Online);
907 });
908}
909
910void AgentBase::setOnline(bool state)
911{
912 Q_D(AgentBase);
913
914 if (d->mPendingQuit) {
915 return;
916 }
917
918 d->mDesiredOnlineState = state;
919 if (!d->mSettings) {
921 d->mSettings->setValue(QLatin1StringView("Agent/Name"), agentName());
922 }
923 d->mSettings->setValue(QLatin1StringView("Agent/DesiredOnlineState"), state);
924 setOnlineInternal(state);
925}
926
927void AgentBase::setTemporaryOffline(int makeOnlineInSeconds)
928{
929 Q_D(AgentBase);
930
931 // if not currently online, avoid bringing it online after the timeout
932 if (!d->mOnline) {
933 return;
934 }
935
936 setOnlineInternal(false);
937
938 if (!d->mTemporaryOfflineTimer) {
939 d->mTemporaryOfflineTimer = new QTimer(d);
940 d->mTemporaryOfflineTimer->setSingleShot(true);
941 connect(d->mTemporaryOfflineTimer, &QTimer::timeout, d, &AgentBasePrivate::slotTemporaryOfflineTimeout);
942 }
943 d->mTemporaryOfflineTimer->setInterval(std::chrono::seconds{makeOnlineInSeconds});
944 d->mTemporaryOfflineTimer->start();
945}
946
947void AgentBase::setOnlineInternal(bool state)
948{
949 Q_D(AgentBase);
950 if (state && d->mNeedsNetwork) {
951 if (QNetworkInformation::instance()->reachability() != QNetworkInformation::Reachability::Online) {
952 // Don't go online if the resource needs network but there is none
953 state = false;
954 }
955 }
956 d->mOnline = state;
957
958 if (d->mTemporaryOfflineTimer) {
959 d->mTemporaryOfflineTimer->stop();
960 }
961
962 const QString newMessage = d->defaultReadyMessage();
963 if (d->mStatusMessage != newMessage && d->mStatusCode != AgentBase::Broken) {
964 Q_EMIT status(d->mStatusCode, newMessage);
965 }
966
967 doSetOnline(state);
968 Q_EMIT onlineChanged(state);
969}
970
971void AgentBase::doSetOnline(bool online)
972{
973 Q_UNUSED(online)
974}
975
976KAboutData AgentBase::aboutData() const
977{
978 // akonadi_google_resource_1 -> org.kde.akonadi_google_resource
979 const QString desktopEntry = QLatin1StringView("org.kde.") + qApp->applicationName().remove(QRegularExpression(QStringLiteral("_[0-9]+$")));
980
981 KAboutData data(qApp->applicationName(), agentName(), qApp->applicationVersion());
982 data.setDesktopFileName(desktopEntry);
983 return data;
984}
985
986void AgentBase::configure(WId windowId)
987{
988 Q_UNUSED(windowId)
989
990 // Fallback if the agent implements the new plugin-based configuration,
991 // but someone calls the deprecated configure() method
992 auto instance = Akonadi::AgentManager::self()->instance(identifier());
993 QPointer<AgentConfigurationDialog> dialog = new AgentConfigurationDialog(instance, nullptr);
994 if (dialog->exec()) {
996 } else {
998 }
999 delete dialog;
1000}
1001
1002#ifdef Q_OS_WIN // krazy:exclude=cpp
1003void AgentBase::configure(qlonglong windowId)
1004{
1005 configure(static_cast<WId>(windowId));
1006}
1007#endif
1008
1010{
1011 const bool registered = QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.freedesktop.akonaditray"));
1012 if (!registered) {
1013 return 0;
1014 }
1015
1016 QDBusInterface dbus(QStringLiteral("org.freedesktop.akonaditray"), QStringLiteral("/Actions"), QStringLiteral("org.freedesktop.Akonadi.Tray"));
1017 const QDBusMessage reply = dbus.call(QStringLiteral("getWinId"));
1018
1019 if (reply.type() == QDBusMessage::ErrorMessage) {
1020 return 0;
1021 }
1022
1023 const WId winid = static_cast<WId>(reply.arguments().at(0).toLongLong());
1024
1025 return winid;
1026}
1027
1028void AgentBase::quit()
1029{
1030 Q_D(AgentBase);
1031 aboutToQuit();
1032
1033 if (d->mSettings) {
1034 d->mChangeRecorder->setConfig(nullptr);
1035 d->mSettings->sync();
1036 delete d->mSettings;
1037 d->mSettings = nullptr;
1038 }
1039
1040 delete d->mEventLoopLocker;
1041 d->mEventLoopLocker = nullptr;
1042}
1043
1045{
1046 Q_D(AgentBase);
1047 d->mPendingQuit = true;
1048}
1049
1051{
1052 Q_D(AgentBase);
1053 // prevent the monitor from picking up deletion signals for our own data if we are a resource
1054 // and thus avoid that we kill our own data as last act before our own death
1055 d->mChangeRecorder->blockSignals(true);
1056
1057 aboutToQuit();
1058
1059 const QString fileName = d->mSettings->fileName();
1060
1061 /*
1062 * First destroy the settings object...
1063 */
1064 d->mChangeRecorder->setConfig(nullptr);
1065 delete d->mSettings;
1066 d->mSettings = nullptr;
1067
1068 /*
1069 * ... then remove the file from hd.
1070 */
1071 if (!QFile::remove(fileName)) {
1072 qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove " << fileName;
1073 }
1074
1075 /*
1076 * ... and remove the changes file from hd.
1077 */
1078 const QString changeDataFileName = fileName + QStringLiteral("_changes.dat");
1079 if (!QFile::remove(changeDataFileName)) {
1080 qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove " << changeDataFileName;
1081 }
1082
1083 /*
1084 * ... and also remove the agent configuration file if there is one.
1085 */
1087 if (!QFile::remove(configFile)) {
1088 qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove config file " << configFile;
1089 }
1090
1091 delete d->mEventLoopLocker;
1092 d->mEventLoopLocker = nullptr;
1093}
1094
1096{
1097 Q_D(AgentBase);
1098
1099 // TODO in theory we should re-connect change recorder signals here that we disconnected previously
1100 d->mObserver = observer;
1101
1102 const bool hasObserverV3 = (dynamic_cast<AgentBase::ObserverV3 *>(d->mObserver) != nullptr);
1103 const bool hasTagObserver = (dynamic_cast<AgentBase::TagObserver *>(d->mObserver) != nullptr);
1104
1105 disconnect(d->mChangeRecorder, &Monitor::tagAdded, d, &AgentBasePrivate::tagAdded);
1106 disconnect(d->mChangeRecorder, &Monitor::tagChanged, d, &AgentBasePrivate::tagChanged);
1107 disconnect(d->mChangeRecorder, &Monitor::tagRemoved, d, &AgentBasePrivate::tagRemoved);
1108 disconnect(d->mChangeRecorder, &Monitor::itemsTagsChanged, d, &AgentBasePrivate::itemsTagsChanged);
1109 disconnect(d->mChangeRecorder, &Monitor::itemsFlagsChanged, d, &AgentBasePrivate::itemsFlagsChanged);
1110 disconnect(d->mChangeRecorder, &Monitor::itemsMoved, d, &AgentBasePrivate::itemsMoved);
1111 disconnect(d->mChangeRecorder, &Monitor::itemsRemoved, d, &AgentBasePrivate::itemsRemoved);
1112 disconnect(d->mChangeRecorder, &Monitor::itemsLinked, d, &AgentBasePrivate::itemsLinked);
1113 disconnect(d->mChangeRecorder, &Monitor::itemsUnlinked, d, &AgentBasePrivate::itemsUnlinked);
1114 disconnect(d->mChangeRecorder, &Monitor::itemMoved, d, &AgentBasePrivate::itemMoved);
1115 disconnect(d->mChangeRecorder, &Monitor::itemRemoved, d, &AgentBasePrivate::itemRemoved);
1116 disconnect(d->mChangeRecorder, &Monitor::itemLinked, d, &AgentBasePrivate::itemLinked);
1117 disconnect(d->mChangeRecorder, &Monitor::itemUnlinked, d, &AgentBasePrivate::itemUnlinked);
1118
1119 if (hasTagObserver) {
1120 connect(d->mChangeRecorder, &Monitor::tagAdded, d, &AgentBasePrivate::tagAdded);
1121 connect(d->mChangeRecorder, &Monitor::tagChanged, d, &AgentBasePrivate::tagChanged);
1122 connect(d->mChangeRecorder, &Monitor::tagRemoved, d, &AgentBasePrivate::tagRemoved);
1123 connect(d->mChangeRecorder, &Monitor::itemsTagsChanged, d, &AgentBasePrivate::itemsTagsChanged);
1124
1125 // If the agent has a TagObserver, we assume it wants to receive everything tag-related.
1126 d->mChangeRecorder->itemFetchScope().setFetchTags(true);
1127 d->mChangeRecorder->tagFetchScope().setFetchAllAttributes(true);
1128 d->mChangeRecorder->tagFetchScope().setFetchRemoteId(true);
1129 }
1130
1131 if (hasObserverV3) {
1132 connect(d->mChangeRecorder, &Monitor::itemsFlagsChanged, d, &AgentBasePrivate::itemsFlagsChanged);
1133 connect(d->mChangeRecorder, &Monitor::itemsMoved, d, &AgentBasePrivate::itemsMoved);
1134 connect(d->mChangeRecorder, &Monitor::itemsRemoved, d, &AgentBasePrivate::itemsRemoved);
1135 connect(d->mChangeRecorder, &Monitor::itemsLinked, d, &AgentBasePrivate::itemsLinked);
1136 connect(d->mChangeRecorder, &Monitor::itemsUnlinked, d, &AgentBasePrivate::itemsUnlinked);
1137 } else {
1138 // V2 - don't connect these if we have V3
1139 connect(d->mChangeRecorder, &Monitor::itemMoved, d, &AgentBasePrivate::itemMoved);
1140 connect(d->mChangeRecorder, &Monitor::itemRemoved, d, &AgentBasePrivate::itemRemoved);
1141 connect(d->mChangeRecorder, &Monitor::itemLinked, d, &AgentBasePrivate::itemLinked);
1142 connect(d->mChangeRecorder, &Monitor::itemUnlinked, d, &AgentBasePrivate::itemUnlinked);
1143 }
1144}
1145
1147{
1148 return d_ptr->mId;
1149}
1150
1152{
1153 Q_D(AgentBase);
1154 if (name == d->mName) {
1155 return;
1156 }
1157
1158 // TODO: rename collection
1159 d->mName = name;
1160
1161 if (d->mName.isEmpty() || d->mName == d->mId) {
1162 d->mSettings->remove(QLatin1StringView("Resource/Name"));
1163 d->mSettings->remove(QLatin1StringView("Agent/Name"));
1164 } else {
1165 d->mSettings->setValue(QLatin1StringView("Agent/Name"), d->mName);
1166 }
1167
1168 d->mSettings->sync();
1169
1170 d->setProgramName();
1171
1172 Q_EMIT agentNameChanged(d->mName);
1173}
1174
1176{
1177 Q_D(const AgentBase);
1178 if (d->mName.isEmpty()) {
1179 return d->mId;
1180 } else {
1181 return d->mName;
1182 }
1183}
1184
1186{
1187 Q_D(AgentBase);
1188 if (activities == d->mActivities) {
1189 return;
1190 }
1191
1192 d->mActivities = activities;
1193 if (d->mActivities.isEmpty()) {
1194 d->mSettings->remove(QStringLiteral("Agent/Activities"));
1195 } else {
1196 d->mSettings->setValue(QStringLiteral("Agent/Activities"), d->mActivities);
1197 }
1198 Q_EMIT agentActivitiesChanged(d->mActivities);
1199}
1200
1202{
1203 Q_D(const AgentBase);
1204 return d->mActivities;
1205}
1206
1208{
1209 Q_D(const AgentBase);
1210 return d->mActivitiesEnabled;
1211}
1212
1214{
1215 Q_D(AgentBase);
1216 if (enabled == d->mActivitiesEnabled) {
1217 return;
1218 }
1219
1220 d->mActivitiesEnabled = enabled;
1221 d->mSettings->setValue(QStringLiteral("Agent/ActivitiesEnabled"), enabled);
1222 Q_EMIT agentActivitiesEnabledChanged(d->mActivitiesEnabled);
1223}
1224
1226{
1227 Q_D(AgentBase);
1228 d->changeProcessed();
1229}
1230
1232{
1233 return d_ptr->mChangeRecorder;
1234}
1235
1236KSharedConfigPtr AgentBase::config()
1237{
1239}
1240
1241void AgentBase::abort()
1242{
1244}
1245
1246void AgentBase::reconfigure()
1247{
1249}
1250
1251#include "moc_agentbase.cpp"
1252#include "moc_agentbase_p.cpp"
virtual void itemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection)
Reimplement to handle item unlinking.
virtual void itemMoved(const Akonadi::Item &item, const Akonadi::Collection &collectionSource, const Akonadi::Collection &collectionDestination)
Reimplement to handle item moves.
virtual void collectionChanged(const Akonadi::Collection &collection, const QSet< QByteArray > &changedAttributes)
Reimplement to handle changes to existing collections.
virtual void collectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &collectionSource, const Akonadi::Collection &collectionDestination)
Reimplement to handle collection moves.
virtual void itemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection)
Reimplement to handle item linking.
BC extension of ObserverV2 with support for batch operations.
Definition agentbase.h:302
virtual void itemsFlagsChanged(const Akonadi::Item::List &items, const QSet< QByteArray > &addedFlags, const QSet< QByteArray > &removedFlags)
Reimplement to handle changes in flags of existing items.
virtual void itemsLinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection)
Reimplement to handle batch notifications about items linking.
virtual void itemsRemoved(const Akonadi::Item::List &items)
Reimplement to handle batch notification about items deletion.
virtual void itemsUnlinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection)
Reimplement to handle batch notifications about items unlinking.
virtual void itemsMoved(const Akonadi::Item::List &items, const Akonadi::Collection &sourceCollection, const Akonadi::Collection &destinationCollection)
Reimplement to handle batch notification about items move.
The interface for reacting on monitored or replayed changes.
Definition agentbase.h:179
virtual ~Observer()
Destroys the observer instance.
Definition agentbase.cpp:63
virtual void collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
Reimplement to handle adding of new collections.
Definition agentbase.cpp:93
virtual void collectionChanged(const Akonadi::Collection &collection)
Reimplement to handle changes to existing collections.
virtual void collectionRemoved(const Akonadi::Collection &collection)
Reimplement to handle deletion of collections.
Observer()
Creates an observer instance.
Definition agentbase.cpp:59
virtual void itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection)
Reimplement to handle adding of new items.
Definition agentbase.cpp:67
virtual void itemChanged(const Akonadi::Item &item, const QSet< QByteArray > &partIdentifiers)
Reimplement to handle changes to existing items.
Definition agentbase.cpp:76
virtual void itemRemoved(const Akonadi::Item &item)
Reimplement to handle deletion of items.
Definition agentbase.cpp:85
The base class for all Akonadi agents and resources.
Definition agentbase.h:73
void agentActivitiesEnabledChanged(bool enabled)
This signal is emitted whenever the user has changed enabled activities.
void warning(const QString &message)
This signal shall be used to report warnings.
void changeProcessed()
Marks the current change as processes and replays the next change if change recording is enabled (noo...
virtual void doSetOnline(bool online)
This method is called whenever the online status has changed.
QStringList activities() const
Returns the activities of the agent.
void configurationDialogAccepted()
This signal is emitted whenever the user has accepted the configuration dialog.
void setTemporaryOffline(int makeOnlineInSeconds=300)
Sets the agent offline but will make it online again after a given time.
void setNeedsNetwork(bool needsNetwork)
Sets whether the agent needs network or not.
virtual int status() const
This method returns the current status code of the agent.
void onlineChanged(bool online)
Emitted when the online state changed.
KSharedConfigPtr config()
Returns the config object for this Agent.
virtual void cleanup()
This method is called when the agent is removed from the system, so it can do some cleanup stuff.
void reloadConfiguration()
Emitted if another application has changed the agent's configuration remotely and called AgentInstanc...
void agentActivitiesChanged(const QStringList &activities)
This signal is emitted whenever the user has changed activities.
void setActivities(const QStringList &activities)
This method is used to set the activities of the agent.
virtual QString statusMessage() const
This method returns an i18n'ed description of the current status code.
virtual QString progressMessage() const
This method returns an i18n'ed description of the current progress.
void setActivitiesEnabled(bool enabled)
This method is used to enabled the activities of the agent.
WId winIdForDialogs() const
This method returns the windows id, which should be used for dialogs.
void setAgentName(const QString &name)
This method is used to set the name of the agent.
~AgentBase() override
Destroys the agent base.
ChangeRecorder * changeRecorder() const
Returns the Akonadi::ChangeRecorder object used for monitoring.
virtual void aboutToQuit()
This method is called whenever the agent application is about to quit.
virtual void configure(WId windowId)
This method is called whenever the agent shall show its configuration dialog to the user.
QString agentName() const
Returns the name of the agent.
@ Running
The agent is working on something.
Definition agentbase.h:398
@ NotConfigured
The agent is lacking required configuration.
Definition agentbase.h:400
@ Broken
The agent encountered an error state.
Definition agentbase.h:399
@ Idle
The agent does currently nothing.
Definition agentbase.h:397
void percent(int progress)
This signal should be emitted whenever the progress of an action in the agent (e.g.
void abortRequested()
Emitted when another application has remotely asked the agent to abort its current operation.
bool isOnline() const
Returns whether the agent is currently online.
bool activitiesEnabled() const
Returns the activities status of the agent.
QString identifier() const
Returns the instance identifier of this agent.
virtual int progress() const
This method returns the current progress of the agent in percentage.
static int init(int argc, char **argv)
Use this method in the main function of your agent application to initialize your agent subclass.
Definition agentbase.h:428
void agentNameChanged(const QString &name)
This signal is emitted whenever the name of the agent has changed.
void setOnline(bool state)
Sets whether the agent shall be online or not.
void error(const QString &message)
This signal shall be used to report errors.
void configurationDialogRejected()
This signal is emitted whenever the user has rejected the configuration dialog.
AgentBase(const QString &id)
Creates an agent base.
void registerObserver(Observer *observer)
Registers the given observer for reacting on monitored or recorded changes.
AgentType type() const
Returns the agent type of this instance.
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...
QString name() const
Returns the i18n'ed name of the agent type.
Records and replays change notification.
void replayNext()
Replay the next change notification and erase the previous one from the record.
Represents a collection of PIM items.
Definition collection.h:62
Represents a PIM item stored in Akonadi storage.
Definition item.h:100
QList< Item > List
Describes a list of items.
Definition item.h:110
void itemsTagsChanged(const Akonadi::Item::List &items, const QSet< Akonadi::Tag > &addedTags, const QSet< Akonadi::Tag > &removedTags)
This signal is emitted if tags of monitored items have changed.
void itemChanged(const Akonadi::Item &item, const QSet< QByteArray > &partIdentifiers)
This signal is emitted if a monitored item has changed, e.g.
void collectionMoved(const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &destination)
This signals is emitted if a monitored collection has been moved.
void collectionUnsubscribed(const Akonadi::Collection &collection)
This signal is emitted if a user unsubscribes from a collection.
void itemLinked(const Akonadi::Item &item, const Akonadi::Collection &collection)
This signal is emitted if a reference to an item is added to a virtual collection.
void itemRemoved(const Akonadi::Item &item)
This signal is emitted if.
void tagRemoved(const Akonadi::Tag &tag)
This signal is emitted if a monitored tag is removed from the server storage.
void tagChanged(const Akonadi::Tag &tag)
This signal is emitted if a monitored tag is changed on the server.
void collectionSubscribed(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
This signal is emitted if a collection has been subscribed to by the user.
void tagAdded(const Akonadi::Tag &tag)
This signal is emitted if a tag has been added to Akonadi storage.
void itemsFlagsChanged(const Akonadi::Item::List &items, const QSet< QByteArray > &addedFlags, const QSet< QByteArray > &removedFlags)
This signal is emitted if flags of monitored items have changed.
void collectionRemoved(const Akonadi::Collection &collection)
This signal is emitted if a monitored collection has been removed from the Akonadi storage.
void itemsRemoved(const Akonadi::Item::List &items)
This signal is emitted if monitored items have been removed from Akonadi storage of items have been r...
void itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection)
This signal is emitted if an item has been added to a monitored collection in the Akonadi storage.
void itemsUnlinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection)
This signal is emitted if a reference to items is removed from a virtual collection.
void collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
This signal is emitted if a new collection has been added to a monitored collection in the Akonadi st...
void itemMoved(const Akonadi::Item &item, const Akonadi::Collection &collectionSource, const Akonadi::Collection &collectionDestination)
This signal is emitted if a monitored item has been moved between two collections.
void itemsLinked(const Akonadi::Item::List &items, const Akonadi::Collection &collection)
This signal is emitted if a reference to multiple items is added to a virtual collection.
void collectionChanged(const Akonadi::Collection &collection)
This signal is emitted if a monitored collection has been changed (properties or content).
void itemsMoved(const Akonadi::Item::List &items, const Akonadi::Collection &collectionSource, const Akonadi::Collection &collectionDestination)
This is signal is emitted when multiple monitored items have been moved between two collections.
void itemUnlinked(const Akonadi::Item &item, const Akonadi::Collection &collection)
This signal is emitted if a reference to an item is removed from a virtual collection.
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 QString addNamespace(const QString &string)
Adds the multi-instance namespace to string if required (with '_' as separator).
static QString agentConfigFilePath(const QString &identifier)
Returns absolute path to configuration file of an agent identified by given identifier.
static QString serviceName(ServiceType serviceType)
Returns the namespaced D-Bus service name for serviceType.
static Session * defaultSession()
Returns the default session for this thread.
An Akonadi Tag.
Definition tag.h:26
static void setApplicationData(const KAboutData &aboutData)
static void initTheme()
static void setApplicationDomain(const QByteArray &domain)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
Helper integration between Akonadi and Qt.
KCRASH_EXPORT void initialize()
void initStyle()
QCommandLineOption addHelpOption()
bool addOption(const QCommandLineOption &option)
QCommandLineOption addVersionOption()
bool isSet(const QCommandLineOption &option) const const
void process(const QCoreApplication &app)
void setApplicationDescription(const QString &description)
QString value(const QCommandLineOption &option) const const
void setApplicationName(const QString &application)
void setApplicationVersion(const QString &version)
bool installTranslator(QTranslator *translationFile)
QDBusMessage call(QDBus::CallMode mode, const QString &method, Args &&... args)
QDBusConnectionInterface * interface() const const
QDBusError lastError() const const
bool registerObject(const QString &path, QObject *object, RegisterOptions options)
QDBusConnection sessionBus()
QDBusReply< bool > isServiceRegistered(const QString &serviceName) const const
const QDBusMessage & message() const const
QString message() const const
QList< QVariant > arguments() const const
MessageType type() const const
bool remove()
void setApplicationDisplayName(const QString &name)
QNetworkInformation * instance()
bool loadBackendByFeatures(Features features)
void reachabilityChanged(Reachability newReachability)
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
QObject * parent() const const
QString writableLocation(StandardLocation type)
QString fromLocal8Bit(QByteArrayView str)
bool isEmpty() const const
void timeout()
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Jan 31 2025 12:07:52 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.