mirror of
https://github.com/koreader/koreader
synced 2024-11-10 01:10:34 +00:00
cbba7566b7
Option to show all files in cloudstorage also not supported by KOReader. We can also download any file. To show all files in CS we need to enable option Show unsupported files in file manager (introducing in #5129) Close: #5006
164 lines
5.3 KiB
Lua
164 lines
5.3 KiB
Lua
local DocumentRegistry = require("document/documentregistry")
|
|
local FFIUtil = require("ffi/util")
|
|
local http = require('socket.http')
|
|
local https = require('ssl.https')
|
|
local ltn12 = require('ltn12')
|
|
local mime = require('mime')
|
|
local socket = require('socket')
|
|
local url = require('socket.url')
|
|
local util = require("util")
|
|
local _ = require("gettext")
|
|
|
|
local WebDavApi = {
|
|
}
|
|
|
|
function WebDavApi:isCurrentDirectory( current_item, address, path )
|
|
local is_home, is_parent
|
|
local home_path
|
|
-- find first occurence of / after http(s)://
|
|
local start = string.find( address, "/", 9 )
|
|
if not start then
|
|
home_path = "/"
|
|
else
|
|
home_path = string.sub( address, start )
|
|
end
|
|
local item
|
|
if string.sub( current_item, -1 ) == "/" then
|
|
item = string.sub( current_item, 1, -2 )
|
|
else
|
|
item = current_item
|
|
end
|
|
|
|
if item == home_path then
|
|
is_home = true
|
|
else
|
|
local temp_path = string.sub( item, string.len(home_path) + 1 )
|
|
if temp_path == path then
|
|
is_parent = true
|
|
end
|
|
end
|
|
return is_home or is_parent
|
|
end
|
|
|
|
-- version of urlEncode that doesn't encode the /
|
|
function WebDavApi:urlEncode(url_data)
|
|
local char_to_hex = function(c)
|
|
return string.format("%%%02X", string.byte(c))
|
|
end
|
|
if url_data == nil then
|
|
return
|
|
end
|
|
url_data = url_data:gsub("([^%w%/%-%.%_%~%!%*%'%(%)])", char_to_hex)
|
|
return url_data
|
|
end
|
|
|
|
function WebDavApi:listFolder(address, user, pass, folder_path)
|
|
local path = self:urlEncode( folder_path )
|
|
local webdav_list = {}
|
|
local webdav_file = {}
|
|
|
|
local has_trailing_slash = false
|
|
local has_leading_slash = false
|
|
if string.sub( address, -1 ) ~= "/" then has_trailing_slash = true end
|
|
if path == nil or path == "/" then
|
|
path = ""
|
|
elseif string.sub( path, 1, 2 ) == "/" then
|
|
if has_trailing_slash then
|
|
-- too many slashes, remove one
|
|
path = string.sub( path, 1 )
|
|
end
|
|
has_leading_slash = true
|
|
end
|
|
if not has_trailing_slash and not has_leading_slash then
|
|
address = address .. "/"
|
|
end
|
|
local webdav_url = address .. path
|
|
|
|
local request, sink = {}, {}
|
|
local parsed = url.parse(webdav_url)
|
|
local data = [[<?xml version="1.0"?><a:propfind xmlns:a="DAV:"><a:prop><a:resourcetype/></a:prop></a:propfind>]]
|
|
local auth = string.format("%s:%s", user, pass)
|
|
local headers = { ["Authorization"] = "Basic " .. mime.b64( auth ),
|
|
["Content-Type"] = "application/xml",
|
|
["Depth"] = "1",
|
|
["Content-Length"] = #data}
|
|
request["url"] = webdav_url
|
|
request["method"] = "PROPFIND"
|
|
request["headers"] = headers
|
|
request["source"] = ltn12.source.string(data)
|
|
request["sink"] = ltn12.sink.table(sink)
|
|
http.TIMEOUT = 5
|
|
https.TIMEOUT = 5
|
|
local httpRequest = parsed.scheme == "http" and http.request or https.request
|
|
local headers_request = socket.skip(1, httpRequest(request))
|
|
if headers_request == nil then
|
|
return nil
|
|
end
|
|
|
|
local res_data = table.concat(sink)
|
|
if res_data ~= "" then
|
|
-- iterate through the <d:response> tags, each containing an entry
|
|
for item in res_data:gmatch("<d:response>(.-)</d:response>") do
|
|
--logger.dbg("WebDav catalog item=", item)
|
|
-- <d:href> is the path and filename of the entry.
|
|
local item_fullpath = item:match("<d:href>(.*)</d:href>")
|
|
local is_current_dir = self:isCurrentDirectory( item_fullpath, address, path )
|
|
local item_name = util.urlDecode( FFIUtil.basename( item_fullpath ) )
|
|
local item_path = path .. "/" .. item_name
|
|
if item:find("<d:collection/>") then
|
|
item_name = item_name .. "/"
|
|
if not is_current_dir then
|
|
table.insert(webdav_list, {
|
|
text = item_name,
|
|
url = util.urlDecode( item_path ),
|
|
type = "folder",
|
|
})
|
|
end
|
|
elseif item:find("<d:resourcetype/>") and (DocumentRegistry:hasProvider(item_name)
|
|
or G_reader_settings:isTrue("show_unsupported")) then
|
|
table.insert(webdav_file, {
|
|
text = item_name,
|
|
url = util.urlDecode( item_path ),
|
|
type = "file",
|
|
})
|
|
end
|
|
end
|
|
else
|
|
return nil
|
|
end
|
|
|
|
--sort
|
|
table.sort(webdav_list, function(v1,v2)
|
|
return v1.text < v2.text
|
|
end)
|
|
table.sort(webdav_file, function(v1,v2)
|
|
return v1.text < v2.text
|
|
end)
|
|
for _, files in ipairs(webdav_file) do
|
|
table.insert(webdav_list, {
|
|
text = files.text,
|
|
url = files.url,
|
|
type = files.type,
|
|
})
|
|
end
|
|
return webdav_list
|
|
end
|
|
|
|
function WebDavApi:downloadFile(file_url, user, pass, local_path)
|
|
local parsed = url.parse(file_url)
|
|
local auth = string.format("%s:%s", user, pass)
|
|
local headers = { ["Authorization"] = "Basic " .. mime.b64( auth ) }
|
|
http.TIMEOUT = 5
|
|
https.TIMEOUT = 5
|
|
local httpRequest = parsed.scheme == "http" and http.request or https.request
|
|
local _, code_return, _ = httpRequest{
|
|
url = file_url,
|
|
method = "GET",
|
|
headers = headers,
|
|
sink = ltn12.sink.file(io.open(local_path, "w"))
|
|
}
|
|
return code_return
|
|
end
|
|
|
|
return WebDavApi
|