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

akonadi

  • akonadi
servermanager.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 "servermanager.h"
21 #include "servermanager_p.h"
22 
23 #include "agenttype.h"
24 #include "agentbase.h"
25 #include "agentmanager.h"
26 #include "dbusconnectionpool.h"
27 #ifndef Q_OS_WINCE
28 #include "selftestdialog_p.h"
29 #endif
30 #include "session_p.h"
31 #include "firstrun_p.h"
32 
33 #include <KDebug>
34 #include <KGlobal>
35 #include <KLocale>
36 
37 #include <akonadi/private/protocol_p.h>
38 #include <akonadi/private/xdgbasedirs_p.h>
39 
40 #include <QtDBus>
41 #include <QTimer>
42 
43 #include <boost/scoped_ptr.hpp>
44 
45 using namespace Akonadi;
46 
47 class Akonadi::ServerManagerPrivate
48 {
49  public:
50  ServerManagerPrivate() :
51  instance( new ServerManager( this ) ),
52  mState( ServerManager::NotRunning ),
53  mSafetyTimer( new QTimer ),
54  mFirstRunner( 0 )
55  {
56  mState = instance->state();
57  mSafetyTimer->setSingleShot( true );
58  mSafetyTimer->setInterval( 30000 );
59  QObject::connect( mSafetyTimer.get(), SIGNAL(timeout()), instance, SLOT(timeout()) );
60  KGlobal::locale()->insertCatalog( QString::fromLatin1( "libakonadi" ) );
61  if ( mState == ServerManager::Running && Internal::clientType() == Internal::User && !ServerManager::hasInstanceIdentifier() ) {
62  mFirstRunner = new Firstrun( instance );
63  }
64  }
65 
66  ~ServerManagerPrivate()
67  {
68  delete instance;
69  }
70 
71  void serviceOwnerChanged( const QString&, const QString&, const QString& )
72  {
73  serverProtocolVersion = -1,
74  checkStatusChanged();
75  }
76 
77  void checkStatusChanged()
78  {
79  setState( instance->state() );
80  }
81 
82  void setState( ServerManager::State state )
83  {
84 
85  if ( mState != state ) {
86  mState = state;
87  emit instance->stateChanged( state );
88  if ( state == ServerManager::Running ) {
89  emit instance->started();
90  if ( !mFirstRunner && Internal::clientType() == Internal::User && !ServerManager::hasInstanceIdentifier() ) {
91  mFirstRunner = new Firstrun( instance );
92  }
93  } else if ( state == ServerManager::NotRunning || state == ServerManager::Broken ) {
94  emit instance->stopped();
95  }
96 
97  if ( state == ServerManager::Starting || state == ServerManager::Stopping ) {
98  QMetaObject::invokeMethod( mSafetyTimer.get(), "start", Qt::QueuedConnection ); // in case we are in a different thread
99  } else {
100  QMetaObject::invokeMethod( mSafetyTimer.get(), "stop", Qt::QueuedConnection ); // in case we are in a different thread
101  }
102  }
103  }
104 
105  void timeout()
106  {
107  if ( mState == ServerManager::Starting || mState == ServerManager::Stopping ) {
108  setState( ServerManager::Broken );
109  }
110  }
111 
112  ServerManager *instance;
113  static int serverProtocolVersion;
114  ServerManager::State mState;
115  boost::scoped_ptr<QTimer> mSafetyTimer;
116  Firstrun *mFirstRunner;
117  static Internal::ClientType clientType;
118 };
119 
120 int ServerManagerPrivate::serverProtocolVersion = -1;
121 Internal::ClientType ServerManagerPrivate::clientType = Internal::User;
122 
123 K_GLOBAL_STATIC( ServerManagerPrivate, sInstance )
124 
125 ServerManager::ServerManager(ServerManagerPrivate * dd ) :
126  d( dd )
127 {
128  qRegisterMetaType<Akonadi::ServerManager::State>();
129 
130  QDBusServiceWatcher *watcher = new QDBusServiceWatcher( ServerManager::serviceName( ServerManager::Server ),
131  DBusConnectionPool::threadConnection(),
132  QDBusServiceWatcher::WatchForOwnerChange, this );
133  watcher->addWatchedService( ServerManager::serviceName( ServerManager::Control ) );
134  watcher->addWatchedService( ServerManager::serviceName( ServerManager::UpgradeIndicator ) );
135 
136  // this (and also the two connects below) are queued so that they trigger after AgentManager is done loading
137  // the current agent types and instances
138  // this ensures the invariant of AgentManager reporting a consistent state if ServerManager::state() == Running
139  // that's the case with direct connections as well, but only after you enter the event loop once
140  connect( watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)),
141  this, SLOT(serviceOwnerChanged(QString,QString,QString)), Qt::QueuedConnection );
142 
143  // AgentManager is dangerous to use for agents themselves
144  if ( Internal::clientType() != Internal::User ) {
145  return;
146  }
147  connect( AgentManager::self(), SIGNAL(typeAdded(Akonadi::AgentType)), SLOT(checkStatusChanged()), Qt::QueuedConnection );
148  connect( AgentManager::self(), SIGNAL(typeRemoved(Akonadi::AgentType)), SLOT(checkStatusChanged()), Qt::QueuedConnection );
149 }
150 
151 ServerManager * Akonadi::ServerManager::self()
152 {
153  return sInstance->instance;
154 }
155 
156 bool ServerManager::start()
157 {
158  const bool controlRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( ServerManager::serviceName( ServerManager::Control ) );
159  const bool serverRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( ServerManager::serviceName( ServerManager::Server ) );
160  if ( controlRegistered && serverRegistered ) {
161  return true;
162  }
163 
164  const bool controlLockRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( ServerManager::serviceName( ServerManager::ControlLock ) );
165  if ( controlLockRegistered || controlRegistered ) {
166  kDebug() << "Akonadi server is already starting up";
167  sInstance->setState( Starting );
168  return true;
169  }
170 
171  kDebug() << "executing akonadi_control";
172  const bool ok = QProcess::startDetached( QLatin1String( "akonadi_control" ) );
173  if ( !ok ) {
174  kWarning() << "Unable to execute akonadi_control, falling back to D-Bus auto-launch";
175  QDBusReply<void> reply = DBusConnectionPool::threadConnection().interface()->startService( ServerManager::serviceName(ServerManager::Control) );
176  if ( !reply.isValid() ) {
177  kDebug() << "Akonadi server could not be started via D-Bus either: "
178  << reply.error().message();
179  return false;
180  }
181  }
182  sInstance->setState( Starting );
183  return true;
184 }
185 
186 bool ServerManager::stop()
187 {
188  QDBusInterface iface( ServerManager::serviceName( ServerManager::Control ),
189  QString::fromLatin1( "/ControlManager" ),
190  QString::fromLatin1( "org.freedesktop.Akonadi.ControlManager" ) );
191  if ( !iface.isValid() ) {
192  return false;
193  }
194  iface.call( QDBus::NoBlock, QString::fromLatin1( "shutdown" ) );
195  sInstance->setState( Stopping );
196  return true;
197 }
198 
199 void ServerManager::showSelfTestDialog( QWidget *parent )
200 {
201 #ifndef Q_OS_WINCE
202  Akonadi::SelfTestDialog dlg( parent );
203  dlg.hideIntroduction();
204  dlg.exec();
205 #endif
206 }
207 
208 bool ServerManager::isRunning()
209 {
210  return state() == Running;
211 }
212 
213 ServerManager::State ServerManager::state()
214 {
215  ServerManager::State previousState = NotRunning;
216  if ( sInstance.exists() ) { // be careful, this is called from the ServerManager::Private ctor, so using sInstance unprotected can cause infinite recursion
217  previousState = sInstance->mState;
218  }
219 
220  const bool serverUpgrading = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( ServerManager::serviceName( ServerManager::UpgradeIndicator ) );
221  if ( serverUpgrading )
222  return Upgrading;
223 
224  const bool controlRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( ServerManager::serviceName( ServerManager::Control ) );
225  const bool serverRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( ServerManager::serviceName( ServerManager::Server ) );
226  if ( controlRegistered && serverRegistered ) {
227  // check if the server protocol is recent enough
228  if ( sInstance.exists() ) {
229  if ( Internal::serverProtocolVersion() >= 0 &&
230  Internal::serverProtocolVersion() < SessionPrivate::minimumProtocolVersion() ) {
231  return Broken;
232  }
233  }
234 
235  // AgentManager is dangerous to use for agents themselves
236  if ( Internal::clientType() == Internal::User ) {
237  // besides the running server processes we also need at least one resource to be operational
238  AgentType::List agentTypes = AgentManager::self()->types();
239  foreach ( const AgentType &type, agentTypes ) {
240  if ( type.capabilities().contains( QLatin1String( "Resource" ) ) ) {
241  return Running;
242  }
243  }
244  return Broken;
245  } else {
246  return Running;
247  }
248  }
249 
250  const bool controlLockRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( ServerManager::serviceName( ServerManager::ControlLock ) );
251  if ( controlLockRegistered || controlRegistered ) {
252  kDebug() << "Akonadi server is already starting up";
253  if ( previousState == Running ) {
254  return NotRunning; // we don't know if it's starting or stopping, probably triggered by someone else
255  }
256  return previousState;
257  }
258 
259  if ( serverRegistered ) {
260  kWarning() << "Akonadi server running without control process!";
261  return Broken;
262  }
263 
264  if ( previousState == Starting || previousState == Broken ) { // valid cases where nothing might be running (yet)
265  return previousState;
266  }
267  return NotRunning;
268 }
269 
270 QString ServerManager::instanceIdentifier()
271 {
272  return QLatin1String( qgetenv( "AKONADI_INSTANCE" ) );
273 }
274 
275 bool ServerManager::hasInstanceIdentifier()
276 {
277  return !instanceIdentifier().isEmpty();
278 }
279 
280 static QString makeServiceName( const char* base, const QString &name = QString() )
281 {
282  if ( ServerManager::instanceIdentifier().isEmpty() ) {
283  return QLatin1String( base ) % name;
284  }
285  return QLatin1String( base ) % name % QLatin1Literal( "." ) % ServerManager::instanceIdentifier();
286 }
287 
288 // remove once we require Akonadi 1.9
289 #ifndef AKONADI_DBUS_SERVER_SERVICE_UPGRADING
290 #define AKONADI_DBUS_SERVER_SERVICE_UPGRADING "org.freedesktop.Akonadi.upgrading"
291 #endif
292 
293 QString ServerManager::serviceName( ServerManager::ServiceType serviceType )
294 {
295  switch ( serviceType ) {
296  case Server: return makeServiceName( AKONADI_DBUS_SERVER_SERVICE );
297  case Control: return makeServiceName( AKONADI_DBUS_CONTROL_SERVICE );
298  case ControlLock: return makeServiceName( AKONADI_DBUS_CONTROL_SERVICE_LOCK );
299  case UpgradeIndicator: return makeServiceName( AKONADI_DBUS_SERVER_SERVICE_UPGRADING );
300  }
301  Q_ASSERT( !"WTF?" );
302  return QString();
303 }
304 
305 QString ServerManager::agentServiceName( ServiceAgentType agentType, const QString &identifier )
306 {
307  switch ( agentType ) {
308  case Agent:
309  return makeServiceName( AKONADI_DBUS_SERVER_SERVICE, QString::fromLatin1( ".Agent.%1" ).arg( identifier ) );
310  case Resource:
311  return makeServiceName( AKONADI_DBUS_SERVER_SERVICE, QString::fromLatin1( ".Resource.%1" ).arg( identifier ) );
312  case Preprocessor:
313  return makeServiceName( AKONADI_DBUS_SERVER_SERVICE, QString::fromLatin1( ".Preprocessor.%1" ).arg( identifier ) );
314  }
315  Q_ASSERT( !"WTF?" );
316  return QString();
317 }
318 
319 QString ServerManager::addNamespace(const QString& string)
320 {
321  if ( ServerManager::hasInstanceIdentifier() ) {
322  return string % QLatin1Char( '_' ) % ServerManager::instanceIdentifier();
323  }
324  return string;
325 }
326 
327 int Internal::serverProtocolVersion()
328 {
329  return ServerManagerPrivate::serverProtocolVersion;
330 }
331 
332 void Internal::setServerProtocolVersion( int version )
333 {
334  ServerManagerPrivate::serverProtocolVersion = version;
335  if ( sInstance.exists() ) {
336  sInstance->checkStatusChanged();
337  }
338 }
339 
340 Internal::ClientType Internal::clientType()
341 {
342  return ServerManagerPrivate::clientType;
343 }
344 
345 void Internal::setClientType( ClientType type )
346 {
347  ServerManagerPrivate::clientType = type;
348 }
349 
350 QString Internal::xdgSaveDir( const char *resource, const QString &relPath )
351 {
352  QString fullRelPath = QLatin1String( "akonadi" );
353  if ( !ServerManager::instanceIdentifier().isEmpty() ) {
354  fullRelPath += QLatin1String( "/instance/" ) + ServerManager::instanceIdentifier();
355  }
356  if ( !relPath.isEmpty() ) {
357  fullRelPath += QLatin1Char( '/' ) + relPath;
358  }
359  return XdgBaseDirs::saveDir( resource, fullRelPath );
360 }
361 
362 #include "moc_servermanager.cpp"
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jul 13 2013 01:27:41 by doxygen 1.8.3.1 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.10.5 API Reference

Skip menu "kdepimlibs-4.10.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • 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