diff --git a/lib/download.lua b/lib/download.lua new file mode 100644 index 0000000..17176ad --- /dev/null +++ b/lib/download.lua @@ -0,0 +1,121 @@ +local net = require "minitel" +local dl = {} +dl.protos = {} + +-- Stolen from the old exec/fget +local function parseURL(url) + local proto,addr = url:match("(.-)://(.+)") + addr = addr or url + local hp, path = addr:match("(.-)(/.*)") + hp, path = hp or addr, path or "/" + local host, port = hp:match("(.+):(.+)") + host = host or hp + return proto, host, port, path +end + +function dl.protos.fget(host, optPort, path, dest) -- string string string number -- boolean -- Downloads path from host (on optPort or 70), printing the directory listing, or saving the file to dest. + local socket = assert(net.open(host, optPort or 70)) + socket:write(string.format("t%s\n", path)) + local status + repeat + coroutine.yield() + status = socket:read(1) + until status ~= "" + + if status == "d" then + io.write("Directory Listing:\n") + local tmp = "" + repeat + coroutine.yield() + tmp = socket:read("*a") + + io.write(tmp) + until socket.state == "closed" and tmp == "" + + return true + elseif status == "y" then + if not dest then + error("Must provide local path to save remote files.") + end + + io.write(string.format("Saving %s to %s...\n", path, dest)) + local f = assert(io.open(dest, "wb")) + local tmp = "" + repeat + coroutine.yield() + tmp = socket:read("*a") + + f:write(tmp) + until socket.state == "closed" and tmp == "" + + f:close() + print("Done.") + + return true + else + local err, tmp = "", "" + repeat + coroutine.yield() + tmp = socket:read("*a") + + err = err .. tmp + until socket.state == "closed" and tmp == "" + + error(string.format("Got error from remote host: %s", err)) + end +end + +function dl.protos.http(host, optPort, path, dest, url) -- string string string number -- boolean -- Downloads *url* to *dest* via the internet card, if available. + if not component.list("internet")() then + local proto,host,sPort,path = parseURL(url) + local proxy = os.getenv(proto:upper().."_PROXY") + if not proxy and fs.exists("/boot/cfg/"..proto.."_proxy") then + local f = io.open("/boot/cfg/"..proto.."_proxy","rb") + proxy = f:read() + f:close() + end + if not proxy then error("No internet card or HTTP(S) proxy available") end + if optPort then host=string.format("%s:%i",host,optPort) end + return dl.wget(string.format("%s/%s%s",proxy,host,path)) + end + if not dest then + error("Must provide local path to save remote files.") + end + local R,r=component.invoke(component.list("internet")(),"request",url) + if not R then error(r) end + repeat + coroutine.yield() + until R.finishConnect() + local code, message, headers = R.response() + if code > 299 or code < 200 then + return false, code, message + end + local f=io.open(dest,"wb") + if not f then error("Unable to open file "..dest) end + io.write(string.format("Saving %s to %s...\n", url, dest)) + repeat + coroutine.yield() + ns = R.read(2048) + f:write(ns or "") + until not ns + f:close() + print("Done.") + return true +end +dl.protos.https = dl.protos.http + +function dl.wget(remotePath, dest) -- string string -- -- Downloads from remote *remotePath* to *dest* + local proto, host, sPort, path = parseURL(remotePath) + if dl.protos[proto] then + local port + if sPort then + port = tonumber(sPort) + end + + dl.protos[proto](host, port, path, dest, remotePath) + else + error("Unsupported protocol: " .. tostring(proto)) + end +end + +return setmetatable(dl,{__call=function(_,path,dest) return dl.wget(path,dest) end})