diff --git a/build/te4core.lua b/build/te4core.lua
index 9438c26b4bf810563a9f1085d88626c601d5764c..8222e1f3833ba6e51746ba843d9cae544ff7b5b3 100644
--- a/build/te4core.lua
+++ b/build/te4core.lua
@@ -82,6 +82,7 @@ project "TEngine"
 			"-framework libpng",
 			"-framework ogg",
 			"-framework vorbis",
+			"-Wl,-rpath,'@loader_path/../Frameworks'",
 		}
 		if _OPTIONS.lua == "jit2" then
 			linkoptions {
diff --git a/game/engines/default/engine/ui/Dialog.lua b/game/engines/default/engine/ui/Dialog.lua
index 3f875375f13bf6d7875f140a692df32b8b0a0844..d13ab7513231ae8fbe431e49054a1a2b37997282 100644
--- a/game/engines/default/engine/ui/Dialog.lua
+++ b/game/engines/default/engine/ui/Dialog.lua
@@ -193,7 +193,7 @@ end
 
 function _M:webPopup(url)
 	local d = new(url, game.w * 0.9, game.h * 0.9)
-	local w = require("engine.ui.WebView").new{width=d.iw, height=d.ih, url=url, allow_downloads={addons=true}}
+	local w = require("engine.ui.WebView").new{width=d.iw, height=d.ih, url=url, allow_downloads={addons=true, modules=true}}
 	w.on_title = function(title) d:updateTitle(title) end
 	d:loadUI{{left=0, top=0, ui=w}}
 	d:setupUI()
@@ -563,6 +563,10 @@ end
 --- This provides required cleanups, do not touch
 function _M:cleanup()
 	for p, _ in pairs(self.particles) do p:dieDisplay() end
+
+	for i = 1, #self.uis do
+		if self.uis[i].ui and self.uis[i].ui.on_dialog_cleanup then self.uis[i].ui:on_dialog_cleanup() end
+	end
 end
 
 function _M:drawFrame(x, y, r, g, b, a)
diff --git a/game/engines/default/engine/ui/WebView.lua b/game/engines/default/engine/ui/WebView.lua
index d261d1d56227011973603e514a462009f51f8e90..b7e23f0d2c63f02ab0a416023d15aeb160ed1e62 100644
--- a/game/engines/default/engine/ui/WebView.lua
+++ b/game/engines/default/engine/ui/WebView.lua
@@ -92,17 +92,48 @@ function _M:makeDownloadbox(file)
 	return d
 end
 
+function _M:on_dialog_cleanup()
+	self.downloader = nil
+	self.view = nil
+end
+
 function _M:onDownload(request, update, finish)
-	self.downloader = core.webview.downloader(function(url, file, mime)
-		if mime == "application/t-engine-addon" and self.allow_downloads.addons then
+	local Dialog = require "engine.ui.Dialog"
+
+	self.downloader = core.webview.downloader(function(downid, url, file, mime)
+		print(downid, url, file, mime)
+		if mime == "application/t-engine-addon" and self.allow_downloads.addons and url:find("^http://te4%.org/") then
 			local path = fs.getRealPath("/addons/")
 			if path then
-				print("Accepting addon download to:", path..file)
-				self.download_dialog = self:makeDownloadbox(file)
-				game:registerDialog(self.download_dialog)
-				return path..file
+				Dialog:yesnoPopup("Confirm addon install/update", "Are you sure you want to install this addon? ("..file..")", function(ret)
+					if ret then
+						print("Accepting addon download to:", path..file)
+						self.download_dialog = self:makeDownloadbox(file)
+						game:registerDialog(self.download_dialog)
+						self.view:downloadAction(downid, path..file)
+					else
+						self.view:downloadAction(downid, false)
+					end
+				end)
+				return
+			end
+		elseif mime == "application/t-engine-module" and self.allow_downloads.modules and url:find("^http://te4%.org/") then
+			local path = fs.getRealPath("/modules/")
+			if path then
+				Dialog:yesnoPopup("Confirm module install/update", "Are you sure you want to install this module? ("..file..")", function(ret)
+					if ret then
+						print("Accepting module download to:", path..file)
+						self.download_dialog = self:makeDownloadbox(file)
+						game:registerDialog(self.download_dialog)
+						self.view:downloadAction(downid, path..file)
+					else
+						self.view:downloadAction(downid, false)
+					end
+				end)
+				return
 			end
 		end
+		self.view:downloadAction(downid, false)
 	end, function(cur_size, total_size, speed)
 		self.download_dialog:updateFill(cur_size, total_size, ("%d%% - %d KB/s"):format(cur_size * 100 / total_size, speed / 1024))
 	end, function(url, saved_path)
diff --git a/src/web/web.cpp b/src/web/web.cpp
index 80ec4c586568f73bdd6bdc982f9cf4fe07a0df4a..b7ed7f01a54ba75dd6faca608e6de23f302ee374 100644
--- a/src/web/web.cpp
+++ b/src/web/web.cpp
@@ -36,6 +36,7 @@ typedef struct {
 	int on_request_ref;
 	int on_update_ref;
 	int on_finish_ref;
+	bool closed;
 } web_downloader_type;
 
 static char *webstring_to_buf(WebString *wstr, size_t *flen) {
@@ -52,12 +53,9 @@ class WebDownloader : public WebViewListener::Download {
 public:
 	web_downloader_type *d;
 	WebDownloader() {}
-	void OnRequestDownload(Awesomium::WebView* caller,
-		int download_id,
-		const Awesomium::WebURL& url,
-		const Awesomium::WebString& suggested_filename,
-		const Awesomium::WebString& mime_type) {
+	void OnRequestDownload(WebView* caller, int download_id, const WebURL& url, const WebString& suggested_filename, const WebString& mime_type) {
 		web_downloader_type *d = this->d;
+		if (d->closed) return;
 
 		size_t slen; char *sbuf = webstring_to_buf((WebString*)&suggested_filename, &slen);
 		size_t mlen; char *mbuf = webstring_to_buf((WebString*)&mime_type, &mlen);
@@ -65,28 +63,18 @@ public:
 		size_t ulen; char *ubuf = webstring_to_buf((WebString*)&rurl, &ulen);
 
 		lua_rawgeti(d->L, LUA_REGISTRYINDEX, d->on_request_ref);
+		lua_pushnumber(d->L, download_id);
 		lua_pushlstring(d->L, ubuf, ulen);
 		lua_pushlstring(d->L, sbuf, slen);
 		lua_pushlstring(d->L, mbuf, mlen);
-		lua_pcall(d->L, 3, 1, 0);
+		lua_pcall(d->L, 4, 0, 0);
 		free(sbuf);
 		free(mbuf);
 		free(ubuf);
-		if (lua_isstring(d->L, -1)) {
-			size_t len;
-			const char *buf = lua_tolstring(d->L, -1, &len);
-			WebString wpath = WebString::CreateFromUTF8(buf, len);
-			caller->DidChooseDownloadPath(download_id, wpath);
-		} else caller->DidCancelDownload(download_id);
-		lua_pop(d->L, 1);
 	}
-	void OnUpdateDownload(Awesomium::WebView* caller,
-		int download_id,
-		int64 total_bytes,
-		int64 received_bytes,
-		int64 current_speed) {
-
+	void OnUpdateDownload(WebView* caller, int download_id, int64 total_bytes, int64 received_bytes, int64 current_speed) {
 		web_downloader_type *d = this->d;
+		if (d->closed) return;
 
 		lua_rawgeti(d->L, LUA_REGISTRYINDEX, d->on_update_ref);
 		lua_pushnumber(d->L, received_bytes);
@@ -94,12 +82,9 @@ public:
 		lua_pushnumber(d->L, current_speed);
 		lua_pcall(d->L, 3, 0, 0);
 	}
-	void OnFinishDownload(Awesomium::WebView* caller,
-		int download_id,
-		const Awesomium::WebURL& url,
-		const Awesomium::WebString& saved_path) {
-
+	void OnFinishDownload(WebView* caller, int download_id, const WebURL& url, const WebString& saved_path) {
 		web_downloader_type *d = this->d;
+		if (d->closed) return;
 
 		WebString rurl = url.spec();
 		size_t ulen; char *ubuf = webstring_to_buf((WebString*)&rurl, &ulen);
@@ -136,8 +121,9 @@ static int lua_web_new(lua_State *L) {
 static int lua_web_close(lua_State *L) {
 	web_view_type *view = (web_view_type*)auxiliar_checkclass(L, "web{view}", 1);
 	if (!view->closed) {
-		view->view->Destroy();		
+		view->view->Destroy();
 		view->closed = true;
+		printf("Destroyed webview\n");
 	}
 	return 0;
 }
@@ -320,6 +306,7 @@ static int lua_downloader_new(lua_State *L) {
 	listener->d = new WebDownloader();
 	listener->d->d = listener;
 	listener->L = L;
+	listener->closed = false;
 
 	lua_pushvalue(L, 1);
 	listener->on_request_ref = luaL_ref(L, LUA_REGISTRYINDEX);
@@ -332,10 +319,27 @@ static int lua_downloader_new(lua_State *L) {
 
 static int lua_downloader_close(lua_State *L) {
 	web_downloader_type *listener = (web_downloader_type*)auxiliar_checkclass(L, "web{downloader}", 1);
-	luaL_unref(L, LUA_REGISTRYINDEX, listener->on_request_ref);
-	luaL_unref(L, LUA_REGISTRYINDEX, listener->on_update_ref);
-	luaL_unref(L, LUA_REGISTRYINDEX, listener->on_finish_ref);
-	delete listener->d;
+	if (!listener->closed) {
+		luaL_unref(L, LUA_REGISTRYINDEX, listener->on_request_ref);
+		luaL_unref(L, LUA_REGISTRYINDEX, listener->on_update_ref);
+		luaL_unref(L, LUA_REGISTRYINDEX, listener->on_finish_ref);
+		delete listener->d;
+		listener->closed = true;
+	}
+	return 0;
+}
+
+static int lua_web_download_action(lua_State *L) {
+	web_view_type *view = (web_view_type*)auxiliar_checkclass(L, "web{view}", 1);
+	if (view->closed) return 0;
+	int download_id = luaL_checknumber(L, 2);
+
+	if (lua_isstring(L, 3)) {
+		size_t len;
+		const char *buf = lua_tolstring(L, 3, &len);
+		WebString wpath = WebString::CreateFromUTF8(buf, len);
+		view->view->DidChooseDownloadPath(download_id, wpath);
+	} else view->view->DidCancelDownload(download_id);
 	return 0;
 }
 
@@ -343,6 +347,7 @@ static const struct luaL_Reg view_reg[] =
 {
 	{"__gc", lua_web_close},
 	{"downloader", lua_web_set_downloader},
+	{"downloadAction", lua_web_download_action},
 	{"toScreen", lua_web_toscreen},
 	{"focus", lua_web_focus},
 	{"loading", lua_web_loading},