diff --git a/src/kioslaves/search/kio_search.cpp b/src/kioslaves/search/kio_search.cpp index db1cf85d..813ca466 100644 --- a/src/kioslaves/search/kio_search.cpp +++ b/src/kioslaves/search/kio_search.cpp @@ -1,229 +1,188 @@ /* Copyright (C) 2008-2010 by Sebastian Trueg Copyright (C) 2012-2014 by Vishesh Handa 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, 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_search.h" #include "query.h" #include "resultiterator.h" #include "idutils.h" #include #include #include #include #include #include using namespace Baloo; namespace { KIO::UDSEntry statSearchFolder(const QUrl& url) { KIO::UDSEntry uds; uds.reserve(9); uds.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0700); uds.fastInsert(KIO::UDSEntry::UDS_USER, KUser().loginName()); 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); } return uds; } } SearchProtocol::SearchProtocol(const QByteArray& poolSocket, const QByteArray& appSocket) : KIO::SlaveBase("baloosearch", poolSocket, appSocket) { } SearchProtocol::~SearchProtocol() { } -static QString jsonQueryForType(const QString &type) -{ - const QString jsonQuery(QStringLiteral("{\"dayFilter\": 0,\ - \"monthFilter\": 0, \ - \"yearFilter\": 0, \ - \"type\": [ \"%1\"]}")); - return jsonQuery.arg(type); -} - -static QString jsonQueryFromUrl(const QUrl &url) -{ - const QString path = url.path(); - - if (path == QLatin1String("/documents")) { - return jsonQueryForType(QStringLiteral("Document")); - } else if (path.endsWith(QLatin1String("/images"))) { - return jsonQueryForType(QStringLiteral("Image")); - } else if (path.endsWith(QLatin1String("/audio"))) { - return jsonQueryForType(QStringLiteral("Audio")); - } else if (path.endsWith(QLatin1String("/videos"))) { - return jsonQueryForType(QStringLiteral("Video")); - } - - return QString(); -} - void SearchProtocol::listDir(const QUrl& url) { - Query q; - - QUrlQuery urlQuery(url); - if (urlQuery.hasQueryItem(QStringLiteral("json"))) { - QString jsonString = urlQuery.queryItemValue(QStringLiteral("json"), QUrl::FullyDecoded); - q = Query::fromJSON(jsonString.toUtf8()); - } else if (urlQuery.hasQueryItem(QStringLiteral("query"))) { - QString queryString = urlQuery.queryItemValue(QStringLiteral("query"), QUrl::FullyDecoded); - - q.setSearchString(queryString); - } else { - const QString jsonString = jsonQueryFromUrl(url); - if (!jsonString.isEmpty()) { - q = Query::fromJSON(jsonString.toUtf8()); - } - } + Query q = Query::fromSearchUrl(url); q.setSortingOption(Query::SortNone); ResultIterator it = q.exec(); while (it.next()) { KIO::UDSEntry uds; uds.reserve(10); const QString filePath(it.filePath()); // Code from kdelibs/kioslaves/file.cpp QT_STATBUF statBuf; const QByteArray ba = QFile::encodeName(filePath); if (filePathToStat(ba, statBuf) == 0) { uds.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, statBuf.st_mtime); uds.fastInsert(KIO::UDSEntry::UDS_ACCESS_TIME, statBuf.st_atime); uds.fastInsert(KIO::UDSEntry::UDS_SIZE, statBuf.st_size); #ifndef Q_OS_WIN uds.fastInsert(KIO::UDSEntry::UDS_USER, getUserName(KUserId(statBuf.st_uid))); uds.fastInsert(KIO::UDSEntry::UDS_GROUP, getGroupName(KGroupId(statBuf.st_gid))); #else #pragma message("TODO: st_uid and st_gid are always zero, use GetSecurityInfo to find the owner") #endif mode_t type = statBuf.st_mode & S_IFMT; mode_t access = statBuf.st_mode & 07777; uds.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, type); uds.fastInsert(KIO::UDSEntry::UDS_ACCESS, access); } else { continue; } QUrl url = QUrl::fromLocalFile(filePath); uds.fastInsert(KIO::UDSEntry::UDS_NAME, url.fileName()); uds.fastInsert(KIO::UDSEntry::UDS_URL, url.url()); uds.fastInsert(KIO::UDSEntry::UDS_LOCAL_PATH, filePath); listEntry(uds); } KIO::UDSEntry uds; uds.reserve(5); uds.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral(".")); uds.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); uds.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("inode/directory")); uds.fastInsert(KIO::UDSEntry::UDS_ACCESS, 0700); uds.fastInsert(KIO::UDSEntry::UDS_USER, KUser().loginName()); listEntry(uds); finished(); } void SearchProtocol::mimetype(const QUrl&) { mimeType(QStringLiteral("inode/directory")); finished(); } void SearchProtocol::stat(const QUrl& url) { statEntry(statSearchFolder(url)); finished(); } QString SearchProtocol::getUserName(const KUserId &uid) const { if (Q_UNLIKELY(!uid.isValid())) { return QString(); } if (!mUsercache.contains(uid)) { KUser user(uid); QString name = user.loginName(); if (name.isEmpty()) { name = uid.toString(); } mUsercache.insert(uid, name); return name; } return mUsercache[uid]; } QString SearchProtocol::getGroupName(const KGroupId &gid) const { if (Q_UNLIKELY(!gid.isValid())) { return QString(); } if (!mGroupcache.contains(gid)) { KUserGroup group(gid); QString name = group.name(); if (name.isEmpty()) { name = gid.toString(); } mGroupcache.insert(gid, name); return name; } return mGroupcache[gid]; } extern "C" { Q_DECL_EXPORT int kdemain(int argc, char** argv) { QCoreApplication app(argc, argv); app.setApplicationName(QStringLiteral("kio_baloosearch")); Baloo::SearchProtocol slave(argv[2], argv[3]); slave.dispatchLoop(); return 0; } } diff --git a/src/lib/query.cpp b/src/lib/query.cpp index 762bd0ef..0139a03a 100644 --- a/src/lib/query.cpp +++ b/src/lib/query.cpp @@ -1,362 +1,396 @@ /* * This file is part of the KDE Baloo Project * Copyright (C) 2013 Vishesh Handa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include "query.h" #include "term.h" #include "advancedqueryparser.h" #include "searchstore.h" #include "baloodebug.h" #include #include #include #include #include #include using namespace Baloo; const int defaultLimit = -1; class Baloo::Query::Private { public: Private() { m_limit = defaultLimit; m_offset = 0; m_yearFilter = 0; m_monthFilter = 0; m_dayFilter = 0; m_sortingOption = SortAuto; } Term m_term; QStringList m_types; QString m_searchString; int m_limit; uint m_offset; int m_yearFilter; int m_monthFilter; int m_dayFilter; SortingOption m_sortingOption; QString m_includeFolder; }; Query::Query() : d(new Private) { } Query::Query(const Query& rhs) : d(new Private(*rhs.d)) { } Query::~Query() { delete d; } void Query::addType(const QString& type) { d->m_types << type.split(QLatin1Char('/'), QString::SkipEmptyParts); } void Query::addTypes(const QStringList& typeList) { for (const QString& type : typeList) { addType(type); } } void Query::setType(const QString& type) { d->m_types.clear(); addType(type); } void Query::setTypes(const QStringList& types) { d->m_types = types; } QStringList Query::types() const { return d->m_types; } QString Query::searchString() const { return d->m_searchString; } void Query::setSearchString(const QString& str) { d->m_searchString = str; d->m_term = Term(); } uint Query::limit() const { return d->m_limit; } void Query::setLimit(uint limit) { d->m_limit = limit; } uint Query::offset() const { return d->m_offset; } void Query::setOffset(uint offset) { d->m_offset = offset; } void Query::setDateFilter(int year, int month, int day) { d->m_yearFilter = year; d->m_monthFilter = month; d->m_dayFilter = day; } int Query::yearFilter() const { return d->m_yearFilter; } int Query::monthFilter() const { return d->m_monthFilter; } int Query::dayFilter() const { return d->m_dayFilter; } void Query::setSortingOption(Query::SortingOption option) { d->m_sortingOption = option; } Query::SortingOption Query::sortingOption() const { return d->m_sortingOption; } QString Query::includeFolder() const { return d->m_includeFolder; } void Query::setIncludeFolder(const QString& folder) { d->m_includeFolder = folder; } ResultIterator Query::exec() { if (!d->m_searchString.isEmpty()) { if (d->m_term.isValid()) { qCDebug(BALOO) << "Term already set"; } AdvancedQueryParser parser; d->m_term = parser.parse(d->m_searchString); } Term term(d->m_term); if (!d->m_types.isEmpty()) { for (const QString& type : qAsConst(d->m_types)) { term = term && Term(QStringLiteral("type"), type); } } if (!d->m_includeFolder.isEmpty()) { term = term && Term(QStringLiteral("includefolder"), d->m_includeFolder); } if (d->m_yearFilter || d->m_monthFilter || d->m_dayFilter) { QByteArray ba = QByteArray::number(d->m_yearFilter); if (d->m_monthFilter < 10) ba += '0'; ba += QByteArray::number(d->m_monthFilter); if (d->m_dayFilter < 10) ba += '0'; ba += QByteArray::number(d->m_dayFilter); term = term && Term(QStringLiteral("modified"), ba, Term::Equal); } SearchStore searchStore; QStringList result = searchStore.exec(term, d->m_offset, d->m_limit, d->m_sortingOption == SortAuto); return ResultIterator(result); } QByteArray Query::toJSON() { QVariantMap map; if (!d->m_types.isEmpty()) map[QStringLiteral("type")] = d->m_types; if (d->m_limit != defaultLimit) map[QStringLiteral("limit")] = d->m_limit; if (d->m_offset) map[QStringLiteral("offset")] = d->m_offset; if (!d->m_searchString.isEmpty()) map[QStringLiteral("searchString")] = d->m_searchString; if (d->m_term.isValid()) map[QStringLiteral("term")] = QVariant(d->m_term.toVariantMap()); if (d->m_yearFilter > 0) map[QStringLiteral("yearFilter")] = d->m_yearFilter; if (d->m_monthFilter > 0) map[QStringLiteral("monthFilter")] = d->m_monthFilter; if (d->m_dayFilter > 0) map[QStringLiteral("dayFilter")] = d->m_dayFilter; if (d->m_sortingOption != SortAuto) map[QStringLiteral("sortingOption")] = static_cast(d->m_sortingOption); if (!d->m_includeFolder.isEmpty()) map[QStringLiteral("includeFolder")] = d->m_includeFolder; QJsonObject jo = QJsonObject::fromVariantMap(map); QJsonDocument jdoc; jdoc.setObject(jo); return jdoc.toJson(QJsonDocument::JsonFormat::Compact); } // static Query Query::fromJSON(const QByteArray& arr) { QJsonDocument jdoc = QJsonDocument::fromJson(arr); const QVariantMap map = jdoc.object().toVariantMap(); Query query; query.d->m_types = map[QStringLiteral("type")].toStringList(); if (map.contains(QStringLiteral("limit"))) query.d->m_limit = map[QStringLiteral("limit")].toUInt(); else query.d->m_limit = defaultLimit; query.d->m_offset = map[QStringLiteral("offset")].toUInt(); query.d->m_searchString = map[QStringLiteral("searchString")].toString(); query.d->m_term = Term::fromVariantMap(map[QStringLiteral("term")].toMap()); if (map.contains(QStringLiteral("yearFilter"))) query.d->m_yearFilter = map[QStringLiteral("yearFilter")].toInt(); if (map.contains(QStringLiteral("monthFilter"))) query.d->m_monthFilter = map[QStringLiteral("monthFilter")].toInt(); if (map.contains(QStringLiteral("dayFilter"))) query.d->m_dayFilter = map[QStringLiteral("dayFilter")].toInt(); if (map.contains(QStringLiteral("sortingOption"))) { int option = map.value(QStringLiteral("sortingOption")).toInt(); query.d->m_sortingOption = static_cast(option); } if (map.contains(QStringLiteral("includeFolder"))) { query.d->m_includeFolder = map.value(QStringLiteral("includeFolder")).toString(); } if (!query.d->m_searchString.isEmpty() && query.d->m_term.isValid()) { qCWarning(BALOO) << "Only one of 'searchString' and 'term' should be set:" << arr; } return query; } QUrl Query::toSearchUrl(const QString& title) { QUrl url; url.setScheme(QStringLiteral("baloosearch")); QUrlQuery urlQuery; urlQuery.addQueryItem(QStringLiteral("json"), QString::fromUtf8(toJSON())); if (!title.isEmpty()) urlQuery.addQueryItem(QStringLiteral("title"), title); url.setQuery(urlQuery); return url; } +static QString jsonQueryFromUrl(const QUrl &url) +{ + const QString path = url.path(); + + if (path == QLatin1String("/documents")) { + return QStringLiteral("{\"type\":[\"Document\"]}"); + } else if (path.endsWith(QLatin1String("/images"))) { + return QStringLiteral("{\"type\":[\"Image\"]}"); + } else if (path.endsWith(QLatin1String("/audio"))) { + return QStringLiteral("{\"type\":[\"Audio\"]}"); + } else if (path.endsWith(QLatin1String("/videos"))) { + return QStringLiteral("{\"type\":[\"Video\"]}"); + } + + return QString(); +} + Query Query::fromSearchUrl(const QUrl& url) { if (url.scheme() != QLatin1String("baloosearch")) return Query(); QUrlQuery urlQuery(url); - QString jsonString = urlQuery.queryItemValue(QStringLiteral("json"), QUrl::FullyDecoded); - return Query::fromJSON(jsonString.toUtf8()); + + if (urlQuery.hasQueryItem(QStringLiteral("json"))) { + QString jsonString = urlQuery.queryItemValue(QStringLiteral("json"), QUrl::FullyDecoded); + return Query::fromJSON(jsonString.toUtf8()); + } + + if (urlQuery.hasQueryItem(QStringLiteral("query"))) { + QString queryString = urlQuery.queryItemValue(QStringLiteral("query"), QUrl::FullyDecoded); + Query q; + q.setSearchString(queryString); + return q; + } + + const QString jsonString = jsonQueryFromUrl(url); + if (!jsonString.isEmpty()) { + return Query::fromJSON(jsonString.toUtf8()); + } + + return Query(); } QString Query::titleFromQueryUrl(const QUrl& url) { QUrlQuery urlQuery(url); return urlQuery.queryItemValue(QStringLiteral("title"), QUrl::FullyDecoded); } bool Query::operator==(const Query& rhs) const { if (rhs.d->m_limit != d->m_limit || rhs.d->m_offset != d->m_offset || rhs.d->m_dayFilter != d->m_dayFilter || rhs.d->m_monthFilter != d->m_monthFilter || rhs.d->m_yearFilter != d->m_yearFilter || rhs.d->m_includeFolder != d->m_includeFolder || rhs.d->m_searchString != d->m_searchString || rhs.d->m_sortingOption != d->m_sortingOption) { return false; } if (rhs.d->m_types.size() != d->m_types.size()) return false; for (const QString& type : qAsConst(rhs.d->m_types)) { if (!d->m_types.contains(type)) return false; } return d->m_term == rhs.d->m_term; } bool Query::operator!=(const Query& rhs) const { return !(*this == rhs); } Query& Query::operator=(const Query& rhs) { *d = *rhs.d; return *this; }