1/*
2 This file is part of the KDE Baloo project.
3 SPDX-FileCopyrightText: 2015 Vishesh Handa <vhanda@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.1-or-later
6*/
7
8#include "configcommand.h"
9#include "indexerconfig.h"
10
11#include <QDir>
12#include <QTextStream>
13#include <QFileInfo>
14
15#include <KLocalizedString>
16
17using namespace Baloo;
18
19/*
20 * TODO: remove code duplication, we are performing similar operations
21 * for excludeFolders, includeFolders and excludeFilters just using different
22 * setters/getters. Figure out a way to unify the code while still keeping it
23 * readable.
24 */
25
26namespace
27{
28QString normalizeTrailingSlashes(QString&& path)
29{
30 while (path.endsWith(c: QLatin1Char('/'))) {
31 path.chop(n: 1);
32 }
33 path += QLatin1Char('/');
34 return path;
35}
36}
37
38QString ConfigCommand::command()
39{
40 return QStringLiteral("config");
41}
42
43QString ConfigCommand::description()
44{
45 return i18n("Manipulate the Baloo configuration");
46}
47
48int ConfigCommand::exec(const QCommandLineParser& parser)
49{
50 QStringList args = parser.positionalArguments();
51 args.removeFirst();
52
53 QTextStream out(stdout);
54
55 auto printCommand = [&out](const QString& command, const QString& description) {
56 out << " ";
57 out.setFieldWidth(25);
58 out.setFieldAlignment(QTextStream::AlignLeft);
59 out << command;
60 out.setFieldWidth(0);
61 out.setFieldAlignment(QTextStream::AlignLeft);
62 out << description << '\n';
63 };
64
65 const QString command = args.isEmpty() ? QStringLiteral("help") : args.takeFirst();
66 if (command == QLatin1String("help")) {
67 // Show help
68 out << i18n("The config command can be used to manipulate the Baloo Configuration\n");
69 out << i18n("Usage: balooctl config <command>\n\n");
70 out << i18n("Possible Commands:\n");
71
72 printCommand(QStringLiteral("add"), i18n("Add a value to config parameter"));
73 printCommand(QStringLiteral("rm | remove"), i18n("Remove a value from a config parameter"));
74 printCommand(QStringLiteral("list | ls | show"), i18n("Show the value of a config parameter"));
75 printCommand(QStringLiteral("set"), i18n("Set the value of a config parameter"));
76 printCommand(QStringLiteral("help"), i18n("Display this help menu"));
77 return 0;
78 }
79
80 if (command == QLatin1String("list") || command == QLatin1String("ls") || command == QLatin1String("show")) {
81 if (args.isEmpty()) {
82 out << i18n("The following configuration options may be listed:\n\n");
83
84 printCommand(QStringLiteral("hidden"), i18n("Controls if Baloo indexes hidden files and folders"));
85 printCommand(QStringLiteral("contentIndexing"), i18n("Controls if Baloo indexes file content"));
86 printCommand(QStringLiteral("includeFolders"), i18n("The list of folders which Baloo indexes"));
87 printCommand(QStringLiteral("excludeFolders"), i18n("The list of folders which Baloo will never index"));
88 printCommand(QStringLiteral("excludeFilters"), i18n("The list of filters which are used to exclude files"));
89 printCommand(QStringLiteral("excludeMimetypes"), i18n("The list of mimetypes which are used to exclude files"));
90 return 0;
91 }
92
93 IndexerConfig config;
94 QString value = args.takeFirst();
95 if (value.compare(other: QLatin1String("hidden"), cs: Qt::CaseInsensitive) == 0) {
96 if (config.indexHidden()) {
97 out << "yes\n";
98 } else {
99 out << "no\n";
100 }
101
102 return 0;
103 }
104
105 if (value.compare(QStringLiteral("contentIndexing"), cs: Qt::CaseInsensitive) == 0) {
106 if (config.onlyBasicIndexing()) {
107 out << "no\n";
108 } else {
109 out << "yes\n";
110 }
111
112 return 0;
113 }
114
115 auto printList = [&out](const QStringList& list) {
116 for (const QString& item: list) {
117 out << item << '\n';
118 }
119 };
120
121 if (value.compare(other: QLatin1String("includeFolders"), cs: Qt::CaseInsensitive) == 0) {
122 printList(config.includeFolders());
123 return 0;
124 }
125
126 if (value.compare(other: QLatin1String("excludeFolders"), cs: Qt::CaseInsensitive) == 0) {
127 printList(config.excludeFolders());
128 return 0;
129 }
130
131 if (value.compare(QStringLiteral("excludeFilters"), cs: Qt::CaseInsensitive) == 0) {
132 printList(config.excludeFilters());
133 return 0;
134 }
135
136 if (value.compare(QStringLiteral("excludeMimetypes"), cs: Qt::CaseInsensitive) == 0) {
137 printList(config.excludeMimetypes());
138 return 0;
139 }
140
141 out << i18n("Config parameter could not be found\n");
142 return 1;
143 }
144
145 if (command == QLatin1String("rm") || command == QLatin1String("remove")) {
146 if (args.isEmpty()) {
147 out << i18n("The following configuration options may be modified:\n\n");
148
149 printCommand(QStringLiteral("includeFolders"), i18n("The list of folders which Baloo indexes"));
150 printCommand(QStringLiteral("excludeFolders"), i18n("The list of folders which Baloo will never index"));
151 printCommand(QStringLiteral("excludeFilters"), i18n("The list of filters which are used to exclude files"));
152 printCommand(QStringLiteral("excludeMimetypes"), i18n("The list of mimetypes which are used to exclude files"));
153 return 0;
154 }
155
156 IndexerConfig config;
157 QString value = args.takeFirst();
158 if (value.compare(other: QLatin1String("includeFolders"), cs: Qt::CaseInsensitive) == 0) {
159 if (args.isEmpty()) {
160 out << i18n("A folder must be provided\n");
161 return 1;
162 }
163
164 QString path = args.takeFirst().replace(QStringLiteral("$HOME"), after: QDir::homePath());
165 path = normalizeTrailingSlashes(path: std::move(path));
166 QStringList folders = config.includeFolders();
167 if (!folders.contains(str: path)) {
168 out << i18n("%1 is not in the list of include folders", path) << '\n';
169 return 1;
170 }
171
172 folders.removeAll(t: path);
173 config.setIncludeFolders(folders);
174
175 return 0;
176 }
177
178 if (value.compare(other: QLatin1String("excludeFolders"), cs: Qt::CaseInsensitive) == 0) {
179 if (args.isEmpty()) {
180 out << i18n("A folder must be provided\n");
181 return 1;
182 }
183
184 QString path = args.takeFirst().replace(QStringLiteral("$HOME"), after: QDir::homePath());
185 path = normalizeTrailingSlashes(path: std::move(path));
186 QStringList folders = config.excludeFolders();
187 if (!folders.contains(str: path)) {
188 out << i18n("%1 is not in the list of exclude folders", path) << '\n';
189 return 1;
190 }
191
192 folders.removeAll(t: path);
193 config.setExcludeFolders(folders);
194
195 return 0;
196 }
197
198 if (value.compare(QStringLiteral("excludeFilters"), cs: Qt::CaseInsensitive) == 0) {
199 if (args.isEmpty()) {
200 out << i18n("A filter must be provided\n");
201 return 1;
202 }
203
204 QStringList filters = config.excludeFilters();
205 if (!filters.contains(str: args.first())) {
206 out << i18n("%1 is not in list of exclude filters", args.first()) << '\n';
207 return 1;
208 }
209
210 filters.removeAll(t: args.first());
211 config.setExcludeFilters(filters);
212 return 0;
213 }
214
215 if (value.compare(QStringLiteral("excludeMimetypes"), cs: Qt::CaseInsensitive) == 0) {
216 if (args.isEmpty()) {
217 out << i18n("A mimetype must be provided\n");
218 return 1;
219 }
220
221 QStringList mimetypes = config.excludeMimetypes();
222 if (!mimetypes.contains(str: args.first())) {
223 out << i18n("%1 is not in list of exclude mimetypes", args.first()) << '\n';
224 return 1;
225 }
226
227 mimetypes.removeAll(t: args.first());
228 config.setExcludeMimetypes(mimetypes);
229 return 0;
230 }
231
232 out << i18n("Config parameter could not be found\n");
233 return 1;
234 }
235
236 if (command == QLatin1String("add")) {
237 if (args.isEmpty()) {
238 out << i18n("The following configuration options may be modified:\n\n");
239
240 printCommand(QStringLiteral("includeFolders"), i18n("The list of folders which Baloo indexes"));
241 printCommand(QStringLiteral("excludeFolders"), i18n("The list of folders which Baloo will never index"));
242 printCommand(QStringLiteral("excludeFilters"), i18n("The list of filters which are used to exclude files"));
243 printCommand(QStringLiteral("excludeMimetypes"), i18n("The list of mimetypes which are used to exclude files"));
244 return 0;
245 }
246
247 IndexerConfig config;
248 QString value = args.takeFirst();
249 if (value.compare(other: QLatin1String("includeFolders"), cs: Qt::CaseInsensitive) == 0) {
250 if (args.isEmpty()) {
251 out << i18n("A folder must be provided\n");
252 return 1;
253 }
254
255 auto fileInfo = QFileInfo(args.takeFirst());
256 if (!fileInfo.exists()) {
257 out << i18n("Path does not exist\n");
258 return 1;
259 }
260
261 if (!fileInfo.isDir()) {
262 out << i18n("Path is not a directory\n");
263 return 1;
264 }
265
266 auto path = normalizeTrailingSlashes(path: fileInfo.absoluteFilePath());
267 QStringList folders = config.includeFolders();
268 if (folders.contains(str: path)) {
269 out << i18n("%1 is already in the list of include folders", path) << '\n';
270 return 1;
271 }
272
273 if (config.excludeFolders().contains(str: path)) {
274 out << i18n("%1 is in the list of exclude folders", path) << '\n';
275 return 1;
276 }
277
278 folders.append(t: path);
279 config.setIncludeFolders(folders);
280
281 return 0;
282 }
283
284 if (value.compare(other: QLatin1String("excludeFolders"), cs: Qt::CaseInsensitive) == 0) {
285 if (args.isEmpty()) {
286 out << i18n("A folder must be provided\n");
287 return 1;
288 }
289
290 auto fileInfo = QFileInfo(args.takeFirst());
291 if (!fileInfo.exists()) {
292 out << i18n("Path does not exist\n");
293 return 1;
294 }
295
296 if (!fileInfo.isDir()) {
297 out << i18n("Path is not a directory\n");
298 return 1;
299 }
300
301 auto path = normalizeTrailingSlashes(path: fileInfo.absoluteFilePath());
302 QStringList folders = config.excludeFolders();
303 if (folders.contains(str: path)) {
304 out << i18n("%1 is already in the list of exclude folders", path) << '\n';
305 return 1;
306 }
307
308 if (config.includeFolders().contains(str: path)) {
309 out << i18n("%1 is in the list of exclude folders", path) << '\n';
310 return 1;
311 }
312
313 folders.append(t: path);
314 config.setExcludeFolders(folders);
315
316 return 0;
317 }
318
319 if (value.compare(QStringLiteral("excludeFilters"), cs: Qt::CaseInsensitive) == 0) {
320 if (args.empty()) {
321 out << i18n("A filter must be provided\n");
322 return 1;
323 }
324
325 QStringList filters = config.excludeFilters();
326 if (filters.contains(str: args.first())) {
327 out << i18n("Exclude filter is already in the list\n");
328 return 1;
329 }
330
331 filters.append(t: args.first());
332 config.setExcludeFilters(filters);
333
334 return 0;
335 }
336
337 if (value.compare(QStringLiteral("excludeMimetypes"), cs: Qt::CaseInsensitive) == 0) {
338 if (args.empty()) {
339 out << i18n("A mimetype must be provided\n");
340 return 1;
341 }
342
343 QStringList mimetypes = config.excludeMimetypes();
344 if (mimetypes.contains(str: args.first())) {
345 out << i18n("Exclude mimetype is already in the list\n");
346 return 1;
347 }
348
349 mimetypes.append(t: args.first());
350 config.setExcludeMimetypes(mimetypes);
351
352 return 0;
353 }
354
355 out << i18n("Config parameter could not be found\n");
356 return 1;
357 }
358
359 if (command == QLatin1String("set")) {
360 if (args.isEmpty()) {
361 out << i18n("The following configuration options may be modified:\n\n");
362
363 printCommand(QStringLiteral("hidden"), i18n("Controls if Baloo indexes hidden files and folders"));
364 printCommand(QStringLiteral("contentIndexing"), i18n("Controls if Baloo indexes file content"));
365 return 0;
366 }
367
368 IndexerConfig config;
369 QString configParam = args.takeFirst();
370
371 if (configParam == QLatin1String("hidden")) {
372 if (args.isEmpty()) {
373 out << i18n("A value must be provided\n");
374 return 1;
375 }
376
377 QString value = args.takeFirst();
378 if (value.compare(other: QLatin1String("true"), cs: Qt::CaseInsensitive) == 0
379 || value.compare(other: QLatin1String("y"), cs: Qt::CaseInsensitive) == 0
380 || value.compare(other: QLatin1String("yes"), cs: Qt::CaseInsensitive) == 0
381 || value.compare(other: QLatin1String("1")) == 0) {
382 config.setIndexHidden(true);
383 return 0;
384 }
385
386 if (value.compare(other: QLatin1String("false"), cs: Qt::CaseInsensitive) == 0
387 || value.compare(other: QLatin1String("n"), cs: Qt::CaseInsensitive) == 0
388 || value.compare(other: QLatin1String("no"), cs: Qt::CaseInsensitive) == 0
389 || value.compare(other: QLatin1String("0")) == 0) {
390 config.setIndexHidden(false);
391 return 0;
392 }
393
394 out << i18n("Invalid value\n");
395 return 1;
396 }
397
398 if (configParam.compare(QStringLiteral("contentIndexing"), cs: Qt::CaseInsensitive) == 0) {
399 if (args.isEmpty()) {
400 out << i18n("A value must be provided\n");
401 return 1;
402 }
403
404 QString value = args.takeFirst();
405 if (value.compare(other: QLatin1String("true"), cs: Qt::CaseInsensitive) == 0
406 || value.compare(other: QLatin1String("y"), cs: Qt::CaseInsensitive) == 0
407 || value.compare(other: QLatin1String("yes"), cs: Qt::CaseInsensitive) == 0
408 || value.compare(other: QLatin1String("1")) == 0) {
409 config.setOnlyBasicIndexing(false);
410 return 0;
411 }
412
413 if (value.compare(other: QLatin1String("false"), cs: Qt::CaseInsensitive) == 0
414 || value.compare(other: QLatin1String("n"), cs: Qt::CaseInsensitive) == 0
415 || value.compare(other: QLatin1String("no"), cs: Qt::CaseInsensitive) == 0
416 || value.compare(other: QLatin1String("0")) == 0) {
417 config.setOnlyBasicIndexing(true);
418 return 0;
419 }
420
421 out << i18n("Invalid value\n");
422 return 1;
423 }
424
425 out << i18n("Config parameter could not be found\n");
426 return 1;
427 }
428
429 return 0;
430}
431

source code of baloo/src/tools/balooctl/configcommand.cpp