← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 3256: Display HTTP downloads in the transfer list

 

------------------------------------------------------------
revno: 3256
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Fri 2013-04-12 23:10:13 +0200
message:
  Display HTTP downloads in the transfer list
modified:
  changelog.txt
  dcpp/CID.h
  dcpp/ClientManager.cpp
  dcpp/DirectoryListing.cpp
  dcpp/FavoriteManager.cpp
  dcpp/HashValue.h
  dcpp/HttpManager.cpp
  dcpp/HttpManager.h
  dcpp/SettingsManager.cpp
  win32/MainWindow.cpp
  win32/TransferView.cpp
  win32/TransferView.h
  win32/UserInfoBase.cpp
  win32/WinUtil.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
=== modified file 'changelog.txt'
--- changelog.txt	2013-04-09 17:20:25 +0000
+++ changelog.txt	2013-04-12 21:10:13 +0000
@@ -4,6 +4,7 @@
 * [L#249622] Add user commands to transfer menus
 * Add a tab menu command to disconnect a hub (poy)
 * Validate input before trying a TTH search (emtee)
+* Display HTTP downloads in the transfer list (poy)
 
 -- 0.811 2013-03-04 --
 * Fix status bar parts when the window is too small (poy)

=== modified file 'dcpp/CID.h'
--- dcpp/CID.h	2013-01-18 21:28:38 +0000
+++ dcpp/CID.h	2013-04-12 21:10:13 +0000
@@ -50,7 +50,7 @@
 	}
 	const uint8_t* data() const { return cid; }
 
-	bool isZero() const { return find_if(cid, cid+SIZE, [](uint8_t c) { return c != 0; }) == (cid+SIZE); }
+	explicit operator bool() const { return find_if(cid, cid + SIZE, [](uint8_t c) { return c != 0; }) != cid + SIZE; }
 
 	static CID generate();
 

=== modified file 'dcpp/ClientManager.cpp'
--- dcpp/ClientManager.cpp	2013-02-12 19:16:15 +0000
+++ dcpp/ClientManager.cpp	2013-04-12 21:10:13 +0000
@@ -566,7 +566,7 @@
 }
 
 const CID& ClientManager::getMyPID() {
-	if(pid.isZero())
+	if(!pid)
 		pid = CID(SETTING(PRIVATE_ID));
 	return pid;
 }

=== modified file 'dcpp/DirectoryListing.cpp'
--- dcpp/DirectoryListing.cpp	2013-01-18 21:28:38 +0000
+++ dcpp/DirectoryListing.cpp	2013-04-12 21:10:13 +0000
@@ -70,7 +70,7 @@
 		return UserPtr();
 
 	CID cid(name.substr(i + 1));
-	if(cid.isZero())
+	if(!cid)
 		return UserPtr();
 
 	return ClientManager::getInstance()->getUser(cid);

=== modified file 'dcpp/FavoriteManager.cpp'
--- dcpp/FavoriteManager.cpp	2013-04-12 18:24:09 +0000
+++ dcpp/FavoriteManager.cpp	2013-04-12 21:10:13 +0000
@@ -713,6 +713,7 @@
 			Lock l(cs);
 			publicListMatrix[publicListServer].clear();
 		}
+		fire(FavoriteManagerListener::DownloadStarting(), publicListServer);
 		c = HttpManager::getInstance()->download(publicListServer);
 		running = true;
 	}

=== modified file 'dcpp/HashValue.h'
--- dcpp/HashValue.h	2013-01-18 21:28:38 +0000
+++ dcpp/HashValue.h	2013-04-12 21:10:13 +0000
@@ -19,6 +19,8 @@
 #ifndef DCPLUSPLUS_DCPP_HASH_VALUE_H
 #define DCPLUSPLUS_DCPP_HASH_VALUE_H
 
+#include <algorithm>
+
 #include "FastAlloc.h"
 #include "Encoder.h"
 
