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 <QTimer>
36
37#include <QStandardPaths>
38#include <signal.h>
39#include <stdlib.h>
40#include <strstream>
41#if defined __GLIBC__
42#include <malloc.h> // for dumping memory information
43#endif
44
45#ifdef Q_OS_WIN
46#include <Windows.h>
47#endif
48
49#include <chrono>
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 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
849int AgentBase::init(AgentBase &r)
850{
851 KLocalizedString::setApplicationDomain(QByteArrayLiteral("libakonadi6"));
852 KAboutData::setApplicationData(r.aboutData());
853
855
856 return qApp->exec();
857}
858
860{
861 Q_D(const AgentBase);
862
863 return d->mStatusCode;
864}
865
867{
868 Q_D(const AgentBase);
869
870 return d->mStatusMessage;
871}
872
874{
875 Q_D(const AgentBase);
876
877 return d->mProgress;
878}
879
881{
882 Q_D(const AgentBase);
883
884 return d->mProgressMessage;
885}
886
888{
889 Q_D(const AgentBase);
890
891 return d->mOnline;
892}
893
894void AgentBase::setNeedsNetwork(bool needsNetwork)
895{
896 Q_D(AgentBase);
897 if (d->mNeedsNetwork == needsNetwork) {
898 return;
899 }
900
901 d->mNeedsNetwork = needsNetwork;
902 QNetworkInformation::loadBackendByFeatures(QNetworkInformation::Feature::Reachability);
904 d->slotNetworkStatusChange(reachability == QNetworkInformation::Reachability::Online);
905 });
906}
907
908void AgentBase::setOnline(bool state)
909{
910 Q_D(AgentBase);
911
912 if (d->mPendingQuit) {
913 return;
914 }
915
916 d->mDesiredOnlineState = state;
917 if (!d->mSettings) {
919 d->mSettings->setValue(QLatin1StringView("Agent/Name"), agentName());
920 }
921 d->mSettings->setValue(QLatin1StringView("Agent/DesiredOnlineState"), state);
922 setOnlineInternal(state);
923}
924
925void AgentBase::setTemporaryOffline(int makeOnlineInSeconds)
926{
927 Q_D(AgentBase);
928
929 // if not currently online, avoid bringing it online after the timeout
930 if (!d->mOnline) {
931 return;
932 }
933
934 setOnlineInternal(false);
935
936 if (!d->mTemporaryOfflineTimer) {
937 d->mTemporaryOfflineTimer = new QTimer(d);
938 d->mTemporaryOfflineTimer->setSingleShot(true);
939 connect(d->mTemporaryOfflineTimer, &QTimer::timeout, d, &AgentBasePrivate::slotTemporaryOfflineTimeout);
940 }
941 d->mTemporaryOfflineTimer->setInterval(std::chrono::seconds{makeOnlineInSeconds});
942 d->mTemporaryOfflineTimer->start();
943}
944
945void AgentBase::setOnlineInternal(bool state)
946{
947 Q_D(AgentBase);
948 if (state && d->mNeedsNetwork) {
949 if (QNetworkInformation::instance()->reachability() != QNetworkInformation::Reachability::Online) {
950 // Don't go online if the resource needs network but there is none
951 state = false;
952 }
953 }
954 d->mOnline = state;
955
956 if (d->mTemporaryOfflineTimer) {
957 d->mTemporaryOfflineTimer->stop();
958 }
959
960 const QString newMessage = d->defaultReadyMessage();
961 if (d->mStatusMessage != newMessage && d->mStatusCode != AgentBase::Broken) {
962 Q_EMIT status(d->mStatusCode, newMessage);
963 }
964
965 doSetOnline(state);
966 Q_EMIT onlineChanged(state);
967}
968
969void AgentBase::doSetOnline(bool online)
970{
971 Q_UNUSED(online)
972}
973
974KAboutData AgentBase::aboutData() const
975{
976 // akonadi_google_resource_1 -> org.kde.akonadi_google_resource
977 const QString desktopEntry = QLatin1StringView("org.kde.") + qApp->applicationName().remove(QRegularExpression(QStringLiteral("_[0-9]+$")));
978
979 KAboutData data(qApp->applicationName(), agentName(), qApp->applicationVersion());
980 data.setDesktopFileName(desktopEntry);
981 return data;
982}
983
984void AgentBase::configure(WId windowId)
985{
986 Q_UNUSED(windowId)
987 qCWarning(AKONADIAGENTBASE_LOG) << "Calling AgentBase::configure instead of using an AgentConfigurationDialog is not supported anymore.";
988}
989
990#ifdef Q_OS_WIN // krazy:exclude=cpp
991void AgentBase::configure(qlonglong windowId)
992{
993 configure(static_cast<WId>(windowId));
994}
995#endif
996
998{
999 const bool registered = QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.freedesktop.akonaditray"));
1000 if (!registered) {
1001 return 0;
1002 }
1003
1004 QDBusInterface dbus(QStringLiteral("org.freedesktop.akonaditray"), QStringLiteral("/Actions"), QStringLiteral("org.freedesktop.Akonadi.Tray"));
1005 const QDBusMessage reply = dbus.call(QStringLiteral("getWinId"));
1006
1007 if (reply.type() == QDBusMessage::ErrorMessage) {
1008 return 0;
1009 }
1010
1011 const WId winid = static_cast<WId>(reply.arguments().at(0).toLongLong());
1012
1013 return winid;
1014}
1015
1016void AgentBase::quit()
1017{
1018 Q_D(AgentBase);
1019 aboutToQuit();
1020
1021 if (d->mSettings) {
1022 d->mChangeRecorder->setConfig(nullptr);
1023 d->mSettings->sync();
1024 delete d->mSettings;
1025 d->mSettings = nullptr;
1026 }
1027
1028 delete d->mEventLoopLocker;
1029 d->mEventLoopLocker = nullptr;
1030}
1031
1033{
1034 Q_D(AgentBase);
1035 d->mPendingQuit = true;
1036}
1037
1039{
1040 Q_D(AgentBase);
1041 // prevent the monitor from picking up deletion signals for our own data if we are a resource
1042 // and thus avoid that we kill our own data as last act before our own death
1043 d->mChangeRecorder->blockSignals(true);
1044
1045 aboutToQuit();
1046
1047 const QString fileName = d->mSettings->fileName();
1048
1049 /*
1050 * First destroy the settings object...
1051 */
1052 d->mChangeRecorder->setConfig(nullptr);
1053 delete d->mSettings;
1054 d->mSettings = nullptr;
1055
1056 /*
1057 * ... then remove the file from hd.
1058 */
1059 if (!QFile::remove(fileName)) {
1060 qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove " << fileName;
1061 }
1062
1063 /*
1064 * ... and remove the changes file from hd.
1065 */
1066 const QString changeDataFileName = fileName + QStringLiteral("_changes.dat");
1067 if (!QFile::remove(changeDataFileName)) {
1068 qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove " << changeDataFileName;
1069 }
1070
1071 /*
1072 * ... and also remove the agent configuration file if there is one.
1073 */
1075 if (!QFile::remove(configFile)) {
1076 qCWarning(AKONADIAGENTBASE_LOG) << "Impossible to remove config file " << configFile;
1077 }
1078
1079 delete d->mEventLoopLocker;
1080 d->mEventLoopLocker = nullptr;
1081}
1082
1084{
1085 Q_D(AgentBase);
1086
1087 // TODO in theory we should re-connect change recorder signals here that we disconnected previously
1088 d->mObserver = observer;
1089
1090 const bool hasObserverV3 = (dynamic_cast<AgentBase::ObserverV3 *>(d->mObserver) != nullptr);
1091 const bool hasTagObserver = (dynamic_cast<AgentBase::TagObserver *>(d->mObserver) != nullptr);
1092
1093 disconnect(d->mChangeRecorder, &Monitor::tagAdded, d, &AgentBasePrivate::tagAdded);
1094 disconnect(d->mChangeRecorder, &Monitor::tagChanged, d, &AgentBasePrivate::tagChanged);
1095 disconnect(d->mChangeRecorder, &Monitor::tagRemoved, d, &AgentBasePrivate::tagRemoved);
1096 disconnect(d->mChangeRecorder, &Monitor::itemsTagsChanged, d, &AgentBasePrivate::itemsTagsChanged);
1097 disconnect(d->mChangeRecorder, &Monitor::itemsFlagsChanged, d, &AgentBasePrivate::itemsFlagsChanged);
1098 disconnect(d->mChangeRecorder, &Monitor::itemsMoved, d, &AgentBasePrivate::itemsMoved);
1099 disconnect(d->mChangeRecorder, &Monitor::itemsRemoved, d, &AgentBasePrivate::itemsRemoved);
1100 disconnect(d->mChangeRecorder, &Monitor::itemsLinked, d, &AgentBasePrivate::itemsLinked);
1101 disconnect(d->mChangeRecorder, &Monitor::itemsUnlinked, d, &AgentBasePrivate::itemsUnlinked);
1102 disconnect(d->mChangeRecorder, &Monitor::itemMoved, d, &AgentBasePrivate::itemMoved);
1103 disconnect(d->mChangeRecorder, &Monitor::itemRemoved, d, &AgentBasePrivate::itemRemoved);
1104 disconnect(d->mChangeRecorder, &Monitor::itemLinked, d, &AgentBasePrivate::itemLinked);
1105 disconnect(d->mChangeRecorder, &Monitor::itemUnlinked, d, &AgentBasePrivate::itemUnlinked);
1106
1107 if (hasTagObserver) {
1108 connect(d->mChangeRecorder, &Monitor::tagAdded, d, &AgentBasePrivate::tagAdded);
1109 connect(d->mChangeRecorder, &Monitor::tagChanged, d, &AgentBasePrivate::tagChanged);
1110 connect(d->mChangeRecorder, &Monitor::tagRemoved, d, &AgentBasePrivate::tagRemoved);
1111 connect(d->mChangeRecorder, &Monitor::itemsTagsChanged, d, &AgentBasePrivate::itemsTagsChanged);
1112
1113 // If the agent has a TagObserver, we assume it wants to receive everything tag-related.
1114 d->mChangeRecorder->itemFetchScope().setFetchTags(true);
1115 d->mChangeRecorder->tagFetchScope().setFetchAllAttributes(true);
1116 d->mChangeRecorder->tagFetchScope().setFetchRemoteId(true);
1117 }
1118
1119 if (hasObserverV3) {
1120 connect(d->mChangeRecorder, &Monitor::itemsFlagsChanged, d, &AgentBasePrivate::itemsFlagsChanged);
1121 connect(d->mChangeRecorder, &Monitor::itemsMoved, d, &AgentBasePrivate::itemsMoved);
1122 connect(d->mChangeRecorder, &Monitor::itemsRemoved, d, &AgentBasePrivate::itemsRemoved);
1123 connect(d->mChangeRecorder, &Monitor::itemsLinked, d, &AgentBasePrivate::itemsLinked);
1124 connect(d->mChangeRecorder, &Monitor::itemsUnlinked, d, &AgentBasePrivate::itemsUnlinked);
1125 } else {
1126 // V2 - don't connect these if we have V3
1127 connect(d->mChangeRecorder, &Monitor::itemMoved, d, &AgentBasePrivate::itemMoved);
1128 connect(d->mChangeRecorder, &Monitor::itemRemoved, d, &AgentBasePrivate::itemRemoved);
1129 connect(d->mChangeRecorder, &Monitor::itemLinked, d, &AgentBasePrivate::itemLinked);
1130 connect(d->mChangeRecorder, &Monitor::itemUnlinked, d, &AgentBasePrivate::itemUnlinked);
1131 }
1132}
1133
1135{
1136 return d_ptr->mId;
1137}
1138
1140{
1141 Q_D(AgentBase);
1142 if (name == d->mName) {
1143 return;
1144 }
1145
1146 // TODO: rename collection
1147 d->mName = name;
1148
1149 if (d->mName.isEmpty() || d->mName == d->mId) {
1150 d->mSettings->remove(QLatin1StringView("Resource/Name"));
1151 d->mSettings->remove(QLatin1StringView("Agent/Name"));
1152 } else {
1153 d->mSettings->setValue(QLatin1StringView("Agent/Name"), d->mName);
1154 }
1155
1156 d->mSettings->sync();
1157
1158 d->setProgramName();
1159
1160 Q_EMIT agentNameChanged(d->mName);
1161}
1162
1164{
1165 Q_D(const AgentBase);
1166 if (d->mName.isEmpty()) {
1167 return d->mId;
1168 } else {
1169 return d->mName;
1170 }
1171}
1172
1174{
1175 Q_D(AgentBase);
1176 if (activities == d->mActivities) {
1177 return;
1178 }
1179
1180 d->mActivities = activities;
1181 if (d->mActivities.isEmpty()) {
1182 d->mSettings->remove(QStringLiteral("Agent/Activities"));
1183 } else {
1184 d->mSettings->setValue(QStringLiteral("Agent/Activities"), d->mActivities);
1185 }
1186 Q_EMIT agentActivitiesChanged(d->mActivities);
1187}
1188
1190{
1191 Q_D(const AgentBase);
1192 return d->mActivities;
1193}
1194
1196{
1197 Q_D(const AgentBase);
1198 return d->mActivitiesEnabled;
1199}
1200
1202{
1203 Q_D(AgentBase);
1204 if (enabled == d->mActivitiesEnabled) {
1205 return;
1206 }
1207
1208 d->mActivitiesEnabled = enabled;
1209 d->mSettings->setValue(QStringLiteral("Agent/ActivitiesEnabled"), enabled);
1210 Q_EMIT agentActivitiesEnabledChanged(d->mActivitiesEnabled);
1211}
1212
1214{
1215 Q_D(AgentBase);
1216 d->changeProcessed();
1217}
1218
1220{
1221 return d_ptr->mChangeRecorder;
1222}
1223
1224KSharedConfigPtr AgentBase::config()
1225{
1227}
1228
1229void AgentBase::abort()
1230{
1232}
1233
1234void AgentBase::reconfigure()
1235{
1237}
1238
1239#include "moc_agentbase.cpp"
1240#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 Apr 11 2025 11:52:13 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.