mini gopher cient "nago" updated I updated the "nano-gopher" client nago, and put it into the scripts section of my gopherspace. It is a very simple client, pure shell script, using anything from netcat, socat, or snarf to request directories and files from a gopher server and to display them. Selection in directories is done via entering the corresponding number. The script can be adapted to personal preferences, although it already respects some environment variables. For illustration, I append here the current version: #!/bin/sh # $Id: nago.sh,v 1.8 2009/11/24 12:20:26 yargo Exp $ # licenced under GPL 2005 Yargo C Bonetti # external programs pager=${PAGER:-more} browser=${BROWSER:-lynx -force_html} telnet=${TELNET:-telnet} #mync () { ${NETCAT:-/sys/pkg/sbin/nc} "$@" ; } #mync () { socat tcp4:$1:$2 - ; } mync () { read gf ; snarf "gopher://$1:$2/$gf" '-'; } STDHOME=sdf.lonestar.org/ # just in case somebody changes the standard ;-) gopherport=70 gopherhome=${GOPHER_HOME:-$STDHOME} # temporary files tmpbase=/tmp tmpprefix=$(basename $0)tmp dirtmp=$tmpbase/$tmpprefix.$$.dir ftmp=$tmpbase/$tmpprefix.$$.tmp stack=$tmpbase/$tmpprefix.$$.stack if [ "$1" = "" ] ; then cat <<EOH usage: $0 [-h|<server>] [<directory> <port>] where <server> is a server in gopherspace, <directory> a subdir on it, and <port> the port to connect to (default $gopherport) e.g: $0 sdf.lonestar.org /users/yargo -h uses environment variable GOPHER_HOME as starting point (currently $GOPHER_HOME), or if that is empty, $STDHOME (only default port $gopherport is supported, and must be a directory) Note: will not work for retrieving a file directly! (undefined behaviour) (GPLed 2005 Yargo C Bonetti) EOH exit 1 fi rmexit () { rm -f $dirtmp $ftmp $stack ; exit $1 ; } # make sure temporary files are writable rm -f $dirtmp $ftmp $stack if ! echo test > $dirtmp ; then echo "** cannot write into temporary file $dirtmp - giving up!" rmexit 9 fi if ! echo test > $ftmp ; then echo "** cannot write into temporary file $ftmp - giving up!" rmexit 9 fi if ! echo test > $stack ; then echo "** cannot write into stack file $stack - giving up!" rmexit 9 fi if [ "$1" = "-h" ] ; then # remove / and all after s_ser=${gopherhome%%/*} # remove first / and all before, and prepend / again s_dir=/${gopherhome#*/} s_por=$gopherport else s_ser=$1 s_dir=/$2 s_por=${3:-$gopherport} fi # selector type: directory s_typ=1 echo "starting at $s_ser:$s_por$s_dir" # get a directory $s_dir from server $s_ser , port $s_por, # preprocess it, and store it getdir () { # get directory, replace SPC by _ if echo "$s_dir" | mync "$s_ser" "$s_por" | sed -e 's/ /_/g' -e 's/ # line number counter ln=1 # add title = server directory, will also represent selectable line number echo " 0 $s_ser:$s_por $s_dir" >$dirtmp # now process every line in turn cat $ftmp | { while read ft rest ; do # test filetype=1st character case $ft in # i=fake, don't generate a number - note: there are TABs in the two strings! i*) echo ". $ft $rest" >>$dirtmp ;; # otherwise it is an entry which may be selected: prepend number, increment *) echo " $ln $ft $rest" >>$dirtmp ; ln=$(($ln+1)) ;; esac done } else # cannot get directory, error return 1 fi } # definitions for actions: ACT_back=0 ACT_select=1 ACT_quit=2 ACT_other=3 # show directory (in $dirtmp), and return selection type, dir, server, port # and action in variables s_typ, s_dir, s_ser, s_por, s_act selectdir () { # take field 1&2 only, remove 1 char after first tab (filetype), # restore SPC, store (note: TABs in sed command!) cat $dirtmp | cut -f 1-2 | sed -e 's/ ./ /' -e 's/_/ /g' >$ftmp ln=X act=$ACT_select # repeat until legal linenumber given (note: 0 is legal!) while ! grep "^ $ln " $dirtmp >/dev/null ; do # show directory $pager $ftmp echo "** enter line number (0 or b for back), o)pen other, or x)it q)uit!" read inp case $inp in # set action flag q*|x*) ln=0 ; act=$ACT_quit ;; o*) ln=0 ; act=$ACT_other echo "other server? (empty=same)" read inp s_ser=${inp:-$s_ser} echo "port? (empty=$gopherport)" read inp s_por=${inp:-$gopherport} echo "directory? (may be empty)" read s_dir ;; b*) ln=0 ; act=$ACT_back ;; *) ln=${inp:-0} if [ $ln = 0 ] ; then act=$ACT_back else act=$ACT_select fi ;; esac done s_act=$act case $s_act in $ACT_back|$ACT_other) s_typ=1 ;; *) s_typ=$(grep "^ $ln " $dirtmp | cut -f 2 | sed -e 's/\(.\).*/\1/' ) s_por=$(grep "^ $ln " $dirtmp | cut -f 5) # if not enough fields, it's a top level address (server only) if [ "$s_por" = "" ] ; then s_dir=/ s_ser=$(grep "^ $ln " $dirtmp | cut -f 3) s_por=$(grep "^ $ln " $dirtmp | cut -f 4) # otherwise, directory is given as well else s_dir=$(grep "^ $ln " $dirtmp | cut -f 3) s_ser=$(grep "^ $ln " $dirtmp | cut -f 4) fi ;; esac } # save current point in stack pushlevel () { echo "$s_ser $s_por $s_dir" >>$stack } # recall point from stack poplevel () { s_ser=$(tail -n 1 $stack | cut -f 1) s_por=$(tail -n 1 $stack | cut -f 2) s_dir=$(tail -n 1 $stack | cut -f 3) ln=$( wc $stack | { read l dummy ; echo $l ; } ) if [ $ln -gt 0 ] ; then ln=$(($ln-1)) if head -n $ln $stack >$ftmp 2>/dev/null ; then cat $ftmp >$stack else :>$stack fi else echo "** no more data in history, quitting program" rmexit 0 fi } # main program # initialize stack with first arguments, save some "spare" rm -f $stack pushlevel s_act=X while [ $s_act != $ACT_quit ] ; do pushlevel if getdir ; then selectdir case $s_act in $ACT_back) poplevel ; poplevel ;; $ACT_other) echo "going to $s_ser : $s_por, fetching $s_dir" ;; $ACT_select) case $s_typ in 1) echo "changing to $s_dir" ;; 8) echo "telnetting..." $telnet $s_ser $s_por echo "** telnet finished, hit return to continue..." read inp poplevel ;; # otherwise download *) echo "downloading $s_dir ..." if echo "$s_dir" | mync "$s_ser" "$s_por" >$ftmp then case $s_typ in 0) $pager $ftmp ;; h) $browser $ftmp ;; *) echo "cannot display file type $s_typ, only save" ;; esac echo "** enter local filename to save (empty: no saving)" read inp while [ "$inp" != "" ] ; do if [ -f "$inp" ] ; then echo "warning: $inp exists!" elif cat $ftmp >"$inp" ; then break else echo "error: could not write file $inp!" echo "enter local filename to save (empty: no saving)" fi read inp done else echo "cannot download $s_dir!" fi poplevel esac ;; $ACT_quit) echo "bye!" ;; *) echo "** unrecognized command, internal error! trying to go on..." poplevel ;; esac else echo "** error getting $s_dir from $s_ser:$s_por!" poplevel ; poplevel fi done rmexit 0 ( Tue Nov 24 12:43:49 UTC 2009 ) -----