nago updated: now correctly handles filenames with spaces
There is a new version of the small Gopher client 'nago', with several
improvements: file names with embedded spaces were not handled correctly,
which is now solved; in directory listings (selector 1), the selector type
is shown at the end of each line (except for i or 1 types), after a slash;
the trailing line containing only a dot is removed from directory listings.

The current version follows (also available in the 'scripts' section of my
Gopherspace). Please note that the script contains strings with embedded
TABs, and it relies on that - so make sure you do not save them converted
into sequences of SPC!
It may be better to get the script from the 'scripts' directory.

#!/bin/sh
# licenced under GPL 2005 Yargo C Bonetti
CVSID='$Id: nago.sh,v 1.15 2010/01/29 00:07:49 yargo Exp $'

# external programs
pager=${PAGER:-more}
pager=more
browser=${BROWSER:-lynx -force_html}
telnet=${TELNET:-telnet}
#imgviewer=display
imgviewer=echo
#mync () { ${NETCAT:-/sys/pkg/sbin/nc} "$@" ; }
#mync () { socat -t9 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=${TEMP:-/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)
 ($CVSID)
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
 if echo "$s_dir" | mync "$s_ser" "$s_por" | sed -e 's/
 then
  oldifs="$IFS"; IFS='	'
# 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=`expr $ln + 1` ;;
   esac
  done
  }
  IFS="$oldifs"
 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), store
# (note TABs in sed argument)
 cat $dirtmp | cut -f 1-2 |
  sed -e 's/	\(.\)\(.*\)/	\2 \/\1/;s/ \/[.i1]$//' >$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, e(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=`expr $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"
  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 [ "$s_typ" = "7" ] ; then
       echo "please enter request string:"
       read request
       s_dir="$s_dir?$request" 
      fi
      if echo "$s_dir" | mync "$s_ser" "$s_por" >$ftmp
      then
       case $s_typ in
       0) $pager $ftmp ;;
       7) $pager $ftmp ;;
       g) $imgviewer $ftmp ;;
       h) $browser $ftmp ;;
       I) $imgviewer $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

::: Fri Jan 29 00:20:33 UTC 2010
::: reply via mailto:yargo+glog@jerq.org?Subject=g100290011
     -----