⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sharemanager.cpp

📁 一个不错的关于手机模块程序This page contains everything that has changed in the history of DC++. Read this to fin
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/*
 * Copyright (C) 2001-2006 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 "ShareManager.h"
#include "ResourceManager.h"

#include "CryptoManager.h"
#include "ClientManager.h"
#include "LogManager.h"
#include "HashManager.h"

#include "SimpleXML.h"
#include "StringTokenizer.h"
#include "File.h"
#include "FilteredFile.h"
#include "BZUtils.h"

#ifndef _WIN32
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fnmatch.h>
#endif

#include <limits>

ShareManager::ShareManager() : hits(0), listLen(0), bzXmlListLen(0),
	xmlDirty(true), refreshDirs(false), update(false), initial(true), listN(0), refreshing(0), lFile(NULL), 
	xFile(NULL), lastXmlUpdate(0), lastFullUpdate(GET_TICK()), bloom(1<<20)
{ 
	SettingsManager::getInstance()->addListener(this);
	TimerManager::getInstance()->addListener(this);
	DownloadManager::getInstance()->addListener(this);
	HashManager::getInstance()->addListener(this);
}

ShareManager::~ShareManager() {
	SettingsManager::getInstance()->removeListener(this);
	TimerManager::getInstance()->removeListener(this);
	DownloadManager::getInstance()->removeListener(this);
	HashManager::getInstance()->removeListener(this);

	join();

	delete lFile;
	lFile = NULL;
	delete xFile;
	xFile = NULL;

#ifdef _WIN32
	WIN32_FIND_DATA data;
	HANDLE hFind;

	hFind = FindFirstFile(Text::toT(Util::getConfigPath() + "files*.xml.bz2").c_str(), &data);
	if(hFind != INVALID_HANDLE_VALUE) {
		do {
			if(_tcslen(data.cFileName) > 13) // length of "files.xml.bz2"
				File::deleteFile(Util::getAppPath() + Text::fromT(data.cFileName));			
		} while(FindNextFile(hFind, &data));

		FindClose(hFind);
	}

#else
	DIR* dir = opendir(Util::getAppName().c_str());
	if (dir) {
		while (struct dirent* ent = readdir(dir)) {
			if (fnmatch("files*.xml.bz2", ent->d_name, 0) == 0) {
					File::deleteFile(Util::getConfigPath() + ent->d_name);	
				}
		}
		closedir(dir);
	}		
#endif

	for(Directory::MapIter j = directories.begin(); j != directories.end(); ++j) {
		delete j->second;
	}
}

ShareManager::Directory::~Directory() {
	for(MapIter i = directories.begin(); i != directories.end(); ++i)
		delete i->second;
	for(File::Iter i = files.begin(); i != files.end(); ++i) {
		ShareManager::getInstance()->removeTTH(i->getTTH(), *i);
	}
}

string ShareManager::translateTTH(const string& TTH) throw(ShareException) {
	TTHValue v(TTH);
	HashFileIter i = tthIndex.find(&v);
	if(i != tthIndex.end()) {
		return i->second->getADCPath();
	} else {
		throw ShareException(UserConnection::FILE_NOT_AVAILABLE);
	}
}

string ShareManager::translateFileName(const string& aFile) throw(ShareException) {
	RLock<> l(cs);
	if(aFile == "MyList.DcLst") {
		throw ShareException("NMDC-style lists no longer supported, please upgrade your client");
	} else if(aFile == "files.xml.bz2" || aFile == "files.xml") {
		generateXmlList();
		return getBZXmlFile();
	} else {
		if(aFile.length() < 3)
			throw ShareException(UserConnection::FILE_NOT_AVAILABLE);

		string file;

		// Check for tth root identifier
		if(aFile.compare(0, 4, "TTH/") == 0) {
			file = translateTTH(aFile.substr(4));
		} else if(aFile[0] != '/') {
			throw ShareException(UserConnection::FILE_NOT_AVAILABLE);
		}  else {
			file = aFile;
		}

		string::size_type i = file.find('/', 1);
		if(i == string::npos)
			throw ShareException(UserConnection::FILE_NOT_AVAILABLE);
		
		RLock<> l(cs);
		StringPairIter j = lookupVirtual(file.substr(1, i-1));
		if(j == virtualMap.end()) {
			throw ShareException(UserConnection::FILE_NOT_AVAILABLE);
		}

		file = file.substr(i + 1);
		Directory::File::Iter it;
		if(!checkFile(j->second, file, it)) {
			throw ShareException(UserConnection::FILE_NOT_AVAILABLE);
		}

#ifdef _WIN32
		for(i = 0; i < file.length(); ++i) {
			if(file[i] == '/')
				file[i] = '\\';
		}
#endif
		return j->second + file;
	}
}

AdcCommand ShareManager::getFileInfo(const string& aFile) throw(ShareException) {
	if(aFile == "files.xml") {
		generateXmlList();
		/** todo fix size... */
		AdcCommand cmd(AdcCommand::CMD_RES);
		cmd.addParam("FN", "files.xml");
		cmd.addParam("TR", xmlRoot.toBase32());
		return cmd;
	} else if(aFile == "files.xml.bz2") {
		generateXmlList();

		AdcCommand cmd(AdcCommand::CMD_RES);
		cmd.addParam("FN", "files.xml.bz2");
		cmd.addParam("SI", Util::toString(File::getSize(getBZXmlFile())));
		cmd.addParam("TR", xmlbzRoot.toBase32());
		return cmd;
	}

	if(aFile.compare(0, 4, "TTH/") != 0)
		throw ShareException(UserConnection::FILE_NOT_AVAILABLE);

	RLock<> l(cs);
	TTHValue val(aFile.substr(4));
	HashFileIter i = tthIndex.find(&val);
	if(i == tthIndex.end()) {
		throw ShareException(UserConnection::FILE_NOT_AVAILABLE);
	}

	Directory::File::Iter f = i->second;
	AdcCommand cmd(AdcCommand::CMD_RES);
	cmd.addParam("FN", f->getADCPath());
	cmd.addParam("SI", Util::toString(f->getSize()));
	cmd.addParam("TR", f->getTTH().toBase32());
	return cmd;
}

