• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • KDE Home
  • Contact Us
 

akonadi

servermanager.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 "servermanager.h"
00021 #include "servermanager_p.h"
00022 
00023 #include "agenttype.h"
00024 #include "agentbase.h"
00025 #include "agentmanager.h"
00026 #include "dbusconnectionpool.h"
00027 #ifndef Q_OS_WINCE
00028 #include "selftestdialog_p.h"
00029 #endif
00030 #include "session_p.h"
00031 #include "firstrun_p.h"
00032 
00033 #include <KDebug>
00034 #include <KGlobal>
00035 #include <KLocale>
00036 
00037 #include <QtDBus>
00038 #include <QTimer>
00039 
00040 #include <boost/scoped_ptr.hpp>
00041 
00042 #define AKONADI_CONTROL_SERVICE QLatin1String( "org.freedesktop.Akonadi.Control" )
00043 #define AKONADI_SERVER_SERVICE QLatin1String( "org.freedesktop.Akonadi" )
00044 
00045 using namespace Akonadi;
00046 
00047 class Akonadi::ServerManagerPrivate
00048 {
00049   public:
00050     ServerManagerPrivate() :
00051       instance( new ServerManager( this ) ),
00052       mState( ServerManager::NotRunning ),
00053       mSafetyTimer( new QTimer ),
00054       mFirstRunner( 0 )
00055     {
00056       mState = instance->state();
00057       mSafetyTimer->setSingleShot( true );
00058       mSafetyTimer->setInterval( 30000 );
00059       QObject::connect( mSafetyTimer.get(), SIGNAL( timeout() ), instance, SLOT( timeout() ) );
00060       KGlobal::locale()->insertCatalog( QString::fromLatin1( "libakonadi" ) );
00061       if ( mState == ServerManager::Running && Internal::clientType() == Internal::User )
00062         mFirstRunner = new Firstrun( instance );
00063     }
00064 
00065     ~ServerManagerPrivate()
00066     {
00067       delete instance;
00068     }
00069 
00070     void serviceOwnerChanged( const QString&, const QString&, const QString& )
00071     {
00072       serverProtocolVersion = -1,
00073       checkStatusChanged();
00074     }
00075 
00076     void checkStatusChanged()
00077     {
00078       setState( instance->state() );
00079     }
00080 
00081     void setState( ServerManager::State state )
00082     {
00083 
00084       if ( mState != state ) {
00085         mState = state;
00086         emit instance->stateChanged( state );
00087         if ( state == ServerManager::Running ) {
00088           emit instance->started();
00089           if ( !mFirstRunner && Internal::clientType() == Internal::User )
00090             mFirstRunner = new Firstrun( instance );
00091         } else if ( state == ServerManager::NotRunning || state == ServerManager::Broken ) {
00092           emit instance->stopped();
00093         }
00094 
00095         if ( state == ServerManager::Starting || state == ServerManager::Stopping )
00096           QMetaObject::invokeMethod( mSafetyTimer.get(), "start", Qt::QueuedConnection ); // in case we are in a different thread
00097         else
00098           QMetaObject::invokeMethod( mSafetyTimer.get(), "stop", Qt::QueuedConnection ); // in case we are in a different thread
00099       }
00100     }
00101 
00102     void timeout()
00103     {
00104       if ( mState == ServerManager::Starting || mState == ServerManager::Stopping )
00105         setState( ServerManager::Broken );
00106     }
00107 
00108     ServerManager *instance;
00109     static int serverProtocolVersion;
00110     ServerManager::State mState;
00111     boost::scoped_ptr<QTimer> mSafetyTimer;
00112     Firstrun *mFirstRunner;
00113     static Internal::ClientType clientType;
00114 };
00115 
00116 int ServerManagerPrivate::serverProtocolVersion = -1;
00117 Internal::ClientType ServerManagerPrivate::clientType = Internal::User;
00118 
00119 K_GLOBAL_STATIC( ServerManagerPrivate, sInstance )
00120 
00121 ServerManager::ServerManager(ServerManagerPrivate * dd ) :
00122     d( dd )
00123 {
00124   qRegisterMetaType<Akonadi::ServerManager::State>();
00125 
00126   QDBusServiceWatcher *watcher = new QDBusServiceWatcher( AKONADI_SERVER_SERVICE,
00127                                                           DBusConnectionPool::threadConnection(),
00128                                                           QDBusServiceWatcher::WatchForOwnerChange, this );
00129   watcher->addWatchedService( AKONADI_CONTROL_SERVICE );
00130 
00131   connect( watcher, SIGNAL( serviceOwnerChanged( const QString&, const QString&, const QString& ) ),
00132            this, SLOT( serviceOwnerChanged( const QString&, const QString&, const QString& ) ) );
00133 
00134   // AgentManager is dangerous to use for agents themselves
00135   if ( Internal::clientType() != Internal::User )
00136     return;
00137   connect( AgentManager::self(), SIGNAL( typeAdded( const Akonadi::AgentType& ) ), SLOT( checkStatusChanged() ) );
00138   connect( AgentManager::self(), SIGNAL( typeRemoved( const Akonadi::AgentType& ) ), SLOT( checkStatusChanged() ) );
00139 }
00140 
00141 ServerManager * Akonadi::ServerManager::self()
00142 {
00143   return sInstance->instance;
00144 }
00145 
00146 bool ServerManager::start()
00147 {
00148   const bool controlRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE );
00149   const bool serverRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_SERVER_SERVICE );
00150   if (  controlRegistered && serverRegistered )
00151     return true;
00152 
00153   // TODO: use AKONADI_CONTROL_SERVICE_LOCK instead once we depend on a recent enough Akonadi server
00154   const bool controlLockRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE + QLatin1String( ".lock" ) );
00155   if ( controlLockRegistered || controlRegistered ) {
00156     kDebug() << "Akonadi server is already starting up";
00157     sInstance->setState( Starting );
00158     return true;
00159   }
00160 
00161   kDebug() << "executing akonadi_control";
00162   const bool ok = QProcess::startDetached( QLatin1String( "akonadi_control" ) );
00163   if ( !ok ) {
00164     kWarning() << "Unable to execute akonadi_control, falling back to D-Bus auto-launch";
00165     QDBusReply<void> reply = DBusConnectionPool::threadConnection().interface()->startService( AKONADI_CONTROL_SERVICE );
00166     if ( !reply.isValid() ) {
00167       kDebug() << "Akonadi server could not be started via D-Bus either: "
00168                << reply.error().message();
00169       return false;
00170     }
00171   }
00172   sInstance->setState( Starting );
00173   return true;
00174 }
00175 
00176 bool ServerManager::stop()
00177 {
00178   QDBusInterface iface( AKONADI_CONTROL_SERVICE,
00179                         QString::fromLatin1( "/ControlManager" ),
00180                         QString::fromLatin1( "org.freedesktop.Akonadi.ControlManager" ) );
00181   if ( !iface.isValid() )
00182     return false;
00183   iface.call( QDBus::NoBlock, QString::fromLatin1( "shutdown" ) );
00184   sInstance->setState( Stopping );
00185   return true;
00186 }
00187 
00188 void ServerManager::showSelfTestDialog( QWidget *parent )
00189 {
00190 #ifndef Q_OS_WINCE
00191   Akonadi::SelfTestDialog dlg( parent );
00192   dlg.hideIntroduction();
00193   dlg.exec();
00194 #endif
00195 }
00196 
00197 bool ServerManager::isRunning()
00198 {
00199   return state() == Running;
00200 }
00201 
00202 ServerManager::State ServerManager::state()
00203 {
00204   ServerManager::State previousState = NotRunning;
00205   if ( sInstance.exists() ) // be careful, this is called from the ServerManager::Private ctor, so using sInstance unprotected can cause infinite recursion
00206     previousState = sInstance->mState;
00207 
00208   const bool controlRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE );
00209   const bool serverRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_SERVER_SERVICE );
00210   if (  controlRegistered && serverRegistered ) {
00211     // check if the server protocol is recent enough
00212     if ( sInstance.exists() ) {
00213       if ( Internal::serverProtocolVersion() >= 0 &&
00214            Internal::serverProtocolVersion() < SessionPrivate::minimumProtocolVersion() )
00215         return Broken;
00216     }
00217 
00218     // AgentManager is dangerous to use for agents themselves
00219     if ( Internal::clientType() == Internal::User ) {
00220       // besides the running server processes we also need at least one resource to be operational
00221       AgentType::List agentTypes = AgentManager::self()->types();
00222       foreach ( const AgentType &type, agentTypes ) {
00223         if ( type.capabilities().contains( QLatin1String( "Resource" ) ) )
00224           return Running;
00225       }
00226       return Broken;
00227     } else {
00228       return Running;
00229     }
00230   }
00231 
00232   // TODO: use AKONADI_CONTROL_SERVICE_LOCK instead once we depend on a recent enough Akonadi server
00233   const bool controlLockRegistered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE + QLatin1String( ".lock" ) );
00234   if ( controlLockRegistered || controlRegistered ) {
00235     kDebug() << "Akonadi server is already starting up";
00236     if ( previousState == Running )
00237       return NotRunning; // we don't know if it's starting or stopping, probably triggered by someone else
00238     return previousState;
00239   }
00240 
00241   if ( serverRegistered ) {
00242     kWarning() << "Akonadi server running without control process!";
00243     return Broken;
00244   }
00245 
00246   if ( previousState == Starting || previousState == Broken ) // valid cases where nothing might be running (yet)
00247     return previousState;
00248   return NotRunning;
00249 }
00250 
00251 int Internal::serverProtocolVersion()
00252 {
00253   return ServerManagerPrivate::serverProtocolVersion;
00254 }
00255 
00256 void Internal::setServerProtocolVersion( int version )
00257 {
00258   ServerManagerPrivate::serverProtocolVersion = version;
00259   if ( sInstance.exists() )
00260     sInstance->checkStatusChanged();
00261 }
00262 
00263 Internal::ClientType Internal::clientType()
00264 {
00265   return ServerManagerPrivate::clientType;
00266 }
00267 
00268 void Internal::setClientType( ClientType type )
00269 {
00270   ServerManagerPrivate::clientType = type;
00271 }
00272 
00273 #include "servermanager.moc"

akonadi

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

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • 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
Generated for KDE-PIM Libraries by doxygen 1.7.5
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