20#include "firstrun_p.h"
21#include "dbusconnectionpool.h"
22#include "servermanager.h"
24#include <akonadi/agentinstance.h>
25#include <akonadi/agentinstancecreatejob.h>
26#include <akonadi/agentmanager.h>
27#include <akonadi/agenttype.h>
30#include <KConfigGroup>
34#include <KStandardDirs>
36#include <QtDBus/QDBusConnection>
37#include <QtDBus/QDBusInterface>
38#include <QtDBus/QDBusReply>
40#include <QtCore/QMetaMethod>
41#include <QtCore/QMetaObject>
43static char FIRSTRUN_DBUSLOCK[] =
"org.kde.Akonadi.Firstrun.lock";
47Firstrun::Firstrun(QObject *parent)
49 , mConfig(new KConfig(
ServerManager::addNamespace(QLatin1String(
"akonadi-firstrunrc"))))
60 if (DBusConnectionPool::threadConnection().registerService(QLatin1String(FIRSTRUN_DBUSLOCK))) {
61 findPendingDefaults();
62 kDebug() << mPendingDefaults;
65 kDebug() <<
"D-Bus lock found, so someone else does the work for us already.";
72 DBusConnectionPool::threadConnection().unregisterService(QLatin1String(FIRSTRUN_DBUSLOCK));
77void Firstrun::findPendingDefaults()
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;
85 const QString
id = KConfigGroup(&c,
"Agent").readEntry(
"Id", QString());
87 kWarning() <<
"Found invalid default configuration in " << fullName;
93 mPendingDefaults << dirName + fileName;
97#ifndef KDEPIM_NO_KRESOURCES
99 mPendingKres << QLatin1String(
"contact") << QLatin1String(
"calendar");
103#ifndef KDEPIM_NO_KRESOURCES
104static QString resourceTypeForMimetype(
const QStringList &mimeTypes)
106 if (mimeTypes.contains(QLatin1String(
"text/directory"))) {
107 return QString::fromLatin1(
"contact");
109 if (mimeTypes.contains(QLatin1String(
"text/calendar"))) {
110 return QString::fromLatin1(
"calendar");
116void Firstrun::migrateKresType(
const QString &resourceFamily)
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");
134 mProcess->setProgram(QLatin1String(
"kres-migrator"), args);
136 if (!mProcess->waitForStarted()) {
137 migrationFinished(-1);
145void Firstrun::migrationFinished(
int exitCode)
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);
155 }
else if (exitCode != 1) {
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();
168void Firstrun::setupNext()
170 delete mCurrentDefault;
173 if (mPendingDefaults.isEmpty()) {
174#ifndef KDEPIM_NO_KRESOURCES
175 if (!mPendingKres.isEmpty()) {
176 migrateKresType(mPendingKres.takeFirst());
184 mCurrentDefault =
new KConfig(mPendingDefaults.takeFirst());
185 const KConfigGroup agentCfg = KConfigGroup(mCurrentDefault,
"Agent");
188 if (!type.isValid()) {
189 kError() <<
"Unable to obtain agent type for default resource agent configuration " << mCurrentDefault->name();
193 if (type.capabilities().contains(QLatin1String(
"Unique"))) {
195 if (agent.
type() == type) {
197 KConfigGroup cfg(mConfig,
"ProcessedDefaults");
198 cfg.writeEntry(agentCfg.readEntry(
"Id", QString()), agent.
identifier());
205#ifndef KDEPIM_NO_KRESOURCES
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")) {
219 legacyResourceFound =
true;
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"));
235 connect(job, SIGNAL(result(KJob*)), SLOT(instanceCreated(KJob*)));
239void Firstrun::instanceCreated(KJob *job)
241 Q_ASSERT(mCurrentDefault);
244 kError() <<
"Creating agent instance failed for " << mCurrentDefault->name();
250 const KConfigGroup agentCfg = KConfigGroup(mCurrentDefault,
"Agent");
251 const QString agentName = agentCfg.readEntry(
"Name", QString());
252 if (!agentName.isEmpty()) {
257 const KConfigGroup settings = KConfigGroup(mCurrentDefault,
"Settings");
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();
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();
279 if (argType == QVariant::String) {
282 arg = settings.readPathEntry(setting, QString());
284 arg = settings.readEntry(setting, QVariant(argType));
287 const QDBusReply<void> reply = iface->call(methodName, arg);
288 if (!reply.isValid()) {
289 kError() <<
"Setting " << setting <<
" failed for agent " << instance.
identifier();
293 iface->call(QLatin1String(
"writeConfig"));
300 KConfigGroup cfg(mConfig,
"ProcessedDefaults");
301 cfg.writeEntry(agentCfg.readEntry(
"Id", QString()), instance.
identifier());
307QVariant::Type Firstrun::argumentType(
const QMetaObject *mo,
const QString &method)
310 for (
int i = 0; i < mo->methodCount(); ++i) {
311 const QString signature = QString::fromLatin1(mo->method(i).signature());
312 if (signature.startsWith(method)) {
317 if (!m.signature()) {
318 return QVariant::Invalid;
321 const QList<QByteArray> argTypes = m.parameterTypes();
322 if (argTypes.count() != 1) {
323 return QVariant::Invalid;
326 return QVariant::nameToType(argTypes.first());
329#include "moc_firstrun_p.cpp"
Job for creating new agent instances.
void start()
Starts the instance creation.
A representation of an agent instance.
QString identifier() const
Returns the unique identifier of the agent instance.
void synchronize()
Triggers the agent instance to start synchronization.
AgentType type() const
Returns the agent type of this instance.
void setName(const QString &name)
Sets the user visible name of the agent instance.
void reconfigure() const
Tell the agent that its configuration has been changed remotely via D-Bus.
AgentType type(const QString &identifier) const
Returns the agent type with the given identifier or an invalid agent type if the identifier does not ...
static AgentManager * self()
Returns the global instance of the agent manager.
A representation of an agent type.
Provides methods to control the Akonadi server process.
static bool hasInstanceIdentifier()
Returns true if we are connected to a non-default Akonadi server instance.
FreeBusyManager::Singleton.