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"
void synchronize()
Triggers the agent instance to start synchronization.
bool isValid() const
Returns whether the agent type is valid.
QString identifier() const
Returns the unique identifier of the agent instance.
Provides methods to control the Akonadi server process.
A representation of an agent type.
QStringList mimeTypes() const
Returns the list of supported mime types of the agent 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 ...
void setName(const QString &name)
Sets the user visible name of the agent instance.
Job for creating new agent instances.
static AgentManager * self()
Returns the global instance of the agent manager.
A representation of an agent instance.
static bool hasInstanceIdentifier()
Returns true if we are connected to a non-default Akonadi server instance.
void start()
Starts the instance creation.
void reconfigure() const
Tell the agent that its configuration has been changed remotely via D-Bus.