/** * Send the results from a query to the asker * The query's encoding should be UTF-8 */ void Museek::SearchManager::sendSearchResults(const std::string & username, const std::string & query, uint token) { if(! museekd()->isBanned(username) && (username != museekd()->server()->username())) { SharesDatabase* db; if (museekd()->isBuddied(username)) db = museekd()->buddyshares(); else db = museekd()->shares(); Folder results; db->search(query, results); if (!results.empty()) { m_PendingResults[username][token] = results; museekd()->peers()->peerSocket(username, false); } } }
/* this is the best I can do I think... */ void Museek::SharesDatabase::search(const string& _query, Folder& result) { NNLOG("museekd.shares.debug", "sharesdatabase search %s", _query.c_str()); string query = _query; size_t results = 0; string word; if(query.empty()) return; /* add a space to make sure we also get the last word */ query += (wchar_t)' '; vector<Folder* > q_in; // foobar StringList q_out; // -foobar StringList q_part; // *foobar "foo bar" bool quoted = false, was_quoted = false; /* breaks up the query into in-groups, out-files and terms */ string::iterator sit = query.begin(); for(; sit != query.end(); ++sit) { if(*sit == '"') { quoted = ! quoted; was_quoted = true; continue; } wchar_t c = mutate(*sit, quoted ? false : word.empty()); if(! quoted && c == ' ') { wchar_t firstC = word[0]; if(was_quoted || firstC == '*') { if (firstC == '*') word = word.substr(1); q_part.push_back(word); } else if(firstC == '-') { if (word.size() > 0) q_out.push_back(mMuseekd->codeset()->toNet(string(word.data() + 1, word.size() - 1))); } else { /* find files that match this word */ Folder* t = &mCharMap[word[0]][word]; if(! t->empty()) q_in.push_back(t); else return; } was_quoted = false; word = string(); continue; } word += c; } if(q_in.empty() && q_part.empty()) return; else if (!q_in.empty()) { Folder* base = q_in[0]; vector<Folder* >::const_iterator first = q_in.begin()++; Folder::const_iterator it = base->begin(); for(; it != base->end(); ++it) { // Did we already found this result? if(result.find((*it).first) != result.end()) continue; // Don't add results that contains forbidden words if(! q_out.empty()) { string lowr = tolower((*it).first); StringList::const_iterator oit = q_out.begin(); for(; oit != q_out.end(); ++oit) if(lowr.find(*oit) != string::npos) break; if(oit != q_out.end()) continue; } // If we arrive here, we can add the file to the results if it matches every keyword vector<Folder* >::const_iterator ref = first; for(; ref != q_in.end(); ++ref) if((*ref)->find((*it).first) == (*ref)->end()) break; if(ref == q_in.end()) { // Ok, it matches every keyword, but does it match every phrase? StringList::const_iterator partit = q_part.begin(); for(; partit != q_part.end(); ++partit) if (tolower((*it).first).find(tolower(*partit)) == std::string::npos) break; if(partit == q_part.end()) { result[(*it).first] = (*it).second; ++results; } } // Don't send more than 500 results if(results >= 500) return; } } else { // We're only searching phrases (*foobar "foo bar"), search in flat list Folder::iterator fit = mFlat.begin(); StringList::const_iterator wit; for(; fit != mFlat.end(); ++fit) { string entry = tolower(mMuseekd->codeset()->fromNet((*fit).first)); bool notFound = false; for (wit = q_part.begin(); wit != q_part.end(); wit++) { size_t posFound = entry.find(tolower(*wit)); if (posFound == std::string::npos) { notFound = true; break; } } if (!notFound) { result[(*fit).first] = (*fit).second; ++results; } // Don't send more than 500 results if(results >= 500) return; } } }