about summary refs log tree commit diff
path: root/Functions
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-09-10 13:57:31 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-09-10 13:57:31 +0000
commitb67e4abb100f67ca05809baab37700eb5ee0a342 (patch)
treef19c7eb1544bd6071e01155825a7aae3cc99117d /Functions
parentbc3256997b737f6158e9768dcf5738a7c0fbb454 (diff)
downloadzsh-b67e4abb100f67ca05809baab37700eb5ee0a342.tar.gz
zsh-b67e4abb100f67ca05809baab37700eb5ee0a342.tar.xz
zsh-b67e4abb100f67ca05809baab37700eb5ee0a342.zip
manual/7767
Diffstat (limited to 'Functions')
-rw-r--r--Functions/Zftp/zfanon29
-rw-r--r--Functions/Zftp/zfautocheck12
-rw-r--r--Functions/Zftp/zfcd12
-rw-r--r--Functions/Zftp/zfcd_match12
-rw-r--r--Functions/Zftp/zfcget30
-rw-r--r--Functions/Zftp/zfdir30
-rw-r--r--Functions/Zftp/zffcache24
-rw-r--r--Functions/Zftp/zfgcp33
-rw-r--r--Functions/Zftp/zfget34
-rw-r--r--Functions/Zftp/zfget_match33
-rw-r--r--Functions/Zftp/zfgoto31
-rw-r--r--Functions/Zftp/zfinit22
-rw-r--r--Functions/Zftp/zfmark5
-rw-r--r--Functions/Zftp/zfopen30
-rw-r--r--Functions/Zftp/zfparams22
-rw-r--r--Functions/Zftp/zfpcp5
-rw-r--r--Functions/Zftp/zfrglob10
-rw-r--r--Functions/Zftp/zfsession71
-rw-r--r--Functions/Zftp/zfstat29
-rw-r--r--Functions/Zftp/zftp_chpwd26
-rw-r--r--Functions/Zftp/zftp_progress12
-rw-r--r--Functions/Zftp/zftransfer62
-rw-r--r--Functions/Zftp/zfuget50
-rw-r--r--Functions/Zftp/zfuput42
24 files changed, 383 insertions, 283 deletions
diff --git a/Functions/Zftp/zfanon b/Functions/Zftp/zfanon
index 9624d48d9..f5754dda6 100644
--- a/Functions/Zftp/zfanon
+++ b/Functions/Zftp/zfanon
@@ -2,31 +2,19 @@
 
 emulate -L zsh
 
-local opt optlist once dir
+local opt opt_1 dir
 
-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
+while getopts :1 opt; do
+  [[ $opt = "?" ]] && print "zfanon: bad option: -$OPTARG" >&2 && return 1
+  eval "opt_$opt=1"
 done
+(( OPTIND > 1 )) && shift $(( OPTIND - 1 ))
 
 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'.
+  # ashamed to present `N ways of looking at a hostname'.
   local domain host
   # First, maybe we've already got it.  Zen-like.
   if [[ $HOST = *.* ]]; then
@@ -38,7 +26,8 @@ if [[ -z $EMAIL_ADDR ]]; then
     [[ -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 }')
+  [[ -z $host ]] && host=$(nslookup $HOST 2>/dev/null |
+    awk '/Name:/ { print $2 }')
   if [[ -z $host ]]; then
     # we're running out of ideas, but this should work.
     # after all, i wrote it...
@@ -67,7 +56,7 @@ if [[ $1 = */* ]]; then
   1=${1%%/*}
 fi
 
-if [[ $once = 1 ]]; then
+if [[ $opt_1 = 1 ]]; then
   zftp open $1 anonymous $EMAIL_ADDR || return 1
 else
   zftp params $1 anonymous $EMAIL_ADDR
diff --git a/Functions/Zftp/zfautocheck b/Functions/Zftp/zfautocheck
index d06beca4f..993e84ebf 100644
--- a/Functions/Zftp/zfautocheck
+++ b/Functions/Zftp/zfautocheck
@@ -11,9 +11,12 @@
 # command, which implies we are looking for something so should stay open
 # for it.
 
-# Remember the old session:  zflastsession will be overwritten by
+# Remember the old location:  will be overwritten by
 # a successful open.
-local lastsession=$zflastsession
+local lastloc=$zfconfig[lastloc_$ZFTP_SESSION]
+
+# Don't print out user messages when re-opening the connection.
+local ZFTP_VERBOSE=${ZFTP_VERBOSE//0}
 
 # Unset the delay counter from the progress meter in case there was an
 # abnormal exit.
@@ -30,8 +33,9 @@ fi
 
 if [[ $1 = *n* ]]; then
   return 0
-elif [[ -n $lastsession && $ZFTP_HOST = ${lastsession%%:*} ]]; then
-  zfcd ${lastsession#*:}
+elif [[ -n $lastloc && $ZFTP_HOST = ${lastloc%%:*} ]]; then
+  # don't print directory since we're just going back where we were.
+  zfcd ${lastloc#*:} >& /dev/null
 fi
 
 # }
diff --git a/Functions/Zftp/zfcd b/Functions/Zftp/zfcd
index b726d9f55..2ecc8b0f6 100644
--- a/Functions/Zftp/zfcd
+++ b/Functions/Zftp/zfcd
@@ -22,9 +22,9 @@
 emulate -L zsh
 
 if [[ $1 = /* ]]; then
-  zfautocheck -dn
+  zfautocheck -dn || return 1
 else
-  zfautocheck -d
+  zfautocheck -d || return 1
 fi
 
 if [[ $1 = $HOME || $1 = $HOME/* ]]; then
@@ -36,7 +36,7 @@ if (( $# == 0 )); then
   set -- '~'
 elif [[ $# -eq 1 && $1 = - ]]; then
   # Emulate `cd -' behaviour.
-  set -- $zflastdir
+  set -- $zfconfig[lastdir_$ZFTP_SESSION]
 elif [[ $# -eq 2 ]]; then
   # Emulate `cd old new' behaviour.
   # We have to find a character not in $1 or $2; ! is a good bet.
@@ -47,6 +47,8 @@ fi
 # if we want to keep it.
 local lastdir=$ZFTP_PWD
 
-zftp cd "$@"  &&  zflastdir=$lastdir
-print $zflastsession
+zftp cd "$@" && [[ $lastdir != $ZFTP_PWD ]] &&
+zfconfig[lastdir_$ZFTP_SESSION]=$lastdir
+
+print $zfconfig[lastloc_$ZFTP_SESSION]
 # }
diff --git a/Functions/Zftp/zfcd_match b/Functions/Zftp/zfcd_match
index 67e719888..e9d283c97 100644
--- a/Functions/Zftp/zfcd_match
+++ b/Functions/Zftp/zfcd_match
@@ -15,7 +15,7 @@ local tmpf=${TMPPREFIX}zfcm$$
 
 if [[ $ZFTP_SYSTEM = UNIX* ]]; then
   # hoo, aren't we lucky: this makes things so much easier
-  setopt localoptions rcexpandparam
+  setopt rcexpandparam
   local dir
   if [[ $1 = ?*/* ]]; then
     dir=${1%/*}
@@ -25,13 +25,15 @@ if [[ $ZFTP_SYSTEM = UNIX* ]]; then
   # 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.
-  zftp ls -F $dir >$tmpf
+  zftp ls -LF $dir >$tmpf
   reply=($(awk '/\/$/ { print substr($1, 0, length($1)-1) }' $tmpf))
   rm -f $tmpf
-  if [[ $dir = / ]]; then
-    reply=(${dir}$reply)
+  [[ -n $dir && $dir != */ ]] && dir="$dir/"
+  if [[ -n $WIDGET ]]; then
+    _description expl 'remote directory'
+    compadd -S/ -q -P "$dir" - $reply
   elif [[ -n $dir ]]; then
