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";
45 using namespace Akonadi;
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;
84 KConfig c( fullName );
85 const QString
id = KConfigGroup( &c,
"Agent" ).readEntry(
"Id", QString() );
87 kWarning() <<
"Found invalid default configuration in " << fullName;
90 if ( cfg.hasKey(
id ) ) {
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" );
133 mProcess->setProgram( QLatin1String(
"kres-migrator" ), args );
135 if ( !mProcess->waitForStarted() )
136 migrationFinished( -1 );
143 void Firstrun::migrationFinished(
int exitCode )
145 Q_ASSERT( mProcess );
146 if ( exitCode == 0 ) {
147 kDebug() <<
"KResource -> Akonadi migration has been successful";
148 KConfig config( QLatin1String(
"kres-migratorrc" ) );
149 KConfigGroup migrationCfg( &config,
"Migration" );
150 const int targetVersion = migrationCfg.readEntry(
"TargetVersion", 0 );
151 migrationCfg.writeEntry( QString::fromLatin1(
"Version-%1" ).arg( mResourceFamily ), targetVersion );
153 }
else if ( exitCode != 1 ) {
155 kError() <<
"KResource -> Akonadi migration failed!";
156 kError() <<
"command was: " << mProcess->program();
157 kError() <<
"exit code: " << mProcess->exitCode();
158 kError() <<
"stdout: " << mProcess->readAllStandardOutput();
159 kError() <<
"stderr: " << mProcess->readAllStandardError();
167 void Firstrun::setupNext()
169 delete mCurrentDefault;
172 if ( mPendingDefaults.isEmpty() ) {
173 #ifndef KDEPIM_NO_KRESOURCES
174 if ( !mPendingKres.isEmpty() ) {
175 migrateKresType( mPendingKres.takeFirst() );
183 mCurrentDefault =
new KConfig( mPendingDefaults.takeFirst() );
184 const KConfigGroup agentCfg = KConfigGroup( mCurrentDefault,
"Agent" );
188 kError() <<
"Unable to obtain agent type for default resource agent configuration " << mCurrentDefault->name();
193 #ifndef KDEPIM_NO_KRESOURCES
196 const QString kresType = resourceTypeForMimetype( type.
mimeTypes() );
197 if ( !kresType.isEmpty() ) {
198 const QString kresCfgFile = KStandardDirs::locateLocal(
"config", QString::fromLatin1(
"kresources/%1/stdrc" ).arg( kresType ) );
199 KConfig resCfg( kresCfgFile );
200 const KConfigGroup resGroup( &resCfg,
"General" );
201 bool legacyResourceFound =
false;
202 const QStringList kresResources = resGroup.readEntry(
"ResourceKeys", QStringList() )
203 + resGroup.readEntry(
"PassiveResourceKeys", QStringList() );
204 foreach (
const QString &kresResource, kresResources ) {
205 const KConfigGroup cfg( &resCfg, QString::fromLatin1(
"Resource_%1" ).arg( kresResource ) );
206 if ( cfg.readEntry(
"ResourceType", QString() ) != QLatin1String(
"akonadi" ) ) {
207 legacyResourceFound =
true;
211 if ( legacyResourceFound ) {
212 kDebug() <<
"ignoring " << mCurrentDefault->name() <<
" as there is a KResource setup for its type already.";
213 KConfigGroup cfg( mConfig,
"ProcessedDefaults" );
214 cfg.writeEntry( agentCfg.readEntry(
"Id", QString() ), QString::fromLatin1(
"kres" ) );
223 connect( job, SIGNAL(result(KJob*)), SLOT(instanceCreated(KJob*)) );
227 void Firstrun::instanceCreated( KJob *job )
229 Q_ASSERT( mCurrentDefault );
231 if ( job->error() ) {
232 kError() <<
"Creating agent instance failed for " << mCurrentDefault->name();
238 const KConfigGroup agentCfg = KConfigGroup( mCurrentDefault,
"Agent" );
239 const QString agentName = agentCfg.readEntry(
"Name", QString() );
240 if ( !agentName.isEmpty() )
244 const KConfigGroup settings = KConfigGroup( mCurrentDefault,
"Settings" );
246 QDBusInterface *iface =
new QDBusInterface( QString::fromLatin1(
"org.freedesktop.Akonadi.Agent.%1" ).arg( instance.
identifier() ),
247 QLatin1String(
"/Settings" ), QString(),
248 DBusConnectionPool::threadConnection(), this );
249 if ( !iface->isValid() ) {
250 kError() <<
"Unable to obtain the KConfigXT D-Bus interface of " << instance.
identifier();
256 foreach (
const QString &setting, settings.keyList() ) {
257 kDebug() <<
"Setting up " << setting <<
" for agent " << instance.
identifier();
258 const QString methodName = QString::fromLatin1(
"set%1" ).arg( setting );
259 const QVariant::Type argType = argumentType( iface->metaObject(), methodName );
260 if ( argType == QVariant::Invalid ) {
261 kError() <<
"Setting " << setting <<
" not found in agent configuration interface of " << instance.
identifier();
266 if ( argType == QVariant::String ) {
269 arg = settings.readPathEntry( setting, QString() );
271 arg = settings.readEntry( setting, QVariant( argType ) );
273 const QDBusReply<void> reply = iface->call( methodName, arg );
274 if ( !reply.isValid() )
275 kError() <<
"Setting " << setting <<
" failed for agent " << instance.
identifier();
278 iface->call( QLatin1String(
"writeConfig" ) );
285 KConfigGroup cfg( mConfig,
"ProcessedDefaults" );
286 cfg.writeEntry( agentCfg.readEntry(
"Id", QString() ), instance.
identifier() );
292 QVariant::Type Firstrun::argumentType(
const QMetaObject *mo,
const QString &method )
295 for (
int i = 0; i < mo->methodCount(); ++i ) {
296 const QString signature = QString::fromLatin1( mo->method( i ).signature() );
297 if ( signature.startsWith( method ) )
301 if ( !m.signature() )
302 return QVariant::Invalid;
304 const QList<QByteArray> argTypes = m.parameterTypes();
305 if ( argTypes.count() != 1 )
306 return QVariant::Invalid;
308 return QVariant::nameToType( argTypes.first() );
311 #include "moc_firstrun_p.cpp"