← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 2508: Prepare for some bencode integration things

 

------------------------------------------------------------
revno: 2508
committer: Jacek Sieka <arnetheduck@xxxxxxxxx>
branch nick: dcplusplus
timestamp: Sun 2011-04-24 13:27:49 +0200
message:
  Prepare for some bencode integration things
added:
  dcpp/Bundle.cpp
  dcpp/Bundle.h
  dcpp/BundleItem.h
  dcpp/SHA1Hash.h
  dcpp/SimpleBencodeReader.cpp
  dcpp/SimpleBencodeReader.h
modified:
  dcpp/CryptoManager.cpp
  dcpp/DCPlusPlus.cpp
  dcpp/DirectoryListing.cpp
  dcpp/HashManager.cpp
  dcpp/QueueItem.h
  dcpp/QueueManager.cpp
  dcpp/QueueManager.h
  dcpp/Util.cpp
  dcpp/forward.h
  win32/DirectoryListingFrame.cpp
  win32/SearchFrame.cpp
  win32/UsersFrame.cpp


--
lp:dcplusplus
https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk

Your team Dcplusplus-team is subscribed to branch lp:dcplusplus.
To unsubscribe from this branch go to https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk/+edit-subscription
=== added file 'dcpp/Bundle.cpp'
--- dcpp/Bundle.cpp	1970-01-01 00:00:00 +0000
+++ dcpp/Bundle.cpp	2011-04-24 11:27:49 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2001-2011 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 "Bundle.h"
+
+#include <boost/range/algorithm/for_each.hpp>
+
+namespace dcpp {
+
+using boost::for_each;
+
+TTHValue Bundle::getHash() const {
+	TigerHash ret;
+
+	for_each(entries, [&](const Entry &e) { ret.update(e.tth.data, TTHValue::BYTES); });
+
+	return TTHValue(ret.finalize());
+}
+
+}

=== added file 'dcpp/Bundle.h'
--- dcpp/Bundle.h	1970-01-01 00:00:00 +0000
+++ dcpp/Bundle.h	2011-04-24 11:27:49 +0000
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2001-2011 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.
+ */
+
+#ifndef DCPLUSPLUS_DCPP_BUNDLE_H_
+#define DCPLUSPLUS_DCPP_BUNDLE_H_
+
+#include <string>
+#include <set>
+
+#include "TigerHash.h"
+#include "MerkleTree.h"
+#include "Pointer.h"
+
+namespace dcpp {
+
+using std::string;
+
+/**
+ * A bundle is a set of related files that can be searched for by a single hash value.
+ *
+ * The hash is defined as follows:
+ * For each file in the set, ordered by name (byte-order, not linguistic), except those specially marked,
+ * compute the compute the hash. Then calculate the combined hash value by passing the concatenated hashes
+ * of each file through the hash function.
+ */
+class Bundle : public intrusive_ptr_base<Bundle> {
+public:
+	struct Entry {
+		string name;
+		int64_t size;
+		TTHValue tth;
+		bool include;
+
+		friend bool operator<(const Entry &lhs, const Entry& rhs) { return lhs.name < rhs.name; }
+	};
+
+	TTHValue getHash() const;
+
+	string name;
+
+	std::set<Entry> entries;
+};
+
+}
+
+#endif /* DCPLUSPLUS_DCPP_BUNDLE_H_ */

=== added file 'dcpp/BundleItem.h'
--- dcpp/BundleItem.h	1970-01-01 00:00:00 +0000
+++ dcpp/BundleItem.h	2011-04-24 11:27:49 +0000
@@ -0,0 +1,27 @@
+/*
+ * BundleItem.h
+ *
+ *  Created on: 22 apr 2011
+ *      Author: arnetheduck
+ */
+
+#ifndef BUNDLEITEM_H_
+#define BUNDLEITEM_H_
+
+#include "Bundle.h"
+#include "Util.h"
+
+namespace dcpp {
+
+class BundleItem {
+public:
+	BundleItem();
+	BundleItem(const string& root, const BundlePtr &bundle) : root(root), bundle(bundle) { }
+
+	GETSET(string, root, Root);
+	GETSET(BundlePtr, bundle, Bundle);
+};
+
+}
+
+#endif /* BUNDLEITEM_H_ */

