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>
39 #include <QtCore/QDir>
40 #include <QtCore/QMetaMethod>
41 #include <QtCore/QMetaObject>
43 static char FIRSTRUN_DBUSLOCK[] =
"org.kde.Akonadi.Firstrun.lock";
47 Firstrun::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));
77 void 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
104 static 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");
116 void 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);
145 void 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();
168 void 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*)));
239 void 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());
307 QVariant::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"