• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • 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 
00022 #include <akonadi/agentinstance.h>
00023 #include <akonadi/agentinstancecreatejob.h>
00024 #include <akonadi/agentmanager.h>
00025 #include <akonadi/agenttype.h>
00026 
00027 #include <KConfig>
00028 #include <KConfigGroup>
00029 #include <KDebug>
00030 #include <KGlobal>
00031 #include <KProcess>
00032 #include <KStandardDirs>
00033 
00034 #include <QtDBus/QDBusConnection>
00035 #include <QtDBus/QDBusInterface>
00036 #include <QtDBus/QDBusReply>
00037 #include <QtCore/QDir>
00038 #include <QtCore/QMetaMethod>
00039 #include <QtCore/QMetaObject>
00040 
00041 using namespace Akonadi;
00042 
00043 Firstrun::Firstrun( QObject *parent )
00044   : QObject( parent ),
00045     mConfig( new KConfig( QLatin1String( "akonadi-firstrunrc" ) ) ),
00046     mCurrentDefault( 0 ),
00047     mProcess( 0 )
00048 {
00049   findPendingDefaults();
00050   kDebug() << mPendingDefaults;
00051   setupNext();
00052 }
00053 
00054 Firstrun::~Firstrun()
00055 {
00056   delete mConfig;
00057   kDebug() << "done";
00058 }
00059 
00060 void Firstrun::findPendingDefaults()
00061 {
00062   const KConfigGroup cfg( mConfig, "ProcessedDefaults" );
00063   foreach ( const QString &dirName, KGlobal::dirs()->findDirs( "data", QLatin1String( "akonadi/firstrun" ) ) ) {
00064     const QStringList files = QDir( dirName ).entryList( QDir::Files | QDir::Readable );
00065     foreach ( const QString &fileName, files ) {
00066       const QString fullName = dirName + fileName;
00067       KConfig c( fullName );
00068       const QString id = KConfigGroup( &c, "Agent" ).readEntry( "Id", QString() );
00069       if ( id.isEmpty() ) {
00070         kWarning() << "Found invalid default configuration in " << fullName;
00071         continue;
00072       }
00073       if ( cfg.hasKey( id ) )
00074         continue;
00075       mPendingDefaults << dirName + fileName;
00076     }
00077   }
00078 }
00079 
00080 static QString resourceTypeForMimetype( const QStringList &mimeTypes )
00081 {
00082   if ( mimeTypes.contains( QLatin1String( "text/directory" ) ) )
00083     return QString::fromLatin1( "contact" );
00084   if ( mimeTypes.contains( QLatin1String( "text/calendar" ) ) )
00085     return QString::fromLatin1( "calendar" );
00086   // TODO notes
00087   return QString();
00088 }
00089 
00090 void Firstrun::migrateKresType( const QString& resourceFamily )
00091 {
00092   mResourceFamily = resourceFamily;
00093   KConfig config( QLatin1String( "kres-migratorrc" ) );
00094   KConfigGroup migrationCfg( &config, "Migration" );
00095   const bool enabled = migrationCfg.readEntry( "Enabled", false );
00096   const bool setupClientBridge = migrationCfg.readEntry( "SetupClientBridge", true );
00097   const int currentVersion = migrationCfg.readEntry( QString::fromLatin1( "Version-%1" ).arg( resourceFamily ), 0 );
00098   const int targetVersion = migrationCfg.readEntry( "TargetVersion", 0 );
00099   if ( enabled && currentVersion < targetVersion ) {
00100     kDebug() << "Performing migration of legacy KResource settings. Good luck!";
00101     mProcess = new KProcess( this );
00102     connect( mProcess, SIGNAL( finished( int ) ), SLOT( migrationFinished( int ) ) );
00103     QStringList args = QStringList() << QLatin1String( "--interactive-on-change" )
00104                                      << QLatin1String( "--type" ) << resourceFamily;
00105     if ( !setupClientBridge )
00106       args << QLatin1String( "--omit-client-bridge" );
00107     mProcess->setProgram( QLatin1String( "kres-migrator" ), args );
00108     mProcess->start();
00109     if ( !mProcess->waitForStarted() )
00110       migrationFinished( -1 );
00111   } else {
00112     // nothing to do
00113     setupNext();
00114   }
00115 }
00116 
00117 void Firstrun::migrationFinished( int exitCode )
00118 {
00119   Q_ASSERT( mProcess );
00120   if ( exitCode == 0 ) {
00121     kDebug() << "KResource -> Akonadi migration has been successful";
00122     KConfig config( QLatin1String( "kres-migratorrc" ) );
00123     KConfigGroup migrationCfg( &config, "Migration" );
00124     const int targetVersion = migrationCfg.readEntry( "TargetVersion", 0 );
00125     migrationCfg.writeEntry( QString::fromLatin1( "Version-%1" ).arg( mResourceFamily ), targetVersion );
00126     migrationCfg.sync();
00127   } else if ( exitCode != 1 ) {
00128     // exit code 1 means it is already running, so we are probably called by a migrator instance
00129     kError() << "KResource -> Akonadi migration failed!";
00130     kError() << "command was: " << mProcess->program();
00131     kError() << "exit code: " << mProcess->exitCode();
00132     kError() << "stdout: " << mProcess->readAllStandardOutput();
00133     kError() << "stderr: " << mProcess->readAllStandardError();
00134   }
00135 
00136   setupNext();
00137 }
00138 
00139 
00140 void Firstrun::setupNext()
00141 {
00142   delete mCurrentDefault;
00143   mCurrentDefault = 0;
00144 
00145   if ( mPendingDefaults.isEmpty() ) {
00146     deleteLater();
00147     return;
00148   }
00149 
00150   mCurrentDefault = new KConfig( mPendingDefaults.takeFirst() );
00151   const KConfigGroup agentCfg = KConfigGroup( mCurrentDefault, "Agent" );
00152 
00153   AgentType type = AgentManager::self()->type( agentCfg.readEntry( "Type", QString() ) );
00154   if ( !type.isValid() ) {
00155     kError() << "Unable to obtain agent type for default resource agent configuration " << mCurrentDefault->name();
00156     setupNext();
00157     return;
00158   }
00159 
00160   // KDE5: remove me
00161   // check if there is a kresource setup for this type already
00162   const QString kresType = resourceTypeForMimetype( type.mimeTypes() );
00163   if ( !kresType.isEmpty() ) {
00164     const QString kresCfgFile = KStandardDirs::locateLocal( "config", QString::fromLatin1( "kresources/%1/stdrc" ).arg( kresType ) );
00165     KConfig resCfg( kresCfgFile );
00166     const KConfigGroup resGroup( &resCfg, "General" );
00167     bool legacyResourceFound = false;
00168     const QStringList kresResources = resGroup.readEntry( "ResourceKeys", QStringList() )
00169       + resGroup.readEntry( "PassiveResourceKeys", QStringList() );
00170     foreach ( const QString &kresResource, kresResources ) {
00171       const KConfigGroup cfg( &resCfg, QString::fromLatin1( "Resource_%1" ).arg( kresResource ) );
00172       if ( cfg.readEntry( "ResourceType", QString() ) != QLatin1String( "akonadi" ) ) { // not a bridge
00173         legacyResourceFound = true;
00174         break;
00175       }
00176     }
00177     if ( legacyResourceFound ) {
00178       kDebug() << "ignoring " << mCurrentDefault->name() << " as there is a KResource setup for its type already.";
00179       KConfigGroup cfg( mConfig, "ProcessedDefaults" );
00180       cfg.writeEntry( agentCfg.readEntry( "Id", QString() ), QString::fromLatin1( "kres" ) );
00181       cfg.sync();
00182       migrateKresType( kresType );
00183       return;
00184     }
00185   }
00186 
00187   AgentInstanceCreateJob *job = new AgentInstanceCreateJob( type );
00188   connect( job, SIGNAL( result( KJob* ) ), SLOT( instanceCreated( KJob* ) ) );
00189   job->start();
00190 }
00191 
00192 void Firstrun::instanceCreated( KJob *job )
00193 {
00194   Q_ASSERT( mCurrentDefault );
00195 
00196   if ( job->error() ) {
00197     kError() << "Creating agent instance failed for " << mCurrentDefault->name();
00198     setupNext();
00199     return;
00200   }
00201 
00202   AgentInstance instance = static_cast<AgentInstanceCreateJob*>( job )->instance();
00203   const KConfigGroup agentCfg = KConfigGroup( mCurrentDefault, "Agent" );
00204   const QString agentName = agentCfg.readEntry( "Name", QString() );
00205   if ( !agentName.isEmpty() )
00206     instance.setName( agentName );
00207 
00208   // agent specific settings, using the D-Bus <-> KConfigXT bridge
00209   const KConfigGroup settings = KConfigGroup( mCurrentDefault, "Settings" );
00210 
00211   QDBusInterface *iface = new QDBusInterface( QString::fromLatin1( "org.freedesktop.Akonadi.Agent.%1" ).arg( instance.identifier() ),
00212                                               QLatin1String( "/Settings" ), QString(), QDBusConnection::sessionBus(), this );
00213   if ( !iface->isValid() ) {
00214     kError() << "Unable to obtain the KConfigXT D-Bus interface of " << instance.identifier();
00215     setupNext();
00216     delete iface;
00217     return;
00218   }
00219 
00220   foreach ( const QString &setting, settings.keyList() ) {
00221     kDebug() << "Setting up " << setting << " for agent " << instance.identifier();
00222     const QString methodName = QString::fromLatin1( "set%1" ).arg( setting );
00223     const QVariant::Type argType = argumentType( iface->metaObject(), methodName );
00224     if ( argType == QVariant::Invalid ) {
00225       kError() << "Setting " << setting << " not found in agent configuration interface of " << instance.identifier();
00226       continue;
00227     }
00228 
00229     QVariant arg;
00230     if ( argType == QVariant::String ) {
00231       // Since a string could be a path we always use readPathEntry here,
00232       // that shouldn't harm any normal string settings
00233       arg = settings.readPathEntry( setting, QString() );
00234     } else
00235       arg = settings.readEntry( setting, QVariant( argType ) );
00236 
00237     const QDBusReply<void> reply = iface->call( methodName, arg );
00238     if ( !reply.isValid() )
00239       kError() << "Setting " << setting << " failed for agent " << instance.identifier();
00240   }
00241 
00242   instance.reconfigure();
00243   instance.synchronize();
00244   delete iface;
00245 
00246   // remember we set this one up already
00247   KConfigGroup cfg( mConfig, "ProcessedDefaults" );
00248   cfg.writeEntry( agentCfg.readEntry( "Id", QString() ), instance.identifier() );
00249   cfg.sync();
00250 
00251   setupNext();
00252 }
00253 
00254 QVariant::Type Firstrun::argumentType( const QMetaObject *mo, const QString &method )
00255 {
00256   QMetaMethod m;
00257   for ( int i = 0; i < mo->methodCount(); ++i ) {
00258     const QString signature = QString::fromLatin1( mo->method( i ).signature() );
00259     if ( signature.startsWith( method ) )
00260       m = mo->method( i );
00261   }
00262 
00263   if ( !m.signature() )
00264     return QVariant::Invalid;
00265 
00266   const QList<QByteArray> argTypes = m.parameterTypes();
00267   if ( argTypes.count() != 1 )
00268     return QVariant::Invalid;
00269 
00270   return QVariant::nameToType( argTypes.first() );
00271 }
00272 
00273 #include "firstrun_p.moc"

akonadi

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

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kblog
  • kcal
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.6.2-20100208
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal