📄 adchub.cpp
字号:
/*
* Copyright (C) 2001-2005 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"
const string AdcHub::CLIENT_PROTOCOL("ADC/0.9");
AdcHub::AdcHub(const string& aHubURL) : Client(aHubURL, '\n'), state(STATE_PROTOCOL) {
}
AdcHub::~AdcHub() throw() {
Lock l(cs);
clearUsers();
}
void AdcHub::handle(AdcCommand::INF, AdcCommand& c) throw() {
if(c.getParameters().empty())
return;
User::Ptr u = ClientManager::getInstance()->getUser(c.getFrom(), this, true);
cidMap[u->getCID()] = u;
int op = 0;
int reg = 0;
int norm = 0;
string ve;
int sl = 0;
for(StringIterC i = c.getParameters().begin(); i != c.getParameters().end(); ++i) {
if(i->length() < 2)
continue;
if(i->compare(0, 2, "NI") == 0) {
Lock l(cs);
if(!u->getNick().empty()) {
nickMap.erase(u->getNick());
}
u->setNick(i->substr(2));
nickMap.insert(make_pair(u->getNick(), u));
} else if(i->compare(0, 2, "HU") == 0) {
hub = u;
} else if(i->compare(0, 2, "DE") == 0) {
u->setDescription(i->substr(2));
} else if(i->compare(0, 2, "I4") == 0) {
u->setIp(i->substr(2));
} else if(i->compare(0, 2, "SS") == 0) {
u->setBytesShared(i->substr(2));
} else if(i->compare(0, 2, "VE") == 0) {
ve = i->substr(2);
} else if(i->compare(0, 2, "EM") == 0) {
u->setEmail(i->substr(2));
} else if(i->compare(0, 2, "OP") == 0) {
if(i->length() == 2) {
u->unsetFlag(User::OP);
} else {
u->setFlag(User::OP);
}
} else if(i->compare(0, 2, "HO") == 0) {
op = Util::toInt(i->substr(2));
} else if(i->compare(0, 2, "HR") == 0) {
reg = Util::toInt(i->substr(2));
} else if(i->compare(0, 2, "HN") == 0) {
norm = Util::toInt(i->substr(2));
} else if(i->compare(0, 2, "SL") == 0) {
sl = Util::toInt(i->substr(2));
u->setSlots(sl);
} else if(i->compare(0, 2, "BO") == 0) {
if(i->length() == 2) {
u->unsetFlag(User::BOT);
} else {
u->setFlag(User::BOT);
}
} else if(i->compare(0, 2, "HI") == 0) {
if(i->length() == 2) {
u->unsetFlag(User::HIDDEN);
} else {
u->setFlag(User::HIDDEN);
}
} else if(i->compare(0, 2, "HU") == 0) {
if(i->length() == 2) {
u->unsetFlag(User::HUB);
} else {
u->setFlag(User::HUB);
}
} else if(i->compare(0, 2, "U4") == 0) {
u->setUDPPort((short)Util::toInt(i->substr(2)));
}
}
if(!ve.empty()) {
if(ve.find(' ') != string::npos) {
ve.insert(ve.find(' ') + 1, "V:");
}
u->setTag("<" + ve + ",M:" + string(u->getIp().empty() ? "P" : "A") + ",H:" + Util::toString(norm) + "/" +
Util::toString(reg) + "/" + Util::toString(op) + ",S:" +
Util::toString(sl) + ">" );
}
if(u == getMe())
state = STATE_NORMAL;
fire(ClientListener::UserUpdated(), this, u);
}
void AdcHub::handle(AdcCommand::SUP, AdcCommand& c) throw() {
if(state != STATE_PROTOCOL) /** @todo SUP changes */
return;
if(find(c.getParameters().begin(), c.getParameters().end(), "+BASE") == c.getParameters().end()) {
disconnect();
return;
}
state = STATE_IDENTIFY;
info(true);
}
void AdcHub::handle(AdcCommand::MSG, AdcCommand& c) throw() {
if(c.getParameters().empty())
return;
User::Ptr p = cidMap[c.getFrom()];
if(!p)
return;
string pmFrom;
if(c.getParam("PM", 1, pmFrom)) { // add PM<group-cid> as well
User::Ptr pm = cidMap[CID(pmFrom)];
if(!pm)
return;
if(pm == getMe()) {
return;
}
string msg = '<' + p->getNick() + "> " + c.getParam(0);
fire(ClientListener::PrivateMessage(), this, pm, msg);
} else {
string msg = '<' + p->getNick() + "> " + c.getParam(0);
fire(ClientListener::Message(), this, msg);
}
}
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() {
User::Ptr p = cidMap[CID(c.getParam(0))];
if(!p)
return;
if(!p->getNick().empty()) {
Lock l(cs);
nickMap.erase(p->getNick());
}
ClientManager::getInstance()->putUserOffline(p);
fire(ClientListener::UserRemoved(), this, p);
cidMap.erase(CID(c.getParam(0)));
}
void AdcHub::handle(AdcCommand::CTM, AdcCommand& c) throw() {
User::Ptr p = cidMap[c.getFrom()];
if(!p || p == getMe())
return;
if(c.getParameters().size() < 3)
return;
if(c.getParam(0) != CLIENT_PROTOCOL) {
// Protocol unhandled...
AdcCommand cc(AdcCommand::CMD_STA, p->getCID());
cc.addParam(Util::toString(AdcCommand::ERROR_PROTOCOL_UNSUPPORTED));
cc.addParam(c.getParam(0));
cc.addParam(c.getParam(1));
cc.addParam("Protocol unsupported");
send(cc);
return;
}
string token;
c.getParam("TO", 2, token);
ConnectionManager::getInstance()->adcConnect(p->getIp(), (short)Util::toInt(c.getParameters()[1]), token);
}
void AdcHub::handle(AdcCommand::RCM, AdcCommand& c) throw() {
if(SETTING(CONNECTION_TYPE) != SettingsManager::CONNECTION_ACTIVE)
return;
User::Ptr p = cidMap[c.getFrom()];
if(!p || p == getMe())
return;
if(c.getParameters().empty() || c.getParameters()[0] != CLIENT_PROTOCOL)
return;
string token;
c.getParam("TO", 1, token);
connect(&*p, token);
}
void AdcHub::sendUDP(const AdcCommand& cmd) {
try {
Socket s;
s.create(Socket::TYPE_UDP);
string tmp = cmd.toString();
for(User::NickIter i = nickMap.begin(); i != nickMap.end(); ++i) {
if(i->second->getUDPPort() != 0 && !i->second->getIp().empty()) {
try {
s.writeTo(i->second->getIp(), i->second->getUDPPort(), tmp);
} catch(const SocketException& e) {
dcdebug("AdcHub::sendUDP: write failed: %s\n", e.getError().c_str());
}
}
}
} catch(SocketException&) {
dcdebug("Can't create udp socket\n");
}
}
void AdcHub::handle(AdcCommand::STA, AdcCommand& c) throw() {
if(c.getParameters().size() < 2)
return;
fire(ClientListener::Message(), this, c.getParam(1));
}
void AdcHub::handle(AdcCommand::SCH, AdcCommand& c) throw() {
fire(ClientListener::AdcSearch(), this, c);
}
void AdcHub::connect(const User* user) {
u_int32_t r = Util::rand();
connect(user, Util::toString(r));
}
void AdcHub::connect(const User* user, string const& token) {
if(state != STATE_NORMAL)
return;
if(SETTING(CONNECTION_TYPE) == SettingsManager::CONNECTION_ACTIVE) {
send(AdcCommand(AdcCommand::CMD_CTM, user->getCID()).addParam(CLIENT_PROTOCOL).addParam(Util::toString(SETTING(IN_PORT))).addParam(token));
} else {
send(AdcCommand(AdcCommand::CMD_RCM, user->getCID()).addParam(CLIENT_PROTOCOL));
}
}
void AdcHub::disconnect() {
state = STATE_PROTOCOL;
Client::disconnect();
{
Lock l(cs);
clearUsers();
}
}
void AdcHub::hubMessage(const string& aMessage) {
if(state != STATE_NORMAL)
return;
send(AdcCommand(AdcCommand::CMD_MSG, AdcCommand::TYPE_BROADCAST).addParam(aMessage));
}
void AdcHub::privateMessage(const User* user, const string& aMessage) {
if(state != STATE_NORMAL)
return;
send(AdcCommand(AdcCommand::CMD_MSG, user->getCID()).addParam(aMessage).addParam("PM", SETTING(CLIENT_ID)));
}
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_UDP);
if(aFileType == SearchManager::TYPE_TTH) {
c.addParam("TR", aString);
} else {
if(aSizeMode == SearchManager::SIZE_ATLEAST) {
c.addParam(">=", Util::toString(aSize));
} else if(aSizeMode == SearchManager::SIZE_ATMOST) {
c.addParam("<=", Util::toString(aSize));
}
StringTokenizer<string> st(aString, ' ');
for(StringIter i = st.getTokens().begin(); i != st.getTokens().end(); ++i) {
c.addParam("++", *i);
}
}
if(!aToken.empty())
c.addParam("TO", aToken);
sendUDP(c);
if(SETTING(CONNECTION_TYPE) == SettingsManager::CONNECTION_ACTIVE) {
c.setType(AdcCommand::TYPE_PASSIVE);
send(c);
}
}
void AdcHub::password(const string& pwd) {
if(state != STATE_VERIFY)
return;
if(!salt.empty()) {
size_t saltBytes = salt.size() * 5 / 8;
AutoArray<u_int8_t> buf(saltBytes);
Encoder::fromBase32(salt.c_str(), buf, saltBytes);
TigerHash th;
th.update(SETTING(CLIENT_ID).c_str(), SETTING(CLIENT_ID).length());
th.update(pwd.data(), pwd.length());
th.update(buf, saltBytes);
send(AdcCommand(AdcCommand::CMD_PAS, AdcCommand::TYPE_HUB).addParam(Encoder::toBase32(th.finalize(), TigerHash::HASH_SIZE)));
salt.clear();
}
}
void AdcHub::info(bool /*alwaysSend*/) {
if(state != STATE_IDENTIFY && state != STATE_NORMAL)
return;
if(!getMe())
return;
AdcCommand c(AdcCommand::CMD_INF, AdcCommand::TYPE_BROADCAST);
string tmp;
StringMapIter i;
#define ADDPARAM(var, content) \
tmp = content; \
if((i = lastInfoMap.find(var)) != lastInfoMap.end()) { \
if(i->second != tmp) { \
if(tmp.empty()) \
lastInfoMap.erase(i); \
else \
i->second = tmp; \
c.addParam(var, tmp); \
} \
} else if(!tmp.empty()) { \
c.addParam(var, tmp); \
lastInfoMap[var] = tmp; \
}
ADDPARAM("NI", getNick());
ADDPARAM("DE", getDescription());
ADDPARAM("SL", Util::toString(SETTING(SLOTS)));
ADDPARAM("SS", ShareManager::getInstance()->getShareSizeString());
ADDPARAM("SF", Util::toString(ShareManager::getInstance()->getSharedFiles()));
ADDPARAM("EM", SETTING(EMAIL));
ADDPARAM("HN", Util::toString(counts.normal));
ADDPARAM("HR", Util::toString(counts.registered));
ADDPARAM("HO", Util::toString(counts.op));
ADDPARAM("VE", "++ " VERSIONSTRING);
if(SETTING(CONNECTION_TYPE) == SettingsManager::CONNECTION_ACTIVE) {
ADDPARAM("I4", "0.0.0.0");
ADDPARAM("U4", Util::toString(SETTING(UDP_PORT)));
} else {
ADDPARAM("U4", "");
}
#undef ADDPARAM
if(c.getParameters().size() > 0) {
send(c);
}
}
string AdcHub::checkNick(const string& aNick) {
string tmp = aNick;
string::size_type i = 0;
while( (i = tmp.find_first_of(" ", i)) != string::npos) {
tmp[i++]='_';
}
return tmp;
}
string AdcHub::getHubURL() {
return getAddressPort();
}
void AdcHub::clearUsers() {
for(User::NickIter i = nickMap.begin(); i != nickMap.end(); ++i) {
ClientManager::getInstance()->putUserOffline(i->second);
}
nickMap.clear();
cidMap.clear();
}
void AdcHub::on(Connected) throw() {
dcassert(state == STATE_PROTOCOL);
setMe(ClientManager::getInstance()->getUser(CID(SETTING(CLIENT_ID)), this, false));
lastInfoMap.clear();
send(AdcCommand(AdcCommand::CMD_SUP, AdcCommand::TYPE_HUB).addParam("+BAS0"));
fire(ClientListener::Connected(), this);
}
void AdcHub::on(Line, const string& aLine) throw() {
if(BOOLSETTING(ADC_DEBUG)) {
fire(ClientListener::Message(), this, "<ADC>" + aLine + "</ADC>");
}
dispatch(aLine);
}
void AdcHub::on(Failed, const string& aLine) throw() {
clearUsers();
setMe(NULL);
state = STATE_PROTOCOL;
fire(ClientListener::Failed(), this, aLine);
}
/**
* @file
* $Id: AdcHub.cpp,v 1.45 2005/03/19 13:00:47 arnetheduck Exp $
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -