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 )
    -----