• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.8.3 API Reference
  • KDE Home
  • Contact Us
 

akonadi

firstrun.cpp
00001 /*
00002     Copyright (c) 2008 Volker Krause <vkrause@kde.org>
00003 
00004     This library is free software; you can redistribute it and/or modify it
00005     under the terms of the GNU Library General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or (at your
00007     option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful, but WITHOUT
00010     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00011     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00012     License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to the
00016     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017     02110-1301, USA.
00018 */
00019 
00020 #include "firstrun_p.h"
00021 #include "dbusconnectionpool.h"
00022 
00023 #include <akonadi/agentinstance.h>
00024 #include <akonadi/agentinstancecreatejob.h>
00025 #include <akonadi/agentmanager.h>
00026 #include <akonadi/agenttype.h>
00027 
00028 #include <KConfig>
00029 #include <KConfigGroup>
00030 #include <KDebug>
00031 #include <KGlobal>
00032 #include <KProcess>
00033 #include <KStandardDirs>
00034 
00035 #include <QtDBus/QDBusConnection>
00036 #include <QtDBus/QDBusInterface>
00037 #include <QtDBus/QDBusReply>
00038 #include <QtCore/QDir>
00039 #include <QtCore/QMetaMethod>
00040 #include <QtCore/QMetaObject>
00041 
00042 static char FIRSTRUN_DBUSLOCK[] = "org.kde.Akonadi.Firstrun.lock";
00043 
00044 using namespace Akonadi;
00045 
00046 Firstrun::Firstrun( QObject *parent )
00047   : QObject( parent ),
00048     mConfig( new KConfig( QLatin1String( "akonadi-firstrunrc" ) ) ),
00049     mCurrentDefault( 0 ),
00050     mProcess( 0 )
00051 {
00052   kDebug();
00053   if ( DBusConnectionPool::threadConnection().registerService( QLatin1String( FIRSTRUN_DBUSLOCK ) ) ) {
00054     findPendingDefaults();
00055     kDebug() << mPendingDefaults;
00056     setupNext();
00057   } else {
00058     kDebug() << "D-Bus lock found, so someone else does the work for us already.";
00059     deleteLater();
00060   }
00061 }
00062 
00063 Firstrun::~Firstrun()
00064 {
00065   DBusConnectionPool::threadConnection().unregisterService( QLatin1String( FIRSTRUN_DBUSLOCK ) );
00066   delete mConfig;
00067   kDebug() << "done";
00068 }
00069 
00070 void Firstrun::findPendingDefaults()
00071 {
00072   const KConfigGroup cfg( mConfig, "ProcessedDefaults" );
00073   foreach ( const QString &dirName, KGlobal::dirs()->findDirs( "data", QLatin1String( "akonadi/firstrun" ) ) ) {
00074     const QStringList files = QDir( dirName ).entryList( QDir::Files | QDir::Readable );
00075     foreach ( const QString &fileName, files ) {
00076       const QString fullName = dirName + fileName;
00077       KConfig c( fullName );
00078       const QString id = KConfigGroup( &c, "Agent" ).readEntry( "Id", QString() );
00079       if ( id.isEmpty() ) {
00080         kWarning() << "Found invalid default configuration in " << fullName;
00081         continue;
00082       }
00083       if ( cfg.hasKey( id ) )
00084         continue;
00085       mPendingDefaults << dirName + fileName;
00086     }
00087   }
00088 
00089 #ifndef KDEPIM_NO_KRESOURCES
00090   // always check legacy kres for migration, their migrator might have changed again
00091   mPendingKres << QLatin1String("contact") << QLatin1String("calendar");
00092 #endif
00093 }
00094 
00095 #ifndef KDEPIM_NO_KRESOURCES
00096 static QString resourceTypeForMimetype( const QStringList &mimeTypes )
00097 {
00098   if ( mimeTypes.contains( QLatin1String( "text/directory" ) ) )
00099     return QString::fromLatin1( "contact" );
00100   if ( mimeTypes.contains( QLatin1String( "text/calendar" ) ) )
00101     return QString::fromLatin1( "calendar" );
00102   // TODO notes
00103   return QString();
00104 }
00105 
00106 void Firstrun::migrateKresType( const QString& resourceFamily )
00107 {
00108   mResourceFamily = resourceFamily;
00109   KConfig config( QLatin1String( "kres-migratorrc" ) );
00110   KConfigGroup migrationCfg( &config, "Migration" );
00111   const bool enabled = migrationCfg.readEntry( "Enabled", false );
00112   const bool setupClientBridge = migrationCfg.readEntry( "SetupClientBridge", true );
00113   const int currentVersion = migrationCfg.readEntry( QString::fromLatin1( "Version-%1" ).arg( resourceFamily ), 0 );
00114   const int targetVersion = migrationCfg.readEntry( "TargetVersion", 0 );
00115   if ( enabled && currentVersion < targetVersion ) {
00116     kDebug() << "Performing migration of legacy KResource settings. Good luck!";
00117     mProcess = new KProcess( this );
00118     connect( mProcess, SIGNAL(finished(int)), SLOT(migrationFinished(int)) );
00119     QStringList args = QStringList() << QLatin1String( "--interactive-on-change" )
00120                                      << QLatin1String( "--type" ) << resourceFamily;
00121     if ( !setupClientBridge )
00122       args << QLatin1String( "--omit-client-bridge" );
00123     mProcess->setProgram( QLatin1String( "kres-migrator" ), args );
00124     mProcess->start();
00125     if ( !mProcess->waitForStarted() )
00126       migrationFinished( -1 );
00127   } else {
00128     // nothing to do
00129     setupNext();
00130   }
00131 }
00132 
00133 void Firstrun::migrationFinished( int exitCode )
00134 {
00135   Q_ASSERT( mProcess );
00136   if ( exitCode == 0 ) {
00137     kDebug() << "KResource -> Akonadi migration has been successful";
00138     KConfig config( QLatin1String( "kres-migratorrc" ) );
00139     KConfigGroup migrationCfg( &config, "Migration" );
00140     const int targetVersion = migrationCfg.readEntry( "TargetVersion", 0 );
00141     migrationCfg.writeEntry( QString::fromLatin1( "Version-%1" ).arg( mResourceFamily ), targetVersion );
00142     migrationCfg.sync();
00143   } else if ( exitCode != 1 ) {
00144     // exit code 1 means it is already running, so we are probably called by a migrator instance
00145     kError() << "KResource -> Akonadi migration failed!";
00146     kError() << "command was: " << mProcess->program();
00147     kError() << "exit code: " << mProcess->exitCode();
00148     kError() << "stdout: " << mProcess->readAllStandardOutput();
00149     kError() << "stderr: " << mProcess->readAllStandardError();
00150   }
00151 
00152   setupNext();
00153 }
00154 #endif
00155 
00156 
00157 void Firstrun::setupNext()
00158 {
00159   delete mCurrentDefault;
00160   mCurrentDefault = 0;
00161 
00162   if ( mPendingDefaults.isEmpty() ) {
00163 #ifndef KDEPIM_NO_KRESOURCES
00164     if ( !mPendingKres.isEmpty() ) {
00165       migrateKresType( mPendingKres.takeFirst() );
00166       return;
00167     }
00168 #endif
00169     deleteLater();
00170     return;
00171   }
00172 
00173   mCurrentDefault = new KConfig( mPendingDefaults.takeFirst() );
00174   const KConfigGroup agentCfg = KConfigGroup( mCurrentDefault, "Agent" );
00175 
00176   AgentType type = AgentManager::self()->type( agentCfg.readEntry( "Type", QString() ) );
00177   if ( !type.isValid() ) {
00178     kError() << "Unable to obtain agent type for default resource agent configuration " << mCurrentDefault->name();
00179     setupNext();
00180     return;
00181   }
00182 
00183 #ifndef KDEPIM_NO_KRESOURCES
00184   // KDE5: remove me
00185   // check if there is a kresource setup for this type already
00186   const QString kresType = resourceTypeForMimetype( type.mimeTypes() );
00187   if ( !kresType.isEmpty() ) {
00188     const QString kresCfgFile = KStandardDirs::locateLocal( "config", QString::fromLatin1( "kresources/%1/stdrc" ).arg( kresType ) );
00189     KConfig resCfg( kresCfgFile );
00190     const KConfigGroup resGroup( &resCfg, "General" );
00191     bool legacyResourceFound = false;
00192     const QStringList kresResources = resGroup.readEntry( "ResourceKeys", QStringList() )
00193       + resGroup.readEntry( "PassiveResourceKeys", QStringList() );
00194     foreach ( const QString &kresResource, kresResources ) {
00195       const KConfigGroup cfg( &resCfg, QString::fromLatin1( "Resource_%1" ).arg( kresResource ) );
00196       if ( cfg.readEntry( "ResourceType", QString() ) != QLatin1String( "akonadi" ) ) { // not a bridge
00197         legacyResourceFound = true;
00198         break;
00199       }
00200     }
00201     if ( legacyResourceFound ) {
00202       kDebug() << "ignoring " << mCurrentDefault->name() << " as there is a KResource setup for its type already.";
00203       KConfigGroup cfg( mConfig, "ProcessedDefaults" );
00204       cfg.writeEntry( agentCfg.readEntry( "Id", QString() ), QString::fromLatin1( "kres" ) );
00205       cfg.sync();
00206       setupNext();
00207       return;
00208     }
00209   }
00210 #endif
00211 
00212   AgentInstanceCreateJob *job = new AgentInstanceCreateJob( type );
00213   connect( job, SIGNAL(result(KJob*)), SLOT(instanceCreated(KJob*)) );
00214   job->start();
00215 }
00216 
00217 void Firstrun::instanceCreated( KJob *job )
00218 {
00219   Q_ASSERT( mCurrentDefault );
00220 
00221   if ( job->error() ) {
00222     kError() << "Creating agent instance failed for " << mCurrentDefault->name();
00223     setupNext();
00224     return;
00225   }
00226 
00227   AgentInstance instance = static_cast<AgentInstanceCreateJob*>( job )->instance();
00228   const KConfigGroup agentCfg = KConfigGroup( mCurrentDefault, "Agent" );
00229   const QString agentName = agentCfg.readEntry( "Name", QString() );
00230   if ( !agentName.isEmpty() )
00231     instance.setName( agentName );
00232 
00233   // agent specific settings, using the D-Bus <-> KConfigXT bridge
00234   const KConfigGroup settings = KConfigGroup( mCurrentDefault, "Settings" );
00235 
00236   QDBusInterface *iface = new QDBusInterface( QString::fromLatin1( "org.freedesktop.Akonadi.Agent.%1" ).arg( instance.identifier() ),
00237                                               QLatin1String( "/Settings" ), QString(),
00238                                               DBusConnectionPool::threadConnection(), this );
00239   if ( !iface->isValid() ) {
00240     kError() << "Unable to obtain the KConfigXT D-Bus interface of " << instance.identifier();
00241     setupNext();
00242     delete iface;
00243     return;
00244   }
00245 
00246   foreach ( const QString &setting, settings.keyList() ) {
00247     kDebug() << "Setting up " << setting << " for agent " << instance.identifier();
00248     const QString methodName = QString::fromLatin1( "set%1" ).arg( setting );
00249     const QVariant::Type argType = argumentType( iface->metaObject(), methodName );
00250     if ( argType == QVariant::Invalid ) {
00251       kError() << "Setting " << setting << " not found in agent configuration interface of " << instance.identifier();
00252       continue;
00253     }
00254 
00255     QVariant arg;
00256     if ( argType == QVariant::String ) {
00257       // Since a string could be a path we always use readPathEntry here,
00258       // that shouldn't harm any normal string settings
00259       arg = settings.readPathEntry( setting, QString() );
00260     } else
00261       arg = settings.readEntry( setting, QVariant( argType ) );
00262 
00263     const QDBusReply<void> reply = iface->call( methodName, arg );
00264     if ( !reply.isValid() )
00265       kError() << "Setting " << setting << " failed for agent " << instance.identifier();
00266   }
00267 
00268   iface->call( QLatin1String( "writeConfig" ) );
00269 
00270   instance.reconfigure();
00271   instance.synchronize();
00272   delete iface;
00273 
00274   // remember we set this one up already
00275   KConfigGroup cfg( mConfig, "ProcessedDefaults" );
00276   cfg.writeEntry( agentCfg.readEntry( "Id", QString() ), instance.identifier() );
00277   cfg.sync();
00278 
00279   setupNext();
00280 }
00281 
00282 QVariant::Type Firstrun::argumentType( const QMetaObject *mo, const QString &method )
00283 {
00284   QMetaMethod m;
00285   for ( int i = 0; i < mo->methodCount(); ++i ) {
00286     const QString signature = QString::fromLatin1( mo->method( i ).signature() );
00287     if ( signature.startsWith( method ) )
00288       m = mo->method( i );
00289   }
00290 
00291   if ( !m.signature() )
00292     return QVariant::Invalid;
00293 
00294   const QList<QByteArray> argTypes = m.parameterTypes();
00295   if ( argTypes.count() != 1 )
00296     return QVariant::Invalid;
00297 
00298   return QVariant::nameToType( argTypes.first() );
00299 }
00300 
00301 #include "firstrun_p.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu May 10 2012 22:18:33 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs-4.8.3 API Reference

Skip menu "kdepimlibs-4.8.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal