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); } }
/** @todo Handle errors better */ void DownloadManager::on(AdcCommand::STA, UserConnection* aSource, const AdcCommand& cmd) noexcept { if(cmd.getParameters().size() < 2) { aSource->disconnect(); return; } const string& err = cmd.getParameters()[0]; if(err.length() != 3) { aSource->disconnect(); return; } switch(Util::toInt(err.substr(0, 1))) { case AdcCommand::SEV_FATAL: aSource->disconnect(); return; case AdcCommand::SEV_RECOVERABLE: switch(Util::toInt(err.substr(1))) { case AdcCommand::ERROR_FILE_NOT_AVAILABLE: fileNotAvailable(aSource); return; case AdcCommand::ERROR_SLOTS_FULL: noSlots(aSource); return; } case AdcCommand::SEV_SUCCESS: // We don't know any messages that would give us these... dcdebug("Unknown success message %s %s", err.c_str(), cmd.getParam(1).c_str()); return; } aSource->disconnect(); }
/* * Sends request to create connection with me */ void ConnectionManager::revConnectToMe(const Node::Ptr& node, const AdcCommand& cmd) { // don't allow connection if we didn't proceed a handshake //if(!node->isOnline()) // return; // this is valid for active-passive connections only if(!ClientManager::getInstance()->isActive()) return; const string& protocol = cmd.getParam(1); const string& token = cmd.getParam(2); bool secure; if(protocol == CLIENT_PROTOCOL) { secure = false; } else if(protocol == SECURE_CLIENT_PROTOCOL_TEST && CryptoManager::getInstance()->TLSOk()) { secure = true; } else { AdcCommand sta(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_UNSUPPORTED, "Protocol unknown", AdcCommand::TYPE_UDP); sta.addParam("PR", protocol); sta.addParam("TO", token); DHT::getInstance()->send(sta, node->getIdentity().getIp(), static_cast<uint16_t>(Util::toInt(node->getIdentity().getUdpPort())), node->getUser()->getCID(), node->getUdpKey()); return; } connect(node, token, secure); }
/* * Stores outgoing request to avoid receiving invalid responses */ void Utils::trackOutgoingPacket(const string& ip, const AdcCommand& cmd) { Lock l(cs); uint64_t now = GET_TICK(); switch(cmd.getCommand()) { // request packets case AdcCommand::CMD_SCH: case AdcCommand::CMD_PUB: case AdcCommand::CMD_INF: case AdcCommand::CMD_CTM: case AdcCommand::CMD_GET: case AdcCommand::CMD_PSR: OutPacket p = { ip, now, cmd.getCommand() }; sentPackets.push_back(p); break; } // clean up old items // list is sorted by time, so the first unmatched item can break the loop while(!sentPackets.empty()) { uint64_t diff = now - sentPackets.front().time; if(diff >= TIME_FOR_RESPONSE) sentPackets.pop_front(); else break; } }
void UserConnection::handlePM(const AdcCommand& c, bool echo) noexcept{ const string& message = c.getParam(0); OnlineUserPtr peer = nullptr; OnlineUserPtr me = nullptr; auto cm = ClientManager::getInstance(); { RLock l(cm->getCS()); peer = cm->findOnlineUser(user->getCID(), getHubUrl()); //try to use the same hub so nicks match to a hub, not the perfect solution for CCPM, nicks keep changing when hubs go offline. if(peer && peer->getHubUrl() != hubUrl) setHubUrl(peer->getHubUrl()); me = cm->findOnlineUser(cm->getMe()->getCID(), getHubUrl()); } if (!me || !peer){ //ChatMessage cant be formatted without the OnlineUser! disconnect(true); return; } if (echo) { std::swap(peer, me); } string tmp; auto msg = make_shared<ChatMessage>(message, peer, me, peer); if (c.getParam("TS", 1, tmp)) { msg->setTime(Util::toInt64(tmp)); } msg->setThirdPerson(c.hasFlag("ME", 1)); fire(UserConnectionListener::PrivateMessage(), this, msg); }
void ClientManager::sendUDP(AdcCommand& cmd, const OnlineUser& user) { dcassert(cmd.getType() == AdcCommand::TYPE_UDP); if(!user.getIdentity().isUdpActive()) { cmd.setType(AdcCommand::TYPE_DIRECT); cmd.setTo(user.getIdentity().getSID()); const_cast<Client&>(user.getClient()).send(cmd); } else { sendUDP(user.getIdentity().getIp(), user.getIdentity().getUdpPort(), cmd.toString(getMe()->getCID())); } }
/* * General flooding protection */ bool Utils::checkFlood(const string& ip, const AdcCommand& cmd) { // ignore empty commands if(cmd.getParameters().empty()) return false; // there maximum allowed request packets from one IP per minute // response packets are allowed only if request has been sent to the IP address size_t maxAllowedPacketsPerMinute = 0; uint32_t requestCmd = AdcCommand::CMD_SCH; switch(cmd.getCommand()) { // request packets case AdcCommand::CMD_SCH: maxAllowedPacketsPerMinute = 20; break; case AdcCommand::CMD_PUB: maxAllowedPacketsPerMinute = 10; break; case AdcCommand::CMD_INF: maxAllowedPacketsPerMinute = 3; break; case AdcCommand::CMD_CTM: maxAllowedPacketsPerMinute = 2; break; case AdcCommand::CMD_RCM: maxAllowedPacketsPerMinute = 2; break; case AdcCommand::CMD_GET: maxAllowedPacketsPerMinute = 2; break; case AdcCommand::CMD_PSR: maxAllowedPacketsPerMinute = 3; break; // response packets case AdcCommand::CMD_STA: return true; // STA can be response for more commands, but since it is for informative purposes only, there shouldn't be no way to abuse it case AdcCommand::CMD_SND: requestCmd = AdcCommand::CMD_GET; case AdcCommand::CMD_RES: // default value of requestCmd Lock l(cs); for(std::list<OutPacket>::iterator i = sentPackets.begin(); i != sentPackets.end(); i++) { if(i->cmd == requestCmd && i->ip == ip) { sentPackets.erase(i); return true; } } dcdebug("Received unwanted response from %s. Packet dropped.\n", ip.c_str()); return false; } Lock l(cs); std::unordered_multiset<uint32_t>& packetsPerIp = receivedPackets[ip]; packetsPerIp.insert(cmd.getCommand()); if(packetsPerIp.count(cmd.getCommand()) > maxAllowedPacketsPerMinute) { dcdebug("Request flood detected (%d) from %s. Packet dropped.\n", packetsPerIp.count(cmd.getCommand()), ip.c_str()); return false; } return true; }
void UserConnection::handle(AdcCommand::STA t, const AdcCommand& c) { if(c.getParameters().size() >= 2) { const string& code = c.getParam(0); if(!code.empty() && code[0] - '0' == AdcCommand::SEV_FATAL) { fire(UserConnectionListener::ProtocolError(), this, c.getParam(1)); return; } } fire(t, this, c); }
void ConnectionManager::on(AdcCommand::INF, UserConnection* aSource, const AdcCommand& cmd) throw() { if(aSource->getState() != UserConnection::STATE_INF) { // Already got this once, ignore... aSource->send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_GENERIC, "Expecting INF")); dcdebug("CM::onINF %p sent INF twice\n", (void*)aSource); aSource->disconnect(); return; } string cid; if(!cmd.getParam("ID", 0, cid)) { aSource->send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_INF_MISSING, "ID missing").addParam("FL", "ID")); dcdebug("CM::onINF missing ID\n"); aSource->disconnect(); return; } aSource->setUser(ClientManager::getInstance()->findUser(CID(cid))); if(!aSource->getUser()) { dcdebug("CM::onINF: User not found"); aSource->send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_GENERIC, "User not found")); putConnection(aSource); return; } if(aSource->isSet(UserConnection::FLAG_INCOMING)) { aSource->setFlag(UserConnection::FLAG_DOWNLOAD); addDownloadConnection(aSource); } else { aSource->setFlag(UserConnection::FLAG_UPLOAD); addUploadConnection(aSource); } }
void ConnectionManager::on(AdcCommand::SUP, UserConnection* aSource, const AdcCommand& cmd) throw() { if(aSource->getState() != UserConnection::STATE_SUPNICK) { // Already got this once, ignore...@todo fix support updates dcdebug("CM::onMyNick %p sent nick twice\n", (void*)aSource); return; } bool baseOk = false; for(StringIterC i = cmd.getParameters().begin(); i != cmd.getParameters().end(); ++i) { if(i->compare(0, 2, "AD") == 0) { string feat = i->substr(2); if(feat == UserConnection::FEATURE_ADC_BASE) { baseOk = true; // ADC clients must support all these... aSource->setFlag(UserConnection::FLAG_SUPPORTS_ADCGET); aSource->setFlag(UserConnection::FLAG_SUPPORTS_MINISLOTS); aSource->setFlag(UserConnection::FLAG_SUPPORTS_TTHF); aSource->setFlag(UserConnection::FLAG_SUPPORTS_TTHL); // For compatibility with older clients... aSource->setFlag(UserConnection::FLAG_SUPPORTS_XML_BZLIST); } else if(feat == UserConnection::FEATURE_ZLIB_GET) { aSource->setFlag(UserConnection::FLAG_SUPPORTS_ZLIB_GET); } else if(feat == UserConnection::FEATURE_ADC_BZIP) { aSource->setFlag(UserConnection::FLAG_SUPPORTS_XML_BZLIST); } } } if(!baseOk) { aSource->send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_GENERIC, "Invalid SUP")); aSource->disconnect(); return; } if(aSource->isSet(UserConnection::FLAG_INCOMING)) { StringList defFeatures = adcFeatures; if(BOOLSETTING(COMPRESS_TRANSFERS)) { defFeatures.push_back("AD" + UserConnection::FEATURE_ZLIB_GET); } aSource->sup(defFeatures); aSource->inf(false); } else { aSource->inf(true); } aSource->setState(UserConnection::STATE_INF); }
void MessageManager::on(AdcCommand::PMI, UserConnection* uc, const AdcCommand& cmd) noexcept { if (cmd.hasFlag("QU", 0)) { RLock l(cs); auto i = ccpms.find(uc->getUser()); if (i != ccpms.end()) uc->disconnect(true); } }
/* * Creates connection to specified node */ void ConnectionManager::connectToMe(const Node::Ptr& node, const AdcCommand& cmd) { // don't allow connection if we didn't proceed a handshake if(!node->isOnline()) { // do handshake at first DHT::getInstance()->info(node->getIdentity().getIp(), static_cast<uint16_t>(Util::toInt(node->getIdentity().getUdpPort())), DHT::PING | DHT::MAKE_ONLINE, node->getUser()->getCID(), node->getUdpKey()); return; } const string& protocol = cmd.getParam(1); const string& port = cmd.getParam(2); const string& token = cmd.getParam(3); bool secure = false; if(protocol == CLIENT_PROTOCOL) { // Nothing special } else if(protocol == SECURE_CLIENT_PROTOCOL_TEST && CryptoManager::getInstance()->TLSOk()) { secure = true; } else { AdcCommand cmd(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_UNSUPPORTED, "Protocol unknown", AdcCommand::TYPE_UDP); cmd.addParam("PR", protocol); cmd.addParam("TO", token); DHT::getInstance()->send(cmd, node->getIdentity().getIp(), static_cast<uint16_t>(Util::toInt(node->getIdentity().getUdpPort())), node->getUser()->getCID(), node->getUdpKey()); return; } if(!node->getIdentity().isTcpActive(0)) { AdcCommand err(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_GENERIC, "IP unknown", AdcCommand::TYPE_UDP); DHT::getInstance()->send(err, node->getIdentity().getIp(), static_cast<uint16_t>(Util::toInt(node->getIdentity().getUdpPort())), node->getUser()->getCID(), node->getUdpKey()); return; } dcpp::ConnectionManager::getInstance()->adcConnect(*node, static_cast<uint16_t>(Util::toInt(port)), token, secure); }
void DownloadManager::on(AdcCommand::SND, UserConnection* aSource, const AdcCommand& cmd) noexcept { if(aSource->getState() != UserConnection::STATE_SND) { dcdebug("DM::onFileLength Bad state, ignoring\n"); return; } const string& type = cmd.getParam(0); int64_t start = Util::toInt64(cmd.getParam(2)); int64_t bytes = Util::toInt64(cmd.getParam(3)); if(type != Transfer::names[aSource->getDownload()->getType()]) { // Uhh??? We didn't ask for this... aSource->disconnect(); return; } startData(aSource, start, bytes, cmd.hasFlag("ZL", 4)); }
void ClientManager::send(AdcCommand& cmd, const CID& cid) { Lock l(cs); OnlineIter i = onlineUsers.find(cid); if(i != onlineUsers.end()) { OnlineUser& u = *i->second; if(cmd.getType() == AdcCommand::TYPE_UDP && !u.getIdentity().isUdpActive()) { cmd.setType(AdcCommand::TYPE_DIRECT); cmd.setTo(u.getIdentity().getSID()); u.getClient().send(cmd); } else { try { udp.writeTo(u.getIdentity().getIp(), static_cast<uint16_t>(Util::toInt(u.getIdentity().getUdpPort())), cmd.toString(getMe()->getCID())); } catch(const SocketException&) { dcdebug("Socket exception sending ADC UDP command\n"); } } } }
void SearchManager::respond(const AdcCommand& cmd, const OnlineUser& user) { // Filter own searches if(user.getUser() == ClientManager::getInstance()->getMe()) return; auto results = ShareManager::getInstance()->search(cmd.getParameters(), user.getIdentity().isUdpActive() ? 10 : 5); if(results.empty()) return; string token; cmd.getParam("TO", 0, token); for(auto& i: results) { AdcCommand res = i->toRES(AdcCommand::TYPE_UDP); if(!token.empty()) res.addParam("TO", token); ClientManager::getInstance()->sendUDP(res, user); } }
void UploadManager::on(AdcCommand::GFI, UserConnection* aSource, const AdcCommand& c) throw() { if(c.getParameters().size() < 2) { aSource->send(AdcCommand(AdcCommand::SEV_RECOVERABLE, AdcCommand::ERROR_PROTOCOL_GENERIC, "Missing parameters")); return; } const string& type = c.getParam(0); const string& ident = c.getParam(1); if(type == Transfer::TYPE_FILE) { try { aSource->send(ShareManager::getInstance()->getFileInfo(ident)); } catch(const ShareException&) { aSource->fileNotAvail(); } } else { aSource->fileNotAvail(); } }
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); } }
/* * 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 UploadManager::on(AdcCommand::GET, UserConnection* aSource, const AdcCommand& c) throw() { int64_t aBytes = Util::toInt64(c.getParam(3)); int64_t aStartPos = Util::toInt64(c.getParam(2)); const string& fname = c.getParam(1); const string& type = c.getParam(0); if(prepareFile(*aSource, type, fname, aStartPos, aBytes, c.hasFlag("RE", 4))) { Upload* u = aSource->getUpload(); dcassert(u != NULL); AdcCommand cmd(AdcCommand::CMD_SND); cmd.addParam(type).addParam(fname) .addParam(Util::toString(u->getPos())) .addParam(Util::toString(u->getSize() - u->getPos())); if(c.hasFlag("ZL", 4)) { u->setStream(new FilteredInputStream<ZFilter, true>(u->getStream())); u->setFlag(Upload::FLAG_ZUPLOAD); cmd.addParam("ZL1"); } aSource->send(cmd); u->setStart(GET_TICK()); aSource->setState(UserConnection::STATE_RUNNING); aSource->transmitFile(u->getStream()); fire(UploadManagerListener::Starting(), u); } }
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); } }
void UserConnection::handlePM(const AdcCommand& c, bool echo) noexcept { auto message = c.getParam(0); auto cm = ClientManager::getInstance(); auto lock = cm->lock(); auto peer = cm->findOnlineUser(user->getCID(), hubUrl); auto me = cm->findOnlineUser(cm->getMe()->getCID(), hubUrl); // null pointers allowed here as the conn may be going on without hubs. if(echo) { std::swap(peer, me); } if(peer && peer->getIdentity().noChat()) return; if(PluginManager::getInstance()->runHook(HOOK_CHAT_PM_IN, peer, message)) return; string tmp; fire(UserConnectionListener::PrivateMessage(), this, ChatMessage(message, peer, me, peer, c.hasFlag("ME", 1), c.getParam("TS", 1, tmp) ? Util::toInt64(tmp) : 0)); }
/* * 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 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))); }
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"); } } }