[springlobby] 01/07: New upstream version 0.256+dfsg

Markus Koschany apo at moszumanska.debian.org
Sat May 6 18:46:08 UTC 2017


This is an automated email from the git hooks/post-receive script.

apo pushed a commit to branch master
in repository springlobby.

commit c31d65a27f39cfa60a7c12ae82c357aca9df6f68
Author: Markus Koschany <apo at debian.org>
Date:   Sat May 6 20:22:21 2017 +0200

    New upstream version 0.256+dfsg
---
 .travis.yml                                        |   1 +
 ChangeLog                                          |   6 +
 VERSION                                            |   2 +-
 springlobby_config.h                               |   2 +-
 src/CMakeLists.txt                                 |   1 +
 src/battle.cpp                                     |  19 +-
 src/downloader/lib/.travis.yml                     |   3 +-
 src/downloader/lib/CMakeLists.txt                  |   2 +-
 src/downloader/lib/src/CMakeLists.txt              |   6 +-
 .../lib/src/Downloader/Http/HttpDownloader.cpp     |   9 +
 .../lib/src/Downloader/Http/HttpDownloader.h       |   2 +-
 src/downloader/lib/src/Downloader/IDownloader.cpp  |  10 +
 src/downloader/lib/src/Downloader/IDownloader.h    |  13 +-
 .../lib/src/Downloader/Rapid/RapidDownloader.cpp   |   3 +-
 .../lib/src/Downloader/Rapid/RapidDownloader.h     |   2 +-
 src/downloader/lib/src/Downloader/Rapid/Repo.cpp   |   2 +-
 src/downloader/lib/src/Downloader/Rapid/Sdp.cpp    | 226 ++++++++++-----------
 src/downloader/lib/src/Downloader/Rapid/Sdp.h      |  22 +-
 src/downloader/lib/src/FileSystem/File.cpp         |   6 +-
 src/downloader/lib/src/FileSystem/FileSystem.cpp   |  95 +++++++--
 src/downloader/lib/src/FileSystem/FileSystem.h     |   9 +-
 src/downloader/lib/src/FileSystem/HashMD5.h        |   2 +-
 src/downloader/lib/src/lib/CMakeLists.txt          |  10 +-
 .../lib/src/lsl/lslunitsync/CMakeLists.txt         |   2 +-
 src/downloader/lib/src/lsl/lslunitsync/c_api.cpp   |   6 +
 src/downloader/lib/src/lsl/lslunitsync/c_api.h     |   1 +
 .../lib/src/lsl/lslunitsync/unitsync.cpp           |  89 ++++----
 src/downloader/lib/src/lsl/lslunitsync/unitsync.h  |   6 +-
 src/downloader/lib/src/main.cpp                    |   6 +
 src/downloader/lib/src/pr-downloader.cpp           |  13 +-
 src/downloader/lib/src/pr-downloader.h             |  12 ++
 src/downloader/lib/test/CMakeLists.txt             |  11 +-
 src/gui/chatpanel.cpp                              |   2 +-
 src/gui/singleplayertab.cpp                        |  14 +-
 src/gui/ui.cpp                                     |  14 --
 src/gui/ui.h                                       |   1 -
 src/ibattle.cpp                                    |  48 +++--
 src/serverevents.cpp                               |   2 +-
 src/socket.cpp                                     |   2 +-
 src/springlobbyapp.cpp                             |   7 +
 src/stacktrace.h                                   |   2 +
 src/sysinfo.cpp                                    |   5 +
 src/tasserver.cpp                                  |  25 ++-
 43 files changed, 451 insertions(+), 270 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 1a3d176..38c1300 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,6 +4,7 @@ compiler:
   - clang
 sudo: required
 dist: trusty
+cache: ccache
 
 install:
   - sudo apt-get install -y libwxgtk3.0-dev libboost-thread1.55-dev libboost-system1.55-dev
diff --git a/ChangeLog b/ChangeLog
index 3148a6c..1e6e152 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 ChangeLog of Springlobby
 
+## 0.256
+ - lazy init of unitsync (faster startup)
+ - fix crash when Scroll wheel over games in single player tab
+ - always validate rapid downloads
+ - don't log private conversations to springlobby.log
+
 ## 0.255
  - fix downloading with special chars in springlobby's data dirs
  - merge lsl into prdownloader submodule
diff --git a/VERSION b/VERSION
index e6ab191..020b4db 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.255
+0.256
diff --git a/springlobby_config.h b/springlobby_config.h
index 136af5a..85b59c4 100644
--- a/springlobby_config.h
+++ b/springlobby_config.h
@@ -6,6 +6,6 @@
 #undef VERSION
 
 /* the git tag / commit we build from */
-#define VERSION "0.255"
+#define VERSION "0.256"
 
 #endif	/* SPRINGLOBBY_HEADERGUARD_CONFIG_H */
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c8933ed..ae57c27 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -376,6 +376,7 @@ target_include_directories(springlobby
 		PRIVATE ${CURL_INCLUDE_DIR}
 		PRIVATE ${Boost_INCLUDE_DIRS}
 		PRIVATE ${springlobby_SOURCE_DIR}/src
+		PRIVATE ${springlobby_SOURCE_DIR}/src/downloader/lib/src
 		PRIVATE ${springlobby_SOURCE_DIR}/src/downloader/lib/src/lsl
 	)
 
diff --git a/src/battle.cpp b/src/battle.cpp
index f1860c4..e758c06 100644
--- a/src/battle.cpp
+++ b/src/battle.cpp
@@ -801,22 +801,6 @@ void shuffle(std::vector<User*>& players) // proper shuffle.
 	}
 }
 
-/*
-bool ClanRemovalFunction(const std::map<wxString, Alliance>::value_type &v){
-  return v.second.players.size()<2;
-}
-*/
-/*
-struct ClannersRemovalPredicate{
-  std::map<wxString, Alliance> &clans;
-  PlayerRemovalPredicate(std::map<wxString, Alliance> &clans_):clans(clans_)
-  {
-  }
-  bool operator()(User *u) const{
-    return clans.find(u->GetClan());
-  }
-}*/
-
 void Battle::Autobalance(BalanceType balance_type, bool support_clans, bool strong_clans, int numallyteams)
 {
 	wxLogMessage(_T("Autobalancing alliances, type=%d, clans=%d, strong_clans=%d, numallyteams=%d"), balance_type, support_clans, strong_clans, numallyteams);
@@ -1108,8 +1092,9 @@ void Battle::FixTeamIDs(BalanceType balance_type, bool support_clans, bool stron
 
 void Battle::OnUnitsyncReloaded(wxEvent& /*data*/)
 {
-	if (m_is_self_in)
+	if (m_is_self_in) {
 		SendMyBattleStatus();
+	}
 }
 
 void Battle::ShouldAutoUnspec()
diff --git a/src/downloader/lib/.travis.yml b/src/downloader/lib/.travis.yml
index 919fa00..4addaa8 100644
--- a/src/downloader/lib/.travis.yml
+++ b/src/downloader/lib/.travis.yml
@@ -5,6 +5,7 @@ compiler:
 
 sudo: required
 dist: trusty
+cache: ccache
 
 install:
   - sudo apt-get install -y gcc-4.7 g++-4.7 cmake libcurl4-openssl-dev libjsoncpp-dev
@@ -16,5 +17,5 @@ before_script:
 script:
   - make -j2
   - sudo make install
-  - src/pr-downloader ba:stable
+  - src/pr-downloader devgame:test
   - src/pr-downloader --rapid-validate
diff --git a/src/downloader/lib/CMakeLists.txt b/src/downloader/lib/CMakeLists.txt
index 25b4e6e..112efc5 100644
--- a/src/downloader/lib/CMakeLists.txt
+++ b/src/downloader/lib/CMakeLists.txt
@@ -132,7 +132,7 @@ if(NOT MINIZIP_FOUND)
 endif()
 
 
-subdirs(src)
+add_subdirectory(src)
 
 
 find_program(CLANG_FORMAT_BINARY NAMES clang-format-3.7 clang-format-3.6 clang-format-3.5 clang-format-3.4 clang-format)
diff --git a/src/downloader/lib/src/CMakeLists.txt b/src/downloader/lib/src/CMakeLists.txt
index f1681bc..29df0a7 100644
--- a/src/downloader/lib/src/CMakeLists.txt
+++ b/src/downloader/lib/src/CMakeLists.txt
@@ -1,4 +1,4 @@
-subdirs(lib)
+add_subdirectory(lib)
 
 if (PRD_ARCHIVE_SUPPORT)
 	set(archivessrc FileSystem/SevenZipArchive.cpp FileSystem/ZipArchive.cpp)
@@ -100,6 +100,7 @@ if (PRD_SHAREDLIB)
 			LIBRARY DESTINATION ${PRD_LIBDIR}
 			ARCHIVE DESTINATION ${PRD_LIBDIR} )
 	endif()
+	target_include_directories(${PRDOWNLOADER_SHARED} PRIVATE ${pr-downloader_SOURCE_DIR}/src)
 	target_link_libraries( ${PRDOWNLOADER_SHARED} ${PRDOWNLOADER_LIBS} )
 endif()
 
@@ -115,6 +116,7 @@ if (PRD_STATICLIB)
 			LIBRARY DESTINATION ${PRD_LIBDIR}
 			ARCHIVE DESTINATION ${PRD_LIBDIR} )
 	endif()
+	target_include_directories(${PRDOWNLOADER_STATIC} PRIVATE ${pr-downloader_SOURCE_DIR}/src)
 	target_link_libraries( ${PRDOWNLOADER_STATIC} ${PRDOWNLOADER_LIBS} ${CMAKE_DL_LIBS})
 endif()
 
@@ -171,5 +173,5 @@ endif()
 
 OPTION(PRD_ENABLE_LSL "compile lsl modules" OFF)
 if (PRD_ENABLE_LSL)
-	subdirs(lsl)
+	add_subdirectory(lsl)
 endif()
