109 lines
3.1 KiB
Lua
109 lines
3.1 KiB
Lua
socket = require("socket")
|
|
socket.url = require("socket.url")
|
|
ssl = require("ssl")
|
|
pl = require("pl")
|
|
|
|
ssl_params = {
|
|
mode = "client",
|
|
protocol = "tlsv1_2"
|
|
}
|
|
|
|
links = {}
|
|
history = {}
|
|
|
|
while true do
|
|
::main_loop::
|
|
io.write("> ")
|
|
cmd = io.read()
|
|
if string.lower(cmd) == "q" then
|
|
io.write("Bye!\n")
|
|
break
|
|
elseif tonumber(cmd) ~= nil then
|
|
url = links[tonumber(cmd)]
|
|
elseif string.lower(cmd) == "b" then
|
|
-- Yes, twice
|
|
url = table.remove(history)
|
|
url = table.remove(history)
|
|
else
|
|
url = cmd
|
|
end
|
|
|
|
-- Add scheme if missing
|
|
if string.find(url, "://") == nil then
|
|
url = "gemini://" .. url
|
|
end
|
|
-- Add empty path if needed
|
|
if string.find(string.sub(url, 10, -1), "/") == nil then
|
|
url = url .. "/"
|
|
end
|
|
::parse_url::
|
|
parsed_url = socket.url.parse(url)
|
|
-- Open connection
|
|
conn = socket.tcp()
|
|
ret, str = conn:connect(parsed_url.host, 1965)
|
|
if ret == nil then
|
|
io.write(str) goto main_loop
|
|
end
|
|
conn, err = ssl.wrap(conn, ssl_params)
|
|
if conn == nil then
|
|
io.write(err) goto main_loop
|
|
end
|
|
conn:dohandshake()
|
|
-- Send request
|
|
conn:send(url .. "\r\n")
|
|
-- Parse response header
|
|
header = conn:receive("*l")
|
|
status, meta = table.unpack(utils.split(header, "%s+", false, 2))
|
|
-- Handle sucessful response
|
|
if string.sub(status, 1, 1) == "2" then
|
|
if meta == "text/gemini" then
|
|
-- Handle Geminimap
|
|
links = {}
|
|
preformatted = false
|
|
while true do
|
|
line, err = conn:receive("*l")
|
|
if line ~= nil then
|
|
if string.sub(line,1,3) == "```" then
|
|
preformatted = not preformatted
|
|
elseif preformatted then
|
|
io.write(line .. "\n")
|
|
elseif string.sub(line,1,2) == "=>" then
|
|
line = string.sub(line,3,-1) -- Trim off =>
|
|
line = string.gsub(line,"^%s+","") -- Trim spaces
|
|
link_url, label = table.unpack(utils.split(line, "%s+", false, 2))
|
|
if label == nil then label = link_url end
|
|
table.insert(links, socket.url.absolute(url, link_url))
|
|
io.write("[" .. #links .. "] " .. label .. "\n")
|
|
else
|
|
io.write(text.fill(line))
|
|
end
|
|
else
|
|
break
|
|
end
|
|
end
|
|
elseif string.sub(meta, 1, 5) == "text/" then
|
|
-- Print text
|
|
while true do
|
|
line, err = conn:receive("*l")
|
|
if line ~= nil then
|
|
io.write(line .. "\n")
|
|
else
|
|
break
|
|
end
|
|
end
|
|
end
|
|
-- Handle redirects
|
|
elseif string.sub(status, 1, 1) == "3" then
|
|
url = socket.url.absolute(url, meta)
|
|
goto parse_url
|
|
-- Handle errors
|
|
elseif string.sub(status, 1, 1) == "4" or string.sub(status, 1, 1) == "5" then
|
|
io.write("Error: " .. meta)
|
|
elseif string.sub(status, 1, 1) == "6" then
|
|
io.write("Client certificates not supported.")
|
|
else
|
|
io.write("Invalid response from server.")
|
|
end
|
|
table.insert(history, url)
|
|
end
|