diff --git a/filenamesearch/CMakeLists.txt b/filenamesearch/CMakeLists.txt index b1dddf0b..768b276b 100644 --- a/filenamesearch/CMakeLists.txt +++ b/filenamesearch/CMakeLists.txt @@ -1,8 +1,8 @@ add_library(kio_filenamesearch MODULE kio_filenamesearch.cpp) -target_link_libraries(kio_filenamesearch KF5::KIOCore KF5::DBusAddons Qt5::Network) +target_link_libraries(kio_filenamesearch KF5::KIOCore KF5::DBusAddons Qt5::Network KF5::KIOCore KF5::I18n) set_target_properties(kio_filenamesearch PROPERTIES OUTPUT_NAME "filenamesearch") install(TARGETS kio_filenamesearch DESTINATION ${KDE_INSTALL_PLUGINDIR}/kf5/kio) install(FILES filenamesearch.protocol DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) add_subdirectory(kded) diff --git a/filenamesearch/kio_filenamesearch.cpp b/filenamesearch/kio_filenamesearch.cpp index 2ffee969..57d4e986 100644 --- a/filenamesearch/kio_filenamesearch.cpp +++ b/filenamesearch/kio_filenamesearch.cpp @@ -1,183 +1,206 @@ /*************************************************************************** * Copyright (C) 2010 by Peter Penz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ***************************************************************************/ #include "kio_filenamesearch.h" #include #include #include #include #include #include #include #include #include #include +#include Q_LOGGING_CATEGORY(KIO_FILENAMESEARCH, "kio_filenamesearch") FileNameSearchProtocol::FileNameSearchProtocol(const QByteArray &pool, const QByteArray &app) : SlaveBase("search", pool, app) { QDBusInterface kded(QStringLiteral("org.kde.kded5"), QStringLiteral("/kded"), QStringLiteral("org.kde.kded5")); kded.call(QStringLiteral("loadModule"), QStringLiteral("filenamesearchmodule")); } FileNameSearchProtocol::~FileNameSearchProtocol() { } +void FileNameSearchProtocol::stat(const QUrl& url) +{ + KIO::UDSEntry uds; + uds.reserve(9); + uds.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0700); + uds.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); + uds.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("inode/directory")); + uds.fastInsert(KIO::UDSEntry::UDS_ICON_OVERLAY_NAMES, QStringLiteral("baloo")); + uds.fastInsert(KIO::UDSEntry::UDS_DISPLAY_TYPE, i18n("Search Folder")); + uds.fastInsert(KIO::UDSEntry::UDS_URL, url.url()); + + QUrlQuery query(url); + QString title = query.queryItemValue(QStringLiteral("title"), QUrl::FullyDecoded); + if (!title.isEmpty()) { + uds.fastInsert(KIO::UDSEntry::UDS_NAME, title); + uds.fastInsert(KIO::UDSEntry::UDS_DISPLAY_NAME, title); + } + + statEntry(uds); + finished(); +} + void FileNameSearchProtocol::listDir(const QUrl &url) { const QUrlQuery urlQuery(url); const QString search = urlQuery.queryItemValue("search"); if (search.isEmpty()) { finished(); return; } const QRegularExpression pattern(search, QRegularExpression::CaseInsensitiveOption); std::function validator; if (urlQuery.queryItemValue("checkContent") == QStringLiteral("yes")) { validator = [pattern](const KFileItem &item) -> bool { return item.determineMimeType().inherits(QStringLiteral("text/plain")) && contentContainsPattern(item.url(), pattern); }; } else { validator = [pattern](const KFileItem &item) -> bool { return item.text().contains(pattern); }; } QSet iteratedDirs; const QUrl directory(urlQuery.queryItemValue("url")); searchDirectory(directory, validator, iteratedDirs); finished(); } void FileNameSearchProtocol::searchDirectory(const QUrl &directory, const std::function &itemValidator, QSet &iteratedDirs) { if (directory.path() == QStringLiteral("/proc")) { // Don't try to iterate the /proc directory of Linux return; } // Get all items of the directory QScopedPointer dirLister(new KCoreDirLister); dirLister->setDelayedMimeTypes(true); dirLister->openUrl(directory); QEventLoop eventLoop; QObject::connect(dirLister.data(), static_cast(&KCoreDirLister::canceled), &eventLoop, &QEventLoop::quit); QObject::connect(dirLister.data(), static_cast(&KCoreDirLister::completed), &eventLoop, &QEventLoop::quit); eventLoop.exec(); // Visualize all items that match the search pattern QList pendingDirs; const KFileItemList items = dirLister->items(); for (const KFileItem &item : items) { if (itemValidator(item)) { KIO::UDSEntry entry = item.entry(); entry.replace(KIO::UDSEntry::UDS_URL, item.url().url()); listEntry(entry); } if (item.isDir()) { if (item.isLink()) { // Assure that no endless searching is done in directories that // have already been iterated. const QUrl linkDest = item.url().resolved(QUrl::fromLocalFile(item.linkDest())); if (!iteratedDirs.contains(linkDest.path())) { pendingDirs.append(linkDest); } } else { pendingDirs.append(item.url()); } } } iteratedDirs.insert(directory.path()); dirLister.reset(); // Recursively iterate all sub directories for (const QUrl &pendingDir : qAsConst(pendingDirs)) { searchDirectory(pendingDir, itemValidator, iteratedDirs); } } bool FileNameSearchProtocol::contentContainsPattern(const QUrl &fileName, const QRegularExpression &pattern) { auto fileContainsPattern = [&pattern](const QString &path) -> bool { QFile file(path); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return false; } QTextStream in(&file); while (!in.atEnd()) { const QString line = in.readLine(); if (line.contains(pattern)) { return true; } } return false; }; if (fileName.isLocalFile()) { return fileContainsPattern(fileName.toLocalFile()); } else { QTemporaryFile tempFile; if (tempFile.open()) { KIO::Job* getJob = KIO::file_copy(fileName, QUrl::fromLocalFile(tempFile.fileName()), -1, KIO::Overwrite | KIO::HideProgressInfo); if (getJob->exec()) { // The non-local file was downloaded successfully. return fileContainsPattern(tempFile.fileName()); } } } return false; } extern "C" int Q_DECL_EXPORT kdemain(int argc, char **argv) { QCoreApplication app(argc, argv); if (argc != 4) { qCDebug(KIO_FILENAMESEARCH) << "Usage: kio_filenamesearch protocol domain-socket1 domain-socket2"; return -1; } FileNameSearchProtocol slave(argv[2], argv[3]); slave.dispatchLoop(); return 0; } diff --git a/filenamesearch/kio_filenamesearch.h b/filenamesearch/kio_filenamesearch.h index c867584e..90fd2372 100644 --- a/filenamesearch/kio_filenamesearch.h +++ b/filenamesearch/kio_filenamesearch.h @@ -1,62 +1,63 @@ /*************************************************************************** * Copyright (C) 2010 by Peter Penz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ***************************************************************************/ #ifndef KIO_FILENAMESEARCH_H #define KIO_FILENAMESEARCH_H #include #include #include class QUrl; class QRegularExpression; class KFileItem; Q_DECLARE_LOGGING_CATEGORY(KIO_FILENAMESEARCH) /** * @brief Lists files where the filename matches do a given query. * * The query is defined as part of the "search" query item of the URL. * The directory where the searching is started is defined in the "url" query * item. If the query item "checkContent" is set to "yes", all files with * a text MIME type will be checked for the content. */ class FileNameSearchProtocol : public KIO::SlaveBase { public: FileNameSearchProtocol(const QByteArray &pool, const QByteArray &app); ~FileNameSearchProtocol() override; + void stat(const QUrl& url) override; void listDir(const QUrl &url) override; private: void searchDirectory(const QUrl &directory, const std::function &itemValidator, QSet &iteratedDirs); /** * @return True, if the \a pattern is part of the file \a fileName. */ static bool contentContainsPattern(const QUrl &fileName, const QRegularExpression &pattern); }; #endif