about summary refs log tree commit diff
path: root/Misc/zftp-functions
diff options
context:
space:
mode:
Diffstat (limited to 'Misc/zftp-functions')
-rw-r--r--Misc/zftp-functions1281
1 files changed, 0 insertions, 1281 deletions
diff --git a/Misc/zftp-functions b/Misc/zftp-functions
deleted file mode 100644
index a07e46d72..000000000
--- a/Misc/zftp-functions
+++ /dev/null
@@ -1,1281 +0,0 @@
-# zftp is a loadable module implementing an FTP client as a builtin
-# command so that you can use the shell command language and line
-# editing to make life easier.  If your system has dynamically
-# load libraries and zsh was compiled to use them, it is probably
-# somewhere where it can be loaded at run time.  Otherwise, it depends
-# whether the shell was compiled with zftp already built into it.
-#
-# Here is a suite of functions, plus assorted other code, to make
-# zftp work smoothly.
-#
-# Completion is implemented in a fairly natural way, except that
-# very little support has been provided for non-UNIX remote hosts.
-# On such machines, the safest thing to do is only try to complete
-# files in the current directory; this should be OK.
-#
-# Remote globbing for commands which retrieve files is also
-# implemented.  This can be done in two different ways.  The default
-# is for zsh to do the globbing locally.  The advantage is that full
-# zsh pattern matching (respecting the setting of extendedglob) is
-# possible, and no assumption (apart from the restrictions on
-# directory handling noted above) is made about the behaviour of the
-# server.  The disadvantage is that the entire filename list for the
-# current directory must be retrieved, and then zsh must laboriously
-# do pattern matching against every file, so it is potentially slow
-# for large directories.  Only the non-directory part of file names is
-# globbed.
-#
-# The alternative will be used if $zfrglob has non-zero length.
-# Zsh then sends the pattern to the server for globbing.  Best of
-# luck.
-#
-# To support remote globbing, some functions have been aliased
-# with 'noglob' in front.  Currently, this has a dire effect on
-# completion unless the completeinaliases option is set, so
-# it is set below.  This can conceivably cause you problems
-# if you expect completion for aliases automatically to give you
-# completion for the base command.  I suspect that most people
-# don't even know that happens.
-#
-# The following functions are provided.
-#
-# General status changing and displaying functions:
-# zfparams
-#   Simple front end to `zftp params', except it will automatically
-#   query host, user and password.  These are then stored to be
-#   used with a `zfopen' with no arguments.
-# zfopen [ host [ user ... ] ]
-#   Open a connection and login.  Unless the option -1 (once)
-#   is given, will store the parameters for the open (including
-#   a password which is prompted for and not echoed) so that
-#   if you call zfopen subsequently without arguments it will
-#   reopen the same connection.
-# zfanon anonftphost
-#   Open a connection for anonymous FTP.  Tries to guess an
-#   email address to use as the password, unless $EMAIL_ADDR is
-#   already set.  The first time, will tell you what it has guessed.
-#   It's rude to set EMAIL_ADDR=mozilla.
-# zfcd [ dir | old new ]
-#   Change directory on the server.  This tries to mimic the behaviour
-#   of the shell's cd.  In particular,
-#    zfcd           change to '~' on server, if it interprets it
-#    zfcd -         change to previous directory of current connection
-#    zfcd OLD NEW   change directory from fooOLDbar to fooNEWbar
-#   One piece of magic is builtin:  an initial part of the directory
-#   matching $HOME is translated back to `~'.  Most UNIX servers
-#   recognise the usual shell convention.  So things like `zfcd $PWD'
-#   is useful provide you are under your home directory and the
-#   structure on the remote machine mirrors that on the local.
-# zfhere
-#   Synonym for `zfcd $PWD', see above.
-# zfdir [args]
-#   Show a long diretory list of the remote connection.  Any
-#   arguments are passed on to the server, apart from options.
-#   Currently this always uses a pager to show the directory
-#   list.  Caching is implemented:  zfdir on its own always shows
-#   the current diretory, which is cached; zfdir with some other
-#   directory arguments shows that, which is cached separately
-#   and can be reviewed with `zfdir -r'.  Other options:
-#    -f  force reget, overriding the cache, in case something's changed
-#    -d  delete the cache, but don't show anything.
-#   To pass options to the server, use e.g. `zfdir -- -C'.
-#   This also has the zfcd ~ hack.
-# zfls [args]
-#   Short list of the long directory, depending on what [args]
-#   do to the server.  No options, no caching, no pager.
-# zftype [ a[scii] | i[mage] | b[inary] ]
-#   Set or display the transfer type; currently only ASCII
-#   and image (same as binary) types are supported.
-# zfclose
-#   Close the connection.
-# zfstat
-#   Print the zftp status from local variables; doesn't do any network
-#   operations unless -v is supplied, in which case the server is
-#   asked for its views on the status, too.
-#
-# Functions for retrieving data:
-#   All accept the following options:
-#    -G   Don't do remote globbing (see above); the default is to do it.
-#    -t   Try to set local files to the same time as the remote ones.
-#         Unfortunately we only know the remote time in GMT, so it's
-#         a little tricky and you need perl 5 (installed as `perl')
-#         for this to work.  Suggestions welcome.
-# zfget file1 file2 ...
-#   Retrieve each file from the server.  The remote file is the
-#   full name given, the local file is the non-directory part of that
-#   (assuming UNIX file paths).
-# zfuget file1 file2 ..
-#   Get with update.  Check remote and local sizes and times and
-#   retrieve files which are newer on the server.  Will query
-#   hard cases, which are where the remote file is newer but a
-#   different size, or is older but the same size.  With option -s
-#   (silent) assumes it's best to retrieve the files in both those
-#   cases.  With -v (may be combined with -s), print the information
-#   about the files being considered.
-# zfcget file1 ...
-#   Assuming file1 was incompletely retrieved, try to get the rest of
-#   it.  This relies on a normal UNIX server behaviour which is not
-#   as specified in the FTP standard and hence is not universal.
-# zfgcp file1 file2
-# zfgcp file1 file2 ... dir
-#   Get with the behaviour of cp, i.e. copy remote file1 to local
-#   file2, or get remote fileN into local diretory dir.
-#
-# Function for sending data:
-# zfput file1 file2 ...
-#   Put the local files onto the server under the same name.  The
-#   local files are exactly as given; the remote files are the
-#   non-diretory parts of that. 
-# zfuput file1 file2 ..
-#   Put the local files onto the server, with update.  Works
-#   similarly to zfuget.
-#
-# Utility functions:
-# zftp_chpwd
-#   Show the new directory when it changes; try to put it into
-#   an xterm on shelltool header.  Works best alongside chpwd.
-# zftp_progress
-#   Show the percentage of a file retrieved as it is coming; if the
-#   size is not available show the size transferred so far.  The
-#   percentage may be wrong if sending data from a local pipe.
-#   If you transfer files in the background, you should undefine
-#   this before the transfer.  It is smart enough not to print
-#   anything when stderr is not a terminal.
-# zfcd_match
-#   Function for remote directory completion.
-# zfget_match
-#   Function for remote filename completion.
-# zfrglob varname
-#   This is used for the remote globbing.  The pattern resides
-#   in $varname (note extra level of indirection), and on return
-#   $varname will contain the list of matching files.
-# zfrtime locfile remfile [ time ]
-#   This sad thing does the setting of local file times to those
-#   of the remote, see horror story above.
-
-zmodload -ia zftp
-
-alias zfcd='noglob zfcd'
-alias zfget='noglob zfget'
-alias zfls='noglob zfls'
-alias zfdir='noglob zfdir'
-alias zfuget='noglob zfuget'
-# only way of getting that noglob out of the way at the moment
-setopt completealiases
-
-#
-# zftp completions
-#
-compctl -f -x 'p[1]' \
-  -k '(open params user login type ascii binary mode put putat
-  get getat append appendat ls dir local remote mkdir rmdir delete
-  close quit)'  - \
-  'w[1,cd][1,ls][1,dir][1,rmdir]' -K zfcd_match -S/ -q - \
-  'W[1,get*]' -K zfget_match - 'w[1,delete][1,remote]' -K zfget_match - \
-  'w[1,open][1,params]' -k hosts -- zftp
-compctl -K zfcd_match -S/ -q zfcd zfdir zfls
-compctl -K zfget_match zfget zfgcp zfuget zfcget
-compctl -k hosts zfopen zfparams
-
-function zfanon {
-  local opt optlist once
-  
-  while [[ $1 = -* ]]; do
-    if [[ $1 = - || $1 = -- ]]; then
-      shift;
-      break;
-    fi
-    optlist=${1#-}
-    for (( i = 1; i <= $#optlist; i++)); do
-      opt=$optlist[$i]
-      case $optlist[$i] in
-        1) once=1
-  	 ;;
-        *) print option $opt not recognised >&2
-  	 ;;
-      esac
-    done
-    shift
-  done
-  
-  if [[ -z $EMAIL_ADDR ]]; then
-    # Exercise in futility.  There's a poem by Wallace Stevens
-    # called something like `N ways of looking at a blackbird',
-    # where N is somewhere around 0x14 to 0x18.  Now zftp is
-    # ashamed to prsent `N ways of looking at a hostname'.
-    local domain host
-    # First, maybe we've already got it.  Zen-like.
-    if [[ $HOST = *.* ]]; then
-      # assume this is the full host name
-      host=$HOST
-    elif [[ -f /etc/resolv.conf ]]; then
-      # Next, maybe we've got resolv.conf.
-      domain=$(awk '/domain/ { print $2 }' /etc/resolv.conf)
-      [[ -n $domain ]] && host=$HOST.$domain
-    fi
-    # Next, maybe we've got nlsookup.  May not work on LINUX.
-    [[ -z $host ]] && host=$(nslookup $HOST | awk '/Name:/ { print $2 }')
-    if [[ -z $host ]]; then
-      # we're running out of ideas, but this should work.
-      # after all, i wrote it...
-      # don't want user to know about this, too embarrassed.
-      local oldvb=$ZFTP_VERBOSE oldtm=$ZFTP_TMOUT
-      ZFTP_VERBOSE=
-      ZFTP_TMOUT=5
-      if zftp open $host >& /dev/null; then
-        host=$ZFTP_HOST
-        zftp close $host
-      fi
-      ZFTP_VERBOSE=$oldvb
-      ZFTP_TMOUT=$oldtm
-    fi
-    if [[ -z $host ]]; then
-      print "Can't get your hostname.  Define \$EMAIL_ADDR by hand."
-      return 1;
-    fi
-    EMAIL_ADDR="$USER@$host"
-    print "Using $EMAIL_ADDR as anonymous FTP password."
-  fi
-  
-  if [[ $once = 1 ]]; then
-    zftp open $1 anonymous $EMAIL_ADDR
-  else
-    zftp params $1 anonymous $EMAIL_ADDR
-    zftp open
-  fi
-}
-
-function zfcd {
-  # zfcd:  change directory on the remote server.
-  #
-  #  Currently has the following features:
-  # --- an initial string matching $HOME in the directory is turned back into ~
-  #     to be re-interpreted by the remote server.
-  # --- zfcd with no arguments changes directory to '~'
-  # --- `zfcd old new' and `zfcd -' work analagously to cd
-  # --- if the connection is not currently open, it will try to
-  #     re-open it with the stored parameters as set by zfopen.
-  #     If the connection timed out, however, it won't know until
-  #     too late.  In that case, just try the same zfcd command again
-  #     (but now `zfcd -' and `zfcd old new' won't work).
-  
-  # hack: if directory begins with $HOME, turn it back into ~
-  # there are two reasons for this:
-  #   first, a ~ on the command line gets expanded even with noglob.
-  #     (I suppose this is correct, but I wouldn't like to swear to it.)
-  #   second, we can no do 'zfcd $PWD' and the like, and that will
-  #     work just as long as the directory structures under the home match.
-  
-  # Autoopen:  if not already open, hope there are parameters set up to
-  # do so.  If not, we get the right error message, so no harm done.
-  [[ -z $ZFTP_HOST ]] && { zfopen  || return 1; }
-  
-  if [[ $1 = $HOME || $1 = $HOME/* ]]; then
-    1="~${1#$HOME}"
-  fi
-  
-  if (( $# == 0 )); then
-    # Emulate `cd' behaviour
-    set -- '~'
-  elif [[ $# -eq 1 && $1 = - ]]; then
-    # Emulate `cd -' behaviour.
-    set -- $zflastdir
-  elif [[ $# -eq 2 ]]; then
-    # Emulate `cd old new' behaviour.
-    # We have to find a character not in $1 or $2; ! is a good bet.
-    eval set -- "\${ZFTP_PWD:s!$1!$2!}"
-  fi
-  
-  # We have to remember the current directory before changing it
-  # if we want to keep it.
-  local lastdir=$ZFTP_PWD
-  
-  zftp cd "$@"  &&  zflastdir=$lastdir
-}
-
-function zfcd_match {
-  # see zfcd for details of this hack
-  if [[ $1 = $HOME || $1 = $HOME/* ]]; then
-    1="~${1#$HOME}"
-  fi
-  
-  # error messages only
-  local ZFTP_VERBOSE=45
-  # should we redirect 2>/dev/null or let the user see it?
-  
-  if [[ $ZFTP_SYSTEM = UNIX* ]]; then
-    # hoo, aren't we lucky: this makes things so much easier
-    setopt localoptions rcexpandparam
-    local dir
-    if [[ $1 = ?*/* ]]; then
-      dir=${1%/*}
-    elif [[ $1 = /* ]]; then
-      dir=/
-    fi
-    # If we're using -F, we get away with using a directory
-    # to list, but not a glob.  Don't ask me why.
-    # I hate having to rely on awk here.
-    reply=($(zftp ls -F $dir | 
-    awk '/\/$/ { print substr($1, 0, length($1)-1) }'))
-    if [[ $dir = / ]]; then
-      reply=(${dir}$reply)
-    elif [[ -n $dir ]]; then
-      reply=($dir/$reply)
-    fi
-  else
-    # I simply don't know what to do here.
-    # Just use the list of files for the current directory.
-    zfget_match $*
-  fi
-  
-}
-
-function zfcget {
-  # Continuation get of files from remote server.
-  # For each file, if it's shorter here, try to get the remainder from
-  # over there.  This requires the server to support the REST command
-  # in the way many do but RFC959 doesn't specify.
-  # Options:
-  #   -G   don't to remote globbing, else do
-  #   -t   update the local file times to the same time as the remote.
-  #        Currently this only works if you have the `perl' command,
-  #        and that perl is version 5 with the standard library.
-  #        See the function zfrtime for more gory details.
-  
-  setopt localoptions
-  unsetopt ksharrays shwordsplit
-  
-  local loc rem stat=0 optlist opt nglob remlist locst remst
-  local tmpfile=${TMPPREFIX}zfcget$$ rstat tsize time
-  
-  while [[ $1 = -* ]]; do
-    if [[ $1 = - || $1 = -- ]]; then
-      shift;
-      break;
-    fi
-    optlist=${1#-}
-    for (( i = 1; i <= $#optlist; i++)); do
-      opt=$optlist[$i]
-      case $optlist[$i] in
-        G) nglob=1
-  	 ;;
-        t) time=1
-  	 ;;
-        *) print option $opt not recognised >&2
-  	 ;;
-      esac
-    done
-    shift
-  done
-  
-  for remlist in $*; do
-    # zfcd directory hack to put the front back to ~
-    if [[ $remlist = $HOME || $remlist = $HOME/* ]]; then
-      remlist="~${remlist#$HOME}"
-    fi
-    if [[ $nglob != 1 ]]; then
-      zfrglob remlist
-    fi
-    if (( $#remlist )); then
-      for rem in $remlist; do
-        loc=${rem:t}
-        if [[ ! -f $loc ]]; then
-  	# File does not yet exist
-  	zftp get $rem >$loc || stat=$?
-        else
-  	# Compare the sizes.
-  	locst=($(zftp local $loc))
-  	zftp remote $rem >$tmpfile
-  	rstat=$?
-  	remst=($(<$tmpfile))
-  	rm -f $tmpfile
-  	if [[ $rstat = 2 ]]; then
-  	  print "Server does not support SIZE command.\n" \
-  	  "Assuming you know what you're doing..." 2>&1
-  	  zftp getat $rem $locst[1] >>$loc || stat=$?
-  	  continue
-  	elif [[ $rstat = 1 ]]; then
-  	  print "Remote file not found: $rem" 2>&1
-  	  continue
-  	fi
-  	if [[ $locst[1] -gt $remst[1] ]]; then
-  	  print "Local file is larger!" 2>&1
-  	  continue;
-  	elif [[ $locst[1] == $remst[1] ]]; then
-  	  print "Files are already the same size." 2>&1
-  	  continue
-  	else
-  	  if zftp getat $rem $locst[1] >>$loc; then
-  	    [[ $time = 1 ]] && zfrtime $loc $rem $remst[2]
-  	  else
-  	    stat=1
-  	  fi
-  	fi
-        fi
-      done
-    fi
-  done
-  
-  return $stat
-}
-
-function zfclose {
-  zftp close
-}
-
-function zfdir {
-  # Long directory of remote server.
-  # The remote directory is cached.  In fact, two caches are kept:
-  # one of the standard listing of the current directory, i.e. zfdir
-  # with no arguments, and another for everything else.
-  # To access the appropriate cache, just use zfdir with the same
-  # arguments as previously.  zfdir -r will also re-use the `everything
-  # else' cache; you can always reuse the current directory cache just
-  # with zfdir on its own.
-  #
-  # The current directory cache is emptied when the directory changes;
-  # the other is kept until a new zfdir with a non-empty argument list.
-  # Both are removed when the connection is closed.
-  #
-  # zfdir -f will force the existing cache to be ignored, e.g. if you know
-  #          or suspect the directory has changed.
-  # zfdir -d will remove both caches without listing anything.
-  # If you need to pass -r, -f or -d to the dir itself, use zfdir -- -d etc.
-  
-  setopt localoptions unset
-  unsetopt shwordsplit ksharrays
-  
-  local file opt optlist redir i newargs force
-  
-  while [[ $1 = -* ]]; do
-    if [[ $1 = - || $1 = -- ]]; then
-      shift;
-      break;
-    fi
-    optlist=${1#-}
-    for (( i = 1; i <= $#optlist; i++)); do
-      opt=$optlist[$i]
-      case $optlist[$i] in
-        r) redir=1
-  	 ;;
-        f) force=1
-  	 ;;
-        d) [[ -n $zfcurdir && -f $zfcurdir ]] && rm -f $zfcurdir
-  	 [[ -n $zfotherdir && -f $zfotherdir ]] && rm -f $zfotherdir
-  	 zftp_fcache=()
-  	 return 0
-  	 ;;
-        *) print option $opt not recognised >&2
-  	 ;;
-      esac
-    done
-    shift
-  done
-  
-  # directory hack, see zfcd
-  for (( i = 1; i <= $#argv; i++ )); do
-    if [[ $argv[$i] = $HOME || $argv[$i] = $HOME/* ]]; then
-      argv[$i]="~${argv[$i]#$HOME}"
-    fi
-  done
-  
-  if [[ $# -eq 0 ]]; then
-    # Cache it in the current directory file.  This means that repeated
-    # calls to zfdir with no arguments always use a cached file.
-    [[ -z $zfcurdir ]] && zfcurdir=${TMPPREFIX}zfcurdir$$
-    file=$zfcurdir
-  else
-    # Last directly looked at was not the current one, or at least
-    # had non-standard arguments.
-    [[ -z $zfotherdir ]] && zfotherdir=${TMPPREFIX}zfotherdir$$
-    file=$zfotherdir
-    newargs="$*"
-    if [[ -f $file && $redir != 1 && $force -ne 1 ]]; then
-      # Don't use the cached file if the arguments changed.
-      [[ $newargs = $zfotherargs ]] || rm -f $file
-    fi
-    zfotherargs=$newargs
-  fi
-  
-  if [[ $force -eq 1 ]]; then
-    rm -f $file
-    # if it looks like current directory has changed, better invalidate
-    # the filename cache, too.
-    (( $# == 0 )) && zftp_fcache=()
-  fi
-  
-  if [[ -n $file && -f $file ]]; then
-    eval ${PAGER:-more} \$file
-  else
-    zftp dir $* | tee $file | eval ${PAGER-:more}
-  fi
-}
-
-function zfgcp {
-  # ZFTP get as copy:  i.e. first arguments are remote, last is local.
-  # Supposed to work exactly like a normal copy otherwise, i.e.
-  #  zfcp rfile lfile
-  # or
-  #  zfcp rfile1 rfile2 rfile3 ... ldir
-  # Options:
-  #   -G   don't to remote globbing, else do
-  #   -t   update the local file times to the same time as the remote.
-  #        Currently this only works if you have the `perl' command,
-  #        and that perl is version 5 with the standard library.
-  #        See the function zfrtime for more gory details.
-  
-  setopt localoptions
-  unsetopt shwordsplit
-  
-  local opt optlist nglob remlist rem loc stat=0 time
-  
-  while [[ $1 == -* ]]; do
-    if [[ $1 == - || $1 == -- ]]; then
-      shift;
-      break;
-    fi
-    optlist=${1#-}
-    for (( i = 1; i <= $#optlist; i++)); do
-      opt=$optlist[$i]
-      case $opt in
-        G) nglob=1
-  	 ;;
-        t) time=1
-  	 ;;
-        *) print option $opt not recognised >&2
-  	 ;;
-      esac
-    done
-    shift
-  done
-  
-  # hmm, we should really check this after expanding the glob,
-  # but we shouldn't expand the last argument remotely anyway.
-  if [[ $# -gt 2 && ! -d $argv[-1] ]]; then
-    print "zfgcp:  last argument must be a directory." 2>&1
-    return 1
-  elif [[ $# == 1 ]]; then
-    print "zfgcp:  not enough arguments." 2>&1
-    return 1
-  fi
-  
-  if [[ -d $argv[-1] ]]; then
-    local dir=$argv[-1]
-    argv[-1]=
-    for remlist in $*; do
-      # zfcd directory hack to put the front back to ~
-      if [[ $remlist = $HOME || $remlist = $HOME/* ]]; then
-        remlist="~${remlist#$HOME}"
-      fi
-      if [[ $nglob != 1 ]]; then
-        zfrglob remlist
-      fi
-      if (( $#remlist )); then
-        for rem in $remlist; do
-  	loc=$dir/${rem:t}
-  	if zftp get $rem >$loc; then
-  	  [[ $time = 1 ]] && zfrtime $rem $loc
-  	else
-  	  stat=1
-  	fi
-        done
-      fi
-    done
-  else
-    zftp get $1 >$2 || stat=$?
-  fi
-  return $stat
-}
-
-function zfget {
-  # Get files from remote server.  Options:
-  #   -G   don't to remote globbing, else do
-  #   -t   update the local file times to the same time as the remote.
-  #        Currently this only works if you have the `perl' command,
-  #        and that perl is version 5 with the standard library.
-  #        See the function zfrtime for more gory details.
-  
-  local loc rem stat=0 optlist opt nglob remlist time
-  
-  while [[ $1 == -* ]]; do
-    if [[ $1 == - || $1 == -- ]]; then
-      shift;
-      break;
-    fi
-    optlist=${1#-}
-    for (( i = 1; i <= $#optlist; i++)); do
-      opt=$optlist[$i]
-      case $opt in
-        G) nglob=1
-  	 ;;
-        t) time=1
-  	 ;;
-        *) print option $opt not recognised >&2
-  	 ;;
-      esac
-    done
-    shift
-  done
-  
-  for remlist in $*; do
-    # zfcd directory hack to put the front back to ~
-    if [[ $remlist == $HOME || $remlist == $HOME/* ]]; then
-      remlist="~${remlist#$HOME}"
-    fi
-    if [[ $nglob != 1 ]]; then
-      zfrglob remlist
-    fi
-    if (( $#remlist )); then
-      for rem in $remlist; do
-        loc=${rem:t}
-        if zftp get $rem >$loc; then
-  	[[ $time = 1 ]] && zfrtime $rem $loc
-        else
-  	stat=1
-        fi
-      done
-    fi
-  done
-  
-  return $stat
-}
-
-function zfget_match {
-  # the zfcd hack:  this may not be necessary here
-  if [[ $1 == $HOME || $1 == $HOME/* ]]; then
-    1="~${1#$HOME}"
-  fi
-  
-  
-  if [[ $ZFTP_SYSTEM == UNIX* && $1 == */* ]]; then
-    # On the first argument to ls, we usually get away with a glob.
-    reply=($(zftp ls "$1*$2"))
-  else
-    if (( $#zftp_fcache == 0 )); then
-      # Always cache the current directory and use it
-      # even if the system is UNIX.
-      zftp_fcache=($(zftp ls))
-    fi
-    reply=($zftp_fcache);
-  fi
-}
-
-function zfhere {
-  # Change to the directory corresponding to $PWD on the server.
-  # See zfcd for how this works.
-  zfcd $PWD
-}
-
-function zfls {
-  # directory hack, see zfcd
-  if [[ $1 = $HOME || $1 = $HOME/* ]]; then
-    1="~${1#$HOME}"
-  fi
-  zftp ls $*
-}
-
-function zfopen {
-  # Use zftp params to set parameters for open, rather than sending
-  # them straight to open.  That way they are stored for a future open
-  # command.
-  #
-  # With option -1 (just this 1ce), don't do that.
-  
-  local optlist opt once
-  
-  while [[ $1 = -* ]]; do
-    if [[ $1 = - || $1 = -- ]]; then
-      shift;
-      break;
-    fi
-    optlist=${1#-}
-    for (( i = 1; i <= $#optlist; i++)); do
-      opt=$optlist[$i]
-      case $optlist[$i] in
-        1) once=1
-  	 ;;
-        *) print option $opt not recognised >&2
-  	 ;;
-      esac
-    done
-    shift
-  done
-  
-  # This is where we should try and do same name-lookupage in
-  # both .netrc and .ncftp/bookmarks .  We could even try saving
-  # the info in their for new hosts, like ncftp does.
-  
-  if [[ $once = 1 ]]; then
-    zftp open $*
-  else
-    # set parameters, but only if there was at least a host
-    (( $# > 0 )) && zfparams $*
-    # now call with no parameters
-    zftp open
-  fi
-}
-
-function zfparams {
-    # Set to prompt for any user or password if not given.
-    # Don't worry about accounts here.
-    if (( $# > 0 )); then
-      (( $# < 2 )) && 2='?'
-      (( $# < 3 )) && 3='?'
-    fi
-    zftp params $*
-}
-
-function zfput {
-  # Simple put:  dump every file under the same name, but stripping
-  # off any directory parts.
-  local loc rem stat=0
-  for loc in $*; do
-    rem=${loc:t}
-    zftp put $rem <$loc
-    [[ $? == 0 ]] || stat=$?
-  done
-  return $stat
-}
-
-function zfrglob {
-  # Do the remote globbing for zfput, etc.
-  # We have two choices:
-  #  (1) Get the entire file list and match it one by one
-  #      locally against the pattern.
-  #      Causes problems if we are globbing directories (rare, presumably).
-  #      But: we can cache the current directory, which
-  #      we need for completion anyway.  Works on any OS if you
-  #      stick with a single directory.  This is the default.
-  #  (2) Use remote globbing, i.e. pass it to ls at the site.
-  #      Faster, but only works with UNIX, and only basic globbing.
-  #      We do this if $zfrglob is non-null.
-  
-  # There is only one argument, the variable containing the
-  # pattern to be globbed.  We set this back to an array containing
-  # all the matches.
-  setopt localoptions unset
-  unsetopt ksharrays
-  
-  local pat dir nondir files i
-  
-  eval pat=\$$1
-  
-  # Check if we really need to do anything.  Look for standard
-  # globbing characters, and if extendedglob is set and we are
-  # using zsh for the actual pattern matching also look for
-  # extendedglob characters.
-  if [[ $remlist != *[][*?]* &&
-    ( -n $zfrglob || ! -o extendedglob || $remlist != *[(|)~#^]* ) ]]; then
-    return 0
-  fi
-  
-  if [[ $zfrglob != '' ]]; then
-    eval "$1=(\$(zftp ls \"$pat\" 2>/dev/null))"
-  else
-    if [[ $ZFTP_SYSTEM = UNIX* && $pat = */* ]]; then
-      # not the current directory and we know how to handle paths
-      if [[ $pat = ?*/* ]]; then
-        # careful not to remove too many slashes
-        dir=${pat%/*}
-      else
-        dir=/
-      fi
-      nondir=${pat##*/}
-      files=($(zftp ls "$dir" 2>/dev/null))
-    else
-      # we just have to do an ls and hope that's right
-      nondir=$pat
-      if (( $#zftp_fcache == 0 )); then
-        zftp_fcache=($(zftp ls))
-      fi
-      files=($zftp_fcache)
-    fi
-    # now we want to see which of the $files match $nondir
-    for (( i = 1; i <= $#files; i++)); do
-      # empty words are elided in array assignment
-      [[ $files[$i] = ${~nondir} ]] || files[$i]=''
-    done
-    eval "$1=(\$files)"
-  fi
-}
-
-function zfrtime {
-  # Set the modification time of file LOCAL to that of REMOTE.
-  # If the optional TIME is passed, it should be in the FTP format
-  # CCYYMMDDhhmmSS, i.e. no dot before the seconds, and in GMT.
-  # This is what both `zftp remote' and `zftp local' return.
-  #
-  # Unfortunately, since the time returned from FTP is GMT and
-  # your file needs to be set in local time, we need to do some
-  # hacking around with time.  At the moment this requires perl 5
-  # with the standard library.
-  
-  setopt localoptions unset
-  unsetopt ksharrays
-  
-  local time gmtime loctime
-  
-  if [[ -n $3 ]]; then
-    time=$3
-  else
-    time=($(zftp remote $2 2>/dev/null))
-    [[ -n $time ]] && time=$time[2]
-  fi
-  [[ -z $time ]] && return 1
-  
-  # Now's the real *!@**!?!.  We have the date in GMT and want to turn
-  # it into local time for touch to handle.  It's just too nasty
-  # to handle in zsh; do it in perl.
-  if perl -mTime::Local -e '($file, $t) = @ARGV;
-  $yr = substr($t, 0, 4) - 1900;
-  $mon = substr($t, 4, 2) - 1;
-  $mday = substr($t, 6, 2) + 0;
-  $hr = substr($t, 8, 2) + 0;
-  $min = substr($t, 10, 2) + 0;
-  $sec = substr($t, 12, 2) + 0;
-  $time = Time::Local::timegm($sec, $min, $hr, $mday, $mon, $yr);
-  utime $time, $time, $file and return 0;' $1 $time 2>/dev/null; then
-    print "Setting time for $1 failed.  Need perl 5." 2>1
-  fi
-  
-  # If it wasn't for the GMT/local time thing, it would be this simple.
-  #
-  # time="${time[1,12]}.${time[13,14]}"
-  #
-  # touch -t $time $1
-  
-}
-
-function zfstat {
-  # Give a zftp status report using local variables.
-  # With option -v, connect the remote host and ask it what it
-  # thinks the status is.  
-  
-  setopt localoptions unset
-  unsetopt ksharrays
-  
-  local i stat=0 opt optlist verbose
-  
-  while [[ $1 = -* ]]; do
-    if [[ $1 = - || $1 = -- ]]; then
-      shift;
-      break;
-    fi
-    optlist=${1#-}
-    for (( i = 1; i <= $#optlist; i++)); do
-      opt=$optlist[$i]
-      case $opt in
-        v) verbose=1
-  	 ;;
-        *) print option $opt not recognised >&2
-  	 ;;
-      esac
-    done
-    shift
-  done
-  
-  # hack:  in case the status from a subshell process hasn't been
-  # fixed yet
-  zftp type >&/dev/null
-  
-  if [[ -n $ZFTP_HOST ]]; then
-    print "Host:\t\t$ZFTP_HOST"
-    print "IP:\t\t$ZFTP_IP"
-    [[ -n $ZFTP_SYSTEM ]] && print "System type:\t$ZFTP_SYSTEM"
-    if [[ -n $ZFTP_USER ]]; then
-      print "User:\t\t$ZFTP_USER "
-      [[ -n $ZFTP_ACCOUNT ]] && print "Account:\t$AFTP_ACCOUNT"
-      print "Directory:\t$ZFTP_PWD"
-      print -n "Transfer type:\t"
-      if [[ $ZFTP_TYPE = "I" ]]; then
-        print Image
-      elif [[ $ZFTP_TYPE = "A" ]]; then
-        print Ascii
-      else
-        print Unknown
-      fi
-      print -n "Transfer mode:\t"
-      if [[ $ZFTP_MODE = "S" ]]; then
-        print Stream
-      elif [[ $ZFTP_MODE = "B" ]]; then
-        print Block
-      else
-        print Unknown
-      fi
-    else
-      print "No user logged in."
-    fi
-  else
-    print "Not connected."
-    stat=1
-  fi
-  
-  # things which may be set even if not connected:
-  [[ -n $ZFTP_REPLY ]] && print "Last reply:\t$ZFTP_REPLY"
-  print "Verbosity:\t$ZFTP_VERBOSE"
-  print -n "Preferences:\t"
-  for (( i = 1; i <= ${#ZFTP_PREFS}; i++ )); do
-    case $ZFTP_PREFS[$i] in
-      [pP]) print -n "Passive "
-  	  ;;
-      [sS]) print -n "Sendport "
-  	  ;;
-      [dD]) print -n "Dumb "
-  	  ;;
-      *) print -n "$ZFTP_PREFS[$i]???"
-    esac
-  done
-  print
-  
-  if [[ -n $ZFTP_HOST && $verbose = 1 ]]; then
-    print "Status of remote server:"
-    # make sure we print the reply
-    local ZFTP_VERBOSE=045
-    zftp quote STAT
-  fi
-  
-  return $stat
-}
-
-function zftp_chpwd {
-  # You may want to alter chpwd to call this when $ZFTP_USER is set.
-  # If so, call it with a non-zero first argument so it doesn't
-  # print the new FTP directory.
-  
-  # Cancel the filename cache for the current directory.
-  zftp_fcache=()
-  # ...and also empty the stored directory listing cache.
-  # As this function is called when we close the connection, this
-  # is the only place we need to do these two things.
-  [[ -n $zfcurdir && -f $zfcurdir ]] && rm -f $zfcurdir
-  
-  if [[ -z $ZFTP_USER ]]; then
-    # last call, after an FTP logout
-  
-    # delete the non-current cached directory
-    [[ -n $zfotherdir && -f $zfotherdir ]] && rm -f $zfotherdir
-    zfotherargs=
-  
-    # don't keep zflastdir between opens
-    zflastdir=
-  
-    # return the display to standard
-    # uncomment the following line if you have a chpwd which shows directories
-    # chpwd
-  else
-    [[ -z $zflastdir ]] && zflastdir=$ZFTP_PWD
-    local args
-    if [[ -t 1 && -t 2 ]]; then
-      local str="$ZFTP_HOST:$ZFTP_PWD"
-      [[ -z $1 ]] && print $str
-      [[ ${#str} -lt 70 ]] && str="%m: %~  $str"
-      case $TERM in
-        sun-cmd) print -n -P "\033]l$str\033\\"
-  	       ;;
-        xterm) print -n -P "\033]2;$str\a"
-  	     ;;
-      esac
-    fi
-  fi
-}
-
-function zftp_progress {
-  # Basic progress metre, showing the percent of the file transferred.
-  # You want growing bars?  You gotta write growing bars.
-  
-  # Don't show progress unless stderr is a terminal
-  [[ ! -t 2 ]] && return 0
-  
-  if [[ $ZFTP_TRANSFER = *F ]]; then
-    print 1>&2
-  elif [[ -n $ZFTP_TRANSFER ]]; then
-    if [[ -n $ZFTP_SIZE ]]; then
-      local frac="$(( ZFTP_COUNT * 100 / ZFTP_SIZE ))%"
-      print -n "\r$ZFTP_FILE ($ZFTP_SIZE bytes): $ZFTP_TRANSFER $frac" 1>&2
-    else
-      print -n "\r$ZFTP_FILE: $ZFTP_TRANSFER $ZFTP_COUNT" 1>&2
-    fi
-  fi
-}
-
-function zftype {
-  local type
-  
-  if (( $# == 0 )); then
-    type=$(zftp type)
-    if [[ $type = I ]]; then
-      print "Current type is image (binary)"
-      return 0
-    elif [[ $type = A ]]; then
-      print "Current type is ASCII"
-      return 0
-    else
-      return 1
-    fi
-  else
-    if [[ $1 == [aA]([sS][cC]([iI][iI]|)|) ]]; then
-      type=A
-    elif [[ $1 == [iI]([mM]([aA][gG][eE]|)|) ||
-      $1 == [bB]([iI][nN]([aA][rR][yY]|)|) ]]; then
-      type=I
-    else
-      print "Type not recognised:  $1" 2>&1
-      return 1
-    fi
-    zftp type $type
-  fi
-}
-
-function zfuget {
-  # Get a list of files from the server with update.
-  # In other words, only retrieve files which are newer than local
-  # ones.  This depends on the clocks being adjusted correctly
-  # (i.e. if one is fifteen minutes out, for the next fifteen minutes
-  # updates may not be correctly calculated).  However, difficult
-  # cases --- where the files are the same size, but the remote is newer,
-  # or have different sizes, but the local is newer -- are prompted for.
-  #
-  # Files are globbed on the remote host --- assuming, of course, they
-  # haven't already been globbed local, so use 'noglob' e.g. as
-  # `alias zfuget="noglob zfuget"'.
-  #
-  # Options:
-  #  -G    Glob:     turn off globbing
-  #  -v    verbose:  print more about the files listed.
-  #  -s    silent:   don't ask, just guess.  The guesses are:
-  #                - if the files have different sizes but remote is older ) grab
-  #                - if they have the same size but remote is newer        )
-  #                  which is safe if the remote files are always the right ones.
-  #   -t   time:     update the local file times to the same time as the remote.
-  #                  Currently this only works if you have the `perl' command,
-  #                  and that perl is version 5 with the standard library.
-  #                  See the function zfrtime for more gory details.
-  
-  setopt localoptions
-  unsetopt ksharrays shwordsplit
-  
-  local loc rem stat=0 locstats remstats doit tmpfile=${TMPPREFIX}zfuget$$
-  local rstat remlist verbose optlist opt bad i silent nglob time
-  
-  zfuget_print_time() {
-    local tim=$1
-    print -n "$tim[1,4]/$tim[5,6]/$tim[7,8] $tim[9,10]:$tim[11,12].$tim[13,14]"
-    print -n GMT
-  }
-  
-  zfuget_print () {
-    print -n "\nremote $rem ("
-    zfuget_print_time $remstats[2]
-    print -n ", $remstats[1] bytes)\nlocal $loc ("
-    zfuget_print_time $locstats[2]
-    print ", $locstats[1] bytes)"
-  }
-  
-  while [[ $1 = -* ]]; do
-    if [[ $1 = - || $1 = -- ]]; then
-      shift;
-      break;
-    fi
-    optlist=${1#-}
-    for (( i = 1; i <= $#optlist; i++)); do
-      opt=$optlist[$i]
-      case $optlist[$i] in
-        v) verbose=1
-  	 ;;
-        s) silent=1
-  	 ;;
-        G) nglob=1
-  	 ;;
-        t) time=1
-  	 ;;
-        *) print option $opt not recognised >&2
-  	 ;;
-      esac
-    done
-    shift
-  done
-  
-  [[ -n $bad ]] && return 1
-  
-  for remlist in $*; do
-    # zfcd directory hack to put the front back to ~
-    if [[ $remlist == $HOME || $remlist == $HOME/* ]]; then
-      remlist="~${remlist#$HOME}"
-    fi
-    if [[ $nglob != 1 ]]; then
-      zfrglob remlist
-    fi
-    if (( $#remlist )); then
-      for rem in $remlist; do
-        loc=${rem:t}
-        doit=y
-        remstats=()
-        if [[ -f $loc ]]; then
-  	zftp local $loc >$tmpfile
-  	locstats=($(<$tmpfile))
-  	zftp remote $rem >$tmpfile
-  	rstat=$?
-  	remstats=($(<$tmpfile))
-  	rm -f $tmpfile
-  	if [[ $rstat = 2 ]]; then
-  	  print "Server does not implement full command set required." 1>&2
-  	  return 1
-  	elif [[ $rstat = 1 ]]; then
-  	  print "File not found on server: $rem" 1>&2
-  	  stat=1
-  	  continue
-  	fi
-  	[[ $verbose = 1 ]] && zfuget_print
-  	if (( $locstats[1] != $remstats[1] )); then
-  	  # Files have different sizes
-  	  if [[ $locstats[2] > $remstats[2] && $silent != 1 ]]; then
-  	    [[ $verbose != 1 ]] && zfuget_print
-  	    print "Local file $loc more recent than remote," 1>&2
-  	    print -n "but sizes are different.  Transfer anyway [y/n]? " 1>&2
-  	    read -q doit
-  	  fi
-  	else
-  	  # Files have same size
-  	  if [[ $locstats[2] < $remstats[2] ]]; then
-  	    if [[ $silent != 1 ]]; then
-  	      [[ $verbose != 1 ]] && zfuget_print
-  	      print "Local file $loc has same size as remote," 1>&2
-  	      print -n "but local file is older. Transfer anyway [y/n]? " 1>&2
-  	      read -q doit
-  	    fi
-  	  else
-  	    # presumably same file, so don't get it.
-  	    [[ $verbose = 1 ]] && print Not transferring
-  	    doit=n
-  	  fi
-  	fi
-        else
-  	[[ $verbose = 1 ]] && print New file $loc
-        fi
-        if [[ $doit = y ]]; then
-  	if zftp get $rem >$loc; then
-  	  if [[ $time = 1 ]]; then
-  	    # if $remstats is set, it's second element is the remote time
-  	    zfrtime $loc $rem $remstats[2]
-  	  fi
-  	else
-  	  stat=$?
-  	fi
-  	
-        fi
-      done
-    fi
-  done
-  return $stat
-}
-
-function zfuput {
-  # Put a list of files from the server with update.
-  # See zfuget for details.
-  #
-  # Options:
-  #  -v    verbose:  print more about the files listed.
-  #  -s    silent:   don't ask, just guess.  The guesses are:
-  #                - if the files have different sizes but remote is older ) grab
-  #                - if they have the same size but remote is newer        )
-  #                  which is safe if the remote files are always the right ones.
-  
-  setopt localoptions
-  unsetopt ksharrays shwordsplit
-  
-  local loc rem stat=0 locstats remstats doit tmpfile=${TMPPREFIX}zfuput$$
-  local rstat verbose optlist opt bad i silent
-  
-  zfuput_print_time() {
-    local tim=$1
-    print -n "$tim[1,4]/$tim[5,6]/$tim[7,8] $tim[9,10]:$tim[11,12].$tim[13,14]"
-    print -n GMT
-  }
-  
-  zfuput_print () {
-    print -n "\nremote $rem ("
-    zfuput_print_time $remstats[2]
-    print -n ", $remstats[1] bytes)\nlocal $loc ("
-    zfuput_print_time $locstats[2]
-    print ", $locstats[1] bytes)"
-  }
-  
-  while [[ $1 = -* ]]; do
-    if [[ $1 = - || $1 = -- ]]; then
-      shift;
-      break;
-    fi
-    optlist=${1#-}
-    for (( i = 1; i <= $#optlist; i++)); do
-      opt=$optlist[$i]
-      case $optlist[$i] in
-        v) verbose=1
-  	 ;;
-        s) silent=1
-  	 ;;
-        *) print option $opt not recognised >&2
-  	 ;;
-      esac
-    done
-    shift
-  done
-  
-  [[ -n $bad ]] && return 1
-  
-  if [[ $ZFTP_VERBOSE = *5* ]]; then
-    # should we turn it off locally?
-    print "Messages with code 550 are harmless." >&2
-  fi
-  
-  for loc in $*; do
-    rem=${loc:t}
-    doit=y
-    remstats=()
-    if [[ ! -f $loc ]]; then
-      print "$loc: file not found" >&2
-      stat=1
-      continue
-    fi
-    zftp local $loc >$tmpfile
-    locstats=($(<$tmpfile))
-    zftp remote $rem >$tmpfile
-    rstat=$?
-    remstats=($(<$tmpfile))
-    rm -f $tmpfile
-    if [[ $rstat = 2 ]]; then
-      print "Server does not implement full command set required." 1>&2
-      return 1
-    elif [[ $rstat = 1 ]]; then
-      [[ $verbose = 1 ]] && print New file $loc
-    else
-      [[ $verbose = 1 ]] && zfuput_print
-      if (( $locstats[1] != $remstats[1] )); then
-        # Files have different sizes
-        if [[ $locstats[2] < $remstats[2] && $silent != 1 ]]; then
-  	[[ $verbose != 1 ]] && zfuput_print
-  	print "Remote file $rem more recent than local," 1>&2
-  	print -n "but sizes are different.  Transfer anyway [y/n]? " 1>&2
-  	read -q doit
-        fi
-      else
-        # Files have same size
-        if [[ $locstats[2] > $remstats[2] ]]; then
-  	if [[ $silent != 1 ]]; then
-  	  [[ $verbose != 1 ]] && zfuput_print
-  	  print "Remote file $rem has same size as local," 1>&2
-  	  print -n "but remote file is older. Transfer anyway [y/n]? " 1>&2
-  	  read -q doit
-  	fi
-        else
-  	# presumably same file, so don't get it.
-  	[[ $verbose = 1 ]] && print Not transferring
-  	doit=n
-        fi
-      fi
-    fi
-    if [[ $doit = y ]]; then
-      zftp put $rem <$loc || stat=$?
-    fi
-  done
-  return $stat
-}