diff --git a/game/engines/default/engine/Module.lua b/game/engines/default/engine/Module.lua
index b9824f7e4829c59665a5e11f09903d17e68bc225..ec24a6e6c50615ea74ef1fd918bf77d96fcf0dbe 100644
--- a/game/engines/default/engine/Module.lua
+++ b/game/engines/default/engine/Module.lua
@@ -232,7 +232,10 @@ function _M:instanciate(mod, name, new_game, no_reboot)
 	table.sort(md5s)
 	local fmd5 = md5.sumhexa(table.concat(md5s))
 	print("[MODULE LOADER] module MD5", fmd5, "computed in ", core.game.getTime() - t)
-	local hash_valid, hash_err = profile:checkModuleHash(mod.version_name, fmd5)
+	local hash_valid, hash_err
+	if mod.short_name ~= "boot" then
+		hash_valid, hash_err = profile:checkModuleHash(mod.version_name, fmd5)
+	end
 
 	-- If bad hash, switch to dev profile
 	if not hash_valid and not profile.auth then
@@ -272,7 +275,7 @@ function _M:instanciate(mod, name, new_game, no_reboot)
 	-- Disable the profile if ungood
 	if mod.short_name ~= "boot" then
 		if not hash_valid then
-			game.log("#LIGHT_RED#Profile disabled(switching to development profile) due to %s.", hash_err)
+			game.log("#LIGHT_RED#Profile disabled(switching to development profile) due to %s.", hash_err or "???")
 		end
 	end
 end
diff --git a/game/engines/default/engine/PlayerProfile.lua b/game/engines/default/engine/PlayerProfile.lua
index 832e5ab7da6402c480508953f6d6caefd1fa6ac3..8baea00de1cf95dac7bb56bd45a7d16f5c3326c4 100644
--- a/game/engines/default/engine/PlayerProfile.lua
+++ b/game/engines/default/engine/PlayerProfile.lua
@@ -84,8 +84,6 @@ function _M:init(name)
 		self.login = self.generic.online.login
 		self.pass = self.generic.online.pass
 		self:tryAuth()
-		self:getConfigs("generic")
-		self:syncOnline("generic")
 	end
 end
 
@@ -192,15 +190,24 @@ function _M:saveModuleProfile(name, data, module, nosync)
 	if not nosync then self:setConfigs(module, name, data) end
 end
 
+function _M:checkFirstRun()
+	local result = self.generic.firstrun
+	if not result then
+		firstrun = { When=os.time() }
+		self:saveGenericProfile("firstrun", firstrun, false)
+	end
+	return result
+end
+
 -----------------------------------------------------------------------
 -- Events
 -----------------------------------------------------------------------
 
 function _M:eventAuth(e)
 	if e.ok then
-		print("===", e.ok)
 		self.auth = e.ok:unserialize()
 		print("[PROFILE] Main thread got authed", self.auth.name, self.auth.email, self.auth.drupid)
+		self:getConfigs("generic", function(e) self:syncOnline(e.module) end)
 	end
 end
 
@@ -211,6 +218,33 @@ function _M:eventGetNews(e)
 	end
 end
 
+function _M:eventGetConfigs(e)
+	local data = e.data:unserialize()
+	local module = e.module
+	if not data then print("[ONLINE PROFILE] get configs") return end
+	for name, val in pairs(data) do
+		print("[ONLINE PROFILE] config ", name)
+
+		local field = name
+		local f, err = loadstring(val)
+		if not f and err then
+			print("Error loading profile config: ", err)
+		else
+			if module == "generic" then
+				self.generic[field] = self.generic[field] or {}
+				self:loadData(f, self.generic[field])
+				self:saveGenericProfile(field, self.generic[field], true)
+			else
+				self.modules[module] = self.modules[module] or {}
+				self.modules[module][field] = self.modules[module][field] or {}
+				self:loadData(f, self.modules[module][field])
+				self:saveModuleProfile(field, self.modules[module][field], module, true)
+			end
+		end
+	end
+	if self.evt_cbs.GetConfigs then self.evt_cbs.GetConfigs(e) self.evt_cbs.GetConfigs = nil end
+end
+
 --- Got an event from the profile thread
 function _M:handleEvent(e)
 	e = e:unserialize()
