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

akonadi

  • akonadi
firstrun.cpp
1 /*
2  Copyright (c) 2008 Volker Krause <vkrause@kde.org>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "firstrun_p.h"
21 #include "dbusconnectionpool.h"
22 
23 #include <akonadi/agentinstance.h>
24 #include <akonadi/agentinstancecreatejob.h>
25 #include <akonadi/agentmanager.h>
26 #include <akonadi/agenttype.h>
27 
28 #include <KConfig>
29 #include <KConfigGroup>
30 #include <KDebug>
31 #include <KGlobal>
32 #include <KProcess>
33 #include <KStandardDirs>
34 
35 #include <QtDBus/QDBusConnection>
36 #include <QtDBus/QDBusInterface>
37 #include <QtDBus/QDBusReply>
38 #include <QtCore/QDir>
39 #include <QtCore/QMetaMethod>
40 #include <QtCore/QMetaObject>
41 
42 static char FIRSTRUN_DBUSLOCK[] = "org.kde.Akonadi.Firstrun.lock";
43 
44 using namespace Akonadi;
45 
46 Firstrun::Firstrun( QObject *parent )
47  : QObject( parent ),
48  mConfig( new KConfig( QLatin1String( "akonadi-firstrunrc" ) ) ),
49  mCurrentDefault( 0 ),
50  mProcess( 0 )
51 {
52  kDebug();
53  if ( DBusConnectionPool::threadConnection().registerService( QLatin1String( FIRSTRUN_DBUSLOCK ) ) ) {
54  findPendingDefaults();
55  kDebug() << mPendingDefaults;
56  setupNext();
57  } else {
58  kDebug() << "D-Bus lock found, so someone else does the work for us already.";
59  deleteLater();
60  }
61 }
62 
63 Firstrun::~Firstrun()
64 {
65  DBusConnectionPool::threadConnection().unregisterService( QLatin1String( FIRSTRUN_DBUSLOCK ) );
66  delete mConfig;
67  kDebug() << "done";
68 }
69 
70 void Firstrun::findPendingDefaults()
71 {
72  const KConfigGroup cfg( mConfig, "ProcessedDefaults" );
73  foreach ( const QString &dirName, KGlobal::dirs()->findDirs( "data", QLatin1String( "akonadi/firstrun" ) ) ) {
74  const QStringList files = QDir( dirName ).entryList( QDir::Files | QDir::Readable );
75  foreach ( const QString &fileName, files ) {
76  const QString fullName = dirName + fileName;
77  KConfig c( fullName );
78  const QString id = KConfigGroup( &c, "Agent" ).readEntry( "Id", QString() );
79  if ( id.isEmpty() ) {
80  kWarning() << "Found invalid default configuration in " << fullName;
81  continue;
82  }
83  if ( cfg.hasKey( id ) )
84  continue;
85  mPendingDefaults << dirName + fileName;
86  }
87  }
88 
89 #ifndef KDEPIM_NO_KRESOURCES
90  // always check legacy kres for migration, their migrator might have changed again
91  mPendingKres << QLatin1String("contact") << QLatin1String("calendar");
92 #endif
93 }
94 
95 #ifndef KDEPIM_NO_KRESOURCES
96 static QString resourceTypeForMimetype( const QStringList &mimeTypes )
97 {
98  if ( mimeTypes.contains( QLatin1String( "text/directory" ) ) )
99  return QString::fromLatin1( "contact" );
100  if ( mimeTypes.contains( QLatin1String( "text/calendar" ) ) )
101  return QString::fromLatin1( "calendar" );
102  // TODO notes
103  return QString();
104 }
105 
106 void Firstrun::migrateKresType( const QString& resourceFamily )
107 {
108  mResourceFamily = resourceFamily;
109  KConfig config( QLatin1String( "kres-migratorrc" ) );
110  KConfigGroup migrationCfg( &config, "Migration" );
111  const bool enabled = migrationCfg.readEntry( "Enabled", false );
112  const bool setupClientBridge = migrationCfg.readEntry( "SetupClientBridge", true );
113  const int currentVersion = migrationCfg.readEntry( QString::fromLatin1( "Version-%1" ).arg( resourceFamily ), 0 );
114  const int targetVersion = migrationCfg.readEntry( "TargetVersion", 0 );
115  if ( enabled && currentVersion < targetVersion ) {
116  kDebug() << "Performing migration of legacy KResource settings. Good luck!";
117  mProcess = new KProcess( this );
118  connect( mProcess, SIGNAL(finished(int)), SLOT(migrationFinished(int)) );
119  QStringList args = QStringList() << QLatin1String( "--interactive-on-change" )
120  << QLatin1String( "--type" ) << resourceFamily;
121  if ( !setupClientBridge )
122  args << QLatin1String( "--omit-client-bridge" );
123  mProcess->setProgram( QLatin1String( "kres-migrator" ), args );
124  mProcess->start();
125  if ( !mProcess->waitForStarted() )
126  migrationFinished( -1 );
127  } else {
128  // nothing to do
129  setupNext();
130  }
131 }
132 
133 void Firstrun::migrationFinished( int exitCode )
134 {
135  Q_ASSERT( mProcess );
136  if ( exitCode == 0 ) {
137  kDebug() << "KResource -> Akonadi migration has been successful";
138  KConfig config( QLatin1String( "kres-migratorrc" ) );
139  KConfigGroup migrationCfg( &config, "Migration" );
140  const int targetVersion = migrationCfg.readEntry( "TargetVersion", 0 );
141  migrationCfg.writeEntry( QString::fromLatin1( "Version-%1" ).arg( mResourceFamily ), targetVersion );
142  migrationCfg.sync();
143  } else if ( exitCode != 1 ) {
144  // exit code 1 means it is already running, so we are probably called by a migrator instance
145  kError() << "KResource -> Akonadi migration failed!";
146  kError() << "command was: " << mProcess->program();
147  kError() << "exit code: " << mProcess->exitCode();
148  kError() << "stdout: " << mProcess->readAllStandardOutput();
149  kError() << "stderr: " << mProcess->readAllStandardError();
150  }
151 
152  setupNext();
153 }
154 #endif
155 
156 
157 void Firstrun::setupNext()
158 {
159  delete mCurrentDefault;
160  mCurrentDefault = 0;
161 
162  if ( mPendingDefaults.isEmpty() ) {
163 #ifndef KDEPIM_NO_KRESOURCES
164  if ( !mPendingKres.isEmpty() ) {
165  migrateKresType( mPendingKres.takeFirst() );
166  return;
167  }
168 #endif
169  deleteLater();
170  return;
171  }
172 
173  mCurrentDefault = new KConfig( mPendingDefaults.takeFirst() );
174  const KConfigGroup agentCfg = KConfigGroup( mCurrentDefault, "Agent" );
175 
176  AgentType type = AgentManager::self()->type( agentCfg.readEntry( "Type", QString() ) );
177  if ( !type.isValid() ) {
178  kError() << "Unable to obtain agent type for default resource agent configuration " << mCurrentDefault->name();
179  setupNext();
180  return;
181  }
182 
183 #ifndef KDEPIM_NO_KRESOURCES
184  // KDE5: remove me
185  // check if there is a kresource setup for this type already
186  const QString kresType = resourceTypeForMimetype( type.mimeTypes() );
187  if ( !kresType.isEmpty() ) {
188  const QString kresCfgFile = KStandardDirs::locateLocal( "config", QString::fromLatin1( "kresources/%1/stdrc" ).arg( kresType ) );
189  KConfig resCfg( kresCfgFile );
190  const KConfigGroup resGroup( &resCfg, "General" );
191  bool legacyResourceFound = false;
192  const QStringList kresResources = resGroup.readEntry( "ResourceKeys", QStringList() )
193  + resGroup.readEntry( "PassiveResourceKeys", QStringList() );
194  foreach ( const QString &kresResource, kresResources ) {
195  const KConfigGroup cfg( &resCfg, QString::fromLatin1( "Resource_%1" ).arg( kresResource ) );
196  if ( cfg.readEntry( "ResourceType", QString() ) != QLatin1String( "akonadi" ) ) { // not a bridge
197  legacyResourceFound = true;
198  break;
199  }
200  }
201  if ( legacyResourceFound ) {
202  kDebug() << "ignoring " << mCurrentDefault->name() << " as there is a KResource setup for its type already.";
203  KConfigGroup cfg( mConfig, "ProcessedDefaults" );
204  cfg.writeEntry( agentCfg.readEntry( "Id", QString() ), QString::fromLatin1( "kres" ) );
205  cfg.sync();
206  setupNext();
207  return;
208  }
209  }
210 #endif
211 
212  AgentInstanceCreateJob *job = new AgentInstanceCreateJob( type );
213  connect( job, SIGNAL(result(KJob*)), SLOT(instanceCreated(KJob*)) );
214  job->start();
215 }
216 
217 void Firstrun::instanceCreated( KJob *job )
218 {
219  Q_ASSERT( mCurrentDefault );
220 
221  if ( job->error() ) {
222  kError() << "Creating agent instance failed for " << mCurrentDefault->name();
223  setupNext();
224  return;
225  }
226 
227  AgentInstance instance = static_cast<AgentInstanceCreateJob*>( job )->instance();
228  const KConfigGroup agentCfg = KConfigGroup( mCurrentDefault, "Agent" );
229  const QString agentName = agentCfg.readEntry( "Name", QString() );
230  if ( !agentName.isEmpty() )
231  instance.setName( agentName );
232 
233  // agent specific settings, using the D-Bus <-> KConfigXT bridge
234  const KConfigGroup settings = KConfigGroup( mCurrentDefault, "Settings" );
235 
236  QDBusInterface *iface = new QDBusInterface( QString::fromLatin1( "org.freedesktop.Akonadi.Agent.%1" ).arg( instance.identifier() ),
237  QLatin1String( "/Settings" ), QString(),
238  DBusConnectionPool::threadConnection(), this );
239  if ( !iface->isValid() ) {
240  kError() << "Unable to obtain the KConfigXT D-Bus interface of " << instance.identifier();
241  setupNext();
242  delete iface;
243  return;
244  }
245 
246  foreach ( const QString &setting, settings.keyList() ) {
247  kDebug() << "Setting up " << setting << " for agent " << instance.identifier();
248  const QString methodName = QString::fromLatin1( "set%1" ).arg( setting );
249  const QVariant::Type argType = argumentType( iface->metaObject(), methodName );
250  if ( argType == QVariant::Invalid ) {
251  kError() << "Setting " << setting << " not found in agent configuration interface of " << instance.identifier();
252  continue;
253  }
254 
255  QVariant arg;
256  if ( argType == QVariant::String ) {
257  // Since a string could be a path we always use readPathEntry here,
258  // that shouldn't harm any normal string settings
259  arg = settings.readPathEntry( setting, QString() );
260  } else
261  arg = settings.readEntry( setting, QVariant( argType ) );
262 
263  const QDBusReply<void> reply = iface->call( methodName, arg );
264  if ( !reply.isValid() )
265  kError() << "Setting " << setting << " failed for agent " << instance.identifier();
266  }
267 
268  iface->call( QLatin1String( "writeConfig" ) );
269 
270  instance.reconfigure();
271  instance.synchronize();
272  delete iface;
273 
274  // remember we set this one up already
275  KConfigGroup cfg( mConfig, "ProcessedDefaults" );
276  cfg.writeEntry( agentCfg.readEntry( "Id", QString() ), instance.identifier() );
277  cfg.sync();
278 
279  setupNext();
280 }
281 
282 QVariant::Type Firstrun::argumentType( const QMetaObject *mo, const QString &method )
283 {
284  QMetaMethod m;
285  for ( int i = 0; i < mo->methodCount(); ++i ) {
286  const QString signature = QString::fromLatin1( mo->method( i ).signature() );
287  if ( signature.startsWith( method ) )
288  m = mo->method( i );
289  }
290 
291  if ( !m.signature() )
292  return QVariant::Invalid;
293 
294  const QList<QByteArray> argTypes = m.parameterTypes();
295  if ( argTypes.count() != 1 )
296  return QVariant::Invalid;
297 
298  return QVariant::nameToType( argTypes.first() );
299 }
300 
301 #include "firstrun_p.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Tue Dec 11 2012 12:14:32 by doxygen 1.8.1.2 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.9.4 API Reference

Skip menu "kdepimlibs-4.9.4 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