@@ -29,7 +31,7 @@
 	static const size_t BITS = Hasher::BITS;
 	static const size_t BYTES = Hasher::BYTES;
 
-	HashValue() { }
+	HashValue() { memset(data, 0, BYTES); }
 	explicit HashValue(const uint8_t* aData) { memcpy(data, aData, BYTES); }
 	explicit HashValue(const std::string& base32) { Encoder::fromBase32(base32.c_str(), data, BYTES); }
 
@@ -40,6 +42,8 @@
 	std::string toBase32() const { return Encoder::toBase32(data, BYTES); }
 	std::string& toBase32(std::string& tmp) const { return Encoder::toBase32(data, BYTES, tmp); }
 
+	explicit operator bool() const { return find_if(data, data + BYTES, [](uint8_t c) { return c != 0; }) != data + BYTES; }
+
 	uint8_t data[BYTES];
 };
 

=== modified file 'dcpp/HttpManager.cpp'
--- dcpp/HttpManager.cpp	2013-04-12 18:35:46 +0000
+++ dcpp/HttpManager.cpp	2013-04-12 21:10:13 +0000
@@ -19,6 +19,7 @@
 #include "stdinc.h"
 #include "HttpManager.h"
 
+#include "format.h"
 #include "HttpConnection.h"
 
 namespace dcpp {
@@ -43,6 +44,27 @@
 	return conn;
 }
 
+void HttpManager::disconnect(const string& url) {
+	HttpConnection* c = nullptr;
+
+	{
+		Lock l(cs);
+		conns.erase(std::remove_if(conns.begin(), conns.end(), [&](const Conn& conn) -> bool {
+			if(conn.c->getUrl() == url) {
+				c = conn.c;
+				return true;
+			}
+			return false;
+		}), conns.end());
+	}
+
+	if(c) {
+		fire(HttpManagerListener::Failed(), c, _("Disconnected"));
+		fire(HttpManagerListener::Removed(), c);
+		delete c;
+	}
+}
+
 void HttpManager::shutdown() {
 	Lock l(cs);
 	for(auto& conn: conns) { delete conn.c; }
@@ -86,6 +108,7 @@
 		buf.append(reinterpret_cast<const char*>(data), len);
 	}
 	fire(HttpManagerListener::Updated(), c);