@@ -223,55 +257,10 @@ end
 -- Online stuff
 -----------------------------------------------------------------------
 
-function _M:rpc(data)
-	-- We can work in asynchronous mode, to not delay the main game execution
-	if data.async and game and type(game) == "table" and not game.refuse_threads then
-		data.async = nil
-		local l = lanes.linda()
-
-		function handler(data)
-			local http = require "socket.http"
-			local url = require "socket.url"
-			require "Json2"
-
-			print("[ONLINE PROFILE] async rpc called", "http://te4.org/lua/profilesrpc.ws/"..data.action)
-			local body, status = http.request("http://te4.org/lua/profilesrpc.ws/"..data.action, "json="..url.escape(json.encode(data)))
-			if not body then
-				l:send("final", nil)
-			else
-				local ok, ret = pcall(json.decode, body)
-				l:send("final", ok and ret or nil)
-			end
-			return true
-		end
-
-		local th = lanes.gen("*", handler)(data)
-		-- Tell the game to monitor this thread and end it when it's done
-		game:registerThread(th, l)
-
-		return th, l
-	else
-		print("[ONLINE PROFILE] rpc called", "http://te4.org/lua/profilesrpc.ws/"..data.action)
-		local body, status = http.request("http://te4.org/lua/profilesrpc.ws/"..data.action, "json="..url.escape(json.encode(data)))
-		if not body then return end
-		local ok, ret = pcall(json.decode, body)
-		return ok and ret or nil
-	end
-end
-
 function _M:getNews(callback)
 	print("[ONLINE PROFILE] get news")
-	core.profile.pushOrder("o='GetNews'")
 	self.evt_cbs.GetNews = callback
-end
-
-function _M:sendError(what, err)
-	print("[ONLINE PROFILE] sending error")
-	local popup = Dialog:simplePopup("Sending...", "Sending the error report. Thank you.", nil, true)
-	popup.__showup = nil
-	core.display.forceRedraw()
-	self:rpc{action="SendError", login=self.login, what=what, err=err, module=game.__mod_info.short_name, version=game.__mod_info.version_name}
-	game:unregisterDialog(popup)
+	core.profile.pushOrder("o='GetNews'")
 end
 
 function _M:tryAuth()
@@ -279,41 +268,28 @@ function _M:tryAuth()
 	core.profile.pushOrder(table.serialize{o="Login", l=self.login, p=self.pass})
 end
 
-function _M:getConfigs(module)
-	if not self.auth then return end
-	local data = self:rpc{action="GetConfigs", login=self.login, hash=self.auth.hash, module=module}
-	if not data then print("[ONLINE PROFILE] get configs") return end
-	for name, val in pairs(data) do
-		print("[ONLINE PROFILE] config ", name)
+function _M:logOut()
+	core.profile.pushOrder(table.serialize{o="Logoff"})
+	profile.generic.online = nil
+	profile.auth = nil
 
-		local field = name
-		local f, err = loadstring(val)
-		if not f and err then
-			print("Error loading profile config: ", err)
-		else
-			if module == "generic" then
-				self.generic[field] = self.generic[field] or {}
-				self:loadData(f, self.generic[field])
-				self:saveGenericProfile(field, self.generic[field], true)
-			else
-				self.modules[module] = self.modules[module] or {}
-				self.modules[module][field] = self.modules[module][field] or {}
-				self:loadData(f, self.modules[module][field])
-				self:saveModuleProfile(field, self.modules[module][field], module, true)
-			end
-		end
-	end
+	local restore = fs.getWritePath()
+	fs.setWritePath(engine.homepath)
+	fs.delete("/profiles/"..self.name.."/generic/online.profile")
+	if restore then fs.setWritePath(restore) end
+end
+
+function _M:getConfigs(module, cb)
+	if not self.auth then return end
+	self.evt_cbs.GetConfigs = cb
+	core.profile.pushOrder(table.serialize{o="GetConfigs", module=module})
 end
 
 function _M:setConfigs(module, name, val)
 	if not self.auth then return end
 	if name == "online" then return end
