💾 Archived View for gemini.conman.org › extensions › GLV-1 › handlers › zip.lua captured on 2023-11-14 at 10:06:44.
⬅️ Previous capture (2022-06-04)
-=-=-=-=-=-=-
-- ************************************************************************ -- -- The ZIP file handler -- Copyright 2020 by Sean Conner. All Rights Reserved. -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see <http://www.gnu.org/licenses/>. -- -- Comments, questions and criticisms can be sent to: sean@conman.org -- -- ************************************************************************ -- luacheck: globals init handler -- luacheck: ignore 611 local syslog = require "org.conman.syslog" local fsys = require "org.conman.fsys" local magic = require "org.conman.fsys.magic" local zipr = require "org.conman.zip.read" local zlib = require "zlib" local lpeg = require "lpeg" local uurl = require "GLV-1.url-util" local io = require "io" local string = require "string" local table = require "table" local ipairs = ipairs local pairs = pairs _ENV = {} -- ************************************************************************ local pfile = lpeg.P"/" * lpeg.P(-1) * lpeg.Cc('redirect') + (lpeg.P(1) - lpeg.P"/")^1 * lpeg.P"/" * lpeg.P(-1) * lpeg.Cc(true) + (lpeg.P(1) - lpeg.P"/")^1 * lpeg.P(-1) * lpeg.Cc(true) + lpeg.P(-1) * lpeg.Cc(true) + lpeg.Cc(false) local decr do local char = (lpeg.P"\r" - lpeg.P"\n") / "\n" + lpeg.P(1) decr = lpeg.Cs(char^0) end -- ************************************************************************ function init(iconf,hconf,gconf) if not iconf.directory then return false,"missing directory specification" end local gmime = gconf.mime or {} local hmime = hconf.mime or {} for ext,mimetype in pairs(gmime) do if hmime[ext] == nil then hmime[ext] = mimetype end end if not iconf.mime then iconf.mime = hmime else for ext,mimetype in pairs(hmime) do if iconf.mime[ext] == nil then iconf.mime[ext] = mimetype end end end return true end -- ************************************************************************ function handler(conf,_,_,pathinfo,ios) local match do match = {} match[1],match[2] = pathinfo:match("^(/.*%.zip)/(.*)") end local filename = string.format("%s/%s",conf.directory,match[1]) local zf,err = io.open(filename,"rb") if not zf then syslog('error',"%s: %s",filename,err) ios:write("40\r\n") return 40 end local eocd = zipr.eocd(zf) local listd = {} local listf = {} for entry in zipr.dir(zf,eocd) do local s,e = entry.name:find(match[2],1,true) if s then local w = pfile:match(entry.name,e+1) if w then if entry.usize == 0 then table.insert(listd,entry) else table.insert(listf,entry) end entry._dname = entry.name:sub(e+1,-1) if w == 'redirect' then entry._redirect = true break end end end end if #listd == 0 and #listf == 0 then ios:write("51\r\n") return 51 elseif listd[1] and listd[1]._redirect then ios:write("31 ",uurl.esc_path:match(match[1] .. "/" .. listd[1].name),"\r\n") return 31 elseif #listd == 0 and #listf == 1 then local _ = zipr.file(zf,listf[1]) local cdata = zf:read(listf[1].csize) local udata = zlib.decompress(cdata,-15) local mime = conf.mime[fsys.extension(listf[1].name)] or magic(udata,true) if mime:find("^text/") then udata = decr:match(udata) end ios:write("20 ",mime,"\r\n",udata) return 20 else ios:write( "20 text/gemini\r\n", string.format("Index of %s/%s\r\n",match[1],match[2]), "---------------------------\r\n", "\r\n" ) table.sort(listd,function(a,b) return a.name < b.name end) table.sort(listf,function(a,b) return a.name < b.name end) for _,entry in ipairs(listd) do if #entry._dname > 0 then ios:write(string.format("=> %s\t%s",uurl.esc_path:match(entry._dname),entry._dname),"\r\n") end end if #listd > 0 then ios:write("\r\n") end for _,entry in ipairs(listf) do ios:write(string.format("=> %s\t%s (%d bytes)",uurl.esc_path:match(entry._dname),entry._dname,entry.usize),"\r\n") end ios:write( "\r\n", "---------------------------\r\n", "GLV-1.12556\r\n" ) return 20 end end -- ************************************************************************ return _ENV