=== modified file 'dcpp/CryptoManager.cpp'
--- dcpp/CryptoManager.cpp	2011-04-15 20:53:17 +0000
+++ dcpp/CryptoManager.cpp	2011-04-24 11:27:49 +0000
@@ -30,8 +30,6 @@
 
 namespace dcpp {
 
-
-
 CryptoManager::CryptoManager()
 :
 	certsLoaded(false),
@@ -363,7 +361,6 @@
 	return new SSLSocket(allowUntrusted ? serverContext : serverVerContext);
 }
 
-
 void CryptoManager::decodeBZ2(const uint8_t* is, size_t sz, string& os) {
 	bz_stream bs = { 0 };
 

=== modified file 'dcpp/DCPlusPlus.cpp'
--- dcpp/DCPlusPlus.cpp	2011-02-11 23:08:25 +0000
+++ dcpp/DCPlusPlus.cpp	2011-04-24 11:27:49 +0000
@@ -39,8 +39,6 @@
 #include "ThrottleManager.h"
 #include "ConnectivityManager.h"
 
-#include "StringTokenizer.h"
-
 #ifdef _STLP_DEBUG
 void __stl_debug_terminate() {
 	int* x = 0;

=== modified file 'dcpp/DirectoryListing.cpp'
--- dcpp/DirectoryListing.cpp	2011-04-13 19:16:51 +0000
+++ dcpp/DirectoryListing.cpp	2011-04-24 11:27:49 +0000
@@ -94,7 +94,7 @@
 	}
 }
 