-
 	if type(val) ~= "string" then val = serialize(val) end
-
-	local data = self:rpc{async=true, action="SetConfigs", login=self.login, hash=self.auth.hash, module=module, data={[name] = val}}
-	if not data then return end
-	print("[ONLINE PROFILE] saved ", module, name, val)
+	core.profile.pushOrder(table.serialize{o="SetConfigs", module=module, data=table.serialize{[name] = val}})
 end
 
 function _M:syncOnline(module)
@@ -325,9 +301,46 @@ function _M:syncOnline(module)
 	local data = {}
 	for k, v in pairs(sync) do if k ~= "online" then data[k] = serialize(v) end end
 
-	local data = self:rpc{async=true, action="SetConfigs", login=self.login, hash=self.auth.hash, module=module, data=data}
-	if not data then return end
-	print("[ONLINE PROFILE] saved ", module)
+	core.profile.pushOrder(table.serialize{o="SetConfigs", module=module, data=table.serialize(data)})
+end
+
+function _M:checkModuleHash(module, md5)
+	self.hash_valid = false
+--	if not self.auth then return nil, "no online profile active" end
+--	if config.settings.cheat then return nil, "cheat mode active" end
+--	if game and game:isTainted() then return nil, "savefile tainted" end
+	core.profile.pushOrder(table.serialize{o="CheckModuleHash", module=module, md5=md5})
+
+	-- Wait anwser, this blocks thegame but cant really be avoided :/
+	local stop = false
+	local ok = false
+	while not stop do
+		local evt = core.profile.popEvent()
+		while evt do
+			evt = self:handleEvent(evt) -- Bypass game handling, there is none around at this point
+			if evt.e == "CheckModuleHash" then
+				ok = evt.ok
+				stop = true
+				break
+			end
+			evt = core.profile.popEvent()
+		end
+	end
+
+	if not ok then return nil, "bad game version" end
+	print("[ONLINE PROFILE] module hash is valid")
+	self.hash_valid = true
+	return true
+end
+
+--[[
+function _M:sendError(what, err)
+	print("[ONLINE PROFILE] sending error")
+	local popup = Dialog:simplePopup("Sending...", "Sending the error report. Thank you.", nil, true)
+	popup.__showup = nil
+	core.display.forceRedraw()
+	self:rpc{action="SendError", login=self.login, what=what, err=err, module=game.__mod_info.short_name, version=game.__mod_info.version_name}
+	game:unregisterDialog(popup)
 end
 
 function _M:newProfile(Login, Name, Password, Email)
@@ -351,25 +364,6 @@ function _M:performlogin(login, pass, name, email)
 	end
 end
 
-function _M:logOut()
-	profile.generic.online = nil
-	profile.auth = nil
-
-	local restore = fs.getWritePath()
-	fs.setWritePath(engine.homepath)
-	fs.delete("/profiles/"..self.name.."/generic/online.profile")
-	if restore then fs.setWritePath(restore) end
-end
-
-function _M:checkFirstRun()
-	local result = self.generic.firstrun
-	if not result then
-		firstrun = { When=os.time() }
-		self:saveGenericProfile("firstrun", firstrun, false)
-	end
-	return result
-end
-
 function _M:registerNewCharacter(module)
 	if not self.auth or not self.hash_valid then return end
 	local dialog = Dialog:simplePopup("Registering character", "Character is being registered on http://te4.org/") dialog.__showup = nil core.display.forceRedraw()
@@ -388,15 +382,4 @@ function _M:registerSaveChardump(module, uuid, title, tags, data)
 	if not data or not data.ok then return end
 	print("[ONLINE PROFILE] saved character ", uuid)
 end
-
-function _M:checkModuleHash(module, md5)
-	self.hash_valid = false
-	if not self.auth then return nil, "no online profile active" end
-	if config.settings.cheat then return nil, "cheat mode active" end
-	if game and game:isTainted() then return nil, "savefile tainted" end
-	local data = self:rpc{action="CheckModuleHash", login=self.login, hash=self.auth.hash, module=module, md5=md5}
-	if not data or not data.ok then return nil, "bad game version" end
-	print("[ONLINE PROFILE] module hash is valid")
-	self.hash_valid = true
-	return true
-end
+]]
diff --git a/game/profile-thread/Client.lua b/game/profile-thread/Client.lua
index 5455fd96fe6e16697cc949362d58777687f6c2bd..34d4f3c9d159333fcac7f1bf264dfca167cd35ad 100644
--- a/game/profile-thread/Client.lua
+++ b/game/profile-thread/Client.lua
@@ -101,8 +101,8 @@ end
 
 function _M:orderLogin(o)
 	-- Already logged?
