|
- local socket = require "socket"
- local fs = require "lfs"
-
- local tArgs = {...}
-
- local pcount = 0
- local threads = {}
-
- -- initial configuration
- local config = {}
- config.path = "/var/gopher"
- config.hostname = "shadowkat.net"
- config.port = 70
- config.bindport = 7000
- config.dirinfo = true
- config.timer = 0.1
-
- -- load the config as a lua script
- if tArgs[1] then
- local f = io.open(tArgs[1],"rb")
- local fn = load(f:read("*a"))
- f:close()
- if fn then
- for k,v in pairs(fn()) do
- config[k] = v
- end
- end
- end
-
- local function cleanPath(p) -- canonicalizes the path in theory
- local t,o = {},""
- for s in p:gmatch("[^/]+") do
- if s == ".." then
- t[#t] = nil
- else
- t[#t+1] = s
- end
- end
- for k,v in pairs(t) do
- o=o.."/"..v
- end
- return o
- end
-
- local function logerr(msg)
- -- todo: proper error logging logic
- print("error: "..msg)
- end
-
- local function detectft(path) -- tries to detect the file type
- local attr = fs.attributes(path)
- if attr.mode:sub(1,3) == "dir" then
- return "1"
- end
- if path:sub(-4) == ".png" or path:sub(-4) == ".jpg" or path:sub(-5) == ".jpeg" or path:sub(-4) == ".bmp" or path:sub(-4) == "gif" then
- return "I"
- end
- if path:sub(-5) == ".html" or path:sub(-4) == ".htm" then
- return "h"
- end
- return "0"
- end
-
- local function handleConnect(client)
- client:settimeout(0)
- threads[pcount+1] = coroutine.create(function() local w,err = pcall(function()
- repeat
- coroutine.yield()
- line=client:receive()
- until line
- print(line)
- local path,args = config.path .. cleanPath(line)
- local attr = fs.attributes(path)
- if attr then
- if attr.mode:sub(1,3) == "dir" then
- if lfs.attributes(path.."/.gopherdir.cgi") then
- local f = io.popen(path.."/.gopherdir.cgi")
- coroutine.yield()
- client:send(f:read("*a"))
- f:close()
- elseif lfs.attributes(path.."/.gopherdir") then
- local f = io.open(path.."/.gopherdir")
- client:send(f:read("*a"))
- f:close()
- else
- if config.dirinfo then
- client:send(string.format("i%s\ni%s\n",config.hostname,cleanPath(line)))
- end
- for file in lfs.dir(path) do
- if file:sub(1,1) ~= "." then
- client:send(string.format("%s%s\t%s\t%s\t%d\n",detectft(path.."/"..file),file,string.format("%s/%s",cleanPath(line),file),config.hostname,config.port))
- end
- end
- end
- else
- if path:sub(-4) == ".cgi" then
- local f = io.popen(path)
- coroutine.yield()
- client:send(f:read("*a"))
- f:close()
- else
- local f = io.open(path)
- client:send(f:read("*a"))
- f:close()
- end
- end
- else
- client:send("Not found.")
- end
- client:close()
- end)
- if not w then
- logerr(err)
- client:close()
- end
- end)
- pcount=pcount+1
- end
-
- local server = socket.bind("*",config.bindport)
- server:settimeout(config.timer)
- while true do -- totally not a scheduler
- client = server:accept()
- if client then
- handleConnect(client)
- end
- for k,v in pairs(threads) do
- if coroutine.status(v) == "dead" then
- threads[k] = nil
- else
- coroutine.resume(v)
- end
- end
- end
|