• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.14.10 API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • akonadi
firstrun.cpp
1/*
2 Copyright (c) 2008 Volker Krause <vkrause@kde.org>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#include "firstrun_p.h"
21#include "dbusconnectionpool.h"
22#include "servermanager.h"
23
24#include <akonadi/agentinstance.h>
25#include <akonadi/agentinstancecreatejob.h>
26#include <akonadi/agentmanager.h>
27#include <akonadi/agenttype.h>
28
29#include <KConfig>
30#include <KConfigGroup>
31#include <KDebug>
32#include <KGlobal>
33#include <KProcess>
34#include <KStandardDirs>
35
36#include <QtDBus/QDBusConnection>
37#include <QtDBus/QDBusInterface>
38#include <QtDBus/QDBusReply>
39#include <QtCore/QDir>
40#include <QtCore/QMetaMethod>
41#include <QtCore/QMetaObject>
42
43static char FIRSTRUN_DBUSLOCK[] = "org.kde.Akonadi.Firstrun.lock";
44
45using namespace Akonadi;
46
47Firstrun::Firstrun(QObject *parent)
48 : QObject(parent)
49 , mConfig(new KConfig(ServerManager::addNamespace(QLatin1String("akonadi-firstrunrc"))))
50 , mCurrentDefault(0)
51 , mProcess(0)
52{
53 //The code in firstrun is not safe in multi-instance mode
54 Q_ASSERT(!ServerManager::hasInstanceIdentifier());
55 if (ServerManager::hasInstanceIdentifier()) {
56 deleteLater();
57 return;
58 }
59 kDebug();
60 if (DBusConnectionPool::threadConnection().registerService(QLatin1String(FIRSTRUN_DBUSLOCK))) {
61 findPendingDefaults();
62 kDebug() << mPendingDefaults;
63 setupNext();
64 } else {
65 kDebug() << "D-Bus lock found, so someone else does the work for us already.";
66 deleteLater();
67 }
68}
69
70Firstrun::~Firstrun()
71{
72 DBusConnectionPool::threadConnection().unregisterService(QLatin1String(FIRSTRUN_DBUSLOCK));
73 delete mConfig;
74 kDebug() << "done";
75}
76
77void Firstrun::findPendingDefaults()
78{
79 const KConfigGroup cfg(mConfig, "ProcessedDefaults");
80 foreach (const QString &dirName, KGlobal::dirs()->findDirs("data", QLatin1String("akonadi/firstrun"))) {
81 const QStringList files = QDir(dirName).entryList(QDir::Files | QDir::Readable);
82 foreach (const QString &fileName, files) {
83 const QString fullName = dirName + fileName;
84 KConfig c(fullName);
85 const QString id = KConfigGroup(&c, "Agent").readEntry("Id", QString());
86 if (id.isEmpty()) {
87 kWarning() << "Found invalid default configuration in " << fullName;
88 continue;
89 }
90 if (cfg.hasKey(id)) {
91 continue;
92 }
93 mPendingDefaults << dirName + fileName;
94 }
95 }
96
97#ifndef KDEPIM_NO_KRESOURCES
98 // always check legacy kres for migration, their migrator might have changed again
99 mPendingKres << QLatin1String("contact") << QLatin1String("calendar");
100#endif
101}
102
103#ifndef KDEPIM_NO_KRESOURCES
104static QString resourceTypeForMimetype(const QStringList &mimeTypes)
105{
106 if (mimeTypes.contains(QLatin1String("text/directory"))) {
107 return QString::fromLatin1("contact");
108 }
109 if (mimeTypes.contains(QLatin1String("text/calendar"))) {
110 return QString::fromLatin1("calendar");
111 }
112 // TODO notes
113 return QString();
114}
115
116void Firstrun::migrateKresType(const QString &resourceFamily)
117{
118 mResourceFamily = resourceFamily;
119 KConfig config(QLatin1String("kres-migratorrc"));
120 KConfigGroup migrationCfg(&config, "Migration");
121 const bool enabled = migrationCfg.readEntry("Enabled", false);
122 const bool setupClientBridge = migrationCfg.readEntry("SetupClientBridge", true);
123 const int currentVersion = migrationCfg.readEntry(QString::fromLatin1("Version-%1").arg(resourceFamily), 0);
124 const int targetVersion = migrationCfg.readEntry("TargetVersion", 0);
125 if (enabled && currentVersion < targetVersion) {
126 kDebug() << "Performing migration of legacy KResource settings. Good luck!";
127 mProcess = new KProcess(this);
128 connect(mProcess, SIGNAL(finished(int)), SLOT(migrationFinished(int)));
129 QStringList args = QStringList() << QLatin1String("--interactive-on-change")
130 << QLatin1String("--type") << resourceFamily;
131 if (!setupClientBridge) {
132 args << QLatin1String("--omit-client-bridge");
133 }
134 mProcess->setProgram(QLatin1String("kres-migrator"), args);
135 mProcess->start();
136 if (!mProcess->waitForStarted()) {
137 migrationFinished(-1);
138 }
139 } else {
140 // nothing to do
141 setupNext();
142 }
143}
144
145void Firstrun::migrationFinished(int exitCode)
146{
147 Q_ASSERT(mProcess);
148 if (exitCode == 0) {
149 kDebug() << "KResource -> Akonadi migration has been successful";
150 KConfig config(QLatin1String("kres-migratorrc"));
151 KConfigGroup migrationCfg(&config, "Migration");
152 const int targetVersion = migrationCfg.readEntry("TargetVersion", 0);
153 migrationCfg.writeEntry(QString::fromLatin1("Version-%1").arg(mResourceFamily), targetVersion);
154 migrationCfg.sync();
155 } else if (exitCode != 1) {
156 // exit code 1 means it is already running, so we are probably called by a migrator instance
157 kError() << "KResource -> Akonadi migration failed!";
158 kError() << "command was: " << mProcess->program();
159 kError() << "exit code: " << mProcess->exitCode();
160 kError() << "stdout: " << mProcess->readAllStandardOutput();
161 kError() << "stderr: " << mProcess->readAllStandardError();
162 }
163
164 setupNext();
165}
166#endif
167
168void Firstrun::setupNext()
169{
170 delete mCurrentDefault;
171 mCurrentDefault = 0;
172
173 if (mPendingDefaults.isEmpty()) {
174#ifndef KDEPIM_NO_KRESOURCES
175 if (!mPendingKres.isEmpty()) {
176 migrateKresType(mPendingKres.takeFirst());
177 return;
178 }
179#endif
180 deleteLater();
181 return;
182 }
183
184 mCurrentDefault = new KConfig(mPendingDefaults.takeFirst());
185 const KConfigGroup agentCfg = KConfigGroup(mCurrentDefault, "Agent");
186
187 AgentType type = AgentManager::self()->type(agentCfg.readEntry("Type", QString()));
188 if (!type.isValid()) {
189 kError() << "Unable to obtain agent type for default resource agent configuration " << mCurrentDefault->name();
190 setupNext();
191 return;
192 }
193 if (type.capabilities().contains(QLatin1String("Unique"))) {
194 Q_FOREACH (const AgentInstance &agent, AgentManager::self()->instances()) {
195 if (agent.type() == type) {
196 // remember we set this one up already
197 KConfigGroup cfg(mConfig, "ProcessedDefaults");
198 cfg.writeEntry(agentCfg.readEntry("Id", QString()), agent.identifier());
199 cfg.sync();
200 setupNext();
201 return;
202 }
203 }
204 }
205#ifndef KDEPIM_NO_KRESOURCES
206 // KDE5: remove me
207 // check if there is a kresource setup for this type already
208 const QString kresType = resourceTypeForMimetype(type.mimeTypes());
209 if (!kresType.isEmpty()) {
210 const QString kresCfgFile = KStandardDirs::locateLocal("config", QString::fromLatin1("kresources/%1/stdrc").arg(kresType));
211 KConfig resCfg(kresCfgFile);
212 const KConfigGroup resGroup(&resCfg, "General");
213 bool legacyResourceFound = false;
214 const QStringList kresResources = resGroup.readEntry("ResourceKeys", QStringList())
215 + resGroup.readEntry("PassiveResourceKeys", QStringList());
216 foreach (const QString &kresResource, kresResources) {
217 const KConfigGroup cfg(&resCfg, QString::fromLatin1("Resource_%1").arg(kresResource));
218 if (cfg.readEntry("ResourceType", QString()) != QLatin1String("akonadi")) { // not a bridge
219 legacyResourceFound = true;
220 break;
221 }
222 }
223 if (legacyResourceFound) {
224 kDebug() << "ignoring " << mCurrentDefault->name() << " as there is a KResource setup for its type already.";
225 KConfigGroup cfg(mConfig, "ProcessedDefaults");
226 cfg.writeEntry(agentCfg.readEntry("Id", QString()), QString::fromLatin1("kres"));
227 cfg.sync();
228 setupNext();
229 return;
230 }
231 }
232#endif
233
234 AgentInstanceCreateJob *job = new AgentInstanceCreateJob(type);
235 connect(job, SIGNAL(result(KJob*)), SLOT(instanceCreated(KJob*)));
236 job->start();
237}
238
239void Firstrun::instanceCreated(KJob *job)
240{
241 Q_ASSERT(mCurrentDefault);
242
243 if (job->error()) {
244 kError() << "Creating agent instance failed for " << mCurrentDefault->name();
245 setupNext();
246 return;
247 }
248
249 AgentInstance instance = static_cast<AgentInstanceCreateJob *>(job)->instance();
250 const KConfigGroup agentCfg = KConfigGroup(mCurrentDefault, "Agent");
251 const QString agentName = agentCfg.readEntry("Name", QString());
252 if (!agentName.isEmpty()) {
253 instance.setName(agentName);
254 }
255
256 // agent specific settings, using the D-Bus <-> KConfigXT bridge
257 const KConfigGroup settings = KConfigGroup(mCurrentDefault, "Settings");
258
259 QDBusInterface *iface = new QDBusInterface(QString::fromLatin1("org.freedesktop.Akonadi.Agent.%1").arg(instance.identifier()),
260 QLatin1String("/Settings"), QString(),
261 DBusConnectionPool::threadConnection(), this);
262 if (!iface->isValid()) {
263 kError() << "Unable to obtain the KConfigXT D-Bus interface of " << instance.identifier();
264 setupNext();
265 delete iface;
266 return;
267 }
268
269 foreach (const QString &setting, settings.keyList()) {
270 kDebug() << "Setting up " << setting << " for agent " << instance.identifier();
271 const QString methodName = QString::fromLatin1("set%1").arg(setting);
272 const QVariant::Type argType = argumentType(iface->metaObject(), methodName);
273 if (argType == QVariant::Invalid) {
274 kError() << "Setting " << setting << " not found in agent configuration interface of " << instance.identifier();
275 continue;
276 }
277
278 QVariant arg;
279 if (argType == QVariant::String) {
280 // Since a string could be a path we always use readPathEntry here,
281 // that shouldn't harm any normal string settings
282 arg = settings.readPathEntry(setting, QString());
283 } else {
284 arg = settings.readEntry(setting, QVariant(argType));
285 }
286
287 const QDBusReply<void> reply = iface->call(methodName, arg);
288 if (!reply.isValid()) {
289 kError() << "Setting " << setting << " failed for agent " << instance.identifier();
290 }
291 }
292
293 iface->call(QLatin1String("writeConfig"));
294
295 instance.reconfigure();
296 instance.synchronize();
297 delete iface;
298
299 // remember we set this one up already
300 KConfigGroup cfg(mConfig, "ProcessedDefaults");
301 cfg.writeEntry(agentCfg.readEntry("Id", QString()), instance.identifier());
302 cfg.sync();
303
304 setupNext();
305}
306
307QVariant::Type Firstrun::argumentType(const QMetaObject *mo, const QString &method)
308{
309 QMetaMethod m;
310 for (int i = 0; i < mo->methodCount(); ++i) {
311 const QString signature = QString::fromLatin1(mo->method(i).signature());
312 if (signature.startsWith(method)) {
313 m = mo->method(i);
314 }
315 }
316
317 if (!m.signature()) {
318 return QVariant::Invalid;
319 }
320
321 const QList<QByteArray> argTypes = m.parameterTypes();
322 if (argTypes.count() != 1) {
323 return QVariant::Invalid;
324 }
325
326 return QVariant::nameToType(argTypes.first());
327}
328
329#include "moc_firstrun_p.cpp"
Akonadi::AgentInstanceCreateJob
Job for creating new agent instances.
Definition agentinstancecreatejob.h:72
Akonadi::AgentInstanceCreateJob::start
void start()
Starts the instance creation.
Definition agentinstancecreatejob.cpp:176
Akonadi::AgentInstance
A representation of an agent instance.
Definition agentinstance.h:63
Akonadi::AgentInstance::identifier
QString identifier() const
Returns the unique identifier of the agent instance.
Definition agentinstance.cpp:55
Akonadi::AgentInstance::synchronize
void synchronize()
Triggers the agent instance to start synchronization.
Definition agentinstance.cpp:110
Akonadi::AgentInstance::type
AgentType type() const
Returns the agent type of this instance.
Definition agentinstance.cpp:50
Akonadi::AgentInstance::setName
void setName(const QString &name)
Sets the user visible name of the agent instance.
Definition agentinstance.cpp:60
Akonadi::AgentInstance::reconfigure
void reconfigure() const
Tell the agent that its configuration has been changed remotely via D-Bus.
Definition agentinstance.cpp:149
Akonadi::AgentManager::type
AgentType type(const QString &identifier) const
Returns the agent type with the given identifier or an invalid agent type if the identifier does not ...
Definition agentmanager.cpp:391
Akonadi::AgentManager::self
static AgentManager * self()
Returns the global instance of the agent manager.
Definition agentmanager.cpp:377
Akonadi::AgentType
A representation of an agent type.
Definition agenttype.h:59
Akonadi::ServerManager
Provides methods to control the Akonadi server process.
Definition servermanager.h:43
Akonadi::ServerManager::hasInstanceIdentifier
static bool hasInstanceIdentifier()
Returns true if we are connected to a non-default Akonadi server instance.
Definition servermanager.cpp:289
Akonadi
FreeBusyManager::Singleton.
Definition actionstatemanager_p.h:28
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Wed Jan 24 2024 00:00:00 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Related Pages

kdepimlibs-4.14.10 API Reference

Skip menu "kdepimlibs-4.14.10 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal