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

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