/* * Copyright (C) 2001-2008 Jacek Sieka, arnetheduck on gmail point com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "stdinc.h" #include "DCPlusPlus.h" #include "AdcHub.h" #include "ClientManager.h" #include "ShareManager.h" #include "StringTokenizer.h" #include "AdcCommand.h" #include "ConnectionManager.h" #include "version.h" #include "Util.h" #include "UserCommand.h" #include "CryptoManager.h" #include "LogManager.h" namespace dcpp { const string AdcHub::CLIENT_PROTOCOL("ADC/1.0"); const string AdcHub::CLIENT_PROTOCOL_TEST("ADC/0.10"); const string AdcHub::SECURE_CLIENT_PROTOCOL_TEST("ADCS/0.10"); const string AdcHub::ADCS_FEATURE("ADC0"); const string AdcHub::TCP4_FEATURE("TCP4"); const string AdcHub::UDP4_FEATURE("UDP4"); const string AdcHub::BASE_SUPPORT("ADBASE"); const string AdcHub::BAS0_SUPPORT("ADBAS0"); const string AdcHub::TIGR_SUPPORT("ADTIGR"); const string AdcHub::UCM0_SUPPORT("ADUCM0"); const string AdcHub::BLO0_SUPPORT("ADBLO0"); AdcHub::AdcHub(const string& aHubURL, bool secure) : Client(aHubURL, '\n', secure), oldPassword(false), sid(0) { TimerManager::getInstance()->addListener(this); } AdcHub::~AdcHub() throw() { TimerManager::getInstance()->removeListener(this); clearUsers(); } OnlineUser& AdcHub::getUser(const uint32_t aSID, const CID& aCID) { OnlineUser* ou = findUser(aSID); if(ou) { return *ou; } UserPtr p = ClientManager::getInstance()->getUser(aCID); { Lock l(cs); ou = users.insert(make_pair(aSID, new OnlineUser(p, *this, aSID))).first->second; } if(aSID != AdcCommand::HUB_SID) ClientManager::getInstance()->putOnline(ou); return *ou; } OnlineUser* AdcHub::findUser(const uint32_t aSID) const { Lock l(cs); SIDMap::const_iterator i = users.find(aSID); return i == users.end() ? NULL : i->second; } OnlineUser* AdcHub::findUser(const CID& aCID) const { Lock l(cs); for(SIDMap::const_iterator i = users.begin(); i != users.end(); ++i) { if(i->second->getUser()->getCID() == aCID) { return i->second; } } return 0; } void AdcHub::putUser(const uint32_t aSID, bool disconnect) { OnlineUser* ou = 0; { Lock l(cs); SIDIter i = users.find(aSID); if(i == users.end()) return; ou = i->second; users.erase(i); } if(aSID != AdcCommand::HUB_SID) ClientManager::getInstance()->putOffline(ou, disconnect); fire(ClientListener::UserRemoved(), this, *ou); delete ou; } void AdcHub::clearUsers() { SIDMap tmp; { Lock l(cs); users.swap(tmp); } for(SIDIter i = tmp.begin(); i != tmp.end(); ++i) { if(i->first != AdcCommand::HUB_SID) ClientManager::getInstance()->putOffline(i->second); delete i->second; } } void AdcHub::handle(AdcCommand::INF, AdcCommand& c) throw() { if(c.getParameters().empty()) return; string cid; OnlineUser* u = 0; if(c.getParam("ID", 0, cid)) { u = findUser(CID(cid)); if(u) { if(u->getIdentity().getSID() != c.getFrom()) { // Same CID but different SID not allowed - buggy hub? string nick; if(!c.getParam("NI", 0, nick)) { nick = "[nick unknown]"; } fire(ClientListener::StatusMessage(), this, str(F_("%1% (%2%) has same CID {%3%} as %4% (%5%), ignoring") % u->getIdentity().getNick() % u->getIdentity().getSIDString() % cid % nick % AdcCommand::fromSID(c.getFrom()))); return; } } else { u = &getUser(c.getFrom(), CID(cid)); } } else if(c.getFrom() == AdcCommand::HUB_SID) { u = &getUser(c.getFrom(), CID()); } else { u = findUser(c.getFrom()); } if(!u) { dcdebug("AdcHub::INF Unknown user / no ID\n"); return; } for(StringIterC i = c.getParameters().begin(); i != c.getParameters().end(); ++i) { if(i->length() < 2) continue; u->getIdentity().set(i->c_str(), i->substr(2)); } if(u->getIdentity().isBot()) { u->getUser()->setFlag(User::BOT); } else { u->getUser()->unsetFlag(User::BOT); } if(u->getIdentity().supports(ADCS_FEATURE)) { u->getUser()->setFlag(User::TLS); } if(u->getUser() == getMyIdentity().getUser()) { state = STATE_NORMAL; setAutoReconnect(true); setMyIdentity(u->getIdentity()); updateCounts(false); } if(u->getIdentity().isHub()) { setHubIdentity(u->getIdentity()); fire(ClientListener::HubUpdated(), this); } else { fire(ClientListener::UserUpdated(), this, *u); } } void AdcHub::handle(AdcCommand::SUP, AdcCommand& c) throw() { if(state != STATE_PROTOCOL) /** @todo SUP changes */ return; bool baseOk = false; bool tigrOk = false; for(StringIter i = c.getParameters().begin(); i != c.getParameters().end(); ++i) { if(*i == BAS0_SUPPORT) { baseOk = true; tigrOk = true; } else if(*i == BASE_SUPPORT) { baseOk = true; } else if(*i == TIGR_SUPPORT) { tigrOk = true; } } if(!baseOk) { fire(ClientListener::StatusMessage(), this, _("Failed to negotiate base protocol")); disconnect(false); return; } else if(!tigrOk) { oldPassword = true; // Some hubs fake BASE support without TIGR support =/ fire(ClientListener::StatusMessage(), this, _("Hub probably uses an old version of ADC, please encourage the owner to upgrade")); } } void AdcHub::handle(AdcCommand::SID, AdcCommand& c) throw() { if(state != STATE_PROTOCOL) { dcdebug("Invalid state for SID\n"); return; } if(c.getParameters().empty()) return; sid = AdcCommand::toSID(c.getParam(0)); state = STATE_IDENTIFY; info(true); } void AdcHub::handle(AdcCommand::MSG, AdcCommand& c) throw() { if(c.getParameters().empty()) return; OnlineUser* from = findUser(c.getFrom()); if(!from) return; string pmFrom; if(c.getParam("PM", 1, pmFrom)) { // add PM as well OnlineUser* to = findUser(c.getTo()); if(!to) return; OnlineUser* replyTo = findUser(AdcCommand::toSID(pmFrom)); if(!replyTo) return; fire(ClientListener::PrivateMessage(), this, *from, *to, *replyTo, c.getParam(0), c.hasFlag("ME", 1)); } else { fire(ClientListener::Message(), this, *from, c.getParam(0), c.hasFlag("ME", 1)); } } void AdcHub::handle(AdcCommand::GPA, AdcCommand& c) throw() { if(c.getParameters().empty()) return; salt = c.getParam(0); state = STATE_VERIFY; fire(ClientListener::GetPassword(), this); } void AdcHub::handle(AdcCommand::QUI, AdcCommand& c) throw() { uint32_t s = AdcCommand::toSID(c.getParam(0)); OnlineUser* victim = findUser(s); if(!victim) { return; } string tmp; if(c.getParam("MS", 1, tmp)) { OnlineUser* source = 0; string tmp2; if(c.getParam("ID", 1, tmp2)) { source = findUser(AdcCommand::toSID(tmp2)); } if(source) { tmp = str(F_("%1% was kicked by %2%: %3%") % victim->getIdentity().getNick() % source->getIdentity().getNick() % tmp); } else { tmp = str(F_("%1% was kicked: %2%") % victim->getIdentity().getNick() % tmp); } fire(ClientListener::StatusMessage(), this, tmp, ClientListener::FLAG_IS_SPAM); } putUser(s, c.getParam("DI", 1, tmp)); if(s == sid) { if(c.getParam("TL", 1, tmp)) { if(tmp == "-1") { setAutoReconnect(false); } else { setAutoReconnect(true); setReconnDelay(Util::toUInt32(tmp)); } } if(c.getParam("RD", 1, tmp)) { fire(ClientListener::Redirect(), this, tmp); } } } void AdcHub::handle(AdcCommand::CTM, AdcCommand& c) throw() { OnlineUser* u = findUser(c.getFrom()); if(!u || u->getUser() == ClientManager::getInstance()->getMe()) return; if(c.getParameters().size() < 2) return; const string& protocol = c.getParam(0); const string& port = c.getParam(1); string token; if(c.getParameters().size() == 3) { const string& tok = c.getParam(2); // 0.699 put TO before the token, keep this bug fix for a while if(tok.compare(0, 2, "TO") == 0) { token = tok.substr(2); } else { token = tok; } } else { // <= 0.703 would send an empty token for passive connections when replying to RCM } bool secure = false; if(protocol == CLIENT_PROTOCOL || protocol == CLIENT_PROTOCOL_TEST) { // 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_DIRECT); cmd.setTo(c.getFrom()); cmd.addParam("PR", protocol); cmd.addParam("TO", token); send(cmd); return; } if(!u->getIdentity().isTcpActive()) { send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_GENERIC, "IP unknown", AdcCommand::TYPE_DIRECT).setTo(c.getFrom())); return; } ConnectionManager::getInstance()->adcConnect(*u, static_cast(Util::toInt(port)), token, secure); } void AdcHub::handle(AdcCommand::RCM, AdcCommand& c) throw() { if(c.getParameters().size() < 2) { return; } if(!ClientManager::getInstance()->isActive()) return; OnlineUser* u = findUser(c.getFrom()); if(!u || u->getUser() == ClientManager::getInstance()->getMe()) return; const string& protocol = c.getParam(0); const string& tok = c.getParam(1); string token; // 0.699 sent a token with "TO" prefix if(tok.compare(0, 2, "TO") == 0) { token = tok.substr(2); } else { token = tok; } bool secure; if(protocol == CLIENT_PROTOCOL || protocol == CLIENT_PROTOCOL_TEST) { secure = false; } 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_DIRECT); cmd.setTo(c.getFrom()); cmd.addParam("PR", protocol); cmd.addParam("TO", token); send(cmd); return; } connect(*u, token, secure); } void AdcHub::handle(AdcCommand::CMD, AdcCommand& c) throw() { if(c.getParameters().size() < 1) return; const string& name = c.getParam(0); bool rem = c.hasFlag("RM", 1); if(rem) { fire(ClientListener::HubUserCommand(), this, (int)UserCommand::TYPE_REMOVE, 0, name, Util::emptyString); return; } bool sep = c.hasFlag("SP", 1); string sctx; if(!c.getParam("CT", 1, sctx)) return; int ctx = Util::toInt(sctx); if(ctx <= 0) return; if(sep) { fire(ClientListener::HubUserCommand(), this, (int)UserCommand::TYPE_SEPARATOR, ctx, name, Util::emptyString); return; } bool once = c.hasFlag("CO", 1); string txt; if(!c.getParam("TT", 1, txt)) return; fire(ClientListener::HubUserCommand(), this, (int)(once ? UserCommand::TYPE_RAW_ONCE : UserCommand::TYPE_RAW), ctx, name, txt); } void AdcHub::sendUDP(const AdcCommand& cmd) throw() { string command; string ip; uint16_t port; { Lock l(cs); SIDMap::const_iterator i = users.find(cmd.getTo()); if(i == users.end()) { dcdebug("AdcHub::sendUDP: invalid user\n"); return; } OnlineUser& ou = *i->second; if(!ou.getIdentity().isUdpActive()) { return; } ip = ou.getIdentity().getIp(); port = static_cast(Util::toInt(ou.getIdentity().getUdpPort())); command = cmd.toString(ou.getUser()->getCID()); } try { udp.writeTo(ip, port, command); } catch(const SocketException& e) { dcdebug("AdcHub::sendUDP: write failed: %s\n", e.getError().c_str()); udp.close(); } } void AdcHub::handle(AdcCommand::STA, AdcCommand& c) throw() { if(c.getParameters().size() < 2) return; OnlineUser* u = findUser(c.getFrom()); if(!u) return; //int severity = Util::toInt(c.getParam(0).substr(0, 1)); if(c.getParam(0).size() != 3) { return; } int code = Util::toInt(c.getParam(0).substr(1)); if(code == AdcCommand::ERROR_BAD_PASSWORD) { setPassword(Util::emptyString); } else if(code == AdcCommand::ERROR_PROTOCOL_UNSUPPORTED) { string tmp; if(c.getParam("PR", 1, tmp)) { if(tmp == CLIENT_PROTOCOL) { u->getUser()->setFlag(User::NO_ADC_1_0_PROTOCOL); } else if(tmp == CLIENT_PROTOCOL_TEST) { u->getUser()->setFlag(User::NO_ADC_0_10_PROTOCOL); } else if(tmp == SECURE_CLIENT_PROTOCOL_TEST) { u->getUser()->setFlag(User::NO_ADCS_0_10_PROTOCOL); u->getUser()->unsetFlag(User::TLS); } // Try again... ConnectionManager::getInstance()->force(u->getUser()); } } fire(ClientListener::Message(), this, *u, c.getParam(1)); } void AdcHub::handle(AdcCommand::SCH, AdcCommand& c) throw() { OnlineUser* ou = findUser(c.getFrom()); if(!ou) { dcdebug("Invalid user in AdcHub::onSCH\n"); return; } fire(ClientListener::AdcSearch(), this, c, ou->getUser()->getCID()); } void AdcHub::handle(AdcCommand::RES, AdcCommand& c) throw() { OnlineUser* ou = findUser(c.getFrom()); if(!ou) { dcdebug("Invalid user in AdcHub::onRES\n"); return; } SearchManager::getInstance()->onRES(c, ou->getUser()); } void AdcHub::handle(AdcCommand::GET, AdcCommand& c) throw() { if(c.getParameters().size() < 5) { dcdebug("Get with few parameters"); // TODO return STA? return; } const string& type = c.getParam(0); string sk, sh; if(type == "blom" && c.getParam("BK", 4, sk) && c.getParam("BH", 4, sh)) { ByteVector v; size_t m = Util::toUInt32(c.getParam(3)) * 8; size_t k = Util::toUInt32(sk); size_t h = Util::toUInt32(sh); if(k > 8 || k < 1) { send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_TRANSFER_GENERIC, "Unsupported k")); return; } if(h > 64 || h < 1) { send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_TRANSFER_GENERIC, "Unsupported h")); return; } size_t n = ShareManager::getInstance()->getSharedFiles(); // Ideal size for m is n * k / ln(2), but we allow some slack if(m > (5 * n * k / log(2)) || m > (1 << h)) { send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_TRANSFER_GENERIC, "Unsupported m")); return; } ShareManager::getInstance()->getBloom(v, k, m, h); AdcCommand cmd(AdcCommand::CMD_SND, AdcCommand::TYPE_HUB); cmd.addParam(c.getParam(0)); cmd.addParam(c.getParam(1)); cmd.addParam(c.getParam(2)); cmd.addParam(c.getParam(3)); cmd.addParam(c.getParam(4)); send(cmd); send((char*)&v[0], v.size()); } } void AdcHub::connect(const OnlineUser& user, const string& token) { connect(user, token, CryptoManager::getInstance()->TLSOk() && user.getUser()->isSet(User::TLS)); } void AdcHub::connect(const OnlineUser& user, string const& token, bool secure) { if(state != STATE_NORMAL) return; const string* proto; if(secure) { if(user.getUser()->isSet(User::NO_ADCS_0_10_PROTOCOL)) { /// @todo log return; } proto = &SECURE_CLIENT_PROTOCOL_TEST; } else { // dc++ <= 0.703 has a bug which makes it respond with CSTA to the hub if an unrecognised protocol is used *sigh* // so we try 0.10 first... if(user.getUser()->isSet(User::NO_ADC_0_10_PROTOCOL)) { if(user.getUser()->isSet(User::NO_ADC_1_0_PROTOCOL)) { /// @todo log return; } proto = &CLIENT_PROTOCOL; } else { proto = &CLIENT_PROTOCOL_TEST; } } if(ClientManager::getInstance()->isActive()) { uint16_t port = secure ? ConnectionManager::getInstance()->getSecurePort() : ConnectionManager::getInstance()->getPort(); if(port == 0) { // Oops? LogManager::getInstance()->message(str(F_("Not listening for connections - please restart %1%") % APPNAME)); return; } send(AdcCommand(AdcCommand::CMD_CTM, user.getIdentity().getSID(), AdcCommand::TYPE_DIRECT).addParam(*proto).addParam(Util::toString(port)).addParam(token)); } else { send(AdcCommand(AdcCommand::CMD_RCM, user.getIdentity().getSID(), AdcCommand::TYPE_DIRECT).addParam(*proto).addParam(token)); } } void AdcHub::hubMessage(const string& aMessage, bool thirdPerson) { if(state != STATE_NORMAL) return; AdcCommand c(AdcCommand::CMD_MSG, AdcCommand::TYPE_BROADCAST); c.addParam(aMessage); if(thirdPerson) c.addParam("ME", "1"); send(c); } void AdcHub::privateMessage(const OnlineUser& user, const string& aMessage, bool thirdPerson) { if(state != STATE_NORMAL) return; AdcCommand c(AdcCommand::CMD_MSG, user.getIdentity().getSID(), AdcCommand::TYPE_ECHO); c.addParam(aMessage); if(thirdPerson) c.addParam("ME", "1"); c.addParam("PM", getMySID()); send(c); } void AdcHub::search(int aSizeMode, int64_t aSize, int aFileType, const string& aString, const string& aToken) { if(state != STATE_NORMAL) return; AdcCommand c(AdcCommand::CMD_SCH, AdcCommand::TYPE_BROADCAST); if(aFileType == SearchManager::TYPE_TTH) { c.addParam("TR", aString); } else { if(aSizeMode == SearchManager::SIZE_ATLEAST) { c.addParam("GE", Util::toString(aSize)); } else if(aSizeMode == SearchManager::SIZE_ATMOST) { c.addParam("LE", Util::toString(aSize)); } StringTokenizer st(aString, ' '); for(StringIter i = st.getTokens().begin(); i != st.getTokens().end(); ++i) { c.addParam("AN", *i); } if(aFileType == SearchManager::TYPE_DIRECTORY) { c.addParam("TY", "2"); } } if(!aToken.empty()) c.addParam("TO", aToken); if(ClientManager::getInstance()->isActive()) { send(c); } else { c.setType(AdcCommand::TYPE_FEATURE); c.setFeatures("+TCP4"); send(c); } } void AdcHub::password(const string& pwd) { if(state != STATE_VERIFY) return; if(!salt.empty()) { size_t saltBytes = salt.size() * 5 / 8; boost::scoped_array buf(new uint8_t[saltBytes]); Encoder::fromBase32(salt.c_str(), &buf[0], saltBytes); TigerHash th; if(oldPassword) { CID cid = getMyIdentity().getUser()->getCID(); th.update(cid.data(), CID::SIZE); } th.update(pwd.data(), pwd.length()); th.update(&buf[0], saltBytes); send(AdcCommand(AdcCommand::CMD_PAS, AdcCommand::TYPE_HUB).addParam(Encoder::toBase32(th.finalize(), TigerHash::BYTES))); salt.clear(); } } static void addParam(StringMap& lastInfoMap, AdcCommand& c, const string& var, const string& value) { StringMapIter i = lastInfoMap.find(var); if(i != lastInfoMap.end()) { if(i->second != value) { if(value.empty()) { lastInfoMap.erase(i); } else { i->second = value; } c.addParam(var, value); } } else if(!value.empty()) { lastInfoMap.insert(make_pair(var, value)); c.addParam(var, value); } } void AdcHub::info(bool /*alwaysSend*/) { if(state != STATE_IDENTIFY && state != STATE_NORMAL) return; reloadSettings(false); AdcCommand c(AdcCommand::CMD_INF, AdcCommand::TYPE_BROADCAST); updateCounts(false); addParam(lastInfoMap, c, "ID", ClientManager::getInstance()->getMyCID().toBase32()); addParam(lastInfoMap, c, "PD", ClientManager::getInstance()->getMyPID().toBase32()); addParam(lastInfoMap, c, "NI", getCurrentNick()); addParam(lastInfoMap, c, "DE", getCurrentDescription()); addParam(lastInfoMap, c, "SL", Util::toString(SETTING(SLOTS))); addParam(lastInfoMap, c, "SS", ShareManager::getInstance()->getShareSizeString()); addParam(lastInfoMap, c, "SF", Util::toString(ShareManager::getInstance()->getSharedFiles())); addParam(lastInfoMap, c, "EM", SETTING(EMAIL)); addParam(lastInfoMap, c, "HN", Util::toString(counts.normal)); addParam(lastInfoMap, c, "HR", Util::toString(counts.registered)); addParam(lastInfoMap, c, "HO", Util::toString(counts.op)); addParam(lastInfoMap, c, "VE", "++ " VERSIONSTRING); addParam(lastInfoMap, c, "US", Util::toString((long)(Util::toDouble(SETTING(UPLOAD_SPEED))*1024*1024))); addParam(lastInfoMap, c, "AW", Util::getAway() ? "1" : Util::emptyString); if(SETTING(MAX_DOWNLOAD_SPEED) > 0) { addParam(lastInfoMap, c, "DS", Util::toString((SETTING(MAX_DOWNLOAD_SPEED)*1024*8))); } else { addParam(lastInfoMap, c, "DS", Util::emptyString); } string su; if(CryptoManager::getInstance()->TLSOk()) { su += ADCS_FEATURE + ","; } if(ClientManager::getInstance()->isActive()) { if(BOOLSETTING(NO_IP_OVERRIDE) && !SETTING(EXTERNAL_IP).empty()) { addParam(lastInfoMap, c, "I4", Socket::resolve(SETTING(EXTERNAL_IP))); } else { addParam(lastInfoMap, c, "I4", "0.0.0.0"); } addParam(lastInfoMap, c, "U4", Util::toString(SearchManager::getInstance()->getPort())); su += TCP4_FEATURE + ","; su += UDP4_FEATURE + ","; } else { addParam(lastInfoMap, c, "I4", ""); addParam(lastInfoMap, c, "U4", ""); } if(!su.empty()) { su.erase(su.size() - 1); } addParam(lastInfoMap, c, "SU", su); if(c.getParameters().size() > 0) { send(c); } } int64_t AdcHub::getAvailable() const { Lock l(cs); int64_t x = 0; for(SIDMap::const_iterator i = users.begin(); i != users.end(); ++i) { x+=i->second->getIdentity().getBytesShared(); } return x; } string AdcHub::checkNick(const string& aNick) { string tmp = aNick; for(size_t i = 0; i < aNick.size(); ++i) { if(static_cast(tmp[i]) <= 32) { tmp[i] = '_'; } } return tmp; } void AdcHub::send(const AdcCommand& cmd) { if(cmd.getType() == AdcCommand::TYPE_UDP) sendUDP(cmd); send(cmd.toString(sid)); } void AdcHub::on(Connected c) throw() { Client::on(c); lastInfoMap.clear(); sid = 0; AdcCommand cmd(AdcCommand::CMD_SUP, AdcCommand::TYPE_HUB); cmd.addParam(BAS0_SUPPORT).addParam(BASE_SUPPORT).addParam(TIGR_SUPPORT); if(BOOLSETTING(HUB_USER_COMMANDS)) { cmd.addParam(UCM0_SUPPORT); } if(BOOLSETTING(SEND_BLOOM)) { cmd.addParam(BLO0_SUPPORT); } send(cmd); } void AdcHub::on(Line l, const string& aLine) throw() { Client::on(l, aLine); if(BOOLSETTING(ADC_DEBUG)) { fire(ClientListener::StatusMessage(), this, "" + aLine + ""); } dispatch(aLine); } void AdcHub::on(Failed f, const string& aLine) throw() { clearUsers(); Client::on(f, aLine); } void AdcHub::on(Second s, uint32_t aTick) throw() { Client::on(s, aTick); if(state == STATE_NORMAL && (aTick > (getLastActivity() + 120*1000)) ) { send("\n", 1); } } } // namespace dcpp