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);
	}
}
Beispiel #2
0
/** @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);
	}
Beispiel #4
0
	/*
	 * 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()));
	}
}
Beispiel #7
0
	/*
	 * 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);
}
Beispiel #11
0
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);		
	}
Beispiel #13
0
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));
}
Beispiel #14
0
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");
			}
		}
	}
}
Beispiel #15
0
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();
	}
}
Beispiel #17
0
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);
	}
}
Beispiel #20
0
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));
}
Beispiel #22
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);
	}
Beispiel #23
0
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)));
}
Beispiel #24
0
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");
                }
        }

}