00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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 "selftestdialog_p.h"
00027 #include "session_p.h"
00028 #include "firstrun_p.h"
00029
00030 #include <KDebug>
00031 #include <KGlobal>
00032
00033 #include <QtDBus>
00034 #include <QTimer>
00035
00036 #include <boost/scoped_ptr.hpp>
00037
00038 #define AKONADI_CONTROL_SERVICE QLatin1String( "org.freedesktop.Akonadi.Control" )
00039 #define AKONADI_SERVER_SERVICE QLatin1String( "org.freedesktop.Akonadi" )
00040
00041 using namespace Akonadi;
00042
00043 class Akonadi::ServerManagerPrivate
00044 {
00045 public:
00046 ServerManagerPrivate() :
00047 instance( new ServerManager( this ) ),
00048 mState( ServerManager::NotRunning ),
00049 mSafetyTimer( new QTimer ),
00050 mFirstRunner( 0 )
00051 {
00052 mState = instance->state();
00053 mSafetyTimer->setSingleShot( true );
00054 mSafetyTimer->setInterval( 30000 );
00055 QObject::connect( mSafetyTimer.get(), SIGNAL( timeout() ), instance, SLOT( timeout() ) );
00056 KGlobal::locale()->insertCatalog( QString::fromLatin1( "libakonadi" ) );
00057 if ( mState == ServerManager::Running && Internal::clientType() == Internal::User )
00058 mFirstRunner = new Firstrun( instance );
00059 }
00060
00061 ~ServerManagerPrivate()
00062 {
00063 delete instance;
00064 }
00065
00066 void serviceOwnerChanged( const QString&, const QString&, const QString& )
00067 {
00068 serverProtocolVersion = -1,
00069 checkStatusChanged();
00070 }
00071
00072 void checkStatusChanged()
00073 {
00074 setState( instance->state() );
00075 }
00076
00077 void setState( ServerManager::State state )
00078 {
00079
00080 if ( mState != state ) {
00081 mState = state;
00082 emit instance->stateChanged( state );
00083 if ( state == ServerManager::Running ) {
00084 emit instance->started();
00085 if ( !mFirstRunner && Internal::clientType() == Internal::User )
00086 mFirstRunner = new Firstrun( instance );
00087 } else if ( state == ServerManager::NotRunning || state == ServerManager::Broken ) {
00088 emit instance->stopped();
00089 }
00090
00091 if ( state == ServerManager::Starting || state == ServerManager::Stopping )
00092 mSafetyTimer->start();
00093 else
00094 mSafetyTimer->stop();
00095 }
00096 }
00097
00098 void timeout()
00099 {
00100 if ( mState == ServerManager::Starting || mState == ServerManager::Stopping )
00101 setState( ServerManager::Broken );
00102 }
00103
00104 ServerManager *instance;
00105 static int serverProtocolVersion;
00106 ServerManager::State mState;
00107 boost::scoped_ptr<QTimer> mSafetyTimer;
00108 Firstrun *mFirstRunner;
00109 static Internal::ClientType clientType;
00110 };
00111
00112 int ServerManagerPrivate::serverProtocolVersion = -1;
00113 Internal::ClientType ServerManagerPrivate::clientType = Internal::User;
00114
00115 K_GLOBAL_STATIC( ServerManagerPrivate, sInstance )
00116
00117 ServerManager::ServerManager(ServerManagerPrivate * dd ) :
00118 d( dd )
00119 {
00120 QDBusServiceWatcher *watcher = new QDBusServiceWatcher( AKONADI_SERVER_SERVICE,
00121 QDBusConnection::sessionBus(),
00122 QDBusServiceWatcher::WatchForOwnerChange, this );
00123 watcher->addWatchedService( AKONADI_CONTROL_SERVICE );
00124
00125 connect( watcher, SIGNAL( serviceOwnerChanged( const QString&, const QString&, const QString& ) ),
00126 this, SLOT( serviceOwnerChanged( const QString&, const QString&, const QString& ) ) );
00127
00128
00129 if ( Internal::clientType() != Internal::User )
00130 return;
00131 connect( AgentManager::self(), SIGNAL( typeAdded( const Akonadi::AgentType& ) ), SLOT( checkStatusChanged() ) );
00132 connect( AgentManager::self(), SIGNAL( typeRemoved( const Akonadi::AgentType& ) ), SLOT( checkStatusChanged() ) );
00133 }
00134
00135 ServerManager * Akonadi::ServerManager::self()
00136 {
00137 return sInstance->instance;
00138 }
00139
00140 bool ServerManager::start()
00141 {
00142 const bool controlRegistered = QDBusConnection::sessionBus().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE );
00143 const bool serverRegistered = QDBusConnection::sessionBus().interface()->isServiceRegistered( AKONADI_SERVER_SERVICE );
00144 if ( controlRegistered && serverRegistered )
00145 return true;
00146
00147
00148 const bool controlLockRegistered = QDBusConnection::sessionBus().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE + QLatin1String( ".lock" ) );
00149 if ( controlLockRegistered || controlRegistered ) {
00150 kDebug() << "Akonadi server is already starting up";
00151 sInstance->setState( Starting );
00152 return true;
00153 }
00154
00155 kDebug() << "executing akonadi_control";
00156 const bool ok = QProcess::startDetached( QLatin1String( "akonadi_control" ) );
00157 if ( !ok ) {
00158 kWarning() << "Unable to execute akonadi_control, falling back to D-Bus auto-launch";
00159 QDBusReply<void> reply = QDBusConnection::sessionBus().interface()->startService( AKONADI_CONTROL_SERVICE );
00160 if ( !reply.isValid() ) {
00161 kDebug() << "Akonadi server could not be started via D-Bus either: "
00162 << reply.error().message();
00163 return false;
00164 }
00165 }
00166 sInstance->setState( Starting );
00167 return true;
00168 }
00169
00170 bool ServerManager::stop()
00171 {
00172 QDBusInterface iface( AKONADI_CONTROL_SERVICE,
00173 QString::fromLatin1( "/ControlManager" ),
00174 QString::fromLatin1( "org.freedesktop.Akonadi.ControlManager" ) );
00175 if ( !iface.isValid() )
00176 return false;
00177 iface.call( QDBus::NoBlock, QString::fromLatin1( "shutdown" ) );
00178 sInstance->setState( Stopping );
00179 return true;
00180 }
00181
00182 void ServerManager::showSelfTestDialog( QWidget *parent )
00183 {
00184 Akonadi::SelfTestDialog dlg( parent );
00185 dlg.hideIntroduction();
00186 dlg.exec();
00187 }
00188
00189 bool ServerManager::isRunning()
00190 {
00191 return state() == Running;
00192 }
00193
00194 ServerManager::State ServerManager::state()
00195 {
00196 ServerManager::State previousState = NotRunning;
00197 if ( sInstance.exists() )
00198 previousState = sInstance->mState;
00199
00200 const bool controlRegistered = QDBusConnection::sessionBus().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE );
00201 const bool serverRegistered = QDBusConnection::sessionBus().interface()->isServiceRegistered( AKONADI_SERVER_SERVICE );
00202 if ( controlRegistered && serverRegistered ) {
00203
00204 if ( sInstance.exists() ) {
00205 if ( Internal::serverProtocolVersion() >= 0 &&
00206 Internal::serverProtocolVersion() < SessionPrivate::minimumProtocolVersion() )
00207 return Broken;
00208 }
00209
00210
00211 if ( Internal::clientType() == Internal::User ) {
00212
00213 AgentType::List agentTypes = AgentManager::self()->types();
00214 foreach ( const AgentType &type, agentTypes ) {
00215 if ( type.capabilities().contains( QLatin1String( "Resource" ) ) )
00216 return Running;
00217 }
00218 return Broken;
00219 } else {
00220 return Running;
00221 }
00222 }
00223
00224
00225 const bool controlLockRegistered = QDBusConnection::sessionBus().interface()->isServiceRegistered( AKONADI_CONTROL_SERVICE + QLatin1String( ".lock" ) );
00226 if ( controlLockRegistered || controlRegistered ) {
00227 kDebug() << "Akonadi server is already starting up";
00228 if ( previousState == Running )
00229 return NotRunning;
00230 return previousState;
00231 }
00232
00233 if ( serverRegistered ) {
00234 kWarning() << "Akonadi server running without control process!";
00235 return Broken;
00236 }
00237
00238 if ( previousState == Starting || previousState == Broken )
00239 return previousState;
00240 return NotRunning;
00241 }
00242
00243 int Internal::serverProtocolVersion()
00244 {
00245 return ServerManagerPrivate::serverProtocolVersion;
00246 }
00247
00248 void Internal::setServerProtocolVersion( int version )
00249 {
00250 ServerManagerPrivate::serverProtocolVersion = version;
00251 if ( sInstance.exists() )
00252 sInstance->checkStatusChanged();
00253 }
00254
00255 Internal::ClientType Internal::clientType()
00256 {
00257 return ServerManagerPrivate::clientType;
00258 }
00259
00260 void Internal::setClientType( ClientType type )
00261 {
00262 ServerManagerPrivate::clientType = type;
00263 }
00264
00265 #include "servermanager.moc"