]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - builtin/mainmenu/dlg_contentstore.lua
Merge branch 'master' of https://github.com/minetest/minetest
[dragonfireclient.git] / builtin / mainmenu / dlg_contentstore.lua
index 790da03bafc3fdcc01c9a4ae6378b6030b585147..ff32c8c9f7d0d689071ffa375eb32b9f14f37fe7 100644 (file)
@@ -25,7 +25,7 @@ end
 
 -- Unordered preserves the original order of the ContentDB API,
 -- before the package list is ordered based on installed state.
-local store = { packages = {}, packages_full = {}, packages_full_unordered = {} }
+local store = { packages = {}, packages_full = {}, packages_full_unordered = {}, aliases = {} }
 
 local http = core.get_http_api()
 
@@ -62,9 +62,19 @@ local REASON_UPDATE = "update"
 local REASON_DEPENDENCY = "dependency"
 
 
+-- encodes for use as URL parameter or path component
+local function urlencode(str)
+       return str:gsub("[^%a%d()._~-]", function(char)
+               return string.format("%%%02X", string.byte(char))
+       end)
+end
+assert(urlencode("sample text?") == "sample%20text%3F")
+
+
 local function get_download_url(package, reason)
        local base_url = core.settings:get("contentdb_url")
-       local ret = base_url .. ("/packages/%s/%s/releases/%d/download/"):format(package.author, package.name, package.release)
+       local ret = base_url .. ("/packages/%s/releases/%d/download/"):format(
+               package.url_part, package.release)
        if reason then
                ret = ret .. "?reason=" .. reason
        end
@@ -72,34 +82,52 @@ local function get_download_url(package, reason)
 end
 
 
-local function download_package(param)
-       if core.download_file(param.url, param.filename) then
+local function download_and_extract(param)
+       local package = param.package
+
+       local filename = core.get_temp_path(true)
+       if filename == "" or not core.download_file(param.url, filename) then
+               core.log("error", "Downloading " .. dump(param.url) .. " failed")
                return {
-                       filename = param.filename,
-                       successful = true,
+                       msg = fgettext("Failed to download $1", package.name)
                }
+       end
+
+       local tempfolder = core.get_temp_path()
+       if tempfolder ~= "" then
+               tempfolder = tempfolder .. DIR_DELIM .. "MT_" .. math.random(1, 1024000)
+               if not core.extract_zip(filename, tempfolder) then
+                       tempfolder = nil
+               end
        else
-               core.log("error", "downloading " .. dump(param.url) .. " failed")
+               tempfolder = nil
+       end
+       os.remove(filename)
+       if not tempfolder then
                return {
-                       successful = false,
+                       msg = fgettext("Install: Unsupported file type or broken archive"),
                }
        end
+
+       return {
+               path = tempfolder
+       }
 end
 
 local function start_install(package, reason)
        local params = {
                package = package,
                url = get_download_url(package, reason),
-               filename = os.tempfolder() .. "_MODNAME_" .. package.name .. ".zip",
        }
 
        number_downloading = number_downloading + 1
 
        local function callback(result)
-               if result.successful then
-                       local path, msg = pkgmgr.install(package.type,
-                                       result.filename, package.name,
-                                       package.path)
+               if result.msg then
+                       gamedata.errormessage = result.msg
+               else
+                       local path, msg = pkgmgr.install_dir(package.type, result.path, package.name, package.path)
+                       core.delete_dir(result.path)
                        if not path then
                                gamedata.errormessage = msg
                        else
@@ -137,9 +165,6 @@ local function start_install(package, reason)
                                        conf:write()
                                end
                        end
-                       os.remove(result.filename)
-               else
-                       gamedata.errormessage = fgettext("Failed to download $1", package.name)
                end
 
                package.downloading = false
@@ -159,7 +184,7 @@ local function start_install(package, reason)
        package.queued = false
        package.downloading = true
 
-       if not core.handle_async(download_package, params, callback) then
+       if not core.handle_async(download_and_extract, params, callback) then
                core.log("error", "ERROR: async event failed")
                gamedata.errormessage = fgettext("Failed to download $1", package.name)
                return
@@ -184,7 +209,7 @@ local function get_raw_dependencies(package)
        local url_fmt = "/api/packages/%s/dependencies/?only_hard=1&protocol_version=%s&engine_version=%s"
        local version = core.get_version()
        local base_url = core.settings:get("contentdb_url")
-       local url = base_url .. url_fmt:format(package.id, core.get_max_supp_proto(), version.string)
+       local url = base_url .. url_fmt:format(package.url_part, core.get_max_supp_proto(), urlencode(version.string))
 
        local response = http.fetch_sync({ url = url })
        if not response.succeeded then
@@ -559,17 +584,16 @@ function store.load()
        local base_url = core.settings:get("contentdb_url")
        local url = base_url ..
                "/api/packages/?type=mod&type=game&type=txp&protocol_version=" ..
-               core.get_max_supp_proto() .. "&engine_version=" .. version.string
+               core.get_max_supp_proto() .. "&engine_version=" .. urlencode(version.string)
 
        for _, item in pairs(core.settings:get("contentdb_flag_blacklist"):split(",")) do
                item = item:trim()
                if item ~= "" then
-                       url = url .. "&hide=" .. item
+                       url = url .. "&hide=" .. urlencode(item)
                end
        end
 
-       local timeout = tonumber(core.settings:get("curl_file_download_timeout"))
-       local response = http.fetch_sync({ url = url, timeout = timeout })
+       local response = http.fetch_sync({ url = url })
        if not response.succeeded then
                return
        end
@@ -579,12 +603,16 @@ function store.load()
 
        for _, package in pairs(store.packages_full) do
                local name_len = #package.name
+               -- This must match what store.update_paths() does!
+               package.id = package.author:lower() .. "/"
                if package.type == "game" and name_len > 5 and package.name:sub(name_len - 4) == "_game" then
-                       package.id = package.author:lower() .. "/" .. package.name:sub(1, name_len - 5)
+                       package.id = package.id .. package.name:sub(1, name_len - 5)
                else
-                       package.id = package.author:lower() .. "/" .. package.name
+                       package.id = package.id .. package.name
                end
 
+               package.url_part = urlencode(package.author) .. "/" .. urlencode(package.name)
+
                if package.aliases then
                        for _, alias in ipairs(package.aliases) do
                                -- We currently don't support name changing
@@ -834,8 +862,7 @@ function store.get_formspec(dlgdata)
                        formspec[#formspec + 1] = "cdb_downloading.png;3;400;]"
                elseif package.queued then
                        formspec[#formspec + 1] = left_base
-                       formspec[#formspec + 1] = core.formspec_escape(defaulttexturedir)
-                       formspec[#formspec + 1] = "cdb_queued.png;queued]"
+                       formspec[#formspec + 1] = "cdb_queued.png;queued;]"
                elseif not package.path then
                        local elem_name = "install_" .. i .. ";"
                        formspec[#formspec + 1] = "style[" .. elem_name .. "bgcolor=#71aa34]"
@@ -998,9 +1025,9 @@ function store.handle_submit(this, fields)
                end
 
                if fields["view_" .. i] then
-                       local url = ("%s/packages/%s/%s?protocol_version=%d"):format(
-                                       core.settings:get("contentdb_url"),
-                                       package.author, package.name, core.get_max_supp_proto())
+                       local url = ("%s/packages/%s?protocol_version=%d"):format(
+                                       core.settings:get("contentdb_url"), package.url_part,
+                                       core.get_max_supp_proto())
                        core.open_url(url)
                        return true
                end