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

KDE's Doxygen guidelines are available online.