← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 2774: Refactor queue manager a bit

 

------------------------------------------------------------
revno: 2774
committer: Jacek Sieka <arnetheduck@xxxxxxxxx>
branch nick: dcplusplus
timestamp: Thu 2011-12-29 20:05:08 +0100
message:
  Refactor queue manager a bit
modified:
  dcpp/Download.cpp
  dcpp/Download.h
  dcpp/DownloadManager.cpp
  dcpp/FinishedManager.cpp
  dcpp/FinishedManager.h
  dcpp/QueueManager.cpp
  dcpp/QueueManager.h
  dcpp/Transfer.cpp
  dcpp/Transfer.h
  dcpp/UserConnection.h


--
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
=== modified file 'dcpp/Download.cpp'
--- dcpp/Download.cpp	2011-12-23 21:15:27 +0000
+++ dcpp/Download.cpp	2011-12-29 19:05:08 +0000
@@ -23,11 +23,16 @@
 #include "QueueItem.h"
 #include "HashManager.h"
 #include "SettingsManager.h"
+#include "MerkleCheckOutputStream.h"
+#include "MerkleTreeOutputStream.h"
+#include "File.h"
+#include "FilteredFile.h"
+#include "ZUtils.h"
 
 namespace dcpp {
 
-Download::Download(UserConnection& conn, QueueItem& qi, const string& path, bool supportsTrees) noexcept : Transfer(conn, path, qi.getTTH()),
-	tempTarget(qi.getTempTarget()), file(0), treeValid(false)
+Download::Download(UserConnection& conn, QueueItem& qi) noexcept : Transfer(conn, qi.getTarget(), qi.getTTH()),
+	tempTarget(qi.getTempTarget()), treeValid(false)
 {
 	conn.setDownload(this);
 
@@ -38,17 +43,17 @@
 	}
 
 	if(qi.getSize() != -1) {
-		if(HashManager::getInstance()->getTree(getTTH(), getTigerTree())) {
+		if(HashManager::getInstance()->getTree(getTTH(), tt)) {
 			setTreeValid(true);
 			setSegment(qi.getNextSegment(getTigerTree().getBlockSize(), conn.getChunkSize()));
-		} else if(supportsTrees && !qi.getSource(conn.getUser())->isSet(QueueItem::Source::FLAG_NO_TREE) && qi.getSize() > HashManager::MIN_BLOCK_SIZE) {
+		} else if(conn.supportsTrees() && !qi.getSource(conn.getUser())->isSet(QueueItem::Source::FLAG_NO_TREE) && qi.getSize() > HashManager::MIN_BLOCK_SIZE) {
 			// Get the tree unless the file is small (for small files, we'd probably only get the root anyway)
 			setType(TYPE_TREE);
-			getTigerTree().setFileSize(qi.getSize());
+			tt.setFileSize(qi.getSize());
 			setSegment(Segment(0, -1));
 		} else {
 			// Use the root as tree to get some sort of validation at least...
-			getTigerTree() = TigerTree(qi.getSize(), qi.getSize(), getTTH());
+			tt = TigerTree(qi.getSize(), qi.getSize(), getTTH());
 			setTreeValid(true);
 			setSegment(qi.getNextSegment(getTigerTree().getBlockSize(), 0));
 		}
@@ -91,8 +96,78 @@
 	params["target"] = getPath();
 }
 
-string Download::getTargetFileName() {
+string Download::getTargetFileName() const {
 	return Util::getFileName(getPath());
 }
 
+const string& Download::getDownloadTarget() const {
+	return (getTempTarget().empty() ? getPath() : getTempTarget());
+}
+
+void Download::open(int64_t bytes, bool z) {
+	if(getType() == Transfer::TYPE_FILE) {
+		auto target = getDownloadTarget();
+		auto fullSize = tt.getFileSize();
+
+		if(getSegment().getStart() > 0) {
+			if(File::getSize(target) != fullSize) {
+				// When trying the download the next time, the resume pos will be reset
+				throw Exception(_("Target file is missing or wrong size"));
+			}
+		} else {
+			File::ensureDirectory(target);
+		}
+
+		unique_ptr<File> f(new File(target, File::WRITE, File::OPEN | File::CREATE | File::SHARED));
+
+		if(f->getSize() != fullSize) {
+			f->setSize(fullSize);
+		}
+
+		f->setPos(getSegment().getStart());
+		output = move(f);
+		tempTarget = target;
+	} else if(getType() == Transfer::TYPE_FULL_LIST) {
+		auto target = getPath();
+		File::ensureDirectory(target);
+
+		if(isSet(Download::FLAG_XML_BZ_LIST)) {
+			target += ".xml.bz2";
+		} else {
+			target += ".xml";
+		}
+
+		output.reset(new File(target, File::WRITE, File::OPEN | File::TRUNCATE | File::CREATE));
+		tempTarget = target;
+	} else if(getType() == Transfer::TYPE_PARTIAL_LIST) {
+		output.reset(new StringOutputStream(pfs));
+	} else if(getType() == Transfer::TYPE_TREE) {
+		output.reset(new MerkleTreeOutputStream<TigerTree>(tt));
+	}
+
+	if((getType() == Transfer::TYPE_FILE || getType() == Transfer::TYPE_FULL_LIST) && SETTING(BUFFER_SIZE) > 0 ) {
+		output.reset(new BufferedOutputStream<true>(output.release()));
+	}
+
+	if(getType() == Transfer::TYPE_FILE) {
+		typedef MerkleCheckOutputStream<TigerTree, true> MerkleStream;
+
+		output.reset(new MerkleStream(tt, output.release(), getStartPos()));
+		setFlag(Download::FLAG_TTH_CHECK);
+	}
+
+	// Check that we don't get too many bytes
+	output.reset(new LimitedOutputStream<true>(output.release(), bytes));
+
+	if(z) {
+		setFlag(Download::FLAG_ZDOWNLOAD);
+		output.reset(new FilteredOutputStream<UnZFilter, true>(output.release()));
+	}
+}
+
+void Download::close()
+{
+	output.reset();
+}
+
 } // namespace dcpp

=== modified file 'dcpp/Download.h'
--- dcpp/Download.h	2011-12-25 17:31:16 +0000
+++ dcpp/Download.h	2011-12-29 19:05:08 +0000
@@ -2,6 +2,7 @@
 #define DCPLUSPLUS_DCPP_DOWNLOAD_H_
 
 #include <string>
+#include <memory>
 
 #include "forward.h"
 #include "noexcept.h"
@@ -13,12 +14,14 @@
 namespace dcpp {
 
 using std::string;
+using std::unique_ptr;
 
 /**
  * Comes as an argument in the DownloadManagerListener functions.
  * Use it to retrieve information about the ongoing transfer.
  */
-class Download : public Transfer, public Flags {
+class Download : public Transfer, public Flags, boost::noncopyable
+{
 public:
 	enum {
 		FLAG_ZDOWNLOAD = 1 << 1,
@@ -27,32 +30,35 @@
 		FLAG_XML_BZ_LIST = 1 << 4
 	};
 
-	Download(UserConnection& conn, QueueItem& qi, const string& path, bool supportsTrees) noexcept;
+	Download(UserConnection& conn, QueueItem& qi) noexcept;
 
 	virtual void getParams(const UserConnection& aSource, ParamMap& params);
 
 	virtual ~Download();
 
 	/** @return Target filename without path. */
-	string getTargetFileName();
-	/** @internal */
-	const string& getDownloadTarget() {
-		return (getTempTarget().empty() ? getPath() : getTempTarget());
-	}
+	string getTargetFileName() const;
+
+	/** Open the target output for writing */
+	void open(int64_t bytes, bool z);
+
+	/** Release the target output */
+	void close();
 
 	/** @internal */
 	TigerTree& getTigerTree() { return tt; }
-	string& getPFS() { return pfs; }
+	const string& getPFS() const { return pfs; }
 	/** @internal */
 	AdcCommand getCommand(bool zlib);
 
+	const unique_ptr<OutputStream>& getOutput() const { return output; }
+
 	GETSET(string, tempTarget, TempTarget);
-	GETSET(OutputStream*, file, File);
 	GETSET(bool, treeValid, TreeValid);
 private:
-	Download(const Download&);
-	Download& operator=(const Download&);
+	const string& getDownloadTarget() const;
 
+	unique_ptr<OutputStream> output;
 	TigerTree tt;
 	string pfs;
 };

=== modified file 'dcpp/DownloadManager.cpp'
--- dcpp/DownloadManager.cpp	2011-12-23 14:58:25 +0000
+++ dcpp/DownloadManager.cpp	2011-12-29 19:05:08 +0000
@@ -23,11 +23,7 @@
 #include "Download.h"
 #include "LogManager.h"
 #include "User.h"
-#include "File.h"
-#include "FilteredFile.h"
-#include "MerkleCheckOutputStream.h"
 #include "UserConnection.h"
-#include "ZUtils.h"
 
 #include <limits>
 #include <cmath>
@@ -163,7 +159,7 @@
 		return;
 	}
 
-	Download* d = QueueManager::getInstance()->getDownload(*aConn, aConn->isSet(UserConnection::FLAG_SUPPORTS_TTHL));
+	Download* d = QueueManager::getInstance()->getDownload(*aConn);
 
 	if(!d) {
 		Lock l(cs);
@@ -227,7 +223,7 @@
 	}
 
 	try {
-		QueueManager::getInstance()->setFile(d);
+		d->open(bytes, z);
 	} catch(const FileException& e) {
 		failDownload(aSource, str(F_("Could not open target file: %1%") % e.getError()));
 		return;
@@ -236,25 +232,6 @@
 		return;
 	}
 
-	if((d->getType() == Transfer::TYPE_FILE || d->getType() == Transfer::TYPE_FULL_LIST) && SETTING(BUFFER_SIZE) > 0 ) {
-		d->setFile(new BufferedOutputStream<true>(d->getFile()));
-	}
-
-	if(d->getType() == Transfer::TYPE_FILE) {
-		typedef MerkleCheckOutputStream<TigerTree, true> MerkleStream;
-
-		d->setFile(new MerkleStream(d->getTigerTree(), d->getFile(), d->getStartPos()));
-		d->setFlag(Download::FLAG_TTH_CHECK);
-	}
-
-	// Check that we don't get too many bytes
-	d->setFile(new LimitedOutputStream<true>(d->getFile(), bytes));
-
-	if(z) {
-		d->setFlag(Download::FLAG_ZDOWNLOAD);
-		d->setFile(new FilteredOutputStream<UnZFilter, true>(d->getFile()));
-	}
-
 	d->setStart(GET_TICK());
 	d->tick();
 	aSource->setState(UserConnection::STATE_RUNNING);
@@ -278,10 +255,10 @@
 	dcassert(d != NULL);
 
 	try {
-		d->addPos(d->getFile()->write(aData, aLen), aLen);
+		d->addPos(d->getOutput()->write(aData, aLen), aLen);
 		d->tick();
 
-		if(d->getFile()->eof()) {
+		if(d->getOutput()->eof()) {
 			endData(aSource);
 			aSource->setLineMode(0);
 		}
@@ -297,7 +274,7 @@
 	dcassert(d != NULL);
 
 	if(d->getType() == Transfer::TYPE_TREE) {
-		d->getFile()->flush();
+		d->getOutput()->flush();
 
 		int64_t bl = 1024;
 		while(bl * (int64_t)d->getTigerTree().getLeaves().size() < d->getTigerTree().getFileSize())
@@ -321,7 +298,7 @@
 	} else {
 		// First, finish writing the file (flushing the buffers and closing the file...)
 		try {
-			d->getFile()->flush();
+			d->getOutput()->flush();
 		} catch(const Exception& e) {
 			d->resetPos();
 			failDownload(aSource, e.getError());
@@ -405,10 +382,10 @@
 }
 
 void DownloadManager::removeDownload(Download* d) {
-	if(d->getFile()) {
+	if(d->getOutput()) {
 		if(d->getActual() > 0) {
 			try {
-				d->getFile()->flush();
+				d->getOutput()->flush();
 			} catch(const Exception&) {
 			}
 		}

=== modified file 'dcpp/FinishedManager.cpp'
--- dcpp/FinishedManager.cpp	2011-12-28 18:37:58 +0000
+++ dcpp/FinishedManager.cpp	2011-12-29 19:05:08 +0000
@@ -103,7 +103,7 @@
 	ULByUser.clear();
 }
 
-void FinishedManager::update(const string & target, ParamMap& params) {
+void FinishedManager::getParams(const string & target, ParamMap& params) {
 	Lock l(cs);
 
 	auto it = DLByFile.find(target);

=== modified file 'dcpp/FinishedManager.h'
--- dcpp/FinishedManager.h	2011-12-28 18:37:58 +0000
+++ dcpp/FinishedManager.h	2011-12-29 19:05:08 +0000
@@ -39,7 +39,7 @@
 	typedef unordered_map<string, FinishedFileItemPtr> MapByFile;
 	typedef unordered_map<HintedUser, FinishedUserItemPtr, User::Hash> MapByUser;
 
-	void update(const string& target, ParamMap& params);
+	void getParams(const string& target, ParamMap& params);
 	Lock lock();
 	const MapByFile& getMapByFile(bool upload) const;
 	const MapByUser& getMapByUser(bool upload) const;

=== modified file 'dcpp/QueueManager.cpp'
--- dcpp/QueueManager.cpp	2011-12-28 18:52:30 +0000
+++ dcpp/QueueManager.cpp	2011-12-29 19:05:08 +0000
@@ -893,7 +893,7 @@
 	}
 }
 
-Download* QueueManager::getDownload(UserConnection& aSource, bool supportsTrees) noexcept {
+Download* QueueManager::getDownload(UserConnection& aSource) noexcept {
 	Lock l(cs);
 
 	UserPtr& u = aSource.getUser();
@@ -931,7 +931,7 @@
 		}
 	}
 
-	Download* d = new Download(aSource, *q, q->getTarget(), supportsTrees);
+	Download* d = new Download(aSource, *q);
 
 	userQueue.addDownload(q, d);
 
@@ -940,51 +940,6 @@
 	return d;
 }
 
-void QueueManager::setFile(Download* d) {
-	if(d->getType() == Transfer::TYPE_FILE) {
-		Lock l(cs);
-
-		QueueItem* qi = fileQueue.find(d->getPath());
-		if(!qi) {
-			throw QueueException(_("Target removed"));
-		}
-
-		string target = d->getDownloadTarget();
-
-		if(d->getSegment().getStart() > 0) {
-			if(File::getSize(target) != qi->getSize()) {
-				// When trying the download the next time, the resume pos will be reset
-				throw QueueException(_("Target file is missing or wrong size"));
-			}
-		} else {
-			File::ensureDirectory(target);
-		}
-
-		File* f = new File(target, File::WRITE, File::OPEN | File::CREATE | File::SHARED);
-
-		if(f->getSize() != qi->getSize()) {
-			f->setSize(qi->getSize());
-		}
-
-		f->setPos(d->getSegment().getStart());
-		d->setFile(f);
-	} else if(d->getType() == Transfer::TYPE_FULL_LIST) {
-		string target = d->getPath();
-		File::ensureDirectory(target);
-
-		if(d->isSet(Download::FLAG_XML_BZ_LIST)) {
-			target += ".xml.bz2";
-		} else {
-			target += ".xml";
-		}
-		d->setFile(new File(target, File::WRITE, File::OPEN | File::TRUNCATE | File::CREATE));
-	} else if(d->getType() == Transfer::TYPE_PARTIAL_LIST) {
-		d->setFile(new StringOutputStream(d->getPFS()));
-	} else if(d->getType() == Transfer::TYPE_TREE) {
-		d->setFile(new MerkleTreeOutputStream<TigerTree>(d->getTigerTree()));
-	}
-}
-
 void QueueManager::moveFile(const string& source, const string& target) {
 	File::ensureDirectory(target);
 	if(File::getSize(source) > MOVER_LIMIT) {
@@ -1042,134 +997,129 @@
 void QueueManager::putDownload(Download* aDownload, bool finished) noexcept {
 	HintedUserList getConn;
  	string fl_fname;
-	HintedUser fl_user(UserPtr(), Util::emptyString);
 	int fl_flag = 0;
 
+	// Make sure the download gets killed
+	unique_ptr<Download> d(aDownload);
+	aDownload = nullptr;
+
+	d->close();
+
 	{
 		Lock l(cs);
 
-		delete aDownload->getFile();
-		aDownload->setFile(nullptr);
-
-		if(aDownload->getType() == Transfer::TYPE_PARTIAL_LIST) {
-			QueueItem* q = fileQueue.find(aDownload->getPath());
-			if(q) {
-				if(finished) {
-					fire(QueueManagerListener::PartialList(), aDownload->getHintedUser(), aDownload->getPFS());
-					fire(QueueManagerListener::Removed(), q);
+		QueueItem* q = fileQueue.find(d->getPath());
+		if(!q) {
+			// Target has been removed, clean up the mess
+			auto hasTempTarget = !d->getTempTarget().empty();
+			auto isFullList = d->getType() == Transfer::TYPE_FULL_LIST;
+			auto isFile = d->getType() == Transfer::TYPE_FILE && d->getTempTarget() != d->getPath();
+
+			if(hasTempTarget && (isFullList || isFile)) {
+				File::deleteFile(d->getTempTarget());
+			}
+
+			return;
+		}
+
+		if(!finished) {
+			if(d->getType() == Transfer::TYPE_FULL_LIST && !d->getTempTarget().empty()) {
+				// No use keeping an unfinished file list...
+				File::deleteFile(d->getTempTarget());
+			}
+
+			if(d->getType() != Transfer::TYPE_TREE && q->getDownloadedBytes() == 0) {
+				q->setTempTarget(Util::emptyString);
+			}
+
+			if(d->getType() == Transfer::TYPE_FILE) {
+				// mark partially downloaded chunk, but align it to block size
+				int64_t downloaded = d->getPos();
+				downloaded -= downloaded % d->getTigerTree().getBlockSize();
+
+				if(downloaded > 0) {
+					q->addSegment(Segment(d->getStartPos(), downloaded));
+					setDirty();
+				}
+			}
+
+			if(q->getPriority() != QueueItem::PAUSED) {
+				q->getOnlineUsers(getConn);
+			}
+
+			userQueue.removeDownload(q, d->getUser());
+			fire(QueueManagerListener::StatusUpdated(), q);
+		} else { // Finished
+			if(d->getType() == Transfer::TYPE_PARTIAL_LIST) {
+				userQueue.remove(q);
+				fileQueue.remove(q);
+				fire(QueueManagerListener::PartialList(), d->getHintedUser(), d->getPFS());
+				fire(QueueManagerListener::Removed(), q);
+			} else if(d->getType() == Transfer::TYPE_TREE) {
+				// Got a full tree, now add it to the HashManager
+				dcassert(d->getTreeValid());
+				HashManager::getInstance()->addTree(d->getTigerTree());
+
+				userQueue.removeDownload(q, d->getUser());
+				fire(QueueManagerListener::StatusUpdated(), q);
+			} else if(d->getType() == Transfer::TYPE_FULL_LIST) {
+				if(d->isSet(Download::FLAG_XML_BZ_LIST)) {
+					q->setFlag(QueueItem::FLAG_XML_BZLIST);
+				} else {
+					q->unsetFlag(QueueItem::FLAG_XML_BZLIST);
+				}
+
+				auto dir = q->getTempTarget(); // We cheated and stored the initial display directory here (when opening lists from search)
+				q->addSegment(Segment(0, q->getSize()));
+
+				// Now, let's see if this was a directory download filelist...
+				if( (q->isSet(QueueItem::FLAG_DIRECTORY_DOWNLOAD) && directories.find(d->getUser()) != directories.end()) ||
+					(q->isSet(QueueItem::FLAG_MATCH_QUEUE)) )
+				{
+					fl_fname = q->getListName();
+					fl_flag = (q->isSet(QueueItem::FLAG_DIRECTORY_DOWNLOAD) ? QueueItem::FLAG_DIRECTORY_DOWNLOAD : 0)
+						| (q->isSet(QueueItem::FLAG_MATCH_QUEUE) ? QueueItem::FLAG_MATCH_QUEUE : 0);
+				}
+
+				userQueue.remove(q);
+				fire(QueueManagerListener::Finished(), q, dir, d->getAverageSpeed());
+
+				fileQueue.remove(q);
+				fire(QueueManagerListener::Removed(), q);
+			} else if(d->getType() == Transfer::TYPE_FILE) {
+				q->addSegment(d->getSegment());
+
+				if(q->isFinished()) {
+					auto crcError = BOOLSETTING(SFV_CHECK) && checkSfv(q, d.get());
+
+					// Check if we need to move the file
+					if(!d->getTempTarget().empty() && (Util::stricmp(d->getPath().c_str(), d->getTempTarget().c_str()) != 0) ) {
+						moveFile(d->getTempTarget(), d->getPath());
+					}
+
+					if (BOOLSETTING(LOG_FINISHED_DOWNLOADS)) {
+						logFinishedDownload(q, d.get(), crcError);
+					}
 
 					userQueue.remove(q);
-					fileQueue.remove(q);
-				} else {
-					userQueue.removeDownload(q, aDownload->getUser());
-					fire(QueueManagerListener::StatusUpdated(), q);
-				}
-			}
-		} else {
-			QueueItem* q = fileQueue.find(aDownload->getPath());
-
-			if(q) {
-				if(aDownload->getType() == Transfer::TYPE_FULL_LIST) {
-					if(aDownload->isSet(Download::FLAG_XML_BZ_LIST)) {
-						q->setFlag(QueueItem::FLAG_XML_BZLIST);
-					} else {
-						q->unsetFlag(QueueItem::FLAG_XML_BZLIST);
-					}
-				}
-
-				if(finished) {
-					if(aDownload->getType() == Transfer::TYPE_TREE) {
-						// Got a full tree, now add it to the HashManager
-						dcassert(aDownload->getTreeValid());
-						HashManager::getInstance()->addTree(aDownload->getTigerTree());
-
-						userQueue.removeDownload(q, aDownload->getUser());
+					fire(QueueManagerListener::Finished(), q, Util::emptyString, d->getAverageSpeed());
+
+					if(BOOLSETTING(KEEP_FINISHED_FILES)) {
 						fire(QueueManagerListener::StatusUpdated(), q);
 					} else {
-						// Now, let's see if this was a directory download filelist...
-						if( (q->isSet(QueueItem::FLAG_DIRECTORY_DOWNLOAD) && directories.find(aDownload->getUser()) != directories.end()) ||
-							(q->isSet(QueueItem::FLAG_MATCH_QUEUE)) )
-						{
-							fl_fname = q->getListName();
-							fl_user = aDownload->getHintedUser();
-							fl_flag = (q->isSet(QueueItem::FLAG_DIRECTORY_DOWNLOAD) ? QueueItem::FLAG_DIRECTORY_DOWNLOAD : 0)
-								| (q->isSet(QueueItem::FLAG_MATCH_QUEUE) ? QueueItem::FLAG_MATCH_QUEUE : 0);
-						}
-
-						string dir;
-						bool crcError = false;
-						if(aDownload->getType() == Transfer::TYPE_FULL_LIST) {
-							dir = q->getTempTarget();
-							q->addSegment(Segment(0, q->getSize()));
-						} else if(aDownload->getType() == Transfer::TYPE_FILE) {
-							q->addSegment(aDownload->getSegment());
-
-							if (q->isFinished() && BOOLSETTING(SFV_CHECK)) {
-								crcError = checkSfv(q, aDownload);
-							}
-						}
-
-						if(aDownload->getType() != Transfer::TYPE_FILE || q->isFinished()) {
-							// Check if we need to move the file
-							if( aDownload->getType() == Transfer::TYPE_FILE && !aDownload->getTempTarget().empty() && (Util::stricmp(aDownload->getPath().c_str(), aDownload->getTempTarget().c_str()) != 0) ) {
-								moveFile(aDownload->getTempTarget(), aDownload->getPath());
-							}
-
-							if (BOOLSETTING(LOG_FINISHED_DOWNLOADS) && aDownload->getType() == Transfer::TYPE_FILE) {
-								logFinishedDownload(q, aDownload, crcError);
-							}
-
-							fire(QueueManagerListener::Finished(), q, dir, aDownload->getAverageSpeed());
-
-							userQueue.remove(q);
-
-							if(!BOOLSETTING(KEEP_FINISHED_FILES) || aDownload->getType() == Transfer::TYPE_FULL_LIST) {
-								fire(QueueManagerListener::Removed(), q);
-								fileQueue.remove(q);
-							} else {
-								fire(QueueManagerListener::StatusUpdated(), q);
-							}
-						} else {
-							userQueue.removeDownload(q, aDownload->getUser());
-							fire(QueueManagerListener::StatusUpdated(), q);
-						}
-						setDirty();
+						fileQueue.remove(q);
+						fire(QueueManagerListener::Removed(), q);
 					}
 				} else {
-					if(aDownload->getType() != Transfer::TYPE_TREE) {
-						if(q->getDownloadedBytes() == 0) {
-							q->setTempTarget(Util::emptyString);
-						}
-						if(q->isSet(QueueItem::FLAG_USER_LIST)) {
-							// Blah...no use keeping an unfinished file list...
-							File::deleteFile(q->getListName());
-						}
-						if(aDownload->getType() == Transfer::TYPE_FILE) {
-							// mark partially downloaded chunk, but align it to block size
-							int64_t downloaded = aDownload->getPos();
-							downloaded -= downloaded % aDownload->getTigerTree().getBlockSize();
-
-							if(downloaded > 0) {
-								q->addSegment(Segment(aDownload->getStartPos(), downloaded));
-								setDirty();
-							}
-						}
-					}
-
-					if(q->getPriority() != QueueItem::PAUSED) {
-						q->getOnlineUsers(getConn);
-					}
-
-					userQueue.removeDownload(q, aDownload->getUser());
+					userQueue.removeDownload(q, d->getUser());
 					fire(QueueManagerListener::StatusUpdated(), q);
 				}
-			} else if(aDownload->getType() != Transfer::TYPE_TREE) {
-				if(!aDownload->getTempTarget().empty() && (aDownload->getType() == Transfer::TYPE_FULL_LIST || aDownload->getTempTarget() != aDownload->getPath())) {
-					File::deleteFile(aDownload->getTempTarget());
-				}
+			} else {
+				dcassert(0);
 			}
+
+			setDirty();
 		}
-		delete aDownload;
 	}
 
 	for(auto i = getConn.begin(); i != getConn.end(); ++i) {
@@ -1177,7 +1127,7 @@
 	}
 
 	if(!fl_fname.empty()) {
-		processList(fl_fname, fl_user, fl_flag);
+		processList(fl_fname, d->getHintedUser(), fl_flag);
 	}
 }
 
@@ -1730,7 +1680,7 @@
 	params["fileTR"] = qi->getTTH().toBase32();
 	params["sfv"] = Util::toString(crcError ? 1 : 0);
 
-	FinishedManager::getInstance()->update(qi->getTarget(), params);
+	FinishedManager::getInstance()->getParams(qi->getTarget(), params);
 
 	LOG(LogManager::FINISHED_DOWNLOAD, params);
 }

=== modified file 'dcpp/QueueManager.h'
--- dcpp/QueueManager.h	2011-07-30 08:58:17 +0000
+++ dcpp/QueueManager.h	2011-12-29 19:05:08 +0000
@@ -120,7 +120,7 @@
 	using Speaker<QueueManagerListener>::addListener;
 	void addListener(QueueManagerListener* l, const function<void(const QueueItem::StringMap&)>& currentQueue);
 
-	Download* getDownload(UserConnection& aSource, bool supportsTrees) noexcept;
+	Download* getDownload(UserConnection& aSource) noexcept;
 	void putDownload(Download* aDownload, bool finished) noexcept;
 	void setFile(Download* download);
 

=== modified file 'dcpp/Transfer.cpp'
--- dcpp/Transfer.cpp	2011-10-20 14:14:24 +0000
+++ dcpp/Transfer.cpp	2011-12-29 19:05:08 +0000
@@ -101,7 +101,7 @@
 	return getUserConnection().getUser();
 }
 
-const HintedUser Transfer::getHintedUser() const {
+HintedUser Transfer::getHintedUser() const {
 	return getUserConnection().getHintedUser();
 }
 

=== modified file 'dcpp/Transfer.h'
--- dcpp/Transfer.h	2011-12-23 21:15:27 +0000
+++ dcpp/Transfer.h	2011-12-29 19:05:08 +0000
@@ -82,7 +82,7 @@
 
 	UserPtr getUser();
 	const UserPtr getUser() const;
-	const HintedUser getHintedUser() const;
+	HintedUser getHintedUser() const;
 
 	const string& getPath() const { return path; }
 	const TTHValue& getTTH() const { return tth; }

=== modified file 'dcpp/UserConnection.h'
--- dcpp/UserConnection.h	2011-08-11 13:02:19 +0000
+++ dcpp/UserConnection.h	2011-12-29 19:05:08 +0000
@@ -138,7 +138,7 @@
 
 	const UserPtr& getUser() const { return user; }
 	UserPtr& getUser() { return user; }
-	const HintedUser getHintedUser() const { return HintedUser(user, hubUrl); }
+	HintedUser getHintedUser() const { return HintedUser(user, hubUrl); }
 
 	bool isSecure() const { return socket && socket->isSecure(); }
 	bool isTrusted() const { return socket && socket->isTrusted(); }
@@ -165,6 +165,8 @@
 	int64_t getChunkSize() const { return chunkSize; }
 	void updateChunkSize(int64_t leafSize, int64_t lastChunk, uint64_t ticks);
 
+	bool supportsTrees() const { return isSet(FLAG_SUPPORTS_TTHL); }
+
 	GETSET(string, hubUrl, HubUrl);
 	GETSET(string, token, Token);
 	GETSET(string, encoding, Encoding);