Still. More. Documentation.
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
c274c4f723
commit
8629f74d16
207
bollux
207
bollux
|
@ -99,13 +99,6 @@ bollux_quit() {
|
|||
# SIGINT is C-c, and I want to make sure bollux quits when it's typed.
|
||||
trap bollux_quit SIGINT
|
||||
|
||||
# Bash built-in replacement for `sleep`
|
||||
#
|
||||
# [1]: #use-read-as-an-alternative-to-the-sleep-command
|
||||
sleep() { # sleep SECONDS
|
||||
read -rt "$1" <> <(:) || :
|
||||
}
|
||||
|
||||
# Trim leading and trailing whitespace from a string.
|
||||
#
|
||||
# [1]: #trim-leading-and-trailing-white-space-from-string
|
||||
|
@ -177,6 +170,29 @@ prompt() { # prompt [-u] PROMPT [READ_ARGS...]
|
|||
"${read_cmd[@]}" </dev/tty "$@"
|
||||
}
|
||||
|
||||
|
||||
# Bash built-in replacement for `cat'
|
||||
#
|
||||
# One of the more pedantic bits of bollux (is 'pedantic' the right word?) --
|
||||
# `cat' is more than likely installed on any system with bash, so this function
|
||||
# is really just here so I can say that bollux is written as purely in bash as
|
||||
# possible.
|
||||
passthru() {
|
||||
while IFS= read -r; do
|
||||
printf '%s\n' "$REPLY"
|
||||
done
|
||||
}
|
||||
|
||||
# Bash built-in replacement for `sleep'
|
||||
#
|
||||
# The commentary for `passthru' applies here as well, though I didn't write this
|
||||
# function -- Dylan Araps did.
|
||||
#
|
||||
# [1]: #use-read-as-an-alternative-to-the-sleep-command
|
||||
sleep() { # sleep SECONDS
|
||||
read -rt "$1" <> <(:) || :
|
||||
}
|
||||
|
||||
# MAIN BOLLUX DISPATCH FUNCTIONS ###############################################
|
||||
|
||||
# Main entry point into `bollux'.
|
||||
|
@ -772,71 +788,140 @@ gemini_response() { # gemini_response URL
|
|||
run blastoff "$meta" # TODO: confirm redirect
|
||||
;;
|
||||
(4*) # TEMPORARY ERROR
|
||||
# Since the 4* codes ([3], Appendix 1) are all server issues,
|
||||
# bollux can treat them all basically the same. This is an area
|
||||
# that could use some expansion.
|
||||
local desc="Temporary error"
|
||||
case "$code" in
|
||||
(41) desc+=" (server unavailable)" ;;
|
||||
(42) desc+=" (CGI error)" ;;
|
||||
(43) desc+=" (proxy error)" ;;
|
||||
(44) desc+=" (slow down)" ;; # could be particularly improved
|
||||
esac
|
||||
REDIRECTS=0
|
||||
die "$((100 + code))" "Temporary error [$code]: $meta"
|
||||
die "$((100 + code))" "$desc [$code]: $meta"
|
||||
;;
|
||||
(5*) # PERMANENT ERROR
|
||||
# The situation with the 5* codes is basically similar to the 4*
|
||||
# codes. It could maybe use more thought as to what behavior to
|
||||
# implement. Maybe adding the (bad) requests to history,
|
||||
# subject to configuration?
|
||||
local desc="Permanent failure"
|
||||
case "$code" in
|
||||
(51) desc+=" (not found)" ;;
|
||||
(52) desc+=" (gone)" ;;
|
||||
(53) desc+=" (proxy request refused)" ;;
|
||||
# For some reason, codes 54--58 inclusive aren't used.
|
||||
(59) desc+=" (bad request)" ;;
|
||||
esac
|
||||
REDIRECTS=0
|
||||
die "$((100 + code))" "Permanent error [$code]: $meta"
|
||||
die "$((100 + code))" "$desc [$code]: $meta"
|
||||
;;
|
||||
(6*) # CERTIFICATE ERROR
|
||||
(6*) # CERTIFICATE ERROR (TODO)
|
||||
# Dealing with certificates is honestly the most important
|
||||
# feature missing from bollux to get it to 1.0. Right now,
|
||||
# bollux deals with 6* status codes identically to 4* and 5*
|
||||
# codes. This is not ideal, in the slightest.
|
||||
local desc="Client certificate required"
|
||||
case "$code" in
|
||||
(61) desc+=" (certificate not authorized)" ;;
|
||||
(62) desc+=" (certificate not valid)" ;;
|
||||
esac
|
||||
REDIRECTS=0
|
||||
log d "Not implemented: Client certificates"
|
||||
die "$((100 + code))" "[$code] $meta"
|
||||
;;
|
||||
(*)
|
||||
(*) # UNKNOWN
|
||||
# Just in case we get a weird, un-spec-compliant status code.
|
||||
[[ -z "${code-}" ]] && die 100 "Empty response code."
|
||||
die "$((100 + code))" "Unknown response code: $code."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# GOPHER
|
||||
# GOPHER #######################################################################
|
||||
# https://tools.ietf.org/html/rfc1436 protocol
|
||||
# https://tools.ietf.org/html/rfc4266 url
|
||||
#
|
||||
# Gopher is the grand-daddy of gemini (or maybe just weird uncle? hm..),
|
||||
# invented in 1991 as a fancier FTP. There's been a sort of resurgence in it as
|
||||
# a consequence of the shittifying of the WWW, but it's shown its age (which is
|
||||
# why Gemini was born). But why am I telling you this? You're reading the
|
||||
# source code of a Gemini browser! You're a meganerd just like me. Welcome to
|
||||
# the club, kid.
|
||||
#
|
||||
# Since gopher is so old, it actually has two RFCs: RFC 1436 [6] for the
|
||||
# protocol itself, and RFC 4266 [7] for the URL format (gopher predates the
|
||||
# URL!). However, requesting and handling responses is still fundamentally the
|
||||
# same to gemini, so it was pretty easy to implement this. I don't think bollux
|
||||
# handles all the possible item types, but it should get the main ones.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
# Request a resource.
|
||||
gopher_request() { # gopher_request URL
|
||||
local url server port type path
|
||||
url="$1"
|
||||
port=70
|
||||
local url="$1"
|
||||
|
||||
# RFC 4266
|
||||
# [7] § 2.1
|
||||
[[ "$url" =~ gopher://([^/?#:]*)(:([0-9]+))?(/((.))?(/?.*))?$ ]]
|
||||
server="${BASH_REMATCH[1]}"
|
||||
port="${BASH_REMATCH[3]:-70}"
|
||||
type="${BASH_REMATCH[6]:-1}"
|
||||
path="${BASH_REMATCH[7]}"
|
||||
|
||||
local server="${BASH_REMATCH[1]}" \
|
||||
port="${BASH_REMATCH[3]:-$BOLLUX_GOPHER_PORT}" \
|
||||
type="${BASH_REMATCH[6]:-1}" \
|
||||
path="${BASH_REMATCH[7]}"
|
||||
log d "URL='$url' SERVER='$server' TYPE='$type' PATH='$path'"
|
||||
|
||||
# Bash has this really neat feature where it can open a TCP socket
|
||||
# directly. bollux uses that feature here to ask the server for the
|
||||
# resource and then `passthru' it to the next thing.
|
||||
exec 9<>"/dev/tcp/$server/$port"
|
||||
printf '%s\r\n' "$path" >&9
|
||||
passthru <&9
|
||||
}
|
||||
|
||||
# Handle a server response.
|
||||
gopher_response() { # gopher_response URL
|
||||
local url pre type cur_server
|
||||
pre=false
|
||||
url="$1"
|
||||
# RFC 4266
|
||||
local url="$1" pre=false
|
||||
# [7] § 2.1
|
||||
#
|
||||
# Note that this duplicates the code in `gopher_request'. There might
|
||||
# be a good way to thread this data through so that it's not computed
|
||||
# twice.
|
||||
[[ "$url" =~ gopher://([^/?#:]*)(:([0-9]+))?(/((.))?(/?.*))?$ ]]
|
||||
cur_server="${BASH_REMATCH[1]}"
|
||||
type="${BASH_REMATCH[6]:-1}"
|
||||
local cur_server="${BASH_REMATCH[1]}"
|
||||
local type="${BASH_REMATCH[6]:-1}"
|
||||
|
||||
run history_append "$url" "" # gopher doesn't really have titles, huh
|
||||
|
||||
log d "TYPE='$type'"
|
||||
|
||||
# Gopher has a concept of 'line types', or maybe 'item types' --
|
||||
# basically, each line in a gophermap starts with a character, its type,
|
||||
# and then is followed by a series of tab-separated fields describing
|
||||
# where that type is and how to display it. The full list of original
|
||||
# line types can be found in [6] § 3.8, though the types have also been
|
||||
# extended over the years. Since bollux can only display types that are
|
||||
# text-ish, it only concerns itself with those in this case statement.
|
||||
# All the others are simply downloaded.
|
||||
case "$type" in
|
||||
(0) # text
|
||||
(0) # Item is a file
|
||||
# Since gopher doesn't send MIME-type information in-band, we
|
||||
# just assume it's text/plain, and try to convert it later to
|
||||
# UTF-8 with `iconv'.
|
||||
run display text/plain
|
||||
;;
|
||||
(1) # menu
|
||||
(1) # Item is a directory [gophermap]
|
||||
# Since I've already written all the code to typeset gemini
|
||||
# well, it's easy to convert a gophermap to text/gemini and
|
||||
# display it than to write a whole new gophermap typesetter.
|
||||
run gopher_convert | run display text/gemini
|
||||
;;
|
||||
(3) # failure
|
||||
(3) # Error
|
||||
# I don't know all the gopher error cases, and the spec is
|
||||
# pretty quiet on them. So bollux just signals failure and
|
||||
# bails.
|
||||
die 203 "GOPHER: failed"
|
||||
;;
|
||||
(7) # search
|
||||
(7) # Item is an Index-Search server
|
||||
# Gopher search queries are separated from their resources by a
|
||||
# TAB. It's wild.
|
||||
if [[ "$url" =~ $'\t' ]]; then
|
||||
run gopher_convert | run display text/gemini
|
||||
else
|
||||
|
@ -844,16 +929,42 @@ gopher_response() { # gopher_response URL
|
|||
run blastoff "$url $REPLY"
|
||||
fi
|
||||
;;
|
||||
(*) # something else
|
||||
(*) # Anything else
|
||||
# The list at [6] § 3.8 includes the following (noted where it
|
||||
# might be good to differently handle them in the future):
|
||||
#
|
||||
# 2. Item is a CSO phone-book server *****
|
||||
# 4. Item is a BinHexed Macintosh file
|
||||
# 5. Item is DOS binary archive of some sort
|
||||
# 6. Item is a UNIX uuencoded file
|
||||
# 8. Item points to a text-based telnet session *****
|
||||
# 9. Item is a binary file! [exclamation point sic. -- ed.]
|
||||
# +. Item is a redundant server *****
|
||||
# T. Item points to a text-based tn3270 session
|
||||
# g. Item is a GIF format graphics file
|
||||
# I. Item is some kind of image file
|
||||
#
|
||||
# As mentioned, there are other line types floating around as
|
||||
# well. Since I don't browse gopher much, there's not much
|
||||
# personal motivation to extend `gopher_response'; however pull
|
||||
# requests are always welcome.
|
||||
run download "$url"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# convert gophermap to text/gemini (probably naive)
|
||||
# Convert a gophermap naively to a gemini page.
|
||||
#
|
||||
# Based strongly on [8], but bash-ified. Due to the properties of link lines in
|
||||
# gemini, many of the item types in `gemini_reponse' can be linked to the proper
|
||||
# protocol handlers here -- so if a user is trying to reach a TCP link through
|
||||
# gopher, bollux won't have to handle it, for example.*
|
||||
#
|
||||
# * Ideally -- right now, bollux simply errors out on all unknown protocols.
|
||||
# More research needs to be done into how to farm out to `xdg-open' or a
|
||||
# similar generic opener.
|
||||
gopher_convert() {
|
||||
local type label path server port regex
|
||||
# [GOPHER_GEMINI]
|
||||
while IFS= read -r; do
|
||||
printf -v regex '(.)([^\t]*)(\t([^\t]*)\t([^\t]*)\t([^\t]*))?'
|
||||
if [[ "$REPLY" =~ $regex ]]; then
|
||||
|
@ -922,13 +1033,12 @@ gopher_convert() {
|
|||
exec 9>&-
|
||||
}
|
||||
|
||||
|
||||
# 'cat' but in pure bash
|
||||
passthru() {
|
||||
while IFS= read -r; do
|
||||
printf '%s\n' "$REPLY"
|
||||
done
|
||||
}
|
||||
# HANDLING CONTENT #############################################################
|
||||
#
|
||||
# After fetching the resource requested by the user, bollux needs to display or
|
||||
# otherwise 'give' the resource to the user for consumption.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
# display the fetched content
|
||||
display() { # display METADATA [TITLE]
|
||||
|
@ -959,8 +1069,15 @@ display() { # display METADATA [TITLE]
|
|||
case "$mime" in
|
||||
(text/*)
|
||||
set_title "$title${title:+ - }bollux"
|
||||
# render ANSI color escapes and don't wrap pre-formatted blocks
|
||||
less_cmd=(less -RS)
|
||||
# Build the `less' command
|
||||
less_cmd=(less)
|
||||
# Render ANSI color escapes ONLY (as opposed to `-r', which
|
||||
# renders all escapes)
|
||||
less_cmd+=(-R)
|
||||
# Don't wrap text. `fold_line' takes care of wrapping normal
|
||||
# text, and pre-formatted text shouldn't wrap.
|
||||
less_cmd+=(-S)
|
||||
# Load the keybindings (see `lesskey').
|
||||
mklesskey && less_cmd+=(-k "$BOLLUX_LESSKEY")
|
||||
local helpline="${KEY_OPEN}:open, "
|
||||
helpline+="${KEY_GOTO}/"
|
||||
|
|
Loading…
Reference in New Issue