Akonadi

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

KDE's Doxygen guidelines are available online.