-class ListLoader : public dcpp::SimpleXMLReader::CallBack {
+class ListLoader : public SimpleXMLReader::CallBack {
 public:
 	ListLoader(DirectoryListing::Directory* root, bool aUpdating) : cur(root), base("/"), inListing(false), updating(aUpdating) {
 	}
@@ -122,7 +122,7 @@
 string DirectoryListing::loadXML(InputStream& is, bool updating) {
 	ListLoader ll(getRoot(), updating);
 
-	dcpp::SimpleXMLReader(&ll).parse(is, SETTING(MAX_FILELIST_SIZE) ? (size_t)SETTING(MAX_FILELIST_SIZE)*1024*1024 : 0);
+	SimpleXMLReader(&ll).parse(is, SETTING(MAX_FILELIST_SIZE) ? (size_t)SETTING(MAX_FILELIST_SIZE)*1024*1024 : 0);
 
 	return ll.getBase();
 }

=== modified file 'dcpp/HashManager.cpp'
--- dcpp/HashManager.cpp	2011-04-13 19:16:51 +0000
+++ dcpp/HashManager.cpp	2011-04-24 11:27:49 +0000
@@ -812,7 +812,7 @@
 				SFVReader sfv(fname);
 				CRC32Filter* xcrc32 = 0;
 				if(sfv.hasCRC())
-				xcrc32 = &crc32;
+					xcrc32 = &crc32;
 
 				size_t n = 0;
 				TigerTree fastTTH(bs);

=== modified file 'dcpp/QueueItem.h'
--- dcpp/QueueItem.h	2011-04-13 19:16:51 +0000
+++ dcpp/QueueItem.h	2011-04-24 11:27:49 +0000
@@ -39,15 +39,7 @@
 
 class QueueItem : public Flags, public FastAlloc<QueueItem> {
 public:
-	typedef QueueItem* Ptr;
-	typedef std::list<Ptr> List;
-	typedef List::iterator Iter;
-	typedef unordered_map<string*, Ptr, noCaseStringHash, noCaseStringEq> StringMap;
-	typedef StringMap::iterator StringIter;
-	typedef unordered_map<UserPtr, Ptr, User::Hash> UserMap;
-	typedef UserMap::iterator UserIter;
-	typedef unordered_map<UserPtr, List, User::Hash> UserListMap;
-	typedef UserListMap::iterator UserListIter;
+	typedef unordered_map<string*, QueueItemPtr, noCaseStringHash, noCaseStringEq> StringMap;
 
 	enum Priority {
 		DEFAULT = -1,

=== modified file 'dcpp/QueueManager.cpp'
--- dcpp/QueueManager.cpp	2011-04-13 19:16:51 +0000
+++ dcpp/QueueManager.cpp	2011-04-24 11:27:49 +0000
@@ -19,32 +19,27 @@
 #include "stdinc.h"
 #include "QueueManager.h"
 
-#include "format.h"
+#include <boost/range/adaptor/map.hpp>
+#include <boost/range/algorithm/for_each.hpp>
 
 #include "ClientManager.h"
 #include "ConnectionManager.h"
-#include "DirectoryListing.h"
 #include "Download.h"
-#include "DownloadManager.h"
+#include "FilteredFile.h"
+#include "FinishedItem.h"
+#include "FinishedManager.h"
 #include "HashManager.h"
 #include "LogManager.h"
+#include "MerkleCheckOutputStream.h"
 #include "SearchManager.h"
+#include "SearchResult.h"
+#include "SFVReader.h"
 #include "ShareManager.h"
 #include "SimpleXML.h"
-#include "StringTokenizer.h"
-#include "Transfer.h"
 #include "UserConnection.h"
 #include "version.h"
-#include "SearchResult.h"
-#include "MerkleCheckOutputStream.h"
-#include "SFVReader.h"
-#include "FilteredFile.h"
-#include "FinishedItem.h"
-#include "FinishedManager.h"
 #include "ZUtils.h"
 
-#include <climits>
-
 #if !defined(_WIN32) && !defined(PATH_MAX) // Extra PATH_MAX check for Mac OS X
 #include <sys/syslimits.h>
 #endif
@@ -55,6 +50,13 @@
 
 namespace dcpp {
 
+using boost::adaptors::map_values;
+using boost::range::for_each;
+
+QueueManager::FileQueue::~FileQueue() {
+	for_each(queue | map_values, DeleteFunction());
+}
+
 QueueItem* QueueManager::FileQueue::add(const string& aTarget, int64_t aSize,
 						  int aFlags, QueueItem::Priority p, const string& aTempTarget,
 						  time_t aAdded, const TTHValue& root)
@@ -102,32 +104,23 @@
 }
 
 QueueItem* QueueManager::FileQueue::find(const string& target) {
-	QueueItem::StringIter i = queue.find(const_cast<string*>(&target));
+	auto i = queue.find(const_cast<string*>(&target));
 	return (i == queue.end()) ? NULL : i->second;
 }
 
-void QueueManager::FileQueue::find(QueueItem::List& sl, int64_t aSize, const string& suffix) {
-	for(QueueItem::StringIter i = queue.begin(); i != queue.end(); ++i) {
-		if(i->second->getSize() == aSize) {
-			const string& t = i->second->getTarget();
-			if(suffix.empty() || (suffix.length() < t.length() &&
-				Util::stricmp(suffix.c_str(), t.c_str() + (t.length() - suffix.length())) == 0) )
-				sl.push_back(i->second);
-		}
-	}
-}
-
-void QueueManager::FileQueue::find(QueueItem::List& ql, const TTHValue& tth) {
-	for(QueueItem::StringIter i = queue.begin(); i != queue.end(); ++i) {
+QueueManager::QueueItemList QueueManager::FileQueue::find(const TTHValue& tth) {
+	QueueItemList ql;
+	for(auto i = queue.begin(); i != queue.end(); ++i) {
 		QueueItem* qi = i->second;
 		if(qi->getTTH() == tth) {
 			ql.push_back(qi);
 		}
 	}
+	return ql;
 }
 
-static QueueItem* findCandidate(QueueItem* cand, QueueItem::StringIter start, QueueItem::StringIter end, const StringList& recent) {
-	for(QueueItem::StringIter i = start; i != end; ++i) {
+static QueueItem* findCandidate(QueueItem* cand, QueueItem::StringMap::iterator start, QueueItem::StringMap::iterator end, const StringList& recent) {
+	for(auto i = start; i != end; ++i) {
 		QueueItem* q = i->second;
 
 		// We prefer to search for things that are not running...
@@ -161,7 +154,7 @@
 	// We pick a start position at random, hoping that we will find something to search for...
 	QueueItem::StringMap::size_type start = (QueueItem::StringMap::size_type)Util::rand((uint32_t)queue.size());
 
-	QueueItem::StringIter i = queue.begin();
+	auto i = queue.begin();
 	advance(i, start);
 
 	QueueItem* cand = findCandidate(NULL, i, queue.end(), recent);
@@ -186,7 +179,7 @@
 }
 
 void QueueManager::UserQueue::add(QueueItem* qi, const UserPtr& aUser) {
-	QueueItem::List& l = userQueue[qi->getPriority()][aUser];
+	auto& l = userQueue[qi->getPriority()][aUser];
 
 	if(qi->getDownloadedBytes() > 0) {
 		l.push_front(qi);
@@ -199,10 +192,10 @@
 	int p = QueueItem::LAST - 1;
 
 	do {
-		QueueItem::UserListIter i = userQueue[p].find(aUser);
+		auto i = userQueue[p].find(aUser);
 		if(i != userQueue[p].end()) {
 			dcassert(!i->second.empty());
-			for(QueueItem::Iter j = i->second.begin(); j != i->second.end(); ++j) {
+			for(auto j = i->second.begin(); j != i->second.end(); ++j) {
 				QueueItem* qi = *j;
 				if(qi->isWaiting()) {
 					return qi;
@@ -258,14 +251,14 @@
 pair<size_t, int64_t> QueueManager::UserQueue::getQueued(const UserPtr& aUser) const {
 	pair<size_t, int64_t> ret(0, 0);
 	for(size_t i = QueueItem::LOWEST; i < QueueItem::LAST; ++i) {
-		const QueueItem::UserListMap& ulm = userQueue[i];
-		QueueItem::UserListMap::const_iterator iulm = ulm.find(aUser);
+		auto& ulm = userQueue[i];
+		auto iulm = ulm.find(aUser);
 		if(iulm == ulm.end()) {
 			continue;
 		}
 
-		for(QueueItem::List::const_iterator j = iulm->second.begin(); j != iulm->second.end(); ++j) {
-			const QueueItem::Ptr qi = *j;
+		for(auto j = iulm->second.begin(); j != iulm->second.end(); ++j) {
+			auto &qi = *j;
 			++ret.first;
 			if(qi->getSize() != -1) {
 				ret.second += qi->getSize() - qi->getDownloadedBytes();
@@ -276,7 +269,7 @@
 }
 
 QueueItem* QueueManager::UserQueue::getRunning(const UserPtr& aUser) {
-	QueueItem::UserIter i = running.find(aUser);
+	auto i = running.find(aUser);
 	return (i == running.end()) ? 0 : i->second;
 }
 
@@ -292,11 +285,11 @@
 	}
 
 	dcassert(qi->isSource(aUser));
-	QueueItem::UserListMap& ulm = userQueue[qi->getPriority()];
-	QueueItem::UserListIter j = ulm.find(aUser);
+	auto& ulm = userQueue[qi->getPriority()];
+	auto j = ulm.find(aUser);
 	dcassert(j != ulm.end());
-	QueueItem::List& l = j->second;
-	QueueItem::Iter i = find(l.begin(), l.end(), qi);
+	auto& l = j->second;
+	auto i = find(l.begin(), l.end(), qi);
 	dcassert(i != l.end());
 	l.erase(i);
 
@@ -560,7 +553,7 @@
 }
 
 void QueueManager::add(const string& aTarget, int64_t aSize, const TTHValue& root, const HintedUser& aUser,
-	int aFlags /* = 0 */, bool addBad /* = true */)
+	int aFlags /* = 0 */, bool addBad /* = true */, const BundlePtr &bundle)
 {
 	bool wantConnection = true;
 
@@ -599,12 +592,11 @@
 
 		// This will be pretty slow on large queues...
 		if(BOOLSETTING(DONT_DL_ALREADY_QUEUED) && !(aFlags & QueueItem::FLAG_USER_LIST)) {
-			QueueItem::List ql;
-			fileQueue.find(ql, root);
+			auto ql = fileQueue.find(root);
 			if (ql.size() > 0) {
 				// Found one or more existing queue items, lets see if we can add the source to them
 				bool sourceAdded = false;
-				for(QueueItem::Iter i = ql.begin(); i != ql.end(); ++i) {
+				for(auto i = ql.begin(); i != ql.end(); ++i) {
 					if(!(*i)->isSource(aUser)) {
 						try {
 							wantConnection = addSource(*i, aUser, addBad ? QueueItem::Source::FLAG_MASK : 0);
@@ -647,6 +639,12 @@
 		ConnectionManager::getInstance()->getDownloadConnection(aUser);
 }
 
+void QueueManager::add(const string& aRoot, const BundlePtr& bundle, const HintedUser& aUser, int aFlags) {
+	for_each(bundle->entries, [&](const Bundle::Entry& e) { add(aRoot + e.name, e.size, e.tth, aUser, aFlags, true, bundle); });
+	Lock l(cs);
+	bundles.insert(make_pair(bundle->getHash(), BundleItem(aRoot, bundle)));
+}
+
 void QueueManager::readd(const string& target, const HintedUser& aUser) {
 	bool wantConnection = false;
 	{
@@ -876,13 +874,14 @@
 	}
 }
 
-void QueueManager::getTargets(const TTHValue& tth, StringList& sl) {
+StringList QueueManager::getTargets(const TTHValue& tth) {
 	Lock l(cs);
-	QueueItem::List ql;
-	fileQueue.find(ql, tth);
-	for(QueueItem::Iter i = ql.begin(); i != ql.end(); ++i) {
+	auto ql = fileQueue.find(tth);
+	StringList sl;
+	for(auto i = ql.begin(); i != ql.end(); ++i) {
 		sl.push_back((*i)->getTarget());
 	}
+	return sl;
 }
 
 void QueueManager::addListener(QueueManagerListener* ql, const function<void (const QueueItem::StringMap&)>& currentQueue) {
@@ -1429,7 +1428,7 @@
 		f.write(LIT("<Downloads Version=\"" VERSIONSTRING "\">\r\n"));
 		string tmp;
 		string b32tmp;
-		for(QueueItem::StringIter i = fileQueue.getQueue().begin(); i != fileQueue.getQueue().end(); ++i) {
+		for(auto i = fileQueue.getQueue().begin(); i != fileQueue.getQueue().end(); ++i) {
 			QueueItem* qi = i->second;
 			if(!qi->isSet(QueueItem::FLAG_USER_LIST)) {
 				f.write(LIT("\t<Download Target=\""));
@@ -1641,11 +1640,9 @@
 
 	{
 		Lock l(cs);
-		QueueItem::List matches;
-
-		fileQueue.find(matches, sr->getTTH());
-
-		for(QueueItem::Iter i = matches.begin(); i != matches.end(); ++i) {
+		auto matches = fileQueue.find(sr->getTTH());
+
+		for(auto i = matches.begin(); i != matches.end(); ++i) {
 			QueueItem* qi = *i;
 
 			// Size compare to avoid popular spoof
@@ -1681,9 +1678,9 @@
 	{
 		Lock l(cs);
 		for(int i = 0; i < QueueItem::LAST; ++i) {
-			QueueItem::UserListIter j = userQueue.getList(i).find(aUser);
+			auto j = userQueue.getList(i).find(aUser);
 			if(j != userQueue.getList(i).end()) {
-				for(QueueItem::Iter m = j->second.begin(); m != j->second.end(); ++m)
+				for(auto m = j->second.begin(); m != j->second.end(); ++m)
 					fire(QueueManagerListener::StatusUpdated(), *m);
 				if(i != QueueItem::PAUSED)
 					hasDown = true;
@@ -1700,9 +1697,9 @@
 void QueueManager::on(ClientManagerListener::UserDisconnected, const UserPtr& aUser) noexcept {
 	Lock l(cs);
 	for(int i = 0; i < QueueItem::LAST; ++i) {
-		QueueItem::UserListIter j = userQueue.getList(i).find(aUser);
+		auto j = userQueue.getList(i).find(aUser);
 		if(j != userQueue.getList(i).end()) {
-			for(QueueItem::Iter m = j->second.begin(); m != j->second.end(); ++m)
+			for(auto m = j->second.begin(); m != j->second.end(); ++m)
 				fire(QueueManagerListener::StatusUpdated(), *m);
 		}
 	}
@@ -1777,8 +1774,8 @@
 	{
 		auto lock = FinishedManager::getInstance()->lockLists();
 
-		const FinishedManager::MapByFile& map = FinishedManager::getInstance()->getMapByFile(false);
-		FinishedManager::MapByFile::const_iterator it = map.find(qi->getTarget());
+		auto& map = FinishedManager::getInstance()->getMapByFile(false);
+		auto it = map.find(qi->getTarget());
 		if(it != map.end()) {
 			auto entry = it->second;
 			if (!entry->getUsers().empty()) {

=== modified file 'dcpp/QueueManager.h'
--- dcpp/QueueManager.h	2011-04-13 19:16:51 +0000
+++ dcpp/QueueManager.h	2011-04-24 11:27:49 +0000
@@ -36,12 +36,15 @@
 #include "QueueManagerListener.h"
 #include "SearchManagerListener.h"
 #include "ClientManagerListener.h"
+#include "BundleItem.h"
 
 namespace dcpp {
 
 using std::function;
+using std::list;
 using std::pair;
 using std::unordered_multimap;
+using std::unordered_map;
 
 STANDARD_EXCEPTION(QueueException);
 
@@ -79,9 +82,13 @@
 	private SearchManagerListener, private ClientManagerListener
 {
 public:
+	typedef list<QueueItemPtr> QueueItemList;
+
 	/** Add a file to the queue. */
 	void add(const string& aTarget, int64_t aSize, const TTHValue& root, const HintedUser& aUser,
-		int aFlags = 0, bool addBad = true);
+		int aFlags = 0, bool addBad = true, const BundlePtr &bundle = BundlePtr());
+	void add(const string& aRoot, const BundlePtr& bundle, const HintedUser& aUser, int aFlags = 0);
+
 	/** Add a user's filelist to the queue. */
 	void addList(const HintedUser& HintedUser, int aFlags, const string& aInitialDir = Util::emptyString);
 	/** Readd a source that was removed */
@@ -108,7 +115,7 @@
 
 	void setPriority(const string& aTarget, QueueItem::Priority p) noexcept;
 
-	void getTargets(const TTHValue& tth, StringList& sl);
+	StringList getTargets(const TTHValue& tth);
 
 	using Speaker<QueueManagerListener>::addListener;
 	void addListener(QueueManagerListener* l, const function<void(const QueueItem::StringMap&)>& currentQueue);
@@ -176,17 +183,13 @@
 	class FileQueue {
 	public:
 		FileQueue() : lastInsert(queue.end()) { }
-		~FileQueue() {
-			for(QueueItem::StringIter i = queue.begin(); i != queue.end(); ++i)
-				delete i->second;
-		}
+		~FileQueue();
 		void add(QueueItem* qi);
 		QueueItem* add(const string& aTarget, int64_t aSize, int aFlags, QueueItem::Priority p,
 			const string& aTempTarget, time_t aAdded, const TTHValue& root);
 
 		QueueItem* find(const string& target);
-		void find(QueueItem::List& sl, int64_t aSize, const string& ext);
-		void find(QueueItem::List& ql, const TTHValue& tth);
+		QueueItemList find(const TTHValue& tth);
 
 		QueueItem* findAutoSearch(StringList& recent);
 		size_t getSize() { return queue.size(); }
@@ -196,7 +199,7 @@
 	private:
 		QueueItem::StringMap queue;
 		/** A hint where to insert an item... */
-		QueueItem::StringIter lastInsert;
+		QueueItem::StringMap::iterator lastInsert;
 	};
 
 	/** All queue items indexed by user (this is a cache for the FileQueue really...) */
@@ -208,21 +211,21 @@
 		QueueItem* getRunning(const UserPtr& aUser);
 		void addDownload(QueueItem* qi, Download* d);
 		void removeDownload(QueueItem* qi, const UserPtr& d);
-		QueueItem::UserListMap& getList(int p) { return userQueue[p]; }
 		void remove(QueueItem* qi, bool removeRunning = true);
 		void remove(QueueItem* qi, const UserPtr& aUser, bool removeRunning = true);
 		void setPriority(QueueItem* qi, QueueItem::Priority p);
 
-		QueueItem::UserMap& getRunning() { return running; }
+		unordered_map<UserPtr, QueueItemList, User::Hash> getList(size_t i) { return userQueue[i]; }
 		bool isRunning(const UserPtr& aUser) const {
 			return (running.find(aUser) != running.end());
 		}
+
 		pair<size_t, int64_t> getQueued(const UserPtr& aUser) const;
 	private:
 		/** QueueItems by priority and user (this is where the download order is determined) */
-		QueueItem::UserListMap userQueue[QueueItem::LAST];
+		unordered_map<UserPtr, QueueItemList, User::Hash> userQueue[QueueItem::LAST];
 		/** Currently running downloads, a QueueItem is always either here or in the userQueue */
-		QueueItem::UserMap running;
+		unordered_map<UserPtr, QueueItemPtr, User::Hash> running;
 	};
 
 	friend class QueueLoader;
@@ -233,6 +236,8 @@
 
 	mutable CriticalSection cs;
 
+	/** Bundles queued for download */
+	map<TTHValue, BundleItem> bundles;
 	/** QueueItems by target */
 	FileQueue fileQueue;
 	/** QueueItems by user */

=== added file 'dcpp/SHA1Hash.h'
--- dcpp/SHA1Hash.h	1970-01-01 00:00:00 +0000
+++ dcpp/SHA1Hash.h	2011-04-24 11:27:49 +0000
@@ -0,0 +1,42 @@
+/*
+ * SHA1Hash.h
+ *
+ *  Created on: 23 apr 2011
+ *      Author: arnetheduck
+ */
+
+#ifndef DCPLUSPLUS_DCPP_SHA1HASH_H_
+#define DCPLUSPLUS_DCPP_SHA1HASH_H_
+
+#include <openssl/sha.h>
+
+#include "HashValue.h"
+
+namespace dcpp {
+
+class SHA1Hash {
+public:
+	/** Hash size in bytes */
+	static const size_t BITS = 160;
+	static const size_t BYTES = BITS / 8;
+
+	SHA1Hash() { SHA1_Init(&ctx); }
+
+	~SHA1Hash() { }
+
+	/** Calculates the Tiger hash of the data. */
+	void update(const void* data, size_t len) { SHA1_Update(&ctx, data, len); }
+	/** Call once all data has been processed. */
+	uint8_t* finalize() { SHA1_Final(reinterpret_cast<unsigned char*>(&res), &ctx); return res; }
+
+	uint8_t* getResult() { return res; }
+private:
+	SHA_CTX ctx;
+	uint8_t res[BYTES];
+};
+
+typedef HashValue<SHA1Hash> SHA1Value;
+
+} // namespace dcpp
+
+#endif /* DCPLUSPLUS_DCPP_SHA1HASH_H_ */

=== added file 'dcpp/SimpleBencodeReader.cpp'
--- dcpp/SimpleBencodeReader.cpp	1970-01-01 00:00:00 +0000
+++ dcpp/SimpleBencodeReader.cpp	2011-04-24 11:27:49 +0000
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2001-2011 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 "SimpleBencodeReader.h"
+
+#include "Exception.h"
+
+namespace dcpp {
+
+int64_t SimpleBencodeReader::readInt(const char **data)
+{
+	char *endp = 0;
+	auto ret = strtoll(*data, &endp, 10);
+	*data = endp;
+	return ret;
+}
+
+string SimpleBencodeReader::readString(const char **data, const char *end)
+{
+	auto len = readInt(data);
+	if(len < 0 || *data + len + 1 > end) {
+		throw Exception("String too large");
+	}
+
+	if(**data != ':') {
+		throw Exception("Expected :");
+	}
+
+	auto start = *data + 1;
+	*data += len + 1;
+	return string(start, start + len);
+}
+
+void SimpleBencodeReader::decode(const char **data, const char *end) {
+	if (**data == 'l') {
+		cb.startList();
+		++(*data);
+		while (**data != 'e') {
+			decode(data, end);
+		}
+
+		++(*data);
+		cb.endList();
+		return;
+	} else if (**data == 'd') {
+		++(*data);
+		while (**data != 'e') {
+			cb.startDictEntry(readString(data, end));
+			decode(data, end);
+			cb.endDictEntry();
+		}
+		++(*data);
+
+		return;
+	} else if (**data == 'd') {
+		++(*data);
+		cb.intValue(readInt(data));
+
+		if (**data != 'e')
+			throw Exception("Expected 'e'");
+
+		++(*data);
+
+		return;
+	} else if (**data >= '0' && **data <= '9') {
+		cb.stringValue(readString(data, end));
+		return;
+	} else {
+		throw Exception("Unexpected token");
+	}
+}
+
+void SimpleBencodeReader::parse(const string &data) {
+	auto c = data.c_str();
+	decode(&c, c + data.size());
+}
+
+}

=== added file 'dcpp/SimpleBencodeReader.h'
--- dcpp/SimpleBencodeReader.h	1970-01-01 00:00:00 +0000
+++ dcpp/SimpleBencodeReader.h	2011-04-24 11:27:49 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2001-2011 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.
+ */
+
+#ifndef DCPLUSPLUS_DCPP_SIMPLEBENCODEREADER_H_
+#define DCPLUSPLUS_DCPP_SIMPLEBENCODEREADER_H_
+
+#include <string>
+
+namespace dcpp {
+
+using std::string;
+
+class SimpleBencodeReader {
+public:
+	struct Callback : boost::noncopyable {
+		virtual void intValue(int64_t) { }
+		virtual void stringValue(string) { }
+
+		virtual void startList() { }
+		virtual void endList() { }
+
+		virtual void startDictEntry(string) { }
+		virtual void endDictEntry() { }
+	};
+
+	SimpleBencodeReader(Callback &cb) : cb(cb) { }
+
+	void parse(const string& data);
+private:
+	static int64_t readInt(const char **data);
+	static string readString(const char **data, const char *end);
+
+	void decode(const char **data, const char *end);
+
+	Callback &cb;
+};
+
+}
+
+#endif /* DCPLUSPLUS_DCPP_SIMPLEBENCODEREADER_H_ */

=== modified file 'dcpp/Util.cpp'
--- dcpp/Util.cpp	2011-04-15 20:53:17 +0000
+++ dcpp/Util.cpp	2011-04-24 11:27:49 +0000
@@ -33,7 +33,6 @@
 #include "LogManager.h"
 #include "SettingsManager.h"
 #include "SimpleXML.h"
-#include "StringTokenizer.h"
 #include "version.h"
 
 #ifndef _WIN32

=== modified file 'dcpp/forward.h'
--- dcpp/forward.h	2011-04-13 19:16:51 +0000
+++ dcpp/forward.h	2011-04-24 11:27:49 +0000
@@ -31,6 +31,9 @@
 
 class BufferedSocket;
 
+class Bundle;
+typedef boost::intrusive_ptr<Bundle> BundlePtr;
+
 struct ChatMessage;
 
 class CID;
@@ -80,6 +83,7 @@
 class OutputStream;
 
 class QueueItem;
+typedef QueueItem* QueueItemPtr;
 
 class SearchResult;
 typedef boost::intrusive_ptr<SearchResult> SearchResultPtr;

=== modified file 'win32/DirectoryListingFrame.cpp'
--- win32/DirectoryListingFrame.cpp	2011-04-15 21:51:55 +0000
+++ win32/DirectoryListingFrame.cpp	2011-04-24 11:27:49 +0000
@@ -577,7 +577,7 @@
 	targets.clear();
 
 	if(ii && ii->type == ItemInfo::FILE) {
-		QueueManager::getInstance()->getTargets(ii->file->getTTH(), targets);
+		targets = QueueManager::getInstance()->getTargets(ii->file->getTTH());
 		if(!targets.empty()) {
 			menu->appendSeparator();
 			for(i = 0; i < targets.size(); ++i) {

=== modified file 'win32/SearchFrame.cpp'
--- win32/SearchFrame.cpp	2011-04-13 19:16:51 +0000
+++ win32/SearchFrame.cpp	2011-04-24 11:27:49 +0000
@@ -758,9 +758,7 @@
 	}
 
 	if(checkTTH.hasTTH) {
-		targets.clear();
-
-		QueueManager::getInstance()->getTargets(checkTTH.tth, targets);
+		targets = QueueManager::getInstance()->getTargets(checkTTH.tth);
 		if(targets.size() > 0) {
 			menu->appendSeparator();
 			for(StringIter i = targets.begin(); i != targets.end(); ++i, ++n)

=== modified file 'win32/UsersFrame.cpp'
--- win32/UsersFrame.cpp	2011-04-23 10:33:55 +0000
+++ win32/UsersFrame.cpp	2011-04-24 11:27:49 +0000
@@ -103,7 +103,6 @@
 
 	showOnline = filterGrid->addChild(WinUtil::Seeds::checkBox);
 	showOnline->setText(_T("Online"));
-	showOnline->setChecked(); // TODO save / restore last state
 	showOnline->onClicked(updated);
 
 	showFavs = filterGrid->addChild(WinUtil::Seeds::checkBox);
@@ -482,24 +481,32 @@
 	return show(ui.getUser(), false);
 }
 
+static bool isFav(const UserPtr &u) { return FavoriteManager::getInstance()->isFavoriteUser(u); }
+static bool isWaiting(const UserPtr &u) { return UploadManager::getInstance()->isWaiting(u); }
+static bool hasDownload(const UserPtr &u) { return QueueManager::getInstance()->getQueued(u).first > 0; }
+
 bool UsersFrame::show(const UserPtr &u, bool any) const {
-	if((any || showOnline->getChecked()) && u->isOnline()) {
-		return true;
-	}
-
-	if((any || showFavs->getChecked()) && FavoriteManager::getInstance()->isFavoriteUser(u)) {
-		return true;
-	}
-
-	if((any || showWaiting->getChecked()) && UploadManager::getInstance()->isWaiting(u)) {
-		return true;
-	}
-
-	if((any || showQueue->getChecked()) && QueueManager::getInstance()->getQueued(u).first > 0) {
-		return true;
-	}
-
-	return false;
+	if(any && (u->isOnline() || isFav(u) || isWaiting(u) || hasDownload(u))) {
+		return true;
+	}
+
+	if(showOnline->getChecked() && !u->isOnline()) {
+		return false;
+	}
+
+	if(showFavs->getChecked() && !isFav(u)) {
+		return false;
+	}
+
+	if(showWaiting->getChecked() && isWaiting(u)) {
+		return false;
+	}
+
+	if(showQueue->getChecked() && hasDownload(u)) {
+		return false;
+	}
+
+	return true;
 }
 
 UsersFrame::UserInfoList UsersFrame::selectedUsersImpl() const {