20 #include "firstrun_p.h"
21 #include "dbusconnectionpool.h"
23 #include <akonadi/agentinstance.h>
24 #include <akonadi/agentinstancecreatejob.h>
25 #include <akonadi/agentmanager.h>
26 #include <akonadi/agenttype.h>
29 #include <KConfigGroup>
33 #include <KStandardDirs>
35 #include <QtDBus/QDBusConnection>
36 #include <QtDBus/QDBusInterface>
37 #include <QtDBus/QDBusReply>
38 #include <QtCore/QDir>
39 #include <QtCore/QMetaMethod>
40 #include <QtCore/QMetaObject>
42 static char FIRSTRUN_DBUSLOCK[] =
"org.kde.Akonadi.Firstrun.lock";
44 using namespace Akonadi;
46 Firstrun::Firstrun( QObject *parent )
48 mConfig( new KConfig( QLatin1String(
"akonadi-firstrunrc" ) ) ),
53 if ( DBusConnectionPool::threadConnection().registerService( QLatin1String( FIRSTRUN_DBUSLOCK ) ) ) {
54 findPendingDefaults();
55 kDebug() << mPendingDefaults;
58 kDebug() <<
"D-Bus lock found, so someone else does the work for us already.";
65 DBusConnectionPool::threadConnection().unregisterService( QLatin1String( FIRSTRUN_DBUSLOCK ) );
70 void Firstrun::findPendingDefaults()
72 const KConfigGroup cfg( mConfig,
"ProcessedDefaults" );
73 foreach (
const QString &dirName, KGlobal::dirs()->findDirs(
"data", QLatin1String(
"akonadi/firstrun" ) ) ) {
74 const QStringList files = QDir( dirName ).entryList( QDir::Files | QDir::Readable );
75 foreach (
const QString &fileName, files ) {
76 const QString fullName = dirName + fileName;
77 KConfig c( fullName );
78 const QString
id = KConfigGroup( &c,
"Agent" ).readEntry(
"Id", QString() );
80 kWarning() <<
"Found invalid default configuration in " << fullName;
83 if ( cfg.hasKey(
id ) )
85 mPendingDefaults << dirName + fileName;
89 #ifndef KDEPIM_NO_KRESOURCES
91 mPendingKres << QLatin1String(
"contact") << QLatin1String(
"calendar");
95 #ifndef KDEPIM_NO_KRESOURCES
96 static QString resourceTypeForMimetype(
const QStringList &mimeTypes )
98 if ( mimeTypes.contains( QLatin1String(
"text/directory" ) ) )
99 return QString::fromLatin1(
"contact" );
100 if ( mimeTypes.contains( QLatin1String(
"text/calendar" ) ) )
101 return QString::fromLatin1(
"calendar" );
106 void Firstrun::migrateKresType(
const QString& resourceFamily )
108 mResourceFamily = resourceFamily;
109 KConfig config( QLatin1String(
"kres-migratorrc" ) );
110 KConfigGroup migrationCfg( &config,
"Migration" );
111 const bool enabled = migrationCfg.readEntry(
"Enabled",
false );
112 const bool setupClientBridge = migrationCfg.readEntry(
"SetupClientBridge",
true );
113 const int currentVersion = migrationCfg.readEntry( QString::fromLatin1(
"Version-%1" ).arg( resourceFamily ), 0 );
114 const int targetVersion = migrationCfg.readEntry(
"TargetVersion", 0 );
115 if ( enabled && currentVersion < targetVersion ) {
116 kDebug() <<
"Performing migration of legacy KResource settings. Good luck!";
117 mProcess =
new KProcess(
this );
118 connect( mProcess, SIGNAL(finished(
int)), SLOT(migrationFinished(
int)) );
119 QStringList args = QStringList() << QLatin1String(
"--interactive-on-change" )
120 << QLatin1String(
"--type" ) << resourceFamily;
121 if ( !setupClientBridge )
122 args << QLatin1String(
"--omit-client-bridge" );
123 mProcess->setProgram( QLatin1String(
"kres-migrator" ), args );
125 if ( !mProcess->waitForStarted() )
126 migrationFinished( -1 );
133 void Firstrun::migrationFinished(
int exitCode )
135 Q_ASSERT( mProcess );
136 if ( exitCode == 0 ) {
137 kDebug() <<
"KResource -> Akonadi migration has been successful";
138 KConfig config( QLatin1String(
"kres-migratorrc" ) );
139 KConfigGroup migrationCfg( &config,
"Migration" );
140 const int targetVersion = migrationCfg.readEntry(
"TargetVersion", 0 );
141 migrationCfg.writeEntry( QString::fromLatin1(
"Version-%1" ).arg( mResourceFamily ), targetVersion );
143 }
else if ( exitCode != 1 ) {
145 kError() <<
"KResource -> Akonadi migration failed!";
146 kError() <<
"command was: " << mProcess->program();
147 kError() <<
"exit code: " << mProcess->exitCode();
148 kError() <<
"stdout: " << mProcess->readAllStandardOutput();
149 kError() <<
"stderr: " << mProcess->readAllStandardError();
157 void Firstrun::setupNext()
159 delete mCurrentDefault;
162 if ( mPendingDefaults.isEmpty() ) {
163 #ifndef KDEPIM_NO_KRESOURCES
164 if ( !mPendingKres.isEmpty() ) {
165 migrateKresType( mPendingKres.takeFirst() );
173 mCurrentDefault =
new KConfig( mPendingDefaults.takeFirst() );
174 const KConfigGroup agentCfg = KConfigGroup( mCurrentDefault,
"Agent" );
178 kError() <<
"Unable to obtain agent type for default resource agent configuration " << mCurrentDefault->name();
183 #ifndef KDEPIM_NO_KRESOURCES
186 const QString kresType = resourceTypeForMimetype( type.
mimeTypes() );
187 if ( !kresType.isEmpty() ) {
188 const QString kresCfgFile = KStandardDirs::locateLocal(
"config", QString::fromLatin1(
"kresources/%1/stdrc" ).arg( kresType ) );
189 KConfig resCfg( kresCfgFile );
190 const KConfigGroup resGroup( &resCfg,
"General" );
191 bool legacyResourceFound =
false;
192 const QStringList kresResources = resGroup.readEntry(
"ResourceKeys", QStringList() )
193 + resGroup.readEntry(
"PassiveResourceKeys", QStringList() );
194 foreach (
const QString &kresResource, kresResources ) {
195 const KConfigGroup cfg( &resCfg, QString::fromLatin1(
"Resource_%1" ).arg( kresResource ) );
196 if ( cfg.readEntry(
"ResourceType", QString() ) != QLatin1String(
"akonadi" ) ) {
197 legacyResourceFound =
true;
201 if ( legacyResourceFound ) {
202 kDebug() <<
"ignoring " << mCurrentDefault->name() <<
" as there is a KResource setup for its type already.";
203 KConfigGroup cfg( mConfig,
"ProcessedDefaults" );
204 cfg.writeEntry( agentCfg.readEntry(
"Id", QString() ), QString::fromLatin1(
"kres" ) );
213 connect( job, SIGNAL(result(KJob*)), SLOT(instanceCreated(KJob*)) );
217 void Firstrun::instanceCreated( KJob *job )
219 Q_ASSERT( mCurrentDefault );
221 if ( job->error() ) {
222 kError() <<
"Creating agent instance failed for " << mCurrentDefault->name();
228 const KConfigGroup agentCfg = KConfigGroup( mCurrentDefault,
"Agent" );
229 const QString agentName = agentCfg.readEntry(
"Name", QString() );
230 if ( !agentName.isEmpty() )
234 const KConfigGroup settings = KConfigGroup( mCurrentDefault,
"Settings" );
236 QDBusInterface *iface =
new QDBusInterface( QString::fromLatin1(
"org.freedesktop.Akonadi.Agent.%1" ).arg( instance.
identifier() ),
237 QLatin1String(
"/Settings" ), QString(),
238 DBusConnectionPool::threadConnection(), this );
239 if ( !iface->isValid() ) {
240 kError() <<
"Unable to obtain the KConfigXT D-Bus interface of " << instance.
identifier();
246 foreach (
const QString &setting, settings.keyList() ) {
247 kDebug() <<
"Setting up " << setting <<
" for agent " << instance.
identifier();
248 const QString methodName = QString::fromLatin1(
"set%1" ).arg( setting );
249 const QVariant::Type argType = argumentType( iface->metaObject(), methodName );
250 if ( argType == QVariant::Invalid ) {
251 kError() <<
"Setting " << setting <<
" not found in agent configuration interface of " << instance.
identifier();
256 if ( argType == QVariant::String ) {
259 arg = settings.readPathEntry( setting, QString() );
261 arg = settings.readEntry( setting, QVariant( argType ) );
263 const QDBusReply<void> reply = iface->call( methodName, arg );
264 if ( !reply.isValid() )
265 kError() <<
"Setting " << setting <<
" failed for agent " << instance.
identifier();
268 iface->call( QLatin1String(
"writeConfig" ) );
275 KConfigGroup cfg( mConfig,
"ProcessedDefaults" );
276 cfg.writeEntry( agentCfg.readEntry(
"Id", QString() ), instance.
identifier() );
282 QVariant::Type Firstrun::argumentType(
const QMetaObject *mo,
const QString &method )
285 for (
int i = 0; i < mo->methodCount(); ++i ) {
286 const QString signature = QString::fromLatin1( mo->method( i ).signature() );
287 if ( signature.startsWith( method ) )
291 if ( !m.signature() )
292 return QVariant::Invalid;
294 const QList<QByteArray> argTypes = m.parameterTypes();
295 if ( argTypes.count() != 1 )
296 return QVariant::Invalid;
298 return QVariant::nameToType( argTypes.first() );
301 #include "firstrun_p.moc"