diff --git a/src/downloader/lib/src/Downloader/Http/HttpDownloader.cpp b/src/downloader/lib/src/Downloader/Http/HttpDownloader.cpp
index 90fa3d2..19ccc57 100644
--- a/src/downloader/lib/src/Downloader/Http/HttpDownloader.cpp
+++ b/src/downloader/lib/src/Downloader/Http/HttpDownloader.cpp
@@ -37,6 +37,9 @@ CHttpDownloader::~CHttpDownloader()
 static size_t WriteMemoryCallback(void* contents, size_t size, size_t nmemb,
 				  void* userp)
 {
+	if (IDownloader::AbortDownloads())
+		return -1;
+
 	const size_t realsize = size * nmemb;
 	std::string* res = static_cast<std::string*>(userp);
 	res->append((char*)contents, realsize);
@@ -46,6 +49,9 @@ static size_t WriteMemoryCallback(void* contents, size_t size, size_t nmemb,
 static int progress_func(DownloadData* data, double total, double done, double,
 			 double)
 {
+	if (IDownloader::AbortDownloads())
+		return -1;
+
 	data->download->progress = done;
 	if (IDownloader::listener != NULL) {
 		IDownloader::listener(done, total);
@@ -210,6 +216,9 @@ bool CHttpDownloader::search(std::list<IDownload*>& res,
 static size_t multi_write_data(void* ptr, size_t size, size_t nmemb,
 			       DownloadData* data)
 {
+	if (IDownloader::AbortDownloads())
+		return -1;
+
 	// LOG_DEBUG("%d %d",size,  nmemb);
 	if (!data->got_ranges) {
 		LOG_INFO("Server refused ranges"); // The server refused ranges , download
diff --git a/src/downloader/lib/src/Downloader/Http/HttpDownloader.h b/src/downloader/lib/src/Downloader/Http/HttpDownloader.h
index 9fd436b..cd66743 100644
--- a/src/downloader/lib/src/Downloader/Http/HttpDownloader.h
+++ b/src/downloader/lib/src/Downloader/Http/HttpDownloader.h
@@ -3,7 +3,7 @@
 #ifndef HTTP_DOWNLOAD_H
 #define HTTP_DOWNLOAD_H
 
-#include "../IDownloader.h"
+#include "Downloader/IDownloader.h"
 
 #include <curl/curl.h>
 #include <string>
diff --git a/src/downloader/lib/src/Downloader/IDownloader.cpp b/src/downloader/lib/src/Downloader/IDownloader.cpp
index 8109064..3e657fb 100644
--- a/src/downloader/lib/src/Downloader/IDownloader.cpp
+++ b/src/downloader/lib/src/Downloader/IDownloader.cpp
@@ -28,6 +28,16 @@ void IDownloader::Shutdown()
 	rapiddl = NULL;
 	curl_global_cleanup();
 }
+static bool abortDownloads = false;
+void IDownloader::SetAbortDownloads(bool value)
+{
+	abortDownloads = value;
+}
+
+bool IDownloader::AbortDownloads()
+{
+	return abortDownloads;
+}
 
 IDownloader* IDownloader::GetHttpInstance()
 {
diff --git a/src/downloader/lib/src/Downloader/IDownloader.h b/src/downloader/lib/src/Downloader/IDownloader.h
index 6785425..970a69e 100644
--- a/src/downloader/lib/src/Downloader/IDownloader.h
+++ b/src/downloader/lib/src/Downloader/IDownloader.h
@@ -18,17 +18,22 @@ public:
 	static IDownloader* GetRapidInstance();
 
 	/**
-          Initialize all Downloaders
-  */
+	 *Initialize all Downloaders
+	 */
 	static void Initialize();
 
 	/**
-          Shutdown all Downloaders
-  */
+	 * Shutdown all Downloaders
+	 */
 	static void Shutdown();
 	virtual ~IDownloader()
 	{
 	}
+	/**
+	 * Aborts all ongoing downloads
+	 */
+	static void SetAbortDownloads(bool value);
+	static bool AbortDownloads();
 
 	/**
           download specificed download
diff --git a/src/downloader/lib/src/Downloader/Rapid/RapidDownloader.cpp b/src/downloader/lib/src/Downloader/Rapid/RapidDownloader.cpp
index 533d5b3..62ac84b 100644
--- a/src/downloader/lib/src/Downloader/Rapid/RapidDownloader.cpp
+++ b/src/downloader/lib/src/Downloader/Rapid/RapidDownloader.cpp
@@ -32,7 +32,7 @@ CRapidDownloader::~CRapidDownloader()
 	sdps.clear();
 }
 
-void CRapidDownloader::addRemoteDsp(CSdp& sdp)
+void CRapidDownloader::addRemoteSdp(CSdp& sdp)
 {
 	sdps.push_back(sdp);
 }
@@ -195,6 +195,7 @@ bool CRapidDownloader::parse()
 	}
 	gzFile fp = gzdopen(fileno(f), "rb");
 	if (fp == Z_NULL) {
+		fclose(f);
 		LOG_ERROR("Could not open %s", path.c_str());
 		return false;
 	}
diff --git a/src/downloader/lib/src/Downloader/Rapid/RapidDownloader.h b/src/downloader/lib/src/Downloader/Rapid/RapidDownloader.h
index 50eb507..f388a1d 100644
--- a/src/downloader/lib/src/Downloader/Rapid/RapidDownloader.h
+++ b/src/downloader/lib/src/Downloader/Rapid/RapidDownloader.h
@@ -36,7 +36,7 @@ public:
 
 	bool setOption(const std::string& key, const std::string& value) override;
 
-	void addRemoteDsp(CSdp& dsp);
+	void addRemoteSdp(CSdp& dsp);
 	/**
           parses a rep master-file
   */
diff --git a/src/downloader/lib/src/Downloader/Rapid/Repo.cpp b/src/downloader/lib/src/Downloader/Rapid/Repo.cpp
index c7558d3..e1142a2 100644
--- a/src/downloader/lib/src/Downloader/Rapid/Repo.cpp
+++ b/src/downloader/lib/src/Downloader/Rapid/Repo.cpp
@@ -80,7 +80,7 @@ bool CRepo::parse()
 
 		// create new repo from url
 		CSdp sdptmp = CSdp(items[0], items[1], items[3], items[2], repourl);
-		rapid->addRemoteDsp(sdptmp);
+		rapid->addRemoteSdp(sdptmp);
 	}
 	int errnum = Z_OK;
 	const char* errstr = gzerror(fp, &errnum);
diff --git a/src/downloader/lib/src/Downloader/Rapid/Sdp.cpp b/src/downloader/lib/src/Downloader/Rapid/Sdp.cpp
index 8555ac4..7a8f05d 100644
--- a/src/downloader/lib/src/Downloader/Rapid/Sdp.cpp
+++ b/src/downloader/lib/src/Downloader/Rapid/Sdp.cpp
@@ -18,10 +18,9 @@
 
 CSdp::CSdp(const std::string& shortname, const std::string& md5,
 	   const std::string& name, const std::string& depends,
-	   const std::string& url)
+	   const std::string& baseUrl)
     : m_download(NULL)
     , downloadInitialized(false)
-    , globalFiles(NULL)
     , file_handle(NULL)
     , file_pos(0)
     , skipped(false)
@@ -29,11 +28,18 @@ CSdp::CSdp(const std::string& shortname, const std::string& md5,
     , name(name)
     , md5(md5)
     , shortname(shortname)
-    , url(url)
+    , baseUrl(baseUrl)
     , depends(depends)
     , downloaded(false)
 {
-	memset(this->cursize_buf, 0, LENGTH_SIZE);
+	memset(cursize_buf, 0, LENGTH_SIZE);
+	const std::string dir =
+	    fileSystem->getSpringDir() + PATH_DELIMITER + "packages" + PATH_DELIMITER;
+	if (!fileSystem->directoryExists(dir)) {
+		fileSystem->createSubdirs(dir);
+	}
+	sdpPath = dir + md5 + ".sdp";
+	LOG_DEBUG("%s", sdpPath.c_str());
 }
 
 CSdp::~CSdp()
@@ -59,54 +65,57 @@ bool createPoolDirs(const std::string& root)
 	return true;
 }
 
-bool CSdp::download(IDownload* download)
+bool CSdp::downloadSelf(IDownload* dl)
 {
-	if (downloaded) // allow download only once of the same sdp
-		return true;
-	m_download = download;
-	filename =
-	    fileSystem->getSpringDir() + PATH_DELIMITER + "packages" + PATH_DELIMITER;
-	LOG_DEBUG("%s", filename.c_str());
-	if (!fileSystem->directoryExists(filename)) {
-		fileSystem->createSubdirs(filename);
+
+	const std::string tmpFile = sdpPath + ".tmp";
+	IDownload tmpdl(tmpFile);
+	tmpdl.addMirror(baseUrl + "/packages/" + md5 + ".sdp");
+	if(!httpDownload->download(&tmpdl)) {
+		LOG_ERROR("Couldn't download %s", (md5 + ".sdp").c_str());
+		return false;
 	}
-	int count = 0;
-	filename += this->md5 + ".sdp";
-	const std::string tmpFile = filename + ".tmp";
-	std::list<FileData*> files;
+	
 
-	bool rename = false;
-	if (!fileSystem->fileExists(filename)) { //.sdp isn't avaiable, download it
-		IDownload dl(tmpFile);
-		dl.addMirror(url + "/packages/" + this->md5 + ".sdp");
-		httpDownload->download(&dl);
-		fileSystem->parseSdp(tmpFile, files); // parse downloaded file
-		rename = true;
-	} else {
-		fileSystem->parseSdp(filename, files); // parse downloaded file
+	if (!fileSystem->Rename(tmpFile, sdpPath)) {
+		LOG_ERROR("Couldn't rename %s to %s", tmpFile.c_str(), sdpPath.c_str());
+		return false;
+	}
+
+	return true;
+}
+
+bool CSdp::download(IDownload* dl)
+{
+	if (downloaded) // allow download only once of the same sdp
+		return true;
+	m_download = dl;
+	if ((!fileSystem->fileExists(sdpPath)) || (!fileSystem->parseSdp(sdpPath, files))) {// parse downloaded file
+		if (!downloadSelf(dl))
+			return false;
+		fileSystem->parseSdp(sdpPath, files);
 	}
 
-	HashMD5 md5 = HashMD5();
-	FileData tmp = FileData();
 	int i = 0;
-	for (FileData* filedata : files) { // check which file are available on local
-					   // disk -> create list of files to download
+	int count = 0;
+	for (FileData& filedata: files) { // check which file are available on local
+	                                   // disk -> create list of files to download
+		HashMD5 fileMd5;
 		i++;
-		md5.Set(filedata->md5, sizeof(filedata->md5));
+		fileMd5.Set(filedata.md5, sizeof(filedata.md5));
 		std::string file;
-		fileSystem->getPoolFilename(md5.toString(), file);
-		if (!fileSystem->fileExists(
-			file)) { // add non-existing files to download list
+		fileSystem->getPoolFilename(fileMd5.toString(), file);
+		if (!fileSystem->fileExists(file)) { // add non-existing files to download list
 			count++;
-			filedata->download = true;
+			filedata.download = true;
 		} else {
-			filedata->download = false;
+			filedata.download = false;
 		}
 		if (i % 30 == 0) {
 			LOG_DEBUG("\r%d/%d checked", i, (int)files.size());
 		}
 	}
-	LOG_DEBUG("\r%d/%d need to download %d files", i, (unsigned int)files.size(),
+	LOG_DEBUG("\r%d/%d need to download %d files", i, (int)files.size(),
 		  count);
 
 	std::string root = fileSystem->getSpringDir();
@@ -115,35 +124,23 @@ bool CSdp::download(IDownload* download)
 	root += PATH_DELIMITER;
 	if (!createPoolDirs(root)) {
 		LOG_ERROR("Creating pool directories failed");
-		count = 0;
+		return false;
 	}
-	if (count > 0) {
-		downloaded =
-		    downloadStream(this->url + "/streamer.cgi?" + this->md5, files);
-		if (!downloaded) {
-			LOG_ERROR("Couldn't download files for %s", this->md5.c_str());
-			fileSystem->removeFile(tmpFile);
-			fileSystem->removeFile(filename);
-			return false;
-		}
-		LOG_DEBUG("Sucessfully downloaded %d files: %s %s", count,
-			  shortname.c_str(), name.c_str());
-	} else {
-		LOG_DEBUG("Already downloaded: %s", shortname.c_str());
-		downloaded = true;
+	if (!downloadStream()) {
+		LOG_ERROR("Couldn't download files for %s", md5.c_str());
+		fileSystem->removeFile(sdpPath);
+		return false;
 	}
+	LOG_DEBUG("Sucessfully downloaded %d files: %s %s", count,
+		  shortname.c_str(), name.c_str());
 
-	for (FileData* filedata : files) { // free memory
-		delete filedata;
-	}
-	if ((rename) && (!fileSystem->Rename(tmpFile, filename))) {
-		LOG_ERROR("Couldn't rename %s to %s", tmpFile.c_str(), filename.c_str());
+	if (!fileSystem->validateSDP(sdpPath)) { //FIXME: in this call only the downloaded files should be checked
+		LOG_ERROR("Validation failed");
 		return false;
 	}
-	if (downloaded) {
-		download->state = IDownload::STATE_FINISHED;
-	}
-	return downloaded;
+	downloaded = true;
+	dl->state = IDownload::STATE_FINISHED;
+	return true;
 }
 
 /**
@@ -155,10 +152,12 @@ bool CSdp::download(IDownload* download)
 static size_t write_streamed_data(const void* tmp, size_t size, size_t nmemb,
 				  CSdp* sdp)
 {
+	if (IDownloader::AbortDownloads())
+		return -1;
 	char buf[CURL_MAX_WRITE_SIZE];
 	memcpy(&buf, tmp, CURL_MAX_WRITE_SIZE);
 	if (!sdp->downloadInitialized) {
-		sdp->list_it = sdp->globalFiles->begin();
+		sdp->list_it = sdp->files.begin();
 		sdp->downloadInitialized = true;
 		sdp->file_handle = NULL;
 		sdp->file_name = "";
@@ -170,22 +169,26 @@ static size_t write_streamed_data(const void* tmp, size_t size, size_t nmemb,
 
 	while (buf_pos < buf_end) {		// all bytes written?
 		if (sdp->file_handle == NULL) { // no open file, create one
-			while ((!(*sdp->list_it)->download == true) &&
-			       (sdp->list_it != sdp->globalFiles->end())) { // get file
+			while (!sdp->list_it->download) { // get file
 				++sdp->list_it;
 			}
-			HashMD5 md5;
-			md5.Set((*sdp->list_it)->md5, sizeof((*sdp->list_it)->md5));
-			fileSystem->getPoolFilename(md5.toString(), sdp->file_name);
+			assert(sdp->list_it != sdp->files.end());
+
+			FileData& fd = *(sdp->list_it);
+			HashMD5 fileMd5;
+
+			fileMd5.Set(fd.md5, sizeof(fd.md5));
+			fileSystem->getPoolFilename(fileMd5.toString(), sdp->file_name);
 			sdp->file_handle = new CFile();
 			if (sdp->file_handle == NULL) {
-				LOG_ERROR("couldn't open %s", (*sdp->list_it)->name.c_str());
+				LOG_ERROR("couldn't open %s", fd.name.c_str());
 				return -1;
 			}
 			sdp->file_handle->Open(sdp->file_name);
 			sdp->file_pos = 0;
 		}
 		assert(sdp->file_handle != NULL);
+		FileData& fd = *(sdp->list_it);
 		if (sdp->skipped < LENGTH_SIZE) { // check if we skipped all 4 bytes for
 						  // file length, if not so, skip them
 			const int toskip =
@@ -198,13 +201,13 @@ static size_t write_streamed_data(const void* tmp, size_t size, size_t nmemb,
 			sdp->skipped += toskip;
 			buf_pos += toskip;
 			if (sdp->skipped == LENGTH_SIZE) { // all length bytes read, parse
-				(*sdp->list_it)->compsize = parse_int32(sdp->cursize_buf);
-				assert((*sdp->list_it)->size + 2000 >= (*sdp->list_it)->compsize);
+				fd.compsize = parse_int32(sdp->cursize_buf);
+				assert(fd.size + 2000 >= fd.compsize);
 			}
 		}
 		if (sdp->skipped == LENGTH_SIZE) { // length bytes read
 			const int towrite =
-			    intmin((*sdp->list_it)->compsize -
+			    intmin(fd.compsize -
 				       sdp->file_pos, // minimum of bytes to write left in file
 						      // and bytes to write left in buf
 				   buf_end - buf_pos);
@@ -222,11 +225,11 @@ static size_t write_streamed_data(const void* tmp, size_t size, size_t nmemb,
 			sdp->file_pos += res;
 
 			if (sdp->file_pos >=
-			    (*sdp->list_it)->compsize) { // file finished -> next file
+			    fd.compsize) { // file finished -> next file
 				sdp->file_handle->Close();
 				delete sdp->file_handle;
 				sdp->file_handle = NULL;
-				if (!fileSystem->fileIsValid(*sdp->list_it, sdp->file_name.c_str())) {
+				if (!fileSystem->fileIsValid(&fd, sdp->file_name.c_str())) {
 					LOG_ERROR("File is broken?!: %s", sdp->file_name.c_str());
 					fileSystem->removeFile(sdp->file_name.c_str());
 					return -1;
@@ -243,29 +246,30 @@ static size_t write_streamed_data(const void* tmp, size_t size, size_t nmemb,
 /** *
         draw a nice download status-bar
 */
-static int progress_func(CSdp& csdp, double TotalToDownload,
+static int progress_func(CSdp& sdp, double TotalToDownload,
 			 double NowDownloaded, double TotalToUpload,
 			 double NowUploaded)
 {
-
-	(void)csdp;
+	if (IDownloader::AbortDownloads())
+		return -1;
+	(void)sdp;
 	(void)TotalToUpload;
 	(void)NowUploaded; // remove unused warning
-	csdp.m_download->rapid_size[&csdp] = TotalToDownload;
-	csdp.m_download->map_rapid_progress[&csdp] = NowDownloaded;
+	sdp.m_download->rapid_size[&sdp] = TotalToDownload;
+	sdp.m_download->map_rapid_progress[&sdp] = NowDownloaded;
 	uint64_t total = 0;
-	for (auto it : csdp.m_download->rapid_size) {
+	for (auto it : sdp.m_download->rapid_size) {
 		total += it.second;
 	}
-	csdp.m_download->size = total;
+	sdp.m_download->size = total;
 	if (IDownloader::listener != nullptr) {
 		IDownloader::listener(NowDownloaded, TotalToDownload);
 	}
 	total = 0;
-	for (auto it : csdp.m_download->map_rapid_progress) {
+	for (auto it : sdp.m_download->map_rapid_progress) {
 		total += it.second;
 	}
-	csdp.m_download->progress = total;
+	sdp.m_download->progress = total;
 	if (TotalToDownload == NowDownloaded) // force output when download is
 					      // finished
 		LOG_PROGRESS(NowDownloaded, TotalToDownload, true);
@@ -274,56 +278,48 @@ static int progress_func(CSdp& csdp, double TotalToDownload,
 	return 0;
 }
 
-bool CSdp::downloadStream(const std::string& url, std::list<FileData*> files)
+bool CSdp::downloadStream()
 {
-	CurlWrapper* curlw = new CurlWrapper();
-	if (!curlw) {
-		return false;
-	}
+	std::string downloadUrl = baseUrl + "/streamer.cgi?" + md5;
+	CurlWrapper curlw;
+
 	CURLcode res;
 	LOG_INFO("Using rapid");
-	LOG_INFO(url.c_str());
+	LOG_INFO(downloadUrl.c_str());
 
-	curl_easy_setopt(curlw->GetHandle(), CURLOPT_URL, url.c_str());
+	curl_easy_setopt(curlw.GetHandle(), CURLOPT_URL, downloadUrl.c_str());
+
+	const int buflen = (files.size() + 7) / 8;
+	std::vector<char> buf(buflen, 0);
 
-	int buflen = files.size() / 8;
-	if (files.size() % 8 != 0)
-		buflen++;
-	char* buf =
-	    (char*)malloc(buflen); // FIXME: compress blockwise and not all at once
-	memset(buf, 0, buflen);
-	int destlen = files.size() * 2;
-	LOG_DEBUG("%d %d %d", (int)files.size(), buflen, destlen);
 	int i = 0;
-	for (FileData* it : files) {
-		if (it->download == true) {
+	for (FileData& fd: files) {
+		if (fd.download) {
 			buf[i / 8] |= (1 << (i % 8));
 		}
 		i++;
 	}
-	char* dest = (char*)malloc(destlen);
 
-	gzip_str(buf, buflen, dest, &destlen);
+	int destlen = files.size() * 2;
+	std::vector<char> dest(destlen, 0);
+	LOG_DEBUG("%d %d %d", (int)files.size(), buflen, destlen);
+
+	gzip_str(&buf[0], buflen, &dest[0], &destlen);
 
-	curl_easy_setopt(curlw->GetHandle(), CURLOPT_WRITEFUNCTION,
+	curl_easy_setopt(curlw.GetHandle(), CURLOPT_WRITEFUNCTION,
 			 write_streamed_data);
-	curl_easy_setopt(curlw->GetHandle(), CURLOPT_WRITEDATA, this);
+	curl_easy_setopt(curlw.GetHandle(), CURLOPT_WRITEDATA, this);
 
-	globalFiles = &files;
-	curl_easy_setopt(curlw->GetHandle(), CURLOPT_POSTFIELDS, dest);
-	curl_easy_setopt(curlw->GetHandle(), CURLOPT_POSTFIELDSIZE, destlen);
-	curl_easy_setopt(curlw->GetHandle(), CURLOPT_NOPROGRESS, 0L);
-	curl_easy_setopt(curlw->GetHandle(), CURLOPT_PROGRESSFUNCTION, progress_func);
-	curl_easy_setopt(curlw->GetHandle(), CURLOPT_PROGRESSDATA, this);
+	curl_easy_setopt(curlw.GetHandle(), CURLOPT_POSTFIELDS, &dest[0]);
+	curl_easy_setopt(curlw.GetHandle(), CURLOPT_POSTFIELDSIZE, destlen);
+	curl_easy_setopt(curlw.GetHandle(), CURLOPT_NOPROGRESS, 0L);
+	curl_easy_setopt(curlw.GetHandle(), CURLOPT_PROGRESSFUNCTION, progress_func);
+	curl_easy_setopt(curlw.GetHandle(), CURLOPT_PROGRESSDATA, this);
 
-	res = curl_easy_perform(curlw->GetHandle());
-	free(dest);
-	free(buf);
+	res = curl_easy_perform(curlw.GetHandle());
 	/* always cleanup */
-	delete curlw;
-	curlw = NULL;
 	if (res != CURLE_OK) {
-		LOG_ERROR("Curl cleanup error: %s", curl_easy_strerror(res));
+		LOG_ERROR("Curl error: %s", curl_easy_strerror(res));
 		return false;
 	}
 	return true;
diff --git a/src/downloader/lib/src/Downloader/Rapid/Sdp.h b/src/downloader/lib/src/Downloader/Rapid/Sdp.h
index 3ccf217..6ec8360 100644
--- a/src/downloader/lib/src/Downloader/Rapid/Sdp.h
+++ b/src/downloader/lib/src/Downloader/Rapid/Sdp.h
@@ -3,13 +3,14 @@
 #ifndef _SDP_H
 #define _SDP_H
 
+#include "FileSystem/FileData.h"
+
 #include <string>
 #include <list>
 
 #define LENGTH_SIZE 4
 
 class IDownload;
-class FileData;
 class CFile;
 
 class CSdp
@@ -17,14 +18,18 @@ class CSdp
 public:
 	CSdp(const std::string& shortname, const std::string& md5,
 	     const std::string& name, const std::string& depends,
-	     const std::string& url);
+	     const std::string& baseUrl);
 	~CSdp();
 	/**
           download a game, we already know the host where to download from + the
      md5 of the sdp file
           we have to download the sdp + parse it + download associated files
   */
-	bool download(IDownload* download);
+	bool download(IDownload* dl);
+	/**
+          download the sdp file if it doesn't exist yet
+  */
+	bool downloadSelf(IDownload* dl);
 	/**
           returns md5 of a repo
   */
@@ -55,8 +60,8 @@ public:
 	}
 	IDownload* m_download;
 	bool downloadInitialized;
-	std::list<FileData*>::iterator list_it;
-	std::list<FileData*>* globalFiles; // list with all files of an sdp
+	std::list<FileData>::iterator list_it;
+	std::list<FileData> files; // list with all files of an sdp
 	CFile* file_handle;
 	std::string file_name;
 
@@ -94,13 +99,14 @@ private:
   T 192.168.1.2:33202 -> 94.23.170.70:80 [AP]
   ......zL..c`..`d.....K.n/....
   */
-	bool downloadStream(const std::string& url, std::list<FileData*> files);
+	bool downloadStream();
+
 	std::string name;
 	std::string md5;
 	std::string shortname;
-	std::string url;
-	std::string filename;
+	std::string baseUrl;
 	std::string depends;
+	std::string sdpPath;
 	bool downloaded;
 };
 
diff --git a/src/downloader/lib/src/FileSystem/File.cpp b/src/downloader/lib/src/FileSystem/File.cpp
index 8bce303..4687f7c 100644
--- a/src/downloader/lib/src/FileSystem/File.cpp
+++ b/src/downloader/lib/src/FileSystem/File.cpp
@@ -216,7 +216,7 @@ int CFile::Write(const char* buf, int bufsize, int piece)
 
 int CFile::Seek(unsigned long pos, int piece)
 {
-	assert(piece <= (int)pieces.size());
+	assert(piece < (int)pieces.size());
 	if (piece >= 0) { // adjust position relative to piece pos
 		pos = this->piecesize * piece + pos;
 	}
@@ -273,7 +273,7 @@ int CFile::GetPiecesSize(std::vector<unsigned int> pieces) const
 int CFile::GetPieceSize(int piece) const
 {
 	if (piece >= 0) {
-		assert(piece <= (int)pieces.size());
+		assert(piece < (int)pieces.size());
 		if ((int)pieces.size() - 1 == piece) // last piece
 			return size - (piecesize * ((int)pieces.size() - 1));
 		//		LOG("GetPieceSize piece %d, pieces.size() %d piecesize: %d size %d
@@ -289,7 +289,7 @@ int CFile::GetPieceSize(int piece) const
 
 long CFile::GetPiecePos(int piece) const
 {
-	assert(piece <= (int)pieces.size());
+	assert(piece < (int)pieces.size());
 	if (piece >= 0)
 		return pieces[piece].pos;
 	return curpos;
diff --git a/src/downloader/lib/src/FileSystem/FileSystem.cpp b/src/downloader/lib/src/FileSystem/FileSystem.cpp
index 5b3650a..ef6d613 100644
--- a/src/downloader/lib/src/FileSystem/FileSystem.cpp
+++ b/src/downloader/lib/src/FileSystem/FileSystem.cpp
@@ -81,8 +81,14 @@ bool CFileSystem::fileIsValid(const FileData* mod,
 	return true;
 }
 
-bool CFileSystem::parseSdp(const std::string& filename,
-			   std::list<FileData*>& files)
+std::string getMD5fromFilename(const std::string& path)
+{
+	const size_t start = path.rfind(PATH_DELIMITER) + 1;
+	const size_t end = path.find(".", start);
+	return path.substr(start, end-start);
+}
+
+bool CFileSystem::parseSdp(const std::string& filename, std::list<FileData>& files)
 {
 	char c_name[255];
 	unsigned char c_md5[16];
@@ -94,16 +100,21 @@ bool CFileSystem::parseSdp(const std::string& filename,
 	gzFile in = gzdopen(fileno(f), "rb");
 	if (in == Z_NULL) {
 		LOG_ERROR("Could not open %s", filename.c_str());
+		fclose(f);
 		return false;
 	}
 	files.clear();
+	HashMD5 sdpmd5;
+	sdpmd5.Init();
 	while (true) {
+
 		if (!gzread(in, &length, 1)) {
 			if (gzeof(in)) {
 				break;
 			}
 			LOG_ERROR("Unexpected eof in %s", filename.c_str());
 			gzclose(in);
+			fclose(f);
 			return false;
 		}
 		if (!((gzread(in, &c_name, length)) && (gzread(in, &c_md5, 16)) &&
@@ -113,15 +124,31 @@ bool CFileSystem::parseSdp(const std::string& filename,
 			fclose(f);
 			return false;
 		}
-		FileData* f = new FileData;
-		f->name = std::string(c_name, length);
-		memcpy(f->md5, &c_md5, 16);
-		memcpy(f->crc32, &c_crc32, 4);
-		f->size = parse_int32(c_size);
-		files.push_back(f);
+		FileData fd;
+		fd.name = std::string(c_name, length);
+		memcpy(fd.md5, &c_md5, 16);
+		memcpy(fd.crc32, &c_crc32, 4);
+		fd.size = parse_int32(c_size);
+		files.push_back(fd);
+		
+		HashMD5 nameMd5;
+		nameMd5.Init();
+		nameMd5.Update(fd.name.data(), fd.name.size());
+		nameMd5.Final();
+		assert(nameMd5.getSize() == 16);
+		assert(sizeof(fd.md5) == 16);
+		sdpmd5.Update((const char*)nameMd5.Data(), nameMd5.getSize());
+		sdpmd5.Update((const char*)&fd.md5[0], sizeof(fd.md5));
 	}
 	gzclose(in);
 	fclose(f);
+	sdpmd5.Final();
+	const std::string filehash = getMD5fromFilename(filename);
+	if (filehash != sdpmd5.toString()) {
+		LOG_ERROR("%s is invalid, deleted (%s vs %s)", filename.c_str(), filehash.c_str(), sdpmd5.toString().c_str());
+		removeFile(filename);
+		return false;
+	}
 	LOG_DEBUG("Parsed %s with %d files", filename.c_str(), (int)files.size());
 	return true;
 }
@@ -475,21 +502,61 @@ bool CFileSystem::parseTorrent(const char* data, int size, IDownload* dl)
 
 bool CFileSystem::dumpSDP(const std::string& filename)
 {
-	std::list<FileData*> files;
-	files.clear();
+	std::list<FileData> files;
 	if (!parseSdp(filename, files))
 		return false;
 	LOG_INFO("md5 (filename in pool)           crc32        size filename");
 	std::list<FileData*>::iterator it;
 	HashMD5 md5;
-	for (it = files.begin(); it != files.end(); ++it) {
-		md5.Set((*it)->md5, sizeof((*it)->md5));
-		LOG_INFO("%s %.8X %8d %s", md5.toString().c_str(), (*it)->crc32,
-			 (*it)->size, (*it)->name.c_str());
+	for (const FileData& fd: files) {
+		md5.Set(fd.md5, sizeof(fd.md5));
+		LOG_INFO("%s %.8X %8d %s", md5.toString().c_str(), fd.crc32,
+		         fd.size, fd.name.c_str());
 	}
 	return true;
 }
 
+bool CFileSystem::validateSDP(const std::string& sdpPath)
+{
+	LOG_DEBUG("CFileSystem::validateSDP() ...");
+	if (!fileExists(sdpPath)){
+		LOG_ERROR("SDP file doesn't exist: %s", sdpPath.c_str());
+		return false;
+	}
+
+	std::list<FileData> files;
+	if (!parseSdp(sdpPath, files)) {// parse downloaded file
+		LOG_ERROR("Removing invalid SDP file: %s", sdpPath.c_str());
+		if (!removeFile(sdpPath)) {
+			LOG_ERROR("Failed removing %s, aborting", sdpPath.c_str());
+			return false;
+		}
+		return false;
+	}
+
+	bool valid = true;
+	for (FileData& fd : files) {
+
+		std::string filePath;
+		HashMD5 fileMd5;
+		fileMd5.Set(fd.md5, sizeof(fd.md5));
+		getPoolFilename(fileMd5.toString(), filePath);
+		if(!fileExists(filePath)) {
+			valid = false;
+			LOG_INFO("Missing file: %s", filePath.c_str());
+		} else if (!fileIsValid(&fd, filePath)) {
+			valid = false;
+			LOG_INFO("Removing invalid file: %s", filePath.c_str());
+			if (!removeFile(filePath)) {
+				LOG_ERROR("Failed removing %s, aborting", filePath.c_str());
+				return false;
+			}
+		}
+	}
+	LOG_DEBUG("CFileSystem::validateSDP() done");
+	return valid;
+}
+
 bool CFileSystem::extractEngine(const std::string& filename,
 				const std::string& version)
 {
diff --git a/src/downloader/lib/src/FileSystem/FileSystem.h b/src/downloader/lib/src/FileSystem/FileSystem.h
index 143fd02..9030c5a 100644
--- a/src/downloader/lib/src/FileSystem/FileSystem.h
+++ b/src/downloader/lib/src/FileSystem/FileSystem.h
@@ -3,12 +3,13 @@
 #ifndef FILE_SYSTEM_H
 #define FILE_SYSTEM_H
 
+#include "FileData.h"
+
 #include <list>
 #include <string>
 
 class SRepository;
 class CRepo;
-class FileData;
 class IDownload;
 
 #ifdef WIN32
@@ -30,7 +31,7 @@ public:
 	/**
           parses the file for a mod and creates
   */
-	bool parseSdp(const std::string& filename, std::list<FileData*>& files);
+	bool parseSdp(const std::string& filename, std::list<FileData>& files);
 	/**
    *	Validates a pool-file, (checks the md5)
    */
@@ -87,6 +88,10 @@ public:
   */
 	bool dumpSDP(const std::string& filename);
 	/**
+  *	validates the given .sdp
+  */
+	bool validateSDP(const std::string& filename);
+	/**
   *	extracts a 7z file to dstdir
   */
 	bool extract(const std::string& filename, const std::string& dstdir,
diff --git a/src/downloader/lib/src/FileSystem/HashMD5.h b/src/downloader/lib/src/FileSystem/HashMD5.h
index cb14bf1..a3d6795 100644
--- a/src/downloader/lib/src/FileSystem/HashMD5.h
+++ b/src/downloader/lib/src/FileSystem/HashMD5.h
@@ -16,8 +16,8 @@ public:
 	bool Set(const unsigned char* data, int size);
 	unsigned char get(int pos) const;
 	static std::string CalculateHash(const char* data, const int size);
+	const unsigned char* Data() const { return &mdContext.digest[0]; }
 
-protected:
 	int getSize() const;
 
 private:
diff --git a/src/downloader/lib/src/lib/CMakeLists.txt b/src/downloader/lib/src/lib/CMakeLists.txt
index d4ed54a..459d2c5 100644
--- a/src/downloader/lib/src/lib/CMakeLists.txt
+++ b/src/downloader/lib/src/lib/CMakeLists.txt
@@ -1,9 +1,9 @@
 if(PRD_ARCHIVE_SUPPORT)
-	subdirs(7z)
+	add_subdirectory(7z)
 	if (NOT MINIZIP_FOUND)
-		subdirs(minizip)
+		add_subdirectory(minizip)
 	endif()
 endif()
-subdirs(md5)
-subdirs(bencode)
-subdirs(sha1)
+add_subdirectory(md5)
+add_subdirectory(bencode)
+add_subdirectory(sha1)
diff --git a/src/downloader/lib/src/lsl/lslunitsync/CMakeLists.txt b/src/downloader/lib/src/lsl/lslunitsync/CMakeLists.txt
index 569b32c..54d1fed 100644
--- a/src/downloader/lib/src/lsl/lslunitsync/CMakeLists.txt
+++ b/src/downloader/lib/src/lsl/lslunitsync/CMakeLists.txt
@@ -32,7 +32,7 @@ endif()
 if (UNIX AND NOT MINGW AND NOT APPLE)
 	FIND_LIBRARY(RT_LIBRARY rt)
 endif()
-TARGET_LINK_LIBRARIES(lsl-unitsync lsl-utils ${Boost_LIBRARIES} ${PNG_LIBRARY} ${X11_LIBRARIES} ${CMAKE_DL_LIBS} ${RT_LIBRARY})
+TARGET_LINK_LIBRARIES(lsl-unitsync lsl-utils ${Boost_LIBRARIES} ${PNG_LIBRARY} ${X11_LIBRARIES} ${CMAKE_DL_LIBS} ${RT_LIBRARY} ${PRD_JSONCPP_LIBRARIES})
 target_include_directories(lsl-unitsync
 		PRIVATE ${pr-downloader_SOURCE_DIR}/src/lsl
 		PRIVATE ${pr-downloader_SOURCE_DIR}/src/lib
diff --git a/src/downloader/lib/src/lsl/lslunitsync/c_api.cpp b/src/downloader/lib/src/lsl/lslunitsync/c_api.cpp
index 94e9d9c..8be330f 100644
--- a/src/downloader/lib/src/lsl/lslunitsync/c_api.cpp
+++ b/src/downloader/lib/src/lsl/lslunitsync/c_api.cpp
@@ -562,6 +562,12 @@ unsigned int UnitsyncLib::GetPrimaryModChecksumFromName(const std::string& name)
 	return m_get_primary_mod_checksum_from_name(name.c_str());
 }
 
+unsigned int UnitsyncLib::GetMapChecksumFromName(const std::string& name)
+{
+	InitLib(m_get_map_checksum_from_name);
+	return m_get_map_checksum_from_name(name.c_str());
+}
+
 UnitsyncLib::StringVector UnitsyncLib::GetModDeps(int index)
 {
 	const int count = GetPrimaryModArchiveCount(index);
diff --git a/src/downloader/lib/src/lsl/lslunitsync/c_api.h b/src/downloader/lib/src/lsl/lslunitsync/c_api.h
index a0a0b38..5e659c9 100644
--- a/src/downloader/lib/src/lsl/lslunitsync/c_api.h
+++ b/src/downloader/lib/src/lsl/lslunitsync/c_api.h
@@ -165,6 +165,7 @@ public:
 	int GetPrimaryModArchiveCount(int index);
 	std::string GetPrimaryModArchiveList(int arnr);
 	unsigned int GetPrimaryModChecksumFromName(const std::string& name);
+	unsigned int GetMapChecksumFromName(const std::string& name);
 	StringVector GetModDeps(int index);
 
 	StringVector GetSides(const std::string& modName);
diff --git a/src/downloader/lib/src/lsl/lslunitsync/unitsync.cpp b/src/downloader/lib/src/lsl/lslunitsync/unitsync.cpp
index 31df17a..27e2bcf 100644
--- a/src/downloader/lib/src/lsl/lslunitsync/unitsync.cpp
+++ b/src/downloader/lib/src/lsl/lslunitsync/unitsync.cpp
@@ -162,52 +162,38 @@ void Unitsync::PopulateArchiveList()
 	const int numMaps = susynclib().GetMapCount();
 	for (int i = 0; i < numMaps; i++) {
 		std::string name, archivename;
-		unsigned int hash;
 		try {
 			const int count = susynclib().GetMapArchiveCount(i);
 			if (count > 0) {
 				archivename = susynclib().GetMapArchiveName(0);
 			}
 			name = susynclib().GetMapName(i);
-			hash = susynclib().GetMapChecksum(i);
 			//PrefetchMap( name ); // DEBUG
 		} catch (...) {
 			continue;
 		}
-		try {
-			assert(!name.empty());
-			m_maps_list[name] = LSL::Util::ToUIntString(hash);
-			if (!archivename.empty())
-				m_maps_archive_name[name] = archivename;
-			m_map_array.push_back(name);
-		} catch (...) {
-			LslError("Found map with hash collision: %s hash: %d", name.c_str(), hash);
-		}
+		assert(!name.empty());
+		if (!archivename.empty())
+			m_maps_archive_name[name] = archivename;
+		m_map_array.push_back(name);
 		FetchUnitsyncErrors(name);
 	}
 	const int numMods = susynclib().GetPrimaryModCount();
 	for (int i = 0; i < numMods; i++) {
 		std::string name, archivename;
-		unsigned int hash;
 		try {
 			const int count = susynclib().GetPrimaryModArchiveCount(i);
 			if (count > 0) {
 				archivename = susynclib().GetPrimaryModArchive(i);
 			}
 			name = GetGameInfo(i, "name");
-			hash = susynclib().GetPrimaryModChecksumFromName(name);
 		} catch (...) {
 			continue;
 		}
-		try {
-			assert(!name.empty());
-			m_mods_list[name] = LSL::Util::ToUIntString(hash);
-			if (!archivename.empty())
-				m_mods_archive_name[name] = archivename;
-			m_mod_array.push_back(name);
-		} catch (...) {
-			LslError("Found game with hash collision: %s hash: %s", name.c_str(), hash);
-		}
+		assert(!name.empty());
+		if (!archivename.empty())
+			m_mods_archive_name[name] = archivename;
+		m_mod_array.push_back(name);
 		FetchUnitsyncErrors(name);
 	}
 	m_unsorted_mod_array = m_mod_array;
@@ -248,18 +234,31 @@ StringVector Unitsync::GetGameList() const
 	return m_mod_array;
 }
 
-bool Unitsync::GameExists(const std::string& gamename, const std::string& hash) const
+bool Unitsync::GameExists(const std::string& gamename, const std::string& hash)
 {
 	TRY_LOCK(false)
-	LocalArchivesVector::const_iterator itor = m_mods_list.find(gamename);
-	if (itor == m_mods_list.end() || itor->second.empty())
+	LocalArchivesVector::const_iterator itor = m_mods_archive_name.find(gamename);
+	if (itor == m_mods_archive_name.end() || itor->second.empty())
 		return false;
 
 	assert(!itor->second.empty()); //empty hashes are invalid
 
 	if (hash.empty())
 		return true;
-	return itor->second == hash;
+	return GetGameHash(gamename) == hash;
+}
+
+std::string Unitsync::GetGameHash(const std::string& name)
+{
+	LocalArchivesVector::const_iterator itor = m_mods_list.find(name);
+	if (itor != m_mods_list.end()) {
+		return itor->second;
+	}
+	const unsigned int modhash = susynclib().GetPrimaryModChecksumFromName(name);
+	assert(modhash>0);
+	const std::string strhash = LSL::Util::ToUIntString(modhash);
+	m_mods_list[name] = strhash;
+	return strhash;
 }
 
 UnitsyncGame Unitsync::GetGame(const std::string& gamename)
@@ -267,7 +266,9 @@ UnitsyncGame Unitsync::GetGame(const std::string& gamename)
 	UnitsyncGame m;
 	TRY_LOCK(m);
 	m.name = gamename;
-	m.hash = m_mods_list[gamename];
+	m.hash = GetGameHash(gamename);
+	assert(m.hash != "0");
+	assert(!m.hash.empty());
 	return m;
 }
 
@@ -277,7 +278,9 @@ UnitsyncGame Unitsync::GetGame(int index)
 	UnitsyncGame m;
 	TRY_LOCK(m);
 	m.name = m_mod_array[index];
-	m.hash = m_mods_list[m.name];
+	m.hash = GetGameHash(m.name);
+	assert(m.hash != "0");
+	assert(!m.hash.empty());
 	return m;
 }
 
@@ -300,17 +303,31 @@ StringVector Unitsync::GetGameValidMapList(const std::string& gamename) const
 	return ret;
 }
 
-bool Unitsync::MapExists(const std::string& mapname, const std::string& hash) const
+bool Unitsync::MapExists(const std::string& mapname, const std::string& hash)
 {
 	assert(!mapname.empty());
 	TRY_LOCK(false)
-	LocalArchivesVector::const_iterator itor = m_maps_list.find(mapname);
-	if (itor == m_maps_list.end())
+	LocalArchivesVector::const_iterator itor = m_maps_archive_name.find(mapname);
+	if (itor == m_maps_archive_name.end())
 		return false;
 	assert(!itor->second.empty()); //empty hashes are invalid
 	if (hash.empty())
 		return true;
-	return itor->second == hash;
+
+	return GetMapHash(mapname) == hash;
+}
+
+std::string Unitsync::GetMapHash(const std::string& name)
+{
+	LocalArchivesVector::const_iterator itor = m_maps_list.find(name);
+	if (itor != m_maps_list.end()) {
+		return itor->second;
+	}
+	const unsigned int modhash = susynclib().GetMapChecksumFromName(name);
+	assert(modhash > 0);
+	const std::string strhash = LSL::Util::ToUIntString(modhash);
+	m_maps_list[name] = strhash;
+	return strhash;
 }
 
 UnitsyncMap Unitsync::GetMap(int index)
@@ -320,7 +337,7 @@ UnitsyncMap Unitsync::GetMap(int index)
 	if (index < 0)
 		return m;
 	m.name = m_map_array[index];
-	m.hash = m_maps_list[m.name];
+	m.hash = GetMapHash(m.name);
 	m.info = _GetMapInfoEx(m.name);
 	assert(!m.hash.empty());
 	return m;
@@ -411,7 +428,7 @@ UnitsyncMap Unitsync::GetMap(const std::string& mapname)
 		LSL_THROWF(unitsync, "Map does not exist: %s", mapname.c_str());
 	}
 	m.name = m_map_array[i];
-	m.hash = m_maps_list[m.name];
+	m.hash = GetMapHash(mapname);
 	m.info = _GetMapInfoEx(m.name);
 	assert(!m.hash.empty());
 	return m;
@@ -427,6 +444,7 @@ GameOptions Unitsync::GetGameOptions(const std::string& name)
 	if (m_game_gameoptions.find(name) != m_game_gameoptions.end()) {
 		return m_game_gameoptions[name];
 	}
+	GetGameHash(name);
 	const std::string filename = GetGameOptionsPath(name);
 	if (!lslcache.Get(filename, ret)) {
 		PrefetchGame(name);
@@ -455,6 +473,7 @@ StringVector Unitsync::GetSides(const std::string& gamename)
 	if (!GameExists(gamename))
 		return ret;
 	TRY_LOCK(ret);
+	GetGameHash(gamename);
 	const std::string cachefile = GetSidesCachePath(gamename);
 
 	if (!lslcache.Get(cachefile, ret) && (GameExists(gamename))) { // cache file failed, try from lsl
@@ -911,6 +930,7 @@ void Unitsync::PrefetchMap(const std::string& mapname)
 
 
 	FetchUnitsyncErrors(mapname);
+	GetMapHash(mapname);
 
 	const int index = Util::IndexInSequence(m_unsorted_map_array, mapname);
 	ASSERT_EXCEPTION(index >= 0, "Map not found");
@@ -949,6 +969,7 @@ void Unitsync::PrefetchGame(const std::string& gamename)
 {
 	assert(!gamename.empty());
 	susynclib().SetCurrentMod(gamename);
+	GetGameHash(gamename);
 	{
 		int count = susynclib().GetModOptionCount(gamename);
 		GameOptions opt;
diff --git a/src/downloader/lib/src/lsl/lslunitsync/unitsync.h b/src/downloader/lib/src/lsl/lslunitsync/unitsync.h
index ba6bf8c..3695c3c 100644
--- a/src/downloader/lib/src/lsl/lslunitsync/unitsync.h
+++ b/src/downloader/lib/src/lsl/lslunitsync/unitsync.h
@@ -51,7 +51,7 @@ public:
 	~Unitsync();
 
 	StringVector GetGameList() const;
-	bool GameExists(const std::string& gamename, const std::string& hash = "") const;
+	bool GameExists(const std::string& gamename, const std::string& hash = "");
 	UnitsyncGame GetGame(const std::string& gamename);
 	UnitsyncGame GetGame(int index);
 
@@ -60,7 +60,7 @@ public:
 
 	StringVector GetMapList() const;
 	StringVector GetGameValidMapList(const std::string& gamename) const;
-	bool MapExists(const std::string& mapname, const std::string& hash = "") const;
+	bool MapExists(const std::string& mapname, const std::string& hash = "");
 
 	UnitsyncMap GetMap(const std::string& mapname);
 	UnitsyncMap GetMap(int index);
@@ -131,6 +131,8 @@ public:
 	std::string GetUnitsCacheFilePath(const std::string& gamename) const;
 
 private:
+	std::string GetMapHash(const std::string& name);
+	std::string GetGameHash(const std::string& name);
 	bool GetImageFromCache(const std::string& cachefile, UnitsyncImage& img, ImageType imgtype);
 	UnitsyncImage GetImageFromUS(const std::string& mapname, const MapInfo& info, ImageType imgtype);
 
diff --git a/src/downloader/lib/src/main.cpp b/src/downloader/lib/src/main.cpp
index b7ab968..90b558f 100644
--- a/src/downloader/lib/src/main.cpp
+++ b/src/downloader/lib/src/main.cpp
@@ -23,6 +23,7 @@ enum {
 	WIDGET_SEARCH,
 	FILESYSTEM_WRITEPATH,
 	FILESYSTEM_DUMPSDP,
+	FILESYSTEM_VALIDATESDP,
 	DOWNLOAD_MAP,
 	DOWNLOAD_GAME,
 	DOWNLOAD_ENGINE,
@@ -38,6 +39,7 @@ static struct option long_options[] = {
     {"rapid-validate", 0, 0, RAPID_VALIDATE},
     {"delete", 0, 0, RAPID_VALIDATE_DELETE},
     {"dump-sdp", 1, 0, FILESYSTEM_DUMPSDP},
+    {"validate-sdp", 1, 0, FILESYSTEM_VALIDATESDP},
     {"http-download", 1, 0, HTTP_DOWNLOAD},
     {"http-search", 1, 0, HTTP_SEARCH},
     {"download-map", 1, 0, DOWNLOAD_MAP},
@@ -142,6 +144,10 @@ int main(int argc, char** argv)
 				DownloadDumpSDP(optarg);
 				break;
 			}
+			case FILESYSTEM_VALIDATESDP: {
+				ValidateSDP(optarg);
+				break;
+			}
 			case FILESYSTEM_WRITEPATH: {
 				DownloadSetConfig(CONFIG_FILESYSTEM_WRITEPATH, optarg);
 				break;
diff --git a/src/downloader/lib/src/pr-downloader.cpp b/src/downloader/lib/src/pr-downloader.cpp
index 80a8258..df56c8e 100644
--- a/src/downloader/lib/src/pr-downloader.cpp
+++ b/src/downloader/lib/src/pr-downloader.cpp
@@ -145,6 +145,7 @@ bool DownloadGetInfo(int id, downloadInfo& info)
 	if (dl != NULL) {
 		strncpy(info.filename, dl->name.c_str(),
 			NAME_LEN - 1); // -1 because of 0 termination
+		info.cat = dl->cat;
 		return true;
 	}
 	return false;
@@ -278,6 +279,11 @@ bool DownloadDumpSDP(const char* path)
 	return fileSystem->dumpSDP(path);
 }
 
+bool ValidateSDP(const char* path)
+{
+	return fileSystem->validateSDP(path);
+}
+
 void DownloadDisableLogging(bool disableLogging)
 {
 	LOG_DISABLE(disableLogging);
@@ -287,8 +293,8 @@ void DownloadDisableLogging(bool disableLogging)
 char* CalcHash(const char* str, int size, int type)
 {
 	const unsigned char* hash;
+	MD5_CTX ctx;
 	if (type == 0) {
-		MD5_CTX ctx;
 		MD5Init(&ctx);
 		MD5Update(&ctx, (unsigned char*)str, size);
 		MD5Final(&ctx);
@@ -303,3 +309,8 @@ char* CalcHash(const char* str, int size, int type)
 	ret[encoded.size()] = '\0';
 	return ret;
 }
+
+void SetAbortDownloads(bool value)
+{
+	IDownloader::SetAbortDownloads(value);
+}
diff --git a/src/downloader/lib/src/pr-downloader.h b/src/downloader/lib/src/pr-downloader.h
index 844d216..ef50d71 100644
--- a/src/downloader/lib/src/pr-downloader.h
+++ b/src/downloader/lib/src/pr-downloader.h
@@ -81,6 +81,11 @@ extern bool DownloadRapidValidate(bool deletebroken);
 extern bool DownloadDumpSDP(const char* path);
 
 /**
+* validate sdp files
+*/
+extern bool ValidateSDP(const char* path);
+
+/**
 * control printing to stdout
 */
 extern void DownloadDisableLogging(bool disableLogging);
@@ -95,4 +100,11 @@ extern void SetDownloadListener(IDownloaderProcessUpdateListener listener);
  *   0 - md5
 */
 extern char* CalcHash(const char* str, int size, int type);
+
+/**
+* abort all downloads - must be called before shutting down,
+* all downloads must return before calling shutdown
+*/
+extern void SetAbortDownloads(bool value);
+
 #endif
diff --git a/src/downloader/lib/test/CMakeLists.txt b/src/downloader/lib/test/CMakeLists.txt
index 862a504..c1165a2 100644
--- a/src/downloader/lib/test/CMakeLists.txt
+++ b/src/downloader/lib/test/CMakeLists.txt
@@ -4,7 +4,7 @@ FIND_PACKAGE(Boost 1.35.0 COMPONENTS unit_test_framework)
 IF(NOT Boost_FOUND)
 	Message(STATUS "Note: Unit tests will not be built: Boost::test library was not found")
 Else()
-	add_custom_target(check ${CMAKE_CTEST_COMMAND} --output-on-failure)
+	add_custom_target(checkDownloader ${CMAKE_CTEST_COMMAND} --output-on-failure)
 	If (NOT (WIN32 OR Boost_USE_STATIC_LIBS))
 		#Win32 tests links static
 		add_definitions(-DBOOST_TEST_DYN_LINK)
@@ -26,18 +26,19 @@ Else()
 
 	target_include_directories(prd_test
 		PRIVATE ${Boost_INCLUDE_DIRS}
-	)	
+	)
 #	target_include_directories(libSpringLobby_test
 #		PRIVATE ${libSpringLobby_SOURCE_DIR}/src
 #	)
 
 
-
 ################################################################################
 ### libSpringLobby
 
+if (PRD_ENABLE_LSL)
+
 SET(basic_testSrc
-	${CMAKE_CURRENT_SOURCE_DIR}/lsl/basic.cpp 
+	${CMAKE_CURRENT_SOURCE_DIR}/lsl/basic.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/lsl/usync.cpp
 	)
 
@@ -53,6 +54,8 @@ IF( NOT WIN32 )
 	TARGET_LINK_LIBRARIES(libSpringLobby_test X11 )
 ENDIF()
 
+endif(PRD_ENABLE_LSL)
+
 ################################################################################
 ### swig
 
diff --git a/src/gui/chatpanel.cpp b/src/gui/chatpanel.cpp
index 00e5e04..4eca171 100644
--- a/src/gui/chatpanel.cpp
+++ b/src/gui/chatpanel.cpp
@@ -935,7 +935,7 @@ bool ChatPanel::Say(const wxString& message) //FIXME: remove all parsing / token
 	}
 	while (lines.HasMoreTokens()) {
 		wxString line = lines.GetNextToken();
-		wxLogMessage(_T( "line: %s" ), line.c_str());
+		wxLogDebug(_T( "line: %s" ), line.c_str());
 
 		if (line == "/help") {
 			ui().ConsoleHelp();
diff --git a/src/gui/singleplayertab.cpp b/src/gui/singleplayertab.cpp
index d42a600..8685fed 100644
--- a/src/gui/singleplayertab.cpp
+++ b/src/gui/singleplayertab.cpp
@@ -343,6 +343,9 @@ bool SinglePlayerTab::ValidSetup() const
 void SinglePlayerTab::OnMapSelect(wxCommandEvent& /*unused*/)
 {
 	unsigned int index = (unsigned int)m_map_pick->GetCurrentSelection();
+
+	if (index >= m_map_pick->GetCount() - 1) { return; } 
+
 	SetMap(index);
 }
 
@@ -350,6 +353,9 @@ void SinglePlayerTab::OnMapSelect(wxCommandEvent& /*unused*/)
 void SinglePlayerTab::OnModSelect(wxCommandEvent& /*unused*/)
 {
 	unsigned int index = (unsigned int)m_mod_pick->GetCurrentSelection();
+
+	if (index >= m_mod_pick->GetCount() - 1) { return; }
+
 	size_t num_bots = m_battle.GetNumBots();
 	SetMod(index);
 	if (num_bots != m_battle.GetNumBots())
@@ -358,9 +364,13 @@ void SinglePlayerTab::OnModSelect(wxCommandEvent& /*unused*/)
 
 void SinglePlayerTab::OnEngineSelect(wxCommandEvent& /*event*/)
 {
-	SlPaths::SetUsedSpringIndex(STD_STRING(m_engine_pick->GetString(m_engine_pick->GetSelection())));
+	int index = m_engine_pick->GetSelection();
+
+	if (static_cast<unsigned int>(index) >= (m_engine_pick->GetCount() - 1)) { return; }	
+
+	SlPaths::SetUsedSpringIndex(STD_STRING(m_engine_pick->GetString(index)));
 	LSL::usync().ReloadUnitSyncLib();
-	m_battle.SetEngineVersion(STD_STRING(m_engine_pick->GetString(m_engine_pick->GetSelection())));
+	m_battle.SetEngineVersion(STD_STRING(m_engine_pick->GetString(index)));
 }
 
 void SinglePlayerTab::OnMapBrowse(wxCommandEvent& /*unused*/)
diff --git a/src/gui/ui.cpp b/src/gui/ui.cpp
index 9e7552b..98cac82 100644
--- a/src/gui/ui.cpp
+++ b/src/gui/ui.cpp
@@ -638,20 +638,6 @@ void Ui::OnUserBattleStatus(User& user)
 	OnBattleInfoUpdated(*battle, wxEmptyString);
 }
 
-
-void Ui::OnRequestBattleStatus(IBattle& battle)
-{
-	if (m_main_win == 0)
-		return;
-	try {
-		if (mw().GetJoinTab().GetBattleRoomTab().GetBattle() == &battle) {
-			mw().GetJoinTab().GetBattleRoomTab().GetBattle()->OnRequestBattleStatus();
-		}
-	} catch (...) {
-	}
-}
-
-
 void Ui::OnSaidBattle(IBattle& /*battle*/, const wxString& nick, const wxString& msg)
 {
 	if (m_main_win == 0)
diff --git a/src/gui/ui.h b/src/gui/ui.h
index 87fc3e5..df69e2d 100644
--- a/src/gui/ui.h
+++ b/src/gui/ui.h
@@ -88,7 +88,6 @@ public:
 	void OnJoinedBattle(IBattle& battle);
 	void OnHostedBattle(IBattle& battle);
 	void OnUserBattleStatus(User& user);
-	void OnRequestBattleStatus(IBattle& battle);
 
 	void OnSaidBattle(IBattle& battle, const wxString& nick, const wxString& msg);
 
diff --git a/src/ibattle.cpp b/src/ibattle.cpp
index 428967b..93f9eef 100644
--- a/src/ibattle.cpp
+++ b/src/ibattle.cpp
@@ -67,19 +67,19 @@ bool IBattle::IsSynced()
 	LoadGame();
 	LoadMap();
 	if (!m_host_game.name.empty() && m_local_game.name != m_host_game.name) {
-		wxLogWarning("Not synced: game name doesn't match: '%s' '%s'", m_host_game.name.c_str(), m_local_game.name.c_str());
+		wxLogWarning("Not synced: game name doesn't match host:'%s' local:'%s'", m_host_game.name.c_str(), m_local_game.name.c_str());
 		return false;
 	}
 	if (!m_host_map.name.empty() && m_local_map.name != m_host_map.name) {
-		wxLogWarning("Not synced: map name doesn't match: '%s' '%s'", m_host_map.name.c_str(), m_local_map.name.c_str());
+		wxLogWarning("Not synced: map name doesn't match host:'%s' local:'%s'", m_host_map.name.c_str(), m_local_map.name.c_str());
 		return false;
 	}
 	if (!m_host_game.hash.empty() && m_host_game.hash != "0" && m_host_game.hash != m_local_game.hash) {
-		wxLogWarning("Not synced: game hash doesn't match: '%s' '%s'", m_host_game.hash.c_str(), m_local_game.hash.c_str());
+		wxLogWarning("Not synced: game hash doesn't match host:'%s' local:'%s'", m_host_game.hash.c_str(), m_local_game.hash.c_str());
 		return false;
 	}
 	if (!m_host_map.hash.empty() && m_host_map.hash != "0" && m_host_map.hash != m_local_map.hash) {
-		wxLogWarning("Not synced: map hash doesn't match: '%s' '%s'", m_host_map.hash.c_str(), m_local_map.hash.c_str());
+		wxLogWarning("Not synced: map hash doesn't match host:'%s' local:'%s'", m_host_map.hash.c_str(), m_local_map.hash.c_str());
 		return false;
 	}
 	if (!GameExists()) {
@@ -761,11 +761,12 @@ std::string IBattle::GetHostMapHash() const
 void IBattle::SetHostGame(const std::string& gamename, const std::string& hash)
 {
 	assert(hash.empty() || LSL::Util::MakeHashUnsigned(hash) == hash);
-	if (m_host_game.name != gamename || m_host_game.hash != hash) {
-		m_game_loaded = false;
-		m_host_game.name = gamename;
-		m_host_game.hash = hash;
+	if ((m_host_game.name == gamename) && (m_host_game.hash == hash)) {
+		return;
 	}
+	m_game_loaded = false;
+	m_host_game.name = gamename;
+	m_host_game.hash = hash;
 }
 
 
@@ -775,28 +776,31 @@ void IBattle::SetLocalGame(const LSL::UnitsyncGame& mod)
 	if (mod.hash.empty()) {
 		wxLogWarning("empty hash: %s", mod.name);
 	}
-	if (mod.name != m_local_game.name || mod.hash != m_local_game.hash) {
-		m_previous_local_game_name = m_local_game.name;
-		m_local_game = mod;
-		m_game_loaded = true;
+	if ((mod.name == m_local_game.name) && (mod.hash == m_local_game.hash)) {
+		return;
 	}
+	m_previous_local_game_name = m_local_game.name;
+	m_local_game = mod;
+	m_game_loaded = true;
 }
 
 
 const LSL::UnitsyncGame& IBattle::LoadGame()
 {
 	ASSERT_LOGIC(!m_host_game.name.empty(), "m_host_game.name.empty() is FALSE");
-	if (!m_game_loaded) {
-		if (GameExists(true)) {
-			try {
-				SetLocalGame(LSL::usync().GetGame(m_host_game.name));
-				bool options_loaded = CustomBattleOptions().loadOptions(LSL::Enum::ModOption, m_host_game.name);
-				ASSERT_EXCEPTION(options_loaded, _T("couldn't load the game options"));
-				m_game_loaded = true;
-			} catch (...) {
-			}
-		}
+	if (m_game_loaded) {
+		return m_local_game;
+	}
+	if (!GameExists(true)) {
+		wxLogWarning("Game doesn't exist");
+		return m_local_game;
 	}
+	try {
+		SetLocalGame(LSL::usync().GetGame(m_host_game.name));
+		bool options_loaded = CustomBattleOptions().loadOptions(LSL::Enum::ModOption, m_host_game.name);
+		ASSERT_EXCEPTION(options_loaded, _T("couldn't load the game options"));
+		m_game_loaded = true;
+	} catch (...) {	}
 	return m_local_game;
 }
 
diff --git a/src/serverevents.cpp b/src/serverevents.cpp
index 68e07e8..5ff6d4b 100644
--- a/src/serverevents.cpp
+++ b/src/serverevents.cpp
@@ -715,7 +715,7 @@ void ServerEvents::OnRequestBattleStatus(int battleid)
 {
 	try {
 		IBattle& battle = m_serv.GetBattle(battleid);
-		ui().OnRequestBattleStatus(battle);
+		battle.OnRequestBattleStatus();
 	} catch (assert_exception) {
 	}
 }
diff --git a/src/socket.cpp b/src/socket.cpp
index 310dc17..ab541df 100644
--- a/src/socket.cpp
+++ b/src/socket.cpp
@@ -46,7 +46,7 @@ bool GetMac(std::vector<unsigned char>& mac)
 
 	DWORD dwStatus = GetAdaptersInfo(AdapterInfo, &dwBufLen); // Get info
 	if (dwStatus != NO_ERROR)
-		return wxEmptyString; // Check status
+		return false; // Check status
 	for (size_t i = 0; i < sizeof(AdapterInfo); i++) {
 		mac.resize(AdapterInfo[i].AddressLength);
 		mac.assign(AdapterInfo[i].Address, AdapterInfo[i].Address + AdapterInfo[i].AddressLength);
diff --git a/src/springlobbyapp.cpp b/src/springlobbyapp.cpp
index f92956d..b6686af 100644
--- a/src/springlobbyapp.cpp
+++ b/src/springlobbyapp.cpp
@@ -31,6 +31,7 @@
 #include <wx/utils.h>
 #include <wx/wfstream.h>
 
+#include "stacktrace.h"
 #include "springlobbyapp.h"
 #include "gui/mainwindow.h"
 #include "settings.h"
@@ -222,6 +223,12 @@ int SpringLobbyApp::OnExit()
 void SpringLobbyApp::OnFatalException()
 {
 	wxLogError("Fatal exception!");
+
+	StackTrace stackTracer;
+	stackTracer.WalkFromException();
+	auto trace = stackTracer.GetStackTrace();
+
+	wxLogError("Stack trace: " + trace);	
 }
 
 
diff --git a/src/stacktrace.h b/src/stacktrace.h
index 18017bd..d07c955 100644
--- a/src/stacktrace.h
+++ b/src/stacktrace.h
@@ -30,10 +30,12 @@ private:
 #else
 class StackTrace
 {
+public:
 	wxString GetStackTrace() const
 	{
 		return wxEmptyString;
 	}
+	void WalkFromException() {}
 };
 
 #endif
diff --git a/src/sysinfo.cpp b/src/sysinfo.cpp
index 9c30102..0e85a12 100644
--- a/src/sysinfo.cpp
+++ b/src/sysinfo.cpp
@@ -67,6 +67,11 @@ std::string GetSpringlobbyInfo()
 	getWritePaths(paths);
 	for (size_t i = 0; i < paths.size(); ++i) {
 		std::string path = paths[i].m_path;
+
+		if (path.empty()) {
+			continue;
+		}
+		
 #if defined(__WIN32__) || defined(_MSC_VER)
 		path = Utf8ToLocalEncoding(path.c_str());
 #endif
diff --git a/src/tasserver.cpp b/src/tasserver.cpp
index 46885e3..5e7fd8d 100644
--- a/src/tasserver.cpp
+++ b/src/tasserver.cpp
@@ -724,7 +724,10 @@ void TASServer::ExecuteCommand(const std::string& cmd, const std::string& inpara
 		m_se->OnPrivateMessageEx(user, user, params);
 	} else if (cmd == "JOINBATTLE") {
 		const int id = GetIntParam(params);
-		const std::string hash = LSL::Util::MakeHashUnsigned(GetWordParam(params));
+		std::string hash = LSL::Util::MakeHashUnsigned(GetWordParam(params));
+		if (hash == "0") {
+			hash.clear();
+		}
 		m_battle_id = id;
 		m_se->OnJoinedBattle(id, hash);
 		m_se->OnBattleInfoUpdated(m_battle_id);
@@ -985,12 +988,20 @@ void TASServer::SendCmd(const std::string& command, const std::string& param, bo
 		return;
 	}
 
-	if (command != "PING") { //don't log PING
-		if (send_success)
-			wxLogMessage(wxString::Format(_T("sent: %s"), msg.c_str()));
-		else
-			wxLogMessage(wxString::Format(_T("sending: %s failed"), msg.c_str()));
-	}
+	if (command == "PING") return;
+	if (command == "SAY") return;
+	if (command == "SAYEX") return;
+	if (command == "SAYPRIVATE") return;
+	if (command == "SAYPRIVATEEX") return;
+	if (command == "SAYBATTLE") return;
+	if (command == "SAYBATTLEEX") return;
+	if (command == "SAYBATTLEPRIVATE") return;
+	if (command == "SAYBATTLEPRIVATEEX") return;
+
+	if (send_success)
+		wxLogMessage(wxString::Format(_T("sent: %s"), msg.c_str()));
+	else
+		wxLogMessage(wxString::Format(_T("sending: %s failed"), msg.c_str()));
 }
 
 void TASServer::SetRelayIngamePassword(const User& user)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/springlobby.git



More information about the Pkg-games-commits mailing list