Akonadi

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

KDE's Doxygen guidelines are available online.