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 "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 );
00097 else
00098 QMetaObject::invokeMethod( mSafetyTimer.get(), "stop", Qt::QueuedConnection );
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
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
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() )
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
00212 if ( sInstance.exists() ) {
00213 if ( Internal::serverProtocolVersion() >= 0 &&
00214 Internal::serverProtocolVersion() < SessionPrivate::minimumProtocolVersion() )
00215 return Broken;
00216 }
00217
00218
00219 if ( Internal::clientType() == Internal::User ) {
00220
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
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;
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 )
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"