#!/bin/sh ## ## === gosher === ## ## gosher is a simple gopher server in a POSIX shell script: ## ## $ ./gosher [ [] ## ## If PORT is not specified, the default is 70. If GOPHERDIR is not ## specified, "./" is assumed ## ## ## (c) 2018 Vincenzo 'KatolaZ' Nicosia ## ## ###################### ## ## If the script is called with basename "gosher", launch the netcat ## server... ## ## ## NETCAT: the netcat command to use, and any additional option ## ### Original netcat ##NETCAT="nc.traditional" ## ### ncat (from nmap) ##NETCAT="ncat" ## ### Openbsd netcat NETCAT="nc.openbsd" ## ## STYLE: The way in which netcat will talk to gosher_serve ## ### fork with "-c" (Does *not* work with OpenBSD netcat!!!!!) #STYLE='fork' ## ### use named pipes (Does *not* work with original netcat!!!!!) STYLE='pipe' ### prefix of the input FIFO IPREFIX=/tmp/inf_ DEBUG= #DEBUG=yes [ -n "$DEBUG" ] && { set -e set -x } ## function cleanup(){ [ -n "$INF" ] && [ -p "$INF" ] && rm -f ${INF} exit 1 } MYNAME=$(basename $0) MYDIR=$(dirname $(realpath $0)) NETCAT=$(which $NETCAT) if [ -z "${MYNAME#gosher}" ]; then ## we are called as gosher -- launch the server PORT=${1:-70} GOPHERDIR=${2:-"./"} [ ! -f "${NETCAT}" -o ! -x "${NETCAT}" ] && { echo "Wrong NETCAT -- Exiting" >&2 exit 2 } if [ -f "${MYDIR}/gosher_serve" -o -h "${MYDIR}/gosher_serve" ]; then GOSHER_SERVE="${MYDIR}/gosher_serve" trap cleanup 0 HUP INT TRAP TERM QUIT INF=${IPREFIX}$$ [ "$STYLE" = "pipe" ] && { mkfifo -m 600 $INF while [ 1 -eq 1 ]; do ${GOSHER_SERVE} ${GOPHERDIR} <$INF | ${NETCAT} -vvvvv -l -p ${PORT} >$INF done rm -f $INF exit 0 } [ "$STYLE" = 'fork' ] && { while [ 1 -eq 1 ]; do ${NETCAT} -vv -l -p $PORT -c "${GOSHERSERVE} ${GOPHERDIR}" done exit 0 } echo "Wrong STYLE specified -- Exiting" >&2 exit 2 else echo "Cannot find gosher_serve -- Exiting">&2 exit 3 fi fi ###################### ## ## ...otherwise, serve a request ## ## function invalid_selector(){ sel="$1" echo "3Error: Invalid selector: \"$sel\"" printf ".\r\n" exec 1>&- exec 2>&- exit 1 } ## function serve_selector(){ sel="$1" cat "${sel}" echo "$0: selector $sel served -- exiting " >&2 exec 1>&- exec 2>&- exit 0 } ### transform a .gph file into a gophermap ## function serve_index(){ IDX=$1 IFS=' ' while read line; do rline=$(echo $line | sed -r -e 's/\r//g') case $rline in '['*) echo $rline | sed -r -e 's/\[//g;s/\]//g;s/\|/\t/g;s/\t//;s/$/\r/g' ;; t*) echo $rline | cut -c 2- ;; *) echo $line esac done < $IDX printf ".\r\n" exec 1>&- exec 2>&- exit 0 } ### Serve an HTML URL through a redirect page ## function serve_redirect(){ url=$1 cat<< EOF gopher redirect Click to be redirected to: $url EOF exec 1>&- exec 2>&- exit 0 } GOPHERDIR=${1:-"./"} read selector selector=$(echo $selector | sed -r 's:\$.*::g;s:\r::g' ) [ -n "$DEBUG" ] && { echo "iGOPHERDIR: ${GOPHERDIR}" echo "iselector: \"${selector}\"" } case $selector in URL:*) url=$(echo $selector | cut -d ":" -f 2-) serve_redirect $url ;; /?*|"") RP1=$(realpath "${GOPHERDIR}"/"${selector}" || "") [ $? -eq 0 ] || invalid_selector "$selector" RP2=$(realpath "${GOPHERDIR}")"${selector}" [ $? -eq 0 ] || invalid_selector "$selector" [ -n "$DEBUG" ] && { echo "iRP1: ${RP1}" echo "iRP2: ${RP2}" } if [ "${RP1}" = "${RP2}" ]; then if [ -f "${RP1}" ]; then serve_selector "${RP1}" elif [ -d "${RP1}" ]; then [ -f "${RP1}/gophermap" ] && serve_selector "${RP1}/gophermap" [ -f "${RP1}/index.gph" ] && serve_index "${RP1}/index.gph" fi fi invalid_selector "$selector" ;; *) [ -f "${GOPHERDIR}/gophermap" ] && serve_selector "${GOPHERDIR}/gophermap" [ -f "${GOPHERDIR}/index.gph" ] && serve_index "${GOPHERDIR}/index.gph" echo "got invalid selector: \"$selector\"" >&2 invalid_selector "/" ;; esac