www.pudn.com > DCPlusPlus-src.zip > HubManager.cpp


/*  
 * Copyright (C) 2001-2004 Jacek Sieka, j_s at telia 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 "HubManager.h" 
 
#include "ClientManager.h" 
#include "CryptoManager.h" 
 
#include "HttpConnection.h" 
#include "StringTokenizer.h" 
#include "SimpleXML.h" 
#include "UserCommand.h" 
 
#define FAVORITES_FILE "Favorites.xml" 
 
void HubManager::addFavoriteUser(User::Ptr& aUser) {  
	if(find(users.begin(), users.end(), aUser) == users.end()) { 
		users.push_back(aUser); 
		aUser->setFavoriteUser(new FavoriteUser()); 
		fire(HubManagerListener::UserAdded(), aUser); 
		save(); 
	} 
} 
 
void HubManager::removeFavoriteUser(User::Ptr& aUser) { 
	User::Iter i = find(users.begin(), users.end(), aUser); 
	if(i != users.end()) { 
		aUser->setFavoriteUser(NULL); 
		fire(HubManagerListener::UserRemoved(), aUser); 
		users.erase(i); 
		save(); 
	} 
} 
 
void HubManager::addFavorite(const FavoriteHubEntry& aEntry) { 
	FavoriteHubEntry* f; 
 
	FavoriteHubEntry::Iter i = getFavoriteHub(aEntry.getServer()); 
	if(i != favoriteHubs.end()) { 
		return; 
	} 
	f = new FavoriteHubEntry(aEntry); 
	favoriteHubs.push_back(f); 
	fire(HubManagerListener::FavoriteAdded(), f); 
	save(); 
} 
 
void HubManager::removeFavorite(FavoriteHubEntry* entry) { 
	FavoriteHubEntry::Iter i = find(favoriteHubs.begin(), favoriteHubs.end(), entry); 
	if(i == favoriteHubs.end()) { 
		return; 
	} 
 
	fire(HubManagerListener::FavoriteRemoved(), entry); 
	favoriteHubs.erase(i); 
	delete entry; 
	save(); 
} 
 
void HubManager::onHttpFinished() throw() { 
	string::size_type i, j; 
	string* x; 
	string bzlist; 
 
	if(listType == TYPE_BZIP2) { 
		try { 
			CryptoManager::getInstance()->decodeBZ2((u_int8_t*)downloadBuf.data(), downloadBuf.size(), bzlist); 
		} catch(const CryptoException&) { 
			bzlist.clear(); 
		} 
		x = &bzlist; 
	} else { 
		x = &downloadBuf; 
	} 
 
	{ 
		Lock l(cs); 
		publicHubs.clear(); 
 
		if(x->compare(0, 5, " tok(utfText.substr(i, j-i), '|'); 
				i = j + 2; 
				if(tok.getTokens().size() < 4) 
					continue; 
 
				StringList::const_iterator k = tok.getTokens().begin(); 
				const string& name = *k++; 
				const string& server = *k++; 
				const string& desc = *k++; 
				const string& usersOnline = *k++; 
				publicHubs.push_back(HubEntry(name, server, desc, usersOnline)); 
			} 
		} 
	} 
	downloadBuf = Util::emptyString; 
} 
 
class XmlListLoader : public SimpleXMLReader::CallBack { 
public: 
	XmlListLoader(HubEntry::List& lst) : publicHubs(lst) { }; 
	virtual ~XmlListLoader() { } 
	virtual void startTag(const string& name, StringPairList& attribs, bool) { 
		if(name == "Hub") { 
			const string& name = getAttrib(attribs, "Name", 0); 
			const string& server = getAttrib(attribs, "Address", 1); 
			const string& description = getAttrib(attribs, "Description", 2); 
			const string& users = getAttrib(attribs, "Users", 3); 
			const string& country = getAttrib(attribs, "Country", 4); 
			const string& shared = getAttrib(attribs, "Shared", 5); 
			const string& minShare = getAttrib(attribs, "Minshare", 5); 
			const string& minSlots = getAttrib(attribs, "Minslots", 5); 
			const string& maxHubs = getAttrib(attribs, "Maxhubs", 5); 
			const string& maxUsers = getAttrib(attribs, "Maxusers", 5); 
			const string& reliability = getAttrib(attribs, "Reliability", 5); 
			const string& rating = getAttrib(attribs, "Rating", 5); 
			publicHubs.push_back(HubEntry(name, server, description, users, country, shared, minShare, minSlots, maxHubs, maxUsers, reliability, rating)); 
		} 
	} 
	virtual void endTag(const string&, const string&) { 
 
	} 
private: 
	HubEntry::List& publicHubs; 
}; 
 
void HubManager::loadXmlList(const string& xml) { 
	try { 
		XmlListLoader loader(publicHubs); 
		SimpleXMLReader(&loader).fromXML(xml); 
	} catch(const SimpleXMLException&) { 
 
	} 
} 
 
void HubManager::save() { 
	if(dontSave) 
		return; 
 
	Lock l(cs); 
	try { 
		SimpleXML xml; 
 
		xml.addTag("Favorites"); 
		xml.stepIn(); 
 
		xml.addTag("Hubs"); 
		xml.stepIn(); 
 
		for(FavoriteHubEntry::Iter i = favoriteHubs.begin(); i != favoriteHubs.end(); ++i) { 
			xml.addTag("Hub"); 
			xml.addChildAttrib("Name", (*i)->getName()); 
			xml.addChildAttrib("Connect", (*i)->getConnect()); 
			xml.addChildAttrib("Description", (*i)->getDescription()); 
			xml.addChildAttrib("Nick", (*i)->getNick(false)); 
			xml.addChildAttrib("Password", (*i)->getPassword()); 
			xml.addChildAttrib("Server", (*i)->getServer()); 
			xml.addChildAttrib("UserDescription", (*i)->getUserDescription()); 
			xml.addChildAttrib("Bottom", Util::toString((*i)->getBottom())); 
			xml.addChildAttrib("Top", Util::toString((*i)->getTop())); 
			xml.addChildAttrib("Right", Util::toString((*i)->getRight())); 
			xml.addChildAttrib("Left", Util::toString((*i)->getLeft())); 
		} 
		xml.stepOut(); 
		xml.addTag("Users"); 
		xml.stepIn(); 
		for(User::Iter j = users.begin(); j != users.end(); ++j) { 
			xml.addTag("User"); 
			xml.addChildAttrib("Nick", (*j)->getNick()); 
			xml.addChildAttrib("LastHubAddress", (*j)->getLastHubAddress()); 
			xml.addChildAttrib("LastHubName", (*j)->getLastHubName()); 
			xml.addChildAttrib("LastSeen", (*j)->getFavoriteLastSeen()); 
			xml.addChildAttrib("GrantSlot", (*j)->getFavoriteGrantSlot()); 
			xml.addChildAttrib("UserDescription", (*j)->getUserDescription()); 
		} 
		xml.stepOut(); 
		xml.addTag("UserCommands"); 
		xml.stepIn(); 
		for(UserCommand::Iter k = userCommands.begin(); k != userCommands.end(); ++k) { 
			if(!k->isSet(UserCommand::FLAG_NOSAVE)) { 
				xml.addTag("UserCommand"); 
				xml.addChildAttrib("Type", k->getType()); 
				xml.addChildAttrib("Context", k->getCtx()); 
				xml.addChildAttrib("Name", k->getName()); 
				xml.addChildAttrib("Command", k->getCommand()); 
				xml.addChildAttrib("Hub", k->getHub()); 
			} 
		} 
		xml.stepOut(); 
 
		xml.stepOut(); 
 
		string fname = Util::getAppPath() + FAVORITES_FILE; 
 
		File f(fname + ".tmp", File::WRITE, File::CREATE | File::TRUNCATE); 
		f.write(SimpleXML::utf8Header); 
		f.write(xml.toXML()); 
		f.close(); 
		File::deleteFile(fname); 
		File::renameFile(fname + ".tmp", fname); 
 
	} catch(const Exception& e) { 
		dcdebug("HubManager::save: %s\n", e.getError().c_str()); 
	} 
} 
 
void HubManager::load() { 
	 
	// Add NMDC standard op commands 
	static const char kickstr[] =  
		"$To: %[nick] From: %[mynick] $<%[mynick]> You are being kicked because: %[line:Reason]|<%[mynick]> %[mynick] is kicking %[nick] because: %[line:Reason]|$Kick %[nick]|"; 
	addUserCommand(UserCommand::TYPE_RAW_ONCE, UserCommand::CONTEXT_CHAT | UserCommand::CONTEXT_SEARCH, UserCommand::FLAG_NOSAVE,  
		STRING(KICK_USER), kickstr, "op"); 
	static const char redirstr[] = 
		"$OpForceMove $Who:%[nick]$Where:%[line:Target Server]$Msg:%[line:Message]|"; 
	addUserCommand(UserCommand::TYPE_RAW_ONCE, UserCommand::CONTEXT_CHAT | UserCommand::CONTEXT_SEARCH, UserCommand::FLAG_NOSAVE,  
		STRING(REDIRECT_USER), redirstr, "op"); 
 
	// Add ADC standard op commands 
	static const char adc_disconnectstr[] = 
		"HDSC %[mycid] %[cid] DI ND Friendly\\ disconnect\n"; 
	addUserCommand(UserCommand::TYPE_RAW_ONCE, UserCommand::CONTEXT_CHAT | UserCommand::CONTEXT_SEARCH, UserCommand::FLAG_NOSAVE, 
		STRING(DISCONNECT_USER), adc_disconnectstr, "adc://op"); 
	static const char adc_kickstr[] = 
		"HDSC %[mycid] %[cid] KK KK %[line:Reason]\n"; 
	addUserCommand(UserCommand::TYPE_RAW_ONCE, UserCommand::CONTEXT_CHAT | UserCommand::CONTEXT_SEARCH, UserCommand::FLAG_NOSAVE, 
		STRING(KICK_USER), adc_kickstr, "adc://op"); 
	static const char adc_banstr[] = 
		"HDSC %[mycid] %[cid] BN BN %[line:Seconds (-1 = forever)] %[line:Reason]\n"; 
	addUserCommand(UserCommand::TYPE_RAW_ONCE, UserCommand::CONTEXT_CHAT | UserCommand::CONTEXT_SEARCH, UserCommand::FLAG_NOSAVE, 
		STRING(BAN_USER), adc_banstr, "adc://op"); 
	static const char adc_redirstr[] = 
		"HDSC %[mycid] %[cid] RD RD %[line:Redirect address] %[line:Reason]\n"; 
	addUserCommand(UserCommand::TYPE_RAW_ONCE, UserCommand::CONTEXT_CHAT | UserCommand::CONTEXT_SEARCH, UserCommand::FLAG_NOSAVE, 
		STRING(REDIRECT_USER), adc_redirstr, "adc://op"); 
 
 
	try { 
		SimpleXML xml; 
		xml.fromXML(File(Util::getAppPath() + FAVORITES_FILE, File::READ, File::OPEN).read()); 
		 
		if(xml.findChild("Favorites")) { 
			xml.stepIn(); 
			load(&xml); 
			xml.stepOut(); 
		} 
	} catch(const Exception& e) { 
		dcdebug("HubManager::load: %s\n", e.getError().c_str()); 
	} 
} 
 
void HubManager::load(SimpleXML* aXml) { 
	dontSave = true; 
 
	// Old names...load for compatibility. 
	aXml->resetCurrentChild(); 
	if(aXml->findChild("Favorites")) { 
		aXml->stepIn(); 
		while(aXml->findChild("Favorite")) { 
			FavoriteHubEntry* e = new FavoriteHubEntry(); 
			e->setName(aXml->getChildAttrib("Name")); 
			e->setConnect(aXml->getBoolChildAttrib("Connect")); 
			e->setDescription(aXml->getChildAttrib("Description")); 
			e->setNick(aXml->getChildAttrib("Nick")); 
			e->setPassword(aXml->getChildAttrib("Password")); 
			e->setServer(aXml->getChildAttrib("Server")); 
			e->setUserDescription(aXml->getChildAttrib("UserDescription")); 
			favoriteHubs.push_back(e); 
		} 
		aXml->stepOut(); 
	} 
	aXml->resetCurrentChild(); 
	if(aXml->findChild("Commands")) { 
		aXml->stepIn(); 
		while(aXml->findChild("Command")) { 
			const string& name = aXml->getChildAttrib("Name"); 
			const string& command = aXml->getChildAttrib("Command"); 
			const string& hub = aXml->getChildAttrib("Hub"); 
			const string& nick = aXml->getChildAttrib("Nick"); 
			if(nick.empty()) { 
				// Old mainchat style command 
				addUserCommand(UserCommand::TYPE_RAW, UserCommand::CONTEXT_CHAT | UserCommand::CONTEXT_SEARCH,  
					0, name, "<%[mynick]> " + command + "|", hub); 
			} else { 
				addUserCommand(UserCommand::TYPE_RAW, UserCommand::CONTEXT_CHAT | UserCommand::CONTEXT_SEARCH, 
					0, name, "$To: " + nick + " From: %[mynick] $" + command + "|", hub); 
			} 
		} 
		aXml->stepOut(); 
	} 
	// End old names 
 
	aXml->resetCurrentChild(); 
	if(aXml->findChild("Hubs")) { 
		aXml->stepIn(); 
		while(aXml->findChild("Hub")) { 
			FavoriteHubEntry* e = new FavoriteHubEntry(); 
			e->setName(aXml->getChildAttrib("Name")); 
			e->setConnect(aXml->getBoolChildAttrib("Connect")); 
			e->setDescription(aXml->getChildAttrib("Description")); 
			e->setNick(aXml->getChildAttrib("Nick")); 
			e->setPassword(aXml->getChildAttrib("Password")); 
			e->setServer(aXml->getChildAttrib("Server")); 
			e->setUserDescription(aXml->getChildAttrib("UserDescription")); 
			e->setBottom((u_int16_t)aXml->getIntChildAttrib("Bottom") ); 
			e->setTop((u_int16_t)aXml->getIntChildAttrib("Top")); 
			e->setRight((u_int16_t)aXml->getIntChildAttrib("Right")); 
			e->setLeft((u_int16_t)aXml->getIntChildAttrib("Left")); 
			favoriteHubs.push_back(e); 
		} 
		aXml->stepOut(); 
	} 
	aXml->resetCurrentChild(); 
	if(aXml->findChild("Users")) { 
		aXml->stepIn(); 
		while(aXml->findChild("User")) { 
			User::Ptr u = ClientManager::getInstance()->getUser(aXml->getChildAttrib("Nick"), aXml->getChildAttrib("LastHubAddress")); 
			if(!u->isOnline()) { 
				u->setLastHubAddress(aXml->getChildAttrib("LastHubAddress")); 
				u->setLastHubName(aXml->getChildAttrib("LastHubName")); 
			} 
			addFavoriteUser(u); 
			u->setFavoriteGrantSlot(aXml->getBoolChildAttrib("GrantSlot")); 
			u->setFavoriteLastSeen((u_int32_t)aXml->getIntChildAttrib("LastSeen")); 
			u->setUserDescription(aXml->getChildAttrib("UserDescription")); 
		} 
		aXml->stepOut(); 
	} 
	aXml->resetCurrentChild(); 
	if(aXml->findChild("UserCommands")) { 
		aXml->stepIn(); 
		while(aXml->findChild("UserCommand")) { 
			addUserCommand(aXml->getIntChildAttrib("Type"), aXml->getIntChildAttrib("Context"), 
				0, aXml->getChildAttrib("Name"), aXml->getChildAttrib("Command"), aXml->getChildAttrib("Hub")); 
		} 
		aXml->stepOut(); 
	} 
 
	dontSave = false; 
} 
 
void HubManager::refresh() { 
	StringList sl = StringTokenizer(SETTING(HUBLIST_SERVERS), ';').getTokens(); 
	if(sl.empty()) 
		return; 
	const string& server = sl[(lastServer) % sl.size()]; 
	if(Util::strnicmp(server.c_str(), "http://", 7) != 0) { 
		lastServer++; 
		return; 
	} 
 
	fire(HubManagerListener::DownloadStarting(), server); 
	if(!running) { 
		if(!c) 
			c = new HttpConnection(); 
		{ 
			Lock l(cs); 
			publicHubs.clear(); 
		} 
		c->addListener(this); 
		c->downloadFile(server); 
		running = true; 
	} 
} 
 
UserCommand::List HubManager::getUserCommands(int ctx, const string& hub, bool op) { 
	Lock l(cs); 
	UserCommand::List lst; 
	bool adc = hub.size() >= 6 && hub.substr(0, 6) == "adc://"; 
	for(UserCommand::Iter i = userCommands.begin(); i != userCommands.end(); ++i) { 
		UserCommand& uc = *i; 
		if(uc.getCtx() & ctx) { 
		if( (!adc && (uc.getHub().empty() || (op && uc.getHub() == "op"))) || 
				(adc && (uc.getHub() == "adc://" || (op && uc.getHub() == "adc://op"))) || 
				(Util::stricmp(hub, uc.getHub()) == 0) ) 
			{ 
				lst.push_back(*i); 
			} 
		} 
	} 
	return lst; 
} 
 
// HttpConnectionListener 
void HubManager::on(Data, HttpConnection*, const u_int8_t* buf, size_t len) throw() {  
	downloadBuf.append((const char*)buf, len); 
} 
 
void HubManager::on(Failed, HttpConnection*, const string& aLine) throw() {  
	c->removeListener(this); 
	lastServer++; 
	running = false; 
	fire(HubManagerListener::DownloadFailed(), aLine); 
} 
void HubManager::on(Complete, HttpConnection*, const string& aLine) throw() { 
	c->removeListener(this); 
	onHttpFinished(); 
	running = false; 
	fire(HubManagerListener::DownloadFinished(), aLine); 
} 
void HubManager::on(Redirected, HttpConnection*, const string& aLine) throw() {  
	fire(HubManagerListener::DownloadStarting(), aLine); 
} 
void HubManager::on(TypeNormal, HttpConnection*) throw() {  
	listType = TYPE_NORMAL;  
} 
void HubManager::on(TypeBZ2, HttpConnection*) throw() {  
	listType = TYPE_BZIP2;  
} 
 
/** 
 * @file 
 * $Id: HubManager.cpp,v 1.55 2004/09/26 08:45:33 arnetheduck Exp $ 
 */