+	printf("size: %d\n", c->getSize());
 }
 
 void HttpManager::on(HttpConnectionListener::Failed, HttpConnection* c, const string& str) noexcept {
@@ -122,14 +145,16 @@
 void HttpManager::on(TimerManagerListener::Minute, uint64_t tick) noexcept {
 	vector<HttpConnection*> removed;
 
-	Lock l(cs);
-	conns.erase(std::remove_if(conns.begin(), conns.end(), [tick, &removed](const Conn& conn) -> bool {
-		if(conn.remove && tick > conn.remove) {
-			removed.push_back(conn.c);
-			return true;
-		}
-		return false;
-	}), conns.end());
+	{
+		Lock l(cs);
+		conns.erase(std::remove_if(conns.begin(), conns.end(), [tick, &removed](const Conn& conn) -> bool {
+			if(conn.remove && tick > conn.remove) {
+				removed.push_back(conn.c);
+				return true;
+			}
+			return false;
+		}), conns.end());
+	}
 
 	for(auto c: removed) {
 		fire(HttpManagerListener::Removed(), c);

=== modified file 'dcpp/HttpManager.h'
--- dcpp/HttpManager.h	2013-04-12 18:35:46 +0000
+++ dcpp/HttpManager.h	2013-04-12 21:10:13 +0000
@@ -44,6 +44,8 @@
 	HttpConnection* download(string url);
 	HttpConnection* download(string url, const StringMap& postData);
 
+	void disconnect(const string& url);
+
 	void shutdown();
 
 private:

=== modified file 'dcpp/SettingsManager.cpp'
--- dcpp/SettingsManager.cpp	2013-03-22 15:34:41 +0000
+++ dcpp/SettingsManager.cpp	2013-04-12 21:10:13 +0000
@@ -446,7 +446,7 @@
 			xml.stepOut();
 		}
 
-		if(SETTING(PRIVATE_ID).length() != 39 || CID(SETTING(PRIVATE_ID)).isZero()) {
+		if(SETTING(PRIVATE_ID).length() != 39 || !CID(SETTING(PRIVATE_ID))) {
 			set(PRIVATE_ID, CID::generate().toBase32());
 		}
 
@@ -537,7 +537,7 @@
 		xml.stepOut();
 
 	} catch(const Exception&) {
-		if(CID(SETTING(PRIVATE_ID)).isZero())
+		if(!CID(SETTING(PRIVATE_ID)))
 			set(PRIVATE_ID, CID::generate().toBase32());
 	}
 }

=== modified file 'win32/MainWindow.cpp'
--- win32/MainWindow.cpp	2013-04-12 18:24:09 +0000
+++ win32/MainWindow.cpp	2013-04-12 21:10:13 +0000
@@ -159,7 +159,7 @@
 
 	layout();
 
-	for(auto conn: conns) { conn = nullptr; }
+	for(auto& conn: conns) { conn = nullptr; }
 
 	HttpManager::getInstance()->addListener(this);
 	LogManager::getInstance()->addListener(this);

=== modified file 'win32/TransferView.cpp'
--- win32/TransferView.cpp	2013-04-09 16:00:38 +0000
+++ win32/TransferView.cpp	2013-04-12 21:10:13 +0000
@@ -24,6 +24,8 @@
 #include <dcpp/Download.h>
 #include <dcpp/DownloadManager.h>
 #include <dcpp/GeoManager.h>
+#include <dcpp/HttpConnection.h>
+#include <dcpp/HttpManager.h>
 #include <dcpp/QueueManager.h>
 #include <dcpp/SettingsManager.h>
 #include <dcpp/Upload.h>
@@ -93,6 +95,7 @@
 	DownloadManager::getInstance()->addListener(this);
 	UploadManager::getInstance()->addListener(this);
 	QueueManager::getInstance()->addListener(this);
+	HttpManager::getInstance()->addListener(this);
 }
 
 TransferView::~TransferView() {
@@ -103,6 +106,7 @@
 	ConnectionManager::getInstance()->removeListener(this);
 	DownloadManager::getInstance()->removeListener(this);
 	UploadManager::getInstance()->removeListener(this);
+	HttpManager::getInstance()->removeListener(this);
 }
 
 TransferView::ItemInfo::ItemInfo() :
@@ -130,7 +134,7 @@
 	auto ca = dynamic_cast<const ConnectionInfo*>(a), cb = dynamic_cast<const ConnectionInfo*>(b);
 	if(ca && cb && ca->status != cb->status) {
 		// sort running conns first.
-		return ca->status == ConnectionInfo::STATUS_RUNNING ? -1 : 1;
+		return ca->status == STATUS_RUNNING ? -1 : 1;
 	}
 
 	switch(col) {
@@ -303,7 +307,7 @@
 			timeleft += conn.timeleft;
 			transferred += conn.transferred;
 		}
-		if(conn.status == ConnectionInfo::STATUS_RUNNING) {
+		if(conn.status == STATUS_RUNNING) {
 			++running;
 			speed += conn.speed;
 		}
@@ -386,6 +390,48 @@
 	}
 }
 
