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