StringPairIter ShareManager::findVirtual(const string& name) {
	for(StringPairIter i = virtualMap.begin(); i != virtualMap.	end(); ++i) {
		if(Util::stricmp(name, i->second) == 0)
			return i;
	}
	return virtualMap.end();
}

StringPairIter ShareManager::lookupVirtual(const string& name) {
	for(StringPairIter i = virtualMap.begin(); i != virtualMap.	end(); ++i) {
		if(Util::stricmp(name, i->first) == 0)
			return i;
	}
	return virtualMap.end();
}

bool ShareManager::checkFile(const string& dir, const string& aFile, Directory::File::Iter& it) {
	Directory::MapIter mi = directories.find(dir);
	if(mi == directories.end())
		return false;
	Directory* d = mi->second;
								  
	string::size_type i;
	string::size_type j = 0;
	while( (i = aFile.find('/', j)) != string::npos) {
		mi = d->directories.find(aFile.substr(j, i-j));
		j = i + 1;
		if(mi == d->directories.end())
			return false;
		d = mi->second;
	}
	
	it = find_if(d->files.begin(), d->files.end(), Directory::File::StringComp(aFile.substr(j)));
	if(it == d->files.end())
		return false;

	return true;
}

string ShareManager::validateVirtual(const string& aVirt) {
	string tmp = aVirt;
	string::size_type idx;

	while( (idx = tmp.find_first_of("$|:\\/")) != string::npos) {
		tmp[idx] = '_';
	}
	return tmp;
}

void ShareManager::load(SimpleXML* aXml) {
	WLock<> l(cs);

	if(aXml->findChild("Share")) {
		aXml->stepIn();
		while(aXml->findChild("Directory")) {
			const string& virt = aXml->getChildAttrib("Virtual");
			string d(aXml->getChildData()), newVirt;

			if(d[d.length() - 1] != PATH_SEPARATOR)
				d += PATH_SEPARATOR;
			if(!virt.empty()) {
				newVirt = virt;
				if(newVirt[newVirt.length() - 1] == PATH_SEPARATOR) {
					newVirt.erase(newVirt.length() -1, 1);
				}
			} else {
				newVirt = Util::getLastDir(d);
			}

			// get rid of bad characters in virtual names
			newVirt = validateVirtual(newVirt);

			// add only unique directories
			if(lookupVirtual(newVirt) == virtualMap.end()) {
				Directory* dp = new Directory(newVirt);
				directories[d] = dp;
				virtualMap.push_back(make_pair(newVirt, d));
			}
		}
		aXml->stepOut();
	}
}

struct ShareLoader : public SimpleXMLReader::CallBack {
	ShareLoader(ShareManager::Directory::Map& aDirs, StringPairList& aVirts) : dirs(aDirs), virts(aVirts), cur(NULL), depth(0) { }
	virtual void startTag(const string& name, StringPairList& attribs, bool simple) {
		if(name == "Directory") {
			if(depth == 0) {
				const string& name = getAttrib(attribs, "Name", 0);
				for(StringPairIter i = virts.begin(); i != virts.end(); ++i) {
					if(i->first == name) {
						cur = dirs[i->second];
						break;
					}
				}
			} else if(cur != NULL) {
				cur = new ShareManager::Directory(getAttrib(attribs, "Name", 0), cur);
				cur->addType(SearchManager::TYPE_DIRECTORY); // needed since we match our own name in directory searches
				cur->getParent()->directories[cur->getName()] = cur;
			}

			if(simple)
				cur = cur->getParent();
			else
				depth++;
		} else if(cur != NULL && name == "File") {
			const string& fname = getAttrib(attribs, "Name", 0);
			const string& size = getAttrib(attribs, "Size", 1);
			const string& root = getAttrib(attribs, "TTH", 2);
			if(fname.empty() || size.empty() || (root.size() != 39)) {
				dcdebug("Invalid file found: %s\n", fname.c_str());
				return;
			}
			cur->files.insert(ShareManager::Directory::File(fname, Util::toInt64(size), cur, TTHValue(root)));
		}
	}
	virtual void endTag(const string& name, const string&) {
		if(name == "Directory") {
			depth--;
			if(cur) {
				cur = cur->getParent();
			}
		}
	}

private:
	ShareManager::Directory::Map& dirs;
	StringPairList& virts;

