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();
166 void Firstrun::setupNext()
168 delete mCurrentDefault;
171 if ( mPendingDefaults.isEmpty() ) {
172 #ifndef KDEPIM_NO_KRESOURCES
173 if ( !mPendingKres.isEmpty() ) {
174 migrateKresType( mPendingKres.takeFirst() );
182 mCurrentDefault =
new KConfig( mPendingDefaults.takeFirst() );
183 const KConfigGroup agentCfg = KConfigGroup( mCurrentDefault,
"Agent" );
187 kError() <<
"Unable to obtain agent type for default resource agent configuration " << mCurrentDefault->name();
192 #ifndef KDEPIM_NO_KRESOURCES
195 const QString kresType = resourceTypeForMimetype( type.
mimeTypes() );
196 if ( !kresType.isEmpty() ) {
197 const QString kresCfgFile = KStandardDirs::locateLocal(
"config", QString::fromLatin1(
"kresources/%1/stdrc" ).arg( kresType ) );
198 KConfig resCfg( kresCfgFile );
199 const KConfigGroup resGroup( &resCfg,
"General" );
200 bool legacyResourceFound =
false;
201 const QStringList kresResources = resGroup.readEntry(
"ResourceKeys", QStringList() )
202 + resGroup.readEntry(
"PassiveResourceKeys", QStringList() );
203 foreach (
const QString &kresResource, kresResources ) {
204 const KConfigGroup cfg( &resCfg, QString::fromLatin1(
"Resource_%1" ).arg( kresResource ) );
205 if ( cfg.readEntry(
"ResourceType", QString() ) != QLatin1String(
"akonadi" ) ) {
206 legacyResourceFound =
true;
210 if ( legacyResourceFound ) {
211 kDebug() <<
"ignoring " << mCurrentDefault->name() <<
" as there is a KResource setup for its type already.";
212 KConfigGroup cfg( mConfig,
"ProcessedDefaults" );
213 cfg.writeEntry( agentCfg.readEntry(
"Id", QString() ), QString::fromLatin1(
"kres" ) );
222 connect( job, SIGNAL(result(KJob*)), SLOT(instanceCreated(KJob*)) );
226 void Firstrun::instanceCreated( KJob *job )
228 Q_ASSERT( mCurrentDefault );
230 if ( job->error() ) {
231 kError() <<
"Creating agent instance failed for " << mCurrentDefault->name();
237 const KConfigGroup agentCfg = KConfigGroup( mCurrentDefault,
"Agent" );
238 const QString agentName = agentCfg.readEntry(
"Name", QString() );
239 if ( !agentName.isEmpty() )
243 const KConfigGroup settings = KConfigGroup( mCurrentDefault,
"Settings" );
245 QDBusInterface *iface =
new QDBusInterface( QString::fromLatin1(
"org.freedesktop.Akonadi.Agent.%1" ).arg( instance.
identifier() ),
246 QLatin1String(
"/Settings" ), QString(),
247 DBusConnectionPool::threadConnection(), this );
248 if ( !iface->isValid() ) {
249 kError() <<
"Unable to obtain the KConfigXT D-Bus interface of " << instance.
identifier();
255 foreach (
const QString &setting, settings.keyList() ) {
256 kDebug() <<
"Setting up " << setting <<
" for agent " << instance.
identifier();
257 const QString methodName = QString::fromLatin1(
"set%1" ).arg( setting );
258 const QVariant::Type argType = argumentType( iface->metaObject(), methodName );
259 if ( argType == QVariant::Invalid ) {
260 kError() <<
"Setting " << setting <<
" not found in agent configuration interface of " << instance.
identifier();
265 if ( argType == QVariant::String ) {
268 arg = settings.readPathEntry( setting, QString() );
270 arg = settings.readEntry( setting, QVariant( argType ) );
272 const QDBusReply<void> reply = iface->call( methodName, arg );
273 if ( !reply.isValid() )
274 kError() <<
"Setting " << setting <<
" failed for agent " << instance.
identifier();
277 iface->call( QLatin1String(
"writeConfig" ) );
284 KConfigGroup cfg( mConfig,
"ProcessedDefaults" );
285 cfg.writeEntry( agentCfg.readEntry(
"Id", QString() ), instance.
identifier() );
291 QVariant::Type Firstrun::argumentType(
const QMetaObject *mo,
const QString &method )
294 for (
int i = 0; i < mo->methodCount(); ++i ) {
295 const QString signature = QString::fromLatin1( mo->method( i ).signature() );
296 if ( signature.startsWith( method ) )
300 if ( !m.signature() )
301 return QVariant::Invalid;
303 const QList<QByteArray> argTypes = m.parameterTypes();
304 if ( argTypes.count() != 1 )
305 return QVariant::Invalid;
307 return QVariant::nameToType( argTypes.first() );
310 #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.