-    reply=($dir/$reply)
+    reply=(${dir}$reply)
   fi
 else
   # I simply don't know what to do here.
diff --git a/Functions/Zftp/zfcget b/Functions/Zftp/zfcget
index fd6accfed..f95f37704 100644
--- a/Functions/Zftp/zfcget
+++ b/Functions/Zftp/zfcget
@@ -12,35 +12,21 @@
 
 emulate -L zsh
 
-local loc rem stat=0 optlist opt nglob remlist locst remst
-local tmpfile=${TMPPREFIX}zfcget$$ rstat tsize time
+local loc rem stat=0 opt opt_G opt_t remlist locst remst
+local tmpfile=${TMPPREFIX}zfcget$$ rstat tsize
 
-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
+while getopts :Gt opt; do
+  [[ $opt = '?' ]] && print "zfcget: bad option: -$OPTARG" && return 1
+  eval "opt_$opt=1"
 done
+(( OPTIND > 1 )) && shift $(( OPTIND - 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
+  if [[ $opt_G != 1 ]]; then
     zfrglob remlist
   fi
   if (( $#remlist )); then
@@ -73,7 +59,7 @@ for remlist in $*; do
 	  continue
 	else
 	  if zftp getat $rem $locst[1] >>$loc; then
-	    [[ $time = 1 ]] && zfrtime $loc $rem $remst[2]
+	    [[ $opt_t = 1 ]] && zfrtime $loc $rem $remst[2]
 	  else
 	    stat=1
 	  fi
diff --git a/Functions/Zftp/zfdir b/Functions/Zftp/zfdir
index 55befe000..deb5b9762 100644
--- a/Functions/Zftp/zfdir
+++ b/Functions/Zftp/zfdir
@@ -23,6 +23,8 @@ emulate -L zsh
 setopt extendedglob
 
 local file opt optlist redir i newargs force
+local curdir=$zfconfig[curdir_$ZFTP_SESSION]
+local otherdir=$zfconfig[otherdir_$ZFTP_SESSION]
 
 while [[ $1 = -* ]]; do
   if [[ $1 = - || $1 = -- ]]; then
@@ -40,9 +42,9 @@ while [[ $1 = -* ]]; do
 	 ;;
       f) force=1
 	 ;;
-      d) [[ -n $zfcurdir && -f $zfcurdir ]] && rm -f $zfcurdir
-	 [[ -n $zfotherdir && -f $zfotherdir ]] && rm -f $zfotherdir
-	 zftp_fcache=()
+      d) [[ -n $curdir && -f $curdir ]] && rm -f $curdir
+	 [[ -n $otherdir && -f $otherdir ]] && rm -f $otherdir
+	 zffcache -d
 	 return 0
 	 ;;
     esac
@@ -50,7 +52,7 @@ while [[ $1 = -* ]]; do
   shift
 done
 
-zfautocheck -d
+zfautocheck -d || return 1
 
 # directory hack, see zfcd
 for (( i = 1; i <= $#argv; i++ )); do
@@ -62,26 +64,32 @@ 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
+  if [[ -z $curdir ]]; then
+    curdir=${TMPPREFIX}zfcurdir_${ZFTP_SESSION}_$$
+    zfconfig[curdir_$ZFTP_SESSION]=$curdir
+  fi
+  file=$curdir
 else
   # Last directly looked at was not the current one, or at least
   # had non-standard arguments.
-  [[ -z $zfotherdir ]] && zfotherdir=${TMPPREFIX}zfotherdir$$
-  file=$zfotherdir
+  if [[ -z $otherdir ]]; then
+    otherdir=${TMPPREFIX}zfotherdir_${ZFTP_SESSION}_$$
+    zfconfig[otherdir_$ZFTP_SESSION]=$otherdir
+  fi
+  file=$otherdir
   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
+    [[ $newargs = $zfconfig[otherargs_$ZFTP_SESSION] ]] || rm -f $file
   fi
-  zfotherargs=$newargs
+  zfconfig[otherargs_$ZFTP_SESSION]=$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=()
+  (( $# == 0 )) && zffcache -d
 fi
 
 if [[ -n $file && -f $file ]]; then
diff --git a/Functions/Zftp/zffcache b/Functions/Zftp/zffcache
new file mode 100644
index 000000000..0d9686660
--- /dev/null
+++ b/Functions/Zftp/zffcache
@@ -0,0 +1,24 @@
+# Generate an array name for storing the cache for the current session,
+# storing it in fcache_name, then generate the cache for the current
+# directory, or with argument -d clear the cache.
+
+fcache_name=$zfconfig[fcache_$ZFTP_SESSION]
+if [[ -z $fcache_name ]]; then
+  local vals
+  vals=(${(v)zfconfig[(I)fcache_*]##zftp_fcache_})
+  integer i
+  while [[ -n ${vals[(r)zftp_fcache_$i]} ]]; do
+    (( i++ ))
+  done
+  fcache_name=zftp_fcache_$i
+  zfconfig[fcache_$ZFTP_SESSION]=$fcache_name
+fi
+
+if [[ $1 = -d ]]; then
+  unset $fcache_name
+elif (( ${(P)#fcache_name} == 0 )); then
+  local tmpf=${TMPPREFIX}zffcache$$
+  zftp ls >$tmpf
+  eval "$fcache_name=(\${(f)\"\$(<\$tmpf)\"})"
+  rm -f $tmpf
+fi
diff --git a/Functions/Zftp/zfgcp b/Functions/Zftp/zfgcp
index 26a08697d..916a5f7b6 100644
--- a/Functions/Zftp/zfgcp
+++ b/Functions/Zftp/zfgcp
@@ -16,30 +16,16 @@
 
 emulate -L zsh
 
-local opt optlist nglob remlist rem loc time
+local opt remlist rem loc opt_G opt_t
 integer stat do_close
 
-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
+while getopts :Gt opt; do
+  [[ $opt = '?' ]] && print "zfgcp: bad option: -$OPTARG" >&2 && return 1
+  eval "opt_$opt=1"
 done
+(( OPTIND > 1 )) && shift $(( OPTIND - 1 ))
 
-zfautocheck
+zfautocheck || return 1
 
 # hmm, we should really check this after expanding the glob,
 # but we shouldn't expand the last argument remotely anyway.
@@ -59,14 +45,14 @@ if [[ -d $argv[-1] ]]; then
     if [[ $remlist = $HOME || $remlist = $HOME/* ]]; then
       remlist="~${remlist#$HOME}"
     fi
-    if [[ $nglob != 1 ]]; then
+    if [[ $opt_G != 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
+	  [[ $opt_t = 1 ]] && zfrtime $rem $loc
 	else
 	  stat=1
 	fi
@@ -74,6 +60,9 @@ if [[ -d $argv[-1] ]]; then
     fi
   done
 else
+  if [[ $1 = $HOME || $1 = $HOME/* ]]; then
+    1="~${1#$HOME}"
+  fi
   zftp get $1 >$2 || stat=$?
 fi
 
diff --git a/Functions/Zftp/zfget b/Functions/Zftp/zfget
index cee0290b3..cb058204d 100644
--- a/Functions/Zftp/zfget
+++ b/Functions/Zftp/zfget
@@ -19,50 +19,34 @@
 
 emulate -L zsh
 
-local loc rem optlist opt nglob remlist time cat
+local loc rem opt remlist opt_G opt_t opt_c
 integer stat do_close
 
-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
-	 ;;
-      c) cat=1
-	 ;;
-      *) print option $opt not recognised >&2
-	 ;;
-    esac
-  done
-  shift
+while getopts :Gtc opt; do
+  [[ $opt = '?' ]] && print "zfget: bad option: -$OPTARG" && return 1
+  eval "opt_$opt=1"
 done
+(( OPTIND > 1 )) && shift $(( OPTIND - 1 ))
 
-zfautocheck
+zfautocheck || 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
+  if [[ $opt_G != 1 ]]; then
     zfrglob remlist
   fi
   if (( $#remlist )); then
     for rem in $remlist; do
-      if [[ -n $cat ]]; then
+      if [[ -n $opt_c ]]; then
 	zftp get $rem
 	stat=$?
       else
 	loc=${rem:t}
 	if zftp get $rem >$loc; then
-	  [[ $time = 1 ]] && zfrtime $rem $loc
+	  [[ $opt_t = 1 ]] && zfrtime $rem $loc
 	else
 	  stat=1
 	fi
diff --git a/Functions/Zftp/zfget_match b/Functions/Zftp/zfget_match
index 677108ede..875fca5f1 100644
--- a/Functions/Zftp/zfget_match
+++ b/Functions/Zftp/zfget_match
@@ -10,18 +10,29 @@ fi
 local tmpf=${TMPPREFIX}zfgm$$
 
 if [[ $ZFTP_SYSTEM == UNIX* && $1 == */* ]]; then
-  # On the first argument to ls, we usually get away with a glob.
-  zftp ls "$1*$2" >$tmpf
-  reply=($(<$tmpf))
-  rm -f $tmpf
-else
-  if (( $#zftp_fcache == 0 )); then
-    # Always cache the current directory and use it
-    # even if the system is UNIX.
-    zftp ls >$tmpf
-    zftp_fcache=($(<$tmpf))
+  if [[ -n $WIDGET ]]; then
+    local dir=${1:h}
+    [[ $dir = */ ]] || dir="$dir/"
+    zftp ls -LF $dir >$tmpf
+    local reply
+    reply=(${${${(f)"$(<$tmpf)"}##$dir}%\*})
+    rm -f $tmpf
+    _description expl 'remote file'
+    compadd "$expl[@]" -P $dir - $reply
+  else
+    # On the first argument to ls, we usually get away with a glob.
+    zftp ls "$1*$2" >$tmpf
+    reply=($(<$tmpf))
     rm -f $tmpf
   fi
-  reply=($zftp_fcache);
+else
+  local fcache_name
+  zffcache
+  if [[ -n $WIDGET ]]; then
+    _description expl 'remote file'
+    compadd "$expl[@]" -F fignore - ${(P)fcache_name}
+  else
+    reply=(${(P)fcache_name});
+  fi
 fi
 # }
diff --git a/Functions/Zftp/zfgoto b/Functions/Zftp/zfgoto
index bd1cdbfe5..57651e383 100644
--- a/Functions/Zftp/zfgoto
+++ b/Functions/Zftp/zfgoto
@@ -2,6 +2,9 @@
 # Go to bookmark bname, a location on a remote FTP host.  Unless
 # this was the last session or is for anonymous FTP, prompt for
 # the user's password.
+#
+# Maybe this should try and look for an appropriate session to use
+# for the transfer.
 
 emulate -L zsh
 setopt extendedglob
@@ -11,33 +14,20 @@ setopt extendedglob
 : ${ZFTP_BMFILE:=${ZFDOTDIR:-$HOME}/.zfbkmarks}
 
 typeset -A bkmarks
-local line ncftp opt optlist
+local line opt_n opt
 
-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
-      n) ncftp=1
-	 ;;
-      *) print option $opt not recognised >&2
-	 return 1
-	 ;;
-    esac
-  done
-  shift
+while getopts :n opt; do
+  [[ $opt = '?' ]] && print "zfgoto: bad option: -$OPTARG" && return 1
+  eval "opt_$opt=1"
 done
+(( OPTIND > 1 )) && shift $(( OPTIND - 1 ))
 
 if (( $# != 1 )); then
   print "Usage: zfgoto bookmark" >&2
   return 1
 fi
 
-if [[ -n $ncftp && -f ~/.ncftp/bookmarks ]]; then
+if [[ -n $opt_n && -f ~/.ncftp/bookmarks ]]; then
   local oldifs=$IFS
   IFS=,
   while read -rA line; do
@@ -73,7 +63,8 @@ if [[ $ZFTP_USER = $user && $ZFTP_HOST = $host ]]; then
 elif [[ $user = ftp || $user = anonymous ]]; then
   # Anonymous ftp, so we don't need password etc.
   zfanon $host && [[ -n $dir ]] && zfcd $dir
-elif [[ $zflastsession = ${host}:* && $user = $zflastuser ]]; then
+elif [[ $zfconfig[lastloc_$ZFTP_SESSION] = ${host}:* &&
+  $user = $zfconfig[lastuser_$ZFTP_SESSION] ]]; then
   # This was the last session, so assume it's still setup in the
   # open parameters
   zfopen && [[ -n $dir ]] && zfcd $dir
diff --git a/Functions/Zftp/zfinit b/Functions/Zftp/zfinit
index 0bc619277..f650b7bbb 100644
--- a/Functions/Zftp/zfinit
+++ b/Functions/Zftp/zfinit
@@ -4,7 +4,7 @@ emulate -L zsh
 
 if [[ ${+zfconfig} = 0 ]]; then
   typeset -gA zfconfig
-  zfconfig=(progress bar update 1)
+  zfconfig=(progress bar update 1 lastsession default)
 fi
 
 alias zfcd='noglob zfcd'
@@ -14,9 +14,9 @@ alias zfdir='noglob zfdir'
 alias zfuget='noglob zfuget'
 
 autoload -U zfanon zfautocheck zfcd zfcd_match zfcget zfclose zfcput
-autoload -U zfdir zfgcp zfget zfget_match zfgoto zfhere zfinit zfls
-autoload -U zfmark zfopen zfparams zfpcp zfput zfrglob zfrtime zfstat
-autoload -U zftp_chpwd zftp_progress zftype zfuget zfuput
+autoload -U zfdir zffcache zfgcp zfget zfget_match zfgoto zfhere zfinit zfls
+autoload -U zfmark zfopen zfparams zfpcp zfput zfrglob zfrtime zfsession
+autoload -U zfstat zftp_chpwd zftp_progress zftransfer zftype zfuget zfuput
 
 #
 # zftp completions: only use these if new-style completion is not
@@ -33,7 +33,8 @@ if [[ ${#_patcomps} -eq 0 || ${_patcomps[(i)zf*]} -gt ${#_patcomps} ]]; then
     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
+    'w[1,open][1,params]' -k hosts - \
+    'w[1,session]' -s '${$(zftp session):#$ZFTP_SESSION}' -- zftp
   compctl -K zfcd_match -S/ -q zfcd zfdir zfls
   compctl -K zfget_match zfget zfgcp zfuget zfcget
   compctl -k hosts zfanon zfopen zfparams
@@ -42,4 +43,15 @@ if [[ ${#_patcomps} -eq 0 || ${_patcomps[(i)zf*]} -gt ${#_patcomps} ]]; then
     -x 'W[1,-*n*]' \
     -s '$(awk -F, '\''NR > 2 { print $1 }'\'' ~/.ncftp/bookmarks)' -- \
     zfgoto zfmark
+  compctl -s '${$(zftp session):#$ZFTP_SESSION}' -- zfsession
+  # in _zftp for new completion, but hard to inline into a compctl
+  zftransfer_match() {
+    local sess=${1%%:*} oldsess=$ZFTP_SESSION
+    [[ -n $sess ]] && zftp session $sess
+    zfget_match ${1#*:} $2
+    [[ -n $sess && -n $oldsess ]] && zftp session $oldsess
+    reply=(${sess}:${^reply})
+  }
+  compctl -s '$(zftp session)' -S : -x 'C[0,*:*]' \
+    -K zftransfer_match -- zftransfer
 fi
diff --git a/Functions/Zftp/zfmark b/Functions/Zftp/zfmark
index 8d35ce45a..74cc702ac 100644
--- a/Functions/Zftp/zfmark
+++ b/Functions/Zftp/zfmark
@@ -37,8 +37,9 @@ fi
 
 if [[ -n $ZFTP_HOST ]]; then
   bkmarks[$1]="${ZFTP_USER}@${ZFTP_HOST}:${ZFTP_PWD}"
-elif [[ -n $zflastsession ]]; then
-  bkmarks[$1]="${zflastuser}@${zflastsession}"
+elif [[ -n $zfconfig[lastloc_$ZFTP_SESSION] ]]; then
+  bkmarks[$1]="${zfconig[lastuser_$ZFTP_SESSION]}@\
+${zfconfig[lastloc_$ZFTP_SESSION]}"
 else
   print "No current or recent ZFTP session to bookmark." >&2
   return 1
diff --git a/Functions/Zftp/zfopen b/Functions/Zftp/zfopen
index b264aeaba..32b450411 100644
--- a/Functions/Zftp/zfopen
+++ b/Functions/Zftp/zfopen
@@ -7,25 +7,13 @@
 
 emulate -L zsh
 
-local optlist opt once dir
+local opt dir opt_1
 
-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
+while getopts :1 opt; do
+  [[ $opt = "?" ]] && print "zfopen: bad option: -$OPTARG" >&2 && return 1
+  eval "opt_$opt=1"
 done
+(( OPTIND > 1 )) && shift $(( OPTIND - 1 ))
 
 # This is where we should try and do same name-lookupage in
 # both .netrc and .ncftp/bookmarks .  We could even try saving
@@ -37,8 +25,14 @@ if [[ $1 = */* ]]; then
   1=${1%%/*}
 fi
 
-if [[ $once = 1 ]]; then
+if [[ $opt_1 = 1 ]]; then
   zftp open $* || return 1
+  if [[ $# = 1 ]]; then
+    if ! zftp login; then
+      zftp close
+      return 1
+    fi
+  fi
 else
   # set parameters, but only if there was at least a host
   (( $# > 0 )) && zfparams $*
diff --git a/Functions/Zftp/zfparams b/Functions/Zftp/zfparams
index 5c5262c52..faae63251 100644
--- a/Functions/Zftp/zfparams
+++ b/Functions/Zftp/zfparams
@@ -2,11 +2,25 @@
 
 emulate -L zsh
 
-# Set to prompt for any user or password if not given.
-# Don't worry about accounts here.
-if (( $# > 0 )); then
+if [[ $# -eq 1 && $1 = - ]]; then
+  # Delete existing parameter set.
+  local sess=$ZFTP_SESSION key
+  key=${zfconfig[fcache_$sess]}
+  [[ -n $key ]] && unset $key
+  for key in fcache lastloc lastdir curdir otherdir otherargs lastuser; do
+    unset "zfconfig[${key}_${sess}]"
+  done
+elif (( $# > 0 )); then
+  # Set to prompt for any user or password if not given.
+  # Don't worry about accounts here.
   (( $# < 2 )) && 2='?'
-  (( $# < 3 )) && 3='?'
+  if (( $# < 3 )); then
+    if [[ $2 = '?'* ]]; then
+      3="?Password on ${1}: "
+    else
+      3="?Password for ${2##\\?} on ${1}: "
+    fi
+  fi
 fi
 zftp params $*
 # }
diff --git a/Functions/Zftp/zfpcp b/Functions/Zftp/zfpcp
index ddd570e59..9642688b7 100644
--- a/Functions/Zftp/zfpcp
+++ b/Functions/Zftp/zfpcp
@@ -17,7 +17,7 @@ emulate -L zsh
 local rem loc
 integer stat do_close
 
-zfautocheck
+zfautocheck || return 1
 
 if [[ $# -gt 2 || $2 = (.|..) || $2 = */ ]]; then
   local dir=$argv[-1]
@@ -32,6 +32,9 @@ if [[ $# -gt 2 || $2 = (.|..) || $2 = */ ]]; then
     zftp put $rem <$loc || stat=1
   done
 else
+  if [[ $2 = $HOME || $2 = $HOME/* ]]; then
+    2="~${2#$HOME}"
+  fi
   zftp put $2 <$1
   stat=$?
   if [[ stat -ne 0 && $ZFTP_CODE = 553 && $ZFTP_REPLY = *'Is a directory'* ]]
diff --git a/Functions/Zftp/zfrglob b/Functions/Zftp/zfrglob
index fad0c3849..535cb8006 100644
--- a/Functions/Zftp/zfrglob
+++ b/Functions/Zftp/zfrglob
@@ -57,14 +57,10 @@ else
     rm -f $tmpf
   else
     # we just have to do an ls and hope that's right
+    local fcache_name
+    zffcache
     nondir=$pat
-    if (( $#zftp_fcache == 0 )); then
-      # Why does `zftp_fcache=($(zftp ls))' sometimes not work?
-      zftp ls >$tmpf
-      zftp_fcache=($(<$tmpf))
-      rm -f $tmpf
-    fi
-    files=($zftp_fcache)
+    files=(${(P)fcache_name})
   fi
   # now we want to see which of the $files match $nondir:
   # ${...:/foo} deletes occurrences of foo matching a complete word,
diff --git a/Functions/Zftp/zfsession b/Functions/Zftp/zfsession
new file mode 100644
index 000000000..9cd0d918f
--- /dev/null
+++ b/Functions/Zftp/zfsession
@@ -0,0 +1,71 @@
+# function zfsession {
+# Change or list the sessions for the current zftp connection.
+
+emulate -L zsh
+
+local opt opt_l opt_v opt_o opt_d hadopts
+
+while getopts ":lovd" opt; do
+  [[ $opt = "?" ]] && print "zfsession: bad option: -$OPTARG" >&2 && return 1
+  eval "opt_$opt=1"
+  hadopts=1
+done
+(( OPTIND > 1 )) && shift $(( OPTIND - 1 ))
+
+if [[ $# -gt 1 || (( -n $hadopts && -z $opt_d ) && $# -gt 0 ) ]]
+then
+  print "Usage: zfsession ( [ -lvod ] | session )" 1>&2
+  return 1
+fi
+
+if [[ -n $opt_v ]]; then
+  local sess
+  for sess in $(zftp session); do
+    print -n "${(r.15.. ..:.)sess}\t${zfconfig[lastloc_$sess]:-not connected}"
+    if [[ $sess = $ZFTP_SESSION ]]; then
+      print " *"
+    else
+      print
+    fi
+  done
+elif [[ -n $opt_l ]]; then
+  zftp session
+fi
+
+if [[ -n $opt_o ]]; then
+  if [[ $zfconfig[lastsession] != $ZFTP_SESSION ]]; then
+    local cursession=$ZFTP_SESSION
+    zftp session $zfconfig[lastsession]
+    zfconfig[lastsession]=$cursession
+    print $ZFTP_SESSION
+  else
+    print "zfsession: no previous session." >&2
+    return 1
+  fi
+fi
+
+if [[ -n $opt_d ]]; then
+  local del=${1:-$ZFTP_SESSION} key
+  key=${zfconfig[fcache_$del]}
+  [[ -n $key ]] && unset $key
+  for key in fcache lastloc lastdir curdir otherdir otherargs lastuser; do
+    unset "zfconfig[${key}_${del}]"
+  done
+  zftp rmsession $del
+  return
+fi
+
+[[ -n $hadopts ]] && return $stat
+
+if [[ $# = 0 ]]; then
+  print $ZFTP_SESSION
+  return
+fi
+
+local oldsession=${ZFTP_SESSION:-default}
+zftp session $1
+if [[ $ZFTP_SESSION != $oldsession ]]; then
+  zfconfig[lastsession]=$oldsession
+  zftp_chpwd
+fi
+# }
diff --git a/Functions/Zftp/zfstat b/Functions/Zftp/zfstat
index 0ca755d03..6945da99b 100644
--- a/Functions/Zftp/zfstat
+++ b/Functions/Zftp/zfstat
@@ -6,25 +6,15 @@
 setopt localoptions unset
 unsetopt ksharrays
 
-local i stat=0 opt optlist verbose
+local i stat=0 opt opt_v
 
-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
+while getopts :v opt; do
+  [[ $opt = "?" ]] && print "zfstat: bad option: -$OPTARG" >&2 && return 1
+  eval "opt_$opt=1"
 done
+(( OPTIND > 1 )) && shift $(( OPTIND - 1 ))
+
+[[ -n $ZFTP_SESSION ]] && print "Session:\t$ZFTP_SESSION"
 
 if [[ -n $ZFTP_HOST ]]; then
   print "Host:\t\t$ZFTP_HOST"
@@ -55,7 +45,8 @@ if [[ -n $ZFTP_HOST ]]; then
   fi
 else
   print "Not connected."
-  [[ -n $zflastsession ]] && print "Last session:\t$zflastsession"
+  [[ -n $zfconfig[lastloc_$ZFTP_SESSION] ]] &&
+  print "Last location:\t$zfconfig[lastloc_$ZFTP_SESSION]"
   stat=1
 fi
 
@@ -77,7 +68,7 @@ for (( i = 1; i <= ${#ZFTP_PREFS}; i++ )); do
 done
 print
 
-if [[ -n $ZFTP_HOST && $verbose = 1 ]]; then
+if [[ -n $ZFTP_HOST && $opt_v = 1 ]]; then
   zfautocheck -d
   print "Status of remote server:"
   # make sure we print the reply
diff --git a/Functions/Zftp/zftp_chpwd b/Functions/Zftp/zftp_chpwd
index 0b5bbd7d5..53972cd65 100644
--- a/Functions/Zftp/zftp_chpwd
+++ b/Functions/Zftp/zftp_chpwd
@@ -2,14 +2,14 @@
 # You may want to alter chpwd to call this when $ZFTP_USER is set.
 
 # If the directory really changed...
-if [[ $ZFTP_PWD != $zflastdir ]]; then
-  # Cancel the filename cache for the current directory.
-  zftp_fcache=()
+if [[ $ZFTP_PWD != $zfconfig[lastdir_$ZFTP_SESSION] ]]; then
   # ...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
-  zfotherargs=
+  local curdir=$zfconfig[curdir_$ZFTP_SESSION]
+  [[ -n $curdir && -f $curdir ]] && rm -f $curdir
+  zfconfig[otherargs_$ZFTP_SESSION]=
+  zffcache -d
 fi
 
 if [[ -z $ZFTP_USER ]]; then
@@ -18,24 +18,24 @@ if [[ -z $ZFTP_USER ]]; then
   # delete the non-current cached directory
   [[ -n $zfotherdir && -f $zfotherdir ]] && rm -f $zfotherdir
 
-  # don't keep zflastdir between opens (do keep zflastsession)
-  zflastdir=
+  # don't keep lastdir between opens (do keep lastloc)
+  zfconfig[lastdir_$ZFTP_SESSION]=
 
   # return the display to standard
   # uncomment the following line if you have a chpwd which shows directories
-  # chpwd
+  chpwd
 else
-  [[ -n $ZFTP_PWD ]] && zflastdir=$ZFTP_PWD
-  zflastsession="$ZFTP_HOST:$ZFTP_PWD"
-  zflastuser="$ZFTP_USER"
+  [[ -n $ZFTP_PWD ]] && zfconfig[lastdir_$ZFTP_SESSION]=$ZFTP_PWD
+  zfconfig[lastloc_$ZFTP_SESSION]="$ZFTP_HOST:$ZFTP_PWD"
+  zfconfig[lastuser_$ZFTP_SESSION]="$ZFTP_USER"
   local args
   if [[ -t 1 && -t 2 ]]; then
-    local str=$zflastsession
+    local str=$zfconfig[lastloc_$ZFTP_SESSION]
     [[ ${#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"
+      xterm|aixterm) print -n -P "\033]2;$str\a"
 	     ;;
     esac
   fi
diff --git a/Functions/Zftp/zftp_progress b/Functions/Zftp/zftp_progress
index 344d1c9c1..b4b639fce 100644
--- a/Functions/Zftp/zftp_progress
+++ b/Functions/Zftp/zftp_progress
@@ -26,17 +26,19 @@ if [[ -n $ZFTP_TRANSFER ]]; then
   # avoid a `parameter unset' message
   [[ $ZFTP_TRANSFER != *F ]] &&
     (( ${+zftpseconds} )) && (( SECONDS - zftpseconds < update )) && return
-  if [[ -n $ZFTP_SIZE ]]; then
-    local frac="$(( ZFTP_COUNT * 100 / ZFTP_SIZE ))%"
+  # size is usually ZFTP_SIZE, but zftransfer may set ZFTP_TSIZE
+  local size=${ZFTP_TSIZE:-$ZFTP_SIZE}
+  if [[ -n $size ]]; then
+    local frac="$(( ZFTP_COUNT * 100 / size ))%"
     if [[ $style = bar && ${+COLUMNS} = 1 && $COLUMNS -gt 0 ]]; then
       if (( ! ${+zftpseconds} )); then
-	print "$ZFTP_FILE ($ZFTP_SIZE bytes): $ZFTP_TRANSFER" 1>&2
+	print "$ZFTP_FILE ($size bytes): $ZFTP_TRANSFER" 1>&2
       fi
       integer maxwidth=$(( COLUMNS - 7 ))
-      local width="$(( ZFTP_COUNT * maxwidth / ZFTP_SIZE ))"
+      local width="$(( ZFTP_COUNT * maxwidth / size ))"
       print -nP "\r%S${(l:width:):-}%s${(l:maxwidth-width:):-}: ${frac}%%" 1>&2
     else
-      print -n "\r$ZFTP_FILE ($ZFTP_SIZE bytes): $ZFTP_TRANSFER $frac" 1>&2
+      print -n "\r$ZFTP_FILE ($size bytes): $ZFTP_TRANSFER $frac" 1>&2
     fi
   else
     print -n "\r$ZFTP_FILE: $ZFTP_TRANSFER $ZFTP_COUNT" 1>&2
diff --git a/Functions/Zftp/zftransfer b/Functions/Zftp/zftransfer
new file mode 100644
index 000000000..929f099d2
--- /dev/null
+++ b/Functions/Zftp/zftransfer
@@ -0,0 +1,62 @@
+# function zftransfer {
+# Transfer files between two distinct sessions. No remote globbing
+# is done, since only single pairs can be transferred.
+
+emulate -L zsh
+
+local sess1 sess2 file1 file2 oldsess=${ZFTP_SESSION}
+
+if [[ $# -ne 2 ]]; then
+  print "Usage: zftransfer sess1:file1 sess2:file2" 1>&2
+  return 1
+fi
+
+if [[ $1 = *:* ]]; then
+  sess1=${1%%:*}
+  file1=${1#*:}
+fi
+: ${sess1:=$ZFTP_SESSION}
+
+if [[ $2 = *:* ]]; then
+  sess2=${2%%:*}
+  file2=${2#*:}
+fi
+: ${sess2:=$ZFTP_SESSION}
+if [[ -z $file2 || $file2 = */ ]]; then
+  file2="${file2}${file1:t}"
+fi
+
+if [[ $sess1 = $sess2 ]]; then
+  print "zftransfer: must use two distinct sessions." 1>&2
+  return 1
+fi
+
+zftp session $sess1
+zfautocheck || return 1
+
+# It's more useful to show the progress for the second part
+# of the pipeline, but unfortunately that can't necessarily get
+# the size from the pipe --- and if it does, it's probably wrong.
+# To avoid that, try to get the size and set it for the progress to
+# see.
+if [[ $zfconfig[progress] != none ]]; then
+  local ZFTP_TSIZE array tmpfile=${TMPPREFIX}zft$$
+  zftp remote $file1 >$tmpfile 2>/dev/null
+  array=($(<$tmpfile))
+  rm -f $tmpfile
+  [[ $#array -eq 2 ]] && ZFTP_TSIZE=$array[1]
+fi
+
+# We do the RHS of the pipeline in a subshell, too, so that
+# the LHS can get SIGPIPE when it exits.
+{ zfconfig[progress]=none
+  zftp get $file1 } |
+( zftp session $sess2
+  zfautocheck && zftp put $file2 )
+
+local stat=$?
+
+zftp session $oldsess
+
+return $stat
+# }
diff --git a/Functions/Zftp/zfuget b/Functions/Zftp/zfuget
index 482da42e9..955c48f4a 100644
--- a/Functions/Zftp/zfuget
+++ b/Functions/Zftp/zfuget
@@ -26,7 +26,7 @@
 emulate -L zsh
 
 local loc rem locstats remstats doit tmpfile=${TMPPREFIX}zfuget$$
-local rstat remlist verbose optlist opt bad i silent nglob time
+local rstat remlist opt opt_v opt_s opt_G opt_t
 integer stat do_close
 
 zfuget_print_time() {
@@ -43,40 +43,20 @@ zfuget_print () {
   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
+while getopts :vsGt opt; do
+  [[ $opt = "?" ]] && print "zfuget: bad option: -$OPTARG" >&2 && return 1
+  eval "opt_$opt=1"
 done
+(( OPTIND > 1 )) && shift $(( OPTIND - 1 ))
 
-[[ -n $bad ]] && return 1
-
-zfautocheck
+zfautocheck || 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
+  if [[ $opt_n != 1 ]]; then
     zfrglob remlist
   fi
   if (( $#remlist )); then
@@ -99,11 +79,11 @@ for remlist in $*; do
 	  stat=1
 	  continue
 	fi
-	[[ $verbose = 1 ]] && zfuget_print
+	[[ $opt_v = 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
+	  if [[ $locstats[2] > $remstats[2] && $opt_s != 1 ]]; then
+	    [[ $opt_v != 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
@@ -111,24 +91,24 @@ for remlist in $*; do
 	else
 	  # Files have same size
 	  if [[ $locstats[2] < $remstats[2] ]]; then
-	    if [[ $silent != 1 ]]; then
-	      [[ $verbose != 1 ]] && zfuget_print
+	    if [[ $opt_s != 1 ]]; then
+	      [[ $opt_v != 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
+	    [[ $opt_v = 1 ]] && print Not transferring
 	    doit=n
 	  fi
 	fi
       else
-	[[ $verbose = 1 ]] && print New file $loc
+	[[ $opt_v = 1 ]] && print New file $loc
       fi
       if [[ $doit = y ]]; then
 	if zftp get $rem >$loc; then
-	  if [[ $time = 1 ]]; then
+	  if [[ $opt_t = 1 ]]; then
 	    # if $remstats is set, it's second element is the remote time
 	    zfrtime $loc $rem $remstats[2]
 	  fi
diff --git a/Functions/Zftp/zfuput b/Functions/Zftp/zfuput
index b54d0d0d4..cb179052c 100644
--- a/Functions/Zftp/zfuput
+++ b/Functions/Zftp/zfuput
@@ -12,7 +12,7 @@
 emulate -L zsh
 
 local loc rem locstats remstats doit tmpfile=${TMPPREFIX}zfuput$$
-local rstat verbose optlist opt bad i silent
+local rstat opt opt_v opt_s
 integer stat do_close
 
 zfuput_print_time() {
@@ -29,29 +29,13 @@ zfuput_print () {
   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
+while getopts :vs opt; do
+  [[ $opt = "?" ]] && print "zfuget: bad option: -$OPTARG" >&2 && return 1
+  eval "opt_$opt=1"
 done
+(( OPTIND > 1 )) && shift $(( OPTIND - 1 ))
 
-[[ -n $bad ]] && return 1
-
-zfautocheck
+zfautocheck || return 1
 
 if [[ $ZFTP_VERBOSE = *5* ]]; then
   # should we turn it off locally?
@@ -77,13 +61,13 @@ for rem in $*; do
     print "Server does not implement full command set required." 1>&2
     return 1
   elif [[ $rstat = 1 ]]; then
-    [[ $verbose = 1 ]] && print New file $loc
+    [[ $opt_v = 1 ]] && print New file $loc
   else
-    [[ $verbose = 1 ]] && zfuput_print
+    [[ $opt_v = 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
+      if [[ $locstats[2] < $remstats[2] && $opt_s != 1 ]]; then
+	[[ $opt_v != 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
@@ -91,15 +75,15 @@ for rem in $*; do
     else
       # Files have same size
       if [[ $locstats[2] > $remstats[2] ]]; then
-	if [[ $silent != 1 ]]; then
-	  [[ $verbose != 1 ]] && zfuput_print
+	if [[ $opt_s != 1 ]]; then
+	  [[ $opt_v != 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
+	[[ $opt_v = 1 ]] && print Not transferring
 	doit=n
       fi
     fi