File indexing completed on 2024-04-28 03:51:53

0001 /*
0002     This file is part of the KDE Baloo project.
0003     SPDX-FileCopyrightText: 2015 Vishesh Handa <vhanda@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-or-later
0006 */
0007 
0008 #include "configcommand.h"
0009 #include "indexerconfig.h"
0010 
0011 #include <QDir>
0012 #include <QTextStream>
0013 #include <QFileInfo>
0014 
0015 #include <KLocalizedString>
0016 
0017 using namespace Baloo;
0018 
0019 /*
0020  * TODO: remove code duplication, we are performing similar operations
0021  * for excludeFolders, includeFolders and excludeFilters just using different
0022  * setters/getters. Figure out a way to unify the code while still keeping it
0023  * readable.
0024  */
0025 
0026 namespace
0027 {
0028 QString normalizeTrailingSlashes(QString&& path)
0029 {
0030     while (path.endsWith(QLatin1Char('/'))) {
0031         path.chop(1);
0032     }
0033     path += QLatin1Char('/');
0034     return path;
0035 }
0036 }
0037 
0038 QString ConfigCommand::command()
0039 {
0040     return QStringLiteral("config");
0041 }
0042 
0043 QString ConfigCommand::description()
0044 {
0045     return i18n("Manipulate the Baloo configuration");
0046 }
0047 
0048 int ConfigCommand::exec(const QCommandLineParser& parser)
0049 {
0050     QStringList args = parser.positionalArguments();
0051     args.removeFirst();
0052 
0053     QTextStream out(stdout);
0054 
0055     auto printCommand = [&out](const QString& command, const QString& description) {
0056         out << "  ";
0057         out.setFieldWidth(25);
0058         out.setFieldAlignment(QTextStream::AlignLeft);
0059         out << command;
0060         out.setFieldWidth(0);
0061         out.setFieldAlignment(QTextStream::AlignLeft);
0062         out << description << '\n';
0063     };
0064 
0065     const QString command = args.isEmpty() ? QStringLiteral("help") : args.takeFirst();
0066     if (command == QLatin1String("help")) {
0067         // Show help
0068         out << i18n("The config command can be used to manipulate the Baloo Configuration\n");
0069         out << i18n("Usage: balooctl config <command>\n\n");
0070         out << i18n("Possible Commands:\n");
0071 
0072         printCommand(QStringLiteral("add"), i18n("Add a value to config parameter"));
0073         printCommand(QStringLiteral("rm | remove"), i18n("Remove a value from a config parameter"));
0074         printCommand(QStringLiteral("list | ls | show"), i18n("Show the value of a config parameter"));
0075         printCommand(QStringLiteral("set"), i18n("Set the value of a config parameter"));
0076         printCommand(QStringLiteral("help"), i18n("Display this help menu"));
0077         return 0;
0078     }
0079 
0080     if (command == QLatin1String("list") || command == QLatin1String("ls") || command == QLatin1String("show")) {
0081         if (args.isEmpty()) {
0082             out << i18n("The following configuration options may be listed:\n\n");
0083 
0084             printCommand(QStringLiteral("hidden"), i18n("Controls if Baloo indexes hidden files and folders"));
0085             printCommand(QStringLiteral("contentIndexing"), i18n("Controls if Baloo indexes file content"));
0086             printCommand(QStringLiteral("includeFolders"), i18n("The list of folders which Baloo indexes"));
0087             printCommand(QStringLiteral("excludeFolders"), i18n("The list of folders which Baloo will never index"));
0088             printCommand(QStringLiteral("excludeFilters"), i18n("The list of filters which are used to exclude files"));
0089             printCommand(QStringLiteral("excludeMimetypes"), i18n("The list of mimetypes which are used to exclude files"));
0090             return 0;
0091         }
0092 
0093         IndexerConfig config;
0094         QString value = args.takeFirst();
0095         if (value.compare(QLatin1String("hidden"), Qt::CaseInsensitive) == 0) {
0096             if (config.indexHidden()) {
0097                 out << "yes\n";
0098             } else {
0099                 out << "no\n";
0100             }
0101 
0102             return 0;
0103         }
0104 
0105         if (value.compare(QStringLiteral("contentIndexing"), Qt::CaseInsensitive) == 0) {
0106             if (config.onlyBasicIndexing()) {
0107                 out << "no\n";
0108             } else {
0109                 out << "yes\n";
0110             }
0111 
0112             return 0;
0113         }
0114 
0115         auto printList = [&out](const QStringList& list) {
0116             for (const QString& item: list) {
0117                 out << item << '\n';
0118             }
0119         };
0120 
0121         if (value.compare(QLatin1String("includeFolders"), Qt::CaseInsensitive) == 0) {
0122             printList(config.includeFolders());
0123             return 0;
0124         }
0125 
0126         if (value.compare(QLatin1String("excludeFolders"), Qt::CaseInsensitive) == 0) {
0127             printList(config.excludeFolders());
0128             return 0;
0129         }
0130 
0131         if (value.compare(QStringLiteral("excludeFilters"), Qt::CaseInsensitive) == 0) {
0132             printList(config.excludeFilters());
0133             return 0;
0134         }
0135 
0136         if (value.compare(QStringLiteral("excludeMimetypes"), Qt::CaseInsensitive) == 0) {
0137             printList(config.excludeMimetypes());
0138             return 0;
0139         }
0140 
0141         out << i18n("Config parameter could not be found\n");
0142         return 1;
0143     }
0144 
0145     if (command == QLatin1String("rm") || command == QLatin1String("remove")) {
0146         if (args.isEmpty()) {
0147             out << i18n("The following configuration options may be modified:\n\n");
0148 
0149             printCommand(QStringLiteral("includeFolders"), i18n("The list of folders which Baloo indexes"));
0150             printCommand(QStringLiteral("excludeFolders"), i18n("The list of folders which Baloo will never index"));
0151             printCommand(QStringLiteral("excludeFilters"), i18n("The list of filters which are used to exclude files"));
0152             printCommand(QStringLiteral("excludeMimetypes"), i18n("The list of mimetypes which are used to exclude files"));
0153             return 0;
0154         }
0155 
0156         IndexerConfig config;
0157         QString value = args.takeFirst();
0158         if (value.compare(QLatin1String("includeFolders"), Qt::CaseInsensitive) == 0) {
0159             if (args.isEmpty()) {
0160                 out << i18n("A folder must be provided\n");
0161                 return 1;
0162             }
0163 
0164             QString path = args.takeFirst().replace(QStringLiteral("$HOME"), QDir::homePath());
0165             path = normalizeTrailingSlashes(std::move(path));
0166             QStringList folders = config.includeFolders();
0167             if (!folders.contains(path)) {
0168                 out << i18n("%1 is not in the list of include folders", path) << '\n';
0169                 return 1;
0170             }
0171 
0172             folders.removeAll(path);
0173             config.setIncludeFolders(folders);
0174 
0175             return 0;
0176         }
0177 
0178         if (value.compare(QLatin1String("excludeFolders"), Qt::CaseInsensitive) == 0) {
0179             if (args.isEmpty()) {
0180                 out << i18n("A folder must be provided\n");
0181                 return 1;
0182             }
0183 
0184             QString path = args.takeFirst().replace(QStringLiteral("$HOME"), QDir::homePath());
0185             path = normalizeTrailingSlashes(std::move(path));
0186             QStringList folders = config.excludeFolders();
0187             if (!folders.contains(path)) {
0188                 out << i18n("%1 is not in the list of exclude folders", path) << '\n';
0189                 return 1;
0190             }
0191 
0192             folders.removeAll(path);
0193             config.setExcludeFolders(folders);
0194 
0195             return 0;
0196         }
0197 
0198         if (value.compare(QStringLiteral("excludeFilters"), Qt::CaseInsensitive) == 0) {
0199             if (args.isEmpty()) {
0200                 out << i18n("A filter must be provided\n");
0201                 return 1;
0202             }
0203 
0204             QStringList filters = config.excludeFilters();
0205             if (!filters.contains(args.first())) {
0206                 out << i18n("%1 is not in list of exclude filters", args.first()) << '\n';
0207                 return 1;
0208             }
0209 
0210             filters.removeAll(args.first());
0211             config.setExcludeFilters(filters);
0212             return 0;
0213         }
0214 
0215         if (value.compare(QStringLiteral("excludeMimetypes"), Qt::CaseInsensitive) == 0) {
0216             if (args.isEmpty()) {
0217                 out << i18n("A mimetype must be provided\n");
0218                 return 1;
0219             }
0220 
0221             QStringList mimetypes = config.excludeMimetypes();
0222             if (!mimetypes.contains(args.first())) {
0223                 out << i18n("%1 is not in list of exclude mimetypes", args.first()) << '\n';
0224                 return 1;
0225             }
0226 
0227             mimetypes.removeAll(args.first());
0228             config.setExcludeMimetypes(mimetypes);
0229             return 0;
0230         }
0231 
0232         out << i18n("Config parameter could not be found\n");
0233         return 1;
0234     }
0235 
0236     if (command == QLatin1String("add")) {
0237         if (args.isEmpty()) {
0238             out << i18n("The following configuration options may be modified:\n\n");
0239 
0240             printCommand(QStringLiteral("includeFolders"), i18n("The list of folders which Baloo indexes"));
0241             printCommand(QStringLiteral("excludeFolders"), i18n("The list of folders which Baloo will never index"));
0242             printCommand(QStringLiteral("excludeFilters"), i18n("The list of filters which are used to exclude files"));
0243             printCommand(QStringLiteral("excludeMimetypes"), i18n("The list of mimetypes which are used to exclude files"));
0244             return 0;
0245         }
0246 
0247         IndexerConfig config;
0248         QString value = args.takeFirst();
0249         if (value.compare(QLatin1String("includeFolders"), Qt::CaseInsensitive) == 0) {
0250             if (args.isEmpty()) {
0251                 out << i18n("A folder must be provided\n");
0252                 return 1;
0253             }
0254 
0255             auto fileInfo = QFileInfo(args.takeFirst());
0256             if (!fileInfo.exists()) {
0257                 out << i18n("Path does not exist\n");
0258                 return 1;
0259             }
0260 
0261             if (!fileInfo.isDir()) {
0262                 out << i18n("Path is not a directory\n");
0263                 return 1;
0264             }
0265 
0266             auto path = normalizeTrailingSlashes(fileInfo.absoluteFilePath());
0267             QStringList folders = config.includeFolders();
0268             if (folders.contains(path)) {
0269                 out << i18n("%1 is already in the list of include folders", path) << '\n';
0270                 return 1;
0271             }
0272 
0273             if (config.excludeFolders().contains(path)) {
0274                 out << i18n("%1 is in the list of exclude folders", path) << '\n';
0275                 return 1;
0276             }
0277 
0278             folders.append(path);
0279             config.setIncludeFolders(folders);
0280 
0281             return 0;
0282         }
0283 
0284         if (value.compare(QLatin1String("excludeFolders"), Qt::CaseInsensitive) == 0) {
0285             if (args.isEmpty()) {
0286                 out << i18n("A folder must be provided\n");
0287                 return 1;
0288             }
0289 
0290             auto fileInfo = QFileInfo(args.takeFirst());
0291             if (!fileInfo.exists()) {
0292                 out << i18n("Path does not exist\n");
0293                 return 1;
0294             }
0295 
0296             if (!fileInfo.isDir()) {
0297                 out << i18n("Path is not a directory\n");
0298                 return 1;
0299             }
0300 
0301             auto path = normalizeTrailingSlashes(fileInfo.absoluteFilePath());
0302             QStringList folders = config.excludeFolders();
0303             if (folders.contains(path)) {
0304                 out << i18n("%1 is already in the list of exclude folders", path) << '\n';
0305                 return 1;
0306             }
0307 
0308             if (config.includeFolders().contains(path)) {
0309                 out << i18n("%1 is in the list of exclude folders", path) << '\n';
0310                 return 1;
0311             }
0312 
0313             folders.append(path);
0314             config.setExcludeFolders(folders);
0315 
0316             return 0;
0317         }
0318 
0319         if (value.compare(QStringLiteral("excludeFilters"), Qt::CaseInsensitive) == 0) {
0320             if (args.empty()) {
0321                 out << i18n("A filter must be provided\n");
0322                 return 1;
0323             }
0324 
0325             QStringList filters = config.excludeFilters();
0326             if (filters.contains(args.first())) {
0327                 out << i18n("Exclude filter is already in the list\n");
0328                 return 1;
0329             }
0330 
0331             filters.append(args.first());
0332             config.setExcludeFilters(filters);
0333 
0334             return 0;
0335         }
0336 
0337         if (value.compare(QStringLiteral("excludeMimetypes"), Qt::CaseInsensitive) == 0) {
0338             if (args.empty()) {
0339                 out << i18n("A mimetype must be provided\n");
0340                 return 1;
0341             }
0342 
0343             QStringList mimetypes = config.excludeMimetypes();
0344             if (mimetypes.contains(args.first())) {
0345                 out << i18n("Exclude mimetype is already in the list\n");
0346                 return 1;
0347             }
0348 
0349             mimetypes.append(args.first());
0350             config.setExcludeMimetypes(mimetypes);
0351 
0352             return 0;
0353         }
0354 
0355         out << i18n("Config parameter could not be found\n");
0356         return 1;
0357     }
0358 
0359     if (command == QLatin1String("set")) {
0360         if (args.isEmpty()) {
0361             out << i18n("The following configuration options may be modified:\n\n");
0362 
0363             printCommand(QStringLiteral("hidden"), i18n("Controls if Baloo indexes hidden files and folders"));
0364             printCommand(QStringLiteral("contentIndexing"), i18n("Controls if Baloo indexes file content"));
0365             return 0;
0366         }
0367 
0368         IndexerConfig config;
0369         QString configParam = args.takeFirst();
0370 
0371         if (configParam == QLatin1String("hidden"))  {
0372             if (args.isEmpty()) {
0373                 out << i18n("A value must be provided\n");
0374                 return 1;
0375             }
0376 
0377             QString value = args.takeFirst();
0378             if (value.compare(QLatin1String("true"), Qt::CaseInsensitive) == 0
0379                     || value.compare(QLatin1String("y"), Qt::CaseInsensitive) == 0
0380                     || value.compare(QLatin1String("yes"), Qt::CaseInsensitive) == 0
0381                     || value.compare(QLatin1String("1")) == 0) {
0382                 config.setIndexHidden(true);
0383                 return 0;
0384             }
0385 
0386             if (value.compare(QLatin1String("false"), Qt::CaseInsensitive) == 0
0387                     || value.compare(QLatin1String("n"), Qt::CaseInsensitive) == 0
0388                     || value.compare(QLatin1String("no"), Qt::CaseInsensitive) == 0
0389                     || value.compare(QLatin1String("0")) == 0) {
0390                 config.setIndexHidden(false);
0391                 return 0;
0392             }
0393 
0394             out << i18n("Invalid value\n");
0395             return 1;
0396         }
0397 
0398         if (configParam.compare(QStringLiteral("contentIndexing"), Qt::CaseInsensitive) == 0)  {
0399             if (args.isEmpty()) {
0400                 out << i18n("A value must be provided\n");
0401                 return 1;
0402             }
0403 
0404             QString value = args.takeFirst();
0405             if (value.compare(QLatin1String("true"), Qt::CaseInsensitive) == 0
0406                     || value.compare(QLatin1String("y"), Qt::CaseInsensitive) == 0
0407                     || value.compare(QLatin1String("yes"), Qt::CaseInsensitive) == 0
0408                     || value.compare(QLatin1String("1")) == 0) {
0409                 config.setOnlyBasicIndexing(false);
0410                 return 0;
0411             }
0412 
0413             if (value.compare(QLatin1String("false"), Qt::CaseInsensitive) == 0
0414                     || value.compare(QLatin1String("n"), Qt::CaseInsensitive) == 0
0415                     || value.compare(QLatin1String("no"), Qt::CaseInsensitive) == 0
0416                     || value.compare(QLatin1String("0")) == 0) {
0417                 config.setOnlyBasicIndexing(true);
0418                 return 0;
0419             }
0420 
0421             out << i18n("Invalid value\n");
0422             return 1;
0423         }
0424 
0425         out << i18n("Config parameter could not be found\n");
0426         return 1;
0427     }
0428 
0429     return 0;
0430 }