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 | |
50 | static 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 | |
61 | static 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 | |
76 | static 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 | |
83 | static 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 | |
90 | static 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 | |
123 | static 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 | |
151 | static bool statusServer() |
152 | { |
153 | checkAkonadiControlStatus(); |
154 | checkAkonadiServerStatus(); |
155 | checkSearchSupportStatus(); |
156 | checkAvailableAgentTypes(); |
157 | return true; |
158 | } |
159 | |
160 | int 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 | |