diff options
Diffstat (limited to 'src/core/EntrySearcher.cpp')
-rw-r--r-- | src/core/EntrySearcher.cpp | 44 |
1 files changed, 32 insertions, 12 deletions
diff --git a/src/core/EntrySearcher.cpp b/src/core/EntrySearcher.cpp index 21b86a7a1..3b9472c6f 100644 --- a/src/core/EntrySearcher.cpp +++ b/src/core/EntrySearcher.cpp @@ -21,8 +21,9 @@ #include "core/Group.h" #include "core/Tools.h" -EntrySearcher::EntrySearcher(bool caseSensitive) +EntrySearcher::EntrySearcher(bool caseSensitive, bool skipProtected) : m_caseSensitive(caseSensitive) + , m_skipProtected(skipProtected) , m_termParser(R"re(([-!*+]+)?(?:(\w*):)?(?:(?=")"((?:[^"\\]|\\.)*)"|([^ ]*))( |$))re") // Group 1 = modifiers, Group 2 = field, Group 3 = quoted string, Group 4 = unquoted string { @@ -54,7 +55,6 @@ QList<Entry*> EntrySearcher::search(const QList<SearchTerm>& searchTerms, const QList<Entry*> EntrySearcher::search(const QString& searchString, const Group* baseGroup, bool forceSearch) { Q_ASSERT(baseGroup); - parseSearchTerms(searchString); return repeat(baseGroup, forceSearch); } @@ -73,7 +73,7 @@ QList<Entry*> EntrySearcher::repeat(const Group* baseGroup, bool forceSearch) QList<Entry*> results; for (const auto group : baseGroup->groupsRecursive(true)) { if (forceSearch || group->resolveSearchingEnabled()) { - for (auto* entry : group->entries()) { + for (const auto entry : group->entries()) { if (searchEntryImpl(entry)) { results.append(entry); } @@ -137,19 +137,23 @@ void EntrySearcher::setCaseSensitive(bool state) m_caseSensitive = state; } -bool EntrySearcher::isCaseSensitive() +bool EntrySearcher::isCaseSensitive() const { return m_caseSensitive; } -bool EntrySearcher::searchEntryImpl(Entry* entry) +bool EntrySearcher::searchEntryImpl(const Entry* entry) { // Pre-load in case they are needed auto attributes_keys = entry->attributes()->customKeys(); auto attributes = QStringList(attributes_keys + entry->attributes()->values(attributes_keys)); auto attachments = QStringList(entry->attachments()->keys()); + // Build a group hierarchy to allow searching for e.g. /group1/subgroup* + auto hierarchy = entry->group()->hierarchy().join('/').prepend("/"); - bool found; + // By default, empty term matches every entry. + // However when skipping protected fields, we will recject everything instead + bool found = !m_skipProtected; for (const auto& term : m_searchTerms) { switch (term.field) { case Field::Title: @@ -159,6 +163,9 @@ bool EntrySearcher::searchEntryImpl(Entry* entry) found = term.regex.match(entry->resolvePlaceholder(entry->username())).hasMatch(); break; case Field::Password: + if (m_skipProtected) { + continue; + } found = term.regex.match(entry->resolvePlaceholder(entry->password())).hasMatch(); break; case Field::Url: @@ -174,13 +181,20 @@ bool EntrySearcher::searchEntryImpl(Entry* entry) found = !attachments.filter(term.regex).empty(); break; case Field::AttributeValue: - // skip protected attributes - if (entry->attributes()->isProtected(term.word)) { + if (m_skipProtected && entry->attributes()->isProtected(term.word)) { continue; } found = entry->attributes()->contains(term.word) && term.regex.match(entry->attributes()->value(term.word)).hasMatch(); break; + case Field::Group: + // Match against the full hierarchy if the word contains a '/' otherwise just the group name + if (term.word.contains('/')) { + found = term.regex.match(hierarchy).hasMatch(); + } else { + found = term.regex.match(entry->group()->name()).hasMatch(); + } + break; default: // Terms without a specific field try to match title, username, url, and notes found = term.regex.match(entry->resolvePlaceholder(entry->title())).hasMatch() @@ -189,13 +203,18 @@ bool EntrySearcher::searchEntryImpl(Entry* entry) || term.regex.match(entry->notes()).hasMatch(); } - // Short circuit if we failed to match or we matched and are excluding this term - if ((!found && !term.exclude) || (found && term.exclude)) { + // negate the result if exclude: + // * if found and not excluding, the entry matches + // * if didn't found but excluding, the entry also matches + found = (found && !term.exclude) || (!found && term.exclude); + + // short circuit if we failed the match + if (!found) { return false; } } - return true; + return found; } void EntrySearcher::parseSearchTerms(const QString& searchString) @@ -209,7 +228,8 @@ void EntrySearcher::parseSearchTerms(const QString& searchString) {QStringLiteral("title"), Field::Title}, {QStringLiteral("u"), Field::Username}, // u: stands for username rather than url {QStringLiteral("url"), Field::Url}, - {QStringLiteral("username"), Field::Username}}; + {QStringLiteral("username"), Field::Username}, + {QStringLiteral("group"), Field::Group}}; m_searchTerms.clear(); auto results = m_termParser.globalMatch(searchString); |