SearchResultList ShareManager::search(SearchQuery&& query, size_t maxResults) noexcept { SearchResultList results; Lock l(cs); if(query.root != NULL) { auto i = tthIndex.find(*(query.root)); if(i != tthIndex.end()) { results.push_back(new SearchResult(SearchResult::TYPE_FILE, i->second->getSize(), i->second->getParent()->getFullName() + i->second->getName(), i->second->tth)); addHits(1); } return results; } for(auto& i: query.includeInit) { if(!bloom.match(i.getPattern())) return results; } for(auto& dir: directories) { dir.second->search(results, query, maxResults); if(results.size() >= maxResults) { return results; } } return results; }
api_return SearchResultInfo::download(const string& aTargetDirectory, const string& aTargetName, TargetUtil::TargetType aTargetType, QueueItemBase::Priority aPrio) { bool fileDownload = sr->getType() == SearchResult::TYPE_FILE; auto download = [&](const SearchResultPtr& aSR) { if (fileDownload) { QueueManager::getInstance()->createFileBundle(aTargetDirectory + aTargetName, sr->getSize(), sr->getTTH(), sr->getUser(), sr->getDate(), 0, aPrio); } else { DirectoryListingManager::getInstance()->addDirectoryDownload(aSR->getFilePath(), aTargetName, aSR->getUser(), aTargetDirectory, aTargetType, false, aPrio, false, 0, false, false); } }; if (hits >= 1) { //perform also for the children SearchResultList results = { sr }; for (auto si : children) results.push_back(si->sr); SearchResult::pickResults(results, SETTING(MAX_AUTO_MATCH_SOURCES)); boost::for_each(results, download); } else { //perform for the parent download(sr); } return websocketpp::http::status_code::ok; }
void SearchManager::respond(const AdcCommand& adc, const CID& from) { // Filter own searches if(from == ClientManager::getInstance()->getMe()->getCID()) return; UserPtr p = ClientManager::getInstance()->findUser(from); if(!p) return; SearchResultList results; ShareManager::getInstance()->search(results, adc.getParameters(), 10); string token; adc.getParam("TO", 0, token); if(results.empty()) return; for(SearchResultList::const_iterator i = results.begin(); i != results.end(); ++i) { AdcCommand cmd = (*i)->toRES(AdcCommand::TYPE_UDP); if(!token.empty()) cmd.addParam("TO", token); ClientManager::getInstance()->send(cmd, from); } }
void FindResultsTab::OnSearchMatch(wxCommandEvent& e) { SearchResultList* res = (SearchResultList*)e.GetClientData(); if(!res) return; int m = m_book ? m_book->GetPageIndex(m_recv) : 0; if(m == wxNOT_FOUND) { wxDELETE(res); return; } MatchInfo& matchInfo = GetMatchInfo(m); for(SearchResultList::iterator iter = res->begin(); iter != res->end(); iter++) { if(matchInfo.empty() || matchInfo.rbegin()->second.GetFileName() != iter->GetFileName()) { if(!matchInfo.empty()) { AppendText("\n"); } wxFileName fn(iter->GetFileName()); fn.MakeRelativeTo(); AppendText(fn.GetFullPath() + wxT("\n")); } int lineno = m_recv->GetLineCount() - 1; matchInfo.insert(std::make_pair(lineno, *iter)); wxString text = iter->GetPattern(); int delta = -text.Length(); text.Trim(false); delta += text.Length(); text.Trim(); wxString linenum; if(iter->GetMatchState() == CppWordScanner::STATE_CPP_COMMENT || iter->GetMatchState() == CppWordScanner::STATE_C_COMMENT) linenum = wxString::Format(wxT(" %5u //"), iter->GetLineNumber()); else linenum = wxString::Format(wxT(" %5u "), iter->GetLineNumber()); SearchData* d = GetSearchData(m_recv); // Print the scope name if(d->GetDisplayScope()) { TagEntryPtr tag = TagsManagerST::Get()->FunctionFromFileLine(iter->GetFileName(), iter->GetLineNumber()); wxString scopeName(wxT("global")); if(tag) { scopeName = tag->GetPath(); } linenum << wxT("[ ") << scopeName << wxT(" ] "); iter->SetScope(scopeName); } delta += linenum.Length(); AppendText(linenum + text + wxT("\n")); m_recv->IndicatorFillRange(m_sci->PositionFromLine(lineno) + iter->GetColumn() + delta, iter->GetLen()); } wxDELETE(res); }
void FindResultsTab::OnSearchMatch(wxCommandEvent& e) { SearchResultList* res = (SearchResultList*)e.GetClientData(); if(!res) return; SearchResultList::iterator iter = res->begin(); for(; iter != res->end(); ++iter) { if(m_matchInfo.empty() || m_matchInfo.rbegin()->second.GetFileName() != iter->GetFileName()) { if(!m_matchInfo.empty()) { AppendText("\n"); } wxFileName fn(iter->GetFileName()); fn.MakeRelativeTo(); AppendText(fn.GetFullPath() + wxT("\n")); } int lineno = m_sci->GetLineCount() - 1; m_matchInfo.insert(std::make_pair(lineno, *iter)); wxString text = iter->GetPattern(); // int delta = -text.Length(); // text.Trim(false); // delta += text.Length(); // text.Trim(); wxString linenum = wxString::Format(wxT(" %5u: "), iter->GetLineNumber()); SearchData* d = GetSearchData(); // Print the scope name if(d->GetDisplayScope()) { TagEntryPtr tag = TagsManagerST::Get()->FunctionFromFileLine(iter->GetFileName(), iter->GetLineNumber()); wxString scopeName(wxT("global")); if(tag) { scopeName = tag->GetPath(); } linenum << wxT("[ ") << scopeName << wxT(" ] "); iter->SetScope(scopeName); } AppendText(linenum + text + wxT("\n")); int indicatorStartPos = m_sci->PositionFromLine(lineno) + iter->GetColumn() + linenum.Length(); int indicatorLen = iter->GetLen(); m_indicators.push_back(indicatorStartPos); m_sci->IndicatorFillRange(indicatorStartPos, indicatorLen); } wxDELETE(res); }
void SearchManager::respond(const AdcCommand& adc, const CID& from, bool isUdpActive, const string& hubIpPort) { // Filter own searches if(from == ClientManager::getInstance()->getMe()->getCID()) return; UserPtr p = ClientManager::getInstance()->findUser(from); if(!p) return; SearchResultList results; ShareManager::getInstance()->search(results, adc.getParameters(), isUdpActive ? 10 : 5); string token; adc.getParam("TO", 0, token); // TODO: don't send replies to passive users if(results.empty()) { string tth; if(!adc.getParam("TR", 0, tth)) return; PartsInfo partialInfo; if(!QueueManager::getInstance()->handlePartialSearch(TTHValue(tth), partialInfo)) { // if not found, try to find in finished list if(!FinishedManager::getInstance()->handlePartialRequest(TTHValue(tth), partialInfo)) { return; } } AdcCommand cmd = toPSR(true, Util::emptyString, hubIpPort, tth, partialInfo); ClientManager::getInstance()->send(cmd, from); return; } for(SearchResultList::const_iterator i = results.begin(); i != results.end(); ++i) { AdcCommand cmd = (*i)->toRES(AdcCommand::TYPE_UDP); if(!token.empty()) cmd.addParam("TO", token); ClientManager::getInstance()->send(cmd, from); } }
void SearchResult::pickResults(SearchResultList& aResults, int aMaxCount) noexcept { if (static_cast<int>(aResults.size()) <= aMaxCount) { // we can pick all matches } else { // pick the best matches sort(aResults.begin(), aResults.end(), SearchResult::SpeedSortOrder()); aResults.erase(aResults.begin() + aMaxCount, aResults.end()); } }
void SearchResult::pickResults(SearchResultList& aResults, int pickedNum) { if (static_cast<int>(aResults.size()) <= pickedNum) { //we can pick all matches } else { //pick the best matches sort(aResults.begin(), aResults.end(), SearchResult::SpeedSortOrder()); aResults.erase(aResults.begin()+pickedNum, aResults.end()); } }
/** * Alright, the main point here is that when searching, a search string is most often found in * the filename, not directory name, so we want to make that case faster. Also, we want to * avoid changing StringLists unless we absolutely have to --> this should only be done if a string * has been matched in the directory name. This new stringlist should also be used in all descendants, * but not the parents... */ void ShareManager::Directory::search(SearchResultList& results, SearchQuery& query, size_t maxResults) const noexcept { if(query.isExcluded(name)) return; // Find any matches in the directory name and removed matched terms from the query. StringSearch::List newTerms; for(auto& term: query.include) { if(term.match(name)) { if(!newTerms.empty()) { newTerms = query.include; } newTerms.erase(remove(newTerms.begin(), newTerms.end(), term), newTerms.end()); } } // auto const old = query.include; if(!newTerms.empty()) { query.include = newTerms; } if(query.include.empty() && query.ext.empty() && query.gt == 0) { // We satisfied all the search words! Add the directory... /// @todo send the directory hash when we have one results.push_back(new SearchResult(SearchResult::TYPE_DIRECTORY, getSize(), getFullName(), TTHValue(string(39, 'A')))); ShareManager::getInstance()->addHits(1); } if(!query.isDirectory) { for(auto& i: files) { if(!i.tth) { continue; } // check the size if(!(i.getSize() >= query.gt)) { continue; } else if(!(i.getSize() <= query.lt)) { continue; } if(query.isExcluded(i.getName())) continue; // check if the name matches auto j = query.include.begin(); for(; j != query.include.end() && j->match(i.getName()); ++j) ; // Empty if(j != query.include.end()) continue; // check extensions if(!query.hasExt(i.getName())) continue; results.push_back(new SearchResult(SearchResult::TYPE_FILE, i.getSize(), getFullName() + i.getName(), (i.tth))); ShareManager::getInstance()->addHits(1); if(results.size() >= maxResults) { return; } } } for(auto& dir: directories) { dir.second->search(results, query, maxResults); if(results.size() >= maxResults) { return; } } }
int main( int /*argc*/, char** /*argv*/ ) { int fail = 0; std::string name; // ------- { name = "fetch fields"; Search::Query sq; Tag* t = sq.tag(); if( !t || t->xml() != "<query xmlns='" + XMLNS_SEARCH + "'/>" ) { ++fail; printf( "test '%s' failed\n", name.c_str() ); } delete t; } // ------- { name = "receive search fields"; Tag* d = new Tag( "query" ); d->setXmlns( XMLNS_SEARCH ); new Tag( d, "instructions", "foobar" ); new Tag( d, "first" ); new Tag( d, "last" ); new Tag( d, "email" ); new Tag( d, "nick" ); Search::Query sq( d ); Tag* t = sq.tag(); if( !t || t->xml() != "<query xmlns='" + XMLNS_SEARCH + "'>" "<instructions>foobar</instructions>" "<first/>" "<last/>" "<nick/>" "<email/>" "</query>" || sq.instructions() != "foobar" || sq.fields() != ( SearchFieldFirst | SearchFieldLast | SearchFieldNick | SearchFieldEmail ) ) { ++fail; printf( "test '%s' failed\n", name.c_str() ); } delete t; delete d; } // ------- { name = "receive search form"; Tag* d = new Tag( "query" ); d->setXmlns( XMLNS_SEARCH ); Tag* f = new Tag( d, "x" ); f->setXmlns( XMLNS_X_DATA ); f->addAttribute( "type", "form" ); Search::Query sq( d ); Tag* t = sq.tag(); if( !t || t->xml() != "<query xmlns='" + XMLNS_SEARCH + "'>" "<x xmlns='" + XMLNS_X_DATA + "' type='form'/>" "</query>" || !sq.form() ) { ++fail; printf( "test '%s' failed: %s\n", name.c_str(), t->xml().c_str() ); } delete t; delete d; } // ------- { name = "search by form"; DataForm* form = new DataForm( TypeSubmit ); Search::Query sq( form ); Tag* t = sq.tag(); if( !t || t->xml() != "<query xmlns='" + XMLNS_SEARCH + "'>" "<x xmlns='" + XMLNS_X_DATA + "' type='submit'/>" "</query>" ) { ++fail; printf( "test '%s' failed\n", name.c_str() ); } delete t; } // ------- { name = "search by fields"; SearchFieldStruct sfs( "first", "last", "nick", "email" ); Search::Query sq( SearchFieldFirst | SearchFieldLast | SearchFieldNick | SearchFieldEmail, sfs ); Tag* t = sq.tag(); if( !t || t->xml() != "<query xmlns='" + XMLNS_SEARCH + "'>" "<first>first</first>" "<last>last</last>" "<nick>nick</nick>" "<email>email</email>" "</query>" ) { ++fail; printf( "test '%s' failed\n", name.c_str() ); } delete t; } // ------- { name = "receive form result"; Tag* d = new Tag( "query" ); d->setXmlns( XMLNS_SEARCH ); Tag* f = new Tag( d, "x" ); f->setXmlns( XMLNS_X_DATA ); f->addAttribute( "type", "result" ); Search::Query sq( d ); Tag* t = sq.tag(); if( !t || t->xml() != "<query xmlns='" + XMLNS_SEARCH + "'>" "<x xmlns='" + XMLNS_X_DATA + "' type='result'/>" "</query>" ) { ++fail; printf( "test '%s' failed\n", name.c_str() ); } delete t; delete d; } // ------- { name = "receive fields result"; Tag* d = new Tag( "query" ); d->setXmlns( XMLNS_SEARCH ); Tag* i = new Tag( d, "item" ); i->addAttribute( "jid", "foo@bar" ); new Tag( i, "first", "first1" ); new Tag( i, "last", "last1" ); new Tag( i, "email", "email1" ); new Tag( i, "nick", "nick1" ); i = new Tag( d, "item" ); i->addAttribute( "jid", "foo@bar2" ); new Tag( i, "first", "first2" ); new Tag( i, "last", "last2" ); new Tag( i, "nick", "nick2" ); new Tag( i, "email", "email2" ); Search::Query sq( d ); Tag* t = sq.tag(); SearchResultList srl = sq.result(); if( !t || t->xml() != "<query xmlns='" + XMLNS_SEARCH + "'>" "<item jid='foo@bar'>" "<first>first1</first>" "<last>last1</last>" "<nick>nick1</nick>" "<email>email1</email></item>" "<item jid='foo@bar2'>" "<first>first2</first>" "<last>last2</last>" "<nick>nick2</nick>" "<email>email2</email></item>" "</query>" || srl.size() != 2 ) { ++fail; printf( "test '%s' failed: %s\n", name.c_str(), t->xml().c_str() ); } delete t; delete d; } // ------- name = "Search::Query/SEFactory test"; StanzaExtensionFactory sef; sef.registerExtension( new Search::Query() ); Tag* f = new Tag( "iq" ); new Tag( f, "query", "xmlns", XMLNS_SEARCH ); IQ iq( IQ::Get, JID() ); sef.addExtensions( iq, f ); const Search::Query* se = iq.findExtension<Search::Query>( ExtSearch ); if( se == 0 ) { ++fail; printf( "test '%s' failed\n", name.c_str() ); } delete f; printf( "Search::Query: " ); if( fail == 0 ) { printf( "OK\n" ); return 0; } else { printf( "%d test(s) failed\n", fail ); return 1; } }
bool Search::handleIqID( Stanza *stanza, int context ) { TrackMap::iterator it = m_track.find( stanza->id() ); if( it != m_track.end() ) { switch( stanza->subtype() ) { case StanzaIqResult: switch( context ) { case FetchSearchFields: { Tag *q = stanza->findChild( "query" ); if( q && q->hasAttribute( "xmlns", XMLNS_SEARCH ) ) { Tag *x = q->findChild( "x", "xmlns", XMLNS_X_DATA ); if( x ) { DataForm *df = new DataForm( x ); (*it).second->handleSearchFields( stanza->from(), df ); } else { int fields = 0; std::string instructions; if( q->hasChild( "first" ) ) fields |= SearchFieldFirst; if( q->hasChild( "last" ) ) fields |= SearchFieldLast; if( q->hasChild( "nick" ) ) fields |= SearchFieldNick; if( q->hasChild( "email" ) ) fields |= SearchFieldEmail; if( q->hasChild( "instructions" ) ) instructions = q->findChild( "instructions" )->cdata(); (*it).second->handleSearchFields( stanza->from(), fields, instructions ); } } break; } case DoSearch: { Tag *q = stanza->findChild( "query" ); if( q && q->hasAttribute( "xmlns", XMLNS_SEARCH ) ) { Tag *x = q->findChild( "x", "xmlns", XMLNS_X_DATA ); if( x ) { DataForm *df = new DataForm( x ); (*it).second->handleSearchResult( stanza->from(), df ); } else { SearchResultList e; SearchFieldStruct s; const Tag::TagList &l = q->children(); Tag::TagList::const_iterator itl = l.begin(); for( ; itl != l.end(); ++itl ) { if( (*itl)->name() == "item" ) { s.jid.setJID( (*itl)->findAttribute( "jid" ) ); Tag *t = 0; if( ( t = (*itl)->findChild( "first" ) ) != 0 ) s.first = t->cdata(); if( ( t = (*itl)->findChild( "last" ) ) != 0 ) s.last = t->cdata(); if( ( t = (*itl)->findChild( "nick" ) ) != 0 ) s.nick = t->cdata(); if( ( t = (*itl)->findChild( "email" ) ) != 0 ) s.email = t->cdata(); e.push_back( s ); } } (*it).second->handleSearchResult( stanza->from(), e ); } } break; } } break; case StanzaIqError: (*it).second->handleSearchError( stanza->from(), stanza ); break; default: break; } m_track.erase( it ); } return false; }