+TransferView::HttpInfo::HttpInfo(const string& url) :
+	TransferInfo(TTHValue(), true, url, Util::emptyString),
+	status(STATUS_WAITING)
+{
+	columns[COLUMN_PATH] = Text::toT(url);
+	auto slash = columns[COLUMN_PATH].rfind('/');
+	columns[COLUMN_FILE] = slash != tstring::npos ? columns[COLUMN_PATH].substr(slash + 1) : columns[COLUMN_PATH];
+
+	columns[COLUMN_STATUS] = T_("Downloading");
+}
+
+void TransferView::HttpInfo::update(const UpdateInfo& ui) {
+	if(ui.updateMask & UpdateInfo::MASK_STATUS) {
+		status = ui.status;
+	}
+
+	if(ui.updateMask & UpdateInfo::MASK_STATUS_STRING) {
+		columns[COLUMN_STATUS] = ui.statusString;
+	}
+
+	if(ui.updateMask & UpdateInfo::MASK_TRANSFERRED) {
+		transferred = ui.transferred;
+		size = ui.size;
+
+		if(transferred > 0) {
+			columns[COLUMN_TRANSFERRED] = str(TF_("%1%") % Text::toT(Util::formatBytes(transferred)));
+		} else {
+			columns[COLUMN_TRANSFERRED].clear();
+		}
+
+		if(size > 0) {
+			columns[COLUMN_SIZE] = Text::toT(Util::formatBytes(size));
+		} else {
+			columns[COLUMN_SIZE].clear();
+		}
+	}
+}
+
+void TransferView::HttpInfo::disconnect() {
+	HttpManager::getInstance()->disconnect(path);
+}
+
 void TransferView::handleDestroy() {
 	SettingsManager::getInstance()->set(SettingsManager::TRANSFERS_ORDER, WinUtil::toString(transfers->getColumnOrder()));
 	SettingsManager::getInstance()->set(SettingsManager::TRANSFERS_WIDTHS, WinUtil::toString(transfers->getColumnWidths()));
@@ -424,7 +470,7 @@
 		set<TransferInfo*> files;
 		for(auto i: sel) {
 			auto& transfer = transfers->getData(i)->transfer();
-			if(!transfer.getText(COLUMN_FILE).empty()) {
+			if(!dynamic_cast<HttpInfo*>(&transfer) && !transfer.getText(COLUMN_FILE).empty()) {
 				files.insert(&transfer);
 			}
 		}
@@ -782,6 +828,47 @@
 	transferItems.remove(transfer);
 }
 
+void TransferView::addHttpConn(const UpdateInfo& ui) {
+	auto item = findHttpItem(ui.path);
+	if(item) {
+		removeHttpItem(*item);
+	}
+
+	httpItems.emplace_back(ui.path);
+	item = &httpItems.back();
+	item->update(ui);
+
+	transfers->insert(item);
+}
+
+void TransferView::updateHttpConn(const UpdateInfo& ui) {
+	auto item = findHttpItem(ui.path);
+	if(item) {
+		item->update(ui);
+	}
+}
+
+void TransferView::removeHttpConn(const UpdateInfo& ui) {
+	auto item = findHttpItem(ui.path);
+	if(item) {
+		removeHttpItem(*item);
+	}
+}
+
+TransferView::HttpInfo* TransferView::findHttpItem(const string& url) {
+	for(auto& item: httpItems) {
+		if(item.path == url) {
+			return &item;
+		}
+	}
+	return nullptr;
+}
+
+void TransferView::removeHttpItem(HttpInfo& item) {
+	transfers->erase(&item);
+	httpItems.remove(item);
+}
+
 TransferView::UserInfoList TransferView::selectedUsersImpl() const {
 	// AspectUserInfo::usersFromTable won't do because not every item represents a user.
 	UserInfoList users;
@@ -814,7 +901,7 @@
 
 void TransferView::on(ConnectionManagerListener::Added, ConnectionQueueItem* aCqi) noexcept {
 	auto ui = new UpdateInfo(aCqi->getUser(), aCqi->getDownload());
-	ui->setStatus(ConnectionInfo::STATUS_WAITING);
+	ui->setStatus(STATUS_WAITING);
 	ui->setStatusString(T_("Connecting"));
 
 	addedConn(ui);
@@ -938,23 +1025,60 @@
 	onFailed(d, aReason);
 }
 
+void TransferView::on(HttpManagerListener::Added, HttpConnection* c) noexcept {
+	auto ui = makeHttpUI(c);
+	ui->setStatus(STATUS_RUNNING);
+	ui->setTransferred(c->getDone(), c->getDone(), c->getSize());
+
+	addedConn(ui);
+}
+
+void TransferView::on(HttpManagerListener::Updated, HttpConnection* c) noexcept {
+	auto ui = makeHttpUI(c);
+	ui->setTransferred(c->getDone(), c->getDone(), c->getSize());
+
+	updatedConn(ui);
+}
+
+void TransferView::on(HttpManagerListener::Failed, HttpConnection* c, const string& str) noexcept {
+	auto ui = makeHttpUI(c);
+	ui->setStatus(STATUS_WAITING);
+	ui->setStatusString(Text::toT(str));
+	ui->setTransferred(c->getDone(), c->getDone(), c->getSize());
+
+	updatedConn(ui);
+}
+
+void TransferView::on(HttpManagerListener::Complete, HttpConnection* c, const string&) noexcept {
+	auto ui = makeHttpUI(c);
+	ui->setStatus(STATUS_WAITING);
+	ui->setStatusString(T_("Idle"));
+	ui->setTransferred(c->getDone(), c->getDone(), c->getSize());
+
+	updatedConn(ui);
+}
+
+void TransferView::on(HttpManagerListener::Removed, HttpConnection* c) noexcept {
+	removedConn(makeHttpUI(c));
+}
+
 void TransferView::addedConn(UpdateInfo* ui) {
 	callAsync([this, ui] {
-		tasks.emplace_back([=](const UpdateInfo& ui) { addConn(ui); }, unique_ptr<UpdateInfo>(ui));
+		tasks.emplace_back([=](const UpdateInfo& ui) { ui.isHttp() ? addHttpConn(ui) : addConn(ui); }, unique_ptr<UpdateInfo>(ui));
 		updateList = true;
 	});
 }
 
 void TransferView::updatedConn(UpdateInfo* ui) {
 	callAsync([this, ui] {
-		tasks.emplace_back([=](const UpdateInfo& ui) { updateConn(ui); }, unique_ptr<UpdateInfo>(ui));
+		tasks.emplace_back([=](const UpdateInfo& ui) { ui.isHttp() ? updateHttpConn(ui) : updateConn(ui); }, unique_ptr<UpdateInfo>(ui));
 		updateList = true;
 	});
 }
 
 void TransferView::removedConn(UpdateInfo* ui) {
 	callAsync([this, ui] {
-		tasks.emplace_back([=](const UpdateInfo& ui) { removeConn(ui); }, unique_ptr<UpdateInfo>(ui));
+		tasks.emplace_back([=](const UpdateInfo& ui) { ui.isHttp() ? removeHttpConn(ui) : removeConn(ui); }, unique_ptr<UpdateInfo>(ui));
 		updateList = true;
 	});
 }
@@ -962,7 +1086,7 @@
 void TransferView::starting(UpdateInfo* ui, Transfer* t) {
 	ui->setTTH(t->getTTH());
 	ui->setFile(t->getPath());
-	ui->setStatus(ConnectionInfo::STATUS_RUNNING);
+	ui->setStatus(STATUS_RUNNING);
 	ui->setTransferred(t->getPos(), t->getActual(), t->getSize());
 	const UserConnection& uc = t->getUserConnection();
 	ui->setCipher(Text::toT(uc.getCipherName()));
@@ -980,7 +1104,7 @@
 void TransferView::onTransferComplete(Transfer* t, bool download) {
 	auto ui = new UpdateInfo(t->getHintedUser(), download);
 	ui->setFile(t->getPath());
-	ui->setStatus(ConnectionInfo::STATUS_WAITING);
+	ui->setStatus(STATUS_WAITING);
 	ui->setStatusString(T_("Idle"));
 	ui->setTransferred(t->getPos(), t->getActual(), t->getSize());
 
@@ -990,8 +1114,15 @@
 void TransferView::onFailed(Download* d, const string& aReason) {
  	auto ui = new UpdateInfo(d->getHintedUser(), true, true);
 	ui->setFile(d->getPath());
-	ui->setStatus(ConnectionInfo::STATUS_WAITING);
+	ui->setStatus(STATUS_WAITING);
 	ui->setStatusString(Text::toT(aReason));
 
 	updatedConn(ui);
 }
+
+TransferView::UpdateInfo* TransferView::makeHttpUI(HttpConnection* c) {
+	auto ui = new UpdateInfo(true);
+	ui->setHttp();
+	ui->setFile(c->getUrl());
+	return ui;
+}

=== modified file 'win32/TransferView.h'
--- win32/TransferView.h	2013-03-31 17:09:29 +0000
+++ win32/TransferView.h	2013-04-12 21:10:13 +0000
@@ -26,6 +26,7 @@
 #include <dcpp/UploadManagerListener.h>
 #include <dcpp/ConnectionManagerListener.h>
 #include <dcpp/QueueManagerListener.h>
+#include <dcpp/HttpManagerListener.h>
 #include <dcpp/forward.h>
 #include <dcpp/MerkleTree.h>
 #include <dcpp/Util.h>
@@ -45,6 +46,7 @@
 	private UploadManagerListener,
 	private ConnectionManagerListener,
 	private QueueManagerListener,
+	private HttpManagerListener,
 	public AspectUserInfo<TransferView>,
 	public AspectUserCommand<TransferView>
 {
@@ -75,6 +77,11 @@
 		COLUMN_LAST
 	};
 
+	enum Status {
+		STATUS_RUNNING,		///< Transferring
+		STATUS_WAITING		///< Idle
+	};
+
 	struct TransferInfo;
 	struct UpdateInfo;
 
@@ -103,11 +110,6 @@
 	};
 
 	struct ConnectionInfo : public ItemInfo, public UserInfoBase {
-		enum Status {
-			STATUS_RUNNING,		///< Transfering
-			STATUS_WAITING		///< Idle
-		};
-
 		ConnectionInfo(const HintedUser& u, TransferInfo& parent);
 
 		bool operator==(const ConnectionInfo& other) const;
@@ -120,8 +122,8 @@
 
 		double barPos() const;
 
-		void force();
-		void disconnect();
+		virtual void force();
+		virtual void disconnect();
 
 		bool transferFailed;
 		Status status;
@@ -142,8 +144,8 @@
 
 		double barPos() const;
 
-		void force();
-		void disconnect();
+		virtual void force();
+		virtual void disconnect();
 
 		TTHValue tth;
 		bool download;
@@ -153,6 +155,16 @@
 		list<ConnectionInfo> conns;
 	};
 
+	struct HttpInfo : public TransferInfo {
+		HttpInfo(const string& url);
+
+		void update(const UpdateInfo& ui);
+
+		virtual void disconnect();
+
+		Status status;
+	};
+
 	struct UpdateInfo {
 		enum {
 			MASK_STATUS = 1 << 0,
@@ -162,11 +174,13 @@
 			MASK_CIPHER = 1 << 4,
 			MASK_IP = 1 << 5,
 			MASK_COUNTRY = 1 << 6,
-			MASK_PATH = 1 << 7
+			MASK_PATH = 1 << 7,
+			MASK_HTTP = 1 << 8
 		};
 
 		UpdateInfo(const HintedUser& user, bool download, bool transferFailed = false) :
 			updateMask(0), user(user), download(download), transferFailed(transferFailed) { }
+		UpdateInfo(bool download) : download(download), transferFailed(false) { }
 
 		uint32_t updateMask;
 
@@ -182,8 +196,8 @@
 		string tempPath;
 		void setTempPath(const string& path) { tempPath = path; }
 
-		void setStatus(ConnectionInfo::Status aStatus) { status = aStatus; updateMask |= MASK_STATUS; }
-		ConnectionInfo::Status status;
+		void setStatus(Status aStatus) { status = aStatus; updateMask |= MASK_STATUS; }
+		Status status;
 		void setTransferred(int64_t aTransferred, int64_t aActual, int64_t aSize) {
 			transferred = aTransferred; actual = aActual; size = aSize; updateMask |= MASK_TRANSFERRED;
 		}
@@ -201,6 +215,9 @@
 		tstring ip;
 		void setCountry(const tstring& aCountry) { country = aCountry; updateMask |= MASK_COUNTRY; }
 		tstring country;
+
+		void setHttp() { updateMask |= MASK_HTTP; }
+		bool isHttp() const { return (updateMask & MASK_HTTP) == MASK_HTTP; }
 	};
 
 	typedef TypedTable<ItemInfo, false, dwt::TableTree> WidgetTransfers;
@@ -209,6 +226,7 @@
 
 	list<TransferInfo> transferItems; /* the LPARAM data of table entries are direct pointers to
 									  objects stored by this container, hence the std::list. */
+	list<HttpInfo> httpItems;
 
 	TabViewPtr mdi;
 
@@ -242,6 +260,13 @@
 	void removeConn(ConnectionInfo& conn);
 	void removeTransfer(TransferInfo& transfer);
 
+	void addHttpConn(const UpdateInfo& ui);
+	void updateHttpConn(const UpdateInfo& ui);
+	void removeHttpConn(const UpdateInfo& ui);
+
+	HttpInfo* findHttpItem(const string& url);
+	void removeHttpItem(HttpInfo& item);
+
 	// AspectUserInfo
 	UserInfoList selectedUsersImpl() const;
 
@@ -264,6 +289,12 @@
 
 	virtual void on(QueueManagerListener::CRCFailed, Download* d, const string& aReason) noexcept;
 
+	virtual void on(HttpManagerListener::Added, HttpConnection*) noexcept;
+	virtual void on(HttpManagerListener::Updated, HttpConnection*) noexcept;
+	virtual void on(HttpManagerListener::Failed, HttpConnection*, const string&) noexcept;
+	virtual void on(HttpManagerListener::Complete, HttpConnection*, const string&) noexcept;
+	virtual void on(HttpManagerListener::Removed, HttpConnection*) noexcept;
+
 	void addedConn(UpdateInfo* ui);
 	void updatedConn(UpdateInfo* ui);
 	void removedConn(UpdateInfo* ui);
@@ -272,6 +303,7 @@
 	void onTransferTick(Transfer* t, bool download);
 	void onTransferComplete(Transfer* t, bool download);
 	void onFailed(Download* aDownload, const string& aReason);
+	UpdateInfo* makeHttpUI(HttpConnection* c);
 };
 
 #endif // !defined(TRANSFER_VIEW_H)

=== modified file 'win32/UserInfoBase.cpp'
--- win32/UserInfoBase.cpp	2013-03-03 20:15:35 +0000
+++ win32/UserInfoBase.cpp	2013-04-12 21:10:13 +0000
@@ -48,7 +48,7 @@
 	}
 }
 void UserInfoBase::browseList() {
-	if(user.user->getCID().isZero())
+	if(!user.user->getCID())
 		return;
 	try {
 		QueueManager::getInstance()->addList(user, QueueItem::FLAG_CLIENT_VIEW | QueueItem::FLAG_PARTIAL_LIST);

=== modified file 'win32/WinUtil.cpp'
--- win32/WinUtil.cpp	2013-03-22 16:30:58 +0000
+++ win32/WinUtil.cpp	2013-04-12 21:10:13 +0000
@@ -764,6 +764,7 @@
 }
 
 void WinUtil::addHashItems(Menu* menu, const TTHValue& tth, const tstring& filename, int64_t size) {
+	if(!tth) { return; }
 	menu->appendItem(T_("Search for alternates"), [=] { searchHash(tth); }, menuIcon(IDI_SEARCH));
 	menu->appendItem(T_("Lookup TTH at Bitzi.com"), [=] { bitziLink(tth); });
 	menu->appendItem(T_("Copy magnet link to clipboard"), [=] { copyMagnet(tth, filename, size); }, menuIcon(IDI_MAGNET));