📄 nmdchub.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 "NmdcHub.h"
#include "ResourceManager.h"
#include "ClientManager.h"
#include "SearchManager.h"
#include "ShareManager.h"
#include "CryptoManager.h"
#include "ConnectionManager.h"
#include "Socket.h"
#include "UserCommand.h"
#include "StringTokenizer.h"
NmdcHub::NmdcHub(const string& aHubURL) : Client(aHubURL, '|'), supportFlags(0),
adapter(this), state(STATE_CONNECT),
lastActivity(GET_TICK()),
reconnect(true), lastUpdate(0)
{
TimerManager::getInstance()->addListener(this);
}
NmdcHub::~NmdcHub() throw() {
TimerManager::getInstance()->removeListener(this);
Speaker<NmdcHubListener>::removeListeners();
Lock l(cs);
clearUsers();
}
void NmdcHub::connect() {
setRegistered(false);
setReconnDelay(120 + Util::rand(0, 60));
reconnect = true;
supportFlags = 0;
lastMyInfoA.clear();
lastMyInfoB.clear();
lastUpdate = 0;
if(socket->isConnected()) {
disconnect();
}
reloadSettings();
state = STATE_LOCK;
if(getPort() == 0) {
setPort(411);
}
socket->connect(getAddress(), getPort());
}
void NmdcHub::connect(const User* aUser) {
checkstate();
dcdebug("NmdcHub::connectToMe %s\n", aUser->getNick().c_str());
if(SETTING(CONNECTION_TYPE) == SettingsManager::CONNECTION_ACTIVE) {
send("$ConnectToMe " + toNmdc(aUser->getNick()) + " " + getLocalIp() + ":" + Util::toString(SETTING(IN_PORT)) + "|");
} else {
send("$RevConnectToMe " + toNmdc(getNick()) + " " + toNmdc(aUser->getNick()) + "|");
}
}
int64_t NmdcHub::getAvailable() const {
Lock l(cs);
int64_t x = 0;
for(User::NickMap::const_iterator i = users.begin(); i != users.end(); ++i) {
x+=i->second->getBytesShared();
}
return x;
}
void NmdcHub::refreshUserList(bool unknownOnly /* = false */) {
Lock l(cs);
if(unknownOnly) {
for(User::NickIter i = users.begin(); i != users.end(); ++i) {
if(i->second->getConnection().empty()) {
getInfo(i->second);
}
}
} else {
clearUsers();
getNickList();
}
}
void NmdcHub::clearUsers() {
for(User::NickIter i = users.begin(); i != users.end(); ++i) {
ClientManager::getInstance()->putUserOffline(i->second);
}
users.clear();
}
void NmdcHub::onLine(const string& aLine) throw() {
lastActivity = GET_TICK();
if(aLine.length() == 0)
return;
if(aLine[0] != '$') {
// Check if we're being banned...
if(state != STATE_CONNECTED) {
if(Util::findSubString(aLine, "banned") != string::npos) {
reconnect = false;
}
}
Speaker<NmdcHubListener>::fire(NmdcHubListener::Message(), this, Util::validateMessage(fromNmdc(aLine), true));
return;
}
string cmd;
string param;
string::size_type x;
if( (x = aLine.find(' ')) == string::npos) {
cmd = aLine;
} else {
cmd = aLine.substr(0, x);
param = aLine.substr(x+1);
}
if(cmd == "$Search") {
if(state != STATE_CONNECTED) {
return;
}
string::size_type i = 0;
string::size_type j = param.find(' ', i);
if(j == string::npos || i == j)
return;
string seeker = fromNmdc(param.substr(i, j-i));
// Filter own searches
if(SETTING(CONNECTION_TYPE) == SettingsManager::CONNECTION_ACTIVE) {
if(seeker == (getLocalIp() + ":" + Util::toString(SETTING(UDP_PORT)))) {
return;
}
} else {
// Hub:seeker
if(Util::stricmp(seeker.c_str() + 4, getNick().c_str()) == 0) {
return;
}
}
i = j + 1;
{
Lock l(cs);
u_int32_t tick = GET_TICK();
seekers.push_back(make_pair(seeker, tick));
// First, check if it's a flooder
FloodIter fi;
for(fi = flooders.begin(); fi != flooders.end(); ++fi) {
if(fi->first == seeker) {
return;
}
}
int count = 0;
for(fi = seekers.begin(); fi != seekers.end(); ++fi) {
if(fi->first == seeker)
count++;
if(count > 7) {
if(seeker.compare(0, 4, "Hub:") == 0)
Speaker<NmdcHubListener>::fire(NmdcHubListener::SearchFlood(), this, seeker.substr(4));
else
Speaker<NmdcHubListener>::fire(NmdcHubListener::SearchFlood(), this, seeker + STRING(NICK_UNKNOWN));
flooders.push_back(make_pair(seeker, tick));
return;
}
}
}
int a;
if(param[i] == 'F') {
a = SearchManager::SIZE_DONTCARE;
} else if(param[i+2] == 'F') {
a = SearchManager::SIZE_ATLEAST;
} else {
a = SearchManager::SIZE_ATMOST;
}
i += 4;
j = param.find('?', i);
if(j == string::npos || i == j)
return;
string size = param.substr(i, j-i);
i = j + 1;
j = param.find('?', i);
if(j == string::npos || i == j)
return;
int type = Util::toInt(param.substr(i, j-i)) - 1;
i = j + 1;
param = param.substr(i);
if(param.size() > 0) {
Speaker<NmdcHubListener>::fire(NmdcHubListener::Search(), this, seeker, a, Util::toInt64(size), type, fromNmdc(param));
if(seeker.compare(0, 4, "Hub:") == 0) {
User::Ptr u;
{
Lock l(cs);
User::NickIter ni = users.find(seeker.substr(4));
if(ni != users.end() && !ni->second->isSet(User::PASSIVE)) {
u = ni->second;
u->setFlag(User::PASSIVE);
}
}
if(u) {
updated(u);
}
}
}
} else if(cmd == "$MyINFO") {
string::size_type i, j;
i = 5;
j = param.find(' ', i);
if( (j == string::npos) || (j == i) )
return;
string nick = fromNmdc(param.substr(i, j-i));
i = j + 1;
User::Ptr u;
dcassert(nick.size() > 0);
{
Lock l(cs);
User::NickIter ni = users.find(nick);
if(ni == users.end()) {
u = users[nick] = ClientManager::getInstance()->getUser(nick, this);
} else {
u = ni->second;
}
}
j = param.find('$', i);
if(j == string::npos)
return;
string tmpDesc = Util::validateMessage(fromNmdc(param.substr(i, j-i)), true);
// Look for a tag...
if(tmpDesc.size() > 0 && tmpDesc[tmpDesc.size()-1] == '>') {
x = tmpDesc.rfind('<');
if(x != string::npos) {
// Hm, we have something...
u->setTag(tmpDesc.substr(x));
tmpDesc.erase(x);
} else {
u->setTag(Util::emptyString);
}
} else {
u->setTag(Util::emptyString);
}
u->setDescription(tmpDesc);
i = j + 3;
j = param.find('$', i);
if(j == string::npos)
return;
u->setConnection(fromNmdc(param.substr(i, j-i-1)));
i = j + 1;
j = param.find('$', i);
if(j == string::npos)
return;
u->setEmail(Util::validateMessage(fromNmdc(param.substr(i, j-i)), true));
i = j + 1;
j = param.find('$', i);
if(j == string::npos)
return;
u->setBytesShared(param.substr(i, j-i));
Speaker<NmdcHubListener>::fire(NmdcHubListener::MyInfo(), this, u);
} else if(cmd == "$Quit") {
if(!param.empty()) {
User::Ptr u;
{
Lock l(cs);
User::NickIter i = users.find(fromNmdc(param));
if(i == users.end()) {
dcdebug("C::onLine Quitting user %s not found\n", param.c_str());
return;
}
u = i->second;
users.erase(i);
}
Speaker<NmdcHubListener>::fire(NmdcHubListener::Quit(), this, u);
ClientManager::getInstance()->putUserOffline(u, true);
}
} else if(cmd == "$ConnectToMe") {
if(state != STATE_CONNECTED) {
return;
}
string::size_type i = param.find(' ');
string::size_type j;
if( (i == string::npos) || ((i + 1) >= param.size()) ) {
return;
}
i++;
j = param.find(':', i);
if(j == string::npos) {
return;
}
string server = fromNmdc(param.substr(i, j-i));
if(j+1 >= param.size()) {
return;
}
string port = param.substr(j+1);
ConnectionManager::getInstance()->nmdcConnect(server, (short)Util::toInt(port), getNick());
Speaker<NmdcHubListener>::fire(NmdcHubListener::ConnectToMe(), this, server, (short)Util::toInt(port));
} else if(cmd == "$RevConnectToMe") {
if(state != STATE_CONNECTED) {
return;
}
User::Ptr u;
bool up = false;
{
Lock l(cs);
string::size_type j = param.find(' ');
if(j == string::npos) {
return;
}
User::NickIter i = users.find(fromNmdc(param.substr(0, j)));
if(i == users.end()) {
return;
}
u = i->second;
if(!u->isSet(User::PASSIVE)) {
u->setFlag(User::PASSIVE);
up = true;
}
}
if(u) {
if(SETTING(CONNECTION_TYPE) == SettingsManager::CONNECTION_ACTIVE) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -