1/***************************************************************************
2 * Copyright (C) 2007 by Tobias Koenig <tokoe@kde.org> *
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 <QtCore/QCoreApplication>
21#include <QtCore/QDebug>
22#include <QtCore/QDir>
23#include <QtCore/QString>
24#include <QtCore/QStringList>
25#include <QtCore/QSettings>
26#include <QtDBus/QDBusConnection>
27#include <QtDBus/QDBusConnectionInterface>
28#include <QtDBus/QDBusInterface>
29#include <QtDBus/QDBusReply>
30
31#include <config-akonadi.h>
32
33#include <akapplication.h>
34#include <akdbus.h>
35#include <akdebug.h>
36#include "protocol_p.h"
37
38#include "controlmanagerinterface.h"
39#include "akonadistarter.h"
40#include "xdgbasedirs_p.h"
41#include <QSettings>
42
43#if defined(HAVE_UNISTD_H) && !defined(Q_WS_WIN)
44#include <unistd.h>
45#else
46#define WIN32_LEAN_AND_MEAN
47#include <Windows.h>
48#endif
49
50static bool startServer()
51{
52 if (QDBusConnection::sessionBus().interface()->isServiceRegistered(AkDBus::serviceName(AkDBus::Control))
53 || QDBusConnection::sessionBus().interface()->isServiceRegistered(AkDBus::serviceName(AkDBus::Server))) {
54 qWarning() << "Akonadi is already running.";
55 return false;
56 }
57 AkonadiStarter starter;
58 return starter.start();
59}
60
61static bool stopServer()
62{
63 org::freedesktop::Akonadi::ControlManager iface(AkDBus::serviceName(AkDBus::Control),
64 QLatin1String("/ControlManager"),
65 QDBusConnection::sessionBus(), 0);
66 if (!iface.isValid()) {
67 qWarning() << "Akonadi is not running.";
68 return false;
69 }
70
71 iface.shutdown();
72
73 return true;
74}
75
76static bool checkAkonadiControlStatus()
77{
78 const bool registered = QDBusConnection::sessionBus().interface()->isServiceRegistered(AkDBus::serviceName(AkDBus::Control));
79 fprintf(stderr, "Akonadi Control: %s\n", registered ? "running" : "stopped");
80 return registered;
81}
82
83static bool checkAkonadiServerStatus()
84{
85 const bool registered = QDBusConnection::sessionBus().interface()->isServiceRegistered(AkDBus::serviceName(AkDBus::Server));
86 fprintf(stderr, "Akonadi Server: %s\n", registered ? "running" : "stopped");
87 return registered;
88}
89
90static bool checkSearchSupportStatus()
91{
92 QStringList searchMethods;
93 searchMethods << QLatin1String("Remote Search");
94
95 const QString pluginOverride = QString::fromLatin1(qgetenv("AKONADI_OVERRIDE_SEARCHPLUGIN"));
96 if (!pluginOverride.isEmpty()) {
97 searchMethods << pluginOverride;
98 } else {
99 const QStringList dirs = Akonadi::XdgBaseDirs::findPluginDirs();
100 Q_FOREACH (const QString &pluginDir, dirs) {
101 QDir dir(pluginDir + QLatin1String("/akonadi"));
102 const QStringList desktopFiles = dir.entryList(QStringList() << QLatin1String("*.desktop"), QDir::Files);
103 Q_FOREACH (const QString &desktopFileName, desktopFiles) {
104 QSettings desktop(pluginDir + QLatin1String("/akonadi/") + desktopFileName, QSettings::IniFormat);
105 desktop.beginGroup(QLatin1String("Desktop Entry"));
106 if (desktop.value(QLatin1String("Type")).toString() != QLatin1String("AkonadiSearchPlugin")) {
107 continue;
108 }
109 if (!desktop.value(QLatin1String("X-Akonadi-LoadByDefault"), true).toBool()) {
110 continue;
111 }
112
113 searchMethods << desktop.value(QLatin1String("Name")).toString();
114 }
115 }
116 }
117
118 // There's always at least server-search available
119 fprintf(stderr, "Akonadi Server Search Support: available (%s)\n", qPrintable(searchMethods.join(QLatin1String(", "))));
120 return true;
121}
122
123static bool checkAvailableAgentTypes()
124{
125 const QStringList dirs = Akonadi::XdgBaseDirs::findAllResourceDirs("data", QLatin1String("akonadi/agents"));
126 QStringList types;
127 Q_FOREACH (const QString &pluginDir, dirs) {
128 QDir dir(pluginDir);
129 const QStringList plugins = dir.entryList(QStringList() << QLatin1String("*.desktop"), QDir::Files);
130 Q_FOREACH (const QString &plugin, plugins) {
131 QSettings pluginInfo(pluginDir + QLatin1String("/") + plugin, QSettings::IniFormat);
132 pluginInfo.beginGroup(QLatin1String("Desktop Entry"));
133 types << pluginInfo.value(QLatin1String("X-Akonadi-Identifier")).toString();
134 }
135 }
136
137 // Remove duplicates from multiple pluginDirs
138 types.removeDuplicates();
139 types.sort();
140
141 fprintf(stderr, "Available Agent Types: ");
142 if (types.isEmpty()) {
143 fprintf(stderr, "No agent types found! \n");
144 } else {
145 fprintf(stderr, "%s\n", qPrintable(types.join(QLatin1String(", "))));
146 }
147
148 return true;
149}
150
151static bool statusServer()
152{
153 checkAkonadiControlStatus();
154 checkAkonadiServerStatus();
155 checkSearchSupportStatus();
156 checkAvailableAgentTypes();
157 return true;
158}
159
160int main(int argc, char **argv)
161{
162 AkCoreApplication app(argc, argv);
163 app.setDescription(QLatin1String("Akonadi server manipulation tool\n"
164 "Usage: akonadictl [command]\n\n"
165 "Commands:\n"
166 " start : Starts the Akonadi server with all its processes\n"
167 " stop : Stops the Akonadi server and all its processes cleanly\n"
168 " restart : Restart Akonadi server with all its processes\n"
169 " status : Shows a status overview of the Akonadi server\n"
170 " vacuum : Vacuum internal storage (WARNING: needs a lot of time and disk space!)\n"
171 " fsck : Check (and attempt to fix) consistency of the internal storage (can take some time)"));
172
173 app.parseCommandLine();
174
175 QStringList optionsList;
176 optionsList.append(QLatin1String("start"));
177 optionsList.append(QLatin1String("stop"));
178 optionsList.append(QLatin1String("status"));
179 optionsList.append(QLatin1String("restart"));
180 optionsList.append(QLatin1String("vacuum"));
181 optionsList.append(QLatin1String("fsck"));
182
183 QStringList arguments = QCoreApplication::instance()->arguments();
184 if (AkApplication::hasInstanceIdentifier()) { // HACK: we should port all of this to boost::program_options...
185 arguments.removeFirst();
186 arguments.removeFirst();
187 }
188 if (arguments.count() != 2) {
189 app.printUsage();
190 return 1;
191 } else if (!optionsList.contains(arguments[1])) {
192 app.printUsage();
193 return 2;
194 }
195
196 if (arguments[1] == QLatin1String("start")) {
197 if (!startServer()) {
198 return 3;
199 }
200 } else if (arguments[1] == QLatin1String("stop")) {
201 if (!stopServer()) {
202 return 4;
203 }
204 } else if (arguments[1] == QLatin1String("status")) {
205 if (!statusServer()) {
206 return 5;
207 }
208 } else if (arguments[1] == QLatin1String("restart")) {
209 if (!stopServer()) {
210 return 4;
211 } else {
212 do {
213#if defined(HAVE_UNISTD_H) && !defined(Q_WS_WIN)
214 usleep(100000);
215#else
216 Sleep(100000);
217#endif
218 } while (QDBusConnection::sessionBus().interface()->isServiceRegistered(AkDBus::serviceName(AkDBus::Control)));
219 if (!startServer()) {
220 return 3;
221 }
222 }
223 } else if (arguments[1] == QLatin1String("vacuum")) {
224 QDBusInterface iface(AkDBus::serviceName(AkDBus::StorageJanitor), QLatin1String(AKONADI_DBUS_STORAGEJANITOR_PATH));
225 iface.call(QDBus::NoBlock, QLatin1String("vacuum"));
226 } else if (arguments[1] == QLatin1String("fsck")) {
227 QDBusInterface iface(AkDBus::serviceName(AkDBus::StorageJanitor), QLatin1String(AKONADI_DBUS_STORAGEJANITOR_PATH));
228 iface.call(QDBus::NoBlock, QLatin1String("check"));
229 }
230 return 0;
231}
232