	ShareManager::Directory* cur;
	size_t depth;
};

bool ShareManager::loadCache() {
	try {
		ShareLoader loader(directories, virtualMap);
		string txt;
		::File ff(Util::getConfigPath() + "files.xml.bz2", ::File::READ, ::File::OPEN);
		FilteredInputStream<UnBZFilter, false> f(&ff);
		const size_t BUF_SIZE = 64*1024;
		char buf[BUF_SIZE];
		size_t len;
		for(;;) {
			size_t n = BUF_SIZE;
			len = f.read(buf, n);
			txt.append(buf, len);
			if(len < BUF_SIZE)
				break;
		}

		SimpleXMLReader(&loader).fromXML(txt);

		for(Directory::MapIter i = directories.begin(); i != directories.end(); ++i) {
			addTree(i->second);
		}

		return true;
	} catch(const Exception& e) {
		dcdebug("%s\n", e.getError().c_str());
	}
	return false;
}

void ShareManager::save(SimpleXML* aXml) {
	RLock<> l(cs);
	
	aXml->addTag("Share");
	aXml->stepIn();
	for(StringPairIter i = virtualMap.begin(); i != virtualMap.end(); ++i) {
		aXml->addTag("Directory", i->second);
		aXml->addChildAttrib("Virtual", i->first);
	}
	aXml->stepOut();
}

void ShareManager::addDirectory(const string& aDirectory, const string& aName) throw(ShareException) {
	if(aDirectory.empty() || aName.empty()) {
		throw ShareException(STRING(NO_DIRECTORY_SPECIFIED));
	}

	if(Util::stricmp(SETTING(TEMP_DOWNLOAD_DIRECTORY), aDirectory) == 0) {
		throw ShareException(STRING(DONT_SHARE_TEMP_DIRECTORY));
	}

	string d(aDirectory);

	if(d[d.length() - 1] != PATH_SEPARATOR)
		d += PATH_SEPARATOR;

	string vName = validateVirtual(aName);

	Directory* dp = NULL;
	{
		RLock<> l(cs);

		for(Directory::MapIter i = directories.begin(); i != directories.end(); ++i) {
			if(Util::strnicmp(d, i->first, i->first.length()) == 0) {
				// Trying to share an already shared directory
				throw ShareException(STRING(DIRECTORY_ALREADY_SHARED));
			} else if(Util::strnicmp(d, i->first, d.length()) == 0) {
				// Trying to share a parent directory
				throw ShareException(STRING(REMOVE_ALL_SUBDIRECTORIES));
			}
		}

		if(lookupVirtual(vName) != virtualMap.end()) {
			throw ShareException(STRING(VIRTUAL_NAME_EXISTS));
		}
	}
	
	dp = buildTree(d, NULL);
	dp->setName(vName);

	{
		WLock<> l(cs);
		addTree(dp);

		directories[d] = dp;
		virtualMap.push_back(make_pair(vName, d));
		setDirty();
	}
}

void ShareManager::removeDirectory(const string& aDirectory, bool duringRefresh) {
	WLock<> l(cs);

	string d(aDirectory);

	if(d[d.length() - 1] != PATH_SEPARATOR)
		d += PATH_SEPARATOR;

	Directory::MapIter i = directories.find(d);
	if(i != directories.end()) {
		delete i->second;
		directories.erase(i);
	}

	for(StringPairIter j = virtualMap.begin(); j != virtualMap.end(); ++j) {
		if(Util::stricmp(j->second.c_str(), d.c_str()) == 0) {
			virtualMap.erase(j);
			break;
		}
	}

	if(!duringRefresh)
		HashManager::getInstance()->stopHashing(d);

	setDirty();
}

void ShareManager::renameDirectory(const string& oName, const string& nName) throw(ShareException) {
	StringPairIter i;
	WLock<> l(cs);
	//Find the virtual name
	i = lookupVirtual(oName);
	if (lookupVirtual(nName) != virtualMap.end()) {
		throw ShareException(STRING(VIRTUAL_NAME_EXISTS));
	} else {
		// Valid newName, lets rename
		i->first = nName;

		//rename the directory, so it will be updated once
		//a new list is generated.
		if( directories.find(i->second) != directories.end() ) {
			directories.find(i->second)->second->setName(nName);
		}
	}

	//Do not call setDirty here since there might be more
	//dirs that should be renamed, this is to avoid creating
	//a new list during renaming.
}

int64_t ShareManager::getShareSize(const string& aDir) throw() {
	RLock<> l(cs);
	dcassert(aDir.size()>0);
	Directory::MapIter i = directories.find(aDir);

	if(i != directories.end()) {
		return i->second->getSize();
	}

	return -1;
}

int64_t ShareManager::getShareSize() throw() {
	RLock<> l(cs);
	int64_t tmp = 0;
	for(Directory::MapIter i = directories.begin(); i != directories.end(); ++i) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -