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 "agentmanager.h"
14#include "akonadifull-version.h"
15#include "changerecorder.h"
16#include "controladaptor.h"
17#include "itemfetchjob.h"
18#include "monitor_p.h"
19#include "private/standarddirs_p.h"
20#include "servermanager_p.h"
21#include "session.h"
22#include "session_p.h"
23#include "statusadaptor.h"
24
25#include "akonadiagentbase_debug.h"
26
27#include <KAboutData>
28#include <KCrash>
29#include <KLocalizedString>
30
31#include <QCommandLineParser>
32#include <QNetworkInformation>
33#include <QPointer>
34#include <QSettings>
35#include <QStandardPaths>
36#include <QTimer>
37
38#include <stdlib.h>
39#if defined __GLIBC__
40#include <malloc.h> // for dumping memory information
41#endif
42
43#ifdef Q_OS_WIN
44#include <Windows.h>
45#endif
46
47#include <chrono>
48#include <csignal>
49#include <sstream>
50#include <thread>
51
52using namespace Akonadi;
53using namespace std::chrono_literals;
54static AgentBase *sAgentBase = nullptr;
55
59
63
64void AgentBase::Observer::itemAdded(const Item &item, const Collection &collection)
65{
66 Q_UNUSED(item)
67 Q_UNUSED(collection)
68 if (sAgentBase) {
69 sAgentBase->d_ptr->changeProcessed();
70 }
71}
72
73void AgentBase::Observer::itemChanged(const Item &item, const QSet<QByteArray> &partIdentifiers)
74{
75 Q_UNUSED(item)
76 Q_UNUSED(partIdentifiers)
77 if (sAgentBase) {
78 sAgentBase->d_ptr->changeProcessed();
79 }
80}
81
83{
84 Q_UNUSED(item)
85 if (sAgentBase) {
86 sAgentBase->d_ptr->changeProcessed();
87 }
88}
89
91{
92 Q_UNUSED(collection)
93 Q_UNUSED(parent)
94 if (sAgentBase) {
95 sAgentBase->d_ptr->changeProcessed();
96 }
97}
98
100{
101 Q_UNUSED(collection)
102 if (sAgentBase) {
103 sAgentBase->d_ptr->changeProcessed();
104 }
105}
106
108{
109 Q_UNUSED(collection)
110 if (sAgentBase) {
111 sAgentBase->d_ptr->changeProcessed();
112 }
113}
114
116{
117 Q_UNUSED(item)
118 Q_UNUSED(source)
119 Q_UNUSED(dest)
120 if (sAgentBase) {
121 sAgentBase->d_ptr->changeProcessed();
122 }
123}
124
126{
127 Q_UNUSED(item)
128 Q_UNUSED(collection)
129 if (sAgentBase) {
130 // not implementation, let's disconnect the signal to enable optimizations in Monitor
131 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemLinked, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemLinked);
132 sAgentBase->d_ptr->changeProcessed();
133 }
134}
135
137{
138 Q_UNUSED(item)
139 Q_UNUSED(collection)
140 if (sAgentBase) {
141 // not implementation, let's disconnect the signal to enable optimizations in Monitor
142 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemUnlinked, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemUnlinked);
143 sAgentBase->d_ptr->changeProcessed();
144 }
145}
146
148{
149 Q_UNUSED(collection)
150 Q_UNUSED(source)
151 Q_UNUSED(dest)
152 if (sAgentBase) {
153 sAgentBase->d_ptr->changeProcessed();
154 }
155}
156
158{
159 Q_UNUSED(changedAttributes)
160 collectionChanged(collection);
161}
162
164{
165 Q_UNUSED(items)
166 Q_UNUSED(addedFlags)
167 Q_UNUSED(removedFlags)
168
169 if (sAgentBase) {
170 // not implementation, let's disconnect the signal to enable optimizations in Monitor
171 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsFlagsChanged, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsFlagsChanged);
172 sAgentBase->d_ptr->changeProcessed();
173 }
174}
175
176void AgentBase::ObserverV3::itemsMoved(const Akonadi::Item::List &items, const Collection &sourceCollection, const Collection &destinationCollection)
177{
178 Q_UNUSED(items)
179 Q_UNUSED(sourceCollection)
180 Q_UNUSED(destinationCollection)
181
182 if (sAgentBase) {
183 // not implementation, let's disconnect the signal to enable optimizations in Monitor
184 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsMoved, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsMoved);
185 sAgentBase->d_ptr->changeProcessed();
186 }
187}
188
190{
191 Q_UNUSED(items)
192
193 if (sAgentBase) {
194 // not implementation, let's disconnect the signal to enable optimizations in Monitor
195 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsRemoved, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsRemoved);
196 sAgentBase->d_ptr->changeProcessed();
197 }
198}
199
201{
202 Q_UNUSED(items)
203 Q_UNUSED(collection)
204
205 if (sAgentBase) {
206 // not implementation, let's disconnect the signal to enable optimizations in Monitor
207 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsLinked, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsLinked);
208 sAgentBase->d_ptr->changeProcessed();
209 }
210}
211
213{
214 Q_UNUSED(items)
215 Q_UNUSED(collection)
216
217 if (sAgentBase) {
218 // not implementation, let's disconnect the signal to enable optimizations in Monitor
219 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsUnlinked, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsUnlinked);
220 sAgentBase->d_ptr->changeProcessed();
221 }
222}
224AgentBase::TagObserver::TagObserver() = default;
225
226AgentBase::TagObserver::~TagObserver() = default;
227
228void AgentBase::TagObserver::tagAdded(const Akonadi::Tag &tag)
229{
230 Q_UNUSED(tag)
231 if (sAgentBase) {
232 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::tagAdded, sAgentBase->d_ptr.get(), &AgentBasePrivate::tagAdded);
233 sAgentBase->d_ptr->changeProcessed();
234 }
235}
236
237void AgentBase::TagObserver::tagChanged(const Akonadi::Tag &tag)
238{
239 Q_UNUSED(tag)
240 if (sAgentBase) {
241 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::tagChanged, sAgentBase->d_ptr.get(), &AgentBasePrivate::tagChanged);
242 sAgentBase->d_ptr->changeProcessed();
243 }
244}
245
246void AgentBase::TagObserver::tagRemoved(const Akonadi::Tag &tag)
247{
248 Q_UNUSED(tag)
249 if (sAgentBase) {
250 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::tagRemoved, sAgentBase->d_ptr.get(), &AgentBasePrivate::tagRemoved);
251 sAgentBase->d_ptr->changeProcessed();
252 }
253}
254
255void AgentBase::TagObserver::itemsTagsChanged(const Akonadi::Item::List &items, const QSet<Akonadi::Tag> &addedTags, const QSet<Akonadi::Tag> &removedTags)
256{
257 Q_UNUSED(items)
258 Q_UNUSED(addedTags)
259 Q_UNUSED(removedTags)
260
261 if (sAgentBase) {
262 QObject::disconnect(sAgentBase->changeRecorder(), &Monitor::itemsTagsChanged, sAgentBase->d_ptr.get(), &AgentBasePrivate::itemsTagsChanged);
263 sAgentBase->d_ptr->changeProcessed();
264 }
265}
266/// @cond PRIVATE
267
268AgentBasePrivate::AgentBasePrivate(AgentBase *parent)
269 : q_ptr(parent)
270 , mStatusCode(AgentBase::Idle)
271 , mProgress(0)
272 , mNeedsNetwork(false)
273 , mOnline(false)
274 , mDesiredOnlineState(false)
275 , mPendingQuit(false)
276 , mSettings(nullptr)
277 , mChangeRecorder(nullptr)
278 , mTracer(nullptr)
279 , mObserver(nullptr)
280 , mPowerInterface(nullptr)
281 , mTemporaryOfflineTimer(nullptr)
282 , mEventLoopLocker(nullptr)
283{
284 Internal::setClientType(Internal::Agent);
285}
286
287AgentBasePrivate::~AgentBasePrivate()
288{
289 mChangeRecorder->setConfig(nullptr);
290 delete mSettings;
291}
292
293void AgentBasePrivate::init()
294{
295 Q_Q(AgentBase);
296 /**
297 * Create a default session for this process.
298 */
299 SessionPrivate::createDefaultSession(mId.toLatin1());
300
301 mTracer =
302 new org::freedesktop::Akonadi::Tracer(ServerManager::serviceName(ServerManager::Server), QStringLiteral("/tracing"), QDBusConnection::sessionBus(), q);
303
304 new Akonadi__ControlAdaptor(q);
305 new Akonadi__StatusAdaptor(q);
306 if (!QDBusConnection::sessionBus().registerObject(QStringLiteral("/"), q, QDBusConnection::ExportAdaptors)) {
307 Q_EMIT q->error(i18n("Unable to register object at dbus: %1", QDBusConnection::sessionBus().lastError().message()));
308 }
309
310 mSettings = new QSettings(ServerManager::agentConfigFilePath(mId), QSettings::IniFormat);
311
312 mChangeRecorder = new ChangeRecorder(q);
313 mChangeRecorder->setObjectName(QLatin1StringView("AgentBaseChangeRecorder"));
314 mChangeRecorder->ignoreSession(Session::defaultSession());
315 mChangeRecorder->itemFetchScope().setCacheOnly(true);
316 mChangeRecorder->setConfig(mSettings);
317
318 mDesiredOnlineState = mSettings->value(QLatin1StringView("Agent/DesiredOnlineState"), true).toBool();
319 mOnline = mDesiredOnlineState;
320
321 // reinitialize the status message now that online state is available
322 mStatusMessage = defaultReadyMessage();
323
324 mName = mSettings->value(QLatin1StringView("Agent/Name")).toString();
325 if (mName.isEmpty()) {
326 mName = mSettings->value(QLatin1StringView("Resource/Name")).toString();
327 if (!mName.isEmpty()) {
328 mSettings->remove(QLatin1StringView("Resource/Name"));
329 mSettings->setValue(QLatin1StringView("Agent/Name"), mName);
330 }
331 }
332
333 mActivities = mSettings->value(QLatin1StringView("Agent/Activities")).toStringList();
334 mActivitiesEnabled = mSettings->value(QLatin1StringView("Agent/ActivitiesEnabled"), false).toBool();
335 connect(mChangeRecorder, &Monitor::itemAdded, this, &AgentBasePrivate::itemAdded);
336 connect(mChangeRecorder, &Monitor::itemChanged, this, &AgentBasePrivate::itemChanged);
337 connect(mChangeRecorder, &Monitor::collectionAdded, this, &AgentBasePrivate::collectionAdded);
338 connect(mChangeRecorder,
339 qOverload<const Collection &>(&ChangeRecorder::collectionChanged),
340 this,
341 qOverload<const Collection &>(&AgentBasePrivate::collectionChanged));
342 connect(mChangeRecorder,
343 qOverload<const Collection &, const QSet<QByteArray> &>(&ChangeRecorder::collectionChanged),
344 this,
345 qOverload<const Collection &, const QSet<QByteArray> &>(&AgentBasePrivate::collectionChanged));
346 connect(mChangeRecorder, &Monitor::collectionMoved, this, &AgentBasePrivate::collectionMoved);
347 connect(mChangeRecorder, &Monitor::collectionRemoved, this, &AgentBasePrivate::collectionRemoved);
348 connect(mChangeRecorder, &Monitor::collectionSubscribed, this, &AgentBasePrivate::collectionSubscribed);
349 connect(mChangeRecorder, &Monitor::collectionUnsubscribed, this, &AgentBasePrivate::collectionUnsubscribed);
350
351 connect(q, qOverload<int, const QString &>(&AgentBase::status), this, &AgentBasePrivate::slotStatus);
352 connect(q, &AgentBase::percent, this, &AgentBasePrivate::slotPercent);
353 connect(q, &AgentBase::warning, this, &AgentBasePrivate::slotWarning);
354 connect(q, &AgentBase::error, this, &AgentBasePrivate::slotError);
355
356 mPowerInterface = new QDBusInterface(QStringLiteral("org.kde.Solid.PowerManagement"),
357 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/SuspendSession"),
358 QStringLiteral("org.kde.Solid.PowerManagement.Actions.SuspendSession"),
360 this);
361 if (mPowerInterface->isValid()) {
362 connect(mPowerInterface, SIGNAL(resumingFromSuspend()), this, SLOT(slotResumedFromSuspend())); // clazy:exclude=old-style-connect
363 } else {
364 delete mPowerInterface;
365 mPowerInterface = nullptr;
366 }
367
368 // Use reference counting to allow agents to finish internal jobs when the
369 // agent is stopped.
370 mEventLoopLocker = new QEventLoopLocker();
371
372 mResourceTypeName = AgentManager::self()->instance(mId).type().name();
373 setProgramName();
374
375 QTimer::singleShot(0s, q, [this] {
376 delayedInit();
377 });
378}
379
380void AgentBasePrivate::delayedInit()
381{
382 Q_Q(AgentBase);
383
384 const QString serviceId = ServerManager::agentServiceName(ServerManager::Agent, mId);
385 if (!QDBusConnection::sessionBus().registerService(serviceId)) {
386 qCCritical(AKONADIAGENTBASE_LOG) << "Unable to register service" << serviceId << "at dbus:" << QDBusConnection::sessionBus().lastError().message();
387 }
388 q->setOnlineInternal(mDesiredOnlineState);
389
391}
392
393void AgentBasePrivate::setProgramName()
394{
395 // ugly, really ugly, if you find another solution, change it and blame me for this code (Andras)
396 mProgramName = mResourceTypeName;
397 if (!mName.isEmpty()) {
398 mProgramName = i18nc("Name and type of Akonadi resource", "%1 of type %2", mName, mResourceTypeName);
399 }
400}
401
402QString AgentBase::programName() const
403{
404 return d_ptr->mProgramName;
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#if defined(__GLIBC_PREREQ) && __GNUC_PREREQ(2, 33)
754 struct mallinfo2 mi;
755 mi = mallinfo2();
756#else
757 struct mallinfo mi;
758 mi = mallinfo();
759#endif
760 QTextStream stream(&str);
761 stream << "Total non-mmapped bytes (arena): " << mi.arena << '\n'
762 << "# of free chunks (ordblks): " << mi.ordblks << '\n'
763 << "# of free fastbin blocks (smblks>: " << mi.smblks << '\n'
764 << "# of mapped regions (hblks): " << mi.hblks << '\n'
765 << "Bytes in mapped regions (hblkhd): " << mi.hblkhd << '\n'
766 << "Max. total allocated space (usmblks): " << mi.usmblks << '\n'
767 << "Free bytes held in fastbins (fsmblks):" << mi.fsmblks << '\n'
768 << "Total allocated space (uordblks): " << mi.uordblks << '\n'
769 << "Total free space (fordblks): " << mi.fordblks << '\n'
770 << "Topmost releasable block (keepcost): " << mi.keepcost << '\n';
771#else
772 str = QLatin1StringView("mallinfo() not supported");
773#endif
774 return str;
775}
776
777AgentBase::AgentBase(const QString &id)
778 : d_ptr(new AgentBasePrivate(this))
779{
780 sAgentBase = this;
781 d_ptr->mId = id;
782 d_ptr->init();
783}
784
785AgentBase::AgentBase(AgentBasePrivate *d, const QString &id)
786 : d_ptr(d)
787{
788 sAgentBase = this;
789 d_ptr->mId = id;
790 d_ptr->init();
791}
792
793AgentBase::~AgentBase() = default;
794
795void AgentBase::debugAgent(int argc, char **argv)
796{
797 Q_UNUSED(argc)
798#ifdef Q_OS_WIN
799 if (qEnvironmentVariableIsSet("AKONADI_DEBUG_WAIT")) {
800 if (QByteArray(argv[0]).endsWith(QByteArray(qgetenv("AKONADI_DEBUG_WAIT") + QByteArrayLiteral(".exe")))) {
801 while (!IsDebuggerPresent()) {
802 std::this_thread::sleep_for(std::chrono::milliseconds(100));
803 }
804 DebugBreak();
805 }
806 }
807#else
808 Q_UNUSED(argv)
809#endif
810}
811
812QString AgentBase::parseArguments(int argc, char **argv)
813{
814 Q_UNUSED(argc)
815
816 QCommandLineOption identifierOption(QStringLiteral("identifier"), i18nc("@info:shell", "Agent identifier"), QStringLiteral("argument"));
817 QCommandLineParser parser;
818 parser.addOption(identifierOption);
819 parser.addHelpOption();
820 parser.addVersionOption();
821 parser.process(*qApp);
822 parser.setApplicationDescription(i18n("Akonadi Agent"));
823
824 if (!parser.isSet(identifierOption)) {
825 qCDebug(AKONADIAGENTBASE_LOG) << "Identifier argument missing";
826 exit(1);
827 }
828
829 const QString identifier = parser.value(identifierOption);
830 if (identifier.isEmpty()) {
831 qCDebug(AKONADIAGENTBASE_LOG) << "Identifier argument is empty";
832 exit(1);
833 }
834
836 QCoreApplication::setApplicationVersion(QStringLiteral(AKONADI_FULL_VERSION));
837
838 const QFileInfo fi(QString::fromLocal8Bit(argv[0]));
839 // strip off full path and possible .exe suffix
840 const QString catalog = fi.baseName();
841
842 auto translator = new QTranslator(qApp);
843 if (translator->load(catalog)) {
845 } else {
846 delete translator;
847 }
848
849 return identifier;
850}
851
852/// @endcond
853
854int AgentBase::init(AgentBase &r)
855{
856 KLocalizedString::setApplicationDomain(QByteArrayLiteral("libakonadi6"));
857 KAboutData::setApplicationData(r.aboutData());
858
860
861 return qApp->exec();
862}
863
865{
866 Q_D(const AgentBase);
867
868 return d->mStatusCode;
869}
870
872{
873 Q_D(const AgentBase);
874
875 return d->mStatusMessage;
876}
877
879{
880 Q_D(const AgentBase);
881
882 return d->mProgress;
883}
884
886{
887 Q_D(const AgentBase);
888
889 return d->mProgressMessage;
890}
891
893{
894 Q_D(const AgentBase);
895
896 return d->mOnline;
897}
898
899void AgentBase::setNeedsNetwork(bool needsNetwork)
900{
901 Q_D(AgentBase);
902 if (d->mNeedsNetwork == needsNetwork) {
903 return;
904 }
905
906 d->mNeedsNetwork = needsNetwork;
907 QNetworkInformation::loadBackendByFeatures(QNetworkInformation::Feature::Reachability);
909 d->slotNetworkStatusChange(reachability == QNetworkInformation::Reachability::Online);
910 });
911}
912
913void AgentBase::setOnline(bool state)
914{
915 Q_D(AgentBase);
916
917 if (d->mPendingQuit) {
918 return;
919 }
920
921 d->mDesiredOnlineState = state;
922 if (!d->mSettings) {
924 d->mSettings->setValue(QLatin1StringView("Agent/Name"), agentName());
925 }
926 d->mSettings->setValue(QLatin1StringView("Agent/DesiredOnlineState"), state);
927 setOnlineInternal(state);
928}
929
930void AgentBase::setTemporaryOffline(int makeOnlineInSeconds)
931{
932 Q_D(AgentBase);
933
934 // if not currently online, avoid bringing it online after the timeout
935 if (!d->mOnline) {
936 return;
937 }
938
939 setOnlineInternal(false);
940
941 if (!d->mTemporaryOfflineTimer) {
942 d->mTemporaryOfflineTimer = new QTimer(d);
943 d->mTemporaryOfflineTimer->setSingleShot(true);
944 connect(d->mTemporaryOfflineTimer, &QTimer::timeout, d, &AgentBasePrivate::slotTemporaryOfflineTimeout);
945 }
946 d->mTemporaryOfflineTimer->setInterval(std::chrono::seconds{makeOnlineInSeconds});
947 d->mTemporaryOfflineTimer->start();
948}
949
950void AgentBase::setOnlineInternal(bool state)
951{
952 Q_D(AgentBase);
953 if (state && d->mNeedsNetwork) {
954 if (QNetworkInformation::instance()->reachability() != QNetworkInformation::Reachability::Online) {
955 // Don't go online if the resource needs network but there is none
956 state = false;
957 }
958 }
959 d->mOnline = state;
960
961 if (d->mTemporaryOfflineTimer) {
962 d->mTemporaryOfflineTimer->stop();
963 }
964
965 const QString newMessage = d->defaultReadyMessage();
966 if (d->mStatusMessage != newMessage && d->mStatusCode != AgentBase::Broken) {
967 Q_EMIT status(d->mStatusCode, newMessage);
968 }
969
970 doSetOnline(state);
971 Q_EMIT onlineChanged(state);
972}
973
974void AgentBase::doSetOnline(bool online)
975{
976 Q_UNUSED(online)
977}
978
979KAboutData AgentBase::aboutData() const
980{
981 // akonadi_google_resource_1 -> org.kde.akonadi_google_resource
982 const QString desktopEntry = QLatin1StringView("org.kde.") + qApp->applicationName().remove(QRegularExpression(QStringLiteral("_[0-9]+$")));
983
984 KAboutData data(qApp->applicationName(), agentName(), qApp->applicationVersion());
985 data.setDesktopFileName(desktopEntry);
986 return data;
987}
988
989void AgentBase::configure(WId windowId)
990{
991 Q_UNUSED(windowId)
992 qCWarning(AKONADIAGENTBASE_LOG) << "Calling AgentBase::configure instead of using an AgentConfigurationDialog is not supported anymore.";
993}
994
995#ifdef Q_OS_WIN
996void AgentBase::configure(qlonglong windowId)
997{
998 configure(static_cast<WId>(windowId));
999}
1000#endif
1001
1003{
1004 const bool registered = QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.freedesktop.akonaditray"));
1005 if (!registered) {
1006 return 0;
1007 }
1008
1009 QDBusInterface dbus(QStringLiteral("org.freedesktop.akonaditray"), QStringLiteral("/Actions"), QStringLiteral("org.freedesktop.Akonadi.Tray"));
1010 const QDBusMessage reply = dbus.call(QStringLiteral("getWinId"));
1011
1012 if (reply.type() == QDBusMessage::ErrorMessage) {
1013 return 0;
1014 }
1015
1016 const WId winid = static_cast<WId>(reply.arguments().at(0).toLongLong());
1017
1018 return winid;
1019}
1020
1021void AgentBase::quit()
1022{
1023 Q_D(AgentBase);
1024 aboutToQuit();
1025
1026 if (d->mSettings) {
1027 d->mChangeRecorder->setConfig(nullptr);
1028 d->mSettings->sync();
1029 delete d->mSettings;
1030 d->mSettings = nullptr;
1031 }
1032
1033 delete d->mEventLoopLocker;
1034 d->mEventLoopLocker = nullptr;
1035}
1036
1038{
1039 Q_D(AgentBase);
1040 d->mPendingQuit = true;
1041}
1042
1044{
1045 Q_D(AgentBase);
1046 // prevent the monitor from picking up deletion signals for our own data if we are a resource
1047 // and thus avoid that we kill our own data as last act before our own death
1048 d->mChangeRecorder->blockSignals(true);
1049
1050 aboutToQuit();
1051
1052 const QString fileName = d->mSettings->fileName();
1053
1054 /*
1055 * First destroy the settings object...
1056 */
1057 d->mChangeRecorder->setConfig(nullptr);
1058 delete d->mSettings;
1059 d->mSettings = nullptr;
1060
1061 /*
1062 * ... then remove the file from hd.
1063 */
1064 if (!QFile::remove(fileName)) {
1065 qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove " << fileName;
1066 }
1067
1068 /*
1069 * ... and remove the changes file from hd.
1070 */
1071 const QString changeDataFileName = fileName + QStringLiteral("_changes.dat");
1072 if (!QFile::remove(changeDataFileName)) {
1073 qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove " << changeDataFileName;
1074 }
1075
1076 /*
1077 * ... and also remove the agent configuration file if there is one.
1078 */
1080 if (!QFile::remove(configFile)) {
1081 qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove config file " << configFile;
1082 }
1083
1084 delete d->mEventLoopLocker;
1085 d->mEventLoopLocker = nullptr;
1086}
1087
1089{
1090 Q_D(AgentBase);
1091
1092 // TODO in theory we should re-connect change recorder signals here that we disconnected previously
1093 d->mObserver = observer;
1094
1095 const bool hasObserverV3 = (dynamic_cast<AgentBase::ObserverV3 *>(d->mObserver) != nullptr);
1096 const bool hasTagObserver = (dynamic_cast<AgentBase::TagObserver *>(d->mObserver) != nullptr);
1097
1098 disconnect(d->mChangeRecorder, &Monitor::tagAdded, d, &AgentBasePrivate::tagAdded);
1099 disconnect(d->mChangeRecorder, &Monitor::tagChanged, d, &AgentBasePrivate::tagChanged);
1100 disconnect(d->mChangeRecorder, &Monitor::tagRemoved, d, &AgentBasePrivate::tagRemoved);
1101 disconnect(d->mChangeRecorder, &Monitor::itemsTagsChanged, d, &AgentBasePrivate::itemsTagsChanged);
1102 disconnect(d->mChangeRecorder, &Monitor::itemsFlagsChanged, d, &AgentBasePrivate::itemsFlagsChanged);
1103 disconnect(d->mChangeRecorder, &Monitor::itemsMoved, d, &AgentBasePrivate::itemsMoved);
1104 disconnect(d->mChangeRecorder, &Monitor::itemsRemoved, d, &AgentBasePrivate::itemsRemoved);
1105 disconnect(d->mChangeRecorder, &Monitor::itemsLinked, d, &AgentBasePrivate::itemsLinked);
1106 disconnect(d->mChangeRecorder, &Monitor::itemsUnlinked, d, &AgentBasePrivate::itemsUnlinked);
1107 disconnect(d->mChangeRecorder, &Monitor::itemMoved, d, &AgentBasePrivate::itemMoved);
1108 disconnect(d->mChangeRecorder, &Monitor::itemRemoved, d, &AgentBasePrivate::itemRemoved);
1109 disconnect(d->mChangeRecorder, &Monitor::itemLinked, d, &AgentBasePrivate::itemLinked);
1110 disconnect(d->mChangeRecorder, &Monitor::itemUnlinked, d, &AgentBasePrivate::itemUnlinked);
1111
1112 if (hasTagObserver) {
1113 connect(d->mChangeRecorder, &Monitor::tagAdded, d, &AgentBasePrivate::tagAdded);
1114 connect(d->mChangeRecorder, &Monitor::tagChanged, d, &AgentBasePrivate::tagChanged);
1115 connect(d->mChangeRecorder, &Monitor::tagRemoved, d, &AgentBasePrivate::tagRemoved);
1116 connect(d->mChangeRecorder, &Monitor::itemsTagsChanged, d, &AgentBasePrivate::itemsTagsChanged);
1117
1118 // If the agent has a TagObserver, we assume it wants to receive everything tag-related.
1119 d->mChangeRecorder->itemFetchScope().setFetchTags(true);
1120 d->mChangeRecorder->tagFetchScope().setFetchAllAttributes(true);
1121 d->mChangeRecorder->tagFetchScope().setFetchRemoteId(true);
1122 }
1123
1124 if (hasObserverV3) {
1125 connect(d->mChangeRecorder, &Monitor::itemsFlagsChanged, d, &AgentBasePrivate::itemsFlagsChanged);
1126 connect(d->mChangeRecorder, &Monitor::itemsMoved, d, &AgentBasePrivate::itemsMoved);
1127 connect(d->mChangeRecorder, &Monitor::itemsRemoved, d, &AgentBasePrivate::itemsRemoved);
1128 connect(d->mChangeRecorder, &Monitor::itemsLinked, d, &AgentBasePrivate::itemsLinked);
1129 connect(d->mChangeRecorder, &Monitor::itemsUnlinked, d, &AgentBasePrivate::itemsUnlinked);
1130 } else {
1131 // V2 - don't connect these if we have V3
1132 connect(d->mChangeRecorder, &Monitor::itemMoved, d, &AgentBasePrivate::itemMoved);
1133 connect(d->mChangeRecorder, &Monitor::itemRemoved, d, &AgentBasePrivate::itemRemoved);
1134 connect(d->mChangeRecorder, &Monitor::itemLinked, d, &AgentBasePrivate::itemLinked);
1135 connect(d->mChangeRecorder, &Monitor::itemUnlinked, d, &AgentBasePrivate::itemUnlinked);
1136 }
1137}
1138
1140{
1141 return d_ptr->mId;
1142}
1143
1145{
1146 Q_D(AgentBase);
1147 if (name == d->mName) {
1148 return;
1149 }
1150
1151 // TODO: rename collection
1152 d->mName = name;
1153
1154 if (d->mName.isEmpty() || d->mName == d->mId) {
1155 d->mSettings->remove(QLatin1StringView("Resource/Name"));
1156 d->mSettings->remove(QLatin1StringView("Agent/Name"));
1157 } else {
1158 d->mSettings->setValue(QLatin1StringView("Agent/Name"), d->mName);
1159 }
1160
1161 d->mSettings->sync();
1162
1163 d->setProgramName();
1164
1165 Q_EMIT agentNameChanged(d->mName);
1166}
1167
1169{
1170 Q_D(const AgentBase);
1171 if (d->mName.isEmpty()) {
1172 return d->mId;
1173 } else {
1174 return d->mName;
1175 }
1176}
1177
1179{
1180 Q_D(AgentBase);
1181 if (activities == d->mActivities) {
1182 return;
1183 }
1184
1185 d->mActivities = activities;
1186 if (d->mActivities.isEmpty()) {
1187 d->mSettings->remove(QStringLiteral("Agent/Activities"));
1188 } else {
1189 d->mSettings->setValue(QStringLiteral("Agent/Activities"), d->mActivities);
1190 }
1191 Q_EMIT agentActivitiesChanged(d->mActivities);
1192}
1193
1195{
1196 Q_D(const AgentBase);
1197 return d->mActivities;
1198}
1199
1201{
1202 Q_D(const AgentBase);
1203 return d->mActivitiesEnabled;
1204}
1205
1207{
1208 Q_D(AgentBase);
1209 if (enabled == d->mActivitiesEnabled) {
1210 return;
1211 }
1212
1213 d->mActivitiesEnabled = enabled;
1214 d->mSettings->setValue(QStringLiteral("Agent/ActivitiesEnabled"), enabled);
1215 Q_EMIT agentActivitiesEnabledChanged(d->mActivitiesEnabled);
1216}
1217
1219{
1220 Q_D(AgentBase);
1221 d->changeProcessed();
1222}
1223
1225{
1226 return d_ptr->mChangeRecorder;
1227}
1228
1229KSharedConfigPtr AgentBase::config()
1230{
1232}
1233
1234void AgentBase::abort()
1235{
1237}
1238
1239void AgentBase::reconfigure()
1240{
1242}
1243
1244#include "moc_agentbase.cpp"
1245#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:303
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:180
virtual ~Observer()
Destroys the observer instance.
Definition agentbase.cpp:60
virtual void collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
Reimplement to handle adding of new collections.
Definition agentbase.cpp:90
virtual void collectionChanged(const Akonadi::Collection &collection)
Reimplement to handle changes to existing collections.
Definition agentbase.cpp:99
virtual void collectionRemoved(const Akonadi::Collection &collection)
Reimplement to handle deletion of collections.
Observer()
Creates an observer instance.
Definition agentbase.cpp:56
virtual void itemAdded(const Akonadi::Item &item, const Akonadi::Collection &collection)
Reimplement to handle adding of new items.
Definition agentbase.cpp:64
virtual void itemChanged(const Akonadi::Item &item, const QSet< QByteArray > &partIdentifiers)
Reimplement to handle changes to existing items.
Definition agentbase.cpp:73
virtual void itemRemoved(const Akonadi::Item &item)
Reimplement to handle deletion of items.
Definition agentbase.cpp:82
The base class for all Akonadi agents and resources.
Definition agentbase.h:74
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 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.
QString programName() const
Get the application display name.
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:399
@ NotConfigured
The agent is lacking required configuration.
Definition agentbase.h:401
@ Broken
The agent encountered an error state.
Definition agentbase.h:400
@ Idle
The agent does currently nothing.
Definition agentbase.h:398
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.
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.
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 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()
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()
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 May 2 2025 11:53:08 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.