diff options
-rw-r--r--[-rwxr-xr-x] | bollux | 257 |
1 files changed, 128 insertions, 129 deletions
diff --git a/bollux b/bollux index 277af05..30acd0a 100755..100644 --- a/bollux +++ b/bollux | |||
@@ -93,14 +93,14 @@ bollux() { | |||
93 | bollux_args() { | 93 | bollux_args() { |
94 | while getopts :hvq OPT; do | 94 | while getopts :hvq OPT; do |
95 | case "$OPT" in | 95 | case "$OPT" in |
96 | (h) | 96 | h) |
97 | bollux_usage | 97 | bollux_usage |
98 | exit | 98 | exit |
99 | ;; | 99 | ;; |
100 | (v) BOLLUX_LOGLEVEL=DEBUG ;; | 100 | v) BOLLUX_LOGLEVEL=DEBUG ;; |
101 | (q) BOLLUX_LOGLEVEL=QUIET ;; | 101 | q) BOLLUX_LOGLEVEL=QUIET ;; |
102 | (:) die 1 "Option -$OPTARG requires an argument" ;; | 102 | :) die 1 "Option -$OPTARG requires an argument" ;; |
103 | (*) die 1 "Unknown option: -$OPTARG" ;; | 103 | *) die 1 "Unknown option: -$OPTARG" ;; |
104 | esac | 104 | esac |
105 | done | 105 | done |
106 | shift $((OPTIND - 1)) | 106 | shift $((OPTIND - 1)) |
@@ -142,16 +142,16 @@ bollux_config() { | |||
142 | : "${BOLLUX_TIMEOUT:=30}" # connection timeout | 142 | : "${BOLLUX_TIMEOUT:=30}" # connection timeout |
143 | : "${BOLLUX_MAXREDIR:=5}" # max redirects | 143 | : "${BOLLUX_MAXREDIR:=5}" # max redirects |
144 | : "${BOLLUX_PROTO:=gemini}" # default protocol | 144 | : "${BOLLUX_PROTO:=gemini}" # default protocol |
145 | : "${BOLLUX_GEMINI_PORT:=1965}" # default port for gemini | 145 | : "${BOLLUX_GEMINI_PORT:=1965}" # default port for gemini |
146 | : "${BOLLUX_GOPHER_PORT:=70}" # default port for gopher | 146 | : "${BOLLUX_GOPHER_PORT:=70}" # default port for gopher |
147 | : "${BOLLUX_URL:=}" # start url | 147 | : "${BOLLUX_URL:=}" # start url |
148 | : "${BOLLUX_BYEMSG:=See You Space Cowboy ...}" # bye message | 148 | : "${BOLLUX_BYEMSG:=See You Space Cowboy ...}" # bye message |
149 | ## lesskeys | 149 | ## lesskeys |
150 | : "${KEY_OPEN:=o}" # prompt for a link to open | 150 | : "${KEY_OPEN:=o}" # prompt for a link to open |
151 | : "${KEY_GOTO:=g}" # prompt for a page to 'goto' | 151 | : "${KEY_GOTO:=g}" # prompt for a page to 'goto' |
152 | : "${KEY_GOTO_FROM:=G}" # goto a page with current prefilled | 152 | : "${KEY_GOTO_FROM:=G}" # goto a page with current prefilled |
153 | : "${KEY_BACK:=[}" # go back in the history | 153 | : "${KEY_BACK:=[}" # go back in the history |
154 | : "${KEY_FORWARD:=]}" # go forward in the history | 154 | : "${KEY_FORWARD:=]}" # go forward in the history |
155 | : "${KEY_REFRESH:=r}" # refresh the page | 155 | : "${KEY_REFRESH:=r}" # refresh the page |
156 | : "${KEY_CYCLE_PRE:=p}" # cycle T_PRE_DISPLAY | 156 | : "${KEY_CYCLE_PRE:=p}" # cycle T_PRE_DISPLAY |
157 | : "${BOLLUX_CUSTOM_LESSKEY:=$BOLLUX_CONF_DIR/bollux.lesskey}" | 157 | : "${BOLLUX_CUSTOM_LESSKEY:=$BOLLUX_CONF_DIR/bollux.lesskey}" |
@@ -252,24 +252,24 @@ run() { # run COMMAND... | |||
252 | log() { # log LEVEL MESSAGE... | 252 | log() { # log LEVEL MESSAGE... |
253 | # 'QUIET' means don't log anything. | 253 | # 'QUIET' means don't log anything. |
254 | [[ "$BOLLUX_LOGLEVEL" == QUIET ]] && return | 254 | [[ "$BOLLUX_LOGLEVEL" == QUIET ]] && return |
255 | local fmt # ANSI escape code | 255 | local fmt # ANSI escape code |
256 | 256 | ||
257 | case "$1" in | 257 | case "$1" in |
258 | ([dD]*) # Debug level -- only print if bollux -v. | 258 | [dD]*) # Debug level -- only print if bollux -v. |
259 | [[ "$BOLLUX_LOGLEVEL" == DEBUG ]] || return | 259 | [[ "$BOLLUX_LOGLEVEL" == DEBUG ]] || return |
260 | fmt=34 # Blue | 260 | fmt=34 # Blue |
261 | ;; | 261 | ;; |
262 | ([eE]*) # Error level -- always print. | 262 | [eE]*) # Error level -- always print. |
263 | fmt=31 # Red | 263 | fmt=31 # Red |
264 | ;; | 264 | ;; |
265 | (*) # Diagnostic level -- print unless QUIET. | 265 | *) # Diagnostic level -- print unless QUIET. |
266 | fmt=1 # Bold | 266 | fmt=1 # Bold |
267 | ;; | 267 | ;; |
268 | esac | 268 | esac |
269 | shift | 269 | shift |
270 | 270 | ||
271 | printf >&2 '\e[%sm%s:%-16s:\e[0m %s\n' \ | 271 | printf >&2 '\e[%sm%s:%-16s:\e[0m %s\n' \ |
272 | "$fmt" "$PRGN" "${FUNCNAME[${LOG_FUNC:-1}]}" "$*" | 272 | "$fmt" "$PRGN" "${FUNCNAME[${LOG_FUNC:-1}]}" "$*" |
273 | } | 273 | } |
274 | 274 | ||
275 | # Exit with an error and a message describing it. | 275 | # Exit with an error and a message describing it. |
@@ -298,10 +298,10 @@ list_cycle() { # list_cycle LIST<string> DELIM | |||
298 | # T_PRE_DISPLAY, which is user-configurable. I wanted it to be as easy | 298 | # T_PRE_DISPLAY, which is user-configurable. I wanted it to be as easy |
299 | # to configure for users who might not immediately know the bash array | 299 | # to configure for users who might not immediately know the bash array |
300 | # syntax, but can figure out 'variable=value' without much thought. | 300 | # syntax, but can figure out 'variable=value' without much thought. |
301 | local list="${!1}" # Pass the list by name, not value | 301 | local list="${!1}" # Pass the list by name, not value |
302 | local delim="$2" # The delimiter of the string | 302 | local delim="$2" # The delimiter of the string |
303 | local first="${list%%${delim}*}" # The first element | 303 | local first="${list%%${delim}*}" # The first element |
304 | local rest="${list#*${delim}}" # The rest of the elements | 304 | local rest="${list#*${delim}}" # The rest of the elements |
305 | # -v prints to the variable specified. | 305 | # -v prints to the variable specified. |
306 | printf -v "$1" '%s%s%s' "${rest}" "${delim}" "${first}" | 306 | printf -v "$1" '%s%s%s' "${rest}" "${delim}" "${first}" |
307 | } | 307 | } |
@@ -325,7 +325,7 @@ prompt() { # prompt [-u] PROMPT [READ_ARGS...] | |||
325 | read_cmd+=(-i "$BOLLUX_URL") | 325 | read_cmd+=(-i "$BOLLUX_URL") |
326 | shift | 326 | shift |
327 | fi | 327 | fi |
328 | local prompt="$1" # How to prompt the user | 328 | local prompt="$1" # How to prompt the user |
329 | shift | 329 | shift |
330 | read_cmd+=(-p "$prompt> ") | 330 | read_cmd+=(-p "$prompt> ") |
331 | "${read_cmd[@]}" </dev/tty "$@" | 331 | "${read_cmd[@]}" </dev/tty "$@" |
@@ -423,11 +423,11 @@ usplit() { # usplit URL_ARRAY<name> URL | |||
423 | # below performs a reverse lookup on the name to get the actual data. | 423 | # below performs a reverse lookup on the name to get the actual data. |
424 | # shellcheck disable=2034 | 424 | # shellcheck disable=2034 |
425 | local entire_url="${BASH_REMATCH[0]}" \ | 425 | local entire_url="${BASH_REMATCH[0]}" \ |
426 | scheme="${BASH_REMATCH[2]}" \ | 426 | scheme="${BASH_REMATCH[2]}" \ |
427 | authority="${BASH_REMATCH[4]}" \ | 427 | authority="${BASH_REMATCH[4]}" \ |
428 | path="${BASH_REMATCH[5]}" \ | 428 | path="${BASH_REMATCH[5]}" \ |
429 | query="${BASH_REMATCH[7]}" \ | 429 | query="${BASH_REMATCH[7]}" \ |
430 | fragment="${BASH_REMATCH[9]}" | 430 | fragment="${BASH_REMATCH[9]}" |
431 | 431 | ||
432 | # Iterate through the 5 components of a URL and assign them to elements | 432 | # Iterate through the 5 components of a URL and assign them to elements |
433 | # of URL_ARRAY, as follows: | 433 | # of URL_ARRAY, as follows: |
@@ -516,10 +516,10 @@ ucblank() { # ucblank COMPONENT<name> | |||
516 | # `ucset' sets one component of a URL array and setting the 0th element to the | 516 | # `ucset' sets one component of a URL array and setting the 0th element to the |
517 | # new full URL. Use it instead of directly setting the array element with U[x], | 517 | # new full URL. Use it instead of directly setting the array element with U[x], |
518 | # because U[0] will fall out of sync with the rest of the contents. | 518 | # because U[0] will fall out of sync with the rest of the contents. |
519 | ucset() { # ucset URL_ARRAY_INDEX<name> NEW_VALUE | 519 | ucset() { # ucset URL_ARRAY_INDEX<name> NEW_VALUE |
520 | local url_array_component="$1" # Of form 'URL_ARRAY[INDEX]' | 520 | local url_array_component="$1" # Of form 'URL_ARRAY[INDEX]' |
521 | local value="$2" | 521 | local value="$2" |
522 | 522 | ||
523 | # Assign $value to $url_array_component. | 523 | # Assign $value to $url_array_component. |
524 | # | 524 | # |
525 | # Wrapped in an 'eval' for the extra layer of indirection. | 525 | # Wrapped in an 'eval' for the extra layer of indirection. |
@@ -538,8 +538,8 @@ uencode() { # uencode URL | |||
538 | for ((i = 0; i < ${#1}; i++)); do | 538 | for ((i = 0; i < ${#1}; i++)); do |
539 | : "${1:i:1}" | 539 | : "${1:i:1}" |
540 | case "$_" in | 540 | case "$_" in |
541 | ([a-zA-Z0-9.~_-]) printf '%s' "$_" ;; | 541 | [a-zA-Z0-9.~_-]) printf '%s' "$_" ;; |
542 | (*) printf '%%%02X' "'$_" ;; | 542 | *) printf '%%%02X' "'$_" ;; |
543 | esac | 543 | esac |
544 | done | 544 | done |
545 | printf '\n' | 545 | printf '\n' |
@@ -704,7 +704,6 @@ gemini_request() { # gemini_request URL | |||
704 | port="$BOLLUX_GEMINI_PORT" | 704 | port="$BOLLUX_GEMINI_PORT" |
705 | fi | 705 | fi |
706 | 706 | ||
707 | |||
708 | # Build the SSL command to request the resource. | 707 | # Build the SSL command to request the resource. |
709 | # | 708 | # |
710 | # This is the beating heart of bollux, the command that does all the | 709 | # This is the beating heart of bollux, the command that does all the |
@@ -716,12 +715,12 @@ gemini_request() { # gemini_request URL | |||
716 | # manual [9] it says not to use it, but who reads the manual, | 715 | # manual [9] it says not to use it, but who reads the manual, |
717 | # anyway? | 716 | # anyway? |
718 | openssl s_client | 717 | openssl s_client |
719 | -crlf # Automatically add CR+LF to line | 718 | -crlf # Automatically add CR+LF to line |
720 | -quiet # Don't print all the cert stuff | 719 | -quiet # Don't print all the cert stuff |
721 | # -ign_eof # `-quiet' implies `-ign_eof' | 720 | # -ign_eof # `-quiet' implies `-ign_eof' |
722 | -connect "${url[2]}:$port" # The server and port to connect | 721 | -connect "${url[2]}:$port" # The server and port to connect |
723 | -servername "${url[2]}" # SNI: Server Name Identification | 722 | -servername "${url[2]}" # SNI: Server Name Identification |
724 | -no_ssl3 -no_tls1 -no_tls1_1 # disable old TLS/SSL versions | 723 | -no_ssl3 -no_tls1 -no_tls1_1 # disable old TLS/SSL versions |
725 | ) | 724 | ) |
726 | 725 | ||
727 | # Actually request the resource. | 726 | # Actually request the resource. |
@@ -733,9 +732,9 @@ gemini_request() { # gemini_request URL | |||
733 | 732 | ||
734 | # Handle the gemini response - see [3] Section 3. | 733 | # Handle the gemini response - see [3] Section 3. |
735 | gemini_response() { # gemini_response URL | 734 | gemini_response() { # gemini_response URL |
736 | local code meta # received on the first line of the response | 735 | local code meta # received on the first line of the response |
737 | local title # determined by a clunky heuristic, see read loop: (2*) | 736 | local title # determined by a clunky heuristic, see read loop: (2*) |
738 | local url="$1" # the currently-visited URL. | 737 | local url="$1" # the currently-visited URL. |
739 | 738 | ||
740 | # Read the first line. | 739 | # Read the first line. |
741 | # | 740 | # |
@@ -751,7 +750,7 @@ gemini_response() { # gemini_response URL | |||
751 | # `download', below), but I'm not sure how to remedy that issue either. | 750 | # `download', below), but I'm not sure how to remedy that issue either. |
752 | # It requires more research. | 751 | # It requires more research. |
753 | while read -t "$BOLLUX_TIMEOUT" -r code meta || | 752 | while read -t "$BOLLUX_TIMEOUT" -r code meta || |
754 | { (($? > 128)) && die 99 "Timeout."; }; do | 753 | { (($? > 128)) && die 99 "Timeout."; }; do |
755 | break | 754 | break |
756 | done | 755 | done |
757 | log d "[$code] $meta" | 756 | log d "[$code] $meta" |
@@ -763,20 +762,20 @@ gemini_response() { # gemini_response URL | |||
763 | # - I branch on the first digit of the status code, instead of both, to | 762 | # - I branch on the first digit of the status code, instead of both, to |
764 | # minimize the amount of duplicated code I need to write. | 763 | # minimize the amount of duplicated code I need to write. |
765 | case "$code" in | 764 | case "$code" in |
766 | (1*) # INPUT | 765 | 1*) # INPUT |
767 | # Gemini allows GET-style requests, and the INPUT family of | 766 | # Gemini allows GET-style requests, and the INPUT family of |
768 | # response codes facilitate them. `10' is for standard input, | 767 | # response codes facilitate them. `10' is for standard input, |
769 | # and `11' is for sensitive information, like passwords. | 768 | # and `11' is for sensitive information, like passwords. |
770 | REDIRECTS=0 | 769 | REDIRECTS=0 |
771 | BOLLUX_URL="$url" | 770 | BOLLUX_URL="$url" |
772 | case "$code" in | 771 | case "$code" in |
773 | (10) run prompt "$meta" ;; | 772 | 10) run prompt "$meta" ;; |
774 | (11) run prompt "$meta" -s ;; # sensitive input | 773 | 11) run prompt "$meta" -s ;; # sensitive input |
775 | esac | 774 | esac |
776 | run history_append "$url" "${title:-}" | 775 | run history_append "$url" "${title:-}" |
777 | run blastoff "?$(uencode "$REPLY")" | 776 | run blastoff "?$(uencode "$REPLY")" |
778 | ;; | 777 | ;; |
779 | (2*) # OK | 778 | 2*) # OK |
780 | # The `20' family of requests is like HTTP's `200' family: it | 779 | # The `20' family of requests is like HTTP's `200' family: it |
781 | # means that the request worked and the server is sending the | 780 | # means that the request worked and the server is sending the |
782 | # requested content. | 781 | # requested content. |
@@ -811,7 +810,7 @@ gemini_response() { # gemini_response URL | |||
811 | passthru | 810 | passthru |
812 | } | run display "$meta" "${title:-}" | 811 | } | run display "$meta" "${title:-}" |
813 | ;; | 812 | ;; |
814 | (3*) # REDIRECT | 813 | 3*) # REDIRECT |
815 | # Redirects are a fundamental part of any hypertext framework, | 814 | # Redirects are a fundamental part of any hypertext framework, |
816 | # and if I remember correctly, one of the main reasons | 815 | # and if I remember correctly, one of the main reasons |
817 | # solderpunk and others began thinking about gemini (the others | 816 | # solderpunk and others began thinking about gemini (the others |
@@ -838,51 +837,51 @@ gemini_response() { # gemini_response URL | |||
838 | # will also be an option, however. | 837 | # will also be an option, however. |
839 | run blastoff "$meta" # TODO: confirm redirect | 838 | run blastoff "$meta" # TODO: confirm redirect |
840 | ;; | 839 | ;; |
841 | (4*) # TEMPORARY ERROR | 840 | 4*) # TEMPORARY ERROR |
842 | # Since the 4* codes ([3] Appendix 1) are all server issues, | 841 | # Since the 4* codes ([3] Appendix 1) are all server issues, |
843 | # bollux can treat them all basically the same. This is an area | 842 | # bollux can treat them all basically the same. This is an area |
844 | # that could use some expansion. | 843 | # that could use some expansion. |
845 | local desc="Temporary error" | 844 | local desc="Temporary error" |
846 | case "$code" in | 845 | case "$code" in |
847 | (41) desc+=" (server unavailable)" ;; | 846 | 41) desc+=" (server unavailable)" ;; |
848 | (42) desc+=" (CGI error)" ;; | 847 | 42) desc+=" (CGI error)" ;; |
849 | (43) desc+=" (proxy error)" ;; | 848 | 43) desc+=" (proxy error)" ;; |
850 | (44) desc+=" (slow down)" ;; # could be particularly improved | 849 | 44) desc+=" (slow down)" ;; # could be particularly improved |
851 | esac | 850 | esac |
852 | REDIRECTS=0 | 851 | REDIRECTS=0 |
853 | die "$((100 + code))" "$desc [$code]: $meta" | 852 | die "$((100 + code))" "$desc [$code]: $meta" |
854 | ;; | 853 | ;; |
855 | (5*) # PERMANENT ERROR | 854 | 5*) # PERMANENT ERROR |
856 | # The situation with the 5* codes is basically similar to the 4* | 855 | # The situation with the 5* codes is basically similar to the 4* |
857 | # codes. It could maybe use more thought as to what behavior to | 856 | # codes. It could maybe use more thought as to what behavior to |
858 | # implement. Maybe adding the (bad) requests to history, | 857 | # implement. Maybe adding the (bad) requests to history, |
859 | # subject to configuration? | 858 | # subject to configuration? |
860 | local desc="Permanent failure" | 859 | local desc="Permanent failure" |
861 | case "$code" in | 860 | case "$code" in |
862 | (51) desc+=" (not found)" ;; | 861 | 51) desc+=" (not found)" ;; |
863 | (52) desc+=" (gone)" ;; | 862 | 52) desc+=" (gone)" ;; |
864 | (53) desc+=" (proxy request refused)" ;; | 863 | 53) desc+=" (proxy request refused)" ;; |
865 | # For some reason, codes 54--58 inclusive aren't used. | 864 | # For some reason, codes 54--58 inclusive aren't used. |
866 | (59) desc+=" (bad request)" ;; | 865 | 59) desc+=" (bad request)" ;; |
867 | esac | 866 | esac |
868 | REDIRECTS=0 | 867 | REDIRECTS=0 |
869 | die "$((100 + code))" "$desc [$code]: $meta" | 868 | die "$((100 + code))" "$desc [$code]: $meta" |
870 | ;; | 869 | ;; |
871 | (6*) # CERTIFICATE ERROR (TODO) | 870 | 6*) # CERTIFICATE ERROR (TODO) |
872 | # Dealing with certificates is honestly the most important | 871 | # Dealing with certificates is honestly the most important |
873 | # feature missing from bollux to get it to 1.0. Right now, | 872 | # feature missing from bollux to get it to 1.0. Right now, |
874 | # bollux deals with 6* status codes identically to 4* and 5* | 873 | # bollux deals with 6* status codes identically to 4* and 5* |
875 | # codes. This is not ideal, in the slightest. | 874 | # codes. This is not ideal, in the slightest. |
876 | local desc="Client certificate required" | 875 | local desc="Client certificate required" |
877 | case "$code" in | 876 | case "$code" in |
878 | (61) desc+=" (certificate not authorized)" ;; | 877 | 61) desc+=" (certificate not authorized)" ;; |
879 | (62) desc+=" (certificate not valid)" ;; | 878 | 62) desc+=" (certificate not valid)" ;; |
880 | esac | 879 | esac |
881 | REDIRECTS=0 | 880 | REDIRECTS=0 |
882 | log d "Not implemented: Client certificates" | 881 | log d "Not implemented: Client certificates" |
883 | die "$((100 + code))" "[$code] $meta" | 882 | die "$((100 + code))" "[$code] $meta" |
884 | ;; | 883 | ;; |
885 | (*) # UNKNOWN | 884 | *) # UNKNOWN |
886 | # Just in case we get a weird, un-spec-compliant status code. | 885 | # Just in case we get a weird, un-spec-compliant status code. |
887 | [[ -z "${code-}" ]] && die 100 "Empty response code." | 886 | [[ -z "${code-}" ]] && die 100 "Empty response code." |
888 | die "$((100 + code))" "Unknown response code: $code." | 887 | die "$((100 + code))" "Unknown response code: $code." |
@@ -916,9 +915,9 @@ gopher_request() { # gopher_request URL | |||
916 | # [7] Section 2.1 | 915 | # [7] Section 2.1 |
917 | [[ "$url" =~ gopher://([^/?#:]*)(:([0-9]+))?(/((.))?(/?.*))?$ ]] | 916 | [[ "$url" =~ gopher://([^/?#:]*)(:([0-9]+))?(/((.))?(/?.*))?$ ]] |
918 | local server="${BASH_REMATCH[1]}" \ | 917 | local server="${BASH_REMATCH[1]}" \ |
919 | port="${BASH_REMATCH[3]:-$BOLLUX_GOPHER_PORT}" \ | 918 | port="${BASH_REMATCH[3]:-$BOLLUX_GOPHER_PORT}" \ |
920 | type="${BASH_REMATCH[6]:-1}" \ | 919 | type="${BASH_REMATCH[6]:-1}" \ |
921 | path="${BASH_REMATCH[7]}" | 920 | path="${BASH_REMATCH[7]}" |
922 | log d "URL='$url' SERVER='$server' TYPE='$type' PATH='$path'" | 921 | log d "URL='$url' SERVER='$server' TYPE='$type' PATH='$path'" |
923 | 922 | ||
924 | # Bash has this really neat feature where it can open a TCP socket | 923 | # Bash has this really neat feature where it can open a TCP socket |
@@ -952,25 +951,25 @@ gopher_response() { # gopher_response URL | |||
952 | # text-ish, it only concerns itself with those in this case statement. | 951 | # text-ish, it only concerns itself with those in this case statement. |
953 | # All the others are simply downloaded. | 952 | # All the others are simply downloaded. |
954 | case "$type" in | 953 | case "$type" in |
955 | (0) # Item is a file | 954 | 0) # Item is a file |
956 | # Since gopher doesn't send MIME-type information in-band, we | 955 | # Since gopher doesn't send MIME-type information in-band, we |
957 | # just assume it's text/plain, and try to convert it later to | 956 | # just assume it's text/plain, and try to convert it later to |
958 | # UTF-8 with `iconv'. | 957 | # UTF-8 with `iconv'. |
959 | run display text/plain | 958 | run display text/plain |
960 | ;; | 959 | ;; |
961 | (1) # Item is a directory [gophermap] | 960 | 1) # Item is a directory [gophermap] |
962 | # Since I've already written all the code to typeset gemini | 961 | # Since I've already written all the code to typeset gemini |
963 | # well, it's easy to convert a gophermap to text/gemini and | 962 | # well, it's easy to convert a gophermap to text/gemini and |
964 | # display it than to write a whole new gophermap typesetter. | 963 | # display it than to write a whole new gophermap typesetter. |
965 | run gopher_convert | run display text/gemini | 964 | run gopher_convert | run display text/gemini |
966 | ;; | 965 | ;; |
967 | (3) # Error | 966 | 3) # Error |
968 | # I don't know all the gopher error cases, and the spec is | 967 | # I don't know all the gopher error cases, and the spec is |
969 | # pretty quiet on them. So bollux just signals failure and | 968 | # pretty quiet on them. So bollux just signals failure and |
970 | # bails. | 969 | # bails. |
971 | die 203 "GOPHER: failed" | 970 | die 203 "GOPHER: failed" |
972 | ;; | 971 | ;; |
973 | (7) # Item is an Index-Search server | 972 | 7) # Item is an Index-Search server |
974 | # Gopher search queries are separated from their resources by a | 973 | # Gopher search queries are separated from their resources by a |
975 | # TAB. It's wild. | 974 | # TAB. It's wild. |
976 | if [[ "$url" =~ $'\t' ]]; then | 975 | if [[ "$url" =~ $'\t' ]]; then |
@@ -980,7 +979,7 @@ gopher_response() { # gopher_response URL | |||
980 | run blastoff "$url $REPLY" | 979 | run blastoff "$url $REPLY" |
981 | fi | 980 | fi |
982 | ;; | 981 | ;; |
983 | (*) # Anything else | 982 | *) # Anything else |
984 | # The list at [6] Section 3.8 includes the following (noted where it | 983 | # The list at [6] Section 3.8 includes the following (noted where it |
985 | # might be good to differently handle them in the future): | 984 | # might be good to differently handle them in the future): |
986 | # | 985 | # |
@@ -1030,19 +1029,19 @@ gopher_convert() { | |||
1030 | continue | 1029 | continue |
1031 | fi | 1030 | fi |
1032 | case "$type" in | 1031 | case "$type" in |
1033 | (.) # end of file | 1032 | .) # end of file |
1034 | printf '.\n' | 1033 | printf '.\n' |
1035 | break | 1034 | break |
1036 | ;; | 1035 | ;; |
1037 | (i) # label | 1036 | i) # label |
1038 | case "$label" in | 1037 | case "$label" in |
1039 | ('#'* | '*'[[:space:]]*) | 1038 | '#'* | '*'[[:space:]]*) |
1040 | if $pre; then | 1039 | if $pre; then |
1041 | printf '%s\n' '```' | 1040 | printf '%s\n' '```' |
1042 | pre=false | 1041 | pre=false |
1043 | fi | 1042 | fi |
1044 | ;; | 1043 | ;; |
1045 | (*) | 1044 | *) |
1046 | if ! $pre; then | 1045 | if ! $pre; then |
1047 | printf '%s\n' '```' | 1046 | printf '%s\n' '```' |
1048 | pre=true | 1047 | pre=true |
@@ -1051,28 +1050,28 @@ gopher_convert() { | |||
1051 | esac | 1050 | esac |
1052 | printf '%s\n' "$label" | 1051 | printf '%s\n' "$label" |
1053 | ;; | 1052 | ;; |
1054 | (h) # html link | 1053 | h) # html link |
1055 | if $pre; then | 1054 | if $pre; then |
1056 | printf '%s\n' '```' | 1055 | printf '%s\n' '```' |
1057 | pre=false | 1056 | pre=false |
1058 | fi | 1057 | fi |
1059 | printf '=> %s %s\n' "${path:4}" "$label" | 1058 | printf '=> %s %s\n' "${path:4}" "$label" |
1060 | ;; | 1059 | ;; |
1061 | (T) # telnet link | 1060 | T) # telnet link |
1062 | if $pre; then | 1061 | if $pre; then |
1063 | printf '%s\n' '```' | 1062 | printf '%s\n' '```' |
1064 | pre=false | 1063 | pre=false |
1065 | fi | 1064 | fi |
1066 | printf '=> telnet://%s:%s/%s%s %s\n' \ | 1065 | printf '=> telnet://%s:%s/%s%s %s\n' \ |
1067 | "$server" "$port" "$type" "$path" "$label" | 1066 | "$server" "$port" "$type" "$path" "$label" |
1068 | ;; | 1067 | ;; |
1069 | (*) # other type | 1068 | *) # other type |
1070 | if $pre; then | 1069 | if $pre; then |
1071 | printf '%s\n' '```' | 1070 | printf '%s\n' '```' |
1072 | pre=false | 1071 | pre=false |
1073 | fi | 1072 | fi |
1074 | printf '=> gopher://%s:%s/%s%s %s\n' \ | 1073 | printf '=> gopher://%s:%s/%s%s %s\n' \ |
1075 | "$server" "$port" "$type" "$path" "$label" | 1074 | "$server" "$port" "$type" "$path" "$label" |
1076 | ;; | 1075 | ;; |
1077 | esac | 1076 | esac |
1078 | done | 1077 | done |
@@ -1109,7 +1108,7 @@ display() { # display METADATA [TITLE] | |||
1109 | for ((i = 1; i <= "${#hdr[@]}"; i++)); do | 1108 | for ((i = 1; i <= "${#hdr[@]}"; i++)); do |
1110 | h="${hdr[$i]}" | 1109 | h="${hdr[$i]}" |
1111 | case "$h" in | 1110 | case "$h" in |
1112 | (*charset=*) charset="${h#*=}" ;; | 1111 | *charset=*) charset="${h#*=}" ;; |
1113 | esac | 1112 | esac |
1114 | done | 1113 | done |
1115 | 1114 | ||
@@ -1119,7 +1118,7 @@ display() { # display METADATA [TITLE] | |||
1119 | log debug "mime='$mime'; charset='$charset'" | 1118 | log debug "mime='$mime'; charset='$charset'" |
1120 | 1119 | ||
1121 | case "$mime" in | 1120 | case "$mime" in |
1122 | (text/*) | 1121 | text/*) |
1123 | set_title "$title${title:+ - }bollux" | 1122 | set_title "$title${title:+ - }bollux" |
1124 | # Build the `less' command | 1123 | # Build the `less' command |
1125 | less_cmd=(less) | 1124 | less_cmd=(less) |
@@ -1163,7 +1162,7 @@ display() { # display METADATA [TITLE] | |||
1163 | run "${less_cmd[@]}" && bollux_quit | 1162 | run "${less_cmd[@]}" && bollux_quit |
1164 | } || run handle_keypress "$?" | 1163 | } || run handle_keypress "$?" |
1165 | ;; | 1164 | ;; |
1166 | (*) run download "$BOLLUX_URL" ;; | 1165 | *) run download "$BOLLUX_URL" ;; |
1167 | esac | 1166 | esac |
1168 | } | 1167 | } |
1169 | 1168 | ||
@@ -1173,8 +1172,8 @@ less_prompt_escape() { # less_prompt_escape STRING | |||
1173 | for ((i = 0; i < ${#1}; i++)); do | 1172 | for ((i = 0; i < ${#1}; i++)); do |
1174 | : "${1:i:1}" | 1173 | : "${1:i:1}" |
1175 | case "$_" in | 1174 | case "$_" in |
1176 | ([\?:\.%\\]) printf '\%s' "$_" ;; | 1175 | [\?:\.%\\]) printf '\%s' "$_" ;; |
1177 | (*) printf '%s' "$_" ;; | 1176 | *) printf '%s' "$_" ;; |
1178 | esac | 1177 | esac |
1179 | done | 1178 | done |
1180 | printf '\n' | 1179 | printf '\n' |
@@ -1232,7 +1231,7 @@ typeset_gemini() { | |||
1232 | 1231 | ||
1233 | while IFS= read -r; do | 1232 | while IFS= read -r; do |
1234 | case "$REPLY" in | 1233 | case "$REPLY" in |
1235 | ('```'*) | 1234 | '```'*) |
1236 | PRE_LINE_FORCE=false | 1235 | PRE_LINE_FORCE=false |
1237 | if $pre; then | 1236 | if $pre; then |
1238 | pre=false | 1237 | pre=false |
@@ -1240,28 +1239,28 @@ typeset_gemini() { | |||
1240 | pre=true | 1239 | pre=true |
1241 | fi | 1240 | fi |
1242 | case "${T_PRE_DISPLAY%%,*}" in | 1241 | case "${T_PRE_DISPLAY%%,*}" in |
1243 | (pre) | 1242 | pre) |
1244 | : | 1243 | : |
1245 | ;; | 1244 | ;; |
1246 | (alt | both) | 1245 | alt | both) |
1247 | $pre && PRE_LINE_FORCE=true \ | 1246 | $pre && PRE_LINE_FORCE=true \ |
1248 | gemini_pre "${REPLY#\`\`\`}" | 1247 | gemini_pre "${REPLY#\`\`\`}" |
1249 | ;; | 1248 | ;; |
1250 | esac | 1249 | esac |
1251 | continue | 1250 | continue |
1252 | ;; | 1251 | ;; |
1253 | ('=>'*) | 1252 | '=>'*) |
1254 | : $((ln += 1)) | 1253 | : $((ln += 1)) |
1255 | gemini_link "$REPLY" $pre "$ln" | 1254 | gemini_link "$REPLY" $pre "$ln" |
1256 | ;; | 1255 | ;; |
1257 | ('#'*) gemini_header "$REPLY" $pre ;; | 1256 | '#'*) gemini_header "$REPLY" $pre ;; |
1258 | ('*'[[:space:]]*) | 1257 | '*'[[:space:]]*) |
1259 | gemini_list "$REPLY" $pre | 1258 | gemini_list "$REPLY" $pre |
1260 | ;; | 1259 | ;; |
1261 | ('>'*) | 1260 | '>'*) |
1262 | gemini_quote "$REPLY" $pre | 1261 | gemini_quote "$REPLY" $pre |
1263 | ;; | 1262 | ;; |
1264 | (*) gemini_text "$REPLY" $pre ;; | 1263 | *) gemini_text "$REPLY" $pre ;; |
1265 | esac | 1264 | esac |
1266 | done | 1265 | done |
1267 | } | 1266 | } |
@@ -1282,13 +1281,13 @@ gemini_link() { | |||
1282 | printf "\e[${C_SIGIL}m%${S_MARGIN}s ${C_RESET}" "$s" | 1281 | printf "\e[${C_SIGIL}m%${S_MARGIN}s ${C_RESET}" "$s" |
1283 | printf "\e[${C_LINK_NUMBER}m[%d]${C_RESET} " "$ln" | 1282 | printf "\e[${C_LINK_NUMBER}m[%d]${C_RESET} " "$ln" |
1284 | fold_line -n -B "\e[${C_LINK_TITLE}m" -A "${C_RESET}" \ | 1283 | fold_line -n -B "\e[${C_LINK_TITLE}m" -A "${C_RESET}" \ |
1285 | -l "$((${#ln} + 3))" -m "${T_MARGIN}" \ | 1284 | -l "$((${#ln} + 3))" -m "${T_MARGIN}" \ |
1286 | "$WIDTH" "$(trim_string "$t")" | 1285 | "$WIDTH" "$(trim_string "$t")" |
1287 | fold_line -B " \e[${C_LINK_URL}m" \ | 1286 | fold_line -B " \e[${C_LINK_URL}m" \ |
1288 | -A "${C_RESET}" \ | 1287 | -A "${C_RESET}" \ |
1289 | -l "$((${#ln} + 3 + ${#t}))" \ | 1288 | -l "$((${#ln} + 3 + ${#t}))" \ |
1290 | -m "$((T_MARGIN + ${#ln} + 2))" \ | 1289 | -m "$((T_MARGIN + ${#ln} + 2))" \ |
1291 | "$WIDTH" "$a" | 1290 | "$WIDTH" "$a" |
1292 | else | 1291 | else |
1293 | gemini_pre "$1" | 1292 | gemini_pre "$1" |
1294 | fi | 1293 | fi |
@@ -1306,7 +1305,7 @@ gemini_header() { | |||
1306 | 1305 | ||
1307 | printf "\e[${C_SIGIL}m%${S_MARGIN}s ${C_RESET}" "$s" | 1306 | printf "\e[${C_SIGIL}m%${S_MARGIN}s ${C_RESET}" "$s" |
1308 | fold_line -B "\e[${hdrfmt}m" -A "${C_RESET}" -m "${T_MARGIN}" \ | 1307 | fold_line -B "\e[${hdrfmt}m" -A "${C_RESET}" -m "${T_MARGIN}" \ |
1309 | "$WIDTH" "$t" | 1308 | "$WIDTH" "$t" |
1310 | else | 1309 | else |
1311 | gemini_pre "$1" | 1310 | gemini_pre "$1" |
1312 | fi | 1311 | fi |
@@ -1321,7 +1320,7 @@ gemini_list() { | |||
1321 | 1320 | ||
1322 | printf "\e[${C_SIGIL}m%${S_MARGIN}s ${C_RESET}" "$s" | 1321 | printf "\e[${C_SIGIL}m%${S_MARGIN}s ${C_RESET}" "$s" |
1323 | fold_line -B "\e[${C_LIST}m" -A "${C_RESET}" -m "$T_MARGIN" \ | 1322 | fold_line -B "\e[${C_LIST}m" -A "${C_RESET}" -m "$T_MARGIN" \ |
1324 | "$WIDTH" "$t" | 1323 | "$WIDTH" "$t" |
1325 | else | 1324 | else |
1326 | gemini_pre "$1" | 1325 | gemini_pre "$1" |
1327 | fi | 1326 | fi |
@@ -1336,7 +1335,7 @@ gemini_quote() { | |||
1336 | 1335 | ||
1337 | printf "\e[${C_SIGIL}m%${S_MARGIN}s ${C_RESET}" "$s" | 1336 | printf "\e[${C_SIGIL}m%${S_MARGIN}s ${C_RESET}" "$s" |
1338 | fold_line -B "\e[${C_QUOTE}m" -A "${C_RESET}" -m "$T_MARGIN" \ | 1337 | fold_line -B "\e[${C_QUOTE}m" -A "${C_RESET}" -m "$T_MARGIN" \ |
1339 | "$WIDTH" "$t" | 1338 | "$WIDTH" "$t" |
1340 | else | 1339 | else |
1341 | gemini_pre "$1" | 1340 | gemini_pre "$1" |
1342 | fi | 1341 | fi |
@@ -1346,7 +1345,7 @@ gemini_text() { | |||
1346 | if ! ${2-false}; then | 1345 | if ! ${2-false}; then |
1347 | printf "%${S_MARGIN}s " ' ' | 1346 | printf "%${S_MARGIN}s " ' ' |
1348 | fold_line -m "$T_MARGIN" \ | 1347 | fold_line -m "$T_MARGIN" \ |
1349 | "$WIDTH" "$1" | 1348 | "$WIDTH" "$1" |
1350 | else | 1349 | else |
1351 | gemini_pre "$1" | 1350 | gemini_pre "$1" |
1352 | fi | 1351 | fi |
@@ -1370,25 +1369,25 @@ fold_line() { # fold_line [OPTIONS...] WIDTH TEXT | |||
1370 | OPTIND=0 | 1369 | OPTIND=0 |
1371 | while getopts nm:f:l:B:A: OPT; do | 1370 | while getopts nm:f:l:B:A: OPT; do |
1372 | case "$OPT" in | 1371 | case "$OPT" in |
1373 | (n) # -n = no trailing newline | 1372 | n) # -n = no trailing newline |
1374 | newline=false | 1373 | newline=false |
1375 | ;; | 1374 | ;; |
1376 | (m) # -m MARGIN = margin for all lines | 1375 | m) # -m MARGIN = margin for all lines |
1377 | margin_all="$OPTARG" | 1376 | margin_all="$OPTARG" |
1378 | ;; | 1377 | ;; |
1379 | (f) # -f MARGIN = margin for first line | 1378 | f) # -f MARGIN = margin for first line |
1380 | margin_first="$OPTARG" | 1379 | margin_first="$OPTARG" |
1381 | ;; | 1380 | ;; |
1382 | (l) # -l LENGTH = length of line before starting fold | 1381 | l) # -l LENGTH = length of line before starting fold |
1383 | ll="$OPTARG" | 1382 | ll="$OPTARG" |
1384 | ;; | 1383 | ;; |
1385 | (B) # -B BEFORE = text to insert before each line | 1384 | B) # -B BEFORE = text to insert before each line |
1386 | before="$OPTARG" | 1385 | before="$OPTARG" |
1387 | ;; | 1386 | ;; |
1388 | (A) # -A AFTER = text to insert after each line | 1387 | A) # -A AFTER = text to insert after each line |
1389 | after="$OPTARG" | 1388 | after="$OPTARG" |
1390 | ;; | 1389 | ;; |
1391 | (*) return 1 ;; | 1390 | *) return 1 ;; |
1392 | esac | 1391 | esac |
1393 | done | 1392 | done |
1394 | shift "$((OPTIND - 1))" | 1393 | shift "$((OPTIND - 1))" |
@@ -1426,37 +1425,37 @@ fold_line() { # fold_line [OPTIONS...] WIDTH TEXT | |||
1426 | # use the exit code from less (see mklesskey) to do things | 1425 | # use the exit code from less (see mklesskey) to do things |
1427 | handle_keypress() { # handle_keypress CODE | 1426 | handle_keypress() { # handle_keypress CODE |
1428 | case "$1" in | 1427 | case "$1" in |
1429 | (48) # o - open a link -- show a menu of links on the page | 1428 | 48) # o - open a link -- show a menu of links on the page |
1430 | run select_url "$BOLLUX_PAGESRC" | 1429 | run select_url "$BOLLUX_PAGESRC" |
1431 | ;; | 1430 | ;; |
1432 | (49) # g - goto a url -- input a new url | 1431 | 49) # g - goto a url -- input a new url |
1433 | prompt GO | 1432 | prompt GO |
1434 | run blastoff -u "$REPLY" | 1433 | run blastoff -u "$REPLY" |
1435 | ;; | 1434 | ;; |
1436 | (50) # [ - back in the history | 1435 | 50) # [ - back in the history |
1437 | run history_back || { | 1436 | run history_back || { |
1438 | sleep 0.5 | 1437 | sleep 0.5 |
1439 | run blastoff "$BOLLUX_URL" | 1438 | run blastoff "$BOLLUX_URL" |
1440 | } | 1439 | } |
1441 | ;; | 1440 | ;; |
1442 | (51) # ] - forward in the history | 1441 | 51) # ] - forward in the history |
1443 | run history_forward || { | 1442 | run history_forward || { |
1444 | sleep 0.5 | 1443 | sleep 0.5 |
1445 | run blastoff "$BOLLUX_URL" | 1444 | run blastoff "$BOLLUX_URL" |
1446 | } | 1445 | } |
1447 | ;; | 1446 | ;; |
1448 | (52) # r - re-request the current resource | 1447 | 52) # r - re-request the current resource |
1449 | run blastoff "$BOLLUX_URL" | 1448 | run blastoff "$BOLLUX_URL" |
1450 | ;; | 1449 | ;; |
1451 | (53) # G - goto a url (pre-filled with current) | 1450 | 53) # G - goto a url (pre-filled with current) |
1452 | run prompt -u GO | 1451 | run prompt -u GO |
1453 | run blastoff -u "$REPLY" | 1452 | run blastoff -u "$REPLY" |
1454 | ;; | 1453 | ;; |
1455 | (54) # ` - change alt-text visibility and refresh | 1454 | 54) # ` - change alt-text visibility and refresh |
1456 | run list_cycle T_PRE_DISPLAY , | 1455 | run list_cycle T_PRE_DISPLAY , |
1457 | run blastoff "$BOLLUX_URL" | 1456 | run blastoff "$BOLLUX_URL" |
1458 | ;; | 1457 | ;; |
1459 | (55) # 55-57 -- still available for binding | 1458 | 55) # 55-57 -- still available for binding |
1460 | die "$?" "less(1) error" | 1459 | die "$?" "less(1) error" |
1461 | ;; | 1460 | ;; |
1462 | esac | 1461 | esac |
@@ -1473,8 +1472,8 @@ select_url() { # select_url FILE | |||
1473 | PS3="OPEN> " | 1472 | PS3="OPEN> " |
1474 | select u in "${MAPFILE[@]}"; do | 1473 | select u in "${MAPFILE[@]}"; do |
1475 | case "$REPLY" in | 1474 | case "$REPLY" in |
1476 | (q) bollux_quit ;; | 1475 | q) bollux_quit ;; |
1477 | ([^0-9]*) run blastoff -u "$REPLY" && break ;; | 1476 | [^0-9]*) run blastoff -u "$REPLY" && break ;; |
1478 | esac | 1477 | esac |
1479 | run blastoff "${u%%[[:space:]]*}" && break | 1478 | run blastoff "${u%%[[:space:]]*}" && break |
1480 | done </dev/tty | 1479 | done </dev/tty |
@@ -1543,12 +1542,12 @@ history_append() { # history_append URL TITLE | |||
1543 | 1542 | ||
1544 | # Print the URL and its title (if given) to $BOLLUX_HISTFILE. | 1543 | # Print the URL and its title (if given) to $BOLLUX_HISTFILE. |
1545 | local fmt='' | 1544 | local fmt='' |
1546 | fmt+='%(%FT%T)T\t' # %(_)T calls directly to 'strftime'. | 1545 | fmt+='%(%FT%T)T\t' # %(_)T calls directly to 'strftime'. |
1547 | if (( $# == 2 )); then | 1546 | if (($# == 2)); then |
1548 | fmt+='%s\t' # $url | 1547 | fmt+='%s\t' # $url |
1549 | fmt+='%s\n' # $title | 1548 | fmt+='%s\n' # $title |
1550 | else | 1549 | else |
1551 | fmt+='%s%s\n' # printf needs a field for every argument. | 1550 | fmt+='%s%s\n' # printf needs a field for every argument. |
1552 | fi | 1551 | fi |
1553 | run printf -- "$fmt" -1 "$url" "$title" >>"$BOLLUX_HISTFILE" | 1552 | run printf -- "$fmt" -1 "$url" "$title" >>"$BOLLUX_HISTFILE" |
1554 | 1553 | ||
@@ -1567,26 +1566,26 @@ history_back() { | |||
1567 | # one with each call to `history_append'. If we subtract 1, we'll just | 1566 | # one with each call to `history_append'. If we subtract 1, we'll just |
1568 | # be at the end of the array again, reloading the page. | 1567 | # be at the end of the array again, reloading the page. |
1569 | ((HN -= 2)) | 1568 | ((HN -= 2)) |
1570 | 1569 | ||
1571 | if ((HN < 0)); then | 1570 | if ((HN < 0)); then |
1572 | HN=0 | 1571 | HN=0 |
1573 | log e "Beginning of history." | 1572 | log e "Beginning of history." |
1574 | return 1 | 1573 | return 1 |
1575 | fi | 1574 | fi |
1576 | 1575 | ||
1577 | run blastoff "${HISTORY[$HN]}" | 1576 | run blastoff "${HISTORY[$HN]}" |
1578 | } | 1577 | } |
1579 | 1578 | ||
1580 | # Move forward in session history. | 1579 | # Move forward in session history. |
1581 | history_forward() { | 1580 | history_forward() { |
1582 | log d "HN=$HN" | 1581 | log d "HN=$HN" |
1583 | 1582 | ||
1584 | if ((HN >= ${#HISTORY[@]})); then | 1583 | if ((HN >= ${#HISTORY[@]})); then |
1585 | HN="${#HISTORY[@]}" | 1584 | HN="${#HISTORY[@]}" |
1586 | log e "End of history." | 1585 | log e "End of history." |
1587 | return 1 | 1586 | return 1 |
1588 | fi | 1587 | fi |
1589 | 1588 | ||
1590 | run blastoff "${HISTORY[$HN]}" | 1589 | run blastoff "${HISTORY[$HN]}" |
1591 | } | 1590 | } |
1592 | 1591 | ||
@@ -1646,8 +1645,8 @@ blastoff() { # blastoff [-u] URL | |||
1646 | run "${url[1]}_response" "$url" | 1645 | run "${url[1]}_response" "$url" |
1647 | else | 1646 | else |
1648 | log d \ | 1647 | log d \ |
1649 | "No response handler for '${url[1]}';" \ | 1648 | "No response handler for '${url[1]}';" \ |
1650 | " passing thru" | 1649 | " passing thru" |
1651 | passthru | 1650 | passthru |
1652 | fi | 1651 | fi |
1653 | } | 1652 | } |