Akonadi

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

KDE's Doxygen guidelines are available online.