-	if self.auth and self.auth.login == o.login then
-		print("[PROFILE] reusing login")
+	if self.auth and self.auth.login == o.l then
+		print("[PROFILE] reusing login", self.auth.name)
 		cprofile.pushEvent(string.format("e='Auth' ok=%q", table.serialize(self.auth)))
 	else
 		self.user_login = o.l
@@ -125,7 +125,37 @@ function _M:orderGetNews(o)
 	end
 end
 
+function _M:orderGetConfigs(o)
+	if not self.auth then return end
+	self:command("GCFS", o.module)
+	if self:read("200") then
+		local _, _, size = self.last_line:find("^([0-9]+)")
+		size = tonumber(size)
+		if not size or size < 1 then return end
+		local body = self.sock:receive(size)
+		cprofile.pushEvent(string.format("e='GetConfigs' module=%q data=%q", o.module, body))
+	end
+end
+
+function _M:orderSetConfigs(o)
+	if not self.auth then return end
+	self:command("SCFS", o.data:len(), o.module)
+	if self:read("200") then
+		self.sock:send(o.data)
+	end
+end
+
+function _M:orderCheckModuleHash(o)
+	self:command("CMD5", o.md5, o.module)
+	if self:read("200") then
+		cprofile.pushEvent("e='CheckModuleHash' ok=true")
+	else
+		cprofile.pushEvent("e='CheckModuleHash' ok=false")
+	end
+end
+
 function _M:handleOrder(o)
+	if not self.sock then return end
 	o = o:unserialize()
 	if self["order"..o.o] then self["order"..o.o](self, o) end
 end
diff --git a/src/profile.c b/src/profile.c
index 0239999fa71d13b9fd32d5fc6e7805a25294ba08..477ad459362bc616230f3a91ffb15e7349c5ea42 100644
--- a/src/profile.c
+++ b/src/profile.c
@@ -35,6 +35,7 @@ int push_order(lua_State *L)
 {
 	size_t len;
 	const char *code = luaL_checklstring(L, 1, &len);
+	printf("[profile order] %s\n", code);
 
 	profile_queue *q = malloc(sizeof(profile_queue));
 	char *d = calloc(len, sizeof(char));
@@ -80,6 +81,7 @@ int push_event(lua_State *L)
 {
 	size_t len;
 	const char *code = luaL_checklstring(L, 1, &len);
+	printf("[profile event] %s\n", code);
 
 	profile_queue *q = malloc(sizeof(profile_queue));
 	char *d = calloc(len, sizeof(char));