Akonadi

firstrun.cpp
1 /*
2  SPDX-FileCopyrightText: 2008 Volker Krause <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "firstrun_p.h"
8 #include "servermanager.h"
9 #include <QDBusConnection>
10 
11 #include "agentinstance.h"
12 #include "agentinstancecreatejob.h"
13 #include "agentmanager.h"
14 #include "agenttype.h"
15 #include <private/standarddirs_p.h>
16 
17 #include "akonadicore_debug.h"
18 
19 #include <KConfig>
20 #include <KConfigGroup>
21 
22 #include <QCoreApplication>
23 #include <QDBusInterface>
24 #include <QDBusReply>
25 #include <QDir>
26 #include <QMetaMethod>
27 #include <QMetaObject>
28 #include <QStandardPaths>
29 
30 static const char FIRSTRUN_DBUSLOCK[] = "org.kde.Akonadi.Firstrun.lock";
31 
32 using namespace Akonadi;
33 
34 Firstrun::Firstrun(QObject *parent)
35  : QObject(parent)
36  , mConfig(new KConfig(ServerManager::addNamespace(QStringLiteral("akonadi-firstrunrc"))))
37 {
38  // The code in firstrun is not safe in multi-instance mode
41  deleteLater();
42  return;
43  }
44  if (QDBusConnection::sessionBus().registerService(QLatin1String(FIRSTRUN_DBUSLOCK))) {
45  findPendingDefaults();
46  qCDebug(AKONADICORE_LOG) << "D-Bus lock acquired, pending defaults:" << mPendingDefaults;
47  setupNext();
48  } else {
49  qCDebug(AKONADICORE_LOG) << "D-Bus lock found, so someone else does the work for us already.";
50  deleteLater();
51  }
52 }
53 
54 Firstrun::~Firstrun()
55 {
56  if (qApp) {
58  }
59  delete mConfig;
60  qCDebug(AKONADICORE_LOG) << "done";
61 }
62 
63 void Firstrun::findPendingDefaults()
64 {
65  const KConfigGroup cfg(mConfig, "ProcessedDefaults");
66  const auto paths = StandardDirs::locateAllResourceDirs(QStringLiteral("akonadi/firstrun"));
67  for (const QString &dirName : paths) {
68  const QStringList files = QDir(dirName).entryList(QDir::Files | QDir::Readable);
69  for (const QString &fileName : files) {
70  const QString fullName = dirName + QLatin1Char('/') + fileName;
71  KConfig c(fullName);
72  const QString id = KConfigGroup(&c, "Agent").readEntry("Id", QString());
73  if (id.isEmpty()) {
74  qCWarning(AKONADICORE_LOG) << "Found invalid default configuration in " << fullName;
75  continue;
76  }
77  if (cfg.hasKey(id)) {
78  continue;
79  }
80  mPendingDefaults << fullName;
81  }
82  }
83 }
84 
85 void Firstrun::setupNext()
86 {
87  delete mCurrentDefault;
88  mCurrentDefault = nullptr;
89 
90  if (mPendingDefaults.isEmpty()) {
91  deleteLater();
92  return;
93  }
94 
95  mCurrentDefault = new KConfig(mPendingDefaults.takeFirst());
96  const KConfigGroup agentCfg = KConfigGroup(mCurrentDefault, "Agent");
97 
98  AgentType type = AgentManager::self()->type(agentCfg.readEntry("Type", QString()));
99  if (!type.isValid()) {
100  qCCritical(AKONADICORE_LOG) << "Unable to obtain agent type for default resource agent configuration " << mCurrentDefault->name();
101  setupNext();
102  return;
103  }
104  if (type.capabilities().contains(QLatin1String("Unique"))) {
106  for (const AgentInstance &agent : lstAgents) {
107  if (agent.type() == type) {
108  // remember we set this one up already
109  KConfigGroup cfg(mConfig, "ProcessedDefaults");
110  cfg.writeEntry(agentCfg.readEntry("Id", QString()), agent.identifier());
111  cfg.sync();
112  setupNext();
113  return;
114  }
115  }
116  }
117 
118  auto job = new AgentInstanceCreateJob(type);
119  connect(job, &AgentInstanceCreateJob::result, this, &Firstrun::instanceCreated);
120  job->start();
121 }
122 
123 void Firstrun::instanceCreated(KJob *job)
124 {
125  Q_ASSERT(mCurrentDefault);
126 
127  if (job->error()) {
128  qCCritical(AKONADICORE_LOG) << "Creating agent instance failed for " << mCurrentDefault->name();
129  setupNext();
130  return;
131  }
132 
133  AgentInstance instance = static_cast<AgentInstanceCreateJob *>(job)->instance();
134  const KConfigGroup agentCfg = KConfigGroup(mCurrentDefault, "Agent");
135  const QString agentName = agentCfg.readEntry("Name", QString());
136  if (!agentName.isEmpty()) {
137  instance.setName(agentName);
138  }
139 
140  const auto service = ServerManager::agentServiceName(ServerManager::Agent, instance.identifier());
141  auto iface = new QDBusInterface(service, QStringLiteral("/Settings"), QString(), QDBusConnection::sessionBus(), this);
142  if (!iface->isValid()) {
143  qCCritical(AKONADICORE_LOG) << "Unable to obtain the KConfigXT D-Bus interface of " << instance.identifier();
144  setupNext();
145  delete iface;
146  return;
147  }
148  // agent specific settings, using the D-Bus <-> KConfigXT bridge
149  const KConfigGroup settings = KConfigGroup(mCurrentDefault, "Settings");
150 
151  const QStringList lstSettings = settings.keyList();
152  for (const QString &setting : lstSettings) {
153  qCDebug(AKONADICORE_LOG) << "Setting up " << setting << " for agent " << instance.identifier();
154  const QString methodName = QStringLiteral("set%1").arg(setting);
155  const QVariant::Type argType = argumentType(iface->metaObject(), methodName);
156  if (argType == QVariant::Invalid) {
157  qCCritical(AKONADICORE_LOG) << "Setting " << setting << " not found in agent configuration interface of " << instance.identifier();
158  continue;
159  }
160 
161  QVariant arg;
162  if (argType == QVariant::String) {
163  // Since a string could be a path we always use readPathEntry here,
164  // that shouldn't harm any normal string settings
165  arg = settings.readPathEntry(setting, QString());
166  } else {
167  arg = settings.readEntry(setting, QVariant(argType));
168  }
169 
170  const QDBusReply<void> reply = iface->call(methodName, arg);
171  if (!reply.isValid()) {
172  qCCritical(AKONADICORE_LOG) << "Setting " << setting << " failed for agent " << instance.identifier();
173  }
174  }
175 
176  iface->call(QStringLiteral("save"));
177 
178  instance.reconfigure();
179  instance.synchronize();
180  delete iface;
181 
182  // remember we set this one up already
183  KConfigGroup cfg(mConfig, "ProcessedDefaults");
184  cfg.writeEntry(agentCfg.readEntry("Id", QString()), instance.identifier());
185  cfg.sync();
186 
187  setupNext();
188 }
189 
190 QVariant::Type Firstrun::argumentType(const QMetaObject *mo, const QString &method)
191 {
192  QMetaMethod m;
193  for (int i = 0; i < mo->methodCount(); ++i) {
194  const QString signature = QString::fromLatin1(mo->method(i).methodSignature());
195  if (signature.startsWith(method)) {
196  m = mo->method(i);
197  }
198  }
199 
200  if (m.methodSignature().isEmpty()) {
201  return QVariant::Invalid;
202  }
203 
204  const QList<QByteArray> argTypes = m.parameterTypes();
205  if (argTypes.count() != 1) {
206  return QVariant::Invalid;
207  }
208 
209  return QVariant::nameToType(argTypes.first().constData());
210 }
211 
212 #include "moc_firstrun_p.cpp"
int methodCount() const const
T & first()
QString identifier() const
Returns the unique identifier of the agent instance.
QString readEntry(const char *key, const char *aDefault=nullptr) const
void result(KJob *job)
A representation of an agent type.
int count(const T &value) const const
bool isValid() const const
QVariant::Type nameToType(const char *name)
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...
QByteArray methodSignature() const const
QDBusConnection sessionBus()
void reconfigure() const
Tell the agent that its configuration has been changed remotely via D-Bus.
bool unregisterService(const QString &serviceName)
void synchronize()
Triggers the agent instance to start synchronization.
void setName(const QString &name)
Sets the user visible name of the agent instance.
bool isEmpty() const const
QMetaMethod method(int index) const const
AgentType type(const QString &identifier) const
Returns the agent type with the given identifier or an invalid agent type if the identifier does not ...
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
bool isEmpty() const const
QStringList keyList() const
const char * constData() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString fromLatin1(const char *str, int size)
static AgentManager * self()
Returns the global instance of the agent manager.
AgentInstance::List instances() const
Returns the list of all available agent instances.
QString readPathEntry(const char *key, const QString &aDefault) const
static bool hasInstanceIdentifier()
Returns true if we are connected to a non-default Akonadi server instance.
QStringList entryList(QDir::Filters filters, QDir::SortFlags sort) const const
int error() const
QList< QByteArray > parameterTypes() const const
Provides methods to control the Akonadi server process.
Definition: servermanager.h:28
A representation of an agent instance.
QString fullName(const PartType &type)
Returns full part name.
Job for creating new agent instances.
Helper integration between Akonadi and Qt.
QString name() const
Returns the i18n'ed name of the agent type.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu Jun 30 2022 03:51:46 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.