Akonadi

akonadictl/main.cpp
1/***************************************************************************
2 * SPDX-FileCopyrightText: 2007 Tobias Koenig <tokoe@kde.org> *
3 * *
4 * SPDX-License-Identifier: LGPL-2.0-or-later *
5 ***************************************************************************/
6
7#include <QCoreApplication>
8#include <QDBusConnection>
9#include <QDir>
10#include <QPluginLoader>
11#include <QSettings>
12#include <QString>
13#include <QStringList>
14
15#include <KAboutData>
16#include <KLocalizedString>
17
18#include "shared/akapplication.h"
19
20#include "akonadifull-version.h"
21#include "akonadistarter.h"
22#include "controlmanagerinterface.h"
23#include "janitorinterface.h"
24
25#include "private/dbus_p.h"
26#include "private/instance_p.h"
27#include "private/protocol_p.h"
28#include "private/standarddirs_p.h"
29
30#include <chrono>
31#include <iostream>
32#include <thread>
33
34static bool startServer(bool verbose)
35{
36 if (QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Control))
37 || QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Server))) {
38 std::cerr << "Akonadi is already running." << std::endl;
39 return false;
40 }
41 AkonadiStarter starter;
42 return starter.start(verbose);
43}
44
45static bool stopServer()
46{
47 org::freedesktop::Akonadi::ControlManager iface(Akonadi::DBus::serviceName(Akonadi::DBus::Control),
48 QStringLiteral("/ControlManager"),
50 nullptr);
51 if (!iface.isValid()) {
52 std::cerr << "Akonadi is not running." << std::endl;
53 return false;
54 }
55
56 iface.shutdown();
57
58 return true;
59}
60
61static bool isAkonadiServerRunning()
62{
63 return QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Server));
64}
65
66static bool checkAkonadiControlStatus()
67{
68 const bool registered = QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Control));
69 std::cerr << "Akonadi Control: " << (registered ? "running" : "stopped") << std::endl;
70 return registered;
71}
72
73static bool checkAkonadiServerStatus()
74{
75 const bool registered = isAkonadiServerRunning();
76 std::cerr << "Akonadi Server: " << (registered ? "running" : "stopped") << std::endl;
77 return registered;
78}
79
80static bool checkSearchSupportStatus()
81{
82 QStringList searchMethods{QStringLiteral("Remote Search")};
83
84 const QString pluginOverride = QString::fromLatin1(qgetenv("AKONADI_OVERRIDE_SEARCHPLUGIN"));
85 if (!pluginOverride.isEmpty()) {
86 searchMethods << pluginOverride;
87 } else {
89 for (const QString &pluginDir : dirs) {
90 const QDir dir(pluginDir + QLatin1StringView("/akonadi/"));
91 const QStringList pluginFiles = dir.entryList(QDir::Files);
92 for (const QString &pluginFileName : pluginFiles) {
93 QPluginLoader loader(dir.absolutePath() + QLatin1Char('/') + pluginFileName);
94 const QVariantMap metadata = loader.metaData().value(QStringLiteral("MetaData")).toVariant().toMap();
95 if (metadata.value(QStringLiteral("X-Akonadi-PluginType")).toString() != QLatin1StringView("SearchPlugin")) {
96 continue;
97 }
98 if (!metadata.value(QStringLiteral("X-Akonadi-LoadByDefault"), true).toBool()) {
99 continue;
100 }
101 searchMethods << metadata.value(QStringLiteral("X-Akonadi-PluginName")).toString();
102 }
103 }
104 }
105
106 // There's always at least server-search available
107 std::cerr << "Akonadi Server Search Support: available (" << searchMethods.join(QLatin1StringView(", ")).toStdString() << ")" << std::endl;
108 return true;
109}
110
111static bool checkAvailableAgentTypes()
112{
113 const auto dirs = Akonadi::StandardDirs::locateAllResourceDirs(QStringLiteral("akonadi/agents"));
114 QStringList types;
115 for (const QString &pluginDir : dirs) {
116 const QDir dir(pluginDir);
117 const QStringList plugins = dir.entryList(QStringList() << QStringLiteral("*.desktop"), QDir::Files);
118 for (const QString &plugin : plugins) {
119 QSettings pluginInfo(pluginDir + QLatin1Char('/') + plugin, QSettings::IniFormat);
120 pluginInfo.beginGroup(QStringLiteral("Desktop Entry"));
121 types << pluginInfo.value(QStringLiteral("X-Akonadi-Identifier")).toString();
122 }
123 }
124
125 // Remove duplicates from multiple pluginDirs
126 types.removeDuplicates();
127 types.sort();
128
129 std::cerr << "Available Agent Types: ";
130 if (types.isEmpty()) {
131 std::cerr << "No agent types found!" << std::endl;
132 } else {
133 std::cerr << types.join(QLatin1StringView(", ")).toStdString() << std::endl;
134 }
135
136 return true;
137}
138
139static bool instanceRunning(const QString &instanceName = {})
140{
141 const auto oldInstance = Akonadi::Instance::identifier();
142 Akonadi::Instance::setIdentifier(instanceName);
143 const auto service = Akonadi::DBus::serviceName(Akonadi::DBus::Control);
144 Akonadi::Instance::setIdentifier(oldInstance);
145
147}
148
149static void listInstances()
150{
151 struct Instance {
153 bool running;
154 };
155 QList<Instance> instances{{QStringLiteral("(default)"), instanceRunning()}};
156#ifdef Q_OS_WIN
157 const QDir instanceDir(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/akonadi/config/instance"));
158#else
159 const QDir instanceDir(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QStringLiteral("/akonadi/instance"));
160#endif
161 if (instanceDir.exists()) {
162 const auto list = instanceDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
163 for (const auto &e : list) {
164 instances.push_back({e, instanceRunning(e)});
165 }
166 }
167
168 for (const auto &i : std::as_const(instances)) {
169 std::cout << i.name.toStdString();
170 if (i.running) {
171 std::cout << " (running)";
172 }
173 std::cout << std::endl;
174 }
175}
176
177static bool statusServer()
178{
179 checkAkonadiControlStatus();
180 checkAkonadiServerStatus();
181 checkSearchSupportStatus();
182 checkAvailableAgentTypes();
183 return true;
184}
185
186static void runJanitor(const QString &operation)
187{
188 if (!isAkonadiServerRunning()) {
189 std::cerr << "Akonadi Server is not running, " << operation.toStdString() << " will not run" << std::endl;
190 return;
191 }
192
193 org::freedesktop::Akonadi::Janitor janitor(Akonadi::DBus::serviceName(Akonadi::DBus::StorageJanitor),
194 QStringLiteral(AKONADI_DBUS_STORAGEJANITOR_PATH),
196 QObject::connect(&janitor, &org::freedesktop::Akonadi::Janitor::information, &janitor, [](const QString &msg) {
197 std::cout << msg.toStdString() << std::endl;
198 });
199 QObject::connect(&janitor, &org::freedesktop::Akonadi::Janitor::done, &janitor, []() {
200 qApp->exit();
201 });
202 janitor.asyncCall(operation);
203 qApp->exec();
204}
205
206int main(int argc, char **argv)
207{
208 AkCoreApplication app(argc, argv);
209
210 app.setDescription(
211 i18n("Akonadi server manipulation tool\n\n"
212 "Commands:\n"
213 " start Starts the Akonadi server with all its processes\n"
214 " stop Stops the Akonadi server and all its processes cleanly\n"
215 " restart Restart Akonadi server with all its processes\n"
216 " status Shows a status overview of the Akonadi server\n"
217 " instances List all existing Akonadi instances\n"
218 " vacuum Vacuum internal storage (WARNING: needs a lot of time and disk\n"
219 " space!)\n"
220 " fsck Check (and attempt to fix) consistency of the internal storage\n"
221 " (can take some time)"));
222
223 KAboutData aboutData(QStringLiteral("akonadictl"),
224 QStringLiteral("akonadictl"),
225 QStringLiteral(AKONADI_FULL_VERSION),
226 QStringLiteral("akonadictl"),
229
230 app.addPositionalCommandLineOption(QStringLiteral("command"),
231 i18n("Command to execute"),
232 QStringLiteral("start|stop|restart|status|vacuum|fsck|instances"));
233
234 app.parseCommandLine();
235
236 const auto &cmdArgs = app.commandLineArguments();
237 const QStringList commands = cmdArgs.positionalArguments();
238 if (commands.size() != 1) {
239 app.printUsage();
240 return -1;
241 }
242 const bool verbose = cmdArgs.isSet(QStringLiteral("verbose"));
243
244 const QString command = commands[0];
245 if (command == QLatin1StringView("start")) {
246 if (!startServer(verbose)) {
247 return 3;
248 }
249 } else if (command == QLatin1StringView("stop")) {
250 if (!stopServer()) {
251 return 4;
252 }
253 } else if (command == QLatin1StringView("status")) {
254 if (!statusServer()) {
255 return 5;
256 }
257 } else if (command == QLatin1StringView("restart")) {
258 if (!stopServer()) {
259 return 4;
260 } else {
261 do {
262 std::this_thread::sleep_for(std::chrono::milliseconds(100));
263 } while (QDBusConnection::sessionBus().interface()->isServiceRegistered(Akonadi::DBus::serviceName(Akonadi::DBus::Control)));
264 if (!startServer(verbose)) {
265 return 3;
266 }
267 }
268 } else if (command == QLatin1StringView("vacuum")) {
269 runJanitor(QStringLiteral("vacuum"));
270 } else if (command == QLatin1StringView("fsck")) {
271 runJanitor(QStringLiteral("check"));
272 } else if (command == QLatin1StringView("instances")) {
273 listInstances();
274 } else {
275 app.printUsage();
276 return -1;
277 }
278 return 0;
279}
static void setApplicationData(const KAboutData &aboutData)
QString i18n(const char *text, const TYPE &arg...)
char * toString(const EngineQuery &query)
QString name(GameStandardAction id)
KIOCORE_EXPORT QString dir(const QString &fileClass)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
QStringList libraryPaths()
QDBusConnectionInterface * interface() const const
QDBusConnection sessionBus()
QDBusReply< bool > isServiceRegistered(const QString &serviceName) const const
bool isEmpty() const const
qsizetype size() const const
T value(qsizetype i) const const
T value(const Key &key, const T &defaultValue) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QString writableLocation(StandardLocation type)
QString fromLatin1(QByteArrayView str)
bool isEmpty() const const
std::string toStdString() const const
QString join(QChar separator) const const
qsizetype removeDuplicates()
void sort(Qt::CaseSensitivity cs)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:52:53 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.