SearchQuery::SearchQuery(const string& nmdcString, Search::SizeModes aSizeMode, int64_t size, Search::TypeModes aFileType, size_t aMaxResults) noexcept : maxResults(aMaxResults) { if (aFileType == Search::TYPE_TTH && nmdcString.compare(0, 4, "TTH:") == 0) { root = TTHValue(nmdcString.substr(4)); } else { StringTokenizer<string> tok(Text::toLower(nmdcString), '$'); for (auto& term : tok.getTokens()) { if (!term.empty()) { include.addString(term); } } if (aSizeMode == Search::SIZE_ATLEAST) { gt = size; } else if (aSizeMode == Search::SIZE_ATMOST) { lt = size; } switch (aFileType) { case Search::TYPE_AUDIO: ext = AdcHub::parseSearchExts(1 << 0); break; case Search::TYPE_COMPRESSED: ext = AdcHub::parseSearchExts(1 << 1); break; case Search::TYPE_DOCUMENT: ext = AdcHub::parseSearchExts(1 << 2); break; case Search::TYPE_EXECUTABLE: ext = AdcHub::parseSearchExts(1 << 3); break; case Search::TYPE_PICTURE: ext = AdcHub::parseSearchExts(1 << 4); break; case Search::TYPE_VIDEO: ext = AdcHub::parseSearchExts(1 << 5); break; case Search::TYPE_DIRECTORY: itemType = SearchQuery::TYPE_DIRECTORY; break; default: break; } } prepare(); }
/* * Loads existing indexes from disk */ void IndexManager::loadIndexes(SimpleXML& xml) { xml.resetCurrentChild(); if(xml.findChild("Files")) { xml.stepIn(); while(xml.findChild("File")) { const TTHValue tth = TTHValue(xml.getChildAttrib("TTH")); SourceList sources; xml.stepIn(); while(xml.findChild("Source")) { Source source; source.setCID(CID(xml.getChildAttrib("CID"))); source.setIp(xml.getChildAttrib("I4")); source.setUdpPort(static_cast<uint16_t>(xml.getIntChildAttrib("U4"))); source.setSize(xml.getLongLongChildAttrib("SI")); source.setExpires(xml.getLongLongChildAttrib("EX")); source.setPartial(false); sources.push_back(source); } tthList.insert(std::make_pair(tth, sources)); xml.stepOut(); } xml.stepOut(); } }
TTHValue Deserializer::parseTTH(const string& aTTH) { if (!Encoder::isBase32(aTTH.c_str())) { throw std::invalid_argument("Invalid TTH"); } return TTHValue(aTTH); }
LRESULT TempShareDlg::onRemove(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { TCHAR buf[MAX_PATH]; LVITEM item; memzero(&item, sizeof(item)); item.mask = LVIF_TEXT; item.cchTextMax = sizeof(buf); item.pszText = buf; int i = -1; while ((i = ctrlFiles.GetNextItem(-1, LVNI_SELECTED)) != -1) { item.iItem = i; item.iSubItem = 2; ctrlFiles.GetItem(&item); TTHValue tth = TTHValue(Text::fromT(buf)); item.iSubItem = 3; ctrlFiles.GetItem(&item); string key = Text::fromT(buf); ShareManager::getInstance()->removeTempShare(key, tth); ctrlFiles.DeleteItem(i); } return 0; }
TTHValue Deserializer::deserializeTTH(const json& aJson) { auto tthStr = JsonUtil::getField<string>("tth", aJson, false); if (!Encoder::isBase32(tthStr.c_str())) { throw std::invalid_argument("Invalid TTH"); } return TTHValue(tthStr); }
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); } }
virtual size_t write(const void* xbuf, size_t len) throw(Exception) { size_t pos = 0; u_int8_t* b = (u_int8_t*)xbuf; while(pos < len) { size_t left = len - pos; if(bufPos == 0 && left >= TigerTree::HASH_SIZE) { tree.getLeaves().push_back(TTHValue(b + pos)); pos += TigerTree::HASH_SIZE; } else { size_t bytes = min(TigerTree::HASH_SIZE - bufPos, left); memcpy(buf + bufPos, b + pos, bytes); bufPos += bytes; pos += bytes; if(bufPos == TigerTree::HASH_SIZE) { tree.getLeaves().push_back(TTHValue(buf)); bufPos = 0; } } } return len; }
void SearchManager::onRES(const AdcCommand& cmd, const UserPtr& from, const string& remoteIp) { int freeSlots = -1; int64_t size = -1; string file; string tth; string token; for(auto& str: cmd.getParameters()) { if(str.compare(0, 2, "FN") == 0) { file = Util::toNmdcFile(str.substr(2)); } else if(str.compare(0, 2, "SL") == 0) { freeSlots = Util::toInt(str.substr(2)); } else if(str.compare(0, 2, "SI") == 0) { size = Util::toInt64(str.substr(2)); } else if(str.compare(0, 2, "TR") == 0) { tth = str.substr(2); } else if(str.compare(0, 2, "TO") == 0) { token = str.substr(2); } } if(file.empty() || freeSlots == -1 || size == -1) { return; } auto type = (*(file.end() - 1) == '\\' ? SearchResult::TYPE_DIRECTORY : SearchResult::TYPE_FILE); if(type == SearchResult::TYPE_FILE && tth.empty()) { return; } string hubUrl; // token format: [per-hub unique id] "/" [per-search actual token] (see AdcHub::search) auto slash = token.find('/'); if(slash == string::npos) { return; } { auto uniqueId = Util::toUInt32(token.substr(0, slash)); auto lock = ClientManager::getInstance()->lock(); auto& clients = ClientManager::getInstance()->getClients(); auto i = boost::find_if(clients, [uniqueId](const Client* client) { return client->getUniqueId() == uniqueId; }); if(i == clients.end()) { return; } hubUrl = (*i)->getHubUrl(); } token.erase(0, slash + 1); StringList names = ClientManager::getInstance()->getHubNames(from->getCID()); string hubName = names.empty() ? _("Offline") : Util::toString(names); /// @todo Something about the slots fire(SearchManagerListener::SR(), SearchResultPtr(new SearchResult(HintedUser(from, hubUrl), type, 0, freeSlots, size, file, hubName, remoteIp, TTHValue(tth), token))); }
const ShareManager::Directory::File& ShareManager::findFile(const string& virtualFile) const { if(virtualFile.compare(0, 4, "TTH/") == 0) { auto i = tthIndex.find(TTHValue(virtualFile.substr(4))); if(i == tthIndex.end()) { throw ShareException(UserConnection::FILE_NOT_AVAILABLE); } return *i->second; } auto v = splitVirtual(virtualFile); auto it = find_if(v.first->files.begin(), v.first->files.end(), Directory::File::StringComp(v.second)); if(it == v.first->files.end()) throw ShareException(UserConnection::FILE_NOT_AVAILABLE); return *it; }
MemoryInputStream* ShareManager::getTree(const string& virtualFile) const { TigerTree tree; if(virtualFile.compare(0, 4, "TTH/") == 0) { if(!HashManager::getInstance()->getTree(TTHValue(virtualFile.substr(4)), tree)) return nullptr; } else { try { TTHValue tth = getTTH(virtualFile); //if(!tth) { return nullptr; } HashManager::getInstance()->getTree(tth, tree); } catch(const Exception&) { return nullptr; } } ByteVector buf = tree.getLeafData(); return new MemoryInputStream(&buf[0], buf.size()); }
AdcSearch* AdcSearch::getSearch(const string& aSearchString, const string& aExcluded, int64_t aSize, int aTypeMode, int aSizeMode, const StringList& aExtList, MatchType aMatchType, bool returnParents) { AdcSearch* s = nullptr; if(aTypeMode == SearchManager::TYPE_TTH) { s = new AdcSearch(TTHValue(aSearchString)); } else { s = new AdcSearch(aSearchString, aExcluded, aExtList, aMatchType); if(aSizeMode == SearchManager::SIZE_ATLEAST) { s->gt = aSize; } else if(aSizeMode == SearchManager::SIZE_ATMOST) { s->lt = aSize; } s->itemType = (aTypeMode == SearchManager::TYPE_DIRECTORY) ? AdcSearch::TYPE_DIRECTORY : (aTypeMode == SearchManager::TYPE_FILE) ? AdcSearch::TYPE_FILE : AdcSearch::TYPE_ANY; s->addParents = returnParents; } return s; }
SearchQuery* SearchQuery::getSearch(const SearchPtr& aSearch) noexcept { SearchQuery* s = nullptr; if(aSearch->fileType == Search::TYPE_TTH) { s = new SearchQuery(TTHValue(aSearch->query)); } else { s = new SearchQuery(aSearch->query, aSearch->excluded, aSearch->exts, aSearch->matchType); if(aSearch->sizeType == Search::SIZE_ATLEAST) { s->gt = aSearch->size; } else if(aSearch->sizeType == Search::SIZE_ATMOST) { s->lt = aSearch->size; } s->itemType = (aSearch->fileType == Search::TYPE_DIRECTORY) ? SearchQuery::TYPE_DIRECTORY : (aSearch->fileType == Search::TYPE_FILE) ? SearchQuery::TYPE_FILE : SearchQuery::TYPE_ANY; } s->addParents = aSearch->returnParents; s->maxResults = aSearch->maxResults; return s; }
SearchQuery::SearchQuery(const StringList& params, size_t aMaxResults) noexcept : maxResults(aMaxResults) { for(const auto& p: params) { if(p.length() <= 2) continue; uint16_t cmd = toCode(p[0], p[1]); if(toCode('T', 'R') == cmd) { root = TTHValue(p.substr(2)); return; } else if(toCode('A', 'N') == cmd) { include.addString(p.substr(2)); } else if(toCode('N', 'O') == cmd) { exclude.addString(p.substr(2)); } else if(toCode('E', 'X') == cmd) { ext.push_back(Text::toLower(p.substr(2))); } else if(toCode('G', 'R') == cmd) { auto exts = AdcHub::parseSearchExts(Util::toInt(p.substr(2))); ext.insert(ext.begin(), exts.begin(), exts.end()); } else if(toCode('R', 'X') == cmd) { noExt.push_back(Text::toLower(p.substr(2))); } else if(toCode('G', 'E') == cmd) { gt = Util::toInt64(p.substr(2)); } else if(toCode('L', 'E') == cmd) { lt = Util::toInt64(p.substr(2)); } else if(toCode('E', 'Q') == cmd) { lt = gt = Util::toInt64(p.substr(2)); } else if(toCode('T', 'Y') == cmd) { itemType = static_cast<ItemType>(Util::toInt(p.substr(2))); } else if(toCode('M', 'T') == cmd) { matchType = static_cast<Search::MatchType>(Util::toInt(p.substr(2))); } else if(toCode('O', 'T') == cmd) { maxDate = Util::toInt64(p.substr(2)); } else if(toCode('N', 'T') == cmd) { minDate = Util::toInt64(p.substr(2)); } else if(toCode('P', 'P') == cmd) { addParents = (p[2] == '1'); } } prepare(); }
/* * Processes incoming request to publish file */ void IndexManager::processPublishSourceRequest(const Node::Ptr& node, const AdcCommand& cmd) { string tth; if(!cmd.getParam("TR", 1, tth)) return; // nothing to identify a file? string size; if(!cmd.getParam("SI", 1, size)) return; // no file size? string partial; cmd.getParam("PF", 1, partial); addSource(TTHValue(tth), node, Util::toInt64(size), partial == "1"); // send response AdcCommand res(AdcCommand::SEV_SUCCESS, AdcCommand::SUCCESS, "File published", AdcCommand::TYPE_UDP); res.addParam("FC", "PUB"); res.addParam("TR", tth); DHT::getInstance()->send(res, node->getIdentity().getIp(), node->getIdentity().getUdpPort(), node->getUser()->getCID(), node->getUdpKey()); }
void SearchManager::onRES(const AdcCommand& cmd, const UserPtr& from, const string& remoteIp) { int freeSlots = -1; int64_t size = -1; string file; string tth; string token; for(StringIterC i = cmd.getParameters().begin(); i != cmd.getParameters().end(); ++i) { const string& str = *i; if(str.compare(0, 2, "FN") == 0) { file = Util::toNmdcFile(str.substr(2)); } else if(str.compare(0, 2, "SL") == 0) { freeSlots = Util::toInt(str.substr(2)); } else if(str.compare(0, 2, "SI") == 0) { size = Util::toInt64(str.substr(2)); } else if(str.compare(0, 2, "TR") == 0) { tth = str.substr(2); } else if(str.compare(0, 2, "TO") == 0) { token = str.substr(2); } } if(!file.empty() && freeSlots != -1 && size != -1) { /// @todo get the hub this was sent from, to be passed as a hint? (eg by using the token?) StringList names = ClientManager::getInstance()->getHubNames(from->getCID(), Util::emptyString); string hubName = names.empty() ? _("Offline") : Util::toString(names); StringList hubs = ClientManager::getInstance()->getHubs(from->getCID(), Util::emptyString); string hub = hubs.empty() ? _("Offline") : Util::toString(hubs); SearchResult::Types type = (file[file.length() - 1] == '\\' ? SearchResult::TYPE_DIRECTORY : SearchResult::TYPE_FILE); if(type == SearchResult::TYPE_FILE && tth.empty()) return; /// @todo Something about the slots SearchResultPtr sr(new SearchResult(from, type, 0, freeSlots, size, file, hubName, hub, remoteIp, TTHValue(tth), token)); fire(SearchManagerListener::SR(), sr); } }
/* * Processes incoming request to publish file */ void IndexManager::processPublishSourceRequest(const string& ip, uint16_t port, const UDPKey& udpKey, const AdcCommand& cmd) { const CID cid = CID(cmd.getParam(0)); string tth; if(!cmd.getParam("TR", 1, tth)) return; // nothing to identify a file? string size; if(!cmd.getParam("SI", 1, size)) return; // no file size? string partial; cmd.getParam("PF", 1, partial); addSource(TTHValue(tth), cid, ip, port, Util::toInt64(size), partial == "1"); // send response AdcCommand res(AdcCommand::SEV_SUCCESS, AdcCommand::SUCCESS, "File published", AdcCommand::TYPE_UDP); res.addParam("FC", "PUB"); res.addParam("TR", tth); DHT::getInstance()->send(res, ip, port, cid, udpKey); }
void ListLoader::startTag(const string& name, StringPairList& attribs, bool simple) { #ifdef _DEBUG static size_t g_max_attribs_size = 0; if (g_max_attribs_size != attribs.size()) { g_max_attribs_size = attribs.size(); // dcdebug("ListLoader::startTag g_max_attribs_size = %d , attribs.capacity() = %d\n", g_max_attribs_size, attribs.capacity()); } #endif if (ClientManager::isBeforeShutdown()) { throw AbortException("ListLoader::startTag - ClientManager::isBeforeShutdown()"); } if (m_list->getAbort()) { throw AbortException("ListLoader::startTag - " + STRING(ABORT_EM)); } if (m_is_in_listing) { if (name == g_SFile) { dcassert(attribs.size() >= 3); // Иногда есть Shared - 4-тый атрибут. // это тэг от грея. его тоже можно обработать и записать в TS. хотя там 64 битное время const string& l_name = getAttrib(attribs, g_SName, 0); if (l_name.empty()) { dcassert(0); return; } const string& l_s = getAttrib(attribs, g_SSize, 1); if (l_s.empty()) { dcassert(0); return; } const auto l_size = Util::toInt64(l_s); const string& l_h = getAttrib(attribs, g_STTH, 2); if (l_h.empty() || (m_is_own_list == false && l_h.compare(0, 39, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 39) == 0)) { //dcassert(0); return; } const TTHValue l_tth(l_h); /// @todo verify validity? dcassert(l_tth != TTHValue()); if (m_is_updating) { // just update the current file if it is already there. for (auto i = m_cur->m_files.cbegin(); i != m_cur->m_files.cend(); ++i) { auto& file = **i; /// @todo comparisons should be case-insensitive but it takes too long - add a cache if (file.getName() == l_name || file.getTTH() == l_tth) { file.setName(l_name); file.setSize(l_size); file.setTTH(l_tth); return; } } } // [+] FlylinkDC std::shared_ptr<CFlyMediaInfo> l_mediaXY; uint32_t l_i_ts = 0; int l_i_hit = 0; string l_hit; #ifdef FLYLINKDC_USE_DIRLIST_FILE_EXT_STAT auto& l_item = DirectoryListing::g_ext_stat[Util::getFileExtWithoutDot(Text::toLower(l_name))]; l_item.m_count++; if (l_size > l_item.m_max_size) l_item.m_max_size = l_size; if (l_size < l_item.m_min_size) l_item.m_min_size = l_size; #endif if (attribs.size() >= 4) // 3 - стандартный DC++, 4 - GreyLinkDC++ { if (attribs.size() == 4 || attribs.size() >= 11) // Хитрый расширенный формат от http://p2p.toom.su/fs/hms/FCYECUWQ7F5A2FABW32UTMCT6MEMI3GPXBZDQCQ/) { const string l_sharedGL = getAttrib(attribs, g_SShared, 4); if (!l_sharedGL.empty()) { const int64_t tmp_ts = _atoi64(l_sharedGL.c_str()) - 116444736000000000L ; if (tmp_ts <= 0L) l_i_ts = 0; else l_i_ts = uint32_t(tmp_ts / 10000000L); } } string l_ts; if (l_i_ts == 0) { l_ts = getAttrib(attribs, g_STS, 3); // TODO проверить attribs.size() >= 4 если = 4 или 3 то TS нет и можно не искать } if (!m_is_first_check_mediainfo_list) { m_is_first_check_mediainfo_list = true; m_is_mediainfo_list = !l_ts.empty(); } if (!l_ts.empty() // Extended tags - exists only FlylinkDC++ or StrongDC++ sqlite or clones || l_i_ts // Грейлинк - время расшаривания ) { if (!l_ts.empty()) { l_i_ts = atoi(l_ts.c_str()); } if (attribs.size() > 4) // TODO - собрать комбинации всех случаев { l_hit = getAttrib(attribs, g_SHit, 3); const std::string& l_audio = getAttrib(attribs, g_SMAudio, 3); const std::string& l_video = getAttrib(attribs, g_SMVideo, 3); if (!l_audio.empty() || !l_video.empty()) { const string& l_br = getAttrib(attribs, g_SBR, 4); l_mediaXY = std::make_shared<CFlyMediaInfo>(getAttrib(attribs, g_SWH, 3), atoi(l_br.c_str()), l_audio, l_video ); } } #if 0 if (attribs.size() > 4) // TODO - собрать комбинации всех случаев { CFlyMediainfoRAW l_media_item; { l_media_item.m_audio = getAttrib(attribs, g_SMAudio, 3); const size_t l_pos = l_media_item.m_audio.find('|', 0); if (l_pos != string::npos && l_pos) { if (l_pos + 2 < l_media_item.m_audio.length()) { l_media_item.m_audio = l_media_item.m_audio.substr(l_pos + 2); } } } l_media_item.m_video = getAttrib(attribs, g_SMVideo, 3); l_hit = getAttrib(attribs, g_SHit, 3); l_media_item.m_WH = getAttrib(attribs, g_SWH, 3); if (!l_media_item.m_audio.empty() || !l_media_item.m_video.empty()) { l_media_item.m_br = getAttrib(attribs, g_SBR, 4); auto& l_find_mi = g_cache_mediainfo[l_media_item]; if (!l_find_mi) { l_find_mi = std::make_shared<CFlyMediaInfo>(l_media_item.m_WH, atoi(l_media_item.m_br.c_str()), l_media_item.m_audio, l_media_item.m_video ); l_mediaXY = l_find_mi; } } } #endif } l_i_hit = l_hit.empty() ? 0 : atoi(l_hit.c_str()); } auto f = new DirectoryListing::File(m_cur, l_name, l_size, l_tth, l_i_hit, l_i_ts, l_mediaXY); m_cur->m_virus_detect.add(l_name, l_size); m_cur->m_files.push_back(f); if (l_size) { if (m_is_own_list)//[+] FlylinkDC++ { f->setFlag(DirectoryListing::FLAG_SHARED_OWN); // TODO - убить FLAG_SHARED_OWN } else { if (ShareManager::isTTHShared(f->getTTH())) { f->setFlag(DirectoryListing::FLAG_SHARED); } else { if (QueueManager::is_queue_tth(f->getTTH())) { f->setFlag(DirectoryListing::FLAG_QUEUE); } // TODO if(l_size >= 100 * 1024 *1024) { if (!CFlyServerConfig::isParasitFile(f->getName())) // TODO - опимизнуть по расширениям { f->setFlag(DirectoryListing::FLAG_NOT_SHARED); const auto l_status_file = CFlylinkDBManager::getInstance()->get_status_file(f->getTTH()); // TODO - унести в отдельную нитку? if (l_status_file & CFlylinkDBManager::PREVIOUSLY_DOWNLOADED) f->setFlag(DirectoryListing::FLAG_DOWNLOAD); if (l_status_file & CFlylinkDBManager::VIRUS_FILE_KNOWN) f->setFlag(DirectoryListing::FLAG_VIRUS_FILE); if (l_status_file & CFlylinkDBManager::PREVIOUSLY_BEEN_IN_SHARE) f->setFlag(DirectoryListing::FLAG_OLD_TTH); } } } }//[+] FlylinkDC++ } } else if (name == g_SDirectory) { string l_file_name = getAttrib(attribs, g_SName, 0); if (l_file_name.empty()) { // throw SimpleXMLException("Directory missing name attribute"); l_file_name = "empty_file_name_" + Util::toString(++m_empty_file_name_counter); } const bool incomp = getAttrib(attribs, sIncomplete, 1) == "1"; DirectoryListing::Directory* d = nullptr; if (m_is_updating) { for (auto i = m_cur->directories.cbegin(); i != m_cur->directories.cend(); ++i) { /// @todo comparisons should be case-insensitive but it takes too long - add a cache if ((*i)->getName() == l_file_name) { d = *i; if (!d->getComplete()) { d->setComplete(!incomp); } break; } } } if (d == nullptr) { d = new DirectoryListing::Directory(m_list, m_cur, l_file_name, false, !incomp, isMediainfoList()); m_cur->directories.push_back(d); } m_cur = d; if (simple) { // To handle <Directory Name="..." /> endTag(name, Util::emptyString); } } } else if (name == sFileListing) { const string& b = getAttrib(attribs, sBase, 2); if (b.size() >= 1 && b[0] == '/' && b[b.size() - 1] == '/') { m_base = b; } if (m_base.size() > 1) // [+]PPA fix for [4](("Version", "1"),("CID", "EDI7OWB6TZWH6X6L2D3INC6ORQSG6RQDJ6AJ5QY"),("Base", "/"),("Generator", "DC++ 0.785")) { const StringTokenizer<string> sl(m_base.substr(1), '/'); for (auto i = sl.getTokens().cbegin(); i != sl.getTokens().cend(); ++i) { DirectoryListing::Directory* d = nullptr; for (auto j = m_cur->directories.cbegin(); j != m_cur->directories.cend(); ++j) { if ((*j)->getName() == *i) { d = *j; break; } } if (d == nullptr) { d = new DirectoryListing::Directory(m_list, m_cur, *i, false, false, isMediainfoList()); m_cur->directories.push_back(d); } m_cur = d; } } m_cur->setComplete(true); // [+] IRainman Delayed loading (dclst support) const string& l_cidStr = getAttrib(attribs, sCID, 2); if (l_cidStr.size() == 39) { const CID l_CID(l_cidStr); if (!l_CID.isZero()) { if (!m_user) { m_user = ClientManager::createUser(l_CID, "", 0); m_list->setHintedUser(HintedUser(m_user, Util::emptyString)); } } } const string& l_getIncludeSelf = getAttrib(attribs, sIncludeSelf, 2); m_list->setIncludeSelf(l_getIncludeSelf == "1"); // [~] IRainman Delayed loading (dclst support) m_is_in_listing = true; if (simple) { // To handle <Directory Name="..." /> endTag(name, Util::emptyString); } } }
void SearchManager::onData(const string& x, const string& remoteIp) { if(x.compare(0, 4, "$SR ") == 0) { string::size_type i, j; // Directories: $SR <nick><0x20><directory><0x20><free slots>/<total slots><0x05><Hubname><0x20>(<Hubip:port>) // Files: $SR <nick><0x20><filename><0x05><filesize><0x20><free slots>/<total slots><0x05><Hubname><0x20>(<Hubip:port>) i = 4; if( (j = x.find(' ', i)) == string::npos) { return; } string nick = x.substr(i, j-i); i = j + 1; // A file has 2 0x05, a directory only one size_t cnt = count(x.begin() + j, x.end(), 0x05); SearchResult::Types type = SearchResult::TYPE_FILE; string file; int64_t size = 0; if(cnt == 1) { // We have a directory...find the first space beyond the first 0x05 from the back // (dirs might contain spaces as well...clever protocol, eh?) type = SearchResult::TYPE_DIRECTORY; // Get past the hubname that might contain spaces if((j = x.rfind(0x05)) == string::npos) { return; } // Find the end of the directory info if((j = x.rfind(' ', j-1)) == string::npos) { return; } if(j < i + 1) { return; } file = x.substr(i, j-i) + '\\'; } else if(cnt == 2) { if( (j = x.find((char)5, i)) == string::npos) { return; } file = x.substr(i, j-i); i = j + 1; if( (j = x.find(' ', i)) == string::npos) { return; } size = Util::toInt64(x.substr(i, j-i)); } i = j + 1; if( (j = x.find('/', i)) == string::npos) { return; } int freeSlots = Util::toInt(x.substr(i, j-i)); i = j + 1; if( (j = x.find((char)5, i)) == string::npos) { return; } int slots = Util::toInt(x.substr(i, j-i)); i = j + 1; if( (j = x.rfind(" (")) == string::npos) { return; } string hubName = x.substr(i, j-i); i = j + 2; if( (j = x.rfind(')')) == string::npos) { return; } HintedUser user; user.hint = ClientManager::getInstance()->findHub(x.substr(i, j - i)); if(user.hint.empty()) { // Could happen if hub has multiple URLs / IPs user = ClientManager::getInstance()->findLegacyUser(nick); if(!user) return; } string encoding = ClientManager::getInstance()->findHubEncoding(user.hint); nick = Text::toUtf8(nick, encoding); file = Text::toUtf8(file, encoding); hubName = Text::toUtf8(hubName, encoding); if(!user) { user.user = ClientManager::getInstance()->findUser(nick, user.hint); if(!user) return; } string tth; if(hubName.compare(0, 4, "TTH:") == 0) { tth = hubName.substr(4); StringList names = ClientManager::getInstance()->getHubNames(user); hubName = names.empty() ? _("Offline") : Util::toString(names); } if(tth.empty() && type == SearchResult::TYPE_FILE) { return; } fire(SearchManagerListener::SR(), SearchResultPtr(new SearchResult(user, type, slots, freeSlots, size, file, hubName, remoteIp, TTHValue(tth), Util::emptyString))); } else if(x.compare(1, 4, "RES ") == 0 && x[x.length() - 1] == 0x0a) { AdcCommand c(x.substr(0, x.length()-1)); if(c.getParameters().empty()) return; string cid = c.getParam(0); if(cid.size() != 39) return; UserPtr user = ClientManager::getInstance()->findUser(CID(cid)); if(!user) return; // This should be handled by AdcCommand really... c.getParameters().erase(c.getParameters().begin()); onRES(c, user, remoteIp); } /*else if(x.compare(1, 4, "SCH ") == 0 && x[x.length() - 1] == 0x0a) { try { respond(AdcCommand(x.substr(0, x.length()-1))); } catch(ParseException& ) { } }*/ // Needs further DoS investigation }
bool UploadManager::prepareFile(UserConnection& aSource, const string& aType, const string& aFile, int64_t aStartPos, int64_t aBytes, bool listRecursive) { if(aFile.empty() || aStartPos < 0 || aBytes < -1 || aBytes == 0) { aSource.fileNotAvail("Invalid request"); return false; } InputStream* is = 0; int64_t start = 0; int64_t bytesLeft = 0; int64_t size = 0; bool userlist = (aFile == Transfer::USER_LIST_NAME_BZ || aFile == Transfer::USER_LIST_NAME); bool free = userlist; bool leaves = false; bool partList = false; string sourceFile; try { if(aType == Transfer::TYPE_FILE) { sourceFile = ShareManager::getInstance()->toReal(aFile); if(aFile == Transfer::USER_LIST_NAME) { // Unpack before sending... string bz2 = File(sourceFile, File::READ, File::OPEN).read(); string xml; CryptoManager::getInstance()->decodeBZ2(reinterpret_cast<const uint8_t*>(bz2.data()), bz2.size(), xml); // Clear to save some memory... string().swap(bz2); is = new MemoryInputStream(xml); start = 0; bytesLeft = size = xml.size(); } else { File* f = new File(sourceFile, File::READ, File::OPEN); start = aStartPos; size = f->getSize(); bytesLeft = (aBytes == -1) ? size : aBytes; if(size < (start + bytesLeft)) { aSource.fileNotAvail(); delete f; return false; } free = free || (size <= (int64_t)(SETTING(FREE_SLOTS_SIZE) * 1024) ); f->setPos(start); is = f; if((start + bytesLeft) < size) { is = new LimitedInputStream<true>(is, aBytes); } } } else if(aType == Transfer::TYPE_TTHL) { sourceFile = ShareManager::getInstance()->toReal(aFile); MemoryInputStream* mis = ShareManager::getInstance()->getTree(aFile); if(!mis) { aSource.fileNotAvail(); return false; } start = 0; bytesLeft = size = mis->getSize(); is = mis; leaves = true; free = true; } else { aSource.fileNotAvail("Unknown file type"); return false; } } catch(const ShareException& e) { aSource.fileNotAvail(e.getError()); return false; } catch(const Exception& e) { LogManager::getInstance()->message(STRING(UNABLE_TO_SEND_FILE) + sourceFile + ": " + e.getError()); aSource.fileNotAvail(); return false; } Lock l(cs); bool extraSlot = false; if(!aSource.isSet(UserConnection::FLAG_HASSLOT)) { bool hasReserved = (reservedSlots.find(aSource.getUser()) != reservedSlots.end()); bool isFavorite = aSource.getUser()->getFavoriteGrantSlot(); if(!(hasReserved || isFavorite || getFreeSlots() > 0 || getAutoSlot())) { bool supportsFree = aSource.isSet(UserConnection::FLAG_SUPPORTS_MINISLOTS); bool allowedFree = aSource.isSet(UserConnection::FLAG_HASEXTRASLOT) || aSource.isSet(UserConnection::FLAG_OP) || getFreeExtraSlots() > 0; if(free && supportsFree && allowedFree) { extraSlot = true; } else { delete is; aSource.maxedOut(); // Check for tth root identifier string tFile = aFile; if (tFile.compare(0, 4, "TTH/") == 0) tFile = ShareManager::getInstance()->toVirtual(TTHValue(aFile.substr(4))); addFailedUpload(aSource, tFile + " (" + Util::toString((aStartPos*1000/(size+10))/10.0)+"% of " + Util::formatBytes(size) + " done)"); aSource.disconnect(); return false; } } else { clearUserFiles(aSource.getUser()); // this user is using a full slot, nix them. } setLastGrant(GET_TICK()); } Upload* u = new Upload(aSource); u->setStream(is); if(aBytes == -1) u->setSize(size); else u->setSize(start + bytesLeft); u->setStartPos(start); u->setSourceFile(sourceFile); if(userlist) u->setFlag(Upload::FLAG_USER_LIST); if(leaves) u->setFlag(Upload::FLAG_TTH_LEAVES); if(partList) u->setFlag(Upload::FLAG_PARTIAL_LIST); uploads.push_back(u); if(!aSource.isSet(UserConnection::FLAG_HASSLOT)) { if(extraSlot) { if(!aSource.isSet(UserConnection::FLAG_HASEXTRASLOT)) { aSource.setFlag(UserConnection::FLAG_HASEXTRASLOT); extra++; } } else { if(aSource.isSet(UserConnection::FLAG_HASEXTRASLOT)) { aSource.unsetFlag(UserConnection::FLAG_HASEXTRASLOT); extra--; } aSource.setFlag(UserConnection::FLAG_HASSLOT); running++; } reservedSlots.erase(aSource.getUser()); } return true; }
void SearchManager::onPSR(const AdcCommand& cmd, UserPtr from, const string& remoteIp) { uint16_t udpPort = 0; uint32_t partialCount = 0; string tth; string hubIpPort; string nick; PartsInfo partialInfo; for(StringIterC i = cmd.getParameters().begin(); i != cmd.getParameters().end(); ++i) { const string& str = *i; if(str.compare(0, 2, "U4") == 0) { udpPort = static_cast<uint16_t>(Util::toInt(str.substr(2))); } else if(str.compare(0, 2, "NI") == 0) { nick = str.substr(2); } else if(str.compare(0, 2, "HI") == 0) { hubIpPort = str.substr(2); } else if(str.compare(0, 2, "TR") == 0) { tth = str.substr(2); } else if(str.compare(0, 2, "PC") == 0) { partialCount = Util::toUInt32(str.substr(2))*2; } else if(str.compare(0, 2, "PI") == 0) { StringTokenizer<string> tok(str.substr(2), ','); for(StringIter i = tok.getTokens().begin(); i != tok.getTokens().end(); ++i) { partialInfo.push_back((uint16_t)Util::toInt(*i)); } } } string url = ClientManager::getInstance()->findHub(hubIpPort); if(!from || from == ClientManager::getInstance()->getMe()) { // for NMDC support if(nick.empty() || hubIpPort.empty()) { return; } from = ClientManager::getInstance()->findUser(nick, url); if(!from) { // Could happen if hub has multiple URLs / IPs from = ClientManager::getInstance()->findLegacyUser(nick); if(!from) { dcdebug("Search result from unknown user"); return; } } } //ClientManager::getInstance()->setIPUser(from, remoteIp, udpPort); if(partialInfo.size() != partialCount) { // what to do now ? just ignore partial search result :-/ return; } PartsInfo outPartialInfo; QueueItem::PartialSource ps(from->isNMDC() ? ClientManager::getInstance()->getClient(url)->getMyIdentity().getNick() : Util::emptyString, hubIpPort, remoteIp, udpPort); ps.setPartialInfo(partialInfo); QueueManager::getInstance()->handlePartialResult(from, url, TTHValue(tth), ps, outPartialInfo); if((udpPort > 0) && !outPartialInfo.empty()) { try { AdcCommand cmd = SearchManager::getInstance()->toPSR(false, ps.getMyNick(), hubIpPort, tth, outPartialInfo); ClientManager::getInstance()->send(cmd, from->getCID()); } catch(...) { dcdebug("Partial search caught error\n"); } } }
/** * 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; } } }