[Midnightbsd-cvs] src [6904] vendor/NetBSD/tnftp/20100108: add old version from base for comparisons

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Fri Oct 31 18:45:23 EDT 2014


Revision: 6904
          http://svnweb.midnightbsd.org/src/?rev=6904
Author:   laffer1
Date:     2014-10-31 18:45:22 -0400 (Fri, 31 Oct 2014)
Log Message:
-----------
add old version from base for comparisons

Added Paths:
-----------
    vendor/NetBSD/tnftp/20100108/
    vendor/NetBSD/tnftp/20100108/COPYING
    vendor/NetBSD/tnftp/20100108/ChangeLog
    vendor/NetBSD/tnftp/20100108/INSTALL
    vendor/NetBSD/tnftp/20100108/Makefile.am
    vendor/NetBSD/tnftp/20100108/Makefile.in
    vendor/NetBSD/tnftp/20100108/NEWS
    vendor/NetBSD/tnftp/20100108/README
    vendor/NetBSD/tnftp/20100108/THANKS
    vendor/NetBSD/tnftp/20100108/src/
    vendor/NetBSD/tnftp/20100108/src/Makefile.am
    vendor/NetBSD/tnftp/20100108/src/Makefile.in
    vendor/NetBSD/tnftp/20100108/src/cmds.c
    vendor/NetBSD/tnftp/20100108/src/cmdtab.c
    vendor/NetBSD/tnftp/20100108/src/complete.c
    vendor/NetBSD/tnftp/20100108/src/domacro.c
    vendor/NetBSD/tnftp/20100108/src/extern.h
    vendor/NetBSD/tnftp/20100108/src/fetch.c
    vendor/NetBSD/tnftp/20100108/src/fetch.c.orig
    vendor/NetBSD/tnftp/20100108/src/ftp.1
    vendor/NetBSD/tnftp/20100108/src/ftp.c
    vendor/NetBSD/tnftp/20100108/src/ftp_var.h
    vendor/NetBSD/tnftp/20100108/src/main.c
    vendor/NetBSD/tnftp/20100108/src/progressbar.c
    vendor/NetBSD/tnftp/20100108/src/progressbar.h
    vendor/NetBSD/tnftp/20100108/src/ruserpass.c
    vendor/NetBSD/tnftp/20100108/src/util.c
    vendor/NetBSD/tnftp/20100108/src/version.h
    vendor/NetBSD/tnftp/20100108/tnftp.h
    vendor/NetBSD/tnftp/20100108/todo

Added: vendor/NetBSD/tnftp/20100108/COPYING
===================================================================
--- vendor/NetBSD/tnftp/20100108/COPYING	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/COPYING	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,59 @@
+$NetBSD: COPYING,v 1.7 2010/01/12 07:01:01 lukem Exp $
+
+Copyright (c) 2001-2010 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Simon Burge, Luke Mewburn, and Christos Zoulas.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+       This product includes software developed by the NetBSD
+       Foundation, Inc. and its contributors.
+4. Neither the name of The NetBSD Foundation nor the names of its
+   contributors may be used to endorse or promote products derived
+   from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+
+This product also contains software developed by other people, and you
+are advised to read the various source files to read the full details
+of the other licenses. Those licenses also require the following
+acknowledgements:
+
+	This product includes software developed by the NetBSD Foundation,
+	Inc.  and its contributors. Those contributors include:
+		- Simon Burge
+		- Jaromir Dolecek
+		- Klaus Klein
+		- Luke Mewburn
+		- Jason R. Thorpe of the Numerical Aerospace Simulation
+		  Facility, NASA Ames Research Center.
+		- Christos Zoulas
+
+	This product includes software developed by the University of
+	California, Berkeley and its contributors. Those contributors include:
+		- Christos Zoulas of Cornell University.
+		- Guido van Rossum.
+
+	This product includes software developed by Christos Zoulas.
+

Added: vendor/NetBSD/tnftp/20100108/ChangeLog
===================================================================
--- vendor/NetBSD/tnftp/20100108/ChangeLog	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/ChangeLog	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,1794 @@
+$NetBSD: ChangeLog,v 1.58 2010/01/12 06:58:57 lukem Exp $
+
+Tue Jan 12 06:58:15 UTC 2010	lukem
+
+	* Release as "tnftp 20100108"
+
+	* Rename onoff() argument "bool" to "val".
+
+Tue Jan  5 09:12:01 UTC 2010	lukem
+
+	* If ARG_MAX isn't defined, use the result from sysconf(_SC_ARG_MAX).
+	  Fixes build when using newer glibc.
+
+	* Add libnetbsd.la to the LIBADD for libedit.
+	  Fix provided by Adam Sampson.
+
+Mon Jan  4 06:28:07 UTC 2010	lukem
+
+	* Distribute various files not shipped by default automake rules,
+	  to use 'make dist' instead of 'cvs export'.
+
+Wed Dec 30 00:12:47 UTC 2009	lukem
+
+	* Release as "tnftp 20091122"
+
+Sun Nov 15 10:14:44 UTC 2009	lukem
+
+	* Merge NetBSD ftp from 20090520 to 20090915.  Change:
+		- Rename internal getline() to get_line() to avoid
+		  conflict with libc with former.
+		- Avoid a NULL dereference in an error message.
+
+Sat Nov 14 09:21:19 UTC 2009	lukem
+
+	* Convert to automake & libtool.
+
+Sat Jun  6 07:17:38 UTC 2009	lukem
+
+	* Release as "tnftp 20090606"
+
+Fri May 22 01:11:15 UTC 2009	lukem
+
+	* configure fixes:
+	  - Add the time.h headers to accheck_includes, for the strptime check.
+	  - Remove the check for el_init in libedit; we're always replacing
+	    the library and the presence of strvis() in some versions
+	    confuses other checks.
+
+Wed May 20 13:47:43 UTC 2009	lukem
+
+	* Release as "tnftp 20090520"
+
+	* Merge NetBSD ftp from 20070722 to 20090520.  Changes:
+	    - Only attempt to el_parse() a command unknown by the default
+	      parser if editing is enabled.
+	      Fixes PR 38589.
+	    - Turn off the alarmtimer before resetting the SIGALRM handler
+	      back to SIG_DFL.
+	      Fixes PR 35630.
+	    - Add epsv6 and epsv to disable extended passive mode for ipv6 or
+	      both ipv4 and ipv6 respectively.  This hack is due to our
+	      friends a Juniper Networks who break epsv in ipv6.
+	      Should be fixed in ScreenOS 6.2.X.
+	    - Improve parsing of chunked transfer chunks per RFC2616:
+	      - more stringent chunk-size parsing
+	      - ignore optional trailing ';chunk-ext' stuff, instead of barfing
+	      - detect EOF before final \r\n.
+	    - Use the service name to getaddrinfo() (along with the host
+	      name), so that features such as DNS Service Discovery have a
+	      better chance of working.
+	      Display the service name in various status & error messages.
+	    - Don't getservbyname() the :port component of a URL; RFC 3986
+	      says it's just an unsigned number, not a service name.
+	    - Fix numerous WARNS=4 issues (-Wcast-qual -Wsign-compare).
+	    - Fix -Wshadow issues
+	    - Update copyrights
+	    - Remove clause 3 and 4 from TNF licenses
+	    - Rename HAVE_STRUCT_SOCKADDR_SA_LEN to
+	      HAVE_STRUCT_SOCKADDR_IN_SIN_LEN to accurately reflect the
+	      structure member being used.
+	    - Use AF_INET instead of AF_UNSPEC as the default family if
+	      !defined(INET6).
+
+	* configure improvements:
+	  - Style tweaks.
+	  - Use AC_LANG_PROGRAM() instead of AC_LANG_SOURCE()
+	  - Add a check for strptime() requiring separators between
+	    conversions, and use our replacement one if it does.
+
+Sat Dec 20 15:28:24 UTC 2008	lukem
+
+	* configure improvements:
+	  - Move IPv6 check from tnftp.h to configure.ac (as per tnftpd).
+	  - Rework option descriptions.
+	  - Highlight when tests are for a specific option.
+	  - Move configuration results to the end of the file.
+	  - Display $prefix in configure results.
+
+Fri Aug 15 03:03:36 UTC 2008	lukem
+
+	* Add a "Configuration results" display at the end of configure.
+	  Cosmetic tweaks.
+
+Fri Feb 29 09:45:56 UTC 2008	lukem
+
+	* Support @EXEEXT@ for Cygwin (etc).
+
+Mon Aug  6 04:55:19 UTC 2007	lukem
+
+	* Release as "tnftp 20070806"
+
+	* Add a NEWS file.
+
+	* Reduce differences between NetBSD-ftp and local copy.
+
+	* Merge NetBSD ftp from 20070605 to 20070722.
+	  Changes:
+		- Document about:ftp and about:version.
+
+	* Add autoconf check for (Dante) SOCKS5.
+	  (Needs run-time testing and more portability testing.)
+
+Mon Jul 23 11:44:42 UTC 2007	lukem
+
+	* Don't use non-standard: u_char u_short u_int.
+	  Use uint32_t instead of u_int32_t.
+
+	* Consistently use AS_CASE() and AS_IF() in configure.ac.
+
+	* Don't use defined() with HAVE_DECL_xxx.
+	  Use `LL' instead of `L' suffix for fallback
+	  defines of LLONG_MIN and LLONG_MAX.
+
+Sun Jul 22 12:00:17 UTC 2007	lukem
+
+	* Include <arpa/nameser.h> if available, and provide fallback #defines.
+
+	* Sync with lib/libc/inet/inet_pton.c 1.3:
+		* Sync to bind 9.3.x version
+		* Update ISC copyright
+		* Fix some lint
+
+	* Sync with lib/libc/inet/inet_ntop.c 1.3:
+		* Sync to bind 9.3.x version
+		* Update ISC copyright
+		* Use socklen_t instead of size_t
+		* Use snprintf() instead of SPRINTF()
+		* Improve detection of various boundary conditions
+
+	* Sync to NetBSD glob.h 1.21, glob.c 1.16:
+		* Standards compliance fix
+		* De-lint
+		* Don't overflow when DEBUG is defined.
+
+        * Sync fgetln.c to tools/compat/fgetln.c 1.7:
+		* Clause 3 removal.
+
+	* Sync to config.guess 2007-07-22, config.sub 2007-06-28.
+
+	* Consistency tweaks in configure help strings.
+
+	* Add check for struct sockaddr.sa_len.
+	  Change tests for HAVE_foo to defined(HAVE_foo).
+	  Replace HAVE_SOCKADDR_SA_LEN with HAVE_STRUCT_SOCKADDR_SA_LEN.
+
+	* Remove pretence of supporting SOCKS for now;
+	  no test system is available, and the old
+	  autoconf 2.13 support wasn't upgraded to 2.61.
+
+	* configure.ac style consistency tweaks.
+	  Move autoconf aux files from ./ to build-aux/
+
+	* Remove duplicate HAVE_STRERROR replacement in tnftp.h.
+
+Thu Jun  7 04:47:47 UTC 2007	lukem
+
+	* Merge NetBSD ftp from 20070510 to 20070605.  Changes:
+		- Enforce restriction that (http) proxied URL fetchs don't
+		  support being restarted at this time.
+		  Addresses NetBSD Problem Report 28697.
+		- Display times in RFC2822 form rather than using ctime(3),
+		  since the former is more explicit about the timezone offset.
+		- main: call tzset() to ensure TZ is setup for other <time.h>
+		  functions.
+		- remotemodtime(): use strptime() to parse the reply.
+		- fetch_url(): ensure struct tm is zeroed before calling
+		  strptime().
+		- Modify parse_url() to consistently strip the leading `/'
+		  off ftp URLs.
+		  Fixes NetBSD Problem Report 17617.
+		- Use 'RFCnnnn' (with leading 0) instead of 'RFC nnnn', to be
+		  consistent with the style in the RFC index.
+		- Refer to RFC3916 instead of 1738 or 2732.
+		- Expand the list of supported RFCs in ftp(1) to contain the
+		  document name as well.
+
+Fri May 11 04:39:55 UTC 2007	lukem
+
+	* Update INSTALL and COPYING.
+
+	* Rename HAVE_QUAD_SUPPORT to HAVE_PRINTF_LONG_LONG, and only
+	  require support for 'long long' in that check rather than
+	  needing sizeof(off_t)>=8, as some systems have a separate
+	  off64_t when Large File Support is enabled.
+
+	* config.guess: treat 'i86xen:SunOS:5.*' as 'i86pc:SunOS:5.*'
+
+Thu May 10 15:23:33 UTC 2007	lukem
+
+	* Remove checks for util.h and libutil.h, and replacement for
+	  fparseln(), since fparseln() isn't used any more.
+
+	* Merge NetBSD ftp from 20070418 to 20070510.  Changes:
+		- Switch from fparseln() to the internal getline() when
+		  parsing HTTP headers.  Makes ftp a bit more portable
+		  (not needing fparseln()) at the expense of not supporting
+		  arbitrary long header lines, which I'm not concerned about
+		  because we don't support header line continuation either...
+		- Replace references from draft-ietf-ftpext-mlst-NN to RFC 3659.
+		- Fix misplaced const.
+		- Implement copy_bytes() to copy bytes from one fd to another
+		  via the provided buffer, with optional rate-limiting and
+		  hash-mark printing, using one loop and handle short writes.
+		  Refactor sendrequest() and recvrequest() to use copy_data().
+		  Addresses NetBSD Problem Report 15943.
+
+Wed May  9 05:24:55 UTC 2007	lukem
+
+	* Fix typo in poll()-based implementation of usleep() replacement.
+
+Wed May  9 04:58:50 UTC 2007	lukem
+
+	* Rename configure.in to configure.ac, as the latter is the
+	  preferred name in autoconf 2.61.
+
+	* Convert from autoconf 2.13 to 2.61:
+	  * Use a consistent quoting mechanism.
+	  * Use modern autoconf macros, #define names, etc.
+	  * Search for more header files, and only #include if found.
+	  * Remove old-style config.h.in generation.
+	  This may fix various tests on platforms such as FreeBSD and OS X.
+
+	* Add -Wl,-search_paths_first to LDFLAGS on OS X (Darwin) if the
+	  linker supports it.  This is needed so we use our libedit
+	  rather than the system one.
+
+	XXX: SOCKS support is currently disabled until I update the
+	     autoconf support.
+
+Mon Apr 23 06:04:26 UTC 2007	lukem
+
+	* Merge NetBSD ftp from 20050610 to 20070418.  Changes:
+		- Add '-s srcaddr'.
+		- Use IEC 60027-2 2^N based "KiB", "MiB" (etc) instead of
+		  10^n "KB", "MB", ...
+		- Recognize 307 redirect code.
+		- Suppress printing non-COMPLETE reply strings when EPSV/EPRT
+		  fails and we fall-back to PASV/PORT.  Should fix a problem
+		  with the emacs ftp wrapper.
+		- Fix display of 'Continue with <cmd>' messages.
+		- Prevent segfaults in .netrc parsing.
+		- Flush stdout before each command; ftp as slave process on
+		  a pipe should work.
+		- getpass() can return NULL in some implementations; cope.
+		- Support '-q quittime' when waiting for server replies.
+		- Various spelling & grammatical fixes in the manual.
+		- Plug some memory leaks.
+		- If a file upload (via -u) fails, return an non-zero exit
+		  value based on the index of the file that caused the
+		  problem (a la auto-fetch retrieval).
+		- Coverity fixes for CIDs: 873 874 875 1447 1448 2194 2195 3610
+		- Don't remove trailing character during auth_url()
+		- Fix progressbar display on narrow terminals (<43 columns)
+
+Fri Mar 16 06:00:14 UTC 2007	lukem
+
+	* Change the return value of the replacement gai_strerror()
+	  from "char *" to "const char *", to match the current
+	  standards.
+	  Problem noted by Thomas Klausner.
+
+Thu Oct 26 07:24:22 UTC 2006	lukem
+
+	* Correctly parse "AM" and "PM" in the replacement strptime().
+	  Problem noted by Kathryn Hogg.
+
+Sat Jun 25 06:27:00 UTC 2005	lukem
+
+	* Release as "tnftp 20050625"
+
+	* Simplify the detection & replacement of dirname() and fparseln()
+	  and just use AC_REPLACE_FUNCS.
+	  (We don't care if the vendor has a working version in -lgen or -lutil
+	  instead of -lc; they'll get our replacement version in that case).
+	  Fixes build issue on older Darwin where the previous autoconf check
+	  wouldn't find dirname() in the default system libraries.
+
+	* Only provide a prototype for dirname() if we can't find one in
+	  <libgen.h>
+
+	* Search for NS_IN6ADDRSZ instead of IN6ADDRSZ, since we use the
+	  former and not the latter and older Darwin has the former.
+	  (This allows INET6 support to be enabled on Darwin 7.9.0)
+
+Mon Jun 13 09:22:13 UTC 2005	lukem
+
+	* Tweak SOCKS5 support:
+	    acconfig.h:
+		- fix a comment
+		- ensure close() is replaced
+		- list entries in the same order as aclocal.m4
+		  (and the SOCKS5 FAQ)
+	    aclocal.m4:
+		- ensure getpeername() is replaced
+		- don't replace listen() twice
+
+Fri Jun 10 04:39:33 UTC 2005	lukem
+
+	* Release as "tnftp 20050610"
+
+	* Add dependencies on ${srcdir}/../tnftp.h and ../config.h
+
+	* Merge NetBSD ftp from 20050609 to 20050610.  Changes:
+		- Implement getline() to read a line into a buffer.
+		- Convert to use getline() instead of fgets() whenever reading
+		  user input to ensure that an overly long input line doesn't
+		  leave excess characters for the next input operation to
+		  accidentally use as input.
+		- Zero out the password & account after we've finished with it.
+		- Consistently use getpass(3) (i.e, character echo suppressed)
+		  when reading the account data.  For some reason, historically
+		  the "login" code suppressed echo for Account: yet the "user"
+		  command did not!
+		- Display the hostname in the "getaddrinfo failed" warning.
+		- Appease some -Wcast-qual warnings.  Fixing all of these
+		  requires significant code refactoring.  (mmm, legacy code).
+
+Thu Jun  9 16:49:05 UTC 2005	lukem
+
+	* src, libnetbsd: Excise RCSID block, rather than using
+	  #if 0 ...  #endif.  The point was to minimise RCSID
+	  conflicts, and the latter isn't helping there.
+
+	* Merge NetBSD ftp from 20050531 to 20050609.  Changes:
+		- Only print the "Trying <address>..." message if verbose
+		  and there's more than one struct addrinfo in the
+		  getaddrinfo() result.
+		- Don't use non-standard "u_int".
+
+Wed Jun  1 15:08:01 UTC 2005	lukem
+
+	* Look for dirname(3), which may be in -lgen on IRIX, and
+	  replace it if not found..
+
+Wed Jun  1 11:48:58 UTC 2005	lukem
+
+	* libnetbsd:
+		- Don't use non-standard: u_char u_short u_int.
+		- Use uint32_t instead of u_int32_t.
+		- Don't use register.
+
+	* libedit: Don't use non-standard uint or u_int.
+
+Tue May 31 02:23:08 UTC 2005	lukem
+
+	* tnftp.h: need <libgen.h> for dirname(3)
+
+	* Merge ftp from 20050513 to 20050531.  Changes:
+		- Helps if the definition of xconnect() matches its
+		  declaration....
+		- Fix some cast issues highlighted by Scott Reynolds using
+		  gcc 4 on OSX.4
+		- Use size_t instead of int where appropriate.
+		- Make this compile on sparc64 (size_t != int).
+		- Printf field widths and size_t don't always mix well, so
+		  cast to int.  Fixes build problem for alpha.
+		- Some const cleanups.
+		- tab cleanup
+		- Improve method used in fileindir() to determine if `file'
+		  is in or under `dir': realpath(3) on non-NetBSD systems may
+		  fail if the target filename doesn't exist, so instead use
+		  realpath(3) on the parent directory of `file'.
+		  Per discussion with Todd Eigenschink.
+		- formatbuf(): fix %m and %M to use the hostname, not the
+		  username.
+		- fetch_ftp(): preserve 'anonftp' across a disconnect() so
+		  that multiple ftp auto-fetches on the same command line
+		  login automatically.
+		- auto_fetch(): use an initialized volatile int to appease
+		  IRIX cc.
+
+	* Merge libedit from NetBSD 20050105 to 20050531.  Changes include:
+		- Rui Paulo: Incorrect tok_line and tok_str declarations.
+		- Remove clause 3 from the UCB license.
+		- Luke Mewburn: Don't abuse unconstify'ing a string
+		  and writing to it, because you'll core dump. Also remove
+		  extra const that gives pain to the irix compiler.
+		- Make sure we flush after we prepare when we are unbuffered
+		  otherwise the prompt will not appear immediately.
+		- Terminate the arglist with a NULL instead of 0.
+		  (Shuts up gcc4.x)
+
+Sat May 28 13:19:38 UTC 2005	lukem
+
+	* libnetbsd/strvis.c:
+		- Sync to NetBSD's vis.c 1.33:
+		  Use malloc(3) instead of alloca(3).
+		- Remove extraenous #endif
+
+Fri May 27 05:46:58 UTC 2005	lukem
+
+	* libnetbsd/strvis.c: Sync to NetBSD's vis.c 1.30:
+	  Use a more standard TNF license.
+
+	* libedit/sig.c: Include "src/progressbar.h" for xsignal_restart()
+	  prototype.
+
+	* Ensure that fallback #define of __attribute__ is available.
+	  Fixes build problem on HP-UX with cc.
+
+Thu May 26 14:21:08 UTC 2005	lukem
+
+	* Extend xpoll()'s HAVE_SELECT implementation to support POLLRDNORM,
+	  POLLWRNORM, and POLLRDBAND - the latter using exceptfds.
+	  Per discussion with Christos Zoulas.
+
+Mon May 16 13:33:27 UTC 2005	lukem
+
+	* Pull in <poll.h> or <sys/poll.h> if they exist even if we're
+	  not using poll, as struct pollfd might exist in those.
+	  Fixes build problem on OSX.3.
+
+	* Separate CPPFLAGS from CFLAGS.
+
+	* Sync various files in libnetbsd with the original versions
+	  in NetBSD.  Notable changes
+		- Convert 4 clause UCB license to 3 clause.
+		- Use strlcpy instead of strcpy.
+		- Update ISC copyright.
+		- Use NS_INADDRSZ, NS_IN6ADDRSZ and NS_INT16SZ instead of
+		  equivalents without NS_ prefix.
+		- Use socklen_t instead of size_t where appropriate.
+		- Improve bounds checking.
+		- Don't update the size of allocated storage until
+		  realloc succeeds.
+		- Fix comment about return value.
+		- Reverse the order of two loop invariant to make
+		  'strlcat(0, "foo", 0)' not get a SEGV.
+		- Use Todd C. Miller's latest copyright notice (more loose).
+		- Use "long long" instead of "quad" in various
+		  comments & constants.
+		- Support VIS_HTTPSTYLE.
+		- Implement svis(), strsvis(), strsvisx(), strunvisx().
+
+	* Prefer poll over select when implementing replacement usleep().
+
+Sat May 14 04:44:35 UTC 2005	lukem
+
+	* Release "tnftp 20050514"
+
+	* Fail if we can't find a library with tgetent (needed for libedit).
+	  NetBSD PR pkg/28925.
+	* Improve quoting when using various autoconf macros.
+
+	* Merge NetBSD-ftp 20050513:
+		- Correct the "optlen" argument passed to getsockopt(3) and
+		  setsockopt(3) in various places.  Fixes a problem noted by
+		  Allen Briggs.
+		- Improve warning printed when connect(2) for the data
+		  channel fails.
+
+Wed May 11 04:19:43 UTC 2005	lukem
+
+	* Release "tnftp 20050511"
+
+Wed May 11 04:10:01 UTC 2005	lukem
+
+	* Update the THANKS file.
+
+	* Only use poll() to implement xpoll() if it's available,
+	  otherwise attempt to use select() if that's available,
+	  otherwise #error.
+
+	* Detect if struct pollfd is available in <poll.h> or <sys/poll.h>.
+	  Improve consistency in use of autoconf macros.
+
+Wed May 11 02:42:08 UTC 2005	lukem
+
+	* Merge NetBSD-ftp 20050511:
+		- Use socklen_t instead of int as the 5th argument to
+		  getsockopt().  Improve invocation of setsockopt() and
+		  associated failure messages.
+
+Wed May 11 01:46:29 UTC 2005	lukem
+
+	* Clean up RCSID usage in vendor-derived code, restoring original
+	  IDs where possible.
+
+Wed May 11 00:08:16 UTC 2005	lukem
+
+	* Merge NetBSD-ftp 20050510:
+		- Prevent an overly-long input line causing a core dump when
+		  editing is enabled.
+		  Issue noted by Ryoji Kanai in FreeBSD Problem Report # 77158.
+		- Implement a timeout on the accept(2) in dataconn() and the
+		  connect(2) in xconnect() by temporarily setting O_NONBLOCK
+		  on the socket and using xpoll() to wait for the operation
+		  to succeed.  The timeout used is the '-q quittime' argument
+		  (defaults to 60s for accept(2), and the system default for
+		  connect(2)).  Idea inspired by discussion with Chuck Cranor.
+		  This may (indirectly) fix various problems with timeouts in
+		  active mode through broken firewalls.
+		- Implement xpoll() as a wrapper around poll(2), to make it
+		  easier to replace on systems without a functional poll(2).
+		  Unconditionally use xpoll() instead of conditionally using
+		  select(2) or poll(2).
+		- In fetch_url(), don't call freeaddrinfo(res0) too early, as
+		  we use pointers to its contents later in the function.
+		  Problem found by Onno van der Linden.
+		- Fix ftp url reget when globs are being used.
+		  Provided by Mathieu Arnold <mat at FreeBSD.org>.
+		- Factor out common string processing code eliminating static
+		  buffers, making functions that should be static be static,
+		  and cleaning up const usage. Added a guard against buffer
+		  overflow, but the domap function is a bit too complicated
+		  to tackle right now.
+		- Clean up whitespace.
+		- Expand description of http_proxy by suggesting the use of
+		  RFC 1738 '%xx' encoding for "unsafe URL" characters in
+		  usernames and passwords.
+
+Wed Jan  5 05:53:59 UTC 2005	lukem
+
+	* For now, assume libedit is not up-to-date and use our own version.
+
+	* Merge libedit from NetBSD 20020605 to 20050105.  Changes include:
+		- Improve vi-mode.
+		- Delete-previous-char and delete-next-char without an
+		  argument are not supposed to modify the yank buffer in
+		  emacs-mode.
+		- Improve incremental searching.
+		- Improve memory allocation & usage.
+		- Move UCB-licensed code from 4-clause to 3-clause.
+		- Make the tokenization functions publically available.
+		- Various tty access bug-fixes.
+		- Improve readline emulation.
+
+Tue Jan  4 13:33:40 UTC 2005	lukem
+
+	* Unixware 7.1.1 implements RFC 2133 (Basic Socket Interface
+	  Extensions for IPv6) but not the successor RFC 2553. The configure
+	  script detects this and decides that tnftp needs to compile its own
+	  version of getaddrinfo().  This produces the error message
+	    /usr/include/netdb.h:248: `getaddrinfo' previously defined here
+	  because Unixware provides an implementation of getaddrinfo() in
+	  netdb.h instead of a prototype declaration :-/. Since netdb.h
+	  cannot be omitted, we will always get this definition and tnftp's
+	  version of getaddrinfo will always create a conflict.  This ugly
+	  preprocessor hack works around the problem. Hints for a better
+	  solution welcome.  Fix from pkgsrc/net/tnftp.
+
+	* Workaround poll() being a compatibility function on Darwin 7
+	  (MacOSX 10.3) by adding a custom test for _POLL_EMUL_H_ which
+	  is defined in poll.h on some MacOSX 10.3 systems.  Not all 10.3
+	  systems have poll.h, so only do the poll() test if at least one
+	  of the header files is found.  Fix from pkgsrc/net/tnftp.
+
+	* Add a utimes() replacement (using utime()) for Interix.
+	  From pkgsrc/net/tnftp.
+
+Mon Jan  3 10:21:57 UTC 2005	lukem
+
+	* Release "tnftp 20050103"
+
+	* Merge NetBSD-ftp 20050103:
+		- Forbid filenames returned from mget that aren't in (or below)
+		  the current directory.  The previous behaviour (of trusting
+		  the remote server's response when retrieving the list of
+		  files to mget with prompting disabled) has been in ftp
+		  ~forever, and has been a "known issue" for a long time.
+		  Recently an advisory was published by D.J. Bernstein on
+		  behalf of Yosef Klein warning of the problems with the
+		  previous behaviour, so to alleviate concern I've fixed
+		  this with a sledgehammer.
+		- Remember the local cwd after any operation which may
+		  change it.
+		- Use "remotecwd" instead of "remotepwd".
+		- Add (unsigned char) cast to ctype functions
+		- Ensure that "mname" is set in ls() and mls() so that an
+		  aborted confirm() prints the correct name.
+		  Problem highlighted & suggested fix from PR [bin/17766]
+		  by Steve McClellan.
+		- If an ftp auto-fetch transfer is interrupted by SIGINT
+		  (usually ^C), exit with 130 instead of 1 (or rarely, 0).
+		  This allows an ftp auto-fetch in a shell loop to correctly
+		  terminate the loop.
+		  Should fix PR [pkg/26351], and possibly others.
+		- Save approximately 8K by not including http authentication,
+		  extended status messages and help strings when the
+		  appropriate options are set.
+		- Move UCB-licensed code from 4-clause to 3-clause licence.
+		  Patches provided by Joel Baker in PR 22365, verified by
+		  Alistair Crooks.
+		- Always decode %xx in a url's user & pass components.
+		- Only remember {WWW,Proxy}-Authenticate "Basic" challenges; no
+		  point in tracking any others since ftp doesn't support them.
+		- Improve the parsing of HTTP responses.
+		- Don't base64 encode the trailing NUL in the HTTP basic auth
+		  response.  Problem noted by Eric Haszlakiewicz.
+		- Improve parsing of HTTP response headers to be more RFC2616
+		  compliant, and skip LWS (linear white space; CR, LF, space,
+		  tab) and the end of lines and between the field name and
+		  the field value.  This still isn't 100% compliant, since we
+		  don't support "multi line" responses at this time.
+		  This should fix PR [bin/22611] from TAMURA Kent (although I
+		  can't easily find a http server to reproduce the problem
+		  against.)
+		- Fix a minor memory leak when parsing HTTP response headers.
+		- Don't unnecessarily display a 401/407 error when running
+		  with -V.  Fix from PR [bin/18535] by Jeremy Reed.
+		- Don't warn about "ignored setsockopt" failures unless
+		  debugging is enabled.  Suggested by Todd Vierling.
+		- Allow empty passwords in ftp://user:@host/file auto-fetch
+		  URLs, per RFC 1738.  Requested by Simon Poole.
+		- correct URL syntax in comment
+		- Note potentially surprising file-saving behaviour in case
+		  of HTTP redirects
+		- -n is ignored for auto-fetch transfers
+		- If connect(2) in xconnect() fails with EINTR, call select(2)
+		  on the socket until it's writable or it fails with something
+		  other than EINTR.  This matches the behaviour in SUSv3, and
+		  prevents the problem when pressing ^T (SIGINFO, which is
+		  marked as restartable) during connection setup would cause
+		  ftp to fail with EADDRINUSE or EALREADY when the second
+		  connect(2) was attempted on the same socket.  Problem found
+		  and solution provided by Maxime Henrion <mux at freebsd.org>.
+		- Add -q to usage. From Kouichirou Hiratsuka in PR 26199.
+		- PR/25566: Anders Magnusson: ftp(1) do not like large TCP
+		  windows.  Limit it to 8M.
+
+Mon Oct  6 01:23:03 UTC 2003	lukem
+
+	* configure.in improvements:
+		- When testing for IN6ADDRSZ in <arpa/nameser.h>, pull in
+		  <sys/types.h> first.  From Stoned Elipot <seb @ NetBSD>
+		- Whitespace cleanup
+
+Mon Aug 25 11:45:45 UTC 2003	lukem
+
+	* Release "tnftp 20030825"
+
+	* Add autoconf test for <sys/syslimits.h>; Cygwin needs it for ARG_MAX.
+	  Per discussion with Eugene Kotlyarov <ekot at protek36.esoo.ru>.
+
+Thu Jul 31 07:30:00 UTC 2003	lukem
+
+	* release "tnftp 20030731"
+
+	* merge ftp from NetBSD 20030731 to 20030731b:
+		- Work around broken ftp servers (notably ProFTPd) that can't
+		  even follow RFC 2389, and skip any amount of whitespace
+		  before a FEATure response.  The RFC says 'single space' yet
+		  ProFTPd puts two.  Noted by DervishD <raul at pleyades.net>.
+		- Improve formatting of features[] debug dump.
+		- Invalidate remote directory completion cache if any command
+		  which may change the remote contents completes successfully,
+		  including: del, mdel, ren, mkdir, rmdir, quote, and all
+		  upload commands.  Patch from Yar Tikhiy <yar at freebsd.org>.
+
+	* merge ftp from NetBSD 20030228 to 20030731:
+		- $FTPUSERAGENT overrides the HTTP User-Agent header.
+		  Based on patch from Douwe Kiela <virtus at wanadoo.nl>.
+		- Add about:tnftp
+		- Fix URL in about:netbsd
+		- netbsd.org->NetBSD.org
+		- strlcpy fix in fetch.c
+		- Uppercase "URL"
+		- fix a bogus error message when given a HTTP URL with a
+		  trailing slash
+		- groff fixes in man page
+		- tweak progressbar.c copyright; the stuff jason did in util.c
+		  wasn't migrated to this file
+		- Don't coredump when printing '%n' in the prompt if there's
+		  no username yet.
+		  Fix from Maxim Konovalov <maxim at freebsd.org>
+
+	* Add test for HAVE_IN6ADDRSZ (which older Darwin is lacking),
+	  and only enable INET6 if it exists.
+	  Patch from Amitai Schlair <schmonz at schmonz.com>.
+
+	* Improve ipv6 check for older linux systems that don't provide
+	  sin6_scope_id.
+	  Patch from YAMANO Yuji <Yamano_Yuji at tk-bay.ogis-ri.co.jp>.
+
+Fri Feb 28 10:57:30 UTC 2003	lukem
+
+	* tagged as "tnftp 2.0 beta1"
+
+Fri Feb 28 10:07:07 UTC 2003	lukem
+
+	* renamed to `tnftp' (from `lukemftp')
+
+	* renamed `libukem' to `libnetbsd'
+
+
+Mon Jun 17 06:50:13 UTC 2002	lukem
+
+	* #if USE_GLOB_H, use <glob.h> instead of "ftpglob.h".
+	  Requested by Mike Heffner <mikeh at freebsd.org>
+
+Mon Jun 10 08:12:35 UTC 2002	lukem
+
+	* crank FTP_VERSION from 1.6-beta1 to 1.6-beta2
+
+	* replace missing fseeko(), with a wrapper to fseek() which
+	  checks that the offset isn't > LONG_MAX
+
+	* #include <regex.h> #if HAVE_REGEX_H
+
+Mon Jun 10 01:27:46 UTC 2002	lukem
+
+	* check for and replace sa_family_t definition
+
+	* don't bother checking for issetugid(); it was only used in the
+	  internal libedit to prevent $HOME/.editrc from being used if
+	  running set-id, and the newer libedit code wouldn't even read
+	  $HOME/.editrc if issetugid() wasn't available.  as many target
+	  operating systems don't have issetugid(), and lukemftp isn't
+	  likely to be run set-id (and $HOME/.netrc is used in any case),
+	  the issetugid() check has been disabled in libedit.
+
+	* add back cpp code which #defines REGEX #if HAVE_REGEX_H
+
+Wed Jun  5 14:39:11 UTC 2002	lukem
+
+	* crank FTP_VERSION from 1.6alpha1 to 1.6-beta1
+
+	* implement replacement setprogname()
+
+	* use getprogname() instead of __progname
+
+	* convert to christos' replacement fgetln(), as it's better than mine
+
+	* merge ftp from NetBSD 20020605 to 20020606:
+		- use setprogname()
+		- only support -6 if INET6 is defined
+
+Wed Jun  5 13:08:25 UTC 2002	lukem
+
+	* don't bother checking if <glob.h> is usable (see below).
+
+	* always compile in local glob; it's the best way to ensure that
+	  various security issues are fixed
+
+	* update libukem/glob.c from NetBSD's __glob13.c rev 1.22 and rev 1.23
+
+	* merge libedit from NetBSD 20010413 to 20020606:
+		- constify; passes all gcc and lint strict checks.
+		- add config.h [Jason Evans], to create a portable version of
+		  libedit that can be easily compiled on other OS's.
+		- PR/12963:Jason Waterman: Fix signed cast problems.
+		- Fixed an __P remnant
+		- Close quoting.
+		- Generate <>& symbolically.
+		- Punctuation and whitespace nits, fix a typo.
+		- PR/14188: Anthony Mallet: Provide an opaque data
+		  pointer to client programs.
+		- a couple of minor fixes.  originally by Ruslan Ermilov
+		  <ru at FreeBSD.org>, highlighted to me by way of Mike Barcroft
+		  <mike at FreeBSD.org> (thanks!)
+		- PR/14067: Anthony Mallet: Provide a programmatic way
+		  to set the read_char function via a new el_set() operation.
+		  Thanks, nicely done :-)
+		- `existent', not `existant'
+		- Don't use HAVE_ yet.
+		- Fix a warning.
+		- Remove an unused variable.
+		- If term_init() fails, cleanup and return NULL. This
+		  avoids other lossage.  Pointed by charles.
+		- va_{start,end} audit: Make sure that each va_start has one
+		  and only one matching va_end, especially in error cases.
+		  If the va_list is used multiple times, do multiple
+		  va_starts/va_ends.  If a function gets va_list as argument,
+		  don't let it use va_end (since it's the callers
+		  responsibility).  Improved by comments from enami and
+		  christos -- thanks!
+		- history_def_enter: fix off-by-one mistake in delete
+		  condition (the behaviour to keep at least one entry on the
+		  history list is retained). This fixes lib/9704 by Phil Nelson.
+
+	* merge ftp from NetBSD 20020524 to 20020605:
+		- when showing the final progress bar, replace "00:00 ETA"
+		  with the elapsed time.  (suggested by simonb)
+		- actually display transfer stats after a URL fetch.
+		  (bug introduced a *long* time ago)
+		- update copyright & version
+
+	* merge ftp from NetBSD 20001127 to 20020524:
+		- Use "r+" instead of "r+w", since the latter is not standard.
+		  Noted by <Steve.McClellan at radisys.com> in private email.
+		- Only send port number in HTTP/1.1 Host: request if port !=
+		  80.  Fixes [bin/15415] from Takahiro Kambe
+		  <taca at sky.yamashina.kyoto.jp>
+		- Fix bad mode passed by mls() to recvrequest().  Fixes
+		  [bin/16642] from <steve.mcclellan at radisys.com>
+		- update copyrights
+		- minor knf
+		- invoke cmdtab.c_handler()s with argv[0] == c_name instead
+		  of the supplied name. that way the full (unambiguous) name
+		  is displayed in error messages and usage strings.
+		- line2 may overrun if line is too long (> 200).  be more
+		  careful on strcpy.
+		- Handle URLs without files correctly (e.g, when using '-o -').
+		  Fix from Anders Dinsen <anders at dinsen.net> in [bin/13768]
+		- portnum is unsigned, use %u instead of %d
+		- Add -4 to force IPv4 and -6 to force IPv6 address usage.
+		  From Hajimu UMEMOTO, via Mike Heffner of FreeBSD.
+		- use u_char instead of char in base64_encode().
+		  problem noticed by Jorgen Lundman in private mail.
+		- don't make broken file with -R option.
+		- handle "*" in Content-Range properly.
+		- If no_proxy condition is true && urltype == FTP_URL_T,
+		  use fetch_ftp to retrieve
+		- convert to use getprogname()
+		- Fix description for "form", "mode", and "struct" commands.
+		  Inspired by [bin/16736] from Steve McClellan
+		  <steve.mcclellan at radisys.com>
+		- Generate <>& symbolically. I'm avoiding .../dist/...
+		  directories for now.
+		- Punctuation nits.
+		- Whitespace cleanup.
+		- put "site" in alphabetical order. noted by Mike Barcroft
+		  in private email
+		- avoid buffer overrun on PASV from malicious server.
+		- Large file ASCII mode support by using fseeko()
+		  instead of fseek().  From Andrey A. Chernov of FreeBSD,
+		  via Mike Heffner.
+		- Deal with const'ification if el_parse().
+		- call setlocale() on startup
+		- display a limited progress bar (containing bytes xferred
+		  and xfer rate) when the file size is unknown
+		- disable progress bar during remglob()
+
+Thu Mar 14 05:41:49 UTC 2002	lukem
+
+	* ensure all AF_INET6 use is protected with #ifdef INET6
+
+	* remove unnecessary __attribute__ goop
+
+	* libukem/snprintf.c: fix compile errors with gcc 3.x
+
+Tue Apr 17 08:07:29 UTC 2001	lukem
+
+	* autoconf check for %q long long support in *printf()
+	  (instead of %ll), define and use HAVE_PRINTF_QD if so
+
+	* ipv6 isn't compatible with socks, so disable the former
+
+	* look for <libutil.h> (instead of <util.h>) and <arpa/nameser.h>
+
+	* don't check for fparseln() twice
+
+	* fix getaddrinfo() checks
+
+	* crank FTP_VERSION from 1.5 to 1.6alpha1
+
+	* always ensure _PATH_BSHELL and _PATH_TMP are defined
+
+	* prototype inet_pton() if its missing
+
+	* don't bother trying to use if_indextoname() in ip6_sa2str()
+	  (fixes problems on MacOS X)
+
+	* in inet_pton(), pull in <arpa/nameser.h> for IN6ADDRSZ and INT16SZ,
+	  and define if missing
+
+Fri Apr 13 15:24:44 UTC 2001	lukem
+
+	* only include <arpa/nameser.h> if we have it
+
+	* update glob(3) to netbsd-current (20010329), adding support
+	  for GLOB_LIMIT and fixing various buffer overflows.
+
+	* update editline from NetBSD 20000915 -> NetBSD 20010413
+		- Enlarge editline buffers as needed to support arbitrary
+		  length lines.  This also addresses lib/9712 by Phil Nelson.
+		- consistently check for allocation failures and return -1,
+		  if we could not get more memory.
+		- add support for home and end keys.
+		- improve debugging support
+		- el_line_t: make 'limit' const
+
+Mon Nov 27 23:23:40 EST 2000	lukem
+
+	* merge ftp from NetBSD-current (20001127):
+		- implement "mreget"; as per "mget" but uses "reget" instead
+		  of "get"
+		- add -N netrc and $NETRC, as methods to select an alternative
+		  .netrc file
+		- cache local user name and home directory for further use
+		- in mget(), use docase() instead of a local version to do
+		  the case conversion.
+		- format string cleanups
+		- be more explicit that $ftp_proxy and $http_proxy are not
+		  supported for interactive sessions
+		- cope with 2553bis getnameinfo (always attach scope id)
+		  getnameinfo error check.
+		- use NI_MAXHOST with getnameinfo.  we can assume presence of
+		  getnameinfo.
+
+Tue Nov  7 00:16:23 EST 2000	lukem
+
+	* libukem/snprintf.c had a non-functional `%s' due to a
+	  function declaration mismatch.  problem found and fixed
+	  by Hubert Feyrer <hubert at feyrer.de>
+
+Wed Oct 11 14:06:19 EST 2000	lukem
+
+	* released version 1.5
+
+Tue Oct  3 10:22:36 EST 2000	lukem
+
+	* crank to version 1.5 beta6
+
+	* merge ftp from NetBSD-current (20001003)
+		- explicitly use SOCK_STREAM with socket() instead of
+		  res->ai_socktype, because it appears that linux with glibc
+		  doesn't set the latter correctly after one of getaddrinfo()
+		  or getnameinfo().
+		- clarify that $ftp_proxy only works for full URLs and can't
+		  be used for interactive connections.
+
+Mon Sep 25 21:52:12 EST 2000	lukem
+
+	* crank to version 1.5 beta5
+
+Sun Sep 24 13:31:19 EST 2000	lukem
+
+	* merge ftp from NetBSD-current (20000924)
+		- since everything else here uses ANSI C, we might as well
+		  replace __STRING() with the ANSI C stringization stuff...
+		- base64_encode should be static. picked up by hp/ux(!)
+		  compiler
+		- It appears that whilst Apache 1.3.9 incorrectly puts a
+		  trailing space after the chunksize (before the \r\n),
+		  Apache 1.3.11 puts *multiple* trailing spaces after the
+		  chunksize. I 'm fairly certain that this is contrary to
+		  RFC 2068 section 3.6, but whatever...
+		  Found by David Brownlee <abs at mono.org>
+		- always include <netdb.h>, not just when INET6 is defined.
+		  resolves PR [bin/10970] by Richard Earnshaw
+		  <rearnsha at cambridge.arm.com>>
+		- in progressmeter() perform the check for foregroundproc() a
+		  little earlier
+		- removed unused variable `items' in list_vertical()
+
+Sat Sep 23 15:43:34 EST 2000	lukem
+
+	* remove unused sverrno in warnx() and errx()
+
+	* remove unused h_error in getnameinfo()
+
+	* in getaddrinfo(), don't bother declaring in6_addrany[] and
+	  in6_loopback #ifndef INET6
+
+Thu Sep 21 11:26:35 EST 2000	lukem
+
+	* in getaddrinfo.c::str_isnumber(), use strtol() and check the
+	  result, instead of using strtoul() and not checking the result.
+
+	* define INADDRSZ if it's not found (e.g, HP/UX doesn't seem to have
+	  it in <arpa/nameser.h>)
+
+Wed Sep 20 09:23:59 EST 2000	lukem
+
+	* crank to version 1.5 beta4
+
+Mon Sep 18 18:19:54 EST 2000	lukem
+
+	* add AC_AIX test, which defines _ALL_SOURCE under AIX
+
+	* use ANSI # stringization instead of __STRING()
+
+	* define HAVE_RFC2553_NETDB if <netdb.h> defines AI_NUMERICHOST
+	  (et al) and has getaddrinfo(). (some systems only implement RFC2133)
+
+	* don't bother with AC_C_CONST as we depend upon ANSI C elsewhere
+
+	* when HAVE_RFC2553_NETDB isn't set, and we're #defining various EAI_,
+	  AI_, and NI_ items, #undef first incase a system partially implements
+	  these in <netdb.h>
+
+	* look for tgetent() in -ltinfo before -lncurses, because ncurses 5.0
+	  has been split up into multiple libraries.
+	  from Arkadiusz Miskiewicz <misiek at pld.org.pl>
+
+Fri Sep 15 01:09:10 EST 2000	lukem
+
+	* don't bother defining __P() or __STRING() based on whether
+	  __STDC__ is available or not, since these aren't used any more
+
+	* fix mkstemp() prototype
+
+	* declare getpass() if necessary
+
+	* we don't need the readline xxgdb hack in libedit...
+
+	* convert to ansi declarations
+
+	* use ansi prototypes instead of __P()
+
+	* merge in changes from makelist 1.4 -> 1.6:
+		- generate ansi prototypes instead of using __P().  noted by
+		  christos
+		- fix a couple of comments
+		- add -m option to makelist, which generates an mdoc table
+		  with the key bindings and their descriptions
+		- manually add the output of 'sh ./makelist -m vi.c ed.c
+		  common.c' to a new section in editrc(5) called
+		  `EDITOR COMMANDS'
+
+	* merge libedit from NetBSD-current (20000915)
+		* convert to new style guide, which includes:
+			- ansi prototypes & features (such as stdargs)
+			- 8 space indents
+		* history_def_set has a `const int' as a third arg, not an
+		  `int'.  picked up by the ultrix compiler, reported by
+		  simonb@ ...
+		* generate ansi prototypes instead of using __P().  noted by
+		  christos.  fix a couple of comments
+		* make xxgdb and a gdb linked with libedit's readline emulation
+		  work properly together.   xxgdb communicates with a gdb
+		  running on a pty that it sets to -echo,-onlcr prior to
+		  forking the gdb process.  GNU readline preserves the -echo
+		  setting while libedit was undoing it (setting the tty to a
+		  sane state and totally confusing xxgdb's parser).
+		  this diff simply disables libedit if both readline emulation
+		  and "stty -echo" are used/set.   that is enough to make
+		  xxgdb work once again, but (XXX) this is not how GNU readline
+		  handles stty -echo (it does not echo anything, but editing
+		  commands like ^A,^K, etc.  still work), so the readline
+		  emulation isn't perfect.
+
+Tue Aug 29 18:00:08 EST 2000	lukem
+
+	* don't bother testing for #if __STDC__; just assume we have it...
+
+Mon Aug 28 22:45:08 EST 2000	lukem
+
+	* refine tests for IPv6 #defines (EAI_, AI_, NI_, ...).
+	  should improve portability on systems which implement
+	  RFC 2133 but not RFC 2553.
+
+Wed Aug  9 02:12:51 EST 2000	lukem
+
+	* use #if __STDC__ instead of #ifdef __STDC__
+
+	* only test 'case NETDB_INTERNAL:' if it's defined
+
+	* fix support for --program-prefix et al
+
+	* only include <arpa/nameser.h> in the files that need it, because
+	  the DELETE define in some system's implementations causes name
+	  collisions in libedit.
+
+Mon Aug  7 08:17:37 EST 2000	lukem
+
+	* merge ftp from NetBSD-current (20000807)
+		* implement parseport(), which takes a string and attempts to
+		  convert it to a numeric port number
+		* use parseport() in parse_url() and hookup()
+		* don't try and lookup the port number using getaddrinfo(),
+		  as it's too hard to separate a failed host name lookup from
+		  a failed service name lookup.  this was causing lossage on
+		  systems that don't have `http' in services(5) (such as
+		  solaris), but only crept in when we started using
+		  getaddrinfo() unconditionally.
+
+Wed Aug  2 23:43:50 EST 2000	lukem
+
+	* crank to version 1.5 beta3
+
+	* define NO_LONG_LONG not NO_QUAD
+
+	* detect if struct sockaddr.sa_len exists (rather than relying upon
+	  #ifdef BSD4_4)
+
+	* detect if socklen_t exists, and if not, typedef as unsigned int
+
+	* detect if struct addrinfo exists, and if not declare it and #define
+	  associated EAI_, AI_, and NI_ defines.
+
+	* look for & replace: getaddrinfo(), getnameinfo(), inet_ntop(),
+	  inet_pton()
+	* look for gethostbyname2()
+
+	* don't bother looking for hstrerror() or inet_aton() anymore
+
+	* include <arpa/nameser.h> and <stddef.h>
+
+	* define USE_SELECT instead of __USE_SELECT
+
+	* always define HAVE_H_ERRNO
+
+	* add Brian Stark to THANKS, for lots of AIX porting feedback
+
+	* improve detection of sin_len for AIX (now part of sa_len test)
+
+	* add functions needed by recent ftp import:
+		getaddrinfo(), getnameinfo(), inet_ntop(), inet_pton()
+	  remove functions not needed anymore:
+		hstrerror(), inet_aton()
+
+	* use #if HAVE_ISSETUGID not #ifdef
+
+	* update from NetBSD-current (20000802):
+		- rename NO_QUAD to NO_LONG_LONG, QUAD* -> LL* and add ULL*
+		  (unsigned) equivalents. name change suggested by Klaus
+		  Klein <kjk at NetBSD.org>
+		- change defined(BSD4_4) || HAVE_SIN_LEN tests into
+		  HAVE_SOCKADDR_SA_LEN, and set the latter if BSD4_4 exists
+
+Mon Jul 31 10:59:10 EST 2000	lukem
+
+	* merge ftp from NetBSD-current (20000731)
+		- we can't just rename BSD4_4 -> HAVE_SIN_LEN, since bsd
+		  systems define BSD4_4; change tests to test for either
+		  defined(BSD4_4) or HAVE_SIN_LEN
+		- more KNF
+
+Sun Jul 30 16:55:09 EST 2000	lukem
+
+	* merge ftp from NetBSD-current (20000730):
+		- clean up NO_QUAD support: create helper #defines and use as
+		  appropriate:
+			#define         NOQUAD          ! NOQUAD
+			-------         ------          - ------
+			QUADF           "%ld"           "%lld"
+			QUADFP(x)       "%" x "ld"      "%" x "lld"
+			QUADT           long            long long
+			STRTOL(x,y,z)   strtol(x,y,z)   strtoll(x,y,z)
+		- always use getaddrinfo() and getnameinfo() instead of
+		  maintaining two code paths.
+		- rename __USE_SELECT to USE_SELECT
+		- rename BSD4_4 to HAVE_SIN_LEN
+		- replace union sockunion {} with struct sockinet {}, and
+		  modify the code accordingly. this is possibly more portable,
+		  as it doesn't rely upon the structure alignment within the
+		  union for our own stuff.
+
+Fri Jul 28 22:11:17 EST 2000	lukem
+
+	* merge ftp from NetBSD-current (20000728):
+		- no trailing , on last item (FEAT_max) in enum
+		- rename "opts" to "remopts", so people used to "o host"
+		  don't get bitten
+
+Wed Jul 26 18:59:19 EST 2000	lukem
+
+	* merge ftp from NetBSD-current (20000726):
+		- add support for FEAT and OPTS commands with `features' and
+		  `opts'.  (from RFC 2389).
+		- add support for MLST & MLSD (machine parseble listings)
+		  with 'mlst', 'mlsd' and 'pmlsd' (mlsd |$PAGER) commands.
+		  (from draft-ietf-ftpext-mlst-11)
+		- rename remotesyst() to getremoteinfo(), and modify to parse
+		  the result from FEAT (if supported), and take into account
+		  the support for the various extensions such as MDTM, SIZE,
+		  REST (STREAM), MLSD, and FEAT/OPTS.
+		- put each feature into one of the following categories:
+			- known to work (explicit FEAT)
+			- unknown but assume works until explicit failure,
+			  when it's then tagged as `known not to work'.
+			- known not to work (FEAT succeeded but didn't return
+			  anything, or was unknown and then explicit failure)
+		  assign results into features[] matrix.
+		- add support to getreply() so that an optional callback will
+		  be called for each line received from the server except for
+		  the first and last.  this is used in FEAT (and MLST) parsing.
+		- modify various commands to check if REST (STREAM), MDTM and
+		  SIZE are explicitly or implicitly supported before using.
+		- fix `syst' when verbose is off.
+		- minor knf (indent goto labels by one space, etc).
+		- simply various command usage handlers by assuming that
+		  argv != NULL except for quit() and disconnect().
+		- errx?/warnx? audit.  do not pass variable alone, use %s.
+
+	* check for issetugid() and don't use in libedit if it doesn't exist.
+
+	* merge libedit from NetBSD-current (20000726):
+		* Only look in home directory for .editrc.  (Discussed
+		  with Christos.)
+
+	* in glob.c #undef TILDE before redefining, because some AIX systems
+	  #define TILDE in <sys/ioctl.h>
+
+Mon Jul 10 00:28:51 EST 2000	lukem
+
+	* released lukemftp 1.4
+
+Thu Jun 15 23:28:49 EST 2000	lukem
+
+	* merge ftp from NetBSD-current (20000615):
+		* migrate the SYST parsing from setpeer() into a separate
+		  remotesyst().  call remotesyst() only when login has been
+		  successful some servers don't let you run SYST until you've
+		  successfully logged in.
+		* in fetch_ftp(), always call setpeer() with autologin
+		  disabled, and use the following ftp_login() to DTRT.  this
+		  prevents ftp from trying to login a second time if the
+		  first autologin fails when connecting to a remote site
+		  anonymously using autofetch.
+		* reset unix_proxy and unix_server in cleanuppeer()
+		* missed a function conversion in the KNF sweep...
+
+Mon Jun 12 01:16:12 EST 2000	lukem
+
+	* change lukemftp.h to check !HAVE_STRDUP instead of !HAVE_STRSUP.
+	  fixes compile problem on systems which have strdup() as a macro.
+
+	* merge ftp from NetBSD-current (20000612):
+		from itojun: better fix for previous (doesn't need
+		in_addr_t or u_int32_t)
+
+Sun Jun 11 12:19:52 EST 2000	lukem
+
+	* merge ftp from NetBSD-current (20000611):
+		portability fixes for lukemftp:
+		* initconn(): use in_addr_t instead of u_int32_t when
+		  manipulating IPv6 addresses (and assume anything with ipv6
+		  has in_addr_t; if not, i'll add an autoconf test for it)
+		* ai_unmapped(): not all systems have sin_len; so only set
+		  #ifdef BSD4_4
+		* fix some lint
+
+Mon Jun  5 21:10:31 EST 2000	lukem
+
+	* released lukemftp 1.3
+
+Mon Jun  5 19:53:49 EST 2000	lukem
+
+	* convert various support files to ANSI C
+
+	* look for strtoll() instead of strtoq()
+
+	* update COPYRIGHT, THANKS, NEWS
+
+	* merge ftp from NetBSD-current (20000605):
+		- fix ai_unmapped() to be a no-op in the !def INET6 case
+		- display `(-INET6)' at the end of the version string if
+		  !def INET6
+		- clarify in the man page that IPv6 support may not be present
+		  (for lukemftp :)
+
+	* ensure <vis.h> has VIS_WHITE et al
+
+Sun Jun  4 18:00:07 EST 2000	lukem
+
+	* merge ftp from NetBSD-current (20000604):
+		- Change `ls' to use the `LIST' and not `NLST' FTP protocol
+		  command.  Now that after many years on not caring we find
+		  certain popular ftp servers are starting to obey RFC959 to
+		  the letter of the law and will only return a list of
+		  filenames (not directories or other filetypes) in the
+		  output of `NLST', then `LIST' is more useful in this case.
+		  (Note that the aforementioned pedanticness means that
+		  filename completion isn't as useful as it could be...)
+		  Fixes [bin/8937] by David A. Gatwood
+		  <dgatwood at deepspace.mklinux.org>
+		- convert to ANSI KNF
+		- Add support for `fget localfile', which reads a list of
+		  filenames to retrieve from localfile.  Based on work by
+		  Darren Reed.
+		- Update copyright dates.
+		- s/strtoq/strtoll/ (the latter is standardised)
+		- Add support for 'ftp -u url file ...', to upload a list of
+		  files to given url.  Mostly based on [bin/10019] by Scott
+		  Aaron Bamford <sab at ansic.net>
+		- convert IPv4 mapped address (::ffff:10.1.1.1) into real IPv4
+		  address before touching it.  IPv4 mapped address complicates
+		  too many things in FTP protocol handling.
+		- do not pass scoped IPv6 address notation on Host: directive,
+		  since scope identifier is local to the originating node.
+		  do not allow scoped IPv6 address notation in URL, if it is
+		  via proxy.
+		- fixes from cgd:
+		  * sanity check a length (otherwise certain bogus responses
+		    can crash ftp)
+		  * allow a transfer encoding type of `binary'; certain
+		    firewall vendors return this bogus type...
+		- make debugging output unambiguous on IPv6 numeric addrs
+		  (don't use host:port)
+		- http://[::1]:8080/ is legal.
+		- send Host: directive with RFC2732 bracket notation for IPv6
+		  numeric, otherwise "host:port" is ambiguous to servers
+		  (clarification will be submitted as update to RFC2732).
+		- only use getaddrinfo() et al if both NI_NUMERICHOST *and*
+		  INET6 are defined...  (allows --disable-ipv6 in lukemftp's
+		  configure script to disable this as well, which is good for
+		  testing when it appears getaddrinfo() is borken)
+		- updated comment on IPv4 mapped address.  sync with kame.
+		- Fix examples on using pipes in local filenames.  AFAICT,
+		  ftp has always required `dir . |more' not as `dir |more'
+		  treats `|more' as the remote filename. Resolves [bin/9922]
+		  by Geoff Wing <mason at primenet.com.au>
+		- ftp(1): treats IPv4 mapped destination as IPv4 peer, not
+		  native IPv6 peer.  this does not support network with SIIT
+		  translator.
+		- inhibit too-noisy message for scoped address data transfer
+		  (will be enabled in "debug" mode).
+		- only use IPTOS_ setsockopt()s if they're defined (e.g, SunOS
+		  doesn't).  from Havard.Eidnes at runit.sintef.no
+		- allow IPv6 extended numeric address in host part.
+		  (draft-ietf-ipngwg-scopedaddr-format-01.txt). fixes PR 9616.
+
+	* merge libedit from NetBSD-current (20000604):
+		- use strtol() (instead of atoi()) for sane error detection
+
+Wed May 31 19:24:53 EST 2000	lukem
+
+	* merge libedit from NetBSD-current (20000531):
+		- Fix refresh glitches when using auto-margin.
+		- Don't dump core on empty .editrc files.
+		- el_insertstr takes a "const char *" not "char *" now as it
+		  doesn't modify the argument.
+
+Thu Feb  3 20:19:40 EST 2000	lukem
+
+	* released lukemftp 1.2
+
+Tue Feb  1 09:47:51 EST 2000	lukem
+
+	* add --enable-ipv6 and --disable-ipv6 to configure
+
+	* modify libedit/sig.? to use sigfunc instead of sig_t, and
+	  deprecate autoconf tests for retsigtype and sig_t.
+	  This fixes portability problems with Digital UNIX 5.0.
+
+	* merge ftp from NetBSD-current (20000201):
+		- define private type `sigfunc' as
+			typedef void (*sigfunc) __P((int));
+		  and replace use of sig_t and void (*)(int).
+		  certain other OSes define sig_t differently to that (they
+		  add extra arguments), and it causes problems due to
+		  function mismatches, etc...
+
+Wed Jan 26 22:54:38 EST 2000	lukem
+
+	* search for tgetent() in -ltermcap then -lcurses and -lncurses
+
+	* merge ftp from NetBSD-current (20000126):
+		- roll back to using sscanf() instead of strptime() to parse
+		  `yyyymmddhhmmss' strings, since the latter technically can't
+		  parse dates without non alphanumerics between the elements
+		  (even though NetBSD's strptime() copes).
+
+Tue Jan 25 19:09:37 EST 2000	lukem
+
+	* merge ftp from NetBSD-current (20000125):
+		- complete_ambiguous(): be consistent about completing
+		  unambiguous matches; if the word is already complete then
+		  return CC_REFRESH so that the higher layer may append a
+		  suffix if necessary. Fix from Launey Thomas <ljt at alum.mit.edu>
+		- change references from draft-ietf-ipngwg-url-literal-01.txt
+		  to RFC2732
+		- work around bug in apache 1.3.9 which incorrectly puts a
+		  trailing space after the chunksize.  noted by Jun-ichiro
+		  itojun Hagino <itojun at itojun.org> in [bin/9096]
+		- work around lame ftpd's that don't return a correct post-Y2K
+		  date in the output of `MDTM'.  obviously the programmer of
+		  aforementioned lame ftpd's did something like
+			"19%02d", tm->tm_year
+		  instead of
+			"%04d", tm->tm_year + TM_YEAR_BASE
+		  fixes [bin/9289] by jbernard at mines.edu
+
+	* merge libedit from NetBSD-current (20000125):
+		- PR/9244: Kevin Schoedel: libedit dumps bindings
+		  inconsistently
+		- PR/9243: Kevin Schoedel: libedit ignores repeat count
+		- Add support for automatic and magic margins (from tcsh)
+		  This makes the rightmost column usable on all programs
+		  that use editline.
+
+Tue Dec 21 08:59:22 EST 1999	lukem
+
+	* update INSTALL notes for some systems
+
+	* if sl_init() exists, check return value of sl_add() is int and
+	  compile in a replacement copy if it's not the case
+
+	* don't look for <stringlist.h> - always use local prototypes; older
+	  NetBSD systems may have conflicting prototypes
+
+Mon Dec 20 11:21:28 EST 1999	lukem
+
+	* merge ftp from NetBSD-current (19991220):
+	- Move version from ftp_var.h to version.h
+	- Fix chunked support; probably broke after rate limiting was added.
+	  Problem noticed/debugging assisted by giles lean
+	  <giles at nemeton.com.au>.
+	- remove unnecessary freeaddrinfo(res), since res0 was changed to be
+	  freed earlier in itojun's last commit. fixes [bin/8948].
+	- remove `const char *reason'; it was being assigned but not used.
+	- fix memory leak in fetch_url (no freeaddrinfo was there).
+	  sync with recent KAME.
+	- separate out the main `data pump' loop into two: one that supports
+	  rate limiting and one that doesn't. simplifies the code, and speeds
+	  up the latter case a bit, at the expense of duplicating a few
+	  lines...
+
+Sun Nov 28 18:20:41 EST 1999	lukem
+
+	* merge ftp from NetBSD-current (19991128):
+	- implement xsl_init() and  xsl_add(); error checking forms of
+	  sl_{init,add}()
+	- fix bug where the second press of <TAB> on an empty word (i.e, list
+	  all options) may have resulted in an strncmp() against NULL.
+	  (detected by _DIAGASSERT())
+	- in cleanuppeer(), reset username to NULL after free()ing it.
+	  fixes [bin/8870] by Wolfgang Rupprecht <wolfgang at wsrcc.com>
+	- complete_remote(): use remglob("", ...) instead of remglob(".", ...),
+	  for listings of the current working directory; some ftp servers don't
+	  like `NLST .'.
+	  [noted by Giles Lean <giles at nemeton.com.au>]
+	- recvrequest(): treat remote=="" as remote==NULL when calling
+	  command().  (to support the above change)
+	- support `[user@]' in `[user@]host' and `[user@]host[:][path]'.
+	  [based on idea (and initial code) from David Maxwell <david at fundy.ca>]
+	- `idle' may be invoked without any args
+	- reformat some comments
+	- reformat usage string in program and man page
+	- call updateremotepwd() after successful login, not after successful
+	  connect
+	- always call setsockopt(, IPPROTO_IP, IP_TOS, ) (et al); using #if
+	  defined(IPPROTO_IP) doesn't work on certain foreign systems where
+	  enums instead of #defines are used...
+	  [noted by Matthias Pfaller <leo at dachau.marco.de>]
+
+Mon Nov 15 23:01:58 EST 1999	lukem
+
+	* released lukemftp 1.1
+
+Mon Nov 15 09:07:01 EST 1999	lukem
+
+	* merge libedit from NetBSD-current (19991115):
+		- instead of using a private coord_t global variable to store
+		  the size of the rprompt, use the previously unused coord_t
+		  el->el_rprompt.p_pos
+
+Sat Nov 13 14:42:22 EST 1999	lukem
+
+	* support caching of results in AC_MSG_TRY_{COMPILE,LINK}
+	  autoconf tests
+
+	* add NEWS file
+
+	* clarify copyright statement in COPYING
+
+	* merge ftp from NetBSD-current (19991113):
+		- implement `set rprompt'; right side version of `set prompt'.
+		  depends on EL_RPROMPT support i added to editline(3).
+		- allow $FTPPROMPT and $FTPRPROMPT to override defaults for
+		  the relevant prompts
+		- move `%' formatting code from prompt() to expandbuf().
+		- implement `%.' and `%c', similar to the same % codes in
+		  tcsh(1) (functionality I added to tcsh nearly 6 years ago),
+		  except that `%.' always does `...trailing' and `%c' always
+		  does `/<x>trailing'.
+		- unknown `%foo' codes get printed as `%foo'
+		- implement updateremotepwd(); update the global variable
+		  `remotepwd' to contain the remote working directory.
+		- add `set prompt', a user configurable prompt. (defaults to
+		  `ftp> ').  the following escape characters a la tcsh(1) are
+		  supported: %/, %m, %M, and %n.
+		- add global var `username'; used by prompt code
+		- fix a couple of minor memory leaks
+		- bump version
+		- prevent minor memory leak (unnecessary strdup)
+		- implement restarting file:/// non-proxied http:// URLs
+		  (with -R).
+		- fix a semicolono which stopped file:/// from working
+		- split the version string into product and version
+		- be consistent about reporting the version between:
+			+ status command
+			+ about:version URL fetch
+			+ User-agent sent in http requests
+		- hookup(): when using getservbyname() (when getaddrinfo()
+		  isn't available), if the provided port is a valid number
+		  use that rather than trying to do getservbyname() against
+		  it. fixes a problem on foreign systems noted by Chuck
+		  Silvers <chuq at chuq.com>
+		- support `about:version'. also display the version in the
+		  output of `status'.
+
+	* merge libedit from NetBSD-current (19991113):
+		- implement printing a right-side prompt. code derived from
+		  similar work I wrote for tcsh(1) three years ago.
+		- implement EL_RPROMPT, which allows a setting/getting of a
+		  function which returns a string to be used as the
+		  right-side prompt.
+
+	* replace manually managed config.h.in with acconfig.h and use
+	  autoheader to generate the former.
+
+	* add missing entry for `#undef write' in acconfig.h (for SOCKS)
+
+	* configure.in:
+		- use `LL' suffix on long long constant used to test
+		  snprintf("%lld")
+		- test for EL_RPROMPT instead of EL_EDITMODE, since the
+		  former is is a newer required feature
+
+	* in makelist, set LC_ALL="C", in case the locale confuses awk.
+	  problem noted by Peter Seebach <seebs at plethora.net>
+
+Wed Oct 27 07:00:00 UTC 1999	lukem
+
+	* released 1.0
+
+	* removed libedit/TEST/test.c; no need to distribute it
+
+Mon Oct 25 21:59:54 EST 1999	lukem
+
+	* released 1.0b7
+
+	* put VERSION string into lukemftp.h, and display with the `status'
+	  command
+
+Mon Oct 25 11:36:59 EST 1999	lukem
+
+	* merge ftp from NetBSD-current (19991025):
+	- fix up confirm() (broke `a' and `p' in last commit)
+	- simplify main loop (don't need `top' variable any more)
+	- use a struct sockaddr_in6.sin6_addr for the result from inet_pton(),
+	  rather than u_char buf[16]
+	- add a few more comments
+
+	new features:
+	- add `usage'; displays the usage of a command.
+	  implemented by calling the c_handler() with argc = 0, argv =
+	  "funcname".
+	- add `passive auto'; does the same as $FTPMODE=auto.
+	- add `set [option value]'; display all options, or set an option to
+	  a value.
+	- add `unset option'; unset an option.
+	- add getoptionvalue() to retrieve an option's value, and replace a few
+	  global variables with calls to this.
+	- implement cleanuppeer(), which resets various bits of state back to
+	  `disconnected'. call in disconnect() and lostpeer().
+	- support completing on `options'.
+	- improve recovery after a SIGINT may have closed the connection.
+	  XXX: there's still a couple to fix
+
+	other stuff:
+	- various consistency fixes in the man page.
+	- ensure that the command usage strings in the code and man page
+	  match reality.
+	- mput/mget: check that the connection still exists before each xfer.
+	- minor cosmetic changes in confirm().
+	- set code correctly in sizecmd() and modtime()
+	- don't need \n in err() strings.
+	- change lostpeer to take an argument (rather than casting
+	  (sig_t)lostpeer in signal handlers)
+	- knf and whitespace police.
+
+Sun Oct 24 17:02:59 EST 1999	lukem
+
+	* merge libedit from NetBSD-current (19991024):
+		- don't assume locales are not working - it may not be
+		  the case
+		- re_refresh(): cast the character passed to re_addc() to
+		  unsigned char,  so we don't end up calling isprint() with
+		  negative value when chars are signed and character value
+		  is >= 128
+		- Fix pointer arithmatic (caused problems on LP64, including
+		  ftp dumping core when `edit' was turned off then on).
+		  Problem solved by David Huggins-Daines <dhd at eradicator.org>
+
+Tue Oct 12 18:05:21 EST 1999	lukem
+
+	* install man page from ${srcdir} not from .
+
+Tue Oct 12 17:00:41 EST 1999	lukem
+
+	* released 1.0b6
+
+	* merge from NetBSD-current (19991012):
+	  a few user interface and cosmetic tweaks:
+		- confirm(): move from util.c to cmds.c. display mnemonic
+		  string in its prompt. add support for `q' (terminate
+		  current xfer), `?' (show help list)
+		- in various signal handlers, output a linefeed only if
+		  fromatty.
+		- if fgets(stdin) returned NULL (i.e, EOF), clearerr(stdin)
+		  because you don't want future fgets to fail. this is not
+		  done for the fgets() in the main command loop, since ftp
+		  will quit at that point.
+		- unless ftp is invoked with -a, don't retain the anonftp
+		  setting between hosts (`ftp somehost:' sets anonftp, but
+		  you don't want that to `stick' if you close that connection
+		  and open a new one).
+
+Mon Oct 11 23:06:38 EST 1999	lukem
+
+	* check for working const
+
+	* reorganise addition of -lukem to LIBS (was being added twice)
+
+	* merge from netbsd-current:
+		- use sigjmp_buf instead of jmp_buf for sigsetjmp() buffer
+
+	* libedit: don't bother generating & compiling editline.c, since
+	  its component parts are compiled anyway.
+
+Sun Oct 10 12:08:39 EST 1999	lukem
+
+	* released 1.0b5
+
+	* in libedit, use xsignal_restart() (from src/util.c) instead of
+	  signal(); the isn't guaranteed to work on some foreign systems
+	  (e.g, IRIX) if sigaction() is used in the same program.
+
+	* merge from netbsd-current:
+		- use sigsetjmp()/siglongjump() instead of setjmp()/longjmp();
+		  the latter don't save the signal mask on some foreign systems.
+		- ensure signal handlers don't use stdio and do reset errno
+		  if they don't exit with siglongjmp()
+		- use a common SIGINT handler for {send,recv}request()
+		- allow a second SIGINT during the "xfer aborted. waiting for
+		  remote to finish abort." stage. if this occurs, just call
+		  lostpeer() to close the connection.  whilst this might be
+		  considered brutal, it's also extremely handy if you're
+		  impatient or there's lossage at the remote end.
+
+	* add preformatted manual page
+
+	* fix --enable-editline
+
+Wed Oct  6 10:19:00 EST 1999	lukem
+
+	* released 1.0b4
+
+	* don't defining SIGINFO to SIGQUIT if the former doesn't exist; the
+	  code now supports both as a method of getting the transfer stats
+
+	* rototill signal handling in the actual data xfer routines, and
+	  specifically set SIGQUIT to psummary in each one, to override
+	  editline's handler
+
+Tue Oct  5 23:48:29 EST 1999	lukem
+
+	* factor out SIGINFO setting into a handler that is always active
+	  (but only prints out info if bytes > 0). only set the handler if
+	  SIGINFO is defined
+
+	* hijack SIGQUIT to be the same as SIGINFO
+
+	* in {recv,send}request(), factor a lot of duplicated code out into
+	  a `cleanup' section at the end
+
+	* rework shell() a bit
+
+	* enhancments from Marc Horowitz <marc at mit.edu> to improve
+	  connection timeouts:
+		- implement xsignal_restart(), which only sets the SA_RESTART
+		  flag if specifically requested
+		- xsignal() is now a wrapper to xsignal_restart(). INFO,
+		  USR1, USR2 and WINCH are restartable, ALRM, INT, PIPE and
+		  QUIT are not
+		- improve getreply()'s timeout code to take advantage of the
+		  above
+
+	* improve wording of how globbing works for `classic' URLs (host:path)
+	  suggested by John Refling <johnr at imageworks.com> in relation to PRs
+	  [bin/8519] and [bin/8520]
+
+	* always compile in the `edit' command even if NO_EDITCOMPLETE defined
+	  it's just a no-op in the latter case, which is more consistent to
+	  the users
+
+	* always compile in about: support (i.e, remove NO_ABOUT).  i'm
+	  entitled to some vanity in this program...
+
+	* update copyrights
+
+Mon Oct  4 10:57:41 EST 1999	lukem
+
+	* Invoke ar with `cr' not `cq'
+
+	* Use AC_PROG_RANLIB to find ranlib, and use it on the libraries
+
+	* Remove `makelist' from dependency list for libedit files; re-running
+	  configure shouldn't result in rebuilding libedit
+
+	* Add support for --{en,dis}able-editcomplete (defaults to enabled),
+	  which prevents libedit support from being compiled in.
+	  From Chris G. Demetriou <cgd at NetBSD.org>
+
+Sun Oct  3 16:49:01 EST 1999	lukem
+
+	* touch up the README
+
+	* add COPYING, INSTALL, THANKS
+
+	* whitespace consistency
+
+	* in config.h, replace NO_QUAD with HAVE_QUAD_SUPPORT, and in
+	  lukemftp.h define the former if the latter is non zero
+
+	* change test against GETPGRP_VOID from #ifdef to #if
+
+	* snprintf(): in the truncation case, ensure that the length
+	  returned is the actual length, not the needed length
+
+Sat Oct  2 00:41:34 EST 1999	lukem
+
+	* fix more lossage with $(srcdir) / $(VPATH) stuff; seems to work now
+	  when configured in a separate directory
+
+	* actually test the correct variable when determining whether to run
+	  AC_FUNC_GETPGRP
+
+Fri Oct  1 19:32:22 EST 1999	lukem
+
+	* released 1.0b3
+
+	* use AC_PROG_MAKE_SET
+
+	* determine setting of NO_QUAD with configure not lukemftp.h
+
+	* if have long long and have snprintf, test that snprintf
+	  supports %lld. if it doesn't use private version
+
+	* change strtoq from returning off_t to returning long long
+
+	* updates from NetBSD mainline:
+		- only try epsv once per connection (i.e, don't bother again
+		  if it fails)
+		- improve description of rate command
+		- fix up global vars; they're now externed in ftp_var.h
+		  except when main.c includes it
+		- remove "pathnames.h"
+
+Fri Oct  1 10:08:43 EST 1999	lukem
+
+	* updates from NetBSD mainline:
+		- fix determining of homedir
+		- parse_url(): fix checking of portnum
+		- move kame copyrights after bsd/tnfi ones
+
+	* released 1.0b2
+
+	* add %lld and %qd support to snprintf() for displaying long long's
+
+	* support VPATH and srcdir
+
+Thu Sep 30 17:19:35 EST 1999	lukem
+
+	* released 1.0b1
+
+	* fix from NetBSD mainline: in empty() FD_ZERO the correct variable
+
+Wed Sep 29 23:34:33 EST 1999	lukem
+
+	* major rework; reimport code from NetBSD-current 1999/09/29 into
+	  separate subdirectories and build from there. organisation is now:
+		libedit		replacement libedit
+		libukem		replacements for missing functions
+		src		main ftp source
+
+Mon Sep 27 00:43:12 EST 1999	lukem
+
+	* released 1.0 a6
+
+Sun Sep 26 17:17:05 EST 1999	lukem
+
+	* released 1.0 a5
+
+Sat Sep 25 00:58:28 EST 1999	lukem
+
+	* released 1.0 a4
+
+Fri Sep 24 17:07:07 EST 1999	lukem
+
+	* released 1.0 a3
+
+Fri Sep 24 16:18:29 EST 1999	lukem
+
+	* released 1.0 a2
+
+Tue Sep 21 11:38:49 EST 1999	lukem
+
+	* import usr.src/bin/ftp and usr.src/lib/libedit sources from NetBSD

Added: vendor/NetBSD/tnftp/20100108/INSTALL
===================================================================
--- vendor/NetBSD/tnftp/20100108/INSTALL	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/INSTALL	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,60 @@
+INSTALLATION INTRODUCTION
+-------------------------
+
+This file describes how to compile and install tnftp on your system.
+
+	============================================
+	=					   =
+	=  NOTE: You will need an ANSI C compiler. =
+	=					   =
+	============================================
+
+
+For most systems, execute the following to compile and install tnftp:
+	./configure
+	make
+	make install
+
+A preformatted manual page (src/ftp.cat1) is also installed.
+If you wish to install the source (src/ftp.1), ensure that your system
+has up-to-date mandoc macros, such as those that are shipped with groff.
+
+
+CONFIGURATION OPTIONS
+---------------------
+
+tnftp is configured using an `autoconf' generated `configure'
+script.  `configure' supports the following options:
+
+* The standard `autoconf configure' options, including:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [/usr/local]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+                          BSD or GNU make may be required for this to work.
+
+* Specific options:
+  --enable-editcomplete   Turn on command line editing and completion.
+                          (default: enabled)
+  --enable-ipv6           Enable IPv6 support (if your OS supports it).
+                          (default: enabled)
+  --disable-largefile     omit support for large files
+  --with-socks            enable support for (Dante) SOCKS5 proxy
+
+The following environment variables can be set to override various
+compiler related settings.
+  CC=compiler		specify name of the C compiler (default: gcc or cc)
+  CFLAGS=flags		specify flags to C compiler (default: -O -g or just -O)
+  LDFLAGS=flags		specify flags to linker (default: none)
+
+This can be achieved with:
+	env CC="compiler" CFLAGS="flags" LDFLAGS="flags" ./configure
+
+
+	============================================
+	=					   =
+	=  NOTE: You will need an ANSI C compiler. =
+	=					   =
+	============================================
+

Added: vendor/NetBSD/tnftp/20100108/Makefile.am
===================================================================
--- vendor/NetBSD/tnftp/20100108/Makefile.am	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/Makefile.am	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,13 @@
+## $NetBSD: Makefile.am,v 1.2 2010/01/04 06:24:58 lukem Exp $
+
+SUBDIRS = libnetbsd
+
+if USE_LIBEDIT
+SUBDIRS += libedit
+endif
+
+SUBDIRS += src
+
+EXTRA_DIST = \
+	todo \
+	tnftp.h

Added: vendor/NetBSD/tnftp/20100108/Makefile.in
===================================================================
--- vendor/NetBSD/tnftp/20100108/Makefile.in	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/Makefile.in	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,726 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+ at USE_LIBEDIT_TRUE@am__append_1 = libedit
+subdir = .
+DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
+	$(srcdir)/Makefile.in $(srcdir)/tnftp_config.h.in \
+	$(top_srcdir)/configure COPYING ChangeLog INSTALL NEWS THANKS \
+	buildaux/config.guess buildaux/config.sub buildaux/depcomp \
+	buildaux/install-sh buildaux/ltmain.sh buildaux/missing
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = tnftp_config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN   " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+	html-recursive info-recursive install-data-recursive \
+	install-dvi-recursive install-exec-recursive \
+	install-html-recursive install-info-recursive \
+	install-pdf-recursive install-ps-recursive install-recursive \
+	installcheck-recursive installdirs-recursive pdf-recursive \
+	ps-recursive uninstall-recursive
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+	$(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+	distdir dist dist-all distcheck
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = libnetbsd libedit src
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+  { test ! -d "$(distdir)" \
+    || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+         && rm -fr "$(distdir)"; }; }
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NMEDIT = @NMEDIT@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = libnetbsd $(am__append_1) src
+EXTRA_DIST = \
+	todo \
+	tnftp.h
+
+all: tnftp_config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+am--refresh:
+	@:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+	      $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    echo ' $(SHELL) ./config.status'; \
+	    $(SHELL) ./config.status;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	$(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+tnftp_config.h: stamp-h1
+	@if test ! -f $@; then \
+	  rm -f stamp-h1; \
+	  $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+	else :; fi
+
+stamp-h1: $(srcdir)/tnftp_config.h.in $(top_builddir)/config.status
+	@rm -f stamp-h1
+	cd $(top_builddir) && $(SHELL) ./config.status tnftp_config.h
+$(srcdir)/tnftp_config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 
+	($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+	rm -f stamp-h1
+	touch $@
+
+distclean-hdr:
+	-rm -f tnftp_config.h stamp-h1
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool config.lt
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+	@failcom='exit 1'; \
+	for f in x $$MAKEFLAGS; do \
+	  case $$f in \
+	    *=* | --[!k]*);; \
+	    *k*) failcom='fail=yes';; \
+	  esac; \
+	done; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+	@failcom='exit 1'; \
+	for f in x $$MAKEFLAGS; do \
+	  case $$f in \
+	    *=* | --[!k]*);; \
+	    *k*) failcom='fail=yes';; \
+	  esac; \
+	done; \
+	dot_seen=no; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	rev=''; for subdir in $$list; do \
+	  if test "$$subdir" = "."; then :; else \
+	    rev="$$subdir $$rev"; \
+	  fi; \
+	done; \
+	rev="$$rev ."; \
+	target=`echo $@ | sed s/-recursive//`; \
+	for subdir in $$rev; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done && test -z "$$fail"
+tags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+	done
+ctags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) tnftp_config.h.in $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	list='$(SOURCES) $(HEADERS) tnftp_config.h.in $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) tnftp_config.h.in $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS) tnftp_config.h.in $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	$(am__remove_distdir)
+	test -d "$(distdir)" || mkdir "$(distdir)"
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test -d "$(distdir)/$$subdir" \
+	    || $(MKDIR_P) "$(distdir)/$$subdir" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+	-test -n "$(am__skip_mode_fix)" \
+	|| find "$(distdir)" -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
+	  ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+	|| chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	$(am__remove_distdir)
+
+dist-bzip2: distdir
+	tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+	$(am__remove_distdir)
+
+dist-lzma: distdir
+	tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
+	$(am__remove_distdir)
+
+dist-xz: distdir
+	tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz
+	$(am__remove_distdir)
+
+dist-tarZ: distdir
+	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+	$(am__remove_distdir)
+
+dist-shar: distdir
+	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+	$(am__remove_distdir)
+
+dist-zip: distdir
+	-rm -f $(distdir).zip
+	zip -rq $(distdir).zip $(distdir)
+	$(am__remove_distdir)
+
+dist dist-all: distdir
+	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	$(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	case '$(DIST_ARCHIVES)' in \
+	*.tar.gz*) \
+	  GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+	*.tar.bz2*) \
+	  bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+	*.tar.lzma*) \
+	  unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\
+	*.tar.xz*) \
+	  xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+	*.tar.Z*) \
+	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+	*.shar.gz*) \
+	  GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
+	*.zip*) \
+	  unzip $(distdir).zip ;;\
+	esac
+	chmod -R a-w $(distdir); chmod a+w $(distdir)
+	mkdir $(distdir)/_build
+	mkdir $(distdir)/_inst
+	chmod a-w $(distdir)
+	test -d $(distdir)/_build || exit 0; \
+	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+	  && am__cwd=`pwd` \
+	  && $(am__cd) $(distdir)/_build \
+	  && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+	  && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+	        distuninstallcheck \
+	  && chmod -R a-w "$$dc_install_base" \
+	  && ({ \
+	       (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+	            distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+	      } || { rm -rf "$$dc_destdir"; exit 1; }) \
+	  && rm -rf "$$dc_destdir" \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist \
+	  && rm -rf $(DIST_ARCHIVES) \
+	  && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+	  && cd "$$am__cwd" \
+	  || exit 1
+	$(am__remove_distdir)
+	@(echo "$(distdir) archives ready for distribution: "; \
+	  list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+	  sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+	@$(am__cd) '$(distuninstallcheck_dir)' \
+	&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+	   || { echo "ERROR: files left after uninstall:" ; \
+	        if test -n "$(DESTDIR)"; then \
+	          echo "  (check DESTDIR support)"; \
+	        fi ; \
+	        $(distuninstallcheck_listfiles) ; \
+	        exit 1; } >&2
+distcleancheck: distclean
+	@if test '$(srcdir)' = . ; then \
+	  echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+	  exit 1 ; \
+	fi
+	@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+	  || { echo "ERROR: files left in build directory after distclean:" ; \
+	       $(distcleancheck_listfiles) ; \
+	       exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile tnftp_config.h
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-hdr \
+	distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf $(top_srcdir)/autom4te.cache
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \
+	ctags-recursive install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+	all all-am am--refresh check check-am clean clean-generic \
+	clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \
+	dist-gzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \
+	distcheck distclean distclean-generic distclean-hdr \
+	distclean-libtool distclean-tags distcleancheck distdir \
+	distuninstallcheck dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	installdirs-am maintainer-clean maintainer-clean-generic \
+	mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+	ps ps-am tags tags-recursive uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: vendor/NetBSD/tnftp/20100108/NEWS
===================================================================
--- vendor/NetBSD/tnftp/20100108/NEWS	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/NEWS	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,36 @@
+This is tnftp version 20091122.
+
+Changes in tnftp from 20090606 to 20091122:
+
+	Portability fixes.
+
+Changes in tnftp from 20090520 to 20090606:
+
+	Portability fixes.
+
+Changes in tnftp from 20070806 to 20090520:
+
+	Fix intermittent "Alarm clock" error.
+
+	Add epsv6 and epsv to disable extended passive mode for IPv6 or
+	both IPv4 and IPv6 respectively.
+
+	Improve parsing of HTTP chunked transfers per RFC2616.
+
+	Use the service name to getaddrinfo() (along with the host name),
+	so that features such as DNS Service Discovery will work.
+
+	Fix various compiler warnings.
+
+
+Changes in tnftp from 20050625 to 20070806:
+
+	Implement '-s srcaddr' to set the local IP address for
+	all connections.
+
+	Support '-q quittime' when waiting for server replies.
+
+	Use IEC 60027-2 "KiB", "MiB" (etc) instead of "KB", "MB", ...
+
+	Portability fixes, including for FreeBSD, Mac OS X, and Solaris.
+

Added: vendor/NetBSD/tnftp/20100108/README
===================================================================
--- vendor/NetBSD/tnftp/20100108/README	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/README	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,68 @@
+WHAT IS TNFTP?
+--------------
+
+`tnftp' is a `port' of the NetBSD FTP client to other systems.
+See http://www.NetBSD.org/ for more details about NetBSD.
+
+tnftp was formerly known as `lukemftp'
+It was renamed to `tnftp' by Luke Mewburn in February 2003.
+
+The enhancements over the standard ftp client in 4.4BSD (and
+derivatives) include:
+	* command-line editing within ftp
+	* command-line fetching of URLS, including support for:
+	    - http proxies (see $http_proxy, $ftp_proxy)
+	    - authentication
+	* configurable prompt
+	* context sensitive command and filename completion
+	* dynamic progress bar
+	* feature negotiation extensions from RFC 2389
+	  (see `feat' and `remopts')
+	* extensions to ftp from the IETF ftpext working group
+	  (see `mlsd' and `mlst')
+	* IPv6 support (from the WIDE project)
+	* modification time preservation
+	* paging of local and remote files, and of directory listings
+	  (see `lpage', `page', `pdir')
+	* passive mode support, with fallback to active mode
+	* retrieval of filenames listed in a given file (see `fget')
+	* `set option' override of ftp environment variables
+	* TIS Firewall Toolkit gate ftp proxy support (see `gate')
+	* transfer-rate throttling (see `-T', `rate')
+	* uploading of files on the command line (see `-u')
+	* (Dante) SOCKS5 support
+
+Previous features, currently disabled until a test system is available:
+	* SOCKS4 support
+
+
+INSTALLATION
+------------
+
+Refer to `INSTALL' for more information on how to compile and install tnftp.
+
+
+FEEDBACK / BUG REPORTS
+----------------------
+
+Please email feedback back to the maintainer:
+	Luke Mewburn <lukem at NetBSD.org>.
+
+
+COPYRIGHT
+---------
+
+tnftp is covered by a BSD-style copyright notice.
+Please refer to the file `COPYING' for more information.
+
+
+AVAILABILITY
+------------
+
+The primary ftp site for tnftp is:
+	ftp://ftp.NetBSD.org/pub/NetBSD/misc/tnftp/
+
+
+DOCUMENT REFERENCE
+------------------
+$NetBSD: README,v 1.10 2007/08/06 01:58:57 lukem Exp $

Added: vendor/NetBSD/tnftp/20100108/THANKS
===================================================================
--- vendor/NetBSD/tnftp/20100108/THANKS	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/THANKS	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,53 @@
+Whilst a lot of the work in tnftp (both the original sources in NetBSD
+and this port) was done by Luke Mewburn, it would not be as usable
+without the enhancements, bug fixes, or input from the following people:
+
+Amitai Schlair			<schmonz at schmonz.com>
+Anders Dinsen			<anders at dinsen.net>
+Anders Magnusson		<ragge at ltu.se>
+Arkadiusz Miskiewicz		<misiek at pld.org.pl>
+Brian Stark			<bstark1990 at netscape.net>
+Chris G. Demetriou		<cgd at NetBSD.org>
+Christos Zoulas			<christos at NetBSD.org>
+Dan Winship			<danw at mit.edu>
+Darren Reed			<darrenr at pobox.com>
+David Brownlee			<abs at mono.org>
+David Carrel			<carrel at NetBSD.org>
+DervishD			<raul at pleyades.net>
+Douwe Kiela			<virtus at wanadoo.nl>
+Eugene Kotlyarov		<ekot at protek36.esoo.ru>
+Geoff Wing			<mason at primenet.com.au>
+Giles Lean			<giles at nemeton.com.au>
+Havard Eidnes			<Havard.Eidnes at runit.sintef.no>
+Hubert Feyrer			<hubert at feyrer.de>
+ITOH Yasufumi			<itohy at NetBSD.org> 
+Jason R. Thorpe			<thorpej at NetBSD.org>
+John Hawkinson			<jhawk at mit.edu>
+Joseph S. Myers			<jsm28 at cam.ac.uk>
+Jun-ichiro itojun Hagino	<itojun at NetBSD.org> 
+Kimmo Suominen			<kim at tac.nyc.ny.us>
+Klaus Klein			<kleink at NetBSD.org>
+Launey Thomas			<ljt at alum.mit.edu>
+Luke Mewburn			<lukem at NetBSD.org>
+Marc Horowitz			<marc at mit.edu>
+Mathieu Arnold			<mat at FreeBSD.org>
+Matthew R. Green		<mrg at eterna.com.au>
+Matthias Pfaller		<leo at dachau.marco.de>
+Matthias Scheler		<tron at zhadum.de>
+Maxim Konovalov			<maxim at FreeBSD.org>
+Maxime Henrion			<mux at FreeBSD.org>
+Michael L. Hitch		<osymh at terra.oscs.montana.edu>
+Mike Heffner			<mikeh at FreeBSD.org>
+Onno van der Linden		<o.vd.linden at quicknet.nl>
+Ruslan Ermilov			<ru at FreeBSD.org>
+Ryoji Kanai			<rkanai at eeye.com>
+Scott Aaron Bamford		<sab at ansic.net>
+Simon Burge			<simonb at thistledown.com.au>
+Steve McClellan			<steve.mcclellan at radisys.com>
+TAMURA Kent			<kent at NetBSD.org>
+Stoned Elipot			<seb at NetBSD.org>
+Todd C. Miller			<Todd.Miller at courtesan.com>
+YAMANO Yuji			<yyamano at NetBSD.org>
+Yar Tikhiy			<yar at FreeBSD.org>
+
+Apologies to anyone missed.

Added: vendor/NetBSD/tnftp/20100108/src/Makefile.am
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/Makefile.am	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/Makefile.am	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,52 @@
+## $NetBSD: Makefile.am,v 1.2 2010/01/04 06:24:20 lukem Exp $
+
+bin_PROGRAMS = tnftp
+
+tnftp_SOURCES = \
+	cmds.c \
+	cmdtab.c \
+	complete.c \
+	domacro.c \
+	fetch.c \
+	ftp.c \
+	main.c \
+	progressbar.c \
+	ruserpass.c \
+	util.c
+
+tnftp_CPPFLAGS = \
+	-DHAVE_TNFTPD_H=1 \
+	-D_DEFAULT_CONFDIR=\"${sysconfdir}\" \
+	-I$(srcdir) \
+	-I$(top_srcdir)/libnetbsd \
+	-I$(top_srcdir) \
+	-I$(top_builddir)
+
+tnftp_LDADD = \
+	../libnetbsd/libnetbsd.la 
+
+
+if USE_LIBEDIT
+tnftp_CPPFLAGS += \
+	-I$(top_srcdir)/libedit
+
+tnftp_LDADD += \
+	../libedit/libedit.la
+endif
+
+
+man1_MANS = \
+	tnftp.1
+
+tnftp.1: ftp.1
+	cp $(srcdir)/ftp.1 tnftp.1
+
+CLEANFILES = \
+	tnftp.1
+
+EXTRA_DIST = \
+	extern.h \
+	ftp.1 \
+	ftp_var.h \
+	progressbar.h \
+	version.h

Added: vendor/NetBSD/tnftp/20100108/src/Makefile.in
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/Makefile.in	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/Makefile.in	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,809 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+bin_PROGRAMS = tnftp$(EXEEXT)
+ at USE_LIBEDIT_TRUE@am__append_1 = \
+ at USE_LIBEDIT_TRUE@	-I$(top_srcdir)/libedit
+
+ at USE_LIBEDIT_TRUE@am__append_2 = \
+ at USE_LIBEDIT_TRUE@	../libedit/libedit.la
+
+subdir = src
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/tnftp_config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_tnftp_OBJECTS = tnftp-cmds.$(OBJEXT) tnftp-cmdtab.$(OBJEXT) \
+	tnftp-complete.$(OBJEXT) tnftp-domacro.$(OBJEXT) \
+	tnftp-fetch.$(OBJEXT) tnftp-ftp.$(OBJEXT) tnftp-main.$(OBJEXT) \
+	tnftp-progressbar.$(OBJEXT) tnftp-ruserpass.$(OBJEXT) \
+	tnftp-util.$(OBJEXT)
+tnftp_OBJECTS = $(am_tnftp_OBJECTS)
+tnftp_DEPENDENCIES = ../libnetbsd/libnetbsd.la $(am__append_2)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+DEFAULT_INCLUDES = 
+depcomp = $(SHELL) $(top_srcdir)/buildaux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo "  CC    " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo "  CCLD  " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN   " $@;
+SOURCES = $(tnftp_SOURCES)
+DIST_SOURCES = $(tnftp_SOURCES)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+man1dir = $(mandir)/man1
+NROFF = nroff
+MANS = $(man1_MANS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NMEDIT = @NMEDIT@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+tnftp_SOURCES = \
+	cmds.c \
+	cmdtab.c \
+	complete.c \
+	domacro.c \
+	fetch.c \
+	ftp.c \
+	main.c \
+	progressbar.c \
+	ruserpass.c \
+	util.c
+
+tnftp_CPPFLAGS = -DHAVE_TNFTPD_H=1 \
+	-D_DEFAULT_CONFDIR=\"${sysconfdir}\" -I$(srcdir) \
+	-I$(top_srcdir)/libnetbsd -I$(top_srcdir) -I$(top_builddir) \
+	$(am__append_1)
+tnftp_LDADD = ../libnetbsd/libnetbsd.la $(am__append_2)
+man1_MANS = \
+	tnftp.1
+
+CLEANFILES = \
+	tnftp.1
+
+EXTRA_DIST = \
+	extern.h \
+	ftp.1 \
+	ftp_var.h \
+	progressbar.h \
+	version.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+	for p in $$list; do echo "$$p $$p"; done | \
+	sed 's/$(EXEEXT)$$//' | \
+	while read p p1; do if test -f $$p || test -f $$p1; \
+	  then echo "$$p"; echo "$$p"; else :; fi; \
+	done | \
+	sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+	    -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+	sed 'N;N;N;s,\n, ,g' | \
+	$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+	  { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+	    if ($$2 == $$4) files[d] = files[d] " " $$1; \
+	    else { print "f", $$3 "/" $$4, $$1; } } \
+	  END { for (d in files) print "f", d, files[d] }' | \
+	while read type dir files; do \
+	    if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+	    test -z "$$files" || { \
+	    echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+	    $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+	    } \
+	; done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+	files=`for p in $$list; do echo "$$p"; done | \
+	  sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+	      -e 's/$$/$(EXEEXT)/' `; \
+	test -n "$$list" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+	@list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+tnftp$(EXEEXT): $(tnftp_OBJECTS) $(tnftp_DEPENDENCIES) 
+	@rm -f tnftp$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(tnftp_OBJECTS) $(tnftp_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tnftp-cmds.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tnftp-cmdtab.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tnftp-complete.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tnftp-domacro.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tnftp-fetch.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tnftp-ftp.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tnftp-main.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tnftp-progressbar.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tnftp-ruserpass.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/tnftp-util.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+tnftp-cmds.o: cmds.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-cmds.o -MD -MP -MF $(DEPDIR)/tnftp-cmds.Tpo -c -o tnftp-cmds.o `test -f 'cmds.c' || echo '$(srcdir)/'`cmds.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-cmds.Tpo $(DEPDIR)/tnftp-cmds.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='cmds.c' object='tnftp-cmds.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-cmds.o `test -f 'cmds.c' || echo '$(srcdir)/'`cmds.c
+
+tnftp-cmds.obj: cmds.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-cmds.obj -MD -MP -MF $(DEPDIR)/tnftp-cmds.Tpo -c -o tnftp-cmds.obj `if test -f 'cmds.c'; then $(CYGPATH_W) 'cmds.c'; else $(CYGPATH_W) '$(srcdir)/cmds.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-cmds.Tpo $(DEPDIR)/tnftp-cmds.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='cmds.c' object='tnftp-cmds.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-cmds.obj `if test -f 'cmds.c'; then $(CYGPATH_W) 'cmds.c'; else $(CYGPATH_W) '$(srcdir)/cmds.c'; fi`
+
+tnftp-cmdtab.o: cmdtab.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-cmdtab.o -MD -MP -MF $(DEPDIR)/tnftp-cmdtab.Tpo -c -o tnftp-cmdtab.o `test -f 'cmdtab.c' || echo '$(srcdir)/'`cmdtab.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-cmdtab.Tpo $(DEPDIR)/tnftp-cmdtab.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='cmdtab.c' object='tnftp-cmdtab.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-cmdtab.o `test -f 'cmdtab.c' || echo '$(srcdir)/'`cmdtab.c
+
+tnftp-cmdtab.obj: cmdtab.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-cmdtab.obj -MD -MP -MF $(DEPDIR)/tnftp-cmdtab.Tpo -c -o tnftp-cmdtab.obj `if test -f 'cmdtab.c'; then $(CYGPATH_W) 'cmdtab.c'; else $(CYGPATH_W) '$(srcdir)/cmdtab.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-cmdtab.Tpo $(DEPDIR)/tnftp-cmdtab.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='cmdtab.c' object='tnftp-cmdtab.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-cmdtab.obj `if test -f 'cmdtab.c'; then $(CYGPATH_W) 'cmdtab.c'; else $(CYGPATH_W) '$(srcdir)/cmdtab.c'; fi`
+
+tnftp-complete.o: complete.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-complete.o -MD -MP -MF $(DEPDIR)/tnftp-complete.Tpo -c -o tnftp-complete.o `test -f 'complete.c' || echo '$(srcdir)/'`complete.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-complete.Tpo $(DEPDIR)/tnftp-complete.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='complete.c' object='tnftp-complete.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-complete.o `test -f 'complete.c' || echo '$(srcdir)/'`complete.c
+
+tnftp-complete.obj: complete.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-complete.obj -MD -MP -MF $(DEPDIR)/tnftp-complete.Tpo -c -o tnftp-complete.obj `if test -f 'complete.c'; then $(CYGPATH_W) 'complete.c'; else $(CYGPATH_W) '$(srcdir)/complete.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-complete.Tpo $(DEPDIR)/tnftp-complete.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='complete.c' object='tnftp-complete.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-complete.obj `if test -f 'complete.c'; then $(CYGPATH_W) 'complete.c'; else $(CYGPATH_W) '$(srcdir)/complete.c'; fi`
+
+tnftp-domacro.o: domacro.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-domacro.o -MD -MP -MF $(DEPDIR)/tnftp-domacro.Tpo -c -o tnftp-domacro.o `test -f 'domacro.c' || echo '$(srcdir)/'`domacro.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-domacro.Tpo $(DEPDIR)/tnftp-domacro.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='domacro.c' object='tnftp-domacro.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-domacro.o `test -f 'domacro.c' || echo '$(srcdir)/'`domacro.c
+
+tnftp-domacro.obj: domacro.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-domacro.obj -MD -MP -MF $(DEPDIR)/tnftp-domacro.Tpo -c -o tnftp-domacro.obj `if test -f 'domacro.c'; then $(CYGPATH_W) 'domacro.c'; else $(CYGPATH_W) '$(srcdir)/domacro.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-domacro.Tpo $(DEPDIR)/tnftp-domacro.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='domacro.c' object='tnftp-domacro.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-domacro.obj `if test -f 'domacro.c'; then $(CYGPATH_W) 'domacro.c'; else $(CYGPATH_W) '$(srcdir)/domacro.c'; fi`
+
+tnftp-fetch.o: fetch.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-fetch.o -MD -MP -MF $(DEPDIR)/tnftp-fetch.Tpo -c -o tnftp-fetch.o `test -f 'fetch.c' || echo '$(srcdir)/'`fetch.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-fetch.Tpo $(DEPDIR)/tnftp-fetch.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='fetch.c' object='tnftp-fetch.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-fetch.o `test -f 'fetch.c' || echo '$(srcdir)/'`fetch.c
+
+tnftp-fetch.obj: fetch.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-fetch.obj -MD -MP -MF $(DEPDIR)/tnftp-fetch.Tpo -c -o tnftp-fetch.obj `if test -f 'fetch.c'; then $(CYGPATH_W) 'fetch.c'; else $(CYGPATH_W) '$(srcdir)/fetch.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-fetch.Tpo $(DEPDIR)/tnftp-fetch.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='fetch.c' object='tnftp-fetch.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-fetch.obj `if test -f 'fetch.c'; then $(CYGPATH_W) 'fetch.c'; else $(CYGPATH_W) '$(srcdir)/fetch.c'; fi`
+
+tnftp-ftp.o: ftp.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-ftp.o -MD -MP -MF $(DEPDIR)/tnftp-ftp.Tpo -c -o tnftp-ftp.o `test -f 'ftp.c' || echo '$(srcdir)/'`ftp.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-ftp.Tpo $(DEPDIR)/tnftp-ftp.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='ftp.c' object='tnftp-ftp.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-ftp.o `test -f 'ftp.c' || echo '$(srcdir)/'`ftp.c
+
+tnftp-ftp.obj: ftp.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-ftp.obj -MD -MP -MF $(DEPDIR)/tnftp-ftp.Tpo -c -o tnftp-ftp.obj `if test -f 'ftp.c'; then $(CYGPATH_W) 'ftp.c'; else $(CYGPATH_W) '$(srcdir)/ftp.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-ftp.Tpo $(DEPDIR)/tnftp-ftp.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='ftp.c' object='tnftp-ftp.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-ftp.obj `if test -f 'ftp.c'; then $(CYGPATH_W) 'ftp.c'; else $(CYGPATH_W) '$(srcdir)/ftp.c'; fi`
+
+tnftp-main.o: main.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-main.o -MD -MP -MF $(DEPDIR)/tnftp-main.Tpo -c -o tnftp-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-main.Tpo $(DEPDIR)/tnftp-main.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='main.c' object='tnftp-main.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c
+
+tnftp-main.obj: main.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-main.obj -MD -MP -MF $(DEPDIR)/tnftp-main.Tpo -c -o tnftp-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-main.Tpo $(DEPDIR)/tnftp-main.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='main.c' object='tnftp-main.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi`
+
+tnftp-progressbar.o: progressbar.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-progressbar.o -MD -MP -MF $(DEPDIR)/tnftp-progressbar.Tpo -c -o tnftp-progressbar.o `test -f 'progressbar.c' || echo '$(srcdir)/'`progressbar.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-progressbar.Tpo $(DEPDIR)/tnftp-progressbar.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='progressbar.c' object='tnftp-progressbar.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-progressbar.o `test -f 'progressbar.c' || echo '$(srcdir)/'`progressbar.c
+
+tnftp-progressbar.obj: progressbar.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-progressbar.obj -MD -MP -MF $(DEPDIR)/tnftp-progressbar.Tpo -c -o tnftp-progressbar.obj `if test -f 'progressbar.c'; then $(CYGPATH_W) 'progressbar.c'; else $(CYGPATH_W) '$(srcdir)/progressbar.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-progressbar.Tpo $(DEPDIR)/tnftp-progressbar.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='progressbar.c' object='tnftp-progressbar.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-progressbar.obj `if test -f 'progressbar.c'; then $(CYGPATH_W) 'progressbar.c'; else $(CYGPATH_W) '$(srcdir)/progressbar.c'; fi`
+
+tnftp-ruserpass.o: ruserpass.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-ruserpass.o -MD -MP -MF $(DEPDIR)/tnftp-ruserpass.Tpo -c -o tnftp-ruserpass.o `test -f 'ruserpass.c' || echo '$(srcdir)/'`ruserpass.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-ruserpass.Tpo $(DEPDIR)/tnftp-ruserpass.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='ruserpass.c' object='tnftp-ruserpass.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-ruserpass.o `test -f 'ruserpass.c' || echo '$(srcdir)/'`ruserpass.c
+
+tnftp-ruserpass.obj: ruserpass.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-ruserpass.obj -MD -MP -MF $(DEPDIR)/tnftp-ruserpass.Tpo -c -o tnftp-ruserpass.obj `if test -f 'ruserpass.c'; then $(CYGPATH_W) 'ruserpass.c'; else $(CYGPATH_W) '$(srcdir)/ruserpass.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-ruserpass.Tpo $(DEPDIR)/tnftp-ruserpass.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='ruserpass.c' object='tnftp-ruserpass.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-ruserpass.obj `if test -f 'ruserpass.c'; then $(CYGPATH_W) 'ruserpass.c'; else $(CYGPATH_W) '$(srcdir)/ruserpass.c'; fi`
+
+tnftp-util.o: util.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-util.o -MD -MP -MF $(DEPDIR)/tnftp-util.Tpo -c -o tnftp-util.o `test -f 'util.c' || echo '$(srcdir)/'`util.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-util.Tpo $(DEPDIR)/tnftp-util.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='util.c' object='tnftp-util.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-util.o `test -f 'util.c' || echo '$(srcdir)/'`util.c
+
+tnftp-util.obj: util.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-util.obj -MD -MP -MF $(DEPDIR)/tnftp-util.Tpo -c -o tnftp-util.obj `if test -f 'util.c'; then $(CYGPATH_W) 'util.c'; else $(CYGPATH_W) '$(srcdir)/util.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-util.Tpo $(DEPDIR)/tnftp-util.Po
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='util.c' object='tnftp-util.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-util.obj `if test -f 'util.c'; then $(CYGPATH_W) 'util.c'; else $(CYGPATH_W) '$(srcdir)/util.c'; fi`
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+install-man1: $(man1_MANS)
+	@$(NORMAL_INSTALL)
+	test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
+	@list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \
+	{ for i in $$list; do echo "$$i"; done; \
+	} | while read p; do \
+	  if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; echo "$$p"; \
+	done | \
+	sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+	      -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+	sed 'N;N;s,\n, ,g' | { \
+	list=; while read file base inst; do \
+	  if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+	    echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+	    $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
+	  fi; \
+	done; \
+	for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+	while read files; do \
+	  test -z "$$files" || { \
+	    echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
+	    $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
+	done; }
+
+uninstall-man1:
+	@$(NORMAL_UNINSTALL)
+	@list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \
+	files=`{ for i in $$list; do echo "$$i"; done; \
+	} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+	      -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+	test -z "$$files" || { \
+	  echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \
+	  cd "$(DESTDIR)$(man1dir)" && rm -f $$files; }
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@list='$(MANS)'; if test -n "$$list"; then \
+	  list=`for p in $$list; do \
+	    if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+	    if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \
+	  if test -n "$$list" && \
+	    grep 'ab help2man is required to generate this page' $$list >/dev/null; then \
+	    echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \
+	    grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/         /' >&2; \
+	    echo "       to fix them, install help2man, remove and regenerate the man pages;" >&2; \
+	    echo "       typically \`make maintainer-clean' will remove them" >&2; \
+	    exit 1; \
+	  else :; fi; \
+	else :; fi
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(MANS)
+installdirs:
+	for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man1
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-man
+
+uninstall-man: uninstall-man1
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+	clean-generic clean-libtool ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-binPROGRAMS install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-man1 install-pdf install-pdf-am install-ps \
+	install-ps-am install-strip installcheck installcheck-am \
+	installdirs maintainer-clean maintainer-clean-generic \
+	mostlyclean mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+	uninstall-am uninstall-binPROGRAMS uninstall-man \
+	uninstall-man1
+
+
+tnftp.1: ftp.1
+	cp $(srcdir)/ftp.1 tnftp.1
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:

Added: vendor/NetBSD/tnftp/20100108/src/cmds.c
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/cmds.c	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/cmds.c	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,2797 @@
+/*	$NetBSD: cmds.c,v 1.17 2010/01/12 06:55:47 lukem Exp $	*/
+/*	from	NetBSD: cmds.c,v 1.130 2009/07/13 19:05:41 roy Exp	*/
+
+/*-
+ * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1985, 1989, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (C) 1997 and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "tnftp.h"
+
+#if 0	/* tnftp */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cmds.c	8.6 (Berkeley) 10/9/94";
+#else
+__RCSID(" NetBSD: cmds.c,v 1.130 2009/07/13 19:05:41 roy Exp  ");
+#endif
+#endif /* not lint */
+
+/*
+ * FTP User Program -- Command Routines.
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <arpa/ftp.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <glob.h>
+#include <limits.h>
+#include <netdb.h>
+#include <paths.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#endif	/* tnftp */
+
+#include "ftp_var.h"
+#include "version.h"
+
+static struct types {
+	const char	*t_name;
+	const char	*t_mode;
+	int		t_type;
+	const char	*t_arg;
+} types[] = {
+	{ "ascii",	"A",	TYPE_A,	0 },
+	{ "binary",	"I",	TYPE_I,	0 },
+	{ "image",	"I",	TYPE_I,	0 },
+	{ "ebcdic",	"E",	TYPE_E,	0 },
+	{ "tenex",	"L",	TYPE_L,	bytename },
+	{ NULL,		NULL,	0, NULL }
+};
+
+static sigjmp_buf	 jabort;
+
+static int	confirm(const char *, const char *);
+static void	mintr(int);
+static void	mabort(const char *);
+static void	set_type(const char *);
+
+static const char *doprocess(char *, size_t, const char *, int, int, int);
+static const char *domap(char *, size_t, const char *);
+static const char *docase(char *, size_t, const char *);
+static const char *dotrans(char *, size_t, const char *);
+
+/*
+ * Confirm if "cmd" is to be performed upon "file".
+ * If "file" is NULL, generate a "Continue with" prompt instead.
+ */
+static int
+confirm(const char *cmd, const char *file)
+{
+	const char *errormsg;
+	char cline[BUFSIZ];
+	const char *promptleft, *promptright;
+
+	if (!interactive || confirmrest)
+		return (1);
+	if (file == NULL) {
+		promptleft = "Continue with";
+		promptright = cmd;
+	} else {
+		promptleft = cmd;
+		promptright = file;
+	}
+	while (1) {
+		fprintf(ttyout, "%s %s [anpqy?]? ", promptleft, promptright);
+		(void)fflush(ttyout);
+		if (get_line(stdin, cline, sizeof(cline), &errormsg) < 0) {
+			mflag = 0;
+			fprintf(ttyout, "%s; %s aborted\n", errormsg, cmd);
+			return (0);
+		}
+		switch (tolower((unsigned char)*cline)) {
+			case 'a':
+				confirmrest = 1;
+				fprintf(ttyout,
+				    "Prompting off for duration of %s.\n", cmd);
+				break;
+			case 'p':
+				interactive = 0;
+				fputs("Interactive mode: off.\n", ttyout);
+				break;
+			case 'q':
+				mflag = 0;
+				fprintf(ttyout, "%s aborted.\n", cmd);
+				/* FALLTHROUGH */
+			case 'n':
+				return (0);
+			case '?':
+				fprintf(ttyout,
+				    "  confirmation options:\n"
+				    "\ta  answer `yes' for the duration of %s\n"
+				    "\tn  answer `no' for this file\n"
+				    "\tp  turn off `prompt' mode\n"
+				    "\tq  stop the current %s\n"
+				    "\ty  answer `yes' for this file\n"
+				    "\t?  this help list\n",
+				    cmd, cmd);
+				continue;	/* back to while(1) */
+		}
+		return (1);
+	}
+	/* NOTREACHED */
+}
+
+/*
+ * Set transfer type.
+ */
+void
+settype(int argc, char *argv[])
+{
+	struct types *p;
+
+	if (argc == 0 || argc > 2) {
+		const char *sep;
+
+		UPRINTF("usage: %s [", argv[0]);
+		sep = " ";
+		for (p = types; p->t_name; p++) {
+			fprintf(ttyout, "%s%s", sep, p->t_name);
+			sep = " | ";
+		}
+		fputs(" ]\n", ttyout);
+		code = -1;
+		return;
+	}
+	if (argc < 2) {
+		fprintf(ttyout, "Using %s mode to transfer files.\n", typename);
+		code = 0;
+		return;
+	}
+	set_type(argv[1]);
+}
+
+void
+set_type(const char *ttype)
+{
+	struct types *p;
+	int comret;
+
+	for (p = types; p->t_name; p++)
+		if (strcmp(ttype, p->t_name) == 0)
+			break;
+	if (p->t_name == 0) {
+		fprintf(ttyout, "%s: unknown mode.\n", ttype);
+		code = -1;
+		return;
+	}
+	if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
+		comret = command("TYPE %s %s", p->t_mode, p->t_arg);
+	else
+		comret = command("TYPE %s", p->t_mode);
+	if (comret == COMPLETE) {
+		(void)strlcpy(typename, p->t_name, sizeof(typename));
+		curtype = type = p->t_type;
+	}
+}
+
+/*
+ * Internal form of settype; changes current type in use with server
+ * without changing our notion of the type for data transfers.
+ * Used to change to and from ascii for listings.
+ */
+void
+changetype(int newtype, int show)
+{
+	struct types *p;
+	int comret, oldverbose = verbose;
+
+	if (newtype == 0)
+		newtype = TYPE_I;
+	if (newtype == curtype)
+		return;
+	if (ftp_debug == 0 && show == 0)
+		verbose = 0;
+	for (p = types; p->t_name; p++)
+		if (newtype == p->t_type)
+			break;
+	if (p->t_name == 0) {
+		errx(1, "changetype: unknown type %d", newtype);
+	}
+	if (newtype == TYPE_L && bytename[0] != '\0')
+		comret = command("TYPE %s %s", p->t_mode, bytename);
+	else
+		comret = command("TYPE %s", p->t_mode);
+	if (comret == COMPLETE)
+		curtype = newtype;
+	verbose = oldverbose;
+}
+
+/*
+ * Set binary transfer type.
+ */
+/*VARARGS*/
+void
+setbinary(int argc, char *argv[])
+{
+
+	if (argc == 0) {
+		UPRINTF("usage: %s\n", argv[0]);
+		code = -1;
+		return;
+	}
+	set_type("binary");
+}
+
+/*
+ * Set ascii transfer type.
+ */
+/*VARARGS*/
+void
+setascii(int argc, char *argv[])
+{
+
+	if (argc == 0) {
+		UPRINTF("usage: %s\n", argv[0]);
+		code = -1;
+		return;
+	}
+	set_type("ascii");
+}
+
+/*
+ * Set tenex transfer type.
+ */
+/*VARARGS*/
+void
+settenex(int argc, char *argv[])
+{
+
+	if (argc == 0) {
+		UPRINTF("usage: %s\n", argv[0]);
+		code = -1;
+		return;
+	}
+	set_type("tenex");
+}
+
+/*
+ * Set file transfer mode.
+ */
+/*ARGSUSED*/
+void
+setftmode(int argc, char *argv[])
+{
+
+	if (argc != 2) {
+		UPRINTF("usage: %s mode-name\n", argv[0]);
+		code = -1;
+		return;
+	}
+	fprintf(ttyout, "We only support %s mode, sorry.\n", modename);
+	code = -1;
+}
+
+/*
+ * Set file transfer format.
+ */
+/*ARGSUSED*/
+void
+setform(int argc, char *argv[])
+{
+
+	if (argc != 2) {
+		UPRINTF("usage: %s format\n", argv[0]);
+		code = -1;
+		return;
+	}
+	fprintf(ttyout, "We only support %s format, sorry.\n", formname);
+	code = -1;
+}
+
+/*
+ * Set file transfer structure.
+ */
+/*ARGSUSED*/
+void
+setstruct(int argc, char *argv[])
+{
+
+	if (argc != 2) {
+		UPRINTF("usage: %s struct-mode\n", argv[0]);
+		code = -1;
+		return;
+	}
+	fprintf(ttyout, "We only support %s structure, sorry.\n", structname);
+	code = -1;
+}
+
+/*
+ * Send a single file.
+ */
+void
+put(int argc, char *argv[])
+{
+	char buf[MAXPATHLEN];
+	const char *cmd;
+	int loc = 0;
+	char *locfile;
+	const char *remfile;
+
+	if (argc == 2) {
+		argc++;
+		argv[2] = argv[1];
+		loc++;
+	}
+	if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-file")))
+		goto usage;
+	if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
+ usage:
+		UPRINTF("usage: %s local-file [remote-file]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if ((locfile = globulize(argv[1])) == NULL) {
+		code = -1;
+		return;
+	}
+	remfile = argv[2];
+	if (loc)	/* If argv[2] is a copy of the old argv[1], update it */
+		remfile = locfile;
+	cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
+	remfile = doprocess(buf, sizeof(buf), remfile,
+		0, loc && ntflag, loc && mapflag);
+	sendrequest(cmd, locfile, remfile,
+	    locfile != argv[1] || remfile != argv[2]);
+	free(locfile);
+}
+
+static const char *
+doprocess(char *dst, size_t dlen, const char *src,
+    int casef, int transf, int mapf)
+{
+	if (casef)
+		src = docase(dst, dlen, src);
+	if (transf)
+		src = dotrans(dst, dlen, src);
+	if (mapf)
+		src = domap(dst, dlen, src);
+	return src;
+}
+
+/*
+ * Send multiple files.
+ */
+void
+mput(int argc, char *argv[])
+{
+	int i;
+	sigfunc oldintr;
+	int ointer;
+	const char *tp;
+
+	if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-files"))) {
+		UPRINTF("usage: %s local-files\n", argv[0]);
+		code = -1;
+		return;
+	}
+	mflag = 1;
+	oldintr = xsignal(SIGINT, mintr);
+	if (sigsetjmp(jabort, 1))
+		mabort(argv[0]);
+	if (proxy) {
+		char *cp;
+
+		while ((cp = remglob(argv, 0, NULL)) != NULL) {
+			if (*cp == '\0' || !connected) {
+				mflag = 0;
+				continue;
+			}
+			if (mflag && confirm(argv[0], cp)) {
+				char buf[MAXPATHLEN];
+				tp = doprocess(buf, sizeof(buf), cp,
+				    mcase, ntflag, mapflag);
+				sendrequest((sunique) ? "STOU" : "STOR",
+				    cp, tp, cp != tp || !interactive);
+				if (!mflag && fromatty) {
+					ointer = interactive;
+					interactive = 1;
+					if (confirm(argv[0], NULL)) {
+						mflag++;
+					}
+					interactive = ointer;
+				}
+			}
+		}
+		goto cleanupmput;
+	}
+	for (i = 1; i < argc && connected; i++) {
+		char **cpp;
+		glob_t gl;
+		int flags;
+
+		if (!doglob) {
+			if (mflag && confirm(argv[0], argv[i])) {
+				char buf[MAXPATHLEN];
+				tp = doprocess(buf, sizeof(buf), argv[i],
+					0, ntflag, mapflag);
+				sendrequest((sunique) ? "STOU" : "STOR",
+				    argv[i], tp, tp != argv[i] || !interactive);
+				if (!mflag && fromatty) {
+					ointer = interactive;
+					interactive = 1;
+					if (confirm(argv[0], NULL)) {
+						mflag++;
+					}
+					interactive = ointer;
+				}
+			}
+			continue;
+		}
+
+		memset(&gl, 0, sizeof(gl));
+		flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
+		if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
+			warnx("Glob pattern `%s' not found", argv[i]);
+			globfree(&gl);
+			continue;
+		}
+		for (cpp = gl.gl_pathv; cpp && *cpp != NULL && connected;
+		    cpp++) {
+			if (mflag && confirm(argv[0], *cpp)) {
+				char buf[MAXPATHLEN];
+				tp = *cpp;
+				tp = doprocess(buf, sizeof(buf), *cpp,
+				    0, ntflag, mapflag);
+				sendrequest((sunique) ? "STOU" : "STOR",
+				    *cpp, tp, *cpp != tp || !interactive);
+				if (!mflag && fromatty) {
+					ointer = interactive;
+					interactive = 1;
+					if (confirm(argv[0], NULL)) {
+						mflag++;
+					}
+					interactive = ointer;
+				}
+			}
+		}
+		globfree(&gl);
+	}
+ cleanupmput:
+	(void)xsignal(SIGINT, oldintr);
+	mflag = 0;
+}
+
+void
+reget(int argc, char *argv[])
+{
+
+	(void)getit(argc, argv, 1, "r+");
+}
+
+void
+get(int argc, char *argv[])
+{
+
+	(void)getit(argc, argv, 0, restart_point ? "r+" : "w" );
+}
+
+/*
+ * Receive one file.
+ * If restartit is  1, restart the xfer always.
+ * If restartit is -1, restart the xfer only if the remote file is newer.
+ */
+int
+getit(int argc, char *argv[], int restartit, const char *gmode)
+{
+	int	loc, rval;
+	char	*remfile, *olocfile;
+	const char *locfile;
+	char	buf[MAXPATHLEN];
+
+	loc = rval = 0;
+	if (argc == 2) {
+		argc++;
+		argv[2] = argv[1];
+		loc++;
+	}
+	if (argc == 0 || (argc == 1 && !another(&argc, &argv, "remote-file")))
+		goto usage;
+	if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) {
+ usage:
+		UPRINTF("usage: %s remote-file [local-file]\n", argv[0]);
+		code = -1;
+		return (0);
+	}
+	remfile = argv[1];
+	if ((olocfile = globulize(argv[2])) == NULL) {
+		code = -1;
+		return (0);
+	}
+	locfile = doprocess(buf, sizeof(buf), olocfile,
+		loc && mcase, loc && ntflag, loc && mapflag);
+	if (restartit) {
+		struct stat stbuf;
+		int ret;
+
+		if (! features[FEAT_REST_STREAM]) {
+			fprintf(ttyout,
+			    "Restart is not supported by the remote server.\n");
+			return (0);
+		}
+		ret = stat(locfile, &stbuf);
+		if (restartit == 1) {
+			if (ret < 0) {
+				warn("Can't stat `%s'", locfile);
+				goto freegetit;
+			}
+			restart_point = stbuf.st_size;
+		} else {
+			if (ret == 0) {
+				time_t mtime;
+
+				mtime = remotemodtime(argv[1], 0);
+				if (mtime == -1)
+					goto freegetit;
+				if (stbuf.st_mtime >= mtime) {
+					rval = 1;
+					goto freegetit;
+				}
+			}
+		}
+	}
+
+	recvrequest("RETR", locfile, remfile, gmode,
+	    remfile != argv[1] || locfile != argv[2], loc);
+	restart_point = 0;
+ freegetit:
+	(void)free(olocfile);
+	return (rval);
+}
+
+/* ARGSUSED */
+static void
+mintr(int signo)
+{
+
+	alarmtimer(0);
+	if (fromatty)
+		write(fileno(ttyout), "\n", 1);
+	siglongjmp(jabort, 1);
+}
+
+static void
+mabort(const char *cmd)
+{
+	int ointer, oconf;
+
+	if (mflag && fromatty) {
+		ointer = interactive;
+		oconf = confirmrest;
+		interactive = 1;
+		confirmrest = 0;
+		if (confirm(cmd, NULL)) {
+			interactive = ointer;
+			confirmrest = oconf;
+			return;
+		}
+		interactive = ointer;
+		confirmrest = oconf;
+	}
+	mflag = 0;
+}
+
+/*
+ * Get multiple files.
+ */
+void
+mget(int argc, char *argv[])
+{
+	sigfunc oldintr;
+	int ointer;
+	char *cp;
+	const char *tp;
+	int volatile restartit;
+
+	if (argc == 0 ||
+	    (argc == 1 && !another(&argc, &argv, "remote-files"))) {
+		UPRINTF("usage: %s remote-files\n", argv[0]);
+		code = -1;
+		return;
+	}
+	mflag = 1;
+	restart_point = 0;
+	restartit = 0;
+	if (strcmp(argv[0], "mreget") == 0) {
+		if (! features[FEAT_REST_STREAM]) {
+			fprintf(ttyout,
+		    "Restart is not supported by the remote server.\n");
+			return;
+		}
+		restartit = 1;
+	}
+	oldintr = xsignal(SIGINT, mintr);
+	if (sigsetjmp(jabort, 1))
+		mabort(argv[0]);
+	while ((cp = remglob(argv, proxy, NULL)) != NULL) {
+		char buf[MAXPATHLEN];
+		if (*cp == '\0' || !connected) {
+			mflag = 0;
+			continue;
+		}
+		if (! mflag)
+			continue;
+		if (! fileindir(cp, localcwd)) {
+			fprintf(ttyout, "Skipping non-relative filename `%s'\n",
+			    cp);
+			continue;
+		}
+		if (!confirm(argv[0], cp))
+			continue;
+		tp = doprocess(buf, sizeof(buf), cp, mcase, ntflag, mapflag);
+		if (restartit) {
+			struct stat stbuf;
+
+			if (stat(tp, &stbuf) == 0)
+				restart_point = stbuf.st_size;
+			else
+				warn("Can't stat `%s'", tp);
+		}
+		recvrequest("RETR", tp, cp, restart_point ? "r+" : "w",
+		    tp != cp || !interactive, 1);
+		restart_point = 0;
+		if (!mflag && fromatty) {
+			ointer = interactive;
+			interactive = 1;
+			if (confirm(argv[0], NULL))
+				mflag++;
+			interactive = ointer;
+		}
+	}
+	(void)xsignal(SIGINT, oldintr);
+	mflag = 0;
+}
+
+/*
+ * Read list of filenames from a local file and get those
+ */
+void
+fget(int argc, char *argv[])
+{
+	const char *gmode;
+	FILE	*fp;
+	char	buf[MAXPATHLEN], cmdbuf[MAX_C_NAME];
+
+	if (argc != 2) {
+		UPRINTF("usage: %s localfile\n", argv[0]);
+		code = -1;
+		return;
+	}
+
+	fp = fopen(argv[1], "r");
+	if (fp == NULL) {
+		fprintf(ttyout, "Can't open source file %s\n", argv[1]);
+		code = -1;
+		return;
+	}
+
+	(void)strlcpy(cmdbuf, "get", sizeof(cmdbuf));
+	argv[0] = cmdbuf;
+	gmode = restart_point ? "r+" : "w";
+
+	while (get_line(fp, buf, sizeof(buf), NULL) >= 0) {
+		if (buf[0] == '\0')
+			continue;
+		argv[1] = buf;
+		(void)getit(argc, argv, 0, gmode);
+	}
+	fclose(fp);
+}
+
+const char *
+onoff(int val)
+{
+
+	return (val ? "on" : "off");
+}
+
+/*
+ * Show status.
+ */
+/*ARGSUSED*/
+void
+status(int argc, char *argv[])
+{
+
+	if (argc == 0) {
+		UPRINTF("usage: %s\n", argv[0]);
+		code = -1;
+		return;
+	}
+#ifndef NO_STATUS
+	if (connected)
+		fprintf(ttyout, "Connected %sto %s.\n",
+		    connected == -1 ? "and logged in" : "", hostname);
+	else
+		fputs("Not connected.\n", ttyout);
+	if (!proxy) {
+		pswitch(1);
+		if (connected) {
+			fprintf(ttyout, "Connected for proxy commands to %s.\n",
+			    hostname);
+		}
+		else {
+			fputs("No proxy connection.\n", ttyout);
+		}
+		pswitch(0);
+	}
+	fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode),
+	    *gateserver ? gateserver : "(none)", gateport);
+	fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n",
+	    onoff(passivemode), onoff(activefallback));
+	fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n",
+	    modename, typename, formname, structname);
+	fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n",
+	    onoff(verbose), onoff(bell), onoff(interactive), onoff(doglob));
+	fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n",
+	    onoff(sunique), onoff(runique));
+	fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve));
+	fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase),
+	    onoff(crflag));
+	if (ntflag) {
+		fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout);
+	}
+	else {
+		fputs("Ntrans: off.\n", ttyout);
+	}
+	if (mapflag) {
+		fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout);
+	}
+	else {
+		fputs("Nmap: off.\n", ttyout);
+	}
+	fprintf(ttyout,
+	    "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n",
+	    onoff(hash), mark, onoff(progress));
+	fprintf(ttyout,
+	    "Get transfer rate throttle: %s; maximum: %d; increment %d.\n",
+	    onoff(rate_get), rate_get, rate_get_incr);
+	fprintf(ttyout,
+	    "Put transfer rate throttle: %s; maximum: %d; increment %d.\n",
+	    onoff(rate_put), rate_put, rate_put_incr);
+	fprintf(ttyout,
+	    "Socket buffer sizes: send %d, receive %d.\n",
+	    sndbuf_size, rcvbuf_size);
+	fprintf(ttyout, "Use of PORT cmds: %s.\n", onoff(sendport));
+	fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4),
+	    epsv4bad ? " (disabled for this connection)" : "");
+	fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv6: %s%s.\n", onoff(epsv6),
+	    epsv6bad ? " (disabled for this connection)" : "");
+	fprintf(ttyout, "Command line editing: %s.\n",
+#ifdef NO_EDITCOMPLETE
+	    "support not compiled in"
+#else	/* !def NO_EDITCOMPLETE */
+	    onoff(editing)
+#endif	/* !def NO_EDITCOMPLETE */
+	    );
+	if (macnum > 0) {
+		int i;
+
+		fputs("Macros:\n", ttyout);
+		for (i=0; i<macnum; i++) {
+			fprintf(ttyout, "\t%s\n", macros[i].mac_name);
+		}
+	}
+#endif /* !def NO_STATUS */
+	fprintf(ttyout, "Version: %s %s\n", FTP_PRODUCT, FTP_VERSION);
+	code = 0;
+}
+
+/*
+ * Toggle a variable
+ */
+int
+togglevar(int argc, char *argv[], int *var, const char *mesg)
+{
+	if (argc == 1) {
+		*var = !*var;
+	} else if (argc == 2 && strcasecmp(argv[1], "on") == 0) {
+		*var = 1;
+	} else if (argc == 2 && strcasecmp(argv[1], "off") == 0) {
+		*var = 0;
+	} else {
+		UPRINTF("usage: %s [ on | off ]\n", argv[0]);
+		return (-1);
+	}
+	if (mesg)
+		fprintf(ttyout, "%s %s.\n", mesg, onoff(*var));
+	return (*var);
+}
+
+/*
+ * Set beep on cmd completed mode.
+ */
+/*VARARGS*/
+void
+setbell(int argc, char *argv[])
+{
+
+	code = togglevar(argc, argv, &bell, "Bell mode");
+}
+
+/*
+ * Set command line editing
+ */
+/*VARARGS*/
+void
+setedit(int argc, char *argv[])
+{
+
+#ifdef NO_EDITCOMPLETE
+	if (argc == 0) {
+		UPRINTF("usage: %s\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (verbose)
+		fputs("Editing support not compiled in; ignoring command.\n",
+		    ttyout);
+#else	/* !def NO_EDITCOMPLETE */
+	code = togglevar(argc, argv, &editing, "Editing mode");
+	controlediting();
+#endif	/* !def NO_EDITCOMPLETE */
+}
+
+/*
+ * Turn on packet tracing.
+ */
+/*VARARGS*/
+void
+settrace(int argc, char *argv[])
+{
+
+	code = togglevar(argc, argv, &trace, "Packet tracing");
+}
+
+/*
+ * Toggle hash mark printing during transfers, or set hash mark bytecount.
+ */
+/*VARARGS*/
+void
+sethash(int argc, char *argv[])
+{
+	if (argc == 1)
+		hash = !hash;
+	else if (argc != 2) {
+		UPRINTF("usage: %s [ on | off | bytecount ]\n",
+		    argv[0]);
+		code = -1;
+		return;
+	} else if (strcasecmp(argv[1], "on") == 0)
+		hash = 1;
+	else if (strcasecmp(argv[1], "off") == 0)
+		hash = 0;
+	else {
+		int nmark;
+
+		nmark = strsuftoi(argv[1]);
+		if (nmark < 1) {
+			fprintf(ttyout, "mark: bad bytecount value `%s'.\n",
+			    argv[1]);
+			code = -1;
+			return;
+		}
+		mark = nmark;
+		hash = 1;
+	}
+	fprintf(ttyout, "Hash mark printing %s", onoff(hash));
+	if (hash)
+		fprintf(ttyout, " (%d bytes/hash mark)", mark);
+	fputs(".\n", ttyout);
+	if (hash)
+		progress = 0;
+	code = hash;
+}
+
+/*
+ * Turn on printing of server echo's.
+ */
+/*VARARGS*/
+void
+setverbose(int argc, char *argv[])
+{
+
+	code = togglevar(argc, argv, &verbose, "Verbose mode");
+}
+
+/*
+ * Toggle PORT/LPRT cmd use before each data connection.
+ */
+/*VARARGS*/
+void
+setport(int argc, char *argv[])
+{
+
+	code = togglevar(argc, argv, &sendport, "Use of PORT/LPRT cmds");
+}
+
+/*
+ * Toggle transfer progress bar.
+ */
+/*VARARGS*/
+void
+setprogress(int argc, char *argv[])
+{
+
+	code = togglevar(argc, argv, &progress, "Progress bar");
+	if (progress)
+		hash = 0;
+}
+
+/*
+ * Turn on interactive prompting during mget, mput, and mdelete.
+ */
+/*VARARGS*/
+void
+setprompt(int argc, char *argv[])
+{
+
+	code = togglevar(argc, argv, &interactive, "Interactive mode");
+}
+
+/*
+ * Toggle gate-ftp mode, or set gate-ftp server
+ */
+/*VARARGS*/
+void
+setgate(int argc, char *argv[])
+{
+	static char gsbuf[MAXHOSTNAMELEN];
+
+	if (argc == 0 || argc > 3) {
+		UPRINTF(
+		    "usage: %s [ on | off | gateserver [port] ]\n", argv[0]);
+		code = -1;
+		return;
+	} else if (argc < 2) {
+		gatemode = !gatemode;
+	} else {
+		if (argc == 2 && strcasecmp(argv[1], "on") == 0)
+			gatemode = 1;
+		else if (argc == 2 && strcasecmp(argv[1], "off") == 0)
+			gatemode = 0;
+		else {
+			if (argc == 3)
+				gateport = ftp_strdup(argv[2]);
+			(void)strlcpy(gsbuf, argv[1], sizeof(gsbuf));
+			gateserver = gsbuf;
+			gatemode = 1;
+		}
+	}
+	if (gatemode && (gateserver == NULL || *gateserver == '\0')) {
+		fprintf(ttyout,
+		    "Disabling gate-ftp mode - no gate-ftp server defined.\n");
+		gatemode = 0;
+	} else {
+		fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n",
+		    onoff(gatemode), *gateserver ? gateserver : "(none)",
+		    gateport);
+	}
+	code = gatemode;
+}
+
+/*
+ * Toggle metacharacter interpretation on local file names.
+ */
+/*VARARGS*/
+void
+setglob(int argc, char *argv[])
+{
+
+	code = togglevar(argc, argv, &doglob, "Globbing");
+}
+
+/*
+ * Toggle preserving modification times on retrieved files.
+ */
+/*VARARGS*/
+void
+setpreserve(int argc, char *argv[])
+{
+
+	code = togglevar(argc, argv, &preserve, "Preserve modification times");
+}
+
+/*
+ * Set debugging mode on/off and/or set level of debugging.
+ */
+/*VARARGS*/
+void
+setdebug(int argc, char *argv[])
+{
+	if (argc == 0 || argc > 2) {
+		UPRINTF("usage: %s [ on | off | debuglevel ]\n", argv[0]);
+		code = -1;
+		return;
+	} else if (argc == 2) {
+		if (strcasecmp(argv[1], "on") == 0)
+			ftp_debug = 1;
+		else if (strcasecmp(argv[1], "off") == 0)
+			ftp_debug = 0;
+		else {
+			int val;
+
+			val = strsuftoi(argv[1]);
+			if (val < 0) {
+				fprintf(ttyout, "%s: bad debugging value.\n",
+				    argv[1]);
+				code = -1;
+				return;
+			}
+			ftp_debug = val;
+		}
+	} else
+		ftp_debug = !ftp_debug;
+	if (ftp_debug)
+		options |= SO_DEBUG;
+	else
+		options &= ~SO_DEBUG;
+	fprintf(ttyout, "Debugging %s (ftp_debug=%d).\n", onoff(ftp_debug), ftp_debug);
+	code = ftp_debug > 0;
+}
+
+/*
+ * Set current working directory on remote machine.
+ */
+void
+cd(int argc, char *argv[])
+{
+	int r;
+
+	if (argc == 0 || argc > 2 ||
+	    (argc == 1 && !another(&argc, &argv, "remote-directory"))) {
+		UPRINTF("usage: %s remote-directory\n", argv[0]);
+		code = -1;
+		return;
+	}
+	r = command("CWD %s", argv[1]);
+	if (r == ERROR && code == 500) {
+		if (verbose)
+			fputs("CWD command not recognized, trying XCWD.\n",
+			    ttyout);
+		r = command("XCWD %s", argv[1]);
+	}
+	if (r == COMPLETE) {
+		dirchange = 1;
+		updateremotecwd();
+	}
+}
+
+/*
+ * Set current working directory on local machine.
+ */
+void
+lcd(int argc, char *argv[])
+{
+	char *locdir;
+
+	code = -1;
+	if (argc == 1) {
+		argc++;
+		argv[1] = localhome;
+	}
+	if (argc != 2) {
+		UPRINTF("usage: %s [local-directory]\n", argv[0]);
+		return;
+	}
+	if ((locdir = globulize(argv[1])) == NULL)
+		return;
+	if (chdir(locdir) == -1)
+		warn("Can't chdir `%s'", locdir);
+	else {
+		updatelocalcwd();
+		if (localcwd[0]) {
+			fprintf(ttyout, "Local directory now: %s\n", localcwd);
+			code = 0;
+		} else {
+			fprintf(ttyout, "Unable to determine local directory\n");
+		}
+	}
+	(void)free(locdir);
+}
+
+/*
+ * Delete a single file.
+ */
+void
+delete(int argc, char *argv[])
+{
+
+	if (argc == 0 || argc > 2 ||
+	    (argc == 1 && !another(&argc, &argv, "remote-file"))) {
+		UPRINTF("usage: %s remote-file\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (command("DELE %s", argv[1]) == COMPLETE)
+		dirchange = 1;
+}
+
+/*
+ * Delete multiple files.
+ */
+void
+mdelete(int argc, char *argv[])
+{
+	sigfunc oldintr;
+	int ointer;
+	char *cp;
+
+	if (argc == 0 ||
+	    (argc == 1 && !another(&argc, &argv, "remote-files"))) {
+		UPRINTF("usage: %s [remote-files]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	mflag = 1;
+	oldintr = xsignal(SIGINT, mintr);
+	if (sigsetjmp(jabort, 1))
+		mabort(argv[0]);
+	while ((cp = remglob(argv, 0, NULL)) != NULL) {
+		if (*cp == '\0') {
+			mflag = 0;
+			continue;
+		}
+		if (mflag && confirm(argv[0], cp)) {
+			if (command("DELE %s", cp) == COMPLETE)
+				dirchange = 1;
+			if (!mflag && fromatty) {
+				ointer = interactive;
+				interactive = 1;
+				if (confirm(argv[0], NULL)) {
+					mflag++;
+				}
+				interactive = ointer;
+			}
+		}
+	}
+	(void)xsignal(SIGINT, oldintr);
+	mflag = 0;
+}
+
+/*
+ * Rename a remote file.
+ */
+void
+renamefile(int argc, char *argv[])
+{
+
+	if (argc == 0 || (argc == 1 && !another(&argc, &argv, "from-name")))
+		goto usage;
+	if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
+ usage:
+		UPRINTF("usage: %s from-name to-name\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (command("RNFR %s", argv[1]) == CONTINUE &&
+	    command("RNTO %s", argv[2]) == COMPLETE)
+		dirchange = 1;
+}
+
+/*
+ * Get a directory listing of remote files.
+ * Supports being invoked as:
+ *	cmd		runs
+ *	---		----
+ *	dir, ls		LIST
+ *	mlsd		MLSD
+ *	nlist		NLST
+ *	pdir, pls	LIST |$PAGER
+ *	pmlsd		MLSD |$PAGER
+ */
+void
+ls(int argc, char *argv[])
+{
+	const char *cmd;
+	char *remdir, *locbuf;
+	const char *locfile;
+	int pagecmd, mlsdcmd;
+
+	remdir = NULL;
+	locbuf = NULL;
+	locfile = "-";
+	pagecmd = mlsdcmd = 0;
+			/*
+			 * the only commands that start with `p' are
+			 * the `pager' versions.
+			 */
+	if (argv[0][0] == 'p')
+		pagecmd = 1;
+	if (strcmp(argv[0] + pagecmd , "mlsd") == 0) {
+		if (! features[FEAT_MLST]) {
+			fprintf(ttyout,
+			   "MLSD is not supported by the remote server.\n");
+			return;
+		}
+		mlsdcmd = 1;
+	}
+	if (argc == 0)
+		goto usage;
+
+	if (mlsdcmd)
+		cmd = "MLSD";
+	else if (strcmp(argv[0] + pagecmd, "nlist") == 0)
+		cmd = "NLST";
+	else
+		cmd = "LIST";
+
+	if (argc > 1)
+		remdir = argv[1];
+	if (argc > 2)
+		locfile = argv[2];
+	if (argc > 3 || ((pagecmd | mlsdcmd) && argc > 2)) {
+ usage:
+		if (pagecmd || mlsdcmd)
+			UPRINTF("usage: %s [remote-path]\n", argv[0]);
+		else
+			UPRINTF("usage: %s [remote-path [local-file]]\n",
+			    argv[0]);
+		code = -1;
+		goto freels;
+	}
+
+	if (pagecmd) {
+		const char *p;
+		size_t len;
+
+		p = getoptionvalue("pager");
+		if (EMPTYSTRING(p))
+			p = DEFAULTPAGER;
+		len = strlen(p) + 2;
+		locbuf = ftp_malloc(len);
+		locbuf[0] = '|';
+		(void)strlcpy(locbuf + 1, p, len - 1);
+		locfile = locbuf;
+	} else if ((strcmp(locfile, "-") != 0) && *locfile != '|') {
+		if ((locbuf = globulize(locfile)) == NULL ||
+		    !confirm("output to local-file:", locbuf)) {
+			code = -1;
+			goto freels;
+		}
+		locfile = locbuf;
+	}
+	recvrequest(cmd, locfile, remdir, "w", 0, 0);
+ freels:
+	if (locbuf)
+		(void)free(locbuf);
+}
+
+/*
+ * Get a directory listing of multiple remote files.
+ */
+void
+mls(int argc, char *argv[])
+{
+	sigfunc oldintr;
+	int ointer, i;
+	int volatile dolist;
+	char * volatile dest, *odest;
+	const char *lmode;
+
+	if (argc == 0)
+		goto usage;
+	if (argc < 2 && !another(&argc, &argv, "remote-files"))
+		goto usage;
+	if (argc < 3 && !another(&argc, &argv, "local-file")) {
+ usage:
+		UPRINTF("usage: %s remote-files local-file\n", argv[0]);
+		code = -1;
+		return;
+	}
+	odest = dest = argv[argc - 1];
+	argv[argc - 1] = NULL;
+	if (strcmp(dest, "-") && *dest != '|')
+		if (((dest = globulize(dest)) == NULL) ||
+		    !confirm("output to local-file:", dest)) {
+			code = -1;
+			return;
+	}
+	dolist = strcmp(argv[0], "mls");
+	mflag = 1;
+	oldintr = xsignal(SIGINT, mintr);
+	if (sigsetjmp(jabort, 1))
+		mabort(argv[0]);
+	for (i = 1; mflag && i < argc-1 && connected; i++) {
+		lmode = (i == 1) ? "w" : "a";
+		recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], lmode,
+		    0, 0);
+		if (!mflag && fromatty) {
+			ointer = interactive;
+			interactive = 1;
+			if (confirm(argv[0], NULL)) {
+				mflag++;
+			}
+			interactive = ointer;
+		}
+	}
+	(void)xsignal(SIGINT, oldintr);
+	mflag = 0;
+	if (dest != odest)			/* free up after globulize() */
+		free(dest);
+}
+
+/*
+ * Do a shell escape
+ */
+/*ARGSUSED*/
+void
+shell(int argc, char *argv[])
+{
+	pid_t pid;
+	sigfunc oldintr;
+	char shellnam[MAXPATHLEN];
+	const char *shellp, *namep;
+	int wait_status;
+
+	if (argc == 0) {
+		UPRINTF("usage: %s [command [args]]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	oldintr = xsignal(SIGINT, SIG_IGN);
+	if ((pid = fork()) == 0) {
+		for (pid = 3; pid < 20; pid++)
+			(void)close(pid);
+		(void)xsignal(SIGINT, SIG_DFL);
+		shellp = getenv("SHELL");
+		if (shellp == NULL)
+			shellp = _PATH_BSHELL;
+		namep = strrchr(shellp, '/');
+		if (namep == NULL)
+			namep = shellp;
+		else
+			namep++;
+		(void)strlcpy(shellnam, namep, sizeof(shellnam));
+		if (ftp_debug) {
+			fputs(shellp, ttyout);
+			putc('\n', ttyout);
+		}
+		if (argc > 1) {
+			execl(shellp, shellnam, "-c", altarg, (char *)0);
+		}
+		else {
+			execl(shellp, shellnam, (char *)0);
+		}
+		warn("Can't execute `%s'", shellp);
+		code = -1;
+		exit(1);
+	}
+	if (pid > 0)
+		while (wait(&wait_status) != pid)
+			;
+	(void)xsignal(SIGINT, oldintr);
+	if (pid == -1) {
+		warn("Can't fork a subshell; try again later");
+		code = -1;
+	} else
+		code = 0;
+}
+
+/*
+ * Send new user information (re-login)
+ */
+void
+user(int argc, char *argv[])
+{
+	char *password;
+	char emptypass[] = "";
+	int n, aflag = 0;
+
+	if (argc == 0)
+		goto usage;
+	if (argc < 2)
+		(void)another(&argc, &argv, "username");
+	if (argc < 2 || argc > 4) {
+ usage:
+		UPRINTF("usage: %s username [password [account]]\n",
+		    argv[0]);
+		code = -1;
+		return;
+	}
+	n = command("USER %s", argv[1]);
+	if (n == CONTINUE) {
+		if (argc < 3) {
+			password = getpass("Password: ");
+			if (password == NULL)
+				password = emptypass;
+		} else {
+			password = argv[2];
+		}
+		n = command("PASS %s", password);
+		memset(password, 0, strlen(password));
+	}
+	if (n == CONTINUE) {
+		aflag++;
+		if (argc < 4) {
+			password = getpass("Account: ");
+			if (password == NULL)
+				password = emptypass;
+		} else {
+			password = argv[3];
+		}
+		n = command("ACCT %s", password);
+		memset(password, 0, strlen(password));
+	}
+	if (n != COMPLETE) {
+		fputs("Login failed.\n", ttyout);
+		return;
+	}
+	if (!aflag && argc == 4) {
+		password = argv[3];
+		(void)command("ACCT %s", password);
+		memset(password, 0, strlen(password));
+	}
+	connected = -1;
+	getremoteinfo();
+}
+
+/*
+ * Print working directory on remote machine.
+ */
+/*VARARGS*/
+void
+pwd(int argc, char *argv[])
+{
+
+	code = -1;
+	if (argc != 1) {
+		UPRINTF("usage: %s\n", argv[0]);
+		return;
+	}
+	if (! remotecwd[0])
+		updateremotecwd();
+	if (! remotecwd[0])
+		fprintf(ttyout, "Unable to determine remote directory\n");
+	else {
+		fprintf(ttyout, "Remote directory: %s\n", remotecwd);
+		code = 0;
+	}
+}
+
+/*
+ * Print working directory on local machine.
+ */
+void
+lpwd(int argc, char *argv[])
+{
+
+	code = -1;
+	if (argc != 1) {
+		UPRINTF("usage: %s\n", argv[0]);
+		return;
+	}
+	if (! localcwd[0])
+		updatelocalcwd();
+	if (! localcwd[0])
+		fprintf(ttyout, "Unable to determine local directory\n");
+	else {
+		fprintf(ttyout, "Local directory: %s\n", localcwd);
+		code = 0;
+	}
+}
+
+/*
+ * Make a directory.
+ */
+void
+makedir(int argc, char *argv[])
+{
+	int r;
+
+	if (argc == 0 || argc > 2 ||
+	    (argc == 1 && !another(&argc, &argv, "directory-name"))) {
+		UPRINTF("usage: %s directory-name\n", argv[0]);
+		code = -1;
+		return;
+	}
+	r = command("MKD %s", argv[1]);
+	if (r == ERROR && code == 500) {
+		if (verbose)
+			fputs("MKD command not recognized, trying XMKD.\n",
+			    ttyout);
+		r = command("XMKD %s", argv[1]);
+	}
+	if (r == COMPLETE)
+		dirchange = 1;
+}
+
+/*
+ * Remove a directory.
+ */
+void
+removedir(int argc, char *argv[])
+{
+	int r;
+
+	if (argc == 0 || argc > 2 ||
+	    (argc == 1 && !another(&argc, &argv, "directory-name"))) {
+		UPRINTF("usage: %s directory-name\n", argv[0]);
+		code = -1;
+		return;
+	}
+	r = command("RMD %s", argv[1]);
+	if (r == ERROR && code == 500) {
+		if (verbose)
+			fputs("RMD command not recognized, trying XRMD.\n",
+			    ttyout);
+		r = command("XRMD %s", argv[1]);
+	}
+	if (r == COMPLETE)
+		dirchange = 1;
+}
+
+/*
+ * Send a line, verbatim, to the remote machine.
+ */
+void
+quote(int argc, char *argv[])
+{
+
+	if (argc == 0 ||
+	    (argc == 1 && !another(&argc, &argv, "command line to send"))) {
+		UPRINTF("usage: %s line-to-send\n", argv[0]);
+		code = -1;
+		return;
+	}
+	quote1("", argc, argv);
+}
+
+/*
+ * Send a SITE command to the remote machine.  The line
+ * is sent verbatim to the remote machine, except that the
+ * word "SITE" is added at the front.
+ */
+void
+site(int argc, char *argv[])
+{
+
+	if (argc == 0 ||
+	    (argc == 1 && !another(&argc, &argv, "arguments to SITE command"))){
+		UPRINTF("usage: %s line-to-send\n", argv[0]);
+		code = -1;
+		return;
+	}
+	quote1("SITE ", argc, argv);
+}
+
+/*
+ * Turn argv[1..argc) into a space-separated string, then prepend initial text.
+ * Send the result as a one-line command and get response.
+ */
+void
+quote1(const char *initial, int argc, char *argv[])
+{
+	int i;
+	char buf[BUFSIZ];		/* must be >= sizeof(line) */
+
+	(void)strlcpy(buf, initial, sizeof(buf));
+	for (i = 1; i < argc; i++) {
+		(void)strlcat(buf, argv[i], sizeof(buf));
+		if (i < (argc - 1))
+			(void)strlcat(buf, " ", sizeof(buf));
+	}
+	if (command("%s", buf) == PRELIM) {
+		while (getreply(0) == PRELIM)
+			continue;
+	}
+	dirchange = 1;
+}
+
+void
+do_chmod(int argc, char *argv[])
+{
+
+	if (argc == 0 || (argc == 1 && !another(&argc, &argv, "mode")))
+		goto usage;
+	if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
+ usage:
+		UPRINTF("usage: %s mode remote-file\n", argv[0]);
+		code = -1;
+		return;
+	}
+	(void)command("SITE CHMOD %s %s", argv[1], argv[2]);
+}
+
+#define COMMAND_1ARG(argc, argv, cmd)			\
+	if (argc == 1)					\
+		command(cmd);				\
+	else						\
+		command(cmd " %s", argv[1])
+
+void
+do_umask(int argc, char *argv[])
+{
+	int oldverbose = verbose;
+
+	if (argc == 0) {
+		UPRINTF("usage: %s [umask]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	verbose = 1;
+	COMMAND_1ARG(argc, argv, "SITE UMASK");
+	verbose = oldverbose;
+}
+
+void
+idlecmd(int argc, char *argv[])
+{
+	int oldverbose = verbose;
+
+	if (argc < 1 || argc > 2) {
+		UPRINTF("usage: %s [seconds]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	verbose = 1;
+	COMMAND_1ARG(argc, argv, "SITE IDLE");
+	verbose = oldverbose;
+}
+
+/*
+ * Ask the other side for help.
+ */
+void
+rmthelp(int argc, char *argv[])
+{
+	int oldverbose = verbose;
+
+	if (argc == 0) {
+		UPRINTF("usage: %s\n", argv[0]);
+		code = -1;
+		return;
+	}
+	verbose = 1;
+	COMMAND_1ARG(argc, argv, "HELP");
+	verbose = oldverbose;
+}
+
+/*
+ * Terminate session and exit.
+ * May be called with 0, NULL.
+ */
+/*VARARGS*/
+void
+quit(int argc, char *argv[])
+{
+
+			/* this may be called with argc == 0, argv == NULL */
+	if (argc == 0 && argv != NULL) {
+		UPRINTF("usage: %s\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (connected)
+		disconnect(0, NULL);
+	pswitch(1);
+	if (connected)
+		disconnect(0, NULL);
+	exit(0);
+}
+
+/*
+ * Terminate session, but don't exit.
+ * May be called with 0, NULL.
+ */
+void
+disconnect(int argc, char *argv[])
+{
+
+			/* this may be called with argc == 0, argv == NULL */
+	if (argc == 0 && argv != NULL) {
+		UPRINTF("usage: %s\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (!connected)
+		return;
+	(void)command("QUIT");
+	cleanuppeer();
+}
+
+void
+account(int argc, char *argv[])
+{
+	char *ap;
+	char emptypass[] = "";
+
+	if (argc == 0 || argc > 2) {
+		UPRINTF("usage: %s [password]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	else if (argc == 2)
+		ap = argv[1];
+	else {
+		ap = getpass("Account:");
+		if (ap == NULL)
+			ap = emptypass;
+	}
+	(void)command("ACCT %s", ap);
+	memset(ap, 0, strlen(ap));
+}
+
+sigjmp_buf abortprox;
+
+void
+proxabort(int notused)
+{
+
+	sigint_raised = 1;
+	alarmtimer(0);
+	if (!proxy) {
+		pswitch(1);
+	}
+	if (connected) {
+		proxflag = 1;
+	}
+	else {
+		proxflag = 0;
+	}
+	pswitch(0);
+	siglongjmp(abortprox, 1);
+}
+
+void
+doproxy(int argc, char *argv[])
+{
+	struct cmd *c;
+	int cmdpos;
+	sigfunc oldintr;
+	char cmdbuf[MAX_C_NAME];
+
+	if (argc == 0 || (argc == 1 && !another(&argc, &argv, "command"))) {
+		UPRINTF("usage: %s command\n", argv[0]);
+		code = -1;
+		return;
+	}
+	c = getcmd(argv[1]);
+	if (c == (struct cmd *) -1) {
+		fputs("?Ambiguous command.\n", ttyout);
+		code = -1;
+		return;
+	}
+	if (c == 0) {
+		fputs("?Invalid command.\n", ttyout);
+		code = -1;
+		return;
+	}
+	if (!c->c_proxy) {
+		fputs("?Invalid proxy command.\n", ttyout);
+		code = -1;
+		return;
+	}
+	if (sigsetjmp(abortprox, 1)) {
+		code = -1;
+		return;
+	}
+	oldintr = xsignal(SIGINT, proxabort);
+	pswitch(1);
+	if (c->c_conn && !connected) {
+		fputs("Not connected.\n", ttyout);
+		pswitch(0);
+		(void)xsignal(SIGINT, oldintr);
+		code = -1;
+		return;
+	}
+	cmdpos = strcspn(line, " \t");
+	if (cmdpos > 0)		/* remove leading "proxy " from input buffer */
+		memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
+	(void)strlcpy(cmdbuf, c->c_name, sizeof(cmdbuf));
+	argv[1] = cmdbuf;
+	(*c->c_handler)(argc-1, argv+1);
+	if (connected) {
+		proxflag = 1;
+	}
+	else {
+		proxflag = 0;
+	}
+	pswitch(0);
+	(void)xsignal(SIGINT, oldintr);
+}
+
+void
+setcase(int argc, char *argv[])
+{
+
+	code = togglevar(argc, argv, &mcase, "Case mapping");
+}
+
+/*
+ * convert the given name to lower case if it's all upper case, into
+ * a static buffer which is returned to the caller
+ */
+static const char *
+docase(char *dst, size_t dlen, const char *src)
+{
+	size_t i;
+	int dochange = 1;
+
+	for (i = 0; src[i] != '\0' && i < dlen - 1; i++) {
+		dst[i] = src[i];
+		if (islower((unsigned char)dst[i]))
+			dochange = 0;
+	}
+	dst[i] = '\0';
+
+	if (dochange) {
+		for (i = 0; dst[i] != '\0'; i++)
+			if (isupper((unsigned char)dst[i]))
+				dst[i] = tolower((unsigned char)dst[i]);
+	}
+	return dst;
+}
+
+void
+setcr(int argc, char *argv[])
+{
+
+	code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
+}
+
+void
+setntrans(int argc, char *argv[])
+{
+
+	if (argc == 0 || argc > 3) {
+		UPRINTF("usage: %s [inchars [outchars]]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (argc == 1) {
+		ntflag = 0;
+		fputs("Ntrans off.\n", ttyout);
+		code = ntflag;
+		return;
+	}
+	ntflag++;
+	code = ntflag;
+	(void)strlcpy(ntin, argv[1], sizeof(ntin));
+	if (argc == 2) {
+		ntout[0] = '\0';
+		return;
+	}
+	(void)strlcpy(ntout, argv[2], sizeof(ntout));
+}
+
+static const char *
+dotrans(char *dst, size_t dlen, const char *src)
+{
+	const char *cp1;
+	char *cp2 = dst;
+	size_t i, ostop;
+
+	for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
+		continue;
+	for (cp1 = src; *cp1; cp1++) {
+		int found = 0;
+		for (i = 0; *(ntin + i) && i < 16; i++) {
+			if (*cp1 == *(ntin + i)) {
+				found++;
+				if (i < ostop) {
+					*cp2++ = *(ntout + i);
+					if (cp2 - dst >= (ptrdiff_t)(dlen - 1))
+						goto out;
+				}
+				break;
+			}
+		}
+		if (!found) {
+			*cp2++ = *cp1;
+		}
+	}
+out:
+	*cp2 = '\0';
+	return dst;
+}
+
+void
+setnmap(int argc, char *argv[])
+{
+	char *cp;
+
+	if (argc == 1) {
+		mapflag = 0;
+		fputs("Nmap off.\n", ttyout);
+		code = mapflag;
+		return;
+	}
+	if (argc == 0 ||
+	    (argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) {
+		UPRINTF("usage: %s [mapin mapout]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	mapflag = 1;
+	code = 1;
+	cp = strchr(altarg, ' ');
+	if (proxy) {
+		while(*++cp == ' ')
+			continue;
+		altarg = cp;
+		cp = strchr(altarg, ' ');
+	}
+	*cp = '\0';
+	(void)strlcpy(mapin, altarg, MAXPATHLEN);
+	while (*++cp == ' ')
+		continue;
+	(void)strlcpy(mapout, cp, MAXPATHLEN);
+}
+
+static const char *
+domap(char *dst, size_t dlen, const char *src)
+{
+	const char *cp1 = src;
+	char *cp2 = mapin;
+	const char *tp[9], *te[9];
+	int i, toks[9], toknum = 0, match = 1;
+
+	for (i=0; i < 9; ++i) {
+		toks[i] = 0;
+	}
+	while (match && *cp1 && *cp2) {
+		switch (*cp2) {
+			case '\\':
+				if (*++cp2 != *cp1) {
+					match = 0;
+				}
+				break;
+			case '$':
+				if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
+					if (*cp1 != *(++cp2+1)) {
+						toks[toknum = *cp2 - '1']++;
+						tp[toknum] = cp1;
+						while (*++cp1 && *(cp2+1)
+							!= *cp1);
+						te[toknum] = cp1;
+					}
+					cp2++;
+					break;
+				}
+				/* FALLTHROUGH */
+			default:
+				if (*cp2 != *cp1) {
+					match = 0;
+				}
+				break;
+		}
+		if (match && *cp1) {
+			cp1++;
+		}
+		if (match && *cp2) {
+			cp2++;
+		}
+	}
+	if (!match && *cp1) /* last token mismatch */
+	{
+		toks[toknum] = 0;
+	}
+	cp2 = dst;
+	*cp2 = '\0';
+	cp1 = mapout;
+	while (*cp1) {
+		match = 0;
+		switch (*cp1) {
+			case '\\':
+				if (*(cp1 + 1)) {
+					*cp2++ = *++cp1;
+				}
+				break;
+			case '[':
+LOOP:
+				if (*++cp1 == '$' &&
+				    isdigit((unsigned char)*(cp1+1))) {
+					if (*++cp1 == '0') {
+						const char *cp3 = src;
+
+						while (*cp3) {
+							*cp2++ = *cp3++;
+						}
+						match = 1;
+					}
+					else if (toks[toknum = *cp1 - '1']) {
+						const char *cp3 = tp[toknum];
+
+						while (cp3 != te[toknum]) {
+							*cp2++ = *cp3++;
+						}
+						match = 1;
+					}
+				}
+				else {
+					while (*cp1 && *cp1 != ',' &&
+					    *cp1 != ']') {
+						if (*cp1 == '\\') {
+							cp1++;
+						}
+						else if (*cp1 == '$' &&
+						    isdigit((unsigned char)*(cp1+1))) {
+							if (*++cp1 == '0') {
+							   const char *cp3 = src;
+
+							   while (*cp3) {
+								*cp2++ = *cp3++;
+							   }
+							}
+							else if (toks[toknum =
+							    *cp1 - '1']) {
+							   const char *cp3=tp[toknum];
+
+							   while (cp3 !=
+								  te[toknum]) {
+								*cp2++ = *cp3++;
+							   }
+							}
+						}
+						else if (*cp1) {
+							*cp2++ = *cp1++;
+						}
+					}
+					if (!*cp1) {
+						fputs(
+						"nmap: unbalanced brackets.\n",
+						    ttyout);
+						return (src);
+					}
+					match = 1;
+					cp1--;
+				}
+				if (match) {
+					while (*++cp1 && *cp1 != ']') {
+					      if (*cp1 == '\\' && *(cp1 + 1)) {
+							cp1++;
+					      }
+					}
+					if (!*cp1) {
+						fputs(
+						"nmap: unbalanced brackets.\n",
+						    ttyout);
+						return (src);
+					}
+					break;
+				}
+				switch (*++cp1) {
+					case ',':
+						goto LOOP;
+					case ']':
+						break;
+					default:
+						cp1--;
+						goto LOOP;
+				}
+				break;
+			case '$':
+				if (isdigit((unsigned char)*(cp1 + 1))) {
+					if (*++cp1 == '0') {
+						const char *cp3 = src;
+
+						while (*cp3) {
+							*cp2++ = *cp3++;
+						}
+					}
+					else if (toks[toknum = *cp1 - '1']) {
+						const char *cp3 = tp[toknum];
+
+						while (cp3 != te[toknum]) {
+							*cp2++ = *cp3++;
+						}
+					}
+					break;
+				}
+				/* intentional drop through */
+			default:
+				*cp2++ = *cp1;
+				break;
+		}
+		cp1++;
+	}
+	*cp2 = '\0';
+	return *dst ? dst : src;
+}
+
+void
+setpassive(int argc, char *argv[])
+{
+
+	if (argc == 1) {
+		passivemode = !passivemode;
+		activefallback = passivemode;
+	} else if (argc != 2) {
+ passiveusage:
+		UPRINTF("usage: %s [ on | off | auto ]\n", argv[0]);
+		code = -1;
+		return;
+	} else if (strcasecmp(argv[1], "on") == 0) {
+		passivemode = 1;
+		activefallback = 0;
+	} else if (strcasecmp(argv[1], "off") == 0) {
+		passivemode = 0;
+		activefallback = 0;
+	} else if (strcasecmp(argv[1], "auto") == 0) {
+		passivemode = 1;
+		activefallback = 1;
+	} else
+		goto passiveusage;
+	fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n",
+	    onoff(passivemode), onoff(activefallback));
+	code = passivemode;
+}
+
+
+void
+setepsv4(int argc, char *argv[])
+{
+	code = togglevar(argc, argv, &epsv4,
+	    verbose ? "EPSV/EPRT on IPv4" : NULL);
+	epsv4bad = 0;
+}
+
+void
+setepsv6(int argc, char *argv[])
+{
+	code = togglevar(argc, argv, &epsv6,
+	    verbose ? "EPSV/EPRT on IPv6" : NULL);
+	epsv6bad = 0;
+}
+
+void
+setepsv(int argc, char*argv[])
+{
+	setepsv4(argc,argv);
+	setepsv6(argc,argv);
+}
+
+void
+setsunique(int argc, char *argv[])
+{
+
+	code = togglevar(argc, argv, &sunique, "Store unique");
+}
+
+void
+setrunique(int argc, char *argv[])
+{
+
+	code = togglevar(argc, argv, &runique, "Receive unique");
+}
+
+int
+parserate(int argc, char *argv[], int cmdlineopt)
+{
+	int dir, max, incr, showonly;
+	sigfunc oldusr1, oldusr2;
+
+	if (argc > 4 || (argc < (cmdlineopt ? 3 : 2))) {
+ usage:
+		if (cmdlineopt)
+			UPRINTF(
+	"usage: %s (all|get|put),maximum-bytes[,increment-bytes]]\n",
+			    argv[0]);
+		else
+			UPRINTF(
+	"usage: %s (all|get|put) [maximum-bytes [increment-bytes]]\n",
+			    argv[0]);
+		return -1;
+	}
+	dir = max = incr = showonly = 0;
+#define	RATE_GET	1
+#define	RATE_PUT	2
+#define	RATE_ALL	(RATE_GET | RATE_PUT)
+
+	if (strcasecmp(argv[1], "all") == 0)
+		dir = RATE_ALL;
+	else if (strcasecmp(argv[1], "get") == 0)
+		dir = RATE_GET;
+	else if (strcasecmp(argv[1], "put") == 0)
+		dir = RATE_PUT;
+	else
+		goto usage;
+
+	if (argc >= 3) {
+		if ((max = strsuftoi(argv[2])) < 0)
+			goto usage;
+	} else
+		showonly = 1;
+
+	if (argc == 4) {
+		if ((incr = strsuftoi(argv[3])) <= 0)
+			goto usage;
+	} else
+		incr = DEFAULTINCR;
+
+	oldusr1 = xsignal(SIGUSR1, SIG_IGN);
+	oldusr2 = xsignal(SIGUSR2, SIG_IGN);
+	if (dir & RATE_GET) {
+		if (!showonly) {
+			rate_get = max;
+			rate_get_incr = incr;
+		}
+		if (!cmdlineopt || verbose)
+			fprintf(ttyout,
+		"Get transfer rate throttle: %s; maximum: %d; increment %d.\n",
+			    onoff(rate_get), rate_get, rate_get_incr);
+	}
+	if (dir & RATE_PUT) {
+		if (!showonly) {
+			rate_put = max;
+			rate_put_incr = incr;
+		}
+		if (!cmdlineopt || verbose)
+			fprintf(ttyout,
+		"Put transfer rate throttle: %s; maximum: %d; increment %d.\n",
+			    onoff(rate_put), rate_put, rate_put_incr);
+	}
+	(void)xsignal(SIGUSR1, oldusr1);
+	(void)xsignal(SIGUSR2, oldusr2);
+	return 0;
+}
+
+void
+setrate(int argc, char *argv[])
+{
+
+	code = parserate(argc, argv, 0);
+}
+
+/* change directory to parent directory */
+void
+cdup(int argc, char *argv[])
+{
+	int r;
+
+	if (argc == 0) {
+		UPRINTF("usage: %s\n", argv[0]);
+		code = -1;
+		return;
+	}
+	r = command("CDUP");
+	if (r == ERROR && code == 500) {
+		if (verbose)
+			fputs("CDUP command not recognized, trying XCUP.\n",
+			    ttyout);
+		r = command("XCUP");
+	}
+	if (r == COMPLETE) {
+		dirchange = 1;
+		updateremotecwd();
+	}
+}
+
+/*
+ * Restart transfer at specific point
+ */
+void
+restart(int argc, char *argv[])
+{
+
+	if (argc == 0 || argc > 2) {
+		UPRINTF("usage: %s [restart-point]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (! features[FEAT_REST_STREAM]) {
+		fprintf(ttyout,
+		    "Restart is not supported by the remote server.\n");
+		return;
+	}
+	if (argc == 2) {
+		off_t rp;
+		char *ep;
+
+		rp = STRTOLL(argv[1], &ep, 10);
+		if (rp < 0 || *ep != '\0')
+			fprintf(ttyout, "restart: Invalid offset `%s'\n",
+			    argv[1]);
+		else
+			restart_point = rp;
+	}
+	if (restart_point == 0)
+		fputs("No restart point defined.\n", ttyout);
+	else
+		fprintf(ttyout,
+		    "Restarting at " LLF " for next get, put or append\n",
+		    (LLT)restart_point);
+}
+
+/*
+ * Show remote system type
+ */
+void
+syst(int argc, char *argv[])
+{
+	int oldverbose = verbose;
+
+	if (argc == 0) {
+		UPRINTF("usage: %s\n", argv[0]);
+		code = -1;
+		return;
+	}
+	verbose = 1;	/* If we aren't verbose, this doesn't do anything! */
+	(void)command("SYST");
+	verbose = oldverbose;
+}
+
+void
+macdef(int argc, char *argv[])
+{
+	char *tmp;
+	int c;
+
+	if (argc == 0)
+		goto usage;
+	if (macnum == 16) {
+		fputs("Limit of 16 macros have already been defined.\n",
+		    ttyout);
+		code = -1;
+		return;
+	}
+	if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) {
+ usage:
+		UPRINTF("usage: %s macro_name\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (interactive)
+		fputs(
+		"Enter macro line by line, terminating it with a null line.\n",
+		    ttyout);
+	(void)strlcpy(macros[macnum].mac_name, argv[1],
+	    sizeof(macros[macnum].mac_name));
+	if (macnum == 0)
+		macros[macnum].mac_start = macbuf;
+	else
+		macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
+	tmp = macros[macnum].mac_start;
+	while (tmp != macbuf+4096) {
+		if ((c = getchar()) == EOF) {
+			fputs("macdef: end of file encountered.\n", ttyout);
+			code = -1;
+			return;
+		}
+		if ((*tmp = c) == '\n') {
+			if (tmp == macros[macnum].mac_start) {
+				macros[macnum++].mac_end = tmp;
+				code = 0;
+				return;
+			}
+			if (*(tmp-1) == '\0') {
+				macros[macnum++].mac_end = tmp - 1;
+				code = 0;
+				return;
+			}
+			*tmp = '\0';
+		}
+		tmp++;
+	}
+	while (1) {
+		while ((c = getchar()) != '\n' && c != EOF)
+			/* LOOP */;
+		if (c == EOF || getchar() == '\n') {
+			fputs("Macro not defined - 4K buffer exceeded.\n",
+			    ttyout);
+			code = -1;
+			return;
+		}
+	}
+}
+
+/*
+ * Get size of file on remote machine
+ */
+void
+sizecmd(int argc, char *argv[])
+{
+	off_t size;
+
+	if (argc == 0 || argc > 2 ||
+	    (argc == 1 && !another(&argc, &argv, "remote-file"))) {
+		UPRINTF("usage: %s remote-file\n", argv[0]);
+		code = -1;
+		return;
+	}
+	size = remotesize(argv[1], 1);
+	if (size != -1)
+		fprintf(ttyout,
+		    "%s\t" LLF "\n", argv[1], (LLT)size);
+	code = (size > 0);
+}
+
+/*
+ * Get last modification time of file on remote machine
+ */
+void
+modtime(int argc, char *argv[])
+{
+	time_t mtime;
+
+	if (argc == 0 || argc > 2 ||
+	    (argc == 1 && !another(&argc, &argv, "remote-file"))) {
+		UPRINTF("usage: %s remote-file\n", argv[0]);
+		code = -1;
+		return;
+	}
+	mtime = remotemodtime(argv[1], 1);
+	if (mtime != -1)
+		fprintf(ttyout, "%s\t%s", argv[1],
+		    rfc2822time(localtime(&mtime)));
+	code = (mtime > 0);
+}
+
+/*
+ * Show status on remote machine
+ */
+void
+rmtstatus(int argc, char *argv[])
+{
+
+	if (argc == 0) {
+		UPRINTF("usage: %s [remote-file]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	COMMAND_1ARG(argc, argv, "STAT");
+}
+
+/*
+ * Get file if modtime is more recent than current file
+ */
+void
+newer(int argc, char *argv[])
+{
+
+	if (getit(argc, argv, -1, "w"))
+		fprintf(ttyout,
+		    "Local file \"%s\" is newer than remote file \"%s\".\n",
+		    argv[2], argv[1]);
+}
+
+/*
+ * Display one local file through $PAGER.
+ */
+void
+lpage(int argc, char *argv[])
+{
+	size_t len;
+	const char *p;
+	char *pager, *locfile;
+
+	if (argc == 0 || argc > 2 ||
+	    (argc == 1 && !another(&argc, &argv, "local-file"))) {
+		UPRINTF("usage: %s local-file\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if ((locfile = globulize(argv[1])) == NULL) {
+		code = -1;
+		return;
+	}
+	p = getoptionvalue("pager");
+	if (EMPTYSTRING(p))
+		p = DEFAULTPAGER;
+	len = strlen(p) + strlen(locfile) + 2;
+	pager = ftp_malloc(len);
+	(void)strlcpy(pager, p,		len);
+	(void)strlcat(pager, " ",	len);
+	(void)strlcat(pager, locfile,	len);
+	system(pager);
+	code = 0;
+	(void)free(pager);
+	(void)free(locfile);
+}
+
+/*
+ * Display one remote file through $PAGER.
+ */
+void
+page(int argc, char *argv[])
+{
+	int ohash, orestart_point, overbose;
+	size_t len;
+	const char *p;
+	char *pager;
+
+	if (argc == 0 || argc > 2 ||
+	    (argc == 1 && !another(&argc, &argv, "remote-file"))) {
+		UPRINTF("usage: %s remote-file\n", argv[0]);
+		code = -1;
+		return;
+	}
+	p = getoptionvalue("pager");
+	if (EMPTYSTRING(p))
+		p = DEFAULTPAGER;
+	len = strlen(p) + 2;
+	pager = ftp_malloc(len);
+	pager[0] = '|';
+	(void)strlcpy(pager + 1, p, len - 1);
+
+	ohash = hash;
+	orestart_point = restart_point;
+	overbose = verbose;
+	hash = restart_point = verbose = 0;
+	recvrequest("RETR", pager, argv[1], "r+", 1, 0);
+	hash = ohash;
+	restart_point = orestart_point;
+	verbose = overbose;
+	(void)free(pager);
+}
+
+/*
+ * Set the socket send or receive buffer size.
+ */
+void
+setxferbuf(int argc, char *argv[])
+{
+	int size, dir;
+
+	if (argc != 2) {
+ usage:
+		UPRINTF("usage: %s size\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (strcasecmp(argv[0], "sndbuf") == 0)
+		dir = RATE_PUT;
+	else if (strcasecmp(argv[0], "rcvbuf") == 0)
+		dir = RATE_GET;
+	else if (strcasecmp(argv[0], "xferbuf") == 0)
+		dir = RATE_ALL;
+	else
+		goto usage;
+
+	if ((size = strsuftoi(argv[1])) == -1)
+		goto usage;
+
+	if (size == 0) {
+		fprintf(ttyout, "%s: size must be positive.\n", argv[0]);
+		goto usage;
+	}
+
+	if (dir & RATE_PUT)
+		sndbuf_size = size;
+	if (dir & RATE_GET)
+		rcvbuf_size = size;
+	fprintf(ttyout, "Socket buffer sizes: send %d, receive %d.\n",
+	    sndbuf_size, rcvbuf_size);
+	code = 0;
+}
+
+/*
+ * Set or display options (defaults are provided by various env vars)
+ */
+void
+setoption(int argc, char *argv[])
+{
+	struct option *o;
+
+	code = -1;
+	if (argc == 0 || (argc != 1 && argc != 3)) {
+		UPRINTF("usage: %s [option value]\n", argv[0]);
+		return;
+	}
+
+#define	OPTIONINDENT ((int) sizeof("http_proxy"))
+	if (argc == 1) {
+		for (o = optiontab; o->name != NULL; o++) {
+			fprintf(ttyout, "%-*s\t%s\n", OPTIONINDENT,
+			    o->name, o->value ? o->value : "");
+		}
+	} else {
+		set_option(argv[1], argv[2], 1);
+	}
+	code = 0;
+}
+
+void
+set_option(const char * option, const char * value, int doverbose)
+{
+	struct option *o;
+
+	o = getoption(option);
+	if (o == NULL) {
+		fprintf(ttyout, "No such option `%s'.\n", option);
+		return;
+	}
+	FREEPTR(o->value);
+	o->value = ftp_strdup(value);
+	if (verbose && doverbose)
+		fprintf(ttyout, "Setting `%s' to `%s'.\n",
+		    o->name, o->value);
+}
+
+/*
+ * Unset an option
+ */
+void
+unsetoption(int argc, char *argv[])
+{
+	struct option *o;
+
+	code = -1;
+	if (argc == 0 || argc != 2) {
+		UPRINTF("usage: %s option\n", argv[0]);
+		return;
+	}
+
+	o = getoption(argv[1]);
+	if (o == NULL) {
+		fprintf(ttyout, "No such option `%s'.\n", argv[1]);
+		return;
+	}
+	FREEPTR(o->value);
+	fprintf(ttyout, "Unsetting `%s'.\n", o->name);
+	code = 0;
+}
+
+/*
+ * Display features supported by the remote host.
+ */
+void
+feat(int argc, char *argv[])
+{
+	int oldverbose = verbose;
+
+	if (argc == 0) {
+		UPRINTF("usage: %s\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (! features[FEAT_FEAT]) {
+		fprintf(ttyout,
+		    "FEAT is not supported by the remote server.\n");
+		return;
+	}
+	verbose = 1;	/* If we aren't verbose, this doesn't do anything! */
+	(void)command("FEAT");
+	verbose = oldverbose;
+}
+
+void
+mlst(int argc, char *argv[])
+{
+	int oldverbose = verbose;
+
+	if (argc < 1 || argc > 2) {
+		UPRINTF("usage: %s [remote-path]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (! features[FEAT_MLST]) {
+		fprintf(ttyout,
+		    "MLST is not supported by the remote server.\n");
+		return;
+	}
+	verbose = 1;	/* If we aren't verbose, this doesn't do anything! */
+	COMMAND_1ARG(argc, argv, "MLST");
+	verbose = oldverbose;
+}
+
+void
+opts(int argc, char *argv[])
+{
+	int oldverbose = verbose;
+
+	if (argc < 2 || argc > 3) {
+		UPRINTF("usage: %s command [options]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (! features[FEAT_FEAT]) {
+		fprintf(ttyout,
+		    "OPTS is not supported by the remote server.\n");
+		return;
+	}
+	verbose = 1;	/* If we aren't verbose, this doesn't do anything! */
+	if (argc == 2)
+		command("OPTS %s", argv[1]);
+	else
+		command("OPTS %s %s", argv[1], argv[2]);
+	verbose = oldverbose;
+}

Added: vendor/NetBSD/tnftp/20100108/src/cmdtab.c
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/cmdtab.c	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/cmdtab.c	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,314 @@
+/*	$NetBSD: cmdtab.c,v 1.11 2009/05/20 12:53:47 lukem Exp $	*/
+/*	from	NetBSD: cmdtab.c,v 1.51 2009/04/12 10:18:52 lukem Exp	*/
+
+/*-
+ * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1985, 1989, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "tnftp.h"
+
+#if 0	/* tnftp */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cmdtab.c	8.4 (Berkeley) 10/9/94";
+#else
+__RCSID(" NetBSD: cmdtab.c,v 1.51 2009/04/12 10:18:52 lukem Exp  ");
+#endif
+#endif /* not lint */
+
+#include <stdio.h>
+
+#endif	/* tnftp */
+
+#include "ftp_var.h"
+
+/*
+ * User FTP -- Command Tables.
+ */
+
+#define HSTR	static const char
+
+#ifndef NO_HELP
+HSTR	accounthelp[] =	"send account command to remote server";
+HSTR	appendhelp[] =	"append to a file";
+HSTR	asciihelp[] =	"set ascii transfer type";
+HSTR	beephelp[] =	"beep when command completed";
+HSTR	binaryhelp[] =	"set binary transfer type";
+HSTR	casehelp[] =	"toggle mget upper/lower case id mapping";
+HSTR	cdhelp[] =	"change remote working directory";
+HSTR	cduphelp[] =	"change remote working directory to parent directory";
+HSTR	chmodhelp[] =	"change file permissions of remote file";
+HSTR	connecthelp[] =	"connect to remote ftp server";
+HSTR	crhelp[] =	"toggle carriage return stripping on ascii gets";
+HSTR	debughelp[] =	"toggle/set debugging mode";
+HSTR	deletehelp[] =	"delete remote file";
+HSTR	disconhelp[] =	"terminate ftp session";
+HSTR	domachelp[] =	"execute macro";
+HSTR	edithelp[] =	"toggle command line editing";
+HSTR	epsvhelp[] =	"toggle use of EPSV/EPRT on both IPv4 and IPV6 ftp";
+HSTR	epsv4help[] =	"toggle use of EPSV/EPRT on IPv4 ftp";
+HSTR	epsv6help[] =	"toggle use of EPSV/EPRT on IPv6 ftp";
+HSTR	feathelp[] =	"show FEATures supported by remote system";
+HSTR	formhelp[] =	"set file transfer format";
+HSTR	gatehelp[] =	"toggle gate-ftp; specify host[:port] to change proxy";
+HSTR	globhelp[] =	"toggle metacharacter expansion of local file names";
+HSTR	hashhelp[] =	"toggle printing `#' marks; specify number to set size";
+HSTR	helphelp[] =	"print local help information";
+HSTR	idlehelp[] =	"get (set) idle timer on remote side";
+HSTR	lcdhelp[] =	"change local working directory";
+HSTR	lpagehelp[] =	"view a local file through your pager";
+HSTR	lpwdhelp[] =	"print local working directory";
+HSTR	lshelp[] =	"list contents of remote path";
+HSTR	macdefhelp[] =  "define a macro";
+HSTR	mdeletehelp[] =	"delete multiple files";
+HSTR	mgethelp[] =	"get multiple files";
+HSTR	mregethelp[] =	"get multiple files restarting at end of local file";
+HSTR	fgethelp[] =	"get files using a localfile as a source of names";
+HSTR	mkdirhelp[] =	"make directory on the remote machine";
+HSTR	mlshelp[] =	"list contents of multiple remote directories";
+HSTR	mlsdhelp[] =	"list contents of remote directory in a machine "
+			"parsable form";
+HSTR	mlsthelp[] =	"list remote path in a machine parsable form";
+HSTR	modehelp[] =	"set file transfer mode";
+HSTR	modtimehelp[] = "show last modification time of remote file";
+HSTR	mputhelp[] =	"send multiple files";
+HSTR	newerhelp[] =	"get file if remote file is newer than local file ";
+HSTR	nmaphelp[] =	"set templates for default file name mapping";
+HSTR	ntranshelp[] =	"set translation table for default file name mapping";
+HSTR	optshelp[] =	"show or set options for remote commands";
+HSTR	pagehelp[] =	"view a remote file through your pager";
+HSTR	passivehelp[] =	"toggle use of passive transfer mode";
+HSTR	plshelp[] =	"list contents of remote path through your pager";
+HSTR	pmlsdhelp[] =	"list contents of remote directory in a machine "
+			"parsable form through your pager";
+HSTR	porthelp[] =	"toggle use of PORT/LPRT cmd for each data connection";
+HSTR	preservehelp[] ="toggle preservation of modification time of "
+			"retrieved files";
+HSTR	progresshelp[] ="toggle transfer progress meter";
+HSTR	prompthelp[] =	"force interactive prompting on multiple commands";
+HSTR	proxyhelp[] =	"issue command on alternate connection";
+HSTR	pwdhelp[] =	"print working directory on remote machine";
+HSTR	quithelp[] =	"terminate ftp session and exit";
+HSTR	quotehelp[] =	"send arbitrary ftp command";
+HSTR	ratehelp[] =	"set transfer rate limit (in bytes/second)";
+HSTR	receivehelp[] =	"receive file";
+HSTR	regethelp[] =	"get file restarting at end of local file";
+HSTR	remotehelp[] =	"get help from remote server";
+HSTR	renamehelp[] =	"rename file";
+HSTR	resethelp[] =	"clear queued command replies";
+HSTR	restarthelp[]=	"restart file transfer at bytecount";
+HSTR	rmdirhelp[] =	"remove directory on the remote machine";
+HSTR	rmtstatushelp[]="show status of remote machine";
+HSTR	runiquehelp[] = "toggle store unique for local files";
+HSTR	sendhelp[] =	"send one file";
+HSTR	sethelp[] =	"set or display options";
+HSTR	shellhelp[] =	"escape to the shell";
+HSTR	sitehelp[] =	"send site specific command to remote server\n"
+			"\t\tTry \"rhelp site\" or \"site help\" "
+			"for more information";
+HSTR	sizecmdhelp[] = "show size of remote file";
+HSTR	statushelp[] =	"show current status";
+HSTR	structhelp[] =	"set file transfer structure";
+HSTR	suniquehelp[] = "toggle store unique on remote machine";
+HSTR	systemhelp[] =  "show remote system type";
+HSTR	tenexhelp[] =	"set tenex file transfer type";
+HSTR	tracehelp[] =	"toggle packet tracing";
+HSTR	typehelp[] =	"set file transfer type";
+HSTR	umaskhelp[] =	"get (set) umask on remote side";
+HSTR	unsethelp[] =	"unset an option";
+HSTR	usagehelp[] =	"show command usage";
+HSTR	userhelp[] =	"send new user information";
+HSTR	verbosehelp[] =	"toggle verbose mode";
+HSTR	xferbufhelp[] =	"set socket send/receive buffer size";
+#endif
+
+HSTR	empty[] = "";
+
+#ifdef NO_HELP
+#define H(x)	empty
+#else
+#define H(x)	x
+#endif
+
+#ifdef NO_EDITCOMPLETE
+#define	CMPL(x)
+#define	CMPL0
+#else  /* !NO_EDITCOMPLETE */
+#define	CMPL(x)	#x,
+#define	CMPL0	empty,
+#endif /* !NO_EDITCOMPLETE */
+
+struct cmd cmdtab[] = {
+	{ "!",		H(shellhelp),	0, 0, 0, CMPL0		shell },
+	{ "$",		H(domachelp),	1, 0, 0, CMPL0		domacro },
+	{ "account",	H(accounthelp),	0, 1, 1, CMPL0		account},
+	{ "append",	H(appendhelp),	1, 1, 1, CMPL(lr)	put },
+	{ "ascii",	H(asciihelp),	0, 1, 1, CMPL0		setascii },
+	{ "bell",	H(beephelp),	0, 0, 0, CMPL0		setbell },
+	{ "binary",	H(binaryhelp),	0, 1, 1, CMPL0		setbinary },
+	{ "bye",	H(quithelp),	0, 0, 0, CMPL0		quit },
+	{ "case",	H(casehelp),	0, 0, 1, CMPL0		setcase },
+	{ "cd",		H(cdhelp),	0, 1, 1, CMPL(r)	cd },
+	{ "cdup",	H(cduphelp),	0, 1, 1, CMPL0		cdup },
+	{ "chmod",	H(chmodhelp),	0, 1, 1, CMPL(nr)	do_chmod },
+	{ "close",	H(disconhelp),	0, 1, 1, CMPL0		disconnect },
+	{ "cr",		H(crhelp),	0, 0, 0, CMPL0		setcr },
+	{ "debug",	H(debughelp),	0, 0, 0, CMPL0		setdebug },
+	{ "delete",	H(deletehelp),	0, 1, 1, CMPL(r)	delete },
+	{ "dir",	H(lshelp),	1, 1, 1, CMPL(rl)	ls },
+	{ "disconnect",	H(disconhelp),	0, 1, 1, CMPL0		disconnect },
+	{ "edit",	H(edithelp),	0, 0, 0, CMPL0		setedit },
+	{ "epsv",	H(epsvhelp),	0, 0, 0, CMPL0		setepsv },
+	{ "epsv4",	H(epsv4help),	0, 0, 0, CMPL0		setepsv4 },
+	{ "epsv6",	H(epsv6help),	0, 0, 0, CMPL0		setepsv6 },
+	{ "exit",	H(quithelp),	0, 0, 0, CMPL0		quit },
+	{ "features",	H(feathelp),	0, 1, 1, CMPL0		feat },
+	{ "fget",	H(fgethelp),	1, 1, 1, CMPL(l)	fget },
+	{ "form",	H(formhelp),	0, 1, 1, CMPL0		setform },
+	{ "ftp",	H(connecthelp),	0, 0, 1, CMPL0		setpeer },
+	{ "gate",	H(gatehelp),	0, 0, 0, CMPL0		setgate },
+	{ "get",	H(receivehelp),	1, 1, 1, CMPL(rl)	get },
+	{ "glob",	H(globhelp),	0, 0, 0, CMPL0		setglob },
+	{ "hash",	H(hashhelp),	0, 0, 0, CMPL0		sethash },
+	{ "help",	H(helphelp),	0, 0, 1, CMPL(C)	help },
+	{ "idle",	H(idlehelp),	0, 1, 1, CMPL0		idlecmd },
+	{ "image",	H(binaryhelp),	0, 1, 1, CMPL0		setbinary },
+	{ "lcd",	H(lcdhelp),	0, 0, 0, CMPL(l)	lcd },
+	{ "less",	H(pagehelp),	1, 1, 1, CMPL(r)	page },
+	{ "lpage",	H(lpagehelp),	0, 0, 0, CMPL(l)	lpage },
+	{ "lpwd",	H(lpwdhelp),	0, 0, 0, CMPL0		lpwd },
+	{ "ls",		H(lshelp),	1, 1, 1, CMPL(rl)	ls },
+	{ "macdef",	H(macdefhelp),	0, 0, 0, CMPL0		macdef },
+	{ "mdelete",	H(mdeletehelp),	1, 1, 1, CMPL(R)	mdelete },
+	{ "mdir",	H(mlshelp),	1, 1, 1, CMPL(R)	mls },
+	{ "mget",	H(mgethelp),	1, 1, 1, CMPL(R)	mget },
+	{ "mkdir",	H(mkdirhelp),	0, 1, 1, CMPL(r)	makedir },
+	{ "mls",	H(mlshelp),	1, 1, 1, CMPL(R)	mls },
+	{ "mlsd",	H(mlsdhelp),	1, 1, 1, CMPL(r)	ls },
+	{ "mlst",	H(mlsthelp),	1, 1, 1, CMPL(r)	mlst },
+	{ "mode",	H(modehelp),	0, 1, 1, CMPL0		setftmode },
+	{ "modtime",	H(modtimehelp),	0, 1, 1, CMPL(r)	modtime },
+	{ "more",	H(pagehelp),	1, 1, 1, CMPL(r)	page },
+	{ "mput",	H(mputhelp),	1, 1, 1, CMPL(L)	mput },
+	{ "mreget",	H(mregethelp),	1, 1, 1, CMPL(R)	mget },
+	{ "msend",	H(mputhelp),	1, 1, 1, CMPL(L)	mput },
+	{ "newer",	H(newerhelp),	1, 1, 1, CMPL(r)	newer },
+	{ "nlist",	H(lshelp),	1, 1, 1, CMPL(rl)	ls },
+	{ "nmap",	H(nmaphelp),	0, 0, 1, CMPL0		setnmap },
+	{ "ntrans",	H(ntranshelp),	0, 0, 1, CMPL0		setntrans },
+	{ "open",	H(connecthelp),	0, 0, 1, CMPL0		setpeer },
+	{ "page",	H(pagehelp),	1, 1, 1, CMPL(r)	page },
+	{ "passive",	H(passivehelp),	0, 0, 0, CMPL0		setpassive },
+	{ "pdir",	H(plshelp),	1, 1, 1, CMPL(r)	ls },
+	{ "pls",	H(plshelp),	1, 1, 1, CMPL(r)	ls },
+	{ "pmlsd",	H(pmlsdhelp),	1, 1, 1, CMPL(r)	ls },
+	{ "preserve",	H(preservehelp),0, 0, 0, CMPL0		setpreserve },
+	{ "progress",	H(progresshelp),0, 0, 0, CMPL0		setprogress },
+	{ "prompt",	H(prompthelp),	0, 0, 0, CMPL0		setprompt },
+	{ "proxy",	H(proxyhelp),	0, 0, 1, CMPL(c)	doproxy },
+	{ "put",	H(sendhelp),	1, 1, 1, CMPL(lr)	put },
+	{ "pwd",	H(pwdhelp),	0, 1, 1, CMPL0		pwd },
+	{ "quit",	H(quithelp),	0, 0, 0, CMPL0		quit },
+	{ "quote",	H(quotehelp),	1, 1, 1, CMPL0		quote },
+	{ "rate",	H(ratehelp),	0, 0, 0, CMPL0		setrate },
+	{ "rcvbuf",	H(xferbufhelp),	0, 0, 0, CMPL0		setxferbuf },
+	{ "recv",	H(receivehelp),	1, 1, 1, CMPL(rl)	get },
+	{ "reget",	H(regethelp),	1, 1, 1, CMPL(rl)	reget },
+	{ "remopts",	H(optshelp),	0, 1, 1, CMPL0		opts },
+	{ "rename",	H(renamehelp),	0, 1, 1, CMPL(rr)	renamefile },
+	{ "reset",	H(resethelp),	0, 1, 1, CMPL0		reset },
+	{ "restart",	H(restarthelp),	1, 1, 1, CMPL0		restart },
+	{ "rhelp",	H(remotehelp),	0, 1, 1, CMPL0		rmthelp },
+	{ "rmdir",	H(rmdirhelp),	0, 1, 1, CMPL(r)	removedir },
+	{ "rstatus",	H(rmtstatushelp),0, 1, 1, CMPL(r)	rmtstatus },
+	{ "runique",	H(runiquehelp),	0, 0, 1, CMPL0		setrunique },
+	{ "send",	H(sendhelp),	1, 1, 1, CMPL(lr)	put },
+	{ "sendport",	H(porthelp),	0, 0, 0, CMPL0		setport },
+	{ "set",	H(sethelp),	0, 0, 0, CMPL(o)	setoption },
+	{ "site",	H(sitehelp),	0, 1, 1, CMPL0		site },
+	{ "size",	H(sizecmdhelp),	1, 1, 1, CMPL(r)	sizecmd },
+	{ "sndbuf",	H(xferbufhelp),	0, 0, 0, CMPL0		setxferbuf },
+	{ "status",	H(statushelp),	0, 0, 1, CMPL0		status },
+	{ "struct",	H(structhelp),	0, 1, 1, CMPL0		setstruct },
+	{ "sunique",	H(suniquehelp),	0, 0, 1, CMPL0		setsunique },
+	{ "system",	H(systemhelp),	0, 1, 1, CMPL0		syst },
+	{ "tenex",	H(tenexhelp),	0, 1, 1, CMPL0		settenex },
+	{ "throttle",	H(ratehelp),	0, 0, 0, CMPL0		setrate },
+	{ "trace",	H(tracehelp),	0, 0, 0, CMPL0		settrace },
+	{ "type",	H(typehelp),	0, 1, 1, CMPL0		settype },
+	{ "umask",	H(umaskhelp),	0, 1, 1, CMPL0		do_umask },
+	{ "unset",	H(unsethelp),	0, 0, 0, CMPL(o)	unsetoption },
+	{ "usage",	H(usagehelp),	0, 0, 1, CMPL(C)	help },
+	{ "user",	H(userhelp),	0, 1, 1, CMPL0		user },
+	{ "verbose",	H(verbosehelp),	0, 0, 0, CMPL0		setverbose },
+	{ "xferbuf",	H(xferbufhelp),	0, 0, 0, CMPL0		setxferbuf },
+	{ "?",		H(helphelp),	0, 0, 1, CMPL(C)	help },
+	{ NULL,		NULL,		0, 0, 0, CMPL0		NULL },
+};
+
+struct option optiontab[] = {
+	{ "anonpass",	NULL },
+	{ "ftp_proxy",	NULL },
+	{ "http_proxy",	NULL },
+	{ "no_proxy",	NULL },
+	{ "pager",	NULL },
+	{ "prompt",	NULL },
+	{ "rprompt",	NULL },
+	{ NULL,		NULL },
+};

Added: vendor/NetBSD/tnftp/20100108/src/complete.c
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/complete.c	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/complete.c	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,439 @@
+/*	$NetBSD: complete.c,v 1.10 2009/05/20 12:53:47 lukem Exp $	*/
+/*	from	NetBSD: complete.c,v 1.46 2009/04/12 10:18:52 lukem Exp	*/
+
+/*-
+ * Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tnftp.h"
+
+#if 0	/* tnftp */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID(" NetBSD: complete.c,v 1.46 2009/04/12 10:18:52 lukem Exp  ");
+#endif /* not lint */
+
+/*
+ * FTP user program - command and file completion routines
+ */
+
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#endif	/* tnftp */
+
+#include "ftp_var.h"
+
+#ifndef NO_EDITCOMPLETE
+
+static int	     comparstr		(const void *, const void *);
+static unsigned char complete_ambiguous	(char *, int, StringList *);
+static unsigned char complete_command	(char *, int);
+static unsigned char complete_local	(char *, int);
+static unsigned char complete_option	(char *, int);
+static unsigned char complete_remote	(char *, int);
+
+static int
+comparstr(const void *a, const void *b)
+{
+	return (strcmp(*(const char * const *)a, *(const char * const *)b));
+}
+
+/*
+ * Determine if complete is ambiguous. If unique, insert.
+ * If no choices, error. If unambiguous prefix, insert that.
+ * Otherwise, list choices. words is assumed to be filtered
+ * to only contain possible choices.
+ * Args:
+ *	word	word which started the match
+ *	list	list by default
+ *	words	stringlist containing possible matches
+ * Returns a result as per el_set(EL_ADDFN, ...)
+ */
+static unsigned char
+complete_ambiguous(char *word, int list, StringList *words)
+{
+	char insertstr[MAXPATHLEN];
+	char *lastmatch, *p;
+	size_t i, j;
+	size_t matchlen, wordlen;
+
+	wordlen = strlen(word);
+	if (words->sl_cur == 0)
+		return (CC_ERROR);	/* no choices available */
+
+	if (words->sl_cur == 1) {	/* only once choice available */
+		p = words->sl_str[0] + wordlen;
+		if (*p == '\0')		/* at end of word? */
+			return (CC_REFRESH);
+		ftpvis(insertstr, sizeof(insertstr), p, strlen(p));
+		if (el_insertstr(el, insertstr) == -1)
+			return (CC_ERROR);
+		else
+			return (CC_REFRESH);
+	}
+
+	if (!list) {
+		matchlen = 0;
+		lastmatch = words->sl_str[0];
+		matchlen = strlen(lastmatch);
+		for (i = 1 ; i < words->sl_cur ; i++) {
+			for (j = wordlen ; j < strlen(words->sl_str[i]); j++)
+				if (lastmatch[j] != words->sl_str[i][j])
+					break;
+			if (j < matchlen)
+				matchlen = j;
+		}
+		if (matchlen > wordlen) {
+			ftpvis(insertstr, sizeof(insertstr),
+			    lastmatch + wordlen, matchlen - wordlen);
+			if (el_insertstr(el, insertstr) == -1)
+				return (CC_ERROR);
+			else
+				return (CC_REFRESH_BEEP);
+		}
+	}
+
+	putc('\n', ttyout);
+	qsort(words->sl_str, words->sl_cur, sizeof(char *), comparstr);
+	list_vertical(words);
+	return (CC_REDISPLAY);
+}
+
+/*
+ * Complete a command
+ */
+static unsigned char
+complete_command(char *word, int list)
+{
+	struct cmd *c;
+	StringList *words;
+	size_t wordlen;
+	unsigned char rv;
+
+	words = ftp_sl_init();
+	wordlen = strlen(word);
+
+	for (c = cmdtab; c->c_name != NULL; c++) {
+		if (wordlen > strlen(c->c_name))
+			continue;
+		if (strncmp(word, c->c_name, wordlen) == 0)
+			ftp_sl_add(words, ftp_strdup(c->c_name));
+	}
+
+	rv = complete_ambiguous(word, list, words);
+	if (rv == CC_REFRESH) {
+		if (el_insertstr(el, " ") == -1)
+			rv = CC_ERROR;
+	}
+	sl_free(words, 1);
+	return (rv);
+}
+
+/*
+ * Complete a local file
+ */
+static unsigned char
+complete_local(char *word, int list)
+{
+	StringList *words;
+	char dir[MAXPATHLEN];
+	char *file;
+	DIR *dd;
+	struct dirent *dp;
+	unsigned char rv;
+	size_t len;
+
+	if ((file = strrchr(word, '/')) == NULL) {
+		dir[0] = '.';
+		dir[1] = '\0';
+		file = word;
+	} else {
+		if (file == word) {
+			dir[0] = '/';
+			dir[1] = '\0';
+		} else
+			(void)strlcpy(dir, word, file - word + 1);
+		file++;
+	}
+	if (dir[0] == '~') {
+		char *p;
+
+		if ((p = globulize(dir)) == NULL)
+			return (CC_ERROR);
+		(void)strlcpy(dir, p, sizeof(dir));
+		free(p);
+	}
+
+	if ((dd = opendir(dir)) == NULL)
+		return (CC_ERROR);
+
+	words = ftp_sl_init();
+	len = strlen(file);
+
+	for (dp = readdir(dd); dp != NULL; dp = readdir(dd)) {
+		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
+			continue;
+
+#if defined(DIRENT_MISSING_D_NAMLEN)
+		if (len > strlen(dp->d_name))
+			continue;
+#else
+		if (len > dp->d_namlen)
+			continue;
+#endif
+		if (strncmp(file, dp->d_name, len) == 0) {
+			char *tcp;
+
+			tcp = ftp_strdup(dp->d_name);
+			ftp_sl_add(words, tcp);
+		}
+	}
+	closedir(dd);
+
+	rv = complete_ambiguous(file, list, words);
+	if (rv == CC_REFRESH) {
+		struct stat sb;
+		char path[MAXPATHLEN];
+
+		(void)strlcpy(path, dir,		sizeof(path));
+		(void)strlcat(path, "/",		sizeof(path));
+		(void)strlcat(path, words->sl_str[0],	sizeof(path));
+
+		if (stat(path, &sb) >= 0) {
+			char suffix[2] = " ";
+
+			if (S_ISDIR(sb.st_mode))
+				suffix[0] = '/';
+			if (el_insertstr(el, suffix) == -1)
+				rv = CC_ERROR;
+		}
+	}
+	sl_free(words, 1);
+	return (rv);
+}
+/*
+ * Complete an option
+ */
+static unsigned char
+complete_option(char *word, int list)
+{
+	struct option *o;
+	StringList *words;
+	size_t wordlen;
+	unsigned char rv;
+
+	words = ftp_sl_init();
+	wordlen = strlen(word);
+
+	for (o = optiontab; o->name != NULL; o++) {
+		if (wordlen > strlen(o->name))
+			continue;
+		if (strncmp(word, o->name, wordlen) == 0)
+			ftp_sl_add(words, ftp_strdup(o->name));
+	}
+
+	rv = complete_ambiguous(word, list, words);
+	if (rv == CC_REFRESH) {
+		if (el_insertstr(el, " ") == -1)
+			rv = CC_ERROR;
+	}
+	sl_free(words, 1);
+	return (rv);
+}
+
+/*
+ * Complete a remote file
+ */
+static unsigned char
+complete_remote(char *word, int list)
+{
+	static StringList *dirlist;
+	static char	 lastdir[MAXPATHLEN];
+	StringList	*words;
+	char		 dir[MAXPATHLEN];
+	char		*file, *cp;
+	size_t		 i;
+	unsigned char	 rv;
+	char		 cmdbuf[MAX_C_NAME];
+	char		*dummyargv[3] = { NULL, NULL, NULL };
+
+	(void)strlcpy(cmdbuf, "complete", sizeof(cmdbuf));
+	dummyargv[0] = cmdbuf;
+	dummyargv[1] = dir;
+
+	if ((file = strrchr(word, '/')) == NULL) {
+		dir[0] = '\0';
+		file = word;
+	} else {
+		cp = file;
+		while (*cp == '/' && cp > word)
+			cp--;
+		(void)strlcpy(dir, word, cp - word + 2);
+		file++;
+	}
+
+	if (dirchange || dirlist == NULL ||
+	    strcmp(dir, lastdir) != 0) {		/* dir not cached */
+		const char *emesg;
+
+		if (dirlist != NULL)
+			sl_free(dirlist, 1);
+		dirlist = ftp_sl_init();
+
+		mflag = 1;
+		emesg = NULL;
+		while ((cp = remglob(dummyargv, 0, &emesg)) != NULL) {
+			char *tcp;
+
+			if (!mflag)
+				continue;
+			if (*cp == '\0') {
+				mflag = 0;
+				continue;
+			}
+			tcp = strrchr(cp, '/');
+			if (tcp)
+				tcp++;
+			else
+				tcp = cp;
+			tcp = ftp_strdup(tcp);
+			ftp_sl_add(dirlist, tcp);
+		}
+		if (emesg != NULL) {
+			fprintf(ttyout, "\n%s\n", emesg);
+			return (CC_REDISPLAY);
+		}
+		(void)strlcpy(lastdir, dir, sizeof(lastdir));
+		dirchange = 0;
+	}
+
+	words = ftp_sl_init();
+	for (i = 0; i < dirlist->sl_cur; i++) {
+		cp = dirlist->sl_str[i];
+		if (strlen(file) > strlen(cp))
+			continue;
+		if (strncmp(file, cp, strlen(file)) == 0)
+			ftp_sl_add(words, cp);
+	}
+	rv = complete_ambiguous(file, list, words);
+	sl_free(words, 0);
+	return (rv);
+}
+
+/*
+ * Generic complete routine
+ */
+unsigned char
+complete(EditLine *cel, int ch)
+{
+	static char word[FTPBUFLEN];
+	static size_t lastc_argc, lastc_argo;
+
+	struct cmd *c;
+	const LineInfo *lf;
+	int dolist, cmpltype;
+	size_t celems, len;
+
+	lf = el_line(cel);
+	len = lf->lastchar - lf->buffer;
+	if (len >= sizeof(line))
+		return (CC_ERROR);
+	(void)strlcpy(line, lf->buffer, len + 1);
+	cursor_pos = line + (lf->cursor - lf->buffer);
+	lastc_argc = cursor_argc;	/* remember last cursor pos */
+	lastc_argo = cursor_argo;
+	makeargv();			/* build argc/argv of current line */
+
+	if (cursor_argo >= sizeof(word))
+		return (CC_ERROR);
+
+	dolist = 0;
+			/* if cursor and word is same, list alternatives */
+	if (lastc_argc == cursor_argc && lastc_argo == cursor_argo
+	    && strncmp(word, margv[cursor_argc] ? margv[cursor_argc] : "",
+			cursor_argo) == 0)
+		dolist = 1;
+	else if (cursor_argc < (size_t)margc)
+		(void)strlcpy(word, margv[cursor_argc], cursor_argo + 1);
+	word[cursor_argo] = '\0';
+
+	if (cursor_argc == 0)
+		return (complete_command(word, dolist));
+
+	c = getcmd(margv[0]);
+	if (c == (struct cmd *)-1 || c == 0)
+		return (CC_ERROR);
+	celems = strlen(c->c_complete);
+
+		/* check for 'continuation' completes (which are uppercase) */
+	if ((cursor_argc > celems) && (celems > 0)
+	    && isupper((unsigned char) c->c_complete[celems-1]))
+		cursor_argc = celems;
+
+	if (cursor_argc > celems)
+		return (CC_ERROR);
+
+	cmpltype = c->c_complete[cursor_argc - 1];
+	switch (cmpltype) {
+		case 'c':			/* command complete */
+		case 'C':
+			return (complete_command(word, dolist));
+		case 'l':			/* local complete */
+		case 'L':
+			return (complete_local(word, dolist));
+		case 'n':			/* no complete */
+		case 'N':			/* no complete */
+			return (CC_ERROR);
+		case 'o':			/* local complete */
+		case 'O':
+			return (complete_option(word, dolist));
+		case 'r':			/* remote complete */
+		case 'R':
+			if (connected != -1) {
+				fputs("\nMust be logged in to complete.\n",
+				    ttyout);
+				return (CC_REDISPLAY);
+			}
+			return (complete_remote(word, dolist));
+		default:
+			errx(1, "complete: unknown complete type `%c'",
+			    cmpltype);
+			return (CC_ERROR);
+	}
+	/* NOTREACHED */
+}
+
+#endif /* !NO_EDITCOMPLETE */

Added: vendor/NetBSD/tnftp/20100108/src/domacro.c
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/domacro.c	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/domacro.c	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,152 @@
+/*	$NetBSD: domacro.c,v 1.8 2009/05/20 12:53:47 lukem Exp $	*/
+/*	from	NetBSD: domacro.c,v 1.22 2009/04/12 10:18:52 lukem Exp	*/
+
+/*
+ * Copyright (c) 1985, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "tnftp.h"
+
+#if 0	/* tnftp */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)domacro.c	8.3 (Berkeley) 4/2/94";
+#else
+__RCSID(" NetBSD: domacro.c,v 1.22 2009/04/12 10:18:52 lukem Exp  ");
+#endif
+#endif /* not lint */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#endif	/* tnftp */
+
+#include "ftp_var.h"
+
+void
+domacro(int argc, char *argv[])
+{
+	int i, j, count = 2, loopflg = 0;
+	char *cp1, *cp2, line2[FTPBUFLEN];
+	struct cmd *c;
+	char cmdbuf[MAX_C_NAME];
+
+	if ((argc == 0 && argv != NULL) ||
+	    (argc < 2 && !another(&argc, &argv, "macro name"))) {
+		UPRINTF("usage: %s macro_name [args]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	for (i = 0; i < macnum; ++i) {
+		if (!strncmp(argv[1], macros[i].mac_name, 9))
+			break;
+	}
+	if (i == macnum) {
+		fprintf(ttyout, "'%s' macro not found.\n", argv[1]);
+		code = -1;
+		return;
+	}
+	(void)strlcpy(line2, line, sizeof(line2));
+ TOP:
+	cp1 = macros[i].mac_start;
+	while (cp1 != macros[i].mac_end) {
+		while (isspace((unsigned char)*cp1))
+			cp1++;
+		cp2 = line;
+		while (*cp1 != '\0') {
+			switch(*cp1) {
+			case '\\':
+				*cp2++ = *++cp1;
+				break;
+			case '$':
+				if (isdigit((unsigned char)*(cp1+1))) {
+					j = 0;
+					while (isdigit((unsigned char)*++cp1))
+						j = 10*j +  *cp1 - '0';
+					cp1--;
+					if (argc - 2 >= j) {
+						(void)strlcpy(cp2, argv[j+1],
+						    sizeof(line) - (cp2 - line));
+						cp2 += strlen(argv[j+1]);
+					}
+					break;
+				}
+				if (*(cp1+1) == 'i') {
+					loopflg = 1;
+					cp1++;
+					if (count < argc) {
+						(void)strlcpy(cp2, argv[count],
+						    sizeof(line) - (cp2 - line));
+						cp2 += strlen(argv[count]);
+					}
+					break;
+				}
+				/* intentional drop through */
+			default:
+				*cp2++ = *cp1;
+				break;
+			}
+			if (*cp1 != '\0')
+				cp1++;
+		}
+		*cp2 = '\0';
+		makeargv();
+		c = getcmd(margv[0]);
+		if (c == (struct cmd *)-1) {
+			fputs("?Ambiguous command.\n", ttyout);
+			code = -1;
+		} else if (c == 0) {
+			fputs("?Invalid command.\n", ttyout);
+			code = -1;
+		} else if (c->c_conn && !connected) {
+			fputs("Not connected.\n", ttyout);
+			code = -1;
+		} else {
+			if (verbose) {
+				fputs(line, ttyout);
+				putc('\n', ttyout);
+			}
+			(void)strlcpy(cmdbuf, c->c_name, sizeof(cmdbuf));
+			margv[0] = cmdbuf;
+			(*c->c_handler)(margc, margv);
+			if (bell && c->c_bell)
+				(void)putc('\007', ttyout);
+			(void)strlcpy(line, line2, sizeof(line));
+			makeargv();
+			argc = margc;
+			argv = margv;
+		}
+		if (cp1 != macros[i].mac_end)
+			cp1++;
+	}
+	if (loopflg && ++count < argc)
+		goto TOP;
+}

Added: vendor/NetBSD/tnftp/20100108/src/extern.h
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/extern.h	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/extern.h	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,252 @@
+/*	$NetBSD: extern.h,v 1.12 2009/11/15 10:12:37 lukem Exp $	*/
+/*	from	NetBSD: extern.h,v 1.77 2009/07/13 19:05:41 roy Exp	*/
+
+/*-
+ * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 1994 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)extern.h	8.3 (Berkeley) 10/9/94
+ */
+
+/*
+ * Copyright (C) 1997 and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+struct sockaddr;
+struct tm;
+struct addrinfo;
+
+void	abort_remote(FILE *);
+void	abort_squared(int);
+void	abortpt(int);
+void	abortxfer(int);
+void	account(int, char **);
+void	ai_unmapped(struct addrinfo *);
+int	another(int *, char ***, const char *);
+int	auto_fetch(int, char **);
+int	auto_put(int, char **, const char *);
+void	blkfree(char **);
+void	cd(int, char **);
+void	cdup(int, char **);
+void	changetype(int, int);
+void	cleanuppeer(void);
+void	cmdabort(int);
+void	cmdtimeout(int);
+void	cmdscanner(void);
+int	command(const char *, ...)
+     ;
+#ifndef NO_EDITCOMPLETE
+unsigned char complete(EditLine *, int);
+void	controlediting(void);
+#endif /* !NO_EDITCOMPLETE */
+void	crankrate(int);
+FILE   *dataconn(const char *);
+void	delete(int, char **);
+void	disconnect(int, char **);
+void	do_chmod(int, char **);
+void	do_umask(int, char **);
+void	domacro(int, char **);
+void	doproxy(int, char **);
+void	feat(int, char **);
+void	fget(int, char **);
+int	fileindir(const char *, const char *);
+int	foregroundproc(void);
+void	formatbuf(char *, size_t, const char *);
+void	ftpvis(char *, size_t, const char *, size_t);
+int	ftp_login(const char *, const char *, const char *);
+void	get(int, char **);
+struct cmd *getcmd(const char *);
+int	getit(int, char **, int, const char *);
+int	get_line(FILE *, char *, size_t, const char **);
+struct option *getoption(const char *);
+char   *getoptionvalue(const char *);
+void	getremoteinfo(void);
+int	getreply(int);
+char   *globulize(const char *);
+char   *gunique(const char *);
+void	help(int, char **);
+char   *hookup(const char *, const char *);
+void	idlecmd(int, char **);
+int	initconn(void);
+void	intr(int);
+int	isipv6addr(const char *);
+void	list_vertical(StringList *);
+void	lcd(int, char **);
+void	lostpeer(int);
+void	lpage(int, char **);
+void	lpwd(int, char **);
+void	ls(int, char **);
+void	macdef(int, char **);
+void	makeargv(void);
+void	makedir(int, char **);
+void	mdelete(int, char **);
+void	mget(int, char **);
+void	mls(int, char **);
+void	mlst(int, char **);
+void	modtime(int, char **);
+void	mput(int, char **);
+const char *onoff(int);
+void	opts(int, char **);
+void	newer(int, char **);
+void	page(int, char **);
+int	parserate(int, char **, int);
+char   *prompt(void);
+void	proxabort(int);
+void	proxtrans(const char *, const char *, const char *);
+void	psabort(int);
+void	pswitch(int);
+void	put(int, char **);
+void	pwd(int, char **);
+void	quit(int, char **);
+void	quote(int, char **);
+void	quote1(const char *, int, char **);
+void	recvrequest(const char *, const char *, const char *,
+	    const char *, int, int);
+void	reget(int, char **);
+char   *remglob(char **, int, const char **);
+time_t	remotemodtime(const char *, int);
+off_t	remotesize(const char *, int);
+void	removedir(int, char **);
+void	renamefile(int, char **);
+void	reset(int, char **);
+void	restart(int, char **);
+const char *rfc2822time(const struct tm *);
+void	rmthelp(int, char **);
+void	rmtstatus(int, char **);
+char   *rprompt(void);
+int	ruserpass(const char *, char **, char **, char **);
+void	sendrequest(const char *, const char *, const char *, int);
+void	setascii(int, char **);
+void	setbell(int, char **);
+void	setbinary(int, char **);
+void	setcase(int, char **);
+void	setcr(int, char **);
+void	setdebug(int, char **);
+void	setedit(int, char **);
+void	setepsv4(int, char **);
+void	setepsv6(int, char **);
+void	setepsv(int, char **);
+void	setform(int, char **);
+void	setftmode(int, char **);
+void	setgate(int, char **);
+void	setglob(int, char **);
+void	sethash(int, char **);
+void	setnmap(int, char **);
+void	setntrans(int, char **);
+void	setoption(int, char **);
+void	setpassive(int, char **);
+void	setpeer(int, char **);
+void	setport(int, char **);
+void	setpreserve(int, char **);
+void	setprogress(int, char **);
+void	setprompt(int, char **);
+void	setrate(int, char **);
+void	setrunique(int, char **);
+void	setstruct(int, char **);
+void	setsunique(int, char **);
+void	settenex(int, char **);
+void	settrace(int, char **);
+void	setttywidth(int);
+void	settype(int, char **);
+void	setupsockbufsize(int);
+void	setverbose(int, char **);
+void	setxferbuf(int, char **);
+void	set_option(const char *, const char *, int);
+void	shell(int, char **);
+void	site(int, char **);
+void	sizecmd(int, char **);
+char   *slurpstring(void);
+void	status(int, char **);
+int	strsuftoi(const char *);
+void	syst(int, char **);
+int	togglevar(int, char **, int *, const char *);
+void	unsetoption(int, char **);
+void	updatelocalcwd(void);
+void	updateremotecwd(void);
+void	usage(void);
+void	user(int, char **);
+int	ftp_connect(int, const struct sockaddr *, socklen_t);
+int	ftp_listen(int, int);
+int	ftp_poll(struct pollfd *, int, int);
+void   *ftp_malloc(size_t);
+StringList *ftp_sl_init(void);
+void	ftp_sl_add(StringList *, char *);
+char   *ftp_strdup(const char *);

Added: vendor/NetBSD/tnftp/20100108/src/fetch.c
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/fetch.c	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/fetch.c	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,1909 @@
+/*	$NetBSD: fetch.c,v 1.18 2009/11/15 10:12:37 lukem Exp $	*/
+/*     $NetBSD: fetch.c,v 1.206 2014/10/26 16:21:59 christos Exp $     */
+
+/*-
+ * Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Scott Aaron Bamford.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tnftp.h"
+
+#if 0	/* tnftp */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID(" NetBSD: fetch.c,v 1.191 2009/08/17 09:08:16 christos Exp  ");
+#endif /* not lint */
+
+/*
+ * FTP User Program -- Command line file retrieval
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+
+#include <arpa/ftp.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#endif	/* tnftp */
+
+#include "ftp_var.h"
+#include "version.h"
+
+typedef enum {
+	UNKNOWN_URL_T=-1,
+	HTTP_URL_T,
+	FTP_URL_T,
+	FILE_URL_T,
+	CLASSIC_URL_T
+} url_t;
+
+void		aborthttp(int);
+#ifndef NO_AUTH
+static int	auth_url(const char *, char **, const char *, const char *);
+static void	base64_encode(const unsigned char *, size_t, unsigned char *);
+#endif
+static int	go_fetch(const char *);
+static int	fetch_ftp(const char *);
+static int	fetch_url(const char *, const char *, char *, char *);
+static const char *match_token(const char **, const char *);
+static int	parse_url(const char *, const char *, url_t *, char **,
+			    char **, char **, char **, in_port_t *, char **);
+static void	url_decode(char *);
+
+static int	redirect_loop;
+
+
+#define	STRNEQUAL(a,b)	(strncasecmp((a), (b), sizeof((b))-1) == 0)
+#define	ISLWS(x)	((x)=='\r' || (x)=='\n' || (x)==' ' || (x)=='\t')
+#define	SKIPLWS(x)	do { while (ISLWS((*x))) x++; } while (0)
+
+
+#define	ABOUT_URL	"about:"	/* propaganda */
+#define	FILE_URL	"file://"	/* file URL prefix */
+#define	FTP_URL		"ftp://"	/* ftp URL prefix */
+#define	HTTP_URL	"http://"	/* http URL prefix */
+
+
+/*
+ * Determine if token is the next word in buf (case insensitive).
+ * If so, advance buf past the token and any trailing LWS, and
+ * return a pointer to the token (in buf).  Otherwise, return NULL.
+ * token may be preceded by LWS.
+ * token must be followed by LWS or NUL.  (I.e, don't partial match).
+ */
+static const char *
+match_token(const char **buf, const char *token)
+{
+	const char	*p, *orig;
+	size_t		tlen;
+
+	tlen = strlen(token);
+	p = *buf;
+	SKIPLWS(p);
+	orig = p;
+	if (strncasecmp(p, token, tlen) != 0)
+		return NULL;
+	p += tlen;
+	if (*p != '\0' && !ISLWS(*p))
+		return NULL;
+	SKIPLWS(p);
+	orig = *buf;
+	*buf = p;
+	return orig;
+}
+
+#ifndef NO_AUTH
+/*
+ * Generate authorization response based on given authentication challenge.
+ * Returns -1 if an error occurred, otherwise 0.
+ * Sets response to a malloc(3)ed string; caller should free.
+ */
+static int
+auth_url(const char *challenge, char **response, const char *guser,
+	const char *gpass)
+{
+	const char	*cp, *scheme, *errormsg;
+	char		*ep, *clear, *realm;
+	char		 uuser[BUFSIZ], *gotpass;
+	const char	*upass;
+	int		 rval;
+	size_t		 len, clen, rlen;
+
+	*response = NULL;
+	clear = realm = NULL;
+	rval = -1;
+	cp = challenge;
+	scheme = "Basic";	/* only support Basic authentication */
+	gotpass = NULL;
+
+	DPRINTF("auth_url: challenge `%s'\n", challenge);
+
+	if (! match_token(&cp, scheme)) {
+		warnx("Unsupported authentication challenge `%s'",
+		    challenge);
+		goto cleanup_auth_url;
+	}
+
+#define	REALM "realm=\""
+	if (STRNEQUAL(cp, REALM))
+		cp += sizeof(REALM) - 1;
+	else {
+		warnx("Unsupported authentication challenge `%s'",
+		    challenge);
+		goto cleanup_auth_url;
+	}
+/* XXX: need to improve quoted-string parsing to support \ quoting, etc. */
+	if ((ep = strchr(cp, '\"')) != NULL) {
+		len = ep - cp;
+		realm = (char *)ftp_malloc(len + 1);
+		(void)strlcpy(realm, cp, len + 1);
+	} else {
+		warnx("Unsupported authentication challenge `%s'",
+		    challenge);
+		goto cleanup_auth_url;
+	}
+
+	fprintf(ttyout, "Username for `%s': ", realm);
+	if (guser != NULL) {
+		(void)strlcpy(uuser, guser, sizeof(uuser));
+		fprintf(ttyout, "%s\n", uuser);
+	} else {
+		(void)fflush(ttyout);
+		if (get_line(stdin, uuser, sizeof(uuser), &errormsg) < 0) {
+			warnx("%s; can't authenticate", errormsg);
+			goto cleanup_auth_url;
+		}
+	}
+	if (gpass != NULL)
+		upass = gpass;
+	else {
+		gotpass = getpass("Password: ");
+		if (gotpass == NULL) {
+			warnx("Can't read password");
+			goto cleanup_auth_url;
+		}
+		upass = gotpass;
+	}
+
+	clen = strlen(uuser) + strlen(upass) + 2;	/* user + ":" + pass + "\0" */
+	clear = (char *)ftp_malloc(clen);
+	(void)strlcpy(clear, uuser, clen);
+	(void)strlcat(clear, ":", clen);
+	(void)strlcat(clear, upass, clen);
+	if (gotpass)
+		memset(gotpass, 0, strlen(gotpass));
+
+						/* scheme + " " + enc + "\0" */
+	rlen = strlen(scheme) + 1 + (clen + 2) * 4 / 3 + 1;
+	*response = (char *)ftp_malloc(rlen);
+	(void)strlcpy(*response, scheme, rlen);
+	len = strlcat(*response, " ", rlen);
+			/* use  `clen - 1'  to not encode the trailing NUL */
+	base64_encode((unsigned char *)clear, clen - 1,
+	    (unsigned char *)*response + len);
+	memset(clear, 0, clen);
+	rval = 0;
+
+ cleanup_auth_url:
+	FREEPTR(clear);
+	FREEPTR(realm);
+	return (rval);
+}
+
+/*
+ * Encode len bytes starting at clear using base64 encoding into encoded,
+ * which should be at least ((len + 2) * 4 / 3 + 1) in size.
+ */
+static void
+base64_encode(const unsigned char *clear, size_t len, unsigned char *encoded)
+{
+	static const unsigned char enc[] =
+	    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+	unsigned char	*cp;
+	size_t	 i;
+
+	cp = encoded;
+	for (i = 0; i < len; i += 3) {
+		*(cp++) = enc[((clear[i + 0] >> 2))];
+		*(cp++) = enc[((clear[i + 0] << 4) & 0x30)
+			    | ((clear[i + 1] >> 4) & 0x0f)];
+		*(cp++) = enc[((clear[i + 1] << 2) & 0x3c)
+			    | ((clear[i + 2] >> 6) & 0x03)];
+		*(cp++) = enc[((clear[i + 2]     ) & 0x3f)];
+	}
+	*cp = '\0';
+	while (i-- > len)
+		*(--cp) = '=';
+}
+#endif
+
+/*
+ * Decode %xx escapes in given string, `in-place'.
+ */
+static void
+url_decode(char *url)
+{
+	unsigned char *p, *q;
+
+	if (EMPTYSTRING(url))
+		return;
+	p = q = (unsigned char *)url;
+
+#define	HEXTOINT(x) (x - (isdigit(x) ? '0' : (islower(x) ? 'a' : 'A') - 10))
+	while (*p) {
+		if (p[0] == '%'
+		    && p[1] && isxdigit((unsigned char)p[1])
+		    && p[2] && isxdigit((unsigned char)p[2])) {
+			*q++ = HEXTOINT(p[1]) * 16 + HEXTOINT(p[2]);
+			p+=3;
+		} else
+			*q++ = *p++;
+	}
+	*q = '\0';
+}
+
+
+/*
+ * Parse URL of form (per RFC3986):
+ *	<type>://[<user>[:<password>]@]<host>[:<port>][/<path>]
+ * Returns -1 if a parse error occurred, otherwise 0.
+ * It's the caller's responsibility to url_decode() the returned
+ * user, pass and path.
+ *
+ * Sets type to url_t, each of the given char ** pointers to a
+ * malloc(3)ed strings of the relevant section, and port to
+ * the number given, or ftpport if ftp://, or httpport if http://.
+ *
+ * XXX: this is not totally RFC3986 compliant; <path> will have the
+ * leading `/' unless it's an ftp:// URL, as this makes things easier
+ * for file:// and http:// URLs.  ftp:// URLs have the `/' between the
+ * host and the URL-path removed, but any additional leading slashes
+ * in the URL-path are retained (because they imply that we should
+ * later do "CWD" with a null argument).
+ *
+ * Examples:
+ *	 input URL			 output path
+ *	 ---------			 -----------
+ *	"http://host"			"/"
+ *	"http://host/"			"/"
+ *	"http://host/path"		"/path"
+ *	"file://host/dir/file"		"dir/file"
+ *	"ftp://host"			""
+ *	"ftp://host/"			""
+ *	"ftp://host//"			"/"
+ *	"ftp://host/dir/file"		"dir/file"
+ *	"ftp://host//dir/file"		"/dir/file"
+ */
+static int
+parse_url(const char *url, const char *desc, url_t *utype,
+		char **uuser, char **pass, char **host, char **port,
+		in_port_t *portnum, char **path)
+{
+	const char	*origurl, *tport;
+	char		*cp, *ep, *thost;
+	size_t		 len;
+
+	if (url == NULL || desc == NULL || utype == NULL || uuser == NULL
+	    || pass == NULL || host == NULL || port == NULL || portnum == NULL
+	    || path == NULL)
+		errx(1, "parse_url: invoked with NULL argument!");
+	DPRINTF("parse_url: %s `%s'\n", desc, url);
+
+	origurl = url;
+	*utype = UNKNOWN_URL_T;
+	*uuser = *pass = *host = *port = *path = NULL;
+	*portnum = 0;
+	tport = NULL;
+
+	if (STRNEQUAL(url, HTTP_URL)) {
+		url += sizeof(HTTP_URL) - 1;
+		*utype = HTTP_URL_T;
+		*portnum = HTTP_PORT;
+		tport = httpport;
+	} else if (STRNEQUAL(url, FTP_URL)) {
+		url += sizeof(FTP_URL) - 1;
+		*utype = FTP_URL_T;
+		*portnum = FTP_PORT;
+		tport = ftpport;
+	} else if (STRNEQUAL(url, FILE_URL)) {
+		url += sizeof(FILE_URL) - 1;
+		*utype = FILE_URL_T;
+	} else {
+		warnx("Invalid %s `%s'", desc, url);
+ cleanup_parse_url:
+		FREEPTR(*uuser);
+		if (*pass != NULL)
+			memset(*pass, 0, strlen(*pass));
+		FREEPTR(*pass);
+		FREEPTR(*host);
+		FREEPTR(*port);
+		FREEPTR(*path);
+		return (-1);
+	}
+
+	if (*url == '\0')
+		return (0);
+
+			/* find [user[:pass]@]host[:port] */
+	ep = strchr(url, '/');
+	if (ep == NULL)
+		thost = ftp_strdup(url);
+	else {
+		len = ep - url;
+		thost = (char *)ftp_malloc(len + 1);
+		(void)strlcpy(thost, url, len + 1);
+		if (*utype == FTP_URL_T)	/* skip first / for ftp URLs */
+			ep++;
+		*path = ftp_strdup(ep);
+	}
+
+	cp = strchr(thost, '@');	/* look for user[:pass]@ in URLs */
+	if (cp != NULL) {
+		if (*utype == FTP_URL_T)
+			anonftp = 0;	/* disable anonftp */
+		*uuser = thost;
+		*cp = '\0';
+		thost = ftp_strdup(cp + 1);
+		cp = strchr(*uuser, ':');
+		if (cp != NULL) {
+			*cp = '\0';
+			*pass = ftp_strdup(cp + 1);
+		}
+		url_decode(*uuser);
+		if (*pass)
+			url_decode(*pass);
+	}
+
+#ifdef INET6
+			/*
+			 * Check if thost is an encoded IPv6 address, as per
+			 * RFC3986:
+			 *	`[' ipv6-address ']'
+			 */
+	if (*thost == '[') {
+		cp = thost + 1;
+		if ((ep = strchr(cp, ']')) == NULL ||
+		    (ep[1] != '\0' && ep[1] != ':')) {
+			warnx("Invalid address `%s' in %s `%s'",
+			    thost, desc, origurl);
+			goto cleanup_parse_url;
+		}
+		len = ep - cp;		/* change `[xyz]' -> `xyz' */
+		memmove(thost, thost + 1, len);
+		thost[len] = '\0';
+		if (! isipv6addr(thost)) {
+			warnx("Invalid IPv6 address `%s' in %s `%s'",
+			    thost, desc, origurl);
+			goto cleanup_parse_url;
+		}
+		cp = ep + 1;
+		if (*cp == ':')
+			cp++;
+		else
+			cp = NULL;
+	} else
+#endif /* INET6 */
+		if ((cp = strchr(thost, ':')) != NULL)
+			*cp++ = '\0';
+	*host = thost;
+
+			/* look for [:port] */
+	if (cp != NULL) {
+		unsigned long	nport;
+
+		nport = strtoul(cp, &ep, 10);
+		if (*cp == '\0' || *ep != '\0' ||
+		    nport < 1 || nport > MAX_IN_PORT_T) {
+			warnx("Unknown port `%s' in %s `%s'",
+			    cp, desc, origurl);
+			goto cleanup_parse_url;
+		}
+		*portnum = nport;
+		tport = cp;
+	}
+
+	if (tport != NULL)
+		*port = ftp_strdup(tport);
+	if (*path == NULL) {
+		const char *emptypath = "/";
+		if (*utype == FTP_URL_T)	/* skip first / for ftp URLs */
+			emptypath++;
+		*path = ftp_strdup(emptypath);
+	}
+
+	DPRINTF("parse_url: user `%s' pass `%s' host %s port %s(%d) "
+	    "path `%s'\n",
+	    STRorNULL(*uuser), STRorNULL(*pass),
+	    STRorNULL(*host), STRorNULL(*port),
+	    *portnum ? *portnum : -1, STRorNULL(*path));
+
+	return (0);
+}
+
+sigjmp_buf	httpabort;
+
+/*
+ * Retrieve URL, via a proxy if necessary, using HTTP.
+ * If proxyenv is set, use that for the proxy, otherwise try ftp_proxy or
+ * http_proxy as appropriate.
+ * Supports HTTP redirects.
+ * Returns 1 on failure, 0 on completed xfer, -1 if ftp connection
+ * is still open (e.g, ftp xfer with trailing /)
+ */
+static int
+fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
+{
+	struct addrinfo		hints, *res, *res0 = NULL;
+	int			error;
+	sigfunc volatile	oldintr;
+	sigfunc volatile	oldintp;
+	int volatile		s;
+	struct stat		sb;
+	int volatile		ischunked;
+	int volatile		isproxy;
+	int volatile		rval;
+	int volatile		hcode;
+	int			len;
+	size_t			flen;
+	static size_t		bufsize;
+	static char		*xferbuf;
+	const char		*cp, *token;
+	char			*ep;
+	char			buf[FTPBUFLEN];
+	const char		*errormsg;
+	char			*volatile savefile;
+	char			*volatile auth;
+	char			*volatile location;
+	char			*volatile message;
+	char			*uuser, *pass, *host, *port, *path;
+	char			*volatile decodedpath;
+	char			*puser, *ppass, *useragent;
+	off_t			hashbytes, rangestart, rangeend, entitylen;
+	int			(*volatile closefunc)(FILE *);
+	FILE			*volatile fin;
+	FILE			*volatile fout;
+	time_t			mtime;
+	url_t			urltype;
+	in_port_t		portnum;
+
+	DPRINTF("fetch_url: `%s' proxyenv `%s'\n", url, STRorNULL(proxyenv));
+
+	oldintr = oldintp = NULL;
+	closefunc = NULL;
+	fin = fout = NULL;
+	s = -1;
+	savefile = NULL;
+	auth = location = message = NULL;
+	ischunked = isproxy = hcode = 0;
+	rval = 1;
+	uuser = pass = host = path = decodedpath = puser = ppass = NULL;
+
+	if (parse_url(url, "URL", &urltype, &uuser, &pass, &host, &port,
+	    &portnum, &path) == -1)
+		goto cleanup_fetch_url;
+
+	if (urltype == FILE_URL_T && ! EMPTYSTRING(host)
+	    && strcasecmp(host, "localhost") != 0) {
+		warnx("No support for non local file URL `%s'", url);
+		goto cleanup_fetch_url;
+	}
+
+	if (EMPTYSTRING(path)) {
+		if (urltype == FTP_URL_T) {
+			rval = fetch_ftp(url);
+			goto cleanup_fetch_url;
+		}
+		if (urltype != HTTP_URL_T || outfile == NULL)  {
+			warnx("Invalid URL (no file after host) `%s'", url);
+			goto cleanup_fetch_url;
+		}
+	}
+
+	decodedpath = ftp_strdup(path);
+	url_decode(decodedpath);
+
+	if (outfile)
+		savefile = outfile;
+	else {
+		cp = strrchr(decodedpath, '/');		/* find savefile */
+		if (cp != NULL)
+			savefile = ftp_strdup(cp + 1);
+		else
+			savefile = ftp_strdup(decodedpath);
+	}
+	DPRINTF("fetch_url: savefile `%s'\n", savefile);
+	if (EMPTYSTRING(savefile)) {
+		if (urltype == FTP_URL_T) {
+			rval = fetch_ftp(url);
+			goto cleanup_fetch_url;
+		}
+		warnx("No file after directory (you must specify an "
+		    "output file) `%s'", url);
+		goto cleanup_fetch_url;
+	}
+
+	restart_point = 0;
+	filesize = -1;
+	rangestart = rangeend = entitylen = -1;
+	mtime = -1;
+	if (restartautofetch) {
+		if (stat(savefile, &sb) == 0)
+			restart_point = sb.st_size;
+	}
+	if (urltype == FILE_URL_T) {		/* file:// URLs */
+		direction = "copied";
+		fin = fopen(decodedpath, "r");
+		if (fin == NULL) {
+			warn("Can't open `%s'", decodedpath);
+			goto cleanup_fetch_url;
+		}
+		if (fstat(fileno(fin), &sb) == 0) {
+			mtime = sb.st_mtime;
+			filesize = sb.st_size;
+		}
+		if (restart_point) {
+			if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
+				warn("Can't seek to restart `%s'",
+				    decodedpath);
+				goto cleanup_fetch_url;
+			}
+		}
+		if (verbose) {
+			fprintf(ttyout, "Copying %s", decodedpath);
+			if (restart_point)
+				fprintf(ttyout, " (restarting at " LLF ")",
+				    (LLT)restart_point);
+			fputs("\n", ttyout);
+		}
+	} else {				/* ftp:// or http:// URLs */
+		const char *leading;
+		int hasleading;
+
+		if (proxyenv == NULL) {
+			if (urltype == HTTP_URL_T)
+				proxyenv = getoptionvalue("http_proxy");
+			else if (urltype == FTP_URL_T)
+				proxyenv = getoptionvalue("ftp_proxy");
+		}
+		direction = "retrieved";
+		if (! EMPTYSTRING(proxyenv)) {			/* use proxy */
+			url_t purltype;
+			char *phost, *ppath;
+			char *pport, *no_proxy;
+			in_port_t pportnum;
+
+			isproxy = 1;
+
+				/* check URL against list of no_proxied sites */
+			no_proxy = getoptionvalue("no_proxy");
+			if (! EMPTYSTRING(no_proxy)) {
+				char *np, *np_copy, *np_iter;
+				unsigned long np_port;
+				size_t hlen, plen;
+
+				np_iter = np_copy = ftp_strdup(no_proxy);
+				hlen = strlen(host);
+				while ((cp = strsep(&np_iter, " ,")) != NULL) {
+					if (*cp == '\0')
+						continue;
+					if ((np = strrchr(cp, ':')) != NULL) {
+						*np++ =  '\0';
+						np_port = strtoul(np, &ep, 10);
+						if (*np == '\0' || *ep != '\0')
+							continue;
+						if (np_port != portnum)
+							continue;
+					}
+					plen = strlen(cp);
+					if (hlen < plen)
+						continue;
+					if (strncasecmp(host + hlen - plen,
+					    cp, plen) == 0) {
+						isproxy = 0;
+						break;
+					}
+				}
+				FREEPTR(np_copy);
+				if (isproxy == 0 && urltype == FTP_URL_T) {
+					rval = fetch_ftp(url);
+					goto cleanup_fetch_url;
+				}
+			}
+
+			if (isproxy) {
+				if (restart_point) {
+					warnx("Can't restart via proxy URL `%s'",
+					    proxyenv);
+					goto cleanup_fetch_url;
+				}
+				if (parse_url(proxyenv, "proxy URL", &purltype,
+				    &puser, &ppass, &phost, &pport, &pportnum,
+				    &ppath) == -1)
+					goto cleanup_fetch_url;
+
+				if ((purltype != HTTP_URL_T
+				     && purltype != FTP_URL_T) ||
+				    EMPTYSTRING(phost) ||
+				    (! EMPTYSTRING(ppath)
+				     && strcmp(ppath, "/") != 0)) {
+					warnx("Malformed proxy URL `%s'",
+					    proxyenv);
+					FREEPTR(phost);
+					FREEPTR(pport);
+					FREEPTR(ppath);
+					goto cleanup_fetch_url;
+				}
+				if (isipv6addr(host) &&
+				    strchr(host, '%') != NULL) {
+					warnx(
+"Scoped address notation `%s' disallowed via web proxy",
+					    host);
+					FREEPTR(phost);
+					FREEPTR(pport);
+					FREEPTR(ppath);
+					goto cleanup_fetch_url;
+				}
+
+				FREEPTR(host);
+				host = phost;
+				FREEPTR(port);
+				port = pport;
+				FREEPTR(path);
+				path = ftp_strdup(url);
+				FREEPTR(ppath);
+			}
+		} /* ! EMPTYSTRING(proxyenv) */
+
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_flags = 0;
+		hints.ai_family = family;
+		hints.ai_socktype = SOCK_STREAM;
+		hints.ai_protocol = 0;
+		error = getaddrinfo(host, port, &hints, &res0);
+		if (error) {
+			warnx("Can't lookup `%s:%s': %s", host, port,
+			    (error == EAI_SYSTEM) ? strerror(errno)
+						  : gai_strerror(error));
+			goto cleanup_fetch_url;
+		}
+		if (res0->ai_canonname)
+			host = res0->ai_canonname;
+
+		s = -1;
+		for (res = res0; res; res = res->ai_next) {
+			char	hname[NI_MAXHOST], sname[NI_MAXSERV];
+
+			ai_unmapped(res);
+			if (getnameinfo(res->ai_addr, res->ai_addrlen,
+			    hname, sizeof(hname), sname, sizeof(sname),
+			    NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
+				strlcpy(hname, "?", sizeof(hname));
+				strlcpy(sname, "?", sizeof(sname));
+			}
+
+			if (verbose && res0->ai_next) {
+				fprintf(ttyout, "Trying %s:%s ...\n",
+				    hname, sname);
+			}
+
+			s = socket(res->ai_family, SOCK_STREAM,
+			    res->ai_protocol);
+			if (s < 0) {
+				warn(
+				    "Can't create socket for connection to "
+				    "`%s:%s'", hname, sname);
+				continue;
+			}
+
+			if (ftp_connect(s, res->ai_addr, res->ai_addrlen) < 0) {
+				close(s);
+				s = -1;
+				continue;
+			}
+
+			/* success */
+			break;
+		}
+
+		if (s < 0) {
+			warnx("Can't connect to `%s:%s'", host, port);
+			goto cleanup_fetch_url;
+		}
+
+		fin = fdopen(s, "r+");
+		/*
+		 * Construct and send the request.
+		 */
+		if (verbose)
+			fprintf(ttyout, "Requesting %s\n", url);
+		leading = "  (";
+		hasleading = 0;
+		if (isproxy) {
+			if (verbose) {
+				fprintf(ttyout, "%svia %s:%s", leading,
+				    host, port);
+				leading = ", ";
+				hasleading++;
+			}
+			fprintf(fin, "GET %s HTTP/1.0\r\n", path);
+			if (flushcache)
+				fprintf(fin, "Pragma: no-cache\r\n");
+		} else {
+			fprintf(fin, "GET %s HTTP/1.1\r\n", path);
+			if (strchr(host, ':')) {
+				char *h, *p;
+
+				/*
+				 * strip off IPv6 scope identifier, since it is
+				 * local to the node
+				 */
+				h = ftp_strdup(host);
+				if (isipv6addr(h) &&
+				    (p = strchr(h, '%')) != NULL) {
+					*p = '\0';
+				}
+				fprintf(fin, "Host: [%s]", h);
+				free(h);
+			} else
+				fprintf(fin, "Host: %s", host);
+			if (portnum != HTTP_PORT)
+				fprintf(fin, ":%u", portnum);
+			fprintf(fin, "\r\n");
+			fprintf(fin, "Accept: */*\r\n");
+			fprintf(fin, "Connection: close\r\n");
+			if (restart_point) {
+				fputs(leading, ttyout);
+				fprintf(fin, "Range: bytes=" LLF "-\r\n",
+				    (LLT)restart_point);
+				fprintf(ttyout, "restarting at " LLF,
+				    (LLT)restart_point);
+				leading = ", ";
+				hasleading++;
+			}
+			if (flushcache)
+				fprintf(fin, "Cache-Control: no-cache\r\n");
+		}
+		if ((useragent=getenv("FTPUSERAGENT")) != NULL) {
+			fprintf(fin, "User-Agent: %s\r\n", useragent);
+		} else {
+			fprintf(fin, "User-Agent: %s/%s\r\n",
+			    FTP_PRODUCT, FTP_VERSION);
+		}
+		if (wwwauth) {
+			if (verbose) {
+				fprintf(ttyout, "%swith authorization",
+				    leading);
+				leading = ", ";
+				hasleading++;
+			}
+			fprintf(fin, "Authorization: %s\r\n", wwwauth);
+		}
+		if (proxyauth) {
+			if (verbose) {
+				fprintf(ttyout,
+				    "%swith proxy authorization", leading);
+				leading = ", ";
+				hasleading++;
+			}
+			fprintf(fin, "Proxy-Authorization: %s\r\n", proxyauth);
+		}
+		if (verbose && hasleading)
+			fputs(")\n", ttyout);
+		fprintf(fin, "\r\n");
+		if (fflush(fin) == EOF) {
+			warn("Writing HTTP request");
+			goto cleanup_fetch_url;
+		}
+
+				/* Read the response */
+		len = get_line(fin, buf, sizeof(buf), &errormsg);
+		if (len < 0) {
+			if (*errormsg == '\n')
+				errormsg++;
+			warnx("Receiving HTTP reply: %s", errormsg);
+			goto cleanup_fetch_url;
+		}
+		while (len > 0 && (ISLWS(buf[len-1])))
+			buf[--len] = '\0';
+		DPRINTF("fetch_url: received `%s'\n", buf);
+
+				/* Determine HTTP response code */
+		cp = strchr(buf, ' ');
+		if (cp == NULL)
+			goto improper;
+		else
+			cp++;
+		hcode = strtol(cp, &ep, 10);
+		if (*ep != '\0' && !isspace((unsigned char)*ep))
+			goto improper;
+		message = ftp_strdup(cp);
+
+				/* Read the rest of the header. */
+		while (1) {
+			len = get_line(fin, buf, sizeof(buf), &errormsg);
+			if (len < 0) {
+				if (*errormsg == '\n')
+					errormsg++;
+				warnx("Receiving HTTP reply: %s", errormsg);
+				goto cleanup_fetch_url;
+			}
+			while (len > 0 && (ISLWS(buf[len-1])))
+				buf[--len] = '\0';
+			if (len == 0)
+				break;
+			DPRINTF("fetch_url: received `%s'\n", buf);
+
+		/*
+		 * Look for some headers
+		 */
+
+			cp = buf;
+
+			if (match_token(&cp, "Content-Length:")) {
+				filesize = STRTOLL(cp, &ep, 10);
+				if (filesize < 0 || *ep != '\0')
+					goto improper;
+				DPRINTF("fetch_url: parsed len as: " LLF "\n",
+				    (LLT)filesize);
+
+			} else if (match_token(&cp, "Content-Range:")) {
+				if (! match_token(&cp, "bytes"))
+					goto improper;
+
+				if (*cp == '*')
+					cp++;
+				else {
+					rangestart = STRTOLL(cp, &ep, 10);
+					if (rangestart < 0 || *ep != '-')
+						goto improper;
+					cp = ep + 1;
+					rangeend = STRTOLL(cp, &ep, 10);
+					if (rangeend < 0 || rangeend < rangestart)
+						goto improper;
+					cp = ep;
+				}
+				if (*cp != '/')
+					goto improper;
+				cp++;
+				if (*cp == '*')
+					cp++;
+				else {
+					entitylen = STRTOLL(cp, &ep, 10);
+					if (entitylen < 0)
+						goto improper;
+					cp = ep;
+				}
+				if (*cp != '\0')
+					goto improper;
+
+#ifndef NO_DEBUG
+				if (ftp_debug) {
+					fprintf(ttyout, "parsed range as: ");
+					if (rangestart == -1)
+						fprintf(ttyout, "*");
+					else
+						fprintf(ttyout, LLF "-" LLF,
+						    (LLT)rangestart,
+						    (LLT)rangeend);
+					fprintf(ttyout, "/" LLF "\n", (LLT)entitylen);
+				}
+#endif
+				if (! restart_point) {
+					warnx(
+				    "Received unexpected Content-Range header");
+					goto cleanup_fetch_url;
+				}
+
+			} else if (match_token(&cp, "Last-Modified:")) {
+				struct tm parsed;
+				char *t;
+
+				memset(&parsed, 0, sizeof(parsed));
+							/* RFC1123 */
+				if ((t = strptime(cp,
+						"%a, %d %b %Y %H:%M:%S GMT",
+						&parsed))
+							/* RFC0850 */
+				    || (t = strptime(cp,
+						"%a, %d-%b-%y %H:%M:%S GMT",
+						&parsed))
+							/* asctime */
+				    || (t = strptime(cp,
+						"%a, %b %d %H:%M:%S %Y",
+						&parsed))) {
+					parsed.tm_isdst = -1;
+					if (*t == '\0')
+						mtime = timegm(&parsed);
+#ifndef NO_DEBUG
+					if (ftp_debug && mtime != -1) {
+						fprintf(ttyout,
+						    "parsed date as: %s",
+						rfc2822time(localtime(&mtime)));
+					}
+#endif
+				}
+
+			} else if (match_token(&cp, "Location:")) {
+				location = ftp_strdup(cp);
+				DPRINTF("fetch_url: parsed location as `%s'\n",
+				    cp);
+
+			} else if (match_token(&cp, "Transfer-Encoding:")) {
+				if (match_token(&cp, "binary")) {
+					warnx(
+			"Bogus transfer encoding `binary' (fetching anyway)");
+					continue;
+				}
+				if (! (token = match_token(&cp, "chunked"))) {
+					warnx(
+				    "Unsupported transfer encoding `%s'",
+					    token);
+					goto cleanup_fetch_url;
+				}
+				ischunked++;
+				DPRINTF("fetch_url: using chunked encoding\n");
+
+			} else if (match_token(&cp, "Proxy-Authenticate:")
+				|| match_token(&cp, "WWW-Authenticate:")) {
+				if (! (token = match_token(&cp, "Basic"))) {
+					DPRINTF(
+			"fetch_url: skipping unknown auth scheme `%s'\n",
+						    token);
+					continue;
+				}
+				FREEPTR(auth);
+				auth = ftp_strdup(token);
+				DPRINTF("fetch_url: parsed auth as `%s'\n", cp);
+			}
+
+		}
+				/* finished parsing header */
+
+		switch (hcode) {
+		case 200:
+			break;
+		case 206:
+			if (! restart_point) {
+				warnx("Not expecting partial content header");
+				goto cleanup_fetch_url;
+			}
+			break;
+		case 300:
+		case 301:
+		case 302:
+		case 303:
+		case 305:
+		case 307:
+			if (EMPTYSTRING(location)) {
+				warnx(
+				"No redirection Location provided by server");
+				goto cleanup_fetch_url;
+			}
+			if (redirect_loop++ > 5) {
+				warnx("Too many redirections requested");
+				goto cleanup_fetch_url;
+			}
+			if (hcode == 305) {
+				if (verbose)
+					fprintf(ttyout, "Redirected via %s\n",
+					    location);
+				rval = fetch_url(url, location,
+				    proxyauth, wwwauth);
+			} else {
+				if (verbose)
+					fprintf(ttyout, "Redirected to %s\n",
+					    location);
+				rval = go_fetch(location);
+			}
+			goto cleanup_fetch_url;
+#ifndef NO_AUTH
+		case 401:
+		case 407:
+		    {
+			char **authp;
+			char *auser, *apass;
+
+			if (hcode == 401) {
+				authp = &wwwauth;
+				auser = uuser;
+				apass = pass;
+			} else {
+				authp = &proxyauth;
+				auser = puser;
+				apass = ppass;
+			}
+			if (verbose || *authp == NULL ||
+			    auser == NULL || apass == NULL)
+				fprintf(ttyout, "%s\n", message);
+			if (EMPTYSTRING(auth)) {
+				warnx(
+			    "No authentication challenge provided by server");
+				goto cleanup_fetch_url;
+			}
+			if (*authp != NULL) {
+				char reply[10];
+
+				fprintf(ttyout,
+				    "Authorization failed. Retry (y/n)? ");
+				if (get_line(stdin, reply, sizeof(reply), NULL)
+				    < 0) {
+					goto cleanup_fetch_url;
+				}
+				if (tolower((unsigned char)reply[0]) != 'y')
+					goto cleanup_fetch_url;
+				auser = NULL;
+				apass = NULL;
+			}
+			if (auth_url(auth, authp, auser, apass) == 0) {
+				rval = fetch_url(url, proxyenv,
+				    proxyauth, wwwauth);
+				memset(*authp, 0, strlen(*authp));
+				FREEPTR(*authp);
+			}
+			goto cleanup_fetch_url;
+		    }
+#endif
+		default:
+			if (message)
+				warnx("Error retrieving file `%s'", message);
+			else
+				warnx("Unknown error retrieving file");
+			goto cleanup_fetch_url;
+		}
+	}		/* end of ftp:// or http:// specific setup */
+
+	/* Open the output file. */
+
+       /*
+        * Only trust filenames with special meaning if they came from
+        * the command line
+        */
+       if (outfile == savefile) {
+               if (strcmp(savefile, "-") == 0) {
+                       fout = stdout;
+               } else if (*savefile == '|') {
+                       oldpipe = xsignal(SIGPIPE, SIG_IGN);
+                       fout = popen(savefile + 1, "w");
+                       if (fout == NULL) {
+                               warn("Can't execute `%s'", savefile + 1);
+                               goto cleanup_fetch_url;
+                       }
+                       closefunc = pclose;
+		}
+	}
+	if (fout == NULL) {
+		if ((rangeend != -1 && rangeend <= restart_point) ||
+		    (rangestart == -1 && filesize != -1 && filesize <= restart_point)) {
+			/* already done */
+			if (verbose)
+				fprintf(ttyout, "already done\n");
+			rval = 0;
+			goto cleanup_fetch_url;
+		}
+		if (restart_point && rangestart != -1) {
+			if (entitylen != -1)
+				filesize = entitylen;
+			if (rangestart != restart_point) {
+				warnx(
+				    "Size of `%s' differs from save file `%s'",
+				    url, savefile);
+				goto cleanup_fetch_url;
+			}
+			fout = fopen(savefile, "a");
+		} else
+			fout = fopen(savefile, "w");
+		if (fout == NULL) {
+			warn("Can't open `%s'", savefile);
+			goto cleanup_fetch_url;
+		}
+		closefunc = fclose;
+	}
+
+			/* Trap signals */
+	if (sigsetjmp(httpabort, 1))
+		goto cleanup_fetch_url;
+	(void)xsignal(SIGQUIT, psummary);
+	oldintr = xsignal(SIGINT, aborthttp);
+
+	if ((size_t)rcvbuf_size > bufsize) {
+		if (xferbuf)
+			(void)free(xferbuf);
+		bufsize = rcvbuf_size;
+		xferbuf = ftp_malloc(bufsize);
+	}
+
+	bytes = 0;
+	hashbytes = mark;
+	progressmeter(-1);
+
+			/* Finally, suck down the file. */
+	do {
+		long chunksize;
+		short lastchunk;
+
+		chunksize = 0;
+		lastchunk = 0;
+					/* read chunk-size */
+		if (ischunked) {
+			if (fgets(xferbuf, bufsize, fin) == NULL) {
+				warnx("Unexpected EOF reading chunk-size");
+				goto cleanup_fetch_url;
+			}
+			errno = 0;
+			chunksize = strtol(xferbuf, &ep, 16);
+			if (ep == xferbuf) {
+				warnx("Invalid chunk-size");
+				goto cleanup_fetch_url;
+			}
+			if (errno == ERANGE || chunksize < 0) {
+				errno = ERANGE;
+				warn("Chunk-size `%.*s'",
+				    (int)(ep-xferbuf), xferbuf);
+				goto cleanup_fetch_url;
+			}
+
+				/*
+				 * XXX:	Work around bug in Apache 1.3.9 and
+				 *	1.3.11, which incorrectly put trailing
+				 *	space after the chunk-size.
+				 */
+			while (*ep == ' ')
+				ep++;
+
+					/* skip [ chunk-ext ] */
+			if (*ep == ';') {
+				while (*ep && *ep != '\r')
+					ep++;
+			}
+
+			if (strcmp(ep, "\r\n") != 0) {
+				warnx("Unexpected data following chunk-size");
+				goto cleanup_fetch_url;
+			}
+			DPRINTF("fetch_url: got chunk-size of " LLF "\n",
+			    (LLT)chunksize);
+			if (chunksize == 0) {
+				lastchunk = 1;
+				goto chunkdone;
+			}
+		}
+					/* transfer file or chunk */
+		while (1) {
+			struct timeval then, now, td;
+			off_t bufrem;
+
+			if (rate_get)
+				(void)gettimeofday(&then, NULL);
+			bufrem = rate_get ? rate_get : (off_t)bufsize;
+			if (ischunked)
+				bufrem = MIN(chunksize, bufrem);
+			while (bufrem > 0) {
+				flen = fread(xferbuf, sizeof(char),
+				    MIN((off_t)bufsize, bufrem), fin);
+				if (flen <= 0)
+					goto chunkdone;
+				bytes += flen;
+				bufrem -= flen;
+				if (fwrite(xferbuf, sizeof(char), flen, fout)
+				    != flen) {
+					warn("Writing `%s'", savefile);
+					goto cleanup_fetch_url;
+				}
+				if (hash && !progress) {
+					while (bytes >= hashbytes) {
+						(void)putc('#', ttyout);
+						hashbytes += mark;
+					}
+					(void)fflush(ttyout);
+				}
+				if (ischunked) {
+					chunksize -= flen;
+					if (chunksize <= 0)
+						break;
+				}
+			}
+			if (rate_get) {
+				while (1) {
+					(void)gettimeofday(&now, NULL);
+					timersub(&now, &then, &td);
+					if (td.tv_sec > 0)
+						break;
+					usleep(1000000 - td.tv_usec);
+				}
+			}
+			if (ischunked && chunksize <= 0)
+				break;
+		}
+					/* read CRLF after chunk*/
+ chunkdone:
+		if (ischunked) {
+			if (fgets(xferbuf, bufsize, fin) == NULL) {
+				warnx("Unexpected EOF reading chunk CRLF");
+				goto cleanup_fetch_url;
+			}
+			if (strcmp(xferbuf, "\r\n") != 0) {
+				warnx("Unexpected data following chunk");
+				goto cleanup_fetch_url;
+			}
+			if (lastchunk)
+				break;
+		}
+	} while (ischunked);
+
+/* XXX: deal with optional trailer & CRLF here? */
+
+	if (hash && !progress && bytes > 0) {
+		if (bytes < mark)
+			(void)putc('#', ttyout);
+		(void)putc('\n', ttyout);
+	}
+	if (ferror(fin)) {
+		warn("Reading file");
+		goto cleanup_fetch_url;
+	}
+	progressmeter(1);
+	(void)fflush(fout);
+	if (closefunc == fclose && mtime != -1) {
+		struct timeval tval[2];
+
+		(void)gettimeofday(&tval[0], NULL);
+		tval[1].tv_sec = mtime;
+		tval[1].tv_usec = 0;
+		(*closefunc)(fout);
+		fout = NULL;
+
+		if (utimes(savefile, tval) == -1) {
+			fprintf(ttyout,
+			    "Can't change modification time to %s",
+			    rfc2822time(localtime(&mtime)));
+		}
+	}
+	if (bytes > 0)
+		ptransfer(0);
+	bytes = 0;
+
+	rval = 0;
+	goto cleanup_fetch_url;
+
+ improper:
+	warnx("Improper response from `%s:%s'", host, port);
+
+ cleanup_fetch_url:
+	if (oldintr)
+		(void)xsignal(SIGINT, oldintr);
+	if (oldintp)
+		(void)xsignal(SIGPIPE, oldintp);
+	if (fin != NULL)
+		fclose(fin);
+	else if (s != -1)
+		close(s);
+	if (closefunc != NULL && fout != NULL)
+		(*closefunc)(fout);
+	if (res0)
+		freeaddrinfo(res0);
+	if (savefile != outfile)
+		FREEPTR(savefile);
+	FREEPTR(uuser);
+	if (pass != NULL)
+		memset(pass, 0, strlen(pass));
+	FREEPTR(pass);
+	FREEPTR(host);
+	FREEPTR(port);
+	FREEPTR(path);
+	FREEPTR(decodedpath);
+	FREEPTR(puser);
+	if (ppass != NULL)
+		memset(ppass, 0, strlen(ppass));
+	FREEPTR(ppass);
+	FREEPTR(auth);
+	FREEPTR(location);
+	FREEPTR(message);
+	return (rval);
+}
+
+/*
+ * Abort a HTTP retrieval
+ */
+void
+aborthttp(int notused)
+{
+	char msgbuf[100];
+	size_t len;
+
+	sigint_raised = 1;
+	alarmtimer(0);
+	len = strlcpy(msgbuf, "\nHTTP fetch aborted.\n", sizeof(msgbuf));
+	write(fileno(ttyout), msgbuf, len);
+	siglongjmp(httpabort, 1);
+}
+
+/*
+ * Retrieve ftp URL or classic ftp argument using FTP.
+ * Returns 1 on failure, 0 on completed xfer, -1 if ftp connection
+ * is still open (e.g, ftp xfer with trailing /)
+ */
+static int
+fetch_ftp(const char *url)
+{
+	char		*cp, *xargv[5], rempath[MAXPATHLEN];
+	char		*host, *path, *dir, *file, *uuser, *pass;
+	char		*port;
+	char		 cmdbuf[MAXPATHLEN];
+	char		 dirbuf[4];
+	int		 dirhasglob, filehasglob, rval, transtype, xargc;
+	int		 oanonftp, oautologin;
+	in_port_t	 portnum;
+	url_t		 urltype;
+
+	DPRINTF("fetch_ftp: `%s'\n", url);
+	host = path = dir = file = uuser = pass = NULL;
+	port = NULL;
+	rval = 1;
+	transtype = TYPE_I;
+
+	if (STRNEQUAL(url, FTP_URL)) {
+		if ((parse_url(url, "URL", &urltype, &uuser, &pass,
+		    &host, &port, &portnum, &path) == -1) ||
+		    (uuser != NULL && *uuser == '\0') ||
+		    EMPTYSTRING(host)) {
+			warnx("Invalid URL `%s'", url);
+			goto cleanup_fetch_ftp;
+		}
+		/*
+		 * Note: Don't url_decode(path) here.  We need to keep the
+		 * distinction between "/" and "%2F" until later.
+		 */
+
+					/* check for trailing ';type=[aid]' */
+		if (! EMPTYSTRING(path) && (cp = strrchr(path, ';')) != NULL) {
+			if (strcasecmp(cp, ";type=a") == 0)
+				transtype = TYPE_A;
+			else if (strcasecmp(cp, ";type=i") == 0)
+				transtype = TYPE_I;
+			else if (strcasecmp(cp, ";type=d") == 0) {
+				warnx(
+			    "Directory listing via a URL is not supported");
+				goto cleanup_fetch_ftp;
+			} else {
+				warnx("Invalid suffix `%s' in URL `%s'", cp,
+				    url);
+				goto cleanup_fetch_ftp;
+			}
+			*cp = 0;
+		}
+	} else {			/* classic style `[user@]host:[file]' */
+		urltype = CLASSIC_URL_T;
+		host = ftp_strdup(url);
+		cp = strchr(host, '@');
+		if (cp != NULL) {
+			*cp = '\0';
+			uuser = host;
+			anonftp = 0;	/* disable anonftp */
+			host = ftp_strdup(cp + 1);
+		}
+		cp = strchr(host, ':');
+		if (cp != NULL) {
+			*cp = '\0';
+			path = ftp_strdup(cp + 1);
+		}
+	}
+	if (EMPTYSTRING(host))
+		goto cleanup_fetch_ftp;
+
+			/* Extract the file and (if present) directory name. */
+	dir = path;
+	if (! EMPTYSTRING(dir)) {
+		/*
+		 * If we are dealing with classic `[user@]host:[path]' syntax,
+		 * then a path of the form `/file' (resulting from input of the
+		 * form `host:/file') means that we should do "CWD /" before
+		 * retrieving the file.  So we set dir="/" and file="file".
+		 *
+		 * But if we are dealing with URLs like `ftp://host/path' then
+		 * a path of the form `/file' (resulting from a URL of the form
+		 * `ftp://host//file') means that we should do `CWD ' (with an
+		 * empty argument) before retrieving the file.  So we set
+		 * dir="" and file="file".
+		 *
+		 * If the path does not contain / at all, we set dir=NULL.
+		 * (We get a path without any slashes if we are dealing with
+		 * classic `[user@]host:[file]' or URL `ftp://host/file'.)
+		 *
+		 * In all other cases, we set dir to a string that does not
+		 * include the final '/' that separates the dir part from the
+		 * file part of the path.  (This will be the empty string if
+		 * and only if we are dealing with a path of the form `/file'
+		 * resulting from an URL of the form `ftp://host//file'.)
+		 */
+		cp = strrchr(dir, '/');
+		if (cp == dir && urltype == CLASSIC_URL_T) {
+			file = cp + 1;
+			(void)strlcpy(dirbuf, "/", sizeof(dirbuf));
+			dir = dirbuf;
+		} else if (cp != NULL) {
+			*cp++ = '\0';
+			file = cp;
+		} else {
+			file = dir;
+			dir = NULL;
+		}
+	} else
+		dir = NULL;
+	if (urltype == FTP_URL_T && file != NULL) {
+		url_decode(file);
+		/* but still don't url_decode(dir) */
+	}
+	DPRINTF("fetch_ftp: user `%s' pass `%s' host %s port %s "
+	    "path `%s' dir `%s' file `%s'\n",
+	    STRorNULL(uuser), STRorNULL(pass),
+	    STRorNULL(host), STRorNULL(port),
+	    STRorNULL(path), STRorNULL(dir), STRorNULL(file));
+
+	dirhasglob = filehasglob = 0;
+	if (doglob && urltype == CLASSIC_URL_T) {
+		if (! EMPTYSTRING(dir) && strpbrk(dir, "*?[]{}") != NULL)
+			dirhasglob = 1;
+		if (! EMPTYSTRING(file) && strpbrk(file, "*?[]{}") != NULL)
+			filehasglob = 1;
+	}
+
+			/* Set up the connection */
+	oanonftp = anonftp;
+	if (connected)
+		disconnect(0, NULL);
+	anonftp = oanonftp;
+	(void)strlcpy(cmdbuf, getprogname(), sizeof(cmdbuf));
+	xargv[0] = cmdbuf;
+	xargv[1] = host;
+	xargv[2] = NULL;
+	xargc = 2;
+	if (port) {
+		xargv[2] = port;
+		xargv[3] = NULL;
+		xargc = 3;
+	}
+	oautologin = autologin;
+		/* don't autologin in setpeer(), use ftp_login() below */
+	autologin = 0;
+	setpeer(xargc, xargv);
+	autologin = oautologin;
+	if ((connected == 0) ||
+	    (connected == 1 && !ftp_login(host, uuser, pass))) {
+		warnx("Can't connect or login to host `%s:%s'",
+			host, port ? port : "?");
+		goto cleanup_fetch_ftp;
+	}
+
+	switch (transtype) {
+	case TYPE_A:
+		setascii(1, xargv);
+		break;
+	case TYPE_I:
+		setbinary(1, xargv);
+		break;
+	default:
+		errx(1, "fetch_ftp: unknown transfer type %d", transtype);
+	}
+
+		/*
+		 * Change directories, if necessary.
+		 *
+		 * Note: don't use EMPTYSTRING(dir) below, because
+		 * dir=="" means something different from dir==NULL.
+		 */
+	if (dir != NULL && !dirhasglob) {
+		char *nextpart;
+
+		/*
+		 * If we are dealing with a classic `[user@]host:[path]'
+		 * (urltype is CLASSIC_URL_T) then we have a raw directory
+		 * name (not encoded in any way) and we can change
+		 * directories in one step.
+		 *
+		 * If we are dealing with an `ftp://host/path' URL
+		 * (urltype is FTP_URL_T), then RFC3986 says we need to
+		 * send a separate CWD command for each unescaped "/"
+		 * in the path, and we have to interpret %hex escaping
+		 * *after* we find the slashes.  It's possible to get
+		 * empty components here, (from multiple adjacent
+		 * slashes in the path) and RFC3986 says that we should
+		 * still do `CWD ' (with a null argument) in such cases.
+		 *
+		 * Many ftp servers don't support `CWD ', so if there's an
+		 * error performing that command, bail out with a descriptive
+		 * message.
+		 *
+		 * Examples:
+		 *
+		 * host:			dir="", urltype=CLASSIC_URL_T
+		 *		logged in (to default directory)
+		 * host:file			dir=NULL, urltype=CLASSIC_URL_T
+		 *		"RETR file"
+		 * host:dir/			dir="dir", urltype=CLASSIC_URL_T
+		 *		"CWD dir", logged in
+		 * ftp://host/			dir="", urltype=FTP_URL_T
+		 *		logged in (to default directory)
+		 * ftp://host/dir/		dir="dir", urltype=FTP_URL_T
+		 *		"CWD dir", logged in
+		 * ftp://host/file		dir=NULL, urltype=FTP_URL_T
+		 *		"RETR file"
+		 * ftp://host//file		dir="", urltype=FTP_URL_T
+		 *		"CWD ", "RETR file"
+		 * host:/file			dir="/", urltype=CLASSIC_URL_T
+		 *		"CWD /", "RETR file"
+		 * ftp://host///file		dir="/", urltype=FTP_URL_T
+		 *		"CWD ", "CWD ", "RETR file"
+		 * ftp://host/%2F/file		dir="%2F", urltype=FTP_URL_T
+		 *		"CWD /", "RETR file"
+		 * ftp://host/foo/file		dir="foo", urltype=FTP_URL_T
+		 *		"CWD foo", "RETR file"
+		 * ftp://host/foo/bar/file	dir="foo/bar"
+		 *		"CWD foo", "CWD bar", "RETR file"
+		 * ftp://host//foo/bar/file	dir="/foo/bar"
+		 *		"CWD ", "CWD foo", "CWD bar", "RETR file"
+		 * ftp://host/foo//bar/file	dir="foo//bar"
+		 *		"CWD foo", "CWD ", "CWD bar", "RETR file"
+		 * ftp://host/%2F/foo/bar/file	dir="%2F/foo/bar"
+		 *		"CWD /", "CWD foo", "CWD bar", "RETR file"
+		 * ftp://host/%2Ffoo/bar/file	dir="%2Ffoo/bar"
+		 *		"CWD /foo", "CWD bar", "RETR file"
+		 * ftp://host/%2Ffoo%2Fbar/file	dir="%2Ffoo%2Fbar"
+		 *		"CWD /foo/bar", "RETR file"
+		 * ftp://host/%2Ffoo%2Fbar%2Ffile	dir=NULL
+		 *		"RETR /foo/bar/file"
+		 *
+		 * Note that we don't need `dir' after this point.
+		 */
+		do {
+			if (urltype == FTP_URL_T) {
+				nextpart = strchr(dir, '/');
+				if (nextpart) {
+					*nextpart = '\0';
+					nextpart++;
+				}
+				url_decode(dir);
+			} else
+				nextpart = NULL;
+			DPRINTF("fetch_ftp: dir `%s', nextpart `%s'\n",
+			    STRorNULL(dir), STRorNULL(nextpart));
+			if (urltype == FTP_URL_T || *dir != '\0') {
+				(void)strlcpy(cmdbuf, "cd", sizeof(cmdbuf));
+				xargv[0] = cmdbuf;
+				xargv[1] = dir;
+				xargv[2] = NULL;
+				dirchange = 0;
+				cd(2, xargv);
+				if (! dirchange) {
+					if (*dir == '\0' && code == 500)
+						fprintf(stderr,
+"\n"
+"ftp: The `CWD ' command (without a directory), which is required by\n"
+"     RFC3986 to support the empty directory in the URL pathname (`//'),\n"
+"     conflicts with the server's conformance to RFC0959.\n"
+"     Try the same URL without the `//' in the URL pathname.\n"
+"\n");
+					goto cleanup_fetch_ftp;
+				}
+			}
+			dir = nextpart;
+		} while (dir != NULL);
+	}
+
+	if (EMPTYSTRING(file)) {
+		rval = -1;
+		goto cleanup_fetch_ftp;
+	}
+
+	if (dirhasglob) {
+		(void)strlcpy(rempath, dir,	sizeof(rempath));
+		(void)strlcat(rempath, "/",	sizeof(rempath));
+		(void)strlcat(rempath, file,	sizeof(rempath));
+		file = rempath;
+	}
+
+			/* Fetch the file(s). */
+	xargc = 2;
+	(void)strlcpy(cmdbuf, "get", sizeof(cmdbuf));
+	xargv[0] = cmdbuf;
+	xargv[1] = file;
+	xargv[2] = NULL;
+	if (dirhasglob || filehasglob) {
+		int ointeractive;
+
+		ointeractive = interactive;
+		interactive = 0;
+		if (restartautofetch)
+			(void)strlcpy(cmdbuf, "mreget", sizeof(cmdbuf));
+		else
+			(void)strlcpy(cmdbuf, "mget", sizeof(cmdbuf));
+		xargv[0] = cmdbuf;
+		mget(xargc, xargv);
+		interactive = ointeractive;
+	} else {
+		if (outfile == NULL) {
+			cp = strrchr(file, '/');	/* find savefile */
+			if (cp != NULL)
+				outfile = cp + 1;
+			else
+				outfile = file;
+		}
+		xargv[2] = (char *)outfile;
+		xargv[3] = NULL;
+		xargc++;
+		if (restartautofetch)
+			reget(xargc, xargv);
+		else
+			get(xargc, xargv);
+	}
+
+	if ((code / 100) == COMPLETE)
+		rval = 0;
+
+ cleanup_fetch_ftp:
+	FREEPTR(port);
+	FREEPTR(host);
+	FREEPTR(path);
+	FREEPTR(uuser);
+	if (pass)
+		memset(pass, 0, strlen(pass));
+	FREEPTR(pass);
+	return (rval);
+}
+
+/*
+ * Retrieve the given file to outfile.
+ * Supports arguments of the form:
+ *	"host:path", "ftp://host/path"	if $ftpproxy, call fetch_url() else
+ *					call fetch_ftp()
+ *	"http://host/path"		call fetch_url() to use HTTP
+ *	"file:///path"			call fetch_url() to copy
+ *	"about:..."			print a message
+ *
+ * Returns 1 on failure, 0 on completed xfer, -1 if ftp connection
+ * is still open (e.g, ftp xfer with trailing /)
+ */
+static int
+go_fetch(const char *url)
+{
+	char *proxyenv;
+
+#ifndef NO_ABOUT
+	/*
+	 * Check for about:*
+	 */
+	if (STRNEQUAL(url, ABOUT_URL)) {
+		url += sizeof(ABOUT_URL) -1;
+		if (strcasecmp(url, "ftp") == 0 ||
+		    strcasecmp(url, "tnftp") == 0) {
+			fputs(
+"This version of ftp has been enhanced by Luke Mewburn <lukem at NetBSD.org>\n"
+"for the NetBSD project.  Execute `man ftp' for more details.\n", ttyout);
+		} else if (strcasecmp(url, "lukem") == 0) {
+			fputs(
+"Luke Mewburn is the author of most of the enhancements in this ftp client.\n"
+"Please email feedback to <lukem at NetBSD.org>.\n", ttyout);
+		} else if (strcasecmp(url, "netbsd") == 0) {
+			fputs(
+"NetBSD is a freely available and redistributable UNIX-like operating system.\n"
+"For more information, see http://www.NetBSD.org/\n", ttyout);
+		} else if (strcasecmp(url, "version") == 0) {
+			fprintf(ttyout, "Version: %s %s%s\n",
+			    FTP_PRODUCT, FTP_VERSION,
+#ifdef INET6
+			    ""
+#else
+			    " (-IPv6)"
+#endif
+			);
+		} else {
+			fprintf(ttyout, "`%s' is an interesting topic.\n", url);
+		}
+		fputs("\n", ttyout);
+		return (0);
+	}
+#endif
+
+	/*
+	 * Check for file:// and http:// URLs.
+	 */
+	if (STRNEQUAL(url, HTTP_URL) || STRNEQUAL(url, FILE_URL))
+		return (fetch_url(url, NULL, NULL, NULL));
+
+	/*
+	 * Try FTP URL-style and host:file arguments next.
+	 * If ftpproxy is set with an FTP URL, use fetch_url()
+	 * Othewise, use fetch_ftp().
+	 */
+	proxyenv = getoptionvalue("ftp_proxy");
+	if (!EMPTYSTRING(proxyenv) && STRNEQUAL(url, FTP_URL))
+		return (fetch_url(url, NULL, NULL, NULL));
+
+	return (fetch_ftp(url));
+}
+
+/*
+ * Retrieve multiple files from the command line,
+ * calling go_fetch() for each file.
+ *
+ * If an ftp path has a trailing "/", the path will be cd-ed into and
+ * the connection remains open, and the function will return -1
+ * (to indicate the connection is alive).
+ * If an error occurs the return value will be the offset+1 in
+ * argv[] of the file that caused a problem (i.e, argv[x]
+ * returns x+1)
+ * Otherwise, 0 is returned if all files retrieved successfully.
+ */
+int
+auto_fetch(int argc, char *argv[])
+{
+	volatile int	argpos, rval;
+
+	argpos = rval = 0;
+
+	if (sigsetjmp(toplevel, 1)) {
+		if (connected)
+			disconnect(0, NULL);
+		if (rval > 0)
+			rval = argpos + 1;
+		return (rval);
+	}
+	(void)xsignal(SIGINT, intr);
+	(void)xsignal(SIGPIPE, lostpeer);
+
+	/*
+	 * Loop through as long as there's files to fetch.
+	 */
+	for (; (rval == 0) && (argpos < argc); argpos++) {
+		if (strchr(argv[argpos], ':') == NULL)
+			break;
+		redirect_loop = 0;
+		if (!anonftp)
+			anonftp = 2;	/* Handle "automatic" transfers. */
+		rval = go_fetch(argv[argpos]);
+		if (outfile != NULL && strcmp(outfile, "-") != 0
+		    && outfile[0] != '|')
+			outfile = NULL;
+		if (rval > 0)
+			rval = argpos + 1;
+	}
+
+	if (connected && rval != -1)
+		disconnect(0, NULL);
+	return (rval);
+}
+
+
+/*
+ * Upload multiple files from the command line.
+ *
+ * If an error occurs the return value will be the offset+1 in
+ * argv[] of the file that caused a problem (i.e, argv[x]
+ * returns x+1)
+ * Otherwise, 0 is returned if all files uploaded successfully.
+ */
+int
+auto_put(int argc, char **argv, const char *uploadserver)
+{
+	char	*uargv[4], *path, *pathsep;
+	int	 uargc, rval, argpos;
+	size_t	 len;
+	char	 cmdbuf[MAX_C_NAME];
+
+	(void)strlcpy(cmdbuf, "mput", sizeof(cmdbuf));
+	uargv[0] = cmdbuf;
+	uargv[1] = argv[0];
+	uargc = 2;
+	uargv[2] = uargv[3] = NULL;
+	pathsep = NULL;
+	rval = 1;
+
+	DPRINTF("auto_put: target `%s'\n", uploadserver);
+
+	path = ftp_strdup(uploadserver);
+	len = strlen(path);
+	if (path[len - 1] != '/' && path[len - 1] != ':') {
+			/*
+			 * make sure we always pass a directory to auto_fetch
+			 */
+		if (argc > 1) {		/* more than one file to upload */
+			len = strlen(uploadserver) + 2;	/* path + "/" + "\0" */
+			free(path);
+			path = (char *)ftp_malloc(len);
+			(void)strlcpy(path, uploadserver, len);
+			(void)strlcat(path, "/", len);
+		} else {		/* single file to upload */
+			(void)strlcpy(cmdbuf, "put", sizeof(cmdbuf));
+			uargv[0] = cmdbuf;
+			pathsep = strrchr(path, '/');
+			if (pathsep == NULL) {
+				pathsep = strrchr(path, ':');
+				if (pathsep == NULL) {
+					warnx("Invalid URL `%s'", path);
+					goto cleanup_auto_put;
+				}
+				pathsep++;
+				uargv[2] = ftp_strdup(pathsep);
+				pathsep[0] = '/';
+			} else
+				uargv[2] = ftp_strdup(pathsep + 1);
+			pathsep[1] = '\0';
+			uargc++;
+		}
+	}
+	DPRINTF("auto_put: URL `%s' argv[2] `%s'\n",
+	    path, STRorNULL(uargv[2]));
+
+			/* connect and cwd */
+	rval = auto_fetch(1, &path);
+	if(rval >= 0)
+		goto cleanup_auto_put;
+
+	rval = 0;
+
+			/* target filename provided; upload 1 file */
+			/* XXX : is this the best way? */
+	if (uargc == 3) {
+		uargv[1] = argv[0];
+		put(uargc, uargv);
+		if ((code / 100) != COMPLETE)
+			rval = 1;
+	} else {	/* otherwise a target dir: upload all files to it */
+		for(argpos = 0; argv[argpos] != NULL; argpos++) {
+			uargv[1] = argv[argpos];
+			mput(uargc, uargv);
+			if ((code / 100) != COMPLETE) {
+				rval = argpos + 1;
+				break;
+			}
+		}
+	}
+
+ cleanup_auto_put:
+	free(path);
+	FREEPTR(uargv[2]);
+	return (rval);
+}

Added: vendor/NetBSD/tnftp/20100108/src/fetch.c.orig
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/fetch.c.orig	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/fetch.c.orig	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,1901 @@
+/*	$NetBSD: fetch.c,v 1.18 2009/11/15 10:12:37 lukem Exp $	*/
+/*	from	NetBSD: fetch.c,v 1.191 2009/08/17 09:08:16 christos Exp	*/
+
+/*-
+ * Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Scott Aaron Bamford.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tnftp.h"
+
+#if 0	/* tnftp */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID(" NetBSD: fetch.c,v 1.191 2009/08/17 09:08:16 christos Exp  ");
+#endif /* not lint */
+
+/*
+ * FTP User Program -- Command line file retrieval
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+
+#include <arpa/ftp.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#endif	/* tnftp */
+
+#include "ftp_var.h"
+#include "version.h"
+
+typedef enum {
+	UNKNOWN_URL_T=-1,
+	HTTP_URL_T,
+	FTP_URL_T,
+	FILE_URL_T,
+	CLASSIC_URL_T
+} url_t;
+
+void		aborthttp(int);
+#ifndef NO_AUTH
+static int	auth_url(const char *, char **, const char *, const char *);
+static void	base64_encode(const unsigned char *, size_t, unsigned char *);
+#endif
+static int	go_fetch(const char *);
+static int	fetch_ftp(const char *);
+static int	fetch_url(const char *, const char *, char *, char *);
+static const char *match_token(const char **, const char *);
+static int	parse_url(const char *, const char *, url_t *, char **,
+			    char **, char **, char **, in_port_t *, char **);
+static void	url_decode(char *);
+
+static int	redirect_loop;
+
+
+#define	STRNEQUAL(a,b)	(strncasecmp((a), (b), sizeof((b))-1) == 0)
+#define	ISLWS(x)	((x)=='\r' || (x)=='\n' || (x)==' ' || (x)=='\t')
+#define	SKIPLWS(x)	do { while (ISLWS((*x))) x++; } while (0)
+
+
+#define	ABOUT_URL	"about:"	/* propaganda */
+#define	FILE_URL	"file://"	/* file URL prefix */
+#define	FTP_URL		"ftp://"	/* ftp URL prefix */
+#define	HTTP_URL	"http://"	/* http URL prefix */
+
+
+/*
+ * Determine if token is the next word in buf (case insensitive).
+ * If so, advance buf past the token and any trailing LWS, and
+ * return a pointer to the token (in buf).  Otherwise, return NULL.
+ * token may be preceded by LWS.
+ * token must be followed by LWS or NUL.  (I.e, don't partial match).
+ */
+static const char *
+match_token(const char **buf, const char *token)
+{
+	const char	*p, *orig;
+	size_t		tlen;
+
+	tlen = strlen(token);
+	p = *buf;
+	SKIPLWS(p);
+	orig = p;
+	if (strncasecmp(p, token, tlen) != 0)
+		return NULL;
+	p += tlen;
+	if (*p != '\0' && !ISLWS(*p))
+		return NULL;
+	SKIPLWS(p);
+	orig = *buf;
+	*buf = p;
+	return orig;
+}
+
+#ifndef NO_AUTH
+/*
+ * Generate authorization response based on given authentication challenge.
+ * Returns -1 if an error occurred, otherwise 0.
+ * Sets response to a malloc(3)ed string; caller should free.
+ */
+static int
+auth_url(const char *challenge, char **response, const char *guser,
+	const char *gpass)
+{
+	const char	*cp, *scheme, *errormsg;
+	char		*ep, *clear, *realm;
+	char		 uuser[BUFSIZ], *gotpass;
+	const char	*upass;
+	int		 rval;
+	size_t		 len, clen, rlen;
+
+	*response = NULL;
+	clear = realm = NULL;
+	rval = -1;
+	cp = challenge;
+	scheme = "Basic";	/* only support Basic authentication */
+	gotpass = NULL;
+
+	DPRINTF("auth_url: challenge `%s'\n", challenge);
+
+	if (! match_token(&cp, scheme)) {
+		warnx("Unsupported authentication challenge `%s'",
+		    challenge);
+		goto cleanup_auth_url;
+	}
+
+#define	REALM "realm=\""
+	if (STRNEQUAL(cp, REALM))
+		cp += sizeof(REALM) - 1;
+	else {
+		warnx("Unsupported authentication challenge `%s'",
+		    challenge);
+		goto cleanup_auth_url;
+	}
+/* XXX: need to improve quoted-string parsing to support \ quoting, etc. */
+	if ((ep = strchr(cp, '\"')) != NULL) {
+		len = ep - cp;
+		realm = (char *)ftp_malloc(len + 1);
+		(void)strlcpy(realm, cp, len + 1);
+	} else {
+		warnx("Unsupported authentication challenge `%s'",
+		    challenge);
+		goto cleanup_auth_url;
+	}
+
+	fprintf(ttyout, "Username for `%s': ", realm);
+	if (guser != NULL) {
+		(void)strlcpy(uuser, guser, sizeof(uuser));
+		fprintf(ttyout, "%s\n", uuser);
+	} else {
+		(void)fflush(ttyout);
+		if (get_line(stdin, uuser, sizeof(uuser), &errormsg) < 0) {
+			warnx("%s; can't authenticate", errormsg);
+			goto cleanup_auth_url;
+		}
+	}
+	if (gpass != NULL)
+		upass = gpass;
+	else {
+		gotpass = getpass("Password: ");
+		if (gotpass == NULL) {
+			warnx("Can't read password");
+			goto cleanup_auth_url;
+		}
+		upass = gotpass;
+	}
+
+	clen = strlen(uuser) + strlen(upass) + 2;	/* user + ":" + pass + "\0" */
+	clear = (char *)ftp_malloc(clen);
+	(void)strlcpy(clear, uuser, clen);
+	(void)strlcat(clear, ":", clen);
+	(void)strlcat(clear, upass, clen);
+	if (gotpass)
+		memset(gotpass, 0, strlen(gotpass));
+
+						/* scheme + " " + enc + "\0" */
+	rlen = strlen(scheme) + 1 + (clen + 2) * 4 / 3 + 1;
+	*response = (char *)ftp_malloc(rlen);
+	(void)strlcpy(*response, scheme, rlen);
+	len = strlcat(*response, " ", rlen);
+			/* use  `clen - 1'  to not encode the trailing NUL */
+	base64_encode((unsigned char *)clear, clen - 1,
+	    (unsigned char *)*response + len);
+	memset(clear, 0, clen);
+	rval = 0;
+
+ cleanup_auth_url:
+	FREEPTR(clear);
+	FREEPTR(realm);
+	return (rval);
+}
+
+/*
+ * Encode len bytes starting at clear using base64 encoding into encoded,
+ * which should be at least ((len + 2) * 4 / 3 + 1) in size.
+ */
+static void
+base64_encode(const unsigned char *clear, size_t len, unsigned char *encoded)
+{
+	static const unsigned char enc[] =
+	    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+	unsigned char	*cp;
+	size_t	 i;
+
+	cp = encoded;
+	for (i = 0; i < len; i += 3) {
+		*(cp++) = enc[((clear[i + 0] >> 2))];
+		*(cp++) = enc[((clear[i + 0] << 4) & 0x30)
+			    | ((clear[i + 1] >> 4) & 0x0f)];
+		*(cp++) = enc[((clear[i + 1] << 2) & 0x3c)
+			    | ((clear[i + 2] >> 6) & 0x03)];
+		*(cp++) = enc[((clear[i + 2]     ) & 0x3f)];
+	}
+	*cp = '\0';
+	while (i-- > len)
+		*(--cp) = '=';
+}
+#endif
+
+/*
+ * Decode %xx escapes in given string, `in-place'.
+ */
+static void
+url_decode(char *url)
+{
+	unsigned char *p, *q;
+
+	if (EMPTYSTRING(url))
+		return;
+	p = q = (unsigned char *)url;
+
+#define	HEXTOINT(x) (x - (isdigit(x) ? '0' : (islower(x) ? 'a' : 'A') - 10))
+	while (*p) {
+		if (p[0] == '%'
+		    && p[1] && isxdigit((unsigned char)p[1])
+		    && p[2] && isxdigit((unsigned char)p[2])) {
+			*q++ = HEXTOINT(p[1]) * 16 + HEXTOINT(p[2]);
+			p+=3;
+		} else
+			*q++ = *p++;
+	}
+	*q = '\0';
+}
+
+
+/*
+ * Parse URL of form (per RFC3986):
+ *	<type>://[<user>[:<password>]@]<host>[:<port>][/<path>]
+ * Returns -1 if a parse error occurred, otherwise 0.
+ * It's the caller's responsibility to url_decode() the returned
+ * user, pass and path.
+ *
+ * Sets type to url_t, each of the given char ** pointers to a
+ * malloc(3)ed strings of the relevant section, and port to
+ * the number given, or ftpport if ftp://, or httpport if http://.
+ *
+ * XXX: this is not totally RFC3986 compliant; <path> will have the
+ * leading `/' unless it's an ftp:// URL, as this makes things easier
+ * for file:// and http:// URLs.  ftp:// URLs have the `/' between the
+ * host and the URL-path removed, but any additional leading slashes
+ * in the URL-path are retained (because they imply that we should
+ * later do "CWD" with a null argument).
+ *
+ * Examples:
+ *	 input URL			 output path
+ *	 ---------			 -----------
+ *	"http://host"			"/"
+ *	"http://host/"			"/"
+ *	"http://host/path"		"/path"
+ *	"file://host/dir/file"		"dir/file"
+ *	"ftp://host"			""
+ *	"ftp://host/"			""
+ *	"ftp://host//"			"/"
+ *	"ftp://host/dir/file"		"dir/file"
+ *	"ftp://host//dir/file"		"/dir/file"
+ */
+static int
+parse_url(const char *url, const char *desc, url_t *utype,
+		char **uuser, char **pass, char **host, char **port,
+		in_port_t *portnum, char **path)
+{
+	const char	*origurl, *tport;
+	char		*cp, *ep, *thost;
+	size_t		 len;
+
+	if (url == NULL || desc == NULL || utype == NULL || uuser == NULL
+	    || pass == NULL || host == NULL || port == NULL || portnum == NULL
+	    || path == NULL)
+		errx(1, "parse_url: invoked with NULL argument!");
+	DPRINTF("parse_url: %s `%s'\n", desc, url);
+
+	origurl = url;
+	*utype = UNKNOWN_URL_T;
+	*uuser = *pass = *host = *port = *path = NULL;
+	*portnum = 0;
+	tport = NULL;
+
+	if (STRNEQUAL(url, HTTP_URL)) {
+		url += sizeof(HTTP_URL) - 1;
+		*utype = HTTP_URL_T;
+		*portnum = HTTP_PORT;
+		tport = httpport;
+	} else if (STRNEQUAL(url, FTP_URL)) {
+		url += sizeof(FTP_URL) - 1;
+		*utype = FTP_URL_T;
+		*portnum = FTP_PORT;
+		tport = ftpport;
+	} else if (STRNEQUAL(url, FILE_URL)) {
+		url += sizeof(FILE_URL) - 1;
+		*utype = FILE_URL_T;
+	} else {
+		warnx("Invalid %s `%s'", desc, url);
+ cleanup_parse_url:
+		FREEPTR(*uuser);
+		if (*pass != NULL)
+			memset(*pass, 0, strlen(*pass));
+		FREEPTR(*pass);
+		FREEPTR(*host);
+		FREEPTR(*port);
+		FREEPTR(*path);
+		return (-1);
+	}
+
+	if (*url == '\0')
+		return (0);
+
+			/* find [user[:pass]@]host[:port] */
+	ep = strchr(url, '/');
+	if (ep == NULL)
+		thost = ftp_strdup(url);
+	else {
+		len = ep - url;
+		thost = (char *)ftp_malloc(len + 1);
+		(void)strlcpy(thost, url, len + 1);
+		if (*utype == FTP_URL_T)	/* skip first / for ftp URLs */
+			ep++;
+		*path = ftp_strdup(ep);
+	}
+
+	cp = strchr(thost, '@');	/* look for user[:pass]@ in URLs */
+	if (cp != NULL) {
+		if (*utype == FTP_URL_T)
+			anonftp = 0;	/* disable anonftp */
+		*uuser = thost;
+		*cp = '\0';
+		thost = ftp_strdup(cp + 1);
+		cp = strchr(*uuser, ':');
+		if (cp != NULL) {
+			*cp = '\0';
+			*pass = ftp_strdup(cp + 1);
+		}
+		url_decode(*uuser);
+		if (*pass)
+			url_decode(*pass);
+	}
+
+#ifdef INET6
+			/*
+			 * Check if thost is an encoded IPv6 address, as per
+			 * RFC3986:
+			 *	`[' ipv6-address ']'
+			 */
+	if (*thost == '[') {
+		cp = thost + 1;
+		if ((ep = strchr(cp, ']')) == NULL ||
+		    (ep[1] != '\0' && ep[1] != ':')) {
+			warnx("Invalid address `%s' in %s `%s'",
+			    thost, desc, origurl);
+			goto cleanup_parse_url;
+		}
+		len = ep - cp;		/* change `[xyz]' -> `xyz' */
+		memmove(thost, thost + 1, len);
+		thost[len] = '\0';
+		if (! isipv6addr(thost)) {
+			warnx("Invalid IPv6 address `%s' in %s `%s'",
+			    thost, desc, origurl);
+			goto cleanup_parse_url;
+		}
+		cp = ep + 1;
+		if (*cp == ':')
+			cp++;
+		else
+			cp = NULL;
+	} else
+#endif /* INET6 */
+		if ((cp = strchr(thost, ':')) != NULL)
+			*cp++ = '\0';
+	*host = thost;
+
+			/* look for [:port] */
+	if (cp != NULL) {
+		unsigned long	nport;
+
+		nport = strtoul(cp, &ep, 10);
+		if (*cp == '\0' || *ep != '\0' ||
+		    nport < 1 || nport > MAX_IN_PORT_T) {
+			warnx("Unknown port `%s' in %s `%s'",
+			    cp, desc, origurl);
+			goto cleanup_parse_url;
+		}
+		*portnum = nport;
+		tport = cp;
+	}
+
+	if (tport != NULL)
+		*port = ftp_strdup(tport);
+	if (*path == NULL) {
+		const char *emptypath = "/";
+		if (*utype == FTP_URL_T)	/* skip first / for ftp URLs */
+			emptypath++;
+		*path = ftp_strdup(emptypath);
+	}
+
+	DPRINTF("parse_url: user `%s' pass `%s' host %s port %s(%d) "
+	    "path `%s'\n",
+	    STRorNULL(*uuser), STRorNULL(*pass),
+	    STRorNULL(*host), STRorNULL(*port),
+	    *portnum ? *portnum : -1, STRorNULL(*path));
+
+	return (0);
+}
+
+sigjmp_buf	httpabort;
+
+/*
+ * Retrieve URL, via a proxy if necessary, using HTTP.
+ * If proxyenv is set, use that for the proxy, otherwise try ftp_proxy or
+ * http_proxy as appropriate.
+ * Supports HTTP redirects.
+ * Returns 1 on failure, 0 on completed xfer, -1 if ftp connection
+ * is still open (e.g, ftp xfer with trailing /)
+ */
+static int
+fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
+{
+	struct addrinfo		hints, *res, *res0 = NULL;
+	int			error;
+	sigfunc volatile	oldintr;
+	sigfunc volatile	oldintp;
+	int volatile		s;
+	struct stat		sb;
+	int volatile		ischunked;
+	int volatile		isproxy;
+	int volatile		rval;
+	int volatile		hcode;
+	int			len;
+	size_t			flen;
+	static size_t		bufsize;
+	static char		*xferbuf;
+	const char		*cp, *token;
+	char			*ep;
+	char			buf[FTPBUFLEN];
+	const char		*errormsg;
+	char			*volatile savefile;
+	char			*volatile auth;
+	char			*volatile location;
+	char			*volatile message;
+	char			*uuser, *pass, *host, *port, *path;
+	char			*volatile decodedpath;
+	char			*puser, *ppass, *useragent;
+	off_t			hashbytes, rangestart, rangeend, entitylen;
+	int			(*volatile closefunc)(FILE *);
+	FILE			*volatile fin;
+	FILE			*volatile fout;
+	time_t			mtime;
+	url_t			urltype;
+	in_port_t		portnum;
+
+	DPRINTF("fetch_url: `%s' proxyenv `%s'\n", url, STRorNULL(proxyenv));
+
+	oldintr = oldintp = NULL;
+	closefunc = NULL;
+	fin = fout = NULL;
+	s = -1;
+	savefile = NULL;
+	auth = location = message = NULL;
+	ischunked = isproxy = hcode = 0;
+	rval = 1;
+	uuser = pass = host = path = decodedpath = puser = ppass = NULL;
+
+	if (parse_url(url, "URL", &urltype, &uuser, &pass, &host, &port,
+	    &portnum, &path) == -1)
+		goto cleanup_fetch_url;
+
+	if (urltype == FILE_URL_T && ! EMPTYSTRING(host)
+	    && strcasecmp(host, "localhost") != 0) {
+		warnx("No support for non local file URL `%s'", url);
+		goto cleanup_fetch_url;
+	}
+
+	if (EMPTYSTRING(path)) {
+		if (urltype == FTP_URL_T) {
+			rval = fetch_ftp(url);
+			goto cleanup_fetch_url;
+		}
+		if (urltype != HTTP_URL_T || outfile == NULL)  {
+			warnx("Invalid URL (no file after host) `%s'", url);
+			goto cleanup_fetch_url;
+		}
+	}
+
+	decodedpath = ftp_strdup(path);
+	url_decode(decodedpath);
+
+	if (outfile)
+		savefile = ftp_strdup(outfile);
+	else {
+		cp = strrchr(decodedpath, '/');		/* find savefile */
+		if (cp != NULL)
+			savefile = ftp_strdup(cp + 1);
+		else
+			savefile = ftp_strdup(decodedpath);
+	}
+	DPRINTF("fetch_url: savefile `%s'\n", savefile);
+	if (EMPTYSTRING(savefile)) {
+		if (urltype == FTP_URL_T) {
+			rval = fetch_ftp(url);
+			goto cleanup_fetch_url;
+		}
+		warnx("No file after directory (you must specify an "
+		    "output file) `%s'", url);
+		goto cleanup_fetch_url;
+	}
+
+	restart_point = 0;
+	filesize = -1;
+	rangestart = rangeend = entitylen = -1;
+	mtime = -1;
+	if (restartautofetch) {
+		if (strcmp(savefile, "-") != 0 && *savefile != '|' &&
+		    stat(savefile, &sb) == 0)
+			restart_point = sb.st_size;
+	}
+	if (urltype == FILE_URL_T) {		/* file:// URLs */
+		direction = "copied";
+		fin = fopen(decodedpath, "r");
+		if (fin == NULL) {
+			warn("Can't open `%s'", decodedpath);
+			goto cleanup_fetch_url;
+		}
+		if (fstat(fileno(fin), &sb) == 0) {
+			mtime = sb.st_mtime;
+			filesize = sb.st_size;
+		}
+		if (restart_point) {
+			if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
+				warn("Can't seek to restart `%s'",
+				    decodedpath);
+				goto cleanup_fetch_url;
+			}
+		}
+		if (verbose) {
+			fprintf(ttyout, "Copying %s", decodedpath);
+			if (restart_point)
+				fprintf(ttyout, " (restarting at " LLF ")",
+				    (LLT)restart_point);
+			fputs("\n", ttyout);
+		}
+	} else {				/* ftp:// or http:// URLs */
+		const char *leading;
+		int hasleading;
+
+		if (proxyenv == NULL) {
+			if (urltype == HTTP_URL_T)
+				proxyenv = getoptionvalue("http_proxy");
+			else if (urltype == FTP_URL_T)
+				proxyenv = getoptionvalue("ftp_proxy");
+		}
+		direction = "retrieved";
+		if (! EMPTYSTRING(proxyenv)) {			/* use proxy */
+			url_t purltype;
+			char *phost, *ppath;
+			char *pport, *no_proxy;
+			in_port_t pportnum;
+
+			isproxy = 1;
+
+				/* check URL against list of no_proxied sites */
+			no_proxy = getoptionvalue("no_proxy");
+			if (! EMPTYSTRING(no_proxy)) {
+				char *np, *np_copy, *np_iter;
+				unsigned long np_port;
+				size_t hlen, plen;
+
+				np_iter = np_copy = ftp_strdup(no_proxy);
+				hlen = strlen(host);
+				while ((cp = strsep(&np_iter, " ,")) != NULL) {
+					if (*cp == '\0')
+						continue;
+					if ((np = strrchr(cp, ':')) != NULL) {
+						*np++ =  '\0';
+						np_port = strtoul(np, &ep, 10);
+						if (*np == '\0' || *ep != '\0')
+							continue;
+						if (np_port != portnum)
+							continue;
+					}
+					plen = strlen(cp);
+					if (hlen < plen)
+						continue;
+					if (strncasecmp(host + hlen - plen,
+					    cp, plen) == 0) {
+						isproxy = 0;
+						break;
+					}
+				}
+				FREEPTR(np_copy);
+				if (isproxy == 0 && urltype == FTP_URL_T) {
+					rval = fetch_ftp(url);
+					goto cleanup_fetch_url;
+				}
+			}
+
+			if (isproxy) {
+				if (restart_point) {
+					warnx("Can't restart via proxy URL `%s'",
+					    proxyenv);
+					goto cleanup_fetch_url;
+				}
+				if (parse_url(proxyenv, "proxy URL", &purltype,
+				    &puser, &ppass, &phost, &pport, &pportnum,
+				    &ppath) == -1)
+					goto cleanup_fetch_url;
+
+				if ((purltype != HTTP_URL_T
+				     && purltype != FTP_URL_T) ||
+				    EMPTYSTRING(phost) ||
+				    (! EMPTYSTRING(ppath)
+				     && strcmp(ppath, "/") != 0)) {
+					warnx("Malformed proxy URL `%s'",
+					    proxyenv);
+					FREEPTR(phost);
+					FREEPTR(pport);
+					FREEPTR(ppath);
+					goto cleanup_fetch_url;
+				}
+				if (isipv6addr(host) &&
+				    strchr(host, '%') != NULL) {
+					warnx(
+"Scoped address notation `%s' disallowed via web proxy",
+					    host);
+					FREEPTR(phost);
+					FREEPTR(pport);
+					FREEPTR(ppath);
+					goto cleanup_fetch_url;
+				}
+
+				FREEPTR(host);
+				host = phost;
+				FREEPTR(port);
+				port = pport;
+				FREEPTR(path);
+				path = ftp_strdup(url);
+				FREEPTR(ppath);
+			}
+		} /* ! EMPTYSTRING(proxyenv) */
+
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_flags = 0;
+		hints.ai_family = family;
+		hints.ai_socktype = SOCK_STREAM;
+		hints.ai_protocol = 0;
+		error = getaddrinfo(host, port, &hints, &res0);
+		if (error) {
+			warnx("Can't lookup `%s:%s': %s", host, port,
+			    (error == EAI_SYSTEM) ? strerror(errno)
+						  : gai_strerror(error));
+			goto cleanup_fetch_url;
+		}
+		if (res0->ai_canonname)
+			host = res0->ai_canonname;
+
+		s = -1;
+		for (res = res0; res; res = res->ai_next) {
+			char	hname[NI_MAXHOST], sname[NI_MAXSERV];
+
+			ai_unmapped(res);
+			if (getnameinfo(res->ai_addr, res->ai_addrlen,
+			    hname, sizeof(hname), sname, sizeof(sname),
+			    NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
+				strlcpy(hname, "?", sizeof(hname));
+				strlcpy(sname, "?", sizeof(sname));
+			}
+
+			if (verbose && res0->ai_next) {
+				fprintf(ttyout, "Trying %s:%s ...\n",
+				    hname, sname);
+			}
+
+			s = socket(res->ai_family, SOCK_STREAM,
+			    res->ai_protocol);
+			if (s < 0) {
+				warn(
+				    "Can't create socket for connection to "
+				    "`%s:%s'", hname, sname);
+				continue;
+			}
+
+			if (ftp_connect(s, res->ai_addr, res->ai_addrlen) < 0) {
+				close(s);
+				s = -1;
+				continue;
+			}
+
+			/* success */
+			break;
+		}
+
+		if (s < 0) {
+			warnx("Can't connect to `%s:%s'", host, port);
+			goto cleanup_fetch_url;
+		}
+
+		fin = fdopen(s, "r+");
+		/*
+		 * Construct and send the request.
+		 */
+		if (verbose)
+			fprintf(ttyout, "Requesting %s\n", url);
+		leading = "  (";
+		hasleading = 0;
+		if (isproxy) {
+			if (verbose) {
+				fprintf(ttyout, "%svia %s:%s", leading,
+				    host, port);
+				leading = ", ";
+				hasleading++;
+			}
+			fprintf(fin, "GET %s HTTP/1.0\r\n", path);
+			if (flushcache)
+				fprintf(fin, "Pragma: no-cache\r\n");
+		} else {
+			fprintf(fin, "GET %s HTTP/1.1\r\n", path);
+			if (strchr(host, ':')) {
+				char *h, *p;
+
+				/*
+				 * strip off IPv6 scope identifier, since it is
+				 * local to the node
+				 */
+				h = ftp_strdup(host);
+				if (isipv6addr(h) &&
+				    (p = strchr(h, '%')) != NULL) {
+					*p = '\0';
+				}
+				fprintf(fin, "Host: [%s]", h);
+				free(h);
+			} else
+				fprintf(fin, "Host: %s", host);
+			if (portnum != HTTP_PORT)
+				fprintf(fin, ":%u", portnum);
+			fprintf(fin, "\r\n");
+			fprintf(fin, "Accept: */*\r\n");
+			fprintf(fin, "Connection: close\r\n");
+			if (restart_point) {
+				fputs(leading, ttyout);
+				fprintf(fin, "Range: bytes=" LLF "-\r\n",
+				    (LLT)restart_point);
+				fprintf(ttyout, "restarting at " LLF,
+				    (LLT)restart_point);
+				leading = ", ";
+				hasleading++;
+			}
+			if (flushcache)
+				fprintf(fin, "Cache-Control: no-cache\r\n");
+		}
+		if ((useragent=getenv("FTPUSERAGENT")) != NULL) {
+			fprintf(fin, "User-Agent: %s\r\n", useragent);
+		} else {
+			fprintf(fin, "User-Agent: %s/%s\r\n",
+			    FTP_PRODUCT, FTP_VERSION);
+		}
+		if (wwwauth) {
+			if (verbose) {
+				fprintf(ttyout, "%swith authorization",
+				    leading);
+				leading = ", ";
+				hasleading++;
+			}
+			fprintf(fin, "Authorization: %s\r\n", wwwauth);
+		}
+		if (proxyauth) {
+			if (verbose) {
+				fprintf(ttyout,
+				    "%swith proxy authorization", leading);
+				leading = ", ";
+				hasleading++;
+			}
+			fprintf(fin, "Proxy-Authorization: %s\r\n", proxyauth);
+		}
+		if (verbose && hasleading)
+			fputs(")\n", ttyout);
+		fprintf(fin, "\r\n");
+		if (fflush(fin) == EOF) {
+			warn("Writing HTTP request");
+			goto cleanup_fetch_url;
+		}
+
+				/* Read the response */
+		len = get_line(fin, buf, sizeof(buf), &errormsg);
+		if (len < 0) {
+			if (*errormsg == '\n')
+				errormsg++;
+			warnx("Receiving HTTP reply: %s", errormsg);
+			goto cleanup_fetch_url;
+		}
+		while (len > 0 && (ISLWS(buf[len-1])))
+			buf[--len] = '\0';
+		DPRINTF("fetch_url: received `%s'\n", buf);
+
+				/* Determine HTTP response code */
+		cp = strchr(buf, ' ');
+		if (cp == NULL)
+			goto improper;
+		else
+			cp++;
+		hcode = strtol(cp, &ep, 10);
+		if (*ep != '\0' && !isspace((unsigned char)*ep))
+			goto improper;
+		message = ftp_strdup(cp);
+
+				/* Read the rest of the header. */
+		while (1) {
+			len = get_line(fin, buf, sizeof(buf), &errormsg);
+			if (len < 0) {
+				if (*errormsg == '\n')
+					errormsg++;
+				warnx("Receiving HTTP reply: %s", errormsg);
+				goto cleanup_fetch_url;
+			}
+			while (len > 0 && (ISLWS(buf[len-1])))
+				buf[--len] = '\0';
+			if (len == 0)
+				break;
+			DPRINTF("fetch_url: received `%s'\n", buf);
+
+		/*
+		 * Look for some headers
+		 */
+
+			cp = buf;
+
+			if (match_token(&cp, "Content-Length:")) {
+				filesize = STRTOLL(cp, &ep, 10);
+				if (filesize < 0 || *ep != '\0')
+					goto improper;
+				DPRINTF("fetch_url: parsed len as: " LLF "\n",
+				    (LLT)filesize);
+
+			} else if (match_token(&cp, "Content-Range:")) {
+				if (! match_token(&cp, "bytes"))
+					goto improper;
+
+				if (*cp == '*')
+					cp++;
+				else {
+					rangestart = STRTOLL(cp, &ep, 10);
+					if (rangestart < 0 || *ep != '-')
+						goto improper;
+					cp = ep + 1;
+					rangeend = STRTOLL(cp, &ep, 10);
+					if (rangeend < 0 || rangeend < rangestart)
+						goto improper;
+					cp = ep;
+				}
+				if (*cp != '/')
+					goto improper;
+				cp++;
+				if (*cp == '*')
+					cp++;
+				else {
+					entitylen = STRTOLL(cp, &ep, 10);
+					if (entitylen < 0)
+						goto improper;
+					cp = ep;
+				}
+				if (*cp != '\0')
+					goto improper;
+
+#ifndef NO_DEBUG
+				if (ftp_debug) {
+					fprintf(ttyout, "parsed range as: ");
+					if (rangestart == -1)
+						fprintf(ttyout, "*");
+					else
+						fprintf(ttyout, LLF "-" LLF,
+						    (LLT)rangestart,
+						    (LLT)rangeend);
+					fprintf(ttyout, "/" LLF "\n", (LLT)entitylen);
+				}
+#endif
+				if (! restart_point) {
+					warnx(
+				    "Received unexpected Content-Range header");
+					goto cleanup_fetch_url;
+				}
+
+			} else if (match_token(&cp, "Last-Modified:")) {
+				struct tm parsed;
+				char *t;
+
+				memset(&parsed, 0, sizeof(parsed));
+							/* RFC1123 */
+				if ((t = strptime(cp,
+						"%a, %d %b %Y %H:%M:%S GMT",
+						&parsed))
+							/* RFC0850 */
+				    || (t = strptime(cp,
+						"%a, %d-%b-%y %H:%M:%S GMT",
+						&parsed))
+							/* asctime */
+				    || (t = strptime(cp,
+						"%a, %b %d %H:%M:%S %Y",
+						&parsed))) {
+					parsed.tm_isdst = -1;
+					if (*t == '\0')
+						mtime = timegm(&parsed);
+#ifndef NO_DEBUG
+					if (ftp_debug && mtime != -1) {
+						fprintf(ttyout,
+						    "parsed date as: %s",
+						rfc2822time(localtime(&mtime)));
+					}
+#endif
+				}
+
+			} else if (match_token(&cp, "Location:")) {
+				location = ftp_strdup(cp);
+				DPRINTF("fetch_url: parsed location as `%s'\n",
+				    cp);
+
+			} else if (match_token(&cp, "Transfer-Encoding:")) {
+				if (match_token(&cp, "binary")) {
+					warnx(
+			"Bogus transfer encoding `binary' (fetching anyway)");
+					continue;
+				}
+				if (! (token = match_token(&cp, "chunked"))) {
+					warnx(
+				    "Unsupported transfer encoding `%s'",
+					    token);
+					goto cleanup_fetch_url;
+				}
+				ischunked++;
+				DPRINTF("fetch_url: using chunked encoding\n");
+
+			} else if (match_token(&cp, "Proxy-Authenticate:")
+				|| match_token(&cp, "WWW-Authenticate:")) {
+				if (! (token = match_token(&cp, "Basic"))) {
+					DPRINTF(
+			"fetch_url: skipping unknown auth scheme `%s'\n",
+						    token);
+					continue;
+				}
+				FREEPTR(auth);
+				auth = ftp_strdup(token);
+				DPRINTF("fetch_url: parsed auth as `%s'\n", cp);
+			}
+
+		}
+				/* finished parsing header */
+
+		switch (hcode) {
+		case 200:
+			break;
+		case 206:
+			if (! restart_point) {
+				warnx("Not expecting partial content header");
+				goto cleanup_fetch_url;
+			}
+			break;
+		case 300:
+		case 301:
+		case 302:
+		case 303:
+		case 305:
+		case 307:
+			if (EMPTYSTRING(location)) {
+				warnx(
+				"No redirection Location provided by server");
+				goto cleanup_fetch_url;
+			}
+			if (redirect_loop++ > 5) {
+				warnx("Too many redirections requested");
+				goto cleanup_fetch_url;
+			}
+			if (hcode == 305) {
+				if (verbose)
+					fprintf(ttyout, "Redirected via %s\n",
+					    location);
+				rval = fetch_url(url, location,
+				    proxyauth, wwwauth);
+			} else {
+				if (verbose)
+					fprintf(ttyout, "Redirected to %s\n",
+					    location);
+				rval = go_fetch(location);
+			}
+			goto cleanup_fetch_url;
+#ifndef NO_AUTH
+		case 401:
+		case 407:
+		    {
+			char **authp;
+			char *auser, *apass;
+
+			if (hcode == 401) {
+				authp = &wwwauth;
+				auser = uuser;
+				apass = pass;
+			} else {
+				authp = &proxyauth;
+				auser = puser;
+				apass = ppass;
+			}
+			if (verbose || *authp == NULL ||
+			    auser == NULL || apass == NULL)
+				fprintf(ttyout, "%s\n", message);
+			if (EMPTYSTRING(auth)) {
+				warnx(
+			    "No authentication challenge provided by server");
+				goto cleanup_fetch_url;
+			}
+			if (*authp != NULL) {
+				char reply[10];
+
+				fprintf(ttyout,
+				    "Authorization failed. Retry (y/n)? ");
+				if (get_line(stdin, reply, sizeof(reply), NULL)
+				    < 0) {
+					goto cleanup_fetch_url;
+				}
+				if (tolower((unsigned char)reply[0]) != 'y')
+					goto cleanup_fetch_url;
+				auser = NULL;
+				apass = NULL;
+			}
+			if (auth_url(auth, authp, auser, apass) == 0) {
+				rval = fetch_url(url, proxyenv,
+				    proxyauth, wwwauth);
+				memset(*authp, 0, strlen(*authp));
+				FREEPTR(*authp);
+			}
+			goto cleanup_fetch_url;
+		    }
+#endif
+		default:
+			if (message)
+				warnx("Error retrieving file `%s'", message);
+			else
+				warnx("Unknown error retrieving file");
+			goto cleanup_fetch_url;
+		}
+	}		/* end of ftp:// or http:// specific setup */
+
+			/* Open the output file. */
+	if (strcmp(savefile, "-") == 0) {
+		fout = stdout;
+	} else if (*savefile == '|') {
+		oldintp = xsignal(SIGPIPE, SIG_IGN);
+		fout = popen(savefile + 1, "w");
+		if (fout == NULL) {
+			warn("Can't execute `%s'", savefile + 1);
+			goto cleanup_fetch_url;
+		}
+		closefunc = pclose;
+	} else {
+		if ((rangeend != -1 && rangeend <= restart_point) ||
+		    (rangestart == -1 && filesize != -1 && filesize <= restart_point)) {
+			/* already done */
+			if (verbose)
+				fprintf(ttyout, "already done\n");
+			rval = 0;
+			goto cleanup_fetch_url;
+		}
+		if (restart_point && rangestart != -1) {
+			if (entitylen != -1)
+				filesize = entitylen;
+			if (rangestart != restart_point) {
+				warnx(
+				    "Size of `%s' differs from save file `%s'",
+				    url, savefile);
+				goto cleanup_fetch_url;
+			}
+			fout = fopen(savefile, "a");
+		} else
+			fout = fopen(savefile, "w");
+		if (fout == NULL) {
+			warn("Can't open `%s'", savefile);
+			goto cleanup_fetch_url;
+		}
+		closefunc = fclose;
+	}
+
+			/* Trap signals */
+	if (sigsetjmp(httpabort, 1))
+		goto cleanup_fetch_url;
+	(void)xsignal(SIGQUIT, psummary);
+	oldintr = xsignal(SIGINT, aborthttp);
+
+	if ((size_t)rcvbuf_size > bufsize) {
+		if (xferbuf)
+			(void)free(xferbuf);
+		bufsize = rcvbuf_size;
+		xferbuf = ftp_malloc(bufsize);
+	}
+
+	bytes = 0;
+	hashbytes = mark;
+	progressmeter(-1);
+
+			/* Finally, suck down the file. */
+	do {
+		long chunksize;
+		short lastchunk;
+
+		chunksize = 0;
+		lastchunk = 0;
+					/* read chunk-size */
+		if (ischunked) {
+			if (fgets(xferbuf, bufsize, fin) == NULL) {
+				warnx("Unexpected EOF reading chunk-size");
+				goto cleanup_fetch_url;
+			}
+			errno = 0;
+			chunksize = strtol(xferbuf, &ep, 16);
+			if (ep == xferbuf) {
+				warnx("Invalid chunk-size");
+				goto cleanup_fetch_url;
+			}
+			if (errno == ERANGE || chunksize < 0) {
+				errno = ERANGE;
+				warn("Chunk-size `%.*s'",
+				    (int)(ep-xferbuf), xferbuf);
+				goto cleanup_fetch_url;
+			}
+
+				/*
+				 * XXX:	Work around bug in Apache 1.3.9 and
+				 *	1.3.11, which incorrectly put trailing
+				 *	space after the chunk-size.
+				 */
+			while (*ep == ' ')
+				ep++;
+
+					/* skip [ chunk-ext ] */
+			if (*ep == ';') {
+				while (*ep && *ep != '\r')
+					ep++;
+			}
+
+			if (strcmp(ep, "\r\n") != 0) {
+				warnx("Unexpected data following chunk-size");
+				goto cleanup_fetch_url;
+			}
+			DPRINTF("fetch_url: got chunk-size of " LLF "\n",
+			    (LLT)chunksize);
+			if (chunksize == 0) {
+				lastchunk = 1;
+				goto chunkdone;
+			}
+		}
+					/* transfer file or chunk */
+		while (1) {
+			struct timeval then, now, td;
+			off_t bufrem;
+
+			if (rate_get)
+				(void)gettimeofday(&then, NULL);
+			bufrem = rate_get ? rate_get : (off_t)bufsize;
+			if (ischunked)
+				bufrem = MIN(chunksize, bufrem);
+			while (bufrem > 0) {
+				flen = fread(xferbuf, sizeof(char),
+				    MIN((off_t)bufsize, bufrem), fin);
+				if (flen <= 0)
+					goto chunkdone;
+				bytes += flen;
+				bufrem -= flen;
+				if (fwrite(xferbuf, sizeof(char), flen, fout)
+				    != flen) {
+					warn("Writing `%s'", savefile);
+					goto cleanup_fetch_url;
+				}
+				if (hash && !progress) {
+					while (bytes >= hashbytes) {
+						(void)putc('#', ttyout);
+						hashbytes += mark;
+					}
+					(void)fflush(ttyout);
+				}
+				if (ischunked) {
+					chunksize -= flen;
+					if (chunksize <= 0)
+						break;
+				}
+			}
+			if (rate_get) {
+				while (1) {
+					(void)gettimeofday(&now, NULL);
+					timersub(&now, &then, &td);
+					if (td.tv_sec > 0)
+						break;
+					usleep(1000000 - td.tv_usec);
+				}
+			}
+			if (ischunked && chunksize <= 0)
+				break;
+		}
+					/* read CRLF after chunk*/
+ chunkdone:
+		if (ischunked) {
+			if (fgets(xferbuf, bufsize, fin) == NULL) {
+				warnx("Unexpected EOF reading chunk CRLF");
+				goto cleanup_fetch_url;
+			}
+			if (strcmp(xferbuf, "\r\n") != 0) {
+				warnx("Unexpected data following chunk");
+				goto cleanup_fetch_url;
+			}
+			if (lastchunk)
+				break;
+		}
+	} while (ischunked);
+
+/* XXX: deal with optional trailer & CRLF here? */
+
+	if (hash && !progress && bytes > 0) {
+		if (bytes < mark)
+			(void)putc('#', ttyout);
+		(void)putc('\n', ttyout);
+	}
+	if (ferror(fin)) {
+		warn("Reading file");
+		goto cleanup_fetch_url;
+	}
+	progressmeter(1);
+	(void)fflush(fout);
+	if (closefunc == fclose && mtime != -1) {
+		struct timeval tval[2];
+
+		(void)gettimeofday(&tval[0], NULL);
+		tval[1].tv_sec = mtime;
+		tval[1].tv_usec = 0;
+		(*closefunc)(fout);
+		fout = NULL;
+
+		if (utimes(savefile, tval) == -1) {
+			fprintf(ttyout,
+			    "Can't change modification time to %s",
+			    rfc2822time(localtime(&mtime)));
+		}
+	}
+	if (bytes > 0)
+		ptransfer(0);
+	bytes = 0;
+
+	rval = 0;
+	goto cleanup_fetch_url;
+
+ improper:
+	warnx("Improper response from `%s:%s'", host, port);
+
+ cleanup_fetch_url:
+	if (oldintr)
+		(void)xsignal(SIGINT, oldintr);
+	if (oldintp)
+		(void)xsignal(SIGPIPE, oldintp);
+	if (fin != NULL)
+		fclose(fin);
+	else if (s != -1)
+		close(s);
+	if (closefunc != NULL && fout != NULL)
+		(*closefunc)(fout);
+	if (res0)
+		freeaddrinfo(res0);
+	FREEPTR(savefile);
+	FREEPTR(uuser);
+	if (pass != NULL)
+		memset(pass, 0, strlen(pass));
+	FREEPTR(pass);
+	FREEPTR(host);
+	FREEPTR(port);
+	FREEPTR(path);
+	FREEPTR(decodedpath);
+	FREEPTR(puser);
+	if (ppass != NULL)
+		memset(ppass, 0, strlen(ppass));
+	FREEPTR(ppass);
+	FREEPTR(auth);
+	FREEPTR(location);
+	FREEPTR(message);
+	return (rval);
+}
+
+/*
+ * Abort a HTTP retrieval
+ */
+void
+aborthttp(int notused)
+{
+	char msgbuf[100];
+	size_t len;
+
+	sigint_raised = 1;
+	alarmtimer(0);
+	len = strlcpy(msgbuf, "\nHTTP fetch aborted.\n", sizeof(msgbuf));
+	write(fileno(ttyout), msgbuf, len);
+	siglongjmp(httpabort, 1);
+}
+
+/*
+ * Retrieve ftp URL or classic ftp argument using FTP.
+ * Returns 1 on failure, 0 on completed xfer, -1 if ftp connection
+ * is still open (e.g, ftp xfer with trailing /)
+ */
+static int
+fetch_ftp(const char *url)
+{
+	char		*cp, *xargv[5], rempath[MAXPATHLEN];
+	char		*host, *path, *dir, *file, *uuser, *pass;
+	char		*port;
+	char		 cmdbuf[MAXPATHLEN];
+	char		 dirbuf[4];
+	int		 dirhasglob, filehasglob, rval, transtype, xargc;
+	int		 oanonftp, oautologin;
+	in_port_t	 portnum;
+	url_t		 urltype;
+
+	DPRINTF("fetch_ftp: `%s'\n", url);
+	host = path = dir = file = uuser = pass = NULL;
+	port = NULL;
+	rval = 1;
+	transtype = TYPE_I;
+
+	if (STRNEQUAL(url, FTP_URL)) {
+		if ((parse_url(url, "URL", &urltype, &uuser, &pass,
+		    &host, &port, &portnum, &path) == -1) ||
+		    (uuser != NULL && *uuser == '\0') ||
+		    EMPTYSTRING(host)) {
+			warnx("Invalid URL `%s'", url);
+			goto cleanup_fetch_ftp;
+		}
+		/*
+		 * Note: Don't url_decode(path) here.  We need to keep the
+		 * distinction between "/" and "%2F" until later.
+		 */
+
+					/* check for trailing ';type=[aid]' */
+		if (! EMPTYSTRING(path) && (cp = strrchr(path, ';')) != NULL) {
+			if (strcasecmp(cp, ";type=a") == 0)
+				transtype = TYPE_A;
+			else if (strcasecmp(cp, ";type=i") == 0)
+				transtype = TYPE_I;
+			else if (strcasecmp(cp, ";type=d") == 0) {
+				warnx(
+			    "Directory listing via a URL is not supported");
+				goto cleanup_fetch_ftp;
+			} else {
+				warnx("Invalid suffix `%s' in URL `%s'", cp,
+				    url);
+				goto cleanup_fetch_ftp;
+			}
+			*cp = 0;
+		}
+	} else {			/* classic style `[user@]host:[file]' */
+		urltype = CLASSIC_URL_T;
+		host = ftp_strdup(url);
+		cp = strchr(host, '@');
+		if (cp != NULL) {
+			*cp = '\0';
+			uuser = host;
+			anonftp = 0;	/* disable anonftp */
+			host = ftp_strdup(cp + 1);
+		}
+		cp = strchr(host, ':');
+		if (cp != NULL) {
+			*cp = '\0';
+			path = ftp_strdup(cp + 1);
+		}
+	}
+	if (EMPTYSTRING(host))
+		goto cleanup_fetch_ftp;
+
+			/* Extract the file and (if present) directory name. */
+	dir = path;
+	if (! EMPTYSTRING(dir)) {
+		/*
+		 * If we are dealing with classic `[user@]host:[path]' syntax,
+		 * then a path of the form `/file' (resulting from input of the
+		 * form `host:/file') means that we should do "CWD /" before
+		 * retrieving the file.  So we set dir="/" and file="file".
+		 *
+		 * But if we are dealing with URLs like `ftp://host/path' then
+		 * a path of the form `/file' (resulting from a URL of the form
+		 * `ftp://host//file') means that we should do `CWD ' (with an
+		 * empty argument) before retrieving the file.  So we set
+		 * dir="" and file="file".
+		 *
+		 * If the path does not contain / at all, we set dir=NULL.
+		 * (We get a path without any slashes if we are dealing with
+		 * classic `[user@]host:[file]' or URL `ftp://host/file'.)
+		 *
+		 * In all other cases, we set dir to a string that does not
+		 * include the final '/' that separates the dir part from the
+		 * file part of the path.  (This will be the empty string if
+		 * and only if we are dealing with a path of the form `/file'
+		 * resulting from an URL of the form `ftp://host//file'.)
+		 */
+		cp = strrchr(dir, '/');
+		if (cp == dir && urltype == CLASSIC_URL_T) {
+			file = cp + 1;
+			(void)strlcpy(dirbuf, "/", sizeof(dirbuf));
+			dir = dirbuf;
+		} else if (cp != NULL) {
+			*cp++ = '\0';
+			file = cp;
+		} else {
+			file = dir;
+			dir = NULL;
+		}
+	} else
+		dir = NULL;
+	if (urltype == FTP_URL_T && file != NULL) {
+		url_decode(file);
+		/* but still don't url_decode(dir) */
+	}
+	DPRINTF("fetch_ftp: user `%s' pass `%s' host %s port %s "
+	    "path `%s' dir `%s' file `%s'\n",
+	    STRorNULL(uuser), STRorNULL(pass),
+	    STRorNULL(host), STRorNULL(port),
+	    STRorNULL(path), STRorNULL(dir), STRorNULL(file));
+
+	dirhasglob = filehasglob = 0;
+	if (doglob && urltype == CLASSIC_URL_T) {
+		if (! EMPTYSTRING(dir) && strpbrk(dir, "*?[]{}") != NULL)
+			dirhasglob = 1;
+		if (! EMPTYSTRING(file) && strpbrk(file, "*?[]{}") != NULL)
+			filehasglob = 1;
+	}
+
+			/* Set up the connection */
+	oanonftp = anonftp;
+	if (connected)
+		disconnect(0, NULL);
+	anonftp = oanonftp;
+	(void)strlcpy(cmdbuf, getprogname(), sizeof(cmdbuf));
+	xargv[0] = cmdbuf;
+	xargv[1] = host;
+	xargv[2] = NULL;
+	xargc = 2;
+	if (port) {
+		xargv[2] = port;
+		xargv[3] = NULL;
+		xargc = 3;
+	}
+	oautologin = autologin;
+		/* don't autologin in setpeer(), use ftp_login() below */
+	autologin = 0;
+	setpeer(xargc, xargv);
+	autologin = oautologin;
+	if ((connected == 0) ||
+	    (connected == 1 && !ftp_login(host, uuser, pass))) {
+		warnx("Can't connect or login to host `%s:%s'",
+			host, port ? port : "?");
+		goto cleanup_fetch_ftp;
+	}
+
+	switch (transtype) {
+	case TYPE_A:
+		setascii(1, xargv);
+		break;
+	case TYPE_I:
+		setbinary(1, xargv);
+		break;
+	default:
+		errx(1, "fetch_ftp: unknown transfer type %d", transtype);
+	}
+
+		/*
+		 * Change directories, if necessary.
+		 *
+		 * Note: don't use EMPTYSTRING(dir) below, because
+		 * dir=="" means something different from dir==NULL.
+		 */
+	if (dir != NULL && !dirhasglob) {
+		char *nextpart;
+
+		/*
+		 * If we are dealing with a classic `[user@]host:[path]'
+		 * (urltype is CLASSIC_URL_T) then we have a raw directory
+		 * name (not encoded in any way) and we can change
+		 * directories in one step.
+		 *
+		 * If we are dealing with an `ftp://host/path' URL
+		 * (urltype is FTP_URL_T), then RFC3986 says we need to
+		 * send a separate CWD command for each unescaped "/"
+		 * in the path, and we have to interpret %hex escaping
+		 * *after* we find the slashes.  It's possible to get
+		 * empty components here, (from multiple adjacent
+		 * slashes in the path) and RFC3986 says that we should
+		 * still do `CWD ' (with a null argument) in such cases.
+		 *
+		 * Many ftp servers don't support `CWD ', so if there's an
+		 * error performing that command, bail out with a descriptive
+		 * message.
+		 *
+		 * Examples:
+		 *
+		 * host:			dir="", urltype=CLASSIC_URL_T
+		 *		logged in (to default directory)
+		 * host:file			dir=NULL, urltype=CLASSIC_URL_T
+		 *		"RETR file"
+		 * host:dir/			dir="dir", urltype=CLASSIC_URL_T
+		 *		"CWD dir", logged in
+		 * ftp://host/			dir="", urltype=FTP_URL_T
+		 *		logged in (to default directory)
+		 * ftp://host/dir/		dir="dir", urltype=FTP_URL_T
+		 *		"CWD dir", logged in
+		 * ftp://host/file		dir=NULL, urltype=FTP_URL_T
+		 *		"RETR file"
+		 * ftp://host//file		dir="", urltype=FTP_URL_T
+		 *		"CWD ", "RETR file"
+		 * host:/file			dir="/", urltype=CLASSIC_URL_T
+		 *		"CWD /", "RETR file"
+		 * ftp://host///file		dir="/", urltype=FTP_URL_T
+		 *		"CWD ", "CWD ", "RETR file"
+		 * ftp://host/%2F/file		dir="%2F", urltype=FTP_URL_T
+		 *		"CWD /", "RETR file"
+		 * ftp://host/foo/file		dir="foo", urltype=FTP_URL_T
+		 *		"CWD foo", "RETR file"
+		 * ftp://host/foo/bar/file	dir="foo/bar"
+		 *		"CWD foo", "CWD bar", "RETR file"
+		 * ftp://host//foo/bar/file	dir="/foo/bar"
+		 *		"CWD ", "CWD foo", "CWD bar", "RETR file"
+		 * ftp://host/foo//bar/file	dir="foo//bar"
+		 *		"CWD foo", "CWD ", "CWD bar", "RETR file"
+		 * ftp://host/%2F/foo/bar/file	dir="%2F/foo/bar"
+		 *		"CWD /", "CWD foo", "CWD bar", "RETR file"
+		 * ftp://host/%2Ffoo/bar/file	dir="%2Ffoo/bar"
+		 *		"CWD /foo", "CWD bar", "RETR file"
+		 * ftp://host/%2Ffoo%2Fbar/file	dir="%2Ffoo%2Fbar"
+		 *		"CWD /foo/bar", "RETR file"
+		 * ftp://host/%2Ffoo%2Fbar%2Ffile	dir=NULL
+		 *		"RETR /foo/bar/file"
+		 *
+		 * Note that we don't need `dir' after this point.
+		 */
+		do {
+			if (urltype == FTP_URL_T) {
+				nextpart = strchr(dir, '/');
+				if (nextpart) {
+					*nextpart = '\0';
+					nextpart++;
+				}
+				url_decode(dir);
+			} else
+				nextpart = NULL;
+			DPRINTF("fetch_ftp: dir `%s', nextpart `%s'\n",
+			    STRorNULL(dir), STRorNULL(nextpart));
+			if (urltype == FTP_URL_T || *dir != '\0') {
+				(void)strlcpy(cmdbuf, "cd", sizeof(cmdbuf));
+				xargv[0] = cmdbuf;
+				xargv[1] = dir;
+				xargv[2] = NULL;
+				dirchange = 0;
+				cd(2, xargv);
+				if (! dirchange) {
+					if (*dir == '\0' && code == 500)
+						fprintf(stderr,
+"\n"
+"ftp: The `CWD ' command (without a directory), which is required by\n"
+"     RFC3986 to support the empty directory in the URL pathname (`//'),\n"
+"     conflicts with the server's conformance to RFC0959.\n"
+"     Try the same URL without the `//' in the URL pathname.\n"
+"\n");
+					goto cleanup_fetch_ftp;
+				}
+			}
+			dir = nextpart;
+		} while (dir != NULL);
+	}
+
+	if (EMPTYSTRING(file)) {
+		rval = -1;
+		goto cleanup_fetch_ftp;
+	}
+
+	if (dirhasglob) {
+		(void)strlcpy(rempath, dir,	sizeof(rempath));
+		(void)strlcat(rempath, "/",	sizeof(rempath));
+		(void)strlcat(rempath, file,	sizeof(rempath));
+		file = rempath;
+	}
+
+			/* Fetch the file(s). */
+	xargc = 2;
+	(void)strlcpy(cmdbuf, "get", sizeof(cmdbuf));
+	xargv[0] = cmdbuf;
+	xargv[1] = file;
+	xargv[2] = NULL;
+	if (dirhasglob || filehasglob) {
+		int ointeractive;
+
+		ointeractive = interactive;
+		interactive = 0;
+		if (restartautofetch)
+			(void)strlcpy(cmdbuf, "mreget", sizeof(cmdbuf));
+		else
+			(void)strlcpy(cmdbuf, "mget", sizeof(cmdbuf));
+		xargv[0] = cmdbuf;
+		mget(xargc, xargv);
+		interactive = ointeractive;
+	} else {
+		if (outfile == NULL) {
+			cp = strrchr(file, '/');	/* find savefile */
+			if (cp != NULL)
+				outfile = cp + 1;
+			else
+				outfile = file;
+		}
+		xargv[2] = (char *)outfile;
+		xargv[3] = NULL;
+		xargc++;
+		if (restartautofetch)
+			reget(xargc, xargv);
+		else
+			get(xargc, xargv);
+	}
+
+	if ((code / 100) == COMPLETE)
+		rval = 0;
+
+ cleanup_fetch_ftp:
+	FREEPTR(port);
+	FREEPTR(host);
+	FREEPTR(path);
+	FREEPTR(uuser);
+	if (pass)
+		memset(pass, 0, strlen(pass));
+	FREEPTR(pass);
+	return (rval);
+}
+
+/*
+ * Retrieve the given file to outfile.
+ * Supports arguments of the form:
+ *	"host:path", "ftp://host/path"	if $ftpproxy, call fetch_url() else
+ *					call fetch_ftp()
+ *	"http://host/path"		call fetch_url() to use HTTP
+ *	"file:///path"			call fetch_url() to copy
+ *	"about:..."			print a message
+ *
+ * Returns 1 on failure, 0 on completed xfer, -1 if ftp connection
+ * is still open (e.g, ftp xfer with trailing /)
+ */
+static int
+go_fetch(const char *url)
+{
+	char *proxyenv;
+
+#ifndef NO_ABOUT
+	/*
+	 * Check for about:*
+	 */
+	if (STRNEQUAL(url, ABOUT_URL)) {
+		url += sizeof(ABOUT_URL) -1;
+		if (strcasecmp(url, "ftp") == 0 ||
+		    strcasecmp(url, "tnftp") == 0) {
+			fputs(
+"This version of ftp has been enhanced by Luke Mewburn <lukem at NetBSD.org>\n"
+"for the NetBSD project.  Execute `man ftp' for more details.\n", ttyout);
+		} else if (strcasecmp(url, "lukem") == 0) {
+			fputs(
+"Luke Mewburn is the author of most of the enhancements in this ftp client.\n"
+"Please email feedback to <lukem at NetBSD.org>.\n", ttyout);
+		} else if (strcasecmp(url, "netbsd") == 0) {
+			fputs(
+"NetBSD is a freely available and redistributable UNIX-like operating system.\n"
+"For more information, see http://www.NetBSD.org/\n", ttyout);
+		} else if (strcasecmp(url, "version") == 0) {
+			fprintf(ttyout, "Version: %s %s%s\n",
+			    FTP_PRODUCT, FTP_VERSION,
+#ifdef INET6
+			    ""
+#else
+			    " (-IPv6)"
+#endif
+			);
+		} else {
+			fprintf(ttyout, "`%s' is an interesting topic.\n", url);
+		}
+		fputs("\n", ttyout);
+		return (0);
+	}
+#endif
+
+	/*
+	 * Check for file:// and http:// URLs.
+	 */
+	if (STRNEQUAL(url, HTTP_URL) || STRNEQUAL(url, FILE_URL))
+		return (fetch_url(url, NULL, NULL, NULL));
+
+	/*
+	 * Try FTP URL-style and host:file arguments next.
+	 * If ftpproxy is set with an FTP URL, use fetch_url()
+	 * Othewise, use fetch_ftp().
+	 */
+	proxyenv = getoptionvalue("ftp_proxy");
+	if (!EMPTYSTRING(proxyenv) && STRNEQUAL(url, FTP_URL))
+		return (fetch_url(url, NULL, NULL, NULL));
+
+	return (fetch_ftp(url));
+}
+
+/*
+ * Retrieve multiple files from the command line,
+ * calling go_fetch() for each file.
+ *
+ * If an ftp path has a trailing "/", the path will be cd-ed into and
+ * the connection remains open, and the function will return -1
+ * (to indicate the connection is alive).
+ * If an error occurs the return value will be the offset+1 in
+ * argv[] of the file that caused a problem (i.e, argv[x]
+ * returns x+1)
+ * Otherwise, 0 is returned if all files retrieved successfully.
+ */
+int
+auto_fetch(int argc, char *argv[])
+{
+	volatile int	argpos, rval;
+
+	argpos = rval = 0;
+
+	if (sigsetjmp(toplevel, 1)) {
+		if (connected)
+			disconnect(0, NULL);
+		if (rval > 0)
+			rval = argpos + 1;
+		return (rval);
+	}
+	(void)xsignal(SIGINT, intr);
+	(void)xsignal(SIGPIPE, lostpeer);
+
+	/*
+	 * Loop through as long as there's files to fetch.
+	 */
+	for (; (rval == 0) && (argpos < argc); argpos++) {
+		if (strchr(argv[argpos], ':') == NULL)
+			break;
+		redirect_loop = 0;
+		if (!anonftp)
+			anonftp = 2;	/* Handle "automatic" transfers. */
+		rval = go_fetch(argv[argpos]);
+		if (outfile != NULL && strcmp(outfile, "-") != 0
+		    && outfile[0] != '|')
+			outfile = NULL;
+		if (rval > 0)
+			rval = argpos + 1;
+	}
+
+	if (connected && rval != -1)
+		disconnect(0, NULL);
+	return (rval);
+}
+
+
+/*
+ * Upload multiple files from the command line.
+ *
+ * If an error occurs the return value will be the offset+1 in
+ * argv[] of the file that caused a problem (i.e, argv[x]
+ * returns x+1)
+ * Otherwise, 0 is returned if all files uploaded successfully.
+ */
+int
+auto_put(int argc, char **argv, const char *uploadserver)
+{
+	char	*uargv[4], *path, *pathsep;
+	int	 uargc, rval, argpos;
+	size_t	 len;
+	char	 cmdbuf[MAX_C_NAME];
+
+	(void)strlcpy(cmdbuf, "mput", sizeof(cmdbuf));
+	uargv[0] = cmdbuf;
+	uargv[1] = argv[0];
+	uargc = 2;
+	uargv[2] = uargv[3] = NULL;
+	pathsep = NULL;
+	rval = 1;
+
+	DPRINTF("auto_put: target `%s'\n", uploadserver);
+
+	path = ftp_strdup(uploadserver);
+	len = strlen(path);
+	if (path[len - 1] != '/' && path[len - 1] != ':') {
+			/*
+			 * make sure we always pass a directory to auto_fetch
+			 */
+		if (argc > 1) {		/* more than one file to upload */
+			len = strlen(uploadserver) + 2;	/* path + "/" + "\0" */
+			free(path);
+			path = (char *)ftp_malloc(len);
+			(void)strlcpy(path, uploadserver, len);
+			(void)strlcat(path, "/", len);
+		} else {		/* single file to upload */
+			(void)strlcpy(cmdbuf, "put", sizeof(cmdbuf));
+			uargv[0] = cmdbuf;
+			pathsep = strrchr(path, '/');
+			if (pathsep == NULL) {
+				pathsep = strrchr(path, ':');
+				if (pathsep == NULL) {
+					warnx("Invalid URL `%s'", path);
+					goto cleanup_auto_put;
+				}
+				pathsep++;
+				uargv[2] = ftp_strdup(pathsep);
+				pathsep[0] = '/';
+			} else
+				uargv[2] = ftp_strdup(pathsep + 1);
+			pathsep[1] = '\0';
+			uargc++;
+		}
+	}
+	DPRINTF("auto_put: URL `%s' argv[2] `%s'\n",
+	    path, STRorNULL(uargv[2]));
+
+			/* connect and cwd */
+	rval = auto_fetch(1, &path);
+	if(rval >= 0)
+		goto cleanup_auto_put;
+
+	rval = 0;
+
+			/* target filename provided; upload 1 file */
+			/* XXX : is this the best way? */
+	if (uargc == 3) {
+		uargv[1] = argv[0];
+		put(uargc, uargv);
+		if ((code / 100) != COMPLETE)
+			rval = 1;
+	} else {	/* otherwise a target dir: upload all files to it */
+		for(argpos = 0; argv[argpos] != NULL; argpos++) {
+			uargv[1] = argv[argpos];
+			mput(uargc, uargv);
+			if ((code / 100) != COMPLETE) {
+				rval = argpos + 1;
+				break;
+			}
+		}
+	}
+
+ cleanup_auto_put:
+	free(path);
+	FREEPTR(uargv[2]);
+	return (rval);
+}

Added: vendor/NetBSD/tnftp/20100108/src/ftp.1
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/ftp.1	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/ftp.1	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,2406 @@
+.\" 	$NetBSD: ftp.1,v 1.13 2009/11/15 10:12:37 lukem Exp $
+.\" 	from	NetBSD: ftp.1,v 1.130 2009/07/11 18:35:48 joerg Exp
+.\"
+.\" Copyright (c) 1996-2008 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Luke Mewburn.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"
+.\" Copyright (c) 1985, 1989, 1990, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)ftp.1	8.3 (Berkeley) 10/9/94
+.\"
+.Dd May 10, 2008
+.Dt FTP 1
+.Os
+.Sh NAME
+.Nm ftp
+.Nd Internet file transfer program
+.Sh SYNOPSIS
+.Nm
+.Op Fl 46AadefginpRtVv
+.Bk -words
+.Op Fl N Ar netrc
+.Ek
+.Bk -words
+.Op Fl o Ar output
+.Ek
+.Bk -words
+.Op Fl P Ar port
+.Ek
+.Bk -words
+.Op Fl q Ar quittime
+.Ek
+.Bk -words
+.Op Fl r Ar retry
+.Ek
+.Op Fl s Ar srcaddr
+.Bk -words
+.\" [-T dir,max[,inc]]
+.Oo
+.Fl T Xo
+.Sm off
+.Ar dir ,
+.Ar max
+.Op , Ar inc
+.Sm on
+.Xc
+.Oc
+.Ek
+.Bk -words
+.\" [[user@]host [port]]
+.Oo
+.Oo Ar user Ns Li \&@ Oc Ns Ar host
+.Op Ar port
+.Oc
+.Ek
+.Bk -words
+.\" [[user@]host:[path][/]]
+.Sm off
+.Oo
+.Op Ar user Li \&@
+.Ar host Li \&:
+.Op Ar path
+.Op Li /
+.Oc
+.Sm on
+.Ek
+.Bk -words
+.\" [file:///path]
+.Sm off
+.Oo
+.Li file:/// Ar path
+.Oc
+.Sm on
+.Ek
+.Bk -words
+.\" [ftp://[user[:password]@]host[:port]/path[/]]
+.Sm off
+.Oo
+.Li ftp://
+.Oo Ar user
+.Op Li \&: Ar password
+.Li \&@ Oc
+.Ar host Oo Li \&: Ar port Oc
+.Li / Ar path
+.Op Li /
+.Op Li ;type= Ar X
+.Oc
+.Sm on
+.Ek
+.Bk -words
+.\" [http://[user[:password]@]host[:port]/path]
+.Sm off
+.Oo
+.Li http://
+.Oo Ar user
+.Op Li \&: Ar password
+.Li \&@ Oc
+.Ar host Oo Li \&: Ar port Oc
+.Li / Ar path
+.Oc
+.Sm on
+.Ek
+.Op Ar \&.\&.\&.
+.Nm
+.Bk -words
+.Fl u Ar URL Ar file
+.Ek
+.Op Ar \&.\&.\&.
+.Sh DESCRIPTION
+.Nm
+is the user interface to the Internet standard File Transfer Protocol.
+The program allows a user to transfer files to and from a
+remote network site.
+.Pp
+The last five arguments will fetch a file using the
+.Tn FTP
+or
+.Tn HTTP
+protocols, or by direct copying, into the current directory.
+This is ideal for scripts.
+Refer to
+.Sx AUTO-FETCHING FILES
+below for more information.
+.Pp
+Options may be specified at the command line, or to the
+command interpreter.
+.Bl -tag -width Fl
+.It Fl 4
+Forces
+.Nm
+to only use IPv4 addresses.
+.It Fl 6
+Forces
+.Nm
+to only use IPv6 addresses.
+.It Fl A
+Force active mode ftp.
+By default,
+.Nm
+will try to use passive mode ftp and fall back to active mode
+if passive is not supported by the server.
+This option causes
+.Nm
+to always use an active connection.
+It is only useful for connecting to very old servers that do not
+implement passive mode properly.
+.It Fl a
+Causes
+.Nm
+to bypass normal login procedure, and use an anonymous login instead.
+.It Fl d
+Enables debugging.
+.It Fl e
+Disables command line editing.
+This is useful for Emacs ange-ftp mode.
+.It Fl f
+Forces a cache reload for transfers that go through the
+.Tn FTP
+or
+.Tn HTTP
+proxies.
+.It Fl g
+Disables file name globbing.
+.It Fl i
+Turns off interactive prompting during
+multiple file transfers.
+.It Fl N Ar netrc
+Use
+.Ar netrc
+instead of
+.Pa ~/.netrc .
+Refer to
+.Sx THE .netrc FILE
+for more information.
+.It Fl n
+Restrains
+.Nm
+from attempting
+.Dq auto-login
+upon initial connection for non auto-fetch transfers.
+If auto-login is enabled,
+.Nm
+will check the
+.Pa .netrc
+(see below) file in the user's home directory for an entry describing
+an account on the remote machine.
+If no entry exists,
+.Nm
+will prompt for the remote machine login name (default is the user
+identity on the local machine), and, if necessary, prompt for a password
+and an account with which to login.
+To override the auto-login for auto-fetch transfers, specify the
+username (and optionally, password) as appropriate.
+.It Fl o Ar output
+When auto-fetching files, save the contents in
+.Ar output .
+.Ar output
+is parsed according to the
+.Sx FILE NAMING CONVENTIONS
+below.
+If
+.Ar output
+is not
+.Sq -
+or doesn't start with
+.Sq \&| ,
+then only the first file specified will be retrieved into
+.Ar output ;
+all other files will be retrieved into the basename of their
+remote name.
+.It Fl P Ar port
+Sets the port number to
+.Ar port .
+.It Fl p
+Enable passive mode operation for use behind connection filtering firewalls.
+This option has been deprecated as
+.Nm
+now tries to use passive mode by default, falling back to active mode
+if the server does not support passive connections.
+.It Fl q Ar quittime
+Quit if the connection has stalled for
+.Ar quittime
+seconds.
+.It Fl R
+Restart all non-proxied auto-fetches.
+.It Fl r Ar wait
+Retry the connection attempt if it failed, pausing for
+.Ar wait
+seconds.
+.It Fl s Ar srcaddr
+Uses
+.Ar srcaddr
+as the local IP address for all connections.
+.It Fl t
+Enables packet tracing.
+.It Fl T Ar direction Ns , Ns Ar maximum Ns Oo , Ns Ar increment Oc
+Set the maximum transfer rate for
+.Ar direction
+to
+.Ar maximum
+bytes/second,
+and if specified, the increment to
+.Ar increment
+bytes/second.
+Refer to
+.Ic rate
+for more information.
+.It Fl u Ar URL file Op \&.\&.\&.
+Upload files on the command line to
+.Ar URL
+where
+.Ar URL
+is one of the ftp URL types as supported by auto-fetch
+(with an optional target filename for single file uploads), and
+.Ar file
+is one or more local files to be uploaded.
+.It Fl V
+Disable
+.Ic verbose
+and
+.Ic progress ,
+overriding the default of enabled when output is to a terminal.
+.It Fl v
+Enable
+.Ic verbose
+and
+.Ic progress .
+This is the default if output is to a terminal (and in the case of
+.Ic progress ,
+.Nm
+is the foreground process).
+Forces
+.Nm
+to show all responses from the remote server, as well
+as report on data transfer statistics.
+.El
+.Pp
+The client host with which
+.Nm
+is to communicate may be specified on the command line.
+If this is done,
+.Nm
+will immediately attempt to establish a connection to an
+.Tn FTP
+server on that host; otherwise,
+.Nm
+will enter its command interpreter and await instructions
+from the user.
+When
+.Nm
+is awaiting commands from the user the prompt
+.Ql ftp\*[Gt]
+is provided to the user.
+The following commands are recognized
+by
+.Nm ftp :
+.Bl -tag -width Ic
+.It Ic \&! Op Ar command Op Ar args
+Invoke an interactive shell on the local machine.
+If there are arguments, the first is taken to be a command to execute
+directly, with the rest of the arguments as its arguments.
+.It Ic \&$ Ar macro-name Op Ar args
+Execute the macro
+.Ar macro-name
+that was defined with the
+.Ic macdef
+command.
+Arguments are passed to the macro unglobbed.
+.It Ic account Op Ar passwd
+Supply a supplemental password required by a remote system for access
+to resources once a login has been successfully completed.
+If no argument is included, the user will be prompted for an account
+password in a non-echoing input mode.
+.It Ic append Ar local-file Op Ar remote-file
+Append a local file to a file on the remote machine.
+If
+.Ar remote-file
+is left unspecified, the local file name is used in naming the
+remote file after being altered by any
+.Ic ntrans
+or
+.Ic nmap
+setting.
+File transfer uses the current settings for
+.Ic type  ,
+.Ic format ,
+.Ic mode  ,
+and
+.Ic structure .
+.It Ic ascii
+Set the file transfer
+.Ic type
+to network
+.Tn ASCII .
+This is the default type.
+.It Ic bell
+Arrange that a bell be sounded after each file transfer
+command is completed.
+.It Ic binary
+Set the file transfer
+.Ic type
+to support binary image transfer.
+.It Ic bye
+Terminate the
+.Tn FTP
+session with the remote server
+and exit
+.Nm ftp .
+An end of file will also terminate the session and exit.
+.It Ic case
+Toggle remote computer file name case mapping during
+.Ic get ,
+.Ic mget
+and
+.Ic mput
+commands.
+When
+.Ic case
+is on (default is off), remote computer file names with all letters in
+upper case are written in the local directory with the letters mapped
+to lower case.
+.It Ic \&cd Ar remote-directory
+Change the working directory on the remote machine
+to
+.Ar remote-directory .
+.It Ic cdup
+Change the remote machine working directory to the parent of the
+current remote machine working directory.
+.It Ic chmod Ar mode remote-file
+Change the permission modes of the file
+.Ar remote-file
+on the remote
+system to
+.Ar mode .
+.It Ic close
+Terminate the
+.Tn FTP
+session with the remote server, and
+return to the command interpreter.
+Any defined macros are erased.
+.It Ic \&cr
+Toggle carriage return stripping during
+ascii type file retrieval.
+Records are denoted by a carriage return/linefeed sequence
+during ascii type file transfer.
+When
+.Ic \&cr
+is on (the default), carriage returns are stripped from this
+sequence to conform with the
+.Ux
+single linefeed record
+delimiter.
+Records on
+.Pf non\- Ns Ux
+remote systems may contain single linefeeds;
+when an ascii type transfer is made, these linefeeds may be
+distinguished from a record delimiter only when
+.Ic \&cr
+is off.
+.It Ic delete Ar remote-file
+Delete the file
+.Ar remote-file
+on the remote machine.
+.It Ic dir Op Ar remote-path Op Ar local-file
+Print a listing of the contents of a
+directory on the remote machine.
+The listing includes any system-dependent information that the server
+chooses to include; for example, most
+.Ux
+systems will produce
+output from the command
+.Ql ls \-l .
+If
+.Ar remote-path
+is left unspecified, the current working directory is used.
+If interactive prompting is on,
+.Nm
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.Ic dir
+output.
+If no local file is specified, or if
+.Ar local-file
+is
+.Sq Fl ,
+the output is sent to the terminal.
+.It Ic disconnect
+A synonym for
+.Ic close .
+.It Ic edit
+Toggle command line editing, and context sensitive command and file
+completion.
+This is automatically enabled if input is from a terminal, and
+disabled otherwise.
+.It Ic epsv epsv4 epsv6
+Toggle the use of the extended
+.Dv EPSV
+and
+.Dv EPRT
+commands on all IP, IPv4, and IPv6 connections respectively.
+First try
+.Dv EPSV /
+.Dv EPRT ,
+and then
+.Dv PASV /
+.Dv PORT .
+This is enabled by default.
+If an extended command fails then this option will be temporarily
+disabled for the duration of the current connection, or until
+.Ic epsv ,
+.Ic epsv4 ,
+or
+.Ic epsv6
+is executed again.
+.It Ic exit
+A synonym for
+.Ic bye .
+.It Ic features
+Display what features the remote server supports (using the
+.Dv FEAT
+command).
+.It Ic fget Ar localfile
+Retrieve the files listed in
+.Ar localfile ,
+which has one line per filename.
+.It Ic form Ar format
+Set the file transfer
+.Ic form
+to
+.Ar format .
+The default (and only supported)
+format is
+.Dq non-print .
+.It Ic ftp Ar host Op Ar port
+A synonym for
+.Ic open .
+.It Ic ftp_debug Op Ar ftp_debug-value
+Toggle debugging mode.
+If an optional
+.Ar ftp_debug-value
+is specified it is used to set the debugging level.
+When debugging is on,
+.Nm
+prints each command sent to the remote machine, preceded
+by the string
+.Ql \-\-\*[Gt] .
+.It Ic gate Op Ar host Op Ar port
+Toggle gate-ftp mode, which used to connect through the
+TIS FWTK and Gauntlet ftp proxies.
+This will not be permitted if the gate-ftp server hasn't been set
+(either explicitly by the user, or from the
+.Ev FTPSERVER
+environment variable).
+If
+.Ar host
+is given,
+then gate-ftp mode will be enabled, and the gate-ftp server will be set to
+.Ar host .
+If
+.Ar port
+is also given, that will be used as the port to connect to on the
+gate-ftp server.
+.It Ic get Ar remote-file Op Ar local-file
+Retrieve the
+.Ar remote-file
+and store it on the local machine.
+If the local
+file name is not specified, it is given the same
+name it has on the remote machine, subject to
+alteration by the current
+.Ic case  ,
+.Ic ntrans ,
+and
+.Ic nmap
+settings.
+The current settings for
+.Ic type  ,
+.Ic form ,
+.Ic mode  ,
+and
+.Ic structure
+are used while transferring the file.
+.It Ic glob
+Toggle filename expansion for
+.Ic mdelete  ,
+.Ic mget ,
+.Ic mput ,
+and
+.Ic mreget .
+If globbing is turned off with
+.Ic glob  ,
+the file name arguments
+are taken literally and not expanded.
+Globbing for
+.Ic mput
+is done as in
+.Xr csh 1 .
+For
+.Ic mdelete ,
+.Ic mget ,
+and
+.Ic mreget ,
+each remote file name is expanded
+separately on the remote machine and the lists are not merged.
+Expansion of a directory name is likely to be
+different from expansion of the name of an ordinary file:
+the exact result depends on the foreign operating system and ftp server,
+and can be previewed by doing
+.Ql mls remote-files \-
+Note:
+.Ic mget ,
+.Ic mput
+and
+.Ic mreget
+are not meant to transfer
+entire directory subtrees of files.
+That can be done by
+transferring a
+.Xr tar 1
+archive of the subtree (in binary mode).
+.It Ic hash Op Ar size
+Toggle hash-sign
+.Pq Sq #
+printing for each data block transferred.
+The size of a data block defaults to 1024 bytes.
+This can be changed by specifying
+.Ar size
+in bytes.
+Enabling
+.Ic hash
+disables
+.Ic progress .
+.It Ic help Op Ar command
+Print an informative message about the meaning of
+.Ar command .
+If no argument is given,
+.Nm
+prints a list of the known commands.
+.It Ic idle Op Ar seconds
+Set the inactivity timer on the remote server to
+.Ar seconds
+seconds.
+If
+.Ar seconds
+is omitted, the current inactivity timer is printed.
+.It Ic image
+A synonym for
+.Ic binary .
+.It Ic lcd Op Ar directory
+Change the working directory on the local machine.
+If
+no
+.Ar directory
+is specified, the user's home directory is used.
+.It Ic less Ar file
+A synonym for
+.Ic page .
+.It Ic lpage Ar local-file
+Display
+.Ar local-file
+with the program specified by the
+.Ic "set pager"
+option.
+.It Ic lpwd
+Print the working directory on the local machine.
+.It Ic \&ls Op Ar remote-path Op Ar local-file
+A synonym for
+.Ic dir .
+.It Ic macdef Ar macro-name
+Define a macro.
+Subsequent lines are stored as the macro
+.Ar macro-name  ;
+a null line (consecutive newline characters in a file or carriage
+returns from the terminal) terminates macro input mode.
+There is a limit of 16 macros and 4096 total characters in all
+defined macros.
+Macro names can be a maximum of 8 characters.
+Macros are only applicable to the current session they are
+defined within (or if defined outside a session, to the session
+invoked with the next
+.Ic open
+command), and remain defined until a
+.Ic close
+command is executed.
+To invoke a macro, use the
+.Ic $
+command (see above).
+.Pp
+The macro processor interprets
+.Sq $
+and
+.Sq \e
+as special characters.
+A
+.Sq $
+followed by a number (or numbers) is replaced by the
+corresponding argument on the macro invocation command line.
+A
+.Sq $
+followed by an
+.Sq i
+signals the macro processor that the executing macro is to be
+looped.
+On the first pass
+.Dq $i
+is replaced by the first argument on the macro invocation command
+line, on the second pass it is replaced by the second argument,
+and so on.
+A
+.Sq \e
+followed by any character is replaced by that character.
+Use the
+.Sq \e
+to prevent special treatment of the
+.Sq $ .
+.It Ic mdelete Op Ar remote-files
+Delete the
+.Ar remote-files
+on the remote machine.
+.It Ic mdir Ar remote-files local-file
+Like
+.Ic dir  ,
+except multiple remote files may be specified.
+If interactive prompting is on,
+.Nm
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.Ic mdir
+output.
+.It Ic mget Ar remote-files
+Expand the
+.Ar remote-files
+on the remote machine
+and do a
+.Ic get
+for each file name thus produced.
+See
+.Ic glob
+for details on the filename expansion.
+Resulting file names will then be processed according to
+.Ic case  ,
+.Ic ntrans ,
+and
+.Ic nmap
+settings.
+Files are transferred into the local working directory,
+which can be changed with
+.Ql lcd directory ;
+new local directories can be created with
+.Ql "\&! mkdir directory" .
+.It Ic mkdir Ar directory-name
+Make a directory on the remote machine.
+.It Ic mls Ar remote-files local-file
+Like
+.Ic ls  ,
+except multiple remote files may be specified,
+and the
+.Ar local-file
+must be specified.
+If interactive prompting is on,
+.Nm
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.Ic mls
+output.
+.It Ic mlsd Op Ar remote-path
+Display the contents of
+.Ar remote-path
+(which should default to the current directory if not given)
+in a machine-parsable form, using
+.Dv MLSD .
+The format of display can be changed with
+.Sq "remopts mlst ..." .
+.It Ic mlst Op Ar remote-path
+Display the details about
+.Ar remote-path
+(which should default to the current directory if not given)
+in a machine-parsable form, using
+.Dv MLST .
+The format of display can be changed with
+.Sq "remopts mlst ..." .
+.It Ic mode Ar mode-name
+Set the file transfer
+.Ic mode
+to
+.Ar mode-name .
+The default (and only supported)
+mode is
+.Dq stream .
+.It Ic modtime Ar remote-file
+Show the last modification time of the file on the remote machine, in
+.Li RFC2822
+format.
+.It Ic more Ar file
+A synonym for
+.Ic page .
+.It Ic mput Ar local-files
+Expand wild cards in the list of local files given as arguments
+and do a
+.Ic put
+for each file in the resulting list.
+See
+.Ic glob
+for details of filename expansion.
+Resulting file names will then be processed according to
+.Ic ntrans
+and
+.Ic nmap
+settings.
+.It Ic mreget Ar remote-files
+As per
+.Ic mget ,
+but performs a
+.Ic reget
+instead of
+.Ic get .
+.It Ic msend Ar local-files
+A synonym for
+.Ic mput .
+.It Ic newer Ar remote-file Op Ar local-file
+Get the file only if the modification time of the remote file is more
+recent that the file on the current system.
+If the file does not
+exist on the current system, the remote file is considered
+.Ic newer .
+Otherwise, this command is identical to
+.Ar get .
+.It Ic nlist Op Ar remote-path Op Ar local-file
+A synonym for
+.Ic ls .
+.It Ic nmap Op Ar inpattern outpattern
+Set or unset the filename mapping mechanism.
+If no arguments are specified, the filename mapping mechanism is unset.
+If arguments are specified, remote filenames are mapped during
+.Ic mput
+commands and
+.Ic put
+commands issued without a specified remote target filename.
+If arguments are specified, local filenames are mapped during
+.Ic mget
+commands and
+.Ic get
+commands issued without a specified local target filename.
+This command is useful when connecting to a
+.No non\- Ns Ux
+remote computer
+with different file naming conventions or practices.
+The mapping follows the pattern set by
+.Ar inpattern
+and
+.Ar outpattern .
+.Op Ar Inpattern
+is a template for incoming filenames (which may have already been
+processed according to the
+.Ic ntrans
+and
+.Ic case
+settings).
+Variable templating is accomplished by including the
+sequences
+.Dq $1 ,
+.Dq $2 ,
+\&...
+.Dq $9
+in
+.Ar inpattern .
+Use
+.Sq \e
+to prevent this special treatment of the
+.Sq $
+character.
+All other characters are treated literally, and are used to determine the
+.Ic nmap
+.Op Ar inpattern
+variable values.
+For example, given
+.Ar inpattern
+$1.$2 and the remote file name "mydata.data", $1 would have the value
+"mydata", and $2 would have the value "data".
+The
+.Ar outpattern
+determines the resulting mapped filename.
+The sequences
+.Dq $1 ,
+.Dq $2 ,
+\&...
+.Dq $9
+are replaced by any value resulting from the
+.Ar inpattern
+template.
+The sequence
+.Dq $0
+is replaced by the original filename.
+Additionally, the sequence
+.Dq Op Ar seq1 , Ar seq2
+is replaced by
+.Op Ar seq1
+if
+.Ar seq1
+is not a null string; otherwise it is replaced by
+.Ar seq2 .
+For example, the command
+.Pp
+.Bd -literal -offset indent -compact
+nmap $1.$2.$3 [$1,$2].[$2,file]
+.Ed
+.Pp
+would yield
+the output filename "myfile.data" for input filenames "myfile.data" and
+"myfile.data.old", "myfile.file" for the input filename "myfile", and
+"myfile.myfile" for the input filename ".myfile".
+Spaces may be included in
+.Ar outpattern  ,
+as in the example:
+.Dl nmap $1 sed "s/  *$//" \*[Gt] $1
+Use the
+.Sq \e
+character to prevent special treatment
+of the
+.Sq $ ,
+.Sq \&[ ,
+.Sq \&] ,
+and
+.Sq \&,
+characters.
+.It Ic ntrans Op Ar inchars Op Ar outchars
+Set or unset the filename character translation mechanism.
+If no arguments are specified, the filename character
+translation mechanism is unset.
+If arguments are specified, characters in
+remote filenames are translated during
+.Ic mput
+commands and
+.Ic put
+commands issued without a specified remote target filename.
+If arguments are specified, characters in
+local filenames are translated during
+.Ic mget
+commands and
+.Ic get
+commands issued without a specified local target filename.
+This command is useful when connecting to a
+.No non\- Ns Ux
+remote computer
+with different file naming conventions or practices.
+Characters in a filename matching a character in
+.Ar inchars
+are replaced with the corresponding character in
+.Ar outchars .
+If the character's position in
+.Ar inchars
+is longer than the length of
+.Ar outchars  ,
+the character is deleted from the file name.
+.It Ic open Ar host Op Ar port
+Establish a connection to the specified
+.Ar host
+.Tn FTP
+server.
+An optional port number may be supplied,
+in which case,
+.Nm
+will attempt to contact an
+.Tn FTP
+server at that port.
+If the
+.Ic "set auto-login"
+option is on (default),
+.Nm
+will also attempt to automatically log the user in to
+the
+.Tn FTP
+server (see below).
+.It Ic page Ar file
+Retrieve
+.Ic file
+and display with the program specified by the
+.Ic "set pager"
+option.
+.It Ic passive Op Cm auto
+Toggle passive mode (if no arguments are given).
+If
+.Cm auto
+is given, act as if
+.Ev FTPMODE
+is set to
+.Sq auto .
+If passive mode is turned on (default),
+.Nm
+will send a
+.Dv PASV
+command for all data connections instead of a
+.Dv PORT
+command.
+The
+.Dv PASV
+command requests that the remote server open a port for the data connection
+and return the address of that port.
+The remote server listens on that port and the client connects to it.
+When using the more traditional
+.Dv PORT
+command, the client listens on a port and sends that address to the remote
+server, who connects back to it.
+Passive mode is useful when using
+.Nm
+through a gateway router or host that controls the directionality of
+traffic.
+(Note that though
+.Tn FTP
+servers are required to support the
+.Dv PASV
+command by
+.Li RFC1123 ,
+some do not.)
+.It Ic pdir Op Ar remote-path
+Perform
+.Ic dir
+.Op Ar remote-path ,
+and display the result with the program specified by the
+.Ic "set pager"
+option.
+.It Ic pls Op Ar remote-path
+Perform
+.Ic ls
+.Op Ar remote-path ,
+and display the result with the program specified by the
+.Ic "set pager"
+option.
+.It Ic pmlsd Op Ar remote-path
+Perform
+.Ic mlsd
+.Op Ar remote-path ,
+and display the result with the program specified by the
+.Ic "set pager"
+option.
+.It Ic preserve
+Toggle preservation of modification times on retrieved files.
+.It Ic progress
+Toggle display of transfer progress bar.
+The progress bar will be disabled for a transfer that has
+.Ar local-file
+as
+.Sq Fl
+or a command that starts with
+.Sq \&| .
+Refer to
+.Sx FILE NAMING CONVENTIONS
+for more information.
+Enabling
+.Ic progress
+disables
+.Ic hash .
+.It Ic prompt
+Toggle interactive prompting.
+Interactive prompting
+occurs during multiple file transfers to allow the
+user to selectively retrieve or store files.
+If prompting is turned off (default is on), any
+.Ic mget
+or
+.Ic mput
+will transfer all files, and any
+.Ic mdelete
+will delete all files.
+.Pp
+When prompting is on, the following commands are available at a prompt:
+.Bl -tag -width 2n -offset indent
+.It Cm a
+Answer
+.Sq yes
+to the current file, and automatically answer
+.Sq yes
+to any remaining files for the current command.
+.It Cm n
+Answer
+.Sq no ,
+and do not transfer the file.
+.It Cm p
+Answer
+.Sq yes
+to the current file, and turn off prompt mode
+(as is
+.Dq prompt off
+had been given).
+.It Cm q
+Terminate the current operation.
+.It Cm y
+Answer
+.Sq yes ,
+and transfer the file.
+.It Cm \&?
+Display a help message.
+.El
+.Pp
+Any other response will answer
+.Sq yes
+to the current file.
+.It Ic proxy Ar ftp-command
+Execute an ftp command on a secondary control connection.
+This command allows simultaneous connection to two remote
+.Tn FTP
+servers for transferring files between the two servers.
+The first
+.Ic proxy
+command should be an
+.Ic open  ,
+to establish the secondary control connection.
+Enter the command "proxy ?" to see other
+.Tn FTP
+commands executable on the secondary connection.
+The following commands behave differently when prefaced by
+.Ic proxy  :
+.Ic open
+will not define new macros during the auto-login process,
+.Ic close
+will not erase existing macro definitions,
+.Ic get
+and
+.Ic mget
+transfer files from the host on the primary control connection
+to the host on the secondary control connection, and
+.Ic put  ,
+.Ic mput ,
+and
+.Ic append
+transfer files from the host on the secondary control connection
+to the host on the primary control connection.
+Third party file transfers depend upon support of the
+.Tn FTP
+protocol
+.Dv PASV
+command by the server on the secondary control connection.
+.It Ic put Ar local-file Op Ar remote-file
+Store a local file on the remote machine.
+If
+.Ar remote-file
+is left unspecified, the local file name is used
+after processing according to any
+.Ic ntrans
+or
+.Ic nmap
+settings
+in naming the remote file.
+File transfer uses the
+current settings for
+.Ic type  ,
+.Ic format ,
+.Ic mode  ,
+and
+.Ic structure .
+.It Ic pwd
+Print the name of the current working directory on the remote
+machine.
+.It Ic quit
+A synonym for
+.Ic bye .
+.It Ic quote Ar arg1 arg2 ...
+The arguments specified are sent, verbatim, to the remote
+.Tn FTP
+server.
+.It Ic rate Ar direction Oo Ar maximum Oo Ar increment Oc Oc
+Throttle the maximum transfer rate to
+.Ar maximum
+bytes/second.
+If
+.Ar maximum
+is 0, disable the throttle.
+.Pp
+.Ar direction
+may be one of:
+.Bl -tag -width "all" -offset indent -compact
+.It Cm all
+Both directions.
+.It Cm get
+Incoming transfers.
+.It Cm put
+Outgoing transfers.
+.El
+.Pp
+.Ar maximum
+can be modified on the fly by
+.Ar increment
+bytes (default: 1024) each time a given signal is received:
+.Bl -tag -width "SIGUSR1" -offset indent
+.It Dv SIGUSR1
+Increment
+.Ar maximum
+by
+.Ar increment
+bytes.
+.It Dv SIGUSR2
+Decrement
+.Ar maximum
+by
+.Ar increment
+bytes.
+The result must be a positive number.
+.El
+.Pp
+If
+.Ar maximum
+is not supplied, the current throttle rates are displayed.
+.Pp
+Note:
+.Ic rate
+is not yet implemented for ascii mode transfers.
+.It Ic rcvbuf Ar size
+Set the size of the socket receive buffer to
+.Ar size .
+.It Ic recv Ar remote-file Op Ar local-file
+A synonym for
+.Ic get .
+.It Ic reget Ar remote-file Op Ar local-file
+.Ic reget
+acts like
+.Ic get ,
+except that if
+.Ar local-file
+exists and is
+smaller than
+.Ar remote-file  ,
+.Ar local-file
+is presumed to be
+a partially transferred copy of
+.Ar remote-file
+and the transfer
+is continued from the apparent point of failure.
+This command
+is useful when transferring very large files over networks that
+are prone to dropping connections.
+.It Ic remopts Ar command Op Ar command-options
+Set options on the remote
+.Tn FTP
+server for
+.Ar command
+to
+.Ar command-options
+(whose absence is handled on a command-specific basis).
+Remote
+.Tn FTP
+commands known to support options include:
+.Sq MLST
+(used for
+.Dv MLSD
+and
+.Dv MLST ) .
+.It Ic rename Op Ar from Op Ar to
+Rename the file
+.Ar from
+on the remote machine, to the file
+.Ar to .
+.It Ic reset
+Clear reply queue.
+This command re-synchronizes command/reply sequencing with the remote
+.Tn FTP
+server.
+Resynchronization may be necessary following a violation of the
+.Tn FTP
+protocol by the remote server.
+.It Ic restart Ar marker
+Restart the immediately following
+.Ic get
+or
+.Ic put
+at the
+indicated
+.Ar marker .
+On
+.Ux
+systems, marker is usually a byte
+offset into the file.
+.It Ic rhelp Op Ar command-name
+Request help from the remote
+.Tn FTP
+server.
+If a
+.Ar command-name
+is specified it is supplied to the server as well.
+.It Ic rmdir Ar directory-name
+Delete a directory on the remote machine.
+.It Ic rstatus Op Ar remote-file
+With no arguments, show status of remote machine.
+If
+.Ar remote-file
+is specified, show status of
+.Ar remote-file
+on remote machine.
+.It Ic runique
+Toggle storing of files on the local system with unique filenames.
+If a file already exists with a name equal to the target
+local filename for a
+.Ic get
+or
+.Ic mget
+command, a ".1" is appended to the name.
+If the resulting name matches another existing file,
+a ".2" is appended to the original name.
+If this process continues up to ".99", an error
+message is printed, and the transfer does not take place.
+The generated unique filename will be reported.
+Note that
+.Ic runique
+will not affect local files generated from a shell command
+(see below).
+The default value is off.
+.It Ic send Ar local-file Op Ar remote-file
+A synonym for
+.Ic put .
+.It Ic sendport
+Toggle the use of
+.Dv PORT
+commands.
+By default,
+.Nm
+will attempt to use a
+.Dv PORT
+command when establishing
+a connection for each data transfer.
+The use of
+.Dv PORT
+commands can prevent delays
+when performing multiple file transfers.
+If the
+.Dv PORT
+command fails,
+.Nm
+will use the default data port.
+When the use of
+.Dv PORT
+commands is disabled, no attempt will be made to use
+.Dv PORT
+commands for each data transfer.
+This is useful
+for certain
+.Tn FTP
+implementations which do ignore
+.Dv PORT
+commands but, incorrectly, indicate they've been accepted.
+.It Ic set Op Ar option Ar value
+Set
+.Ar option
+to
+.Ar value .
+If
+.Ar option
+and
+.Ar value
+are not given, display all of the options and their values.
+The currently supported options are:
+.Bl -tag -width "http_proxy" -offset indent
+.It Cm anonpass
+Defaults to
+.Ev $FTPANONPASS
+.It Cm ftp_proxy
+Defaults to
+.Ev $ftp_proxy .
+.It Cm http_proxy
+Defaults to
+.Ev $http_proxy .
+.It Cm no_proxy
+Defaults to
+.Ev $no_proxy .
+.It Cm pager
+Defaults to
+.Ev $PAGER .
+.It Cm prompt
+Defaults to
+.Ev $FTPPROMPT .
+.It Cm rprompt
+Defaults to
+.Ev $FTPRPROMPT .
+.El
+.It Ic site Ar arg1 arg2 ...
+The arguments specified are sent, verbatim, to the remote
+.Tn FTP
+server as a
+.Dv SITE
+command.
+.It Ic size Ar remote-file
+Return size of
+.Ar remote-file
+on remote machine.
+.It Ic sndbuf Ar size
+Set the size of the socket send buffer to
+.Ar size .
+.It Ic status
+Show the current status of
+.Nm ftp .
+.It Ic struct Ar struct-name
+Set the file transfer
+.Ar structure
+to
+.Ar struct-name .
+The default (and only supported)
+structure is
+.Dq file .
+.It Ic sunique
+Toggle storing of files on remote machine under unique file names.
+The remote
+.Tn FTP
+server must support
+.Tn FTP
+protocol
+.Dv STOU
+command for
+successful completion.
+The remote server will report unique name.
+Default value is off.
+.It Ic system
+Show the type of operating system running on the remote machine.
+.It Ic tenex
+Set the file transfer type to that needed to
+talk to
+.Tn TENEX
+machines.
+.It Ic throttle
+A synonym for
+.Ic rate .
+.It Ic trace
+Toggle packet tracing.
+.It Ic type Op Ar type-name
+Set the file transfer
+.Ic type
+to
+.Ar type-name .
+If no type is specified, the current type
+is printed.
+The default type is network
+.Tn ASCII .
+.It Ic umask Op Ar newmask
+Set the default umask on the remote server to
+.Ar newmask .
+If
+.Ar newmask
+is omitted, the current umask is printed.
+.It Ic unset Ar option
+Unset
+.Ar option .
+Refer to
+.Ic set
+for more information.
+.It Ic usage Ar command
+Print the usage message for
+.Ar command .
+.It Ic user Ar user-name Oo Ar password Oo Ar account Oc Oc
+Identify yourself to the remote
+.Tn FTP
+server.
+If the
+.Ar password
+is not specified and the server requires it,
+.Nm
+will prompt the user for it (after disabling local echo).
+If an
+.Ar account
+field is not specified, and the
+.Tn FTP
+server
+requires it, the user will be prompted for it.
+If an
+.Ar account
+field is specified, an account command will
+be relayed to the remote server after the login sequence
+is completed if the remote server did not require it
+for logging in.
+Unless
+.Nm
+is invoked with
+.Dq auto-login
+disabled, this process is done automatically on initial connection to the
+.Tn FTP
+server.
+.It Ic verbose
+Toggle verbose mode.
+In verbose mode, all responses from
+the
+.Tn FTP
+server are displayed to the user.
+In addition,
+if verbose is on, when a file transfer completes, statistics
+regarding the efficiency of the transfer are reported.
+By default,
+verbose is on.
+.It Ic xferbuf Ar size
+Set the size of the socket send and receive buffers to
+.Ar size .
+.It Ic \&? Op Ar command
+A synonym for
+.Ic help .
+.El
+.Pp
+Command arguments which have embedded spaces may be quoted with
+quote
+.Sq \&"
+marks.
+.Pp
+Commands which toggle settings can take an explicit
+.Ic on
+or
+.Ic off
+argument to force the setting appropriately.
+.Pp
+Commands which take a byte count as an argument
+(e.g.,
+.Ic hash ,
+.Ic rate ,
+and
+.Ic xferbuf )
+support an optional suffix on the argument which changes the
+interpretation of the argument.
+Supported suffixes are:
+.Bl -tag -width 3n -offset indent -compact
+.It Li b
+Causes no modification.
+(Optional)
+.It Li k
+Kilo; multiply the argument by 1024
+.It Li m
+Mega; multiply the argument by 1048576
+.It Li g
+Giga; multiply the argument by 1073741824
+.El
+.Pp
+If
+.Nm
+receives a
+.Dv SIGINFO
+(see the
+.Dq status
+argument of
+.Xr stty 1 )
+or
+.Dv SIGQUIT
+signal whilst a transfer is in progress, the current transfer rate
+statistics will be written to the standard error output, in the
+same format as the standard completion message.
+.Sh AUTO-FETCHING FILES
+In addition to standard commands, this version of
+.Nm
+supports an auto-fetch feature.
+To enable auto-fetch, simply pass the list of hostnames/files
+on the command line.
+.Pp
+The following formats are valid syntax for an auto-fetch element:
+.Bl -tag -width "FOO "
+.\" [user@]host:[path][/]
+.It Oo Ar user Ns Li \&@ Oc Ns Ar host Ns Li \&: Ns Oo Ar path Oc \
+Ns Oo Li / Oc
+.Dq Classic
+.Tn FTP
+format.
+.Pp
+If
+.Ar path
+contains a glob character and globbing is enabled,
+(see
+.Ic glob ) ,
+then the equivalent of
+.Ql mget path
+is performed.
+.Pp
+If the directory component of
+.Ar path
+contains no globbing characters,
+it is stored locally with the name basename (see
+.Xr basename 1 )
+of
+.Ic path ,
+in the current directory.
+Otherwise, the full remote name is used as the local name,
+relative to the local root directory.
+.\" ftp://[user[:password]@]host[:port]/path[/][;type=X]
+.It Li ftp:// Ns Oo Ar user Ns Oo Ns Li \&: Ns Ar password Oc Ns Li \&@ Oc \
+Ns Ar host Ns Oo Li \&: Ns Ar port Oc Ns Li / Ns Ar path Ns Oo Li / Oc \
+Ns Oo Li ;type= Ns Ar X Oc
+An
+.Tn FTP
+URL, retrieved using the
+.Tn FTP
+protocol if
+.Ic "set ftp_proxy"
+isn't defined.
+Otherwise, transfer the URL using
+.Tn HTTP
+via the proxy defined in
+.Ic "set ftp_proxy" .
+If
+.Ic "set ftp_proxy"
+isn't defined and
+.Ar user
+is given, login as
+.Ar user .
+In this case, use
+.Ar password
+if supplied, otherwise prompt the user for one.
+.Pp
+If a suffix of
+.Sq ;type=A
+or
+.Sq ;type=I
+is supplied, then the transfer type will take place as
+ascii or binary (respectively).
+The default transfer type is binary.
+.Pp
+In order to be compliant with
+.Li RFC3986 ,
+.Nm
+interprets the
+.Ar path
+part of an
+.Dq ftp://
+auto-fetch URL as follows:
+.Bl -bullet
+.It
+The
+.Sq Li /
+immediately after the
+.Ar host Ns Oo Li \&: Ns Ar port Oc
+is interpreted as a separator before the
+.Ar path ,
+and not as part of the
+.Ar path
+itself.
+.It
+The
+.Ar path
+is interpreted as a
+.So Li / Sc Ns -separated
+list of name components.
+For all but the last such component,
+.Nm
+performs the equivalent of a
+.Ic cd
+command.
+For the last path component,
+.Nm
+performs the equivalent of a
+.Ic get
+command.
+.It
+Empty name components,
+which result from
+.Sq Li //
+within the
+.Ar path ,
+or from an extra
+.Sq Li /
+at the beginning of the
+.Ar path ,
+will cause the equivalent of a
+.Ic cd
+command without a directory name.
+This is unlikely to be useful.
+.It
+Any
+.Sq Li \&% Ns Ar XX
+codes
+(per
+.Li RFC3986 )
+within the path components are decoded, with
+.Ar XX
+representing a character code in hexadecimal.
+This decoding takes place after the
+.Ar path
+has been split into components,
+but before each component is used in the equivalent of a
+.Ic cd
+or
+.Ic get
+command.
+Some often-used codes are
+.Sq Li \&%2F
+(which represents
+.Sq Li / )
+and
+.Sq Li \&%7E
+(which represents
+.Sq Li ~ ) .
+.El
+.Pp
+The above interpretation has the following consequences:
+.Bl -bullet
+.It
+The path is interpreted relative to the
+default login directory of the specified user or of the
+.Sq anonymous
+user.
+If the
+.Pa /
+directory is required, use a leading path of
+.Dq %2F .
+If a user's home directory is required (and the remote server supports
+the syntax), use a leading path of
+.Dq %7Euser/ .
+For example, to retrieve
+.Pa /etc/motd
+from
+.Sq localhost
+as the user
+.Sq myname
+with the password
+.Sq mypass ,
+use
+.Dq ftp://myname:mypass@localhost/%2fetc/motd
+.It
+The exact
+.Ic cd
+and
+.Ic get
+commands can be controlled by careful choice of
+where to use
+.Sq /
+and where to use
+.Sq %2F
+(or
+.Sq %2f ) .
+For example, the following URLs correspond to the
+equivalents of the indicated commands:
+.Bl -tag -width "ftp://host/%2Fdir1%2Fdir2%2Ffile"
+.It ftp://host/dir1/dir2/file
+.Dq "cd dir1" ,
+.Dq "cd dir2" ,
+.Dq "get file" .
+.It ftp://host/%2Fdir1/dir2/file
+.Dq "cd /dir1" ,
+.Dq "cd dir2" ,
+.Dq "get file" .
+.It ftp://host/dir1%2Fdir2/file
+.Dq "cd dir1/dir2" ,
+.Dq "get file" .
+.It ftp://host/%2Fdir1%2Fdir2/file
+.Dq "cd /dir1/dir2" ,
+.Dq "get file" .
+.It ftp://host/dir1%2Fdir2%2Ffile
+.Dq "get dir1/dir2/file" .
+.It ftp://host/%2Fdir1%2Fdir2%2Ffile
+.Dq "get /dir1/dir2/file" .
+.El
+.It
+You must have appropriate access permission for each of the
+intermediate directories that is used in the equivalent of a
+.Ic cd
+command.
+.El
+.\" http://[user[:password]@]host[:port]/path
+.It Li http:// Ns Oo Ar user Ns Oo Li \&: Ns Ar password Oc Ns Li \&@ Oc \
+Ns Ar host Ns Oo Li \&: Ns Ar port Oc Ns Li / Ns Ar path
+An
+.Tn HTTP
+URL, retrieved using the
+.Tn HTTP
+protocol.
+If
+.Ic "set http_proxy"
+is defined, it is used as a URL to an
+.Tn HTTP
+proxy server.
+If
+.Tn HTTP
+authorization is required to retrieve
+.Ar path ,
+and
+.Sq user
+(and optionally
+.Sq password )
+is in the URL, use them for the first attempt to authenticate.
+.\" file:///path
+.It Li file:/// Ns Ar path
+A local URL, copied from
+.Pa / Ns Ar path
+on the local host.
+.\" about:
+.It Li about: Ns Ar topic
+Display information regarding
+.Ar topic ;
+no file is retrieved for this auto-fetched element.
+Supported values include:
+.Bl -tag -width "about:version"
+.It Li about:ftp
+Information about
+.Nm ftp .
+.It Li about:version
+The version of
+.Nm ftp .
+Useful to provide when reporting problems.
+.El
+.El
+.Pp
+Unless noted otherwise above, and
+.Fl o Ar output
+is not given, the file is stored in the current directory as the
+.Xr basename 1
+of
+.Ar path .
+Note that if a
+.Tn HTTP
+redirect is received, the fetch is retried using the new target URL
+supplied by the server, with a corresponding new
+.Ar path .
+Using an explicit
+.Fl o Ar output
+is recommended, to avoid writing to unexpected file names.
+.Pp
+If a classic format or an
+.Tn FTP
+URL format has a trailing
+.Sq /
+or an empty
+.Ar path
+component, then
+.Nm
+will connect to the site and
+.Ic cd
+to the directory given as the path, and leave the user in interactive
+mode ready for further input.
+This will not work if
+.Ic "set ftp_proxy"
+is being used.
+.Pp
+Direct
+.Tn HTTP
+transfers use HTTP 1.1.
+Proxied
+.Tn FTP
+and
+.Tn HTTP
+transfers use HTTP 1.0.
+.Pp
+If
+.Fl R
+is given, all auto-fetches that don't go via the
+.Tn FTP
+or
+.Tn HTTP
+proxies will be restarted.
+For
+.Tn FTP ,
+this is implemented by using
+.Nm reget
+instead of
+.Nm get .
+For
+.Tn HTTP ,
+this is implemented by using the
+.Sq "Range: bytes="
+.Tn "HTTP/1.1"
+directive.
+.Pp
+If WWW or proxy WWW authentication is required, you will be prompted
+to enter a username and password to authenticate with.
+.Pp
+When specifying IPv6 numeric addresses in a URL, you need to
+surround the address in square brackets.
+E.g.:
+.Dq ftp://[::1]:21/ .
+This is because colons are used in IPv6 numeric address as well as
+being the separator for the port number.
+.Sh ABORTING A FILE TRANSFER
+To abort a file transfer, use the terminal interrupt key
+(usually Ctrl-C).
+Sending transfers will be immediately halted.
+Receiving transfers will be halted by sending an
+.Tn FTP
+protocol
+.Dv ABOR
+command to the remote server, and discarding any further data received.
+The speed at which this is accomplished depends upon the remote
+server's support for
+.Dv ABOR
+processing.
+If the remote server does not support the
+.Dv ABOR
+command, the prompt will not appear until the remote server has completed
+sending the requested file.
+.Pp
+If the terminal interrupt key sequence is used whilst
+.Nm
+is awaiting a reply from the remote server for the ABOR processing,
+then the connection will be closed.
+This is different from the traditional behaviour (which ignores the
+terminal interrupt during this phase), but is considered more useful.
+.Sh FILE NAMING CONVENTIONS
+Files specified as arguments to
+.Nm
+commands are processed according to the following rules.
+.Bl -enum
+.It
+If the file name
+.Sq Fl
+is specified, the
+.Ar stdin
+(for reading) or
+.Ar stdout
+(for writing) is used.
+.It
+If the first character of the file name is
+.Sq \&| ,
+the
+remainder of the argument is interpreted as a shell command.
+.Nm
+then forks a shell, using
+.Xr popen 3
+with the argument supplied, and reads (writes) from the stdout
+(stdin).
+If the shell command includes spaces, the argument
+must be quoted; e.g.
+.Dq Qq Li \&| ls\ \-lt .
+A particularly
+useful example of this mechanism is:
+.Dq Li dir \&"\&" \&|more .
+.It
+Failing the above checks, if
+.Dq globbing
+is enabled, local file names are expanded according to the rules
+used in the
+.Xr csh  1  ;
+see the
+.Ic glob
+command.
+If the
+.Nm
+command expects a single local file (e.g.
+.Ic put  ) ,
+only the first filename generated by the "globbing" operation is used.
+.It
+For
+.Ic mget
+commands and
+.Ic get
+commands with unspecified local file names, the local filename is
+the remote filename, which may be altered by a
+.Ic case  ,
+.Ic ntrans ,
+or
+.Ic nmap
+setting.
+The resulting filename may then be altered if
+.Ic runique
+is on.
+.It
+For
+.Ic mput
+commands and
+.Ic put
+commands with unspecified remote file names, the remote filename is
+the local filename, which may be altered by a
+.Ic ntrans
+or
+.Ic nmap
+setting.
+The resulting filename may then be altered by the remote server if
+.Ic sunique
+is on.
+.El
+.Sh FILE TRANSFER PARAMETERS
+The
+.Tn FTP
+specification specifies many parameters which may affect a file transfer.
+The
+.Ic type
+may be one of
+.Dq ascii ,
+.Dq image
+(binary),
+.Dq ebcdic ,
+and
+.Dq local byte size
+(for
+.Tn PDP Ns -10's
+and
+.Tn PDP Ns -20's
+mostly).
+.Nm
+supports the ascii and image types of file transfer,
+plus local byte size 8 for
+.Ic tenex
+mode transfers.
+.Pp
+.Nm
+supports only the default values for the remaining
+file transfer parameters:
+.Ic mode ,
+.Ic form ,
+and
+.Ic struct .
+.Sh THE .netrc FILE
+The
+.Pa .netrc
+file contains login and initialization information
+used by the auto-login process.
+It resides in the user's home directory,
+unless overridden with the
+.Fl N Ar netrc
+option, or specified in the
+.Ev NETRC
+environment variable.
+The following tokens are recognized; they may be separated by spaces,
+tabs, or new-lines:
+.Bl -tag -width password
+.It Ic machine Ar name
+Identify a remote machine
+.Ar name .
+The auto-login process searches the
+.Pa .netrc
+file for a
+.Ic machine
+token that matches the remote machine specified on the
+.Nm
+command line or as an
+.Ic open
+command argument.
+Once a match is made, the subsequent
+.Pa .netrc
+tokens are processed,
+stopping when the end of file is reached or another
+.Ic machine
+or a
+.Ic default
+token is encountered.
+.It Ic default
+This is the same as
+.Ic machine
+.Ar name
+except that
+.Ic default
+matches any name.
+There can be only one
+.Ic default
+token, and it must be after all
+.Ic machine
+tokens.
+This is normally used as:
+.Pp
+.Dl default login anonymous password user at site
+.Pp
+thereby giving the user an automatic anonymous
+.Tn FTP
+login to
+machines not specified in
+.Pa .netrc .
+This can be overridden
+by using the
+.Fl n
+flag to disable auto-login.
+.It Ic login Ar name
+Identify a user on the remote machine.
+If this token is present, the auto-login process will initiate
+a login using the specified
+.Ar name .
+.It Ic password Ar string
+Supply a password.
+If this token is present, the auto-login process will supply the
+specified string if the remote server requires a password as part
+of the login process.
+Note that if this token is present in the
+.Pa .netrc
+file for any user other
+than
+.Ar anonymous  ,
+.Nm
+will abort the auto-login process if the
+.Pa .netrc
+is readable by
+anyone besides the user.
+.It Ic account Ar string
+Supply an additional account password.
+If this token is present, the auto-login process will supply the
+specified string if the remote server requires an additional
+account password, or the auto-login process will initiate an
+.Dv ACCT
+command if it does not.
+.It Ic macdef Ar name
+Define a macro.
+This token functions like the
+.Nm
+.Ic macdef
+command functions.
+A macro is defined with the specified name; its contents begin with the
+next
+.Pa .netrc
+line and continue until a blank line (consecutive new-line
+characters) is encountered.
+Like the other tokens in the
+.Pa .netrc
+file, a
+.Ic macdef
+is applicable only to the
+.Ic machine
+definition preceding it.
+A
+.Ic macdef
+entry cannot be used by multiple
+.Ic machine
+definitions; rather, it must be defined following each
+.Ic machine
+it is intended to be used with.
+If a macro named
+.Ic init
+is defined, it is automatically executed as the last step in the
+auto-login process.
+For example,
+.Bd -literal -offset indent
+default
+macdef init
+epsv4 off
+.Ed
+.Pp
+followed by a blank line.
+.El
+.Sh COMMAND LINE EDITING
+.Nm
+supports interactive command line editing, via the
+.Xr editline 3
+library.
+It is enabled with the
+.Ic edit
+command, and is enabled by default if input is from a tty.
+Previous lines can be recalled and edited with the arrow keys,
+and other GNU Emacs-style editing keys may be used as well.
+.Pp
+The
+.Xr editline 3
+library is configured with a
+.Pa .editrc
+file - refer to
+.Xr editrc 5
+for more information.
+.Pp
+An extra key binding is available to
+.Nm
+to provide context sensitive command and filename completion
+(including remote file completion).
+To use this, bind a key to the
+.Xr editline 3
+command
+.Ic ftp-complete .
+By default, this is bound to the TAB key.
+.Sh COMMAND LINE PROMPT
+By default,
+.Nm
+displays a command line prompt of
+.Dq "ftp\*[Gt] "
+to the user.
+This can be changed with the
+.Ic "set prompt"
+command.
+.Pp
+A prompt can be displayed on the right side of the screen (after the
+command input) with the
+.Ic "set rprompt"
+command.
+.Pp
+The following formatting sequences are replaced by the given
+information:
+.Bl -tag -width "%% " -offset indent
+.It Li \&%/
+The current remote working directory.
+.\" %c[[0]n], %.[[0]n]
+.It \&%c Ns Oo Oo Li 0 Oc Ns Ar n Oc , Ns Li \&%. Ns Oo Oo Li 0 Oc Ns Ar n Oc
+The trailing component of the current remote working directory, or
+.Em n
+trailing components if a digit
+.Em n
+is given.
+If
+.Em n
+begins with
+.Sq 0 ,
+the number of skipped components precede the trailing component(s) in
+the format
+.\" ``/<number>trailing''
+.Do
+.Sm off
+.Li / Li \*[Lt] Va number Li \*[Gt]
+.Va trailing
+.Sm on
+.Dc
+(for
+.Sq \&%c )
+or
+.\" ``...trailing''
+.Dq Li \&... Ns Va trailing
+(for
+.Sq \&%. ) .
+.It Li \&%M
+The remote host name.
+.It Li \&%m
+The remote host name, up to the first
+.Sq \&. .
+.It Li \&%n
+The remote user name.
+.It Li \&%%
+A single
+.Sq % .
+.El
+.Sh ENVIRONMENT
+.Nm
+uses the following environment variables.
+.Bl -tag -width "FTPSERVERPORT"
+.It Ev FTPANONPASS
+Password to send in an anonymous
+.Tn FTP
+transfer.
+Defaults to
+.Dq Li `whoami`@ .
+.It Ev FTPMODE
+Overrides the default operation mode.
+Support values are:
+.Bl -tag -width "passive"
+.It Cm active
+active mode
+.Tn FTP
+only
+.It Cm auto
+automatic determination of passive or active (this is the default)
+.It Cm gate
+gate-ftp mode
+.It Cm passive
+passive mode
+.Tn FTP
+only
+.El
+.It Ev FTPPROMPT
+Command-line prompt to use.
+Defaults to
+.Dq "ftp\*[Gt] " .
+Refer to
+.Sx COMMAND LINE PROMPT
+for more information.
+.It Ev FTPRPROMPT
+Command-line right side prompt to use.
+Defaults to
+.Dq "" .
+Refer to
+.Sx COMMAND LINE PROMPT
+for more information.
+.It Ev FTPSERVER
+Host to use as gate-ftp server when
+.Ic gate
+is enabled.
+.It Ev FTPSERVERPORT
+Port to use when connecting to gate-ftp server when
+.Ic gate
+is enabled.
+Default is port returned by a
+.Fn getservbyname
+lookup of
+.Dq ftpgate/tcp .
+.It Ev FTPUSERAGENT
+The value to send for the
+.Tn HTTP
+User-Agent
+header.
+.It Ev HOME
+For default location of a
+.Pa .netrc
+file, if one exists.
+.It Ev NETRC
+An alternate location of the
+.Pa .netrc
+file.
+.It Ev PAGER
+Used by various commands to display files.
+Defaults to
+.Xr more 1
+if empty or not set.
+.It Ev SHELL
+For default shell.
+.It Ev ftp_proxy
+URL of
+.Tn FTP
+proxy to use when making
+.Tn FTP
+URL requests
+(if not defined, use the standard
+.Tn FTP
+protocol).
+.Pp
+See
+.Ev http_proxy
+for further notes about proxy use.
+.It Ev http_proxy
+URL of
+.Tn HTTP
+proxy to use when making
+.Tn HTTP
+URL requests.
+If proxy authentication is required and there is a username and
+password in this URL, they will automatically be used in the first
+attempt to authenticate to the proxy.
+.Pp
+If
+.Dq unsafe
+URL characters are required in the username or password
+(for example
+.Sq @
+or
+.Sq / ) ,
+encode them with
+.Li RFC3986
+.Sq Li \&% Ns Ar XX
+encoding.
+.Pp
+Note that the use of a username and password in
+.Ev ftp_proxy
+and
+.Ev http_proxy
+may be incompatible with other programs that use it
+(such as
+.Xr lynx 1 ) .
+.Pp
+.Em NOTE :
+this is not used for interactive sessions, only for command-line
+fetches.
+.It Ev no_proxy
+A space or comma separated list of hosts (or domains) for which
+proxying is not to be used.
+Each entry may have an optional trailing ":port", which restricts
+the matching to connections to that port.
+.El
+.Sh EXTENDED PASSIVE MODE AND FIREWALLS
+Some firewall configurations do not allow
+.Nm
+to use extended passive mode.
+If you find that even a simple
+.Ic ls
+appears to hang after printing a message such as this:
+.Pp
+.Dl 229 Entering Extended Passive Mode (|||58551|)
+.Pp
+then you will need to disable extended passive mode with
+.Ic epsv4 off .
+See the above section
+.Sx The .netrc File
+for an example of how to make this automatic.
+.Sh SEE ALSO
+.Xr getservbyname 3 ,
+.Xr editrc 5 ,
+.Xr services 5 ,
+.Xr ftpd 8
+.Sh STANDARDS
+.Nm
+attempts to be compliant with:
+.Bl -tag -offset indent -width 8n
+.It Li RFC0959
+.Em File Transfer Protocol
+.It Li RFC1123
+.Em Requirements for Internet Hosts - Application and Support
+.It Li RFC1635
+.Em How to Use Anonymous FTP
+.It Li RFC2389
+.Em Feature negotiation mechanism for the File Transfer Protocol
+.It Li RFC2428
+.Em FTP Extensions for IPv6 and NATs
+.It Li RFC2616
+.Em Hypertext Transfer Protocol -- HTTP/1.1
+.It Li RFC2822
+.Em Internet Message Format
+.It Li RFC3659
+.Em Extensions to FTP
+.It Li RFC3986
+.Em Uniform Resource Identifier (URI)
+.El
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
+.Pp
+Various features such as command line editing, context sensitive
+command and file completion, dynamic progress bar, automatic
+fetching of files and URLs, modification time preservation,
+transfer rate throttling, configurable command line prompt,
+and other enhancements over the standard
+.Bx
+.Nm
+were implemented in
+.Nx 1.3
+and later releases
+by
+.An Luke Mewburn
+.Aq lukem at NetBSD.org .
+.Pp
+IPv6 support was added by the WIDE/KAME project
+(but may not be present in all non-NetBSD versions of this program, depending
+if the operating system supports IPv6 in a similar manner to KAME).
+.Sh BUGS
+Correct execution of many commands depends upon proper behavior
+by the remote server.
+.Pp
+An error in the treatment of carriage returns
+in the
+.Bx 4.2
+ascii-mode transfer code
+has been corrected.
+This correction may result in incorrect transfers of binary files
+to and from
+.Bx 4.2
+servers using the ascii type.
+Avoid this problem by using the binary image type.
+.Pp
+.Nm
+assumes that all IPv4 mapped addresses
+.Po
+IPv6 addresses with a form like
+.Li ::ffff:10.1.1.1
+.Pc
+indicate IPv4 destinations which can be handled by
+.Dv AF_INET
+sockets.
+However, in certain IPv6 network configurations, this assumption is not true.
+In such an environment, IPv4 mapped addresses must be passed to
+.Dv AF_INET6
+sockets directly.
+For example, if your site uses a SIIT translator for IPv6-to-IPv4 translation,
+.Nm
+is unable to support your configuration.

Added: vendor/NetBSD/tnftp/20100108/src/ftp.c
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/ftp.c	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/ftp.c	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,2149 @@
+/*	$NetBSD: ftp.c,v 1.18 2009/05/20 12:53:47 lukem Exp $	*/
+/*	from	NetBSD: ftp.c,v 1.159 2009/04/15 03:42:33 jld Exp	*/
+
+/*-
+ * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1985, 1989, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (C) 1997 and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "tnftp.h"
+#include <arpa/telnet.h>
+
+#if 0	/* tnftp */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ftp.c	8.6 (Berkeley) 10/27/94";
+#else
+__RCSID(" NetBSD: ftp.c,v 1.159 2009/04/15 03:42:33 jld Exp  ");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <arpa/ftp.h>
+#include <arpa/telnet.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#endif	/* tnftp */
+
+#include "ftp_var.h"
+
+volatile sig_atomic_t	abrtflag;
+volatile sig_atomic_t	timeoutflag;
+
+sigjmp_buf	ptabort;
+int	ptabflg;
+int	ptflag = 0;
+char	pasv[BUFSIZ];	/* passive port for proxy data connection */
+
+static int empty(FILE *, FILE *, int);
+
+struct sockinet {
+	union sockunion {
+		struct sockaddr_in  su_sin;
+#ifdef INET6
+		struct sockaddr_in6 su_sin6;
+#endif
+	} si_su;
+#if !defined(HAVE_STRUCT_SOCKADDR_IN_SIN_LEN)
+	int	si_len;
+#endif
+};
+
+#if !defined(HAVE_STRUCT_SOCKADDR_IN_SIN_LEN)
+# define su_len		si_len
+#else
+# define su_len		si_su.su_sin.sin_len
+#endif
+#define su_family	si_su.su_sin.sin_family
+#define su_port		si_su.su_sin.sin_port
+
+struct sockinet myctladdr, hisctladdr, data_addr;
+
+char *
+hookup(const char *host, const char *port)
+{
+	int s = -1, error;
+	struct addrinfo hints, *res, *res0;
+	static char hostnamebuf[MAXHOSTNAMELEN];
+	socklen_t len;
+	int on = 1;
+
+	memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
+	memset((char *)&myctladdr, 0, sizeof (myctladdr));
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_flags = AI_CANONNAME;
+	hints.ai_family = family;
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_protocol = 0;
+	error = getaddrinfo(host, port, &hints, &res0);
+	if (error) {
+		warnx("Can't lookup `%s:%s': %s", host, port,
+		    (error == EAI_SYSTEM) ? strerror(errno)
+					  : gai_strerror(error));
+		code = -1;
+		return (0);
+	}
+
+	if (res0->ai_canonname)
+		(void)strlcpy(hostnamebuf, res0->ai_canonname,
+		    sizeof(hostnamebuf));
+	else
+		(void)strlcpy(hostnamebuf, host, sizeof(hostnamebuf));
+	hostname = hostnamebuf;
+
+	for (res = res0; res; res = res->ai_next) {
+		char hname[NI_MAXHOST], sname[NI_MAXSERV];
+
+		ai_unmapped(res);
+		if (getnameinfo(res->ai_addr, res->ai_addrlen,
+		    hname, sizeof(hname), sname, sizeof(sname),
+		    NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
+			strlcpy(hname, "?", sizeof(hname));
+			strlcpy(sname, "?", sizeof(sname));
+		}
+		if (verbose && res0->ai_next) {
+				/* if we have multiple possibilities */
+			fprintf(ttyout, "Trying %s:%s ...\n", hname, sname);
+		}
+		s = socket(res->ai_family, SOCK_STREAM, res->ai_protocol);
+		if (s < 0) {
+			warn("Can't create socket for connection to `%s:%s'",
+			    hname, sname);
+			continue;
+		}
+		if (ftp_connect(s, res->ai_addr, res->ai_addrlen) < 0) {
+			close(s);
+			s = -1;
+			continue;
+		}
+
+		/* finally we got one */
+		break;
+	}
+	if (s < 0) {
+		warnx("Can't connect to `%s:%s'", host, port);
+		code = -1;
+		freeaddrinfo(res0);
+		return 0;
+	}
+	memcpy(&hisctladdr.si_su, res->ai_addr, res->ai_addrlen);
+	hisctladdr.su_len = res->ai_addrlen;
+	freeaddrinfo(res0);
+	res0 = res = NULL;
+
+	len = hisctladdr.su_len;
+	if (getsockname(s, (struct sockaddr *)&myctladdr.si_su, &len) == -1) {
+		warn("Can't determine my address of connection to `%s:%s'",
+		    host, port);
+		code = -1;
+		goto bad;
+	}
+	myctladdr.su_len = len;
+
+#ifdef IPTOS_LOWDELAY
+	if (hisctladdr.su_family == AF_INET) {
+		int tos = IPTOS_LOWDELAY;
+		if (setsockopt(s, IPPROTO_IP, IP_TOS,
+				(void *)&tos, sizeof(tos)) == -1) {
+				DWARN("setsockopt %s (ignored)",
+				    "IPTOS_LOWDELAY");
+		}
+	}
+#endif
+	cin = fdopen(s, "r");
+	cout = fdopen(s, "w");
+	if (cin == NULL || cout == NULL) {
+		warnx("Can't fdopen socket");
+		if (cin)
+			(void)fclose(cin);
+		if (cout)
+			(void)fclose(cout);
+		code = -1;
+		goto bad;
+	}
+	if (verbose)
+		fprintf(ttyout, "Connected to %s.\n", hostname);
+	if (getreply(0) > 2) {	/* read startup message from server */
+		if (cin)
+			(void)fclose(cin);
+		if (cout)
+			(void)fclose(cout);
+		code = -1;
+		goto bad;
+	}
+
+	if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE,
+			(void *)&on, sizeof(on)) == -1) {
+		DWARN("setsockopt %s (ignored)", "SO_OOBINLINE");
+	}
+
+	return (hostname);
+ bad:
+	(void)close(s);
+	return (NULL);
+}
+
+void
+cmdabort(int notused)
+{
+	int oerrno = errno;
+
+	sigint_raised = 1;
+	alarmtimer(0);
+	if (fromatty)
+		write(fileno(ttyout), "\n", 1);
+	abrtflag++;
+	if (ptflag)
+		siglongjmp(ptabort, 1);
+	errno = oerrno;
+}
+
+void
+cmdtimeout(int notused)
+{
+	int oerrno = errno;
+
+	alarmtimer(0);
+	if (fromatty)
+		write(fileno(ttyout), "\n", 1);
+	timeoutflag++;
+	if (ptflag)
+		siglongjmp(ptabort, 1);
+	errno = oerrno;
+}
+
+/*VARARGS*/
+int
+command(const char *fmt, ...)
+{
+	va_list ap;
+	int r;
+	sigfunc oldsigint;
+
+#ifndef NO_DEBUG
+	if (ftp_debug) {
+		fputs("---> ", ttyout);
+		va_start(ap, fmt);
+		if (strncmp("PASS ", fmt, 5) == 0)
+			fputs("PASS XXXX", ttyout);
+		else if (strncmp("ACCT ", fmt, 5) == 0)
+			fputs("ACCT XXXX", ttyout);
+		else
+			vfprintf(ttyout, fmt, ap);
+		va_end(ap);
+		putc('\n', ttyout);
+	}
+#endif
+	if (cout == NULL) {
+		warnx("No control connection for command");
+		code = -1;
+		return (0);
+	}
+
+	abrtflag = 0;
+
+	oldsigint = xsignal(SIGINT, cmdabort);
+
+	va_start(ap, fmt);
+	vfprintf(cout, fmt, ap);
+	va_end(ap);
+	fputs("\r\n", cout);
+	(void)fflush(cout);
+	cpend = 1;
+	r = getreply(!strcmp(fmt, "QUIT"));
+	if (abrtflag && oldsigint != SIG_IGN)
+		(*oldsigint)(SIGINT);
+	(void)xsignal(SIGINT, oldsigint);
+	return (r);
+}
+
+static const char *m421[] = {
+	"remote server timed out. Connection closed",
+	"user interrupt. Connection closed",
+	"remote server has closed connection",
+};
+
+int
+getreply(int expecteof)
+{
+	char current_line[BUFSIZ];	/* last line of previous reply */
+	int c, n, lineno;
+	int dig;
+	int originalcode = 0, continuation = 0;
+	sigfunc oldsigint, oldsigalrm;
+	int pflag = 0;
+	char *cp, *pt = pasv;
+
+	abrtflag = 0;
+	timeoutflag = 0;
+
+	oldsigint = xsignal(SIGINT, cmdabort);
+	oldsigalrm = xsignal(SIGALRM, cmdtimeout);
+
+	for (lineno = 0 ;; lineno++) {
+		dig = n = code = 0;
+		cp = current_line;
+		while (alarmtimer(quit_time ? quit_time : 60),
+		       ((c = getc(cin)) != '\n')) {
+			if (c == IAC) {     /* handle telnet commands */
+				switch (c = getc(cin)) {
+				case WILL:
+				case WONT:
+					c = getc(cin);
+					fprintf(cout, "%c%c%c", IAC, DONT, c);
+					(void)fflush(cout);
+					break;
+				case DO:
+				case DONT:
+					c = getc(cin);
+					fprintf(cout, "%c%c%c", IAC, WONT, c);
+					(void)fflush(cout);
+					break;
+				default:
+					break;
+				}
+				continue;
+			}
+			dig++;
+			if (c == EOF) {
+				/*
+				 * these will get trashed by pswitch()
+				 * in lostpeer()
+				 */
+				int reply_timeoutflag = timeoutflag;
+				int reply_abrtflag = abrtflag;
+
+				alarmtimer(0);
+				if (expecteof && feof(cin)) {
+					(void)xsignal(SIGINT, oldsigint);
+					(void)xsignal(SIGALRM, oldsigalrm);
+					code = 221;
+					return (0);
+				}
+				cpend = 0;
+				lostpeer(0);
+				if (verbose) {
+					size_t midx;
+					if (reply_timeoutflag)
+						midx = 0;
+					else if (reply_abrtflag)
+						midx = 1;
+					else
+						midx = 2;
+					(void)fprintf(ttyout,
+			    "421 Service not available, %s.\n", m421[midx]);
+					(void)fflush(ttyout);
+				}
+				code = 421;
+				(void)xsignal(SIGINT, oldsigint);
+				(void)xsignal(SIGALRM, oldsigalrm);
+				return (4);
+			}
+			if (c != '\r' && (verbose > 0 ||
+			    ((verbose > -1 && n == '5' && dig > 4) &&
+			    (((!n && c < '5') || (n && n < '5'))
+			     || !retry_connect)))) {
+				if (proxflag &&
+				   (dig == 1 || (dig == 5 && verbose == 0)))
+					fprintf(ttyout, "%s:", hostname);
+				(void)putc(c, ttyout);
+			}
+			if (dig < 4 && isdigit(c))
+				code = code * 10 + (c - '0');
+			if (!pflag && (code == 227 || code == 228))
+				pflag = 1;
+			else if (!pflag && code == 229)
+				pflag = 100;
+			if (dig > 4 && pflag == 1 && isdigit(c))
+				pflag = 2;
+			if (pflag == 2) {
+				if (c != '\r' && c != ')') {
+					if (pt < &pasv[sizeof(pasv) - 1])
+						*pt++ = c;
+				} else {
+					*pt = '\0';
+					pflag = 3;
+				}
+			}
+			if (pflag == 100 && c == '(')
+				pflag = 2;
+			if (dig == 4 && c == '-') {
+				if (continuation)
+					code = 0;
+				continuation++;
+			}
+			if (n == 0)
+				n = c;
+			if (cp < &current_line[sizeof(current_line) - 1])
+				*cp++ = c;
+		}
+		if (verbose > 0 || ((verbose > -1 && n == '5') &&
+		    (n < '5' || !retry_connect))) {
+			(void)putc(c, ttyout);
+			(void)fflush(ttyout);
+		}
+		if (cp[-1] == '\r')
+			cp[-1] = '\0';
+		*cp = '\0';
+		if (lineno == 0)
+			(void)strlcpy(reply_string, current_line,
+			    sizeof(reply_string));
+		if (lineno > 0 && code == 0 && reply_callback != NULL)
+			(*reply_callback)(current_line);
+		if (continuation && code != originalcode) {
+			if (originalcode == 0)
+				originalcode = code;
+			continue;
+		}
+		if (n != '1')
+			cpend = 0;
+		alarmtimer(0);
+		(void)xsignal(SIGINT, oldsigint);
+		(void)xsignal(SIGALRM, oldsigalrm);
+		if (code == 421 || originalcode == 421)
+			lostpeer(0);
+		if (abrtflag && oldsigint != cmdabort && oldsigint != SIG_IGN)
+			(*oldsigint)(SIGINT);
+		if (timeoutflag && oldsigalrm != cmdtimeout &&
+		    oldsigalrm != SIG_IGN)
+			(*oldsigalrm)(SIGINT);
+		return (n - '0');
+	}
+}
+
+static int
+empty(FILE *ecin, FILE *din, int sec)
+{
+	int		nr, nfd;
+	struct pollfd	pfd[2];
+
+	nfd = 0;
+	if (ecin) {
+		pfd[nfd].fd = fileno(ecin);
+		pfd[nfd++].events = POLLIN;
+	}
+
+	if (din) {
+		pfd[nfd].fd = fileno(din);
+		pfd[nfd++].events = POLLIN;
+	}
+
+	if ((nr = ftp_poll(pfd, nfd, sec * 1000)) <= 0)
+		return nr;
+
+	nr = 0;
+	nfd = 0;
+	if (ecin)
+		nr |= (pfd[nfd++].revents & POLLIN) ? 1 : 0;
+	if (din)
+		nr |= (pfd[nfd++].revents & POLLIN) ? 2 : 0;
+	return nr;
+}
+
+sigjmp_buf	xferabort;
+
+void
+abortxfer(int notused)
+{
+	char msgbuf[100];
+	size_t len;
+
+	sigint_raised = 1;
+	alarmtimer(0);
+	mflag = 0;
+	abrtflag = 0;
+	switch (direction[0]) {
+	case 'r':
+		strlcpy(msgbuf, "\nreceive", sizeof(msgbuf));
+		break;
+	case 's':
+		strlcpy(msgbuf, "\nsend", sizeof(msgbuf));
+		break;
+	default:
+		errx(1, "abortxfer: unknown direction `%s'", direction);
+	}
+	len = strlcat(msgbuf, " aborted. Waiting for remote to finish abort.\n",
+	    sizeof(msgbuf));
+	write(fileno(ttyout), msgbuf, len);
+	siglongjmp(xferabort, 1);
+}
+
+/*
+ * Read data from infd & write to outfd, using buf/bufsize as the temporary
+ * buffer, dealing with short writes.
+ * If rate_limit != 0, rate-limit the transfer.
+ * If hash_interval != 0, fputc('c', ttyout) every hash_interval bytes.
+ * Updates global variables: bytes.
+ * Returns 0 if ok, 1 if there was a read error, 2 if there was a write error.
+ * In the case of error, errno contains the appropriate error code.
+ */
+static int
+copy_bytes(int infd, int outfd, char *buf, size_t bufsize,
+	int rate_limit, int hash_interval)
+{
+	volatile off_t	hashc;
+	ssize_t		inc, outc;
+	char		*bufp;
+	struct timeval	tvthen, tvnow, tvdiff;
+	off_t		bufrem, bufchunk;
+	int		serr;
+
+	hashc = hash_interval;
+	if (rate_limit)
+		bufchunk = rate_limit;
+	else
+		bufchunk = bufsize;
+
+	while (1) {
+		if (rate_limit) {
+			(void)gettimeofday(&tvthen, NULL);
+		}
+		errno = 0;
+		inc = outc = 0;
+					/* copy bufchunk at a time */
+		bufrem = bufchunk;
+		while (bufrem > 0) {
+			inc = read(infd, buf, MIN((off_t)bufsize, bufrem));
+			if (inc <= 0)
+				goto copy_done;
+			bytes += inc;
+			bufrem -= inc;
+			bufp = buf;
+			while (inc > 0) {
+				outc = write(outfd, bufp, inc);
+				if (outc < 0)
+					goto copy_done;
+				inc -= outc;
+				bufp += outc;
+			}
+			if (hash_interval) {
+				while (bytes >= hashc) {
+					(void)putc('#', ttyout);
+					hashc += hash_interval;
+				}
+				(void)fflush(ttyout);
+			}
+		}
+		if (rate_limit) {	/* rate limited; wait if necessary */
+			while (1) {
+				(void)gettimeofday(&tvnow, NULL);
+				timersub(&tvnow, &tvthen, &tvdiff);
+				if (tvdiff.tv_sec > 0)
+					break;
+				usleep(1000000 - tvdiff.tv_usec);
+			}
+		}
+	}
+
+ copy_done:
+	serr = errno;
+	if (hash_interval && bytes > 0) {
+		if (bytes < hash_interval)
+			(void)putc('#', ttyout);
+		(void)putc('\n', ttyout);
+		(void)fflush(ttyout);
+	}
+	errno = serr;
+	if (inc == -1)
+		return 1;
+	if (outc == -1)
+		return 2;
+
+	return 0;
+}
+
+void
+sendrequest(const char *cmd, const char *local, const char *remote,
+	    int printnames)
+{
+	struct stat st;
+	int c;
+	FILE *volatile fin;
+	FILE *volatile dout;
+	int (*volatile closefunc)(FILE *);
+	sigfunc volatile oldintr;
+	sigfunc volatile oldintp;
+	off_t volatile hashbytes;
+	int hash_interval;
+	const char *lmode;
+	static size_t bufsize;
+	static char *buf;
+	int oprogress;
+
+	hashbytes = mark;
+	direction = "sent";
+	dout = NULL;
+	bytes = 0;
+	filesize = -1;
+	oprogress = progress;
+	if (verbose && printnames) {
+		if (*local != '-')
+			fprintf(ttyout, "local: %s ", local);
+		if (remote)
+			fprintf(ttyout, "remote: %s\n", remote);
+	}
+	if (proxy) {
+		proxtrans(cmd, local, remote);
+		return;
+	}
+	if (curtype != type)
+		changetype(type, 0);
+	closefunc = NULL;
+	oldintr = NULL;
+	oldintp = NULL;
+	lmode = "w";
+	if (sigsetjmp(xferabort, 1)) {
+		while (cpend)
+			(void)getreply(0);
+		code = -1;
+		goto cleanupsend;
+	}
+	(void)xsignal(SIGQUIT, psummary);
+	oldintr = xsignal(SIGINT, abortxfer);
+	if (strcmp(local, "-") == 0) {
+		fin = stdin;
+		progress = 0;
+	} else if (*local == '|') {
+		oldintp = xsignal(SIGPIPE, SIG_IGN);
+		fin = popen(local + 1, "r");
+		if (fin == NULL) {
+			warn("Can't execute `%s'", local + 1);
+			code = -1;
+			goto cleanupsend;
+		}
+		progress = 0;
+		closefunc = pclose;
+	} else {
+		fin = fopen(local, "r");
+		if (fin == NULL) {
+			warn("Can't open `%s'", local);
+			code = -1;
+			goto cleanupsend;
+		}
+		closefunc = fclose;
+		if (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) {
+			fprintf(ttyout, "%s: not a plain file.\n", local);
+			code = -1;
+			goto cleanupsend;
+		}
+		filesize = st.st_size;
+	}
+	if (initconn()) {
+		code = -1;
+		goto cleanupsend;
+	}
+	if (sigsetjmp(xferabort, 1))
+		goto abort;
+
+	if (restart_point &&
+	    (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
+		int rc;
+
+		rc = -1;
+		switch (curtype) {
+		case TYPE_A:
+			rc = fseeko(fin, restart_point, SEEK_SET);
+			break;
+		case TYPE_I:
+		case TYPE_L:
+			rc = lseek(fileno(fin), restart_point, SEEK_SET);
+			break;
+		}
+		if (rc < 0) {
+			warn("Can't seek to restart `%s'", local);
+			goto cleanupsend;
+		}
+		if (command("REST " LLF, (LLT)restart_point) != CONTINUE)
+			goto cleanupsend;
+		lmode = "r+";
+	}
+	if (remote) {
+		if (command("%s %s", cmd, remote) != PRELIM)
+			goto cleanupsend;
+	} else {
+		if (command("%s", cmd) != PRELIM)
+			goto cleanupsend;
+	}
+	dirchange = 1;
+	dout = dataconn(lmode);
+	if (dout == NULL)
+		goto abort;
+
+	if ((size_t)sndbuf_size > bufsize) {
+		if (buf)
+			(void)free(buf);
+		bufsize = sndbuf_size;
+		buf = ftp_malloc(bufsize);
+	}
+
+	progressmeter(-1);
+	oldintp = xsignal(SIGPIPE, SIG_IGN);
+	hash_interval = (hash && (!progress || filesize < 0)) ? mark : 0;
+
+	switch (curtype) {
+
+	case TYPE_I:
+	case TYPE_L:
+		c = copy_bytes(fileno(fin), fileno(dout), buf, bufsize,
+			       rate_put, hash_interval);
+		if (c == 1) {
+			warn("Reading `%s'", local);
+		} else if (c == 2) {
+			if (errno != EPIPE)
+				warn("Writing to network");
+			bytes = -1;
+		}
+		break;
+
+	case TYPE_A:
+		while ((c = getc(fin)) != EOF) {
+			if (c == '\n') {
+				while (hash_interval && bytes >= hashbytes) {
+					(void)putc('#', ttyout);
+					(void)fflush(ttyout);
+					hashbytes += mark;
+				}
+				if (ferror(dout))
+					break;
+				(void)putc('\r', dout);
+				bytes++;
+			}
+			(void)putc(c, dout);
+			bytes++;
+#if 0	/* this violates RFC0959 */
+			if (c == '\r') {
+				(void)putc('\0', dout);
+				bytes++;
+			}
+#endif
+		}
+		if (hash_interval) {
+			if (bytes < hashbytes)
+				(void)putc('#', ttyout);
+			(void)putc('\n', ttyout);
+		}
+		if (ferror(fin))
+			warn("Reading `%s'", local);
+		if (ferror(dout)) {
+			if (errno != EPIPE)
+				warn("Writing to network");
+			bytes = -1;
+		}
+		break;
+	}
+
+	progressmeter(1);
+	if (closefunc != NULL) {
+		(*closefunc)(fin);
+		fin = NULL;
+	}
+	(void)fclose(dout);
+	dout = NULL;
+	(void)getreply(0);
+	if (bytes > 0)
+		ptransfer(0);
+	goto cleanupsend;
+
+ abort:
+	(void)xsignal(SIGINT, oldintr);
+	oldintr = NULL;
+	if (!cpend) {
+		code = -1;
+		goto cleanupsend;
+	}
+	if (data >= 0) {
+		(void)close(data);
+		data = -1;
+	}
+	if (dout) {
+		(void)fclose(dout);
+		dout = NULL;
+	}
+	(void)getreply(0);
+	code = -1;
+	if (bytes > 0)
+		ptransfer(0);
+
+ cleanupsend:
+	if (oldintr)
+		(void)xsignal(SIGINT, oldintr);
+	if (oldintp)
+		(void)xsignal(SIGPIPE, oldintp);
+	if (data >= 0) {
+		(void)close(data);
+		data = -1;
+	}
+	if (closefunc != NULL && fin != NULL)
+		(*closefunc)(fin);
+	if (dout)
+		(void)fclose(dout);
+	progress = oprogress;
+	restart_point = 0;
+	bytes = 0;
+}
+
+void
+recvrequest(const char *cmd, const char *volatile local, const char *remote,
+	    const char *lmode, int printnames, int ignorespecial)
+{
+	FILE *volatile fout;
+	FILE *volatile din;
+	int (*volatile closefunc)(FILE *);
+	sigfunc volatile oldintr;
+	sigfunc volatile oldintp;
+	int c, d;
+	int volatile is_retr;
+	int volatile tcrflag;
+	int volatile bare_lfs;
+	static size_t bufsize;
+	static char *buf;
+	off_t volatile hashbytes;
+	int hash_interval;
+	struct stat st;
+	time_t mtime;
+	struct timeval tval[2];
+	int oprogress;
+	int opreserve;
+
+	fout = NULL;
+	din = NULL;
+	hashbytes = mark;
+	direction = "received";
+	bytes = 0;
+	bare_lfs = 0;
+	filesize = -1;
+	oprogress = progress;
+	opreserve = preserve;
+	is_retr = (strcmp(cmd, "RETR") == 0);
+	if (is_retr && verbose && printnames) {
+		if (ignorespecial || *local != '-')
+			fprintf(ttyout, "local: %s ", local);
+		if (remote)
+			fprintf(ttyout, "remote: %s\n", remote);
+	}
+	if (proxy && is_retr) {
+		proxtrans(cmd, local, remote);
+		return;
+	}
+	closefunc = NULL;
+	oldintr = NULL;
+	oldintp = NULL;
+	tcrflag = !crflag && is_retr;
+	if (sigsetjmp(xferabort, 1)) {
+		while (cpend)
+			(void)getreply(0);
+		code = -1;
+		goto cleanuprecv;
+	}
+	(void)xsignal(SIGQUIT, psummary);
+	oldintr = xsignal(SIGINT, abortxfer);
+	if (ignorespecial || (strcmp(local, "-") && *local != '|')) {
+		if (access(local, W_OK) < 0) {
+			char *dir = strrchr(local, '/');
+
+			if (errno != ENOENT && errno != EACCES) {
+				warn("Can't access `%s'", local);
+				code = -1;
+				goto cleanuprecv;
+			}
+			if (dir != NULL)
+				*dir = 0;
+			d = access(dir == local ? "/" :
+			    dir ? local : ".", W_OK);
+			if (dir != NULL)
+				*dir = '/';
+			if (d < 0) {
+				warn("Can't access `%s'", local);
+				code = -1;
+				goto cleanuprecv;
+			}
+			if (!runique && errno == EACCES &&
+			    chmod(local, (S_IRUSR|S_IWUSR)) < 0) {
+				warn("Can't chmod `%s'", local);
+				code = -1;
+				goto cleanuprecv;
+			}
+			if (runique && errno == EACCES &&
+			   (local = gunique(local)) == NULL) {
+				code = -1;
+				goto cleanuprecv;
+			}
+		}
+		else if (runique && (local = gunique(local)) == NULL) {
+			code = -1;
+			goto cleanuprecv;
+		}
+	}
+	if (!is_retr) {
+		if (curtype != TYPE_A)
+			changetype(TYPE_A, 0);
+	} else {
+		if (curtype != type)
+			changetype(type, 0);
+		filesize = remotesize(remote, 0);
+		if (code == 421 || code == -1)
+			goto cleanuprecv;
+	}
+	if (initconn()) {
+		code = -1;
+		goto cleanuprecv;
+	}
+	if (sigsetjmp(xferabort, 1))
+		goto abort;
+	if (is_retr && restart_point &&
+	    command("REST " LLF, (LLT) restart_point) != CONTINUE)
+		goto cleanuprecv;
+	if (! EMPTYSTRING(remote)) {
+		if (command("%s %s", cmd, remote) != PRELIM)
+			goto cleanuprecv;
+	} else {
+		if (command("%s", cmd) != PRELIM)
+			goto cleanuprecv;
+	}
+	din = dataconn("r");
+	if (din == NULL)
+		goto abort;
+	if (!ignorespecial && strcmp(local, "-") == 0) {
+		fout = stdout;
+		progress = 0;
+		preserve = 0;
+	} else if (!ignorespecial && *local == '|') {
+		oldintp = xsignal(SIGPIPE, SIG_IGN);
+		fout = popen(local + 1, "w");
+		if (fout == NULL) {
+			warn("Can't execute `%s'", local+1);
+			goto abort;
+		}
+		progress = 0;
+		preserve = 0;
+		closefunc = pclose;
+	} else {
+		fout = fopen(local, lmode);
+		if (fout == NULL) {
+			warn("Can't open `%s'", local);
+			goto abort;
+		}
+		closefunc = fclose;
+	}
+
+	if (fstat(fileno(fout), &st) != -1 && !S_ISREG(st.st_mode)) {
+		progress = 0;
+		preserve = 0;
+	}
+	if ((size_t)rcvbuf_size > bufsize) {
+		if (buf)
+			(void)free(buf);
+		bufsize = rcvbuf_size;
+		buf = ftp_malloc(bufsize);
+	}
+
+	progressmeter(-1);
+	hash_interval = (hash && (!progress || filesize < 0)) ? mark : 0;
+
+	switch (curtype) {
+
+	case TYPE_I:
+	case TYPE_L:
+		if (is_retr && restart_point &&
+		    lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
+			warn("Can't seek to restart `%s'", local);
+			goto cleanuprecv;
+		}
+		c = copy_bytes(fileno(din), fileno(fout), buf, bufsize,
+			       rate_get, hash_interval);
+		if (c == 1) {
+			if (errno != EPIPE)
+				warn("Reading from network");
+			bytes = -1;
+		} else if (c == 2) {
+			warn("Writing `%s'", local);
+		}
+		break;
+
+	case TYPE_A:
+		if (is_retr && restart_point) {
+			int ch;
+			off_t i;
+
+			if (fseeko(fout, (off_t)0, SEEK_SET) < 0)
+				goto done;
+			for (i = 0; i++ < restart_point;) {
+				if ((ch = getc(fout)) == EOF)
+					goto done;
+				if (ch == '\n')
+					i++;
+			}
+			if (fseeko(fout, (off_t)0, SEEK_CUR) < 0) {
+ done:
+				warn("Can't seek to restart `%s'", local);
+				goto cleanuprecv;
+			}
+		}
+		while ((c = getc(din)) != EOF) {
+			if (c == '\n')
+				bare_lfs++;
+			while (c == '\r') {
+				while (hash_interval && bytes >= hashbytes) {
+					(void)putc('#', ttyout);
+					(void)fflush(ttyout);
+					hashbytes += mark;
+				}
+				bytes++;
+				if ((c = getc(din)) != '\n' || tcrflag) {
+					if (ferror(fout))
+						goto break2;
+					(void)putc('\r', fout);
+					if (c == '\0') {
+						bytes++;
+						goto contin2;
+					}
+					if (c == EOF)
+						goto contin2;
+				}
+			}
+			(void)putc(c, fout);
+			bytes++;
+	contin2:	;
+		}
+ break2:
+		if (hash_interval) {
+			if (bytes < hashbytes)
+				(void)putc('#', ttyout);
+			(void)putc('\n', ttyout);
+		}
+		if (ferror(din)) {
+			if (errno != EPIPE)
+				warn("Reading from network");
+			bytes = -1;
+		}
+		if (ferror(fout))
+			warn("Writing `%s'", local);
+		break;
+	}
+
+	progressmeter(1);
+	if (closefunc != NULL) {
+		(*closefunc)(fout);
+		fout = NULL;
+	}
+	(void)fclose(din);
+	din = NULL;
+	(void)getreply(0);
+	if (bare_lfs) {
+		fprintf(ttyout,
+		    "WARNING! %d bare linefeeds received in ASCII mode.\n",
+		    bare_lfs);
+		fputs("File may not have transferred correctly.\n", ttyout);
+	}
+	if (bytes >= 0 && is_retr) {
+		if (bytes > 0)
+			ptransfer(0);
+		if (preserve && (closefunc == fclose)) {
+			mtime = remotemodtime(remote, 0);
+			if (mtime != -1) {
+				(void)gettimeofday(&tval[0], NULL);
+				tval[1].tv_sec = mtime;
+				tval[1].tv_usec = 0;
+				if (utimes(local, tval) == -1) {
+					fprintf(ttyout,
+				"Can't change modification time on %s to %s",
+					    local,
+					    rfc2822time(localtime(&mtime)));
+				}
+			}
+		}
+	}
+	goto cleanuprecv;
+
+ abort:
+			/*
+			 * abort using RFC0959 recommended IP,SYNC sequence
+			 */
+	if (! sigsetjmp(xferabort, 1)) {
+			/* this is the first call */
+		(void)xsignal(SIGINT, abort_squared);
+		if (!cpend) {
+			code = -1;
+			goto cleanuprecv;
+		}
+		abort_remote(din);
+	}
+	code = -1;
+	if (bytes > 0)
+		ptransfer(0);
+
+ cleanuprecv:
+	if (oldintr)
+		(void)xsignal(SIGINT, oldintr);
+	if (oldintp)
+		(void)xsignal(SIGPIPE, oldintp);
+	if (data >= 0) {
+		(void)close(data);
+		data = -1;
+	}
+	if (closefunc != NULL && fout != NULL)
+		(*closefunc)(fout);
+	if (din)
+		(void)fclose(din);
+	progress = oprogress;
+	preserve = opreserve;
+	bytes = 0;
+}
+
+/*
+ * Need to start a listen on the data channel before we send the command,
+ * otherwise the server's connect may fail.
+ */
+int
+initconn(void)
+{
+	char *p, *a;
+	int result, tmpno = 0;
+	int on = 1;
+	int error;
+	unsigned int addr[16], port[2];
+	unsigned int af, hal, pal;
+	socklen_t len;
+	const char *pasvcmd = NULL;
+	int overbose;
+
+#ifdef INET6
+#ifndef NO_DEBUG
+	if (myctladdr.su_family == AF_INET6 && ftp_debug &&
+	    (IN6_IS_ADDR_LINKLOCAL(&myctladdr.si_su.su_sin6.sin6_addr) ||
+	     IN6_IS_ADDR_SITELOCAL(&myctladdr.si_su.su_sin6.sin6_addr))) {
+		warnx("Use of scoped addresses can be troublesome");
+	}
+#endif
+#endif
+
+ reinit:
+	if (passivemode) {
+		data_addr = myctladdr;
+		data = socket(data_addr.su_family, SOCK_STREAM, 0);
+		if (data < 0) {
+			warn("Can't create socket for data connection");
+			return (1);
+		}
+		if ((options & SO_DEBUG) &&
+		    setsockopt(data, SOL_SOCKET, SO_DEBUG,
+				(void *)&on, sizeof(on)) == -1) {
+			DWARN("setsockopt %s (ignored)", "SO_DEBUG");
+		}
+		result = COMPLETE + 1;
+		switch (data_addr.su_family) {
+		case AF_INET:
+			if (epsv4 && !epsv4bad) {
+				pasvcmd = "EPSV";
+				overbose = verbose;
+				if (ftp_debug == 0)
+					verbose = -1;
+				result = command("EPSV");
+				verbose = overbose;
+				if (verbose > 0 &&
+				    (result == COMPLETE || !connected))
+					fprintf(ttyout, "%s\n", reply_string);
+				if (!connected)
+					return (1);
+				/*
+				 * this code is to be friendly with broken
+				 * BSDI ftpd
+				 */
+				if (code / 10 == 22 && code != 229) {
+					fputs(
+"wrong server: return code must be 229\n",
+						ttyout);
+					result = COMPLETE + 1;
+				}
+				if (result != COMPLETE) {
+					epsv4bad = 1;
+					DPRINTF("disabling epsv4 for this "
+					    "connection\n");
+				}
+			}
+			if (result != COMPLETE) {
+				pasvcmd = "PASV";
+				result = command("PASV");
+				if (!connected)
+					return (1);
+			}
+			break;
+#ifdef INET6
+		case AF_INET6:
+			if (epsv6 && !epsv6bad) {
+				pasvcmd = "EPSV";
+				overbose = verbose;
+				if (ftp_debug == 0)
+					verbose = -1;
+				result = command("EPSV");
+				verbose = overbose;
+				if (verbose > 0 &&
+				    (result == COMPLETE || !connected))
+					fprintf(ttyout, "%s\n", reply_string);
+				if (!connected)
+					return (1);
+				/*
+				 * this code is to be friendly with
+				 * broken BSDI ftpd
+				 */
+				if (code / 10 == 22 && code != 229) {
+					fputs(
+						"wrong server: return code must be 229\n",
+						ttyout);
+					result = COMPLETE + 1;
+				}
+				if (result != COMPLETE) {
+					epsv6bad = 1;
+					DPRINTF("disabling epsv6 for this "
+					    "connection\n");
+				}
+			}
+			if (result != COMPLETE) {
+				pasvcmd = "LPSV";
+				result = command("LPSV");
+			}
+			if (!connected)
+				return (1);
+			break;
+#endif
+		default:
+			result = COMPLETE + 1;
+			break;
+		}
+		if (result != COMPLETE) {
+			if (activefallback) {
+				(void)close(data);
+				data = -1;
+				passivemode = 0;
+#if 0
+				activefallback = 0;
+#endif
+				goto reinit;
+			}
+			fputs("Passive mode refused.\n", ttyout);
+			goto bad;
+		}
+
+#define	pack2(var, off) \
+	(((var[(off) + 0] & 0xff) << 8) | ((var[(off) + 1] & 0xff) << 0))
+#define	pack4(var, off) \
+	(((var[(off) + 0] & 0xff) << 24) | ((var[(off) + 1] & 0xff) << 16) | \
+	 ((var[(off) + 2] & 0xff) << 8) | ((var[(off) + 3] & 0xff) << 0))
+#define	UC(b)	(((int)b)&0xff)
+
+		/*
+		 * What we've got at this point is a string of comma separated
+		 * one-byte unsigned integer values, separated by commas.
+		 */
+		if (strcmp(pasvcmd, "PASV") == 0) {
+			if (data_addr.su_family != AF_INET) {
+				fputs(
+    "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
+				error = 1;
+				goto bad;
+			}
+			if (code / 10 == 22 && code != 227) {
+				fputs("wrong server: return code must be 227\n",
+					ttyout);
+				error = 1;
+				goto bad;
+			}
+			error = sscanf(pasv, "%u,%u,%u,%u,%u,%u",
+					&addr[0], &addr[1], &addr[2], &addr[3],
+					&port[0], &port[1]);
+			if (error != 6) {
+				fputs(
+"Passive mode address scan failure. Shouldn't happen!\n", ttyout);
+				error = 1;
+				goto bad;
+			}
+			error = 0;
+			memset(&data_addr, 0, sizeof(data_addr));
+			data_addr.su_family = AF_INET;
+			data_addr.su_len = sizeof(struct sockaddr_in);
+			data_addr.si_su.su_sin.sin_addr.s_addr =
+			    htonl(pack4(addr, 0));
+			data_addr.su_port = htons(pack2(port, 0));
+		} else if (strcmp(pasvcmd, "LPSV") == 0) {
+			if (code / 10 == 22 && code != 228) {
+				fputs("wrong server: return code must be 228\n",
+					ttyout);
+				error = 1;
+				goto bad;
+			}
+			switch (data_addr.su_family) {
+			case AF_INET:
+				error = sscanf(pasv,
+"%u,%u,%u,%u,%u,%u,%u,%u,%u",
+					&af, &hal,
+					&addr[0], &addr[1], &addr[2], &addr[3],
+					&pal, &port[0], &port[1]);
+				if (error != 9) {
+					fputs(
+"Passive mode address scan failure. Shouldn't happen!\n", ttyout);
+					error = 1;
+					goto bad;
+				}
+				if (af != 4 || hal != 4 || pal != 2) {
+					fputs(
+"Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
+					error = 1;
+					goto bad;
+				}
+
+				error = 0;
+				memset(&data_addr, 0, sizeof(data_addr));
+				data_addr.su_family = AF_INET;
+				data_addr.su_len = sizeof(struct sockaddr_in);
+				data_addr.si_su.su_sin.sin_addr.s_addr =
+				    htonl(pack4(addr, 0));
+				data_addr.su_port = htons(pack2(port, 0));
+				break;
+#ifdef INET6
+			case AF_INET6:
+				error = sscanf(pasv,
+"%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
+					&af, &hal,
+					&addr[0], &addr[1], &addr[2], &addr[3],
+					&addr[4], &addr[5], &addr[6], &addr[7],
+					&addr[8], &addr[9], &addr[10],
+					&addr[11], &addr[12], &addr[13],
+					&addr[14], &addr[15],
+					&pal, &port[0], &port[1]);
+				if (error != 21) {
+					fputs(
+"Passive mode address scan failure. Shouldn't happen!\n", ttyout);
+					error = 1;
+					goto bad;
+				}
+				if (af != 6 || hal != 16 || pal != 2) {
+					fputs(
+"Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
+					error = 1;
+					goto bad;
+				}
+
+				error = 0;
+				memset(&data_addr, 0, sizeof(data_addr));
+				data_addr.su_family = AF_INET6;
+				data_addr.su_len = sizeof(struct sockaddr_in6);
+			    {
+				size_t i;
+				for (i = 0; i < sizeof(struct in6_addr); i++) {
+					data_addr.si_su.su_sin6.sin6_addr.s6_addr[i] =
+					    UC(addr[i]);
+				}
+			    }
+				data_addr.su_port = htons(pack2(port, 0));
+				break;
+#endif
+			default:
+				error = 1;
+			}
+		} else if (strcmp(pasvcmd, "EPSV") == 0) {
+			char delim[4];
+
+			port[0] = 0;
+			if (code / 10 == 22 && code != 229) {
+				fputs("wrong server: return code must be 229\n",
+					ttyout);
+				error = 1;
+				goto bad;
+			}
+			if (sscanf(pasv, "%c%c%c%d%c", &delim[0],
+					&delim[1], &delim[2], &port[1],
+					&delim[3]) != 5) {
+				fputs("parse error!\n", ttyout);
+				error = 1;
+				goto bad;
+			}
+			if (delim[0] != delim[1] || delim[0] != delim[2]
+			 || delim[0] != delim[3]) {
+				fputs("parse error!\n", ttyout);
+				error = 1;
+				goto bad;
+			}
+			data_addr = hisctladdr;
+			data_addr.su_port = htons(port[1]);
+		} else
+			goto bad;
+
+		if (ftp_connect(data, (struct sockaddr *)&data_addr.si_su,
+		    data_addr.su_len) < 0) {
+			if (activefallback) {
+				(void)close(data);
+				data = -1;
+				passivemode = 0;
+#if 0
+				activefallback = 0;
+#endif
+				goto reinit;
+			}
+			goto bad;
+		}
+#ifdef IPTOS_THROUGHPUT
+		if (data_addr.su_family == AF_INET) {
+			on = IPTOS_THROUGHPUT;
+			if (setsockopt(data, IPPROTO_IP, IP_TOS,
+					(void *)&on, sizeof(on)) == -1) {
+				DWARN("setsockopt %s (ignored)",
+				    "IPTOS_THROUGHPUT");
+			}
+		}
+#endif
+		return (0);
+	}
+
+ noport:
+	data_addr = myctladdr;
+	if (sendport)
+		data_addr.su_port = 0;	/* let system pick one */
+	if (data != -1)
+		(void)close(data);
+	data = socket(data_addr.su_family, SOCK_STREAM, 0);
+	if (data < 0) {
+		warn("Can't create socket for data connection");
+		if (tmpno)
+			sendport = 1;
+		return (1);
+	}
+	if (!sendport)
+		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR,
+				(void *)&on, sizeof(on)) == -1) {
+			warn("Can't set SO_REUSEADDR on data connection");
+			goto bad;
+		}
+	if (bind(data, (struct sockaddr *)&data_addr.si_su,
+	    data_addr.su_len) < 0) {
+		warn("Can't bind for data connection");
+		goto bad;
+	}
+	if ((options & SO_DEBUG) &&
+	    setsockopt(data, SOL_SOCKET, SO_DEBUG,
+			(void *)&on, sizeof(on)) == -1) {
+		DWARN("setsockopt %s (ignored)", "SO_DEBUG");
+	}
+	len = sizeof(data_addr.si_su);
+	memset((char *)&data_addr, 0, sizeof (data_addr));
+	if (getsockname(data, (struct sockaddr *)&data_addr.si_su, &len) == -1) {
+		warn("Can't determine my address of data connection");
+		goto bad;
+	}
+	data_addr.su_len = len;
+	if (ftp_listen(data, 1) < 0)
+		warn("Can't listen to data connection");
+
+	if (sendport) {
+		char hname[NI_MAXHOST], sname[NI_MAXSERV];
+		struct sockinet tmp;
+
+		switch (data_addr.su_family) {
+		case AF_INET:
+			if (!epsv4 || epsv4bad) {
+				result = COMPLETE + 1;
+				break;
+			}
+			/* FALLTHROUGH */
+#ifdef INET6
+		case AF_INET6:
+			if (!epsv6 || epsv6bad) {
+				result = COMPLETE + 1;
+				break;
+			}
+#endif
+			af = (data_addr.su_family == AF_INET) ? 1 : 2;
+			tmp = data_addr;
+#ifdef INET6
+			if (tmp.su_family == AF_INET6)
+				tmp.si_su.su_sin6.sin6_scope_id = 0;
+#endif
+			if (getnameinfo((struct sockaddr *)&tmp.si_su,
+			    tmp.su_len, hname, sizeof(hname), sname,
+			    sizeof(sname), NI_NUMERICHOST | NI_NUMERICSERV)) {
+				result = ERROR;
+			} else {
+				overbose = verbose;
+				if (ftp_debug == 0)
+					verbose = -1;
+				result = command("EPRT |%u|%s|%s|", af, hname,
+				    sname);
+				verbose = overbose;
+				if (verbose > 0 &&
+				    (result == COMPLETE || !connected))
+					fprintf(ttyout, "%s\n", reply_string);
+				if (!connected)
+					return (1);
+				if (result != COMPLETE) {
+					epsv4bad = 1;
+					DPRINTF("disabling epsv4 for this "
+					    "connection\n");
+				}
+			}
+			break;
+		default:
+			result = COMPLETE + 1;
+			break;
+		}
+		if (result == COMPLETE)
+			goto skip_port;
+
+		switch (data_addr.su_family) {
+		case AF_INET:
+			a = (char *)&data_addr.si_su.su_sin.sin_addr;
+			p = (char *)&data_addr.su_port;
+			result = command("PORT %d,%d,%d,%d,%d,%d",
+				 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
+				 UC(p[0]), UC(p[1]));
+			break;
+#ifdef INET6
+		case AF_INET6:
+			a = (char *)&data_addr.si_su.su_sin6.sin6_addr;
+			p = (char *)&data_addr.su_port;
+			result = command(
+	"LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+				 6, 16,
+				 UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
+				 UC(a[4]),UC(a[5]),UC(a[6]),UC(a[7]),
+				 UC(a[8]),UC(a[9]),UC(a[10]),UC(a[11]),
+				 UC(a[12]),UC(a[13]),UC(a[14]),UC(a[15]),
+				 2, UC(p[0]), UC(p[1]));
+			break;
+#endif
+		default:
+			result = COMPLETE + 1; /* xxx */
+		}
+		if (!connected)
+			return (1);
+	skip_port:
+
+		if (result == ERROR && sendport == -1) {
+			sendport = 0;
+			tmpno = 1;
+			goto noport;
+		}
+		return (result != COMPLETE);
+	}
+	if (tmpno)
+		sendport = 1;
+#ifdef IPTOS_THROUGHPUT
+	if (data_addr.su_family == AF_INET) {
+		on = IPTOS_THROUGHPUT;
+		if (setsockopt(data, IPPROTO_IP, IP_TOS,
+				(void *)&on, sizeof(on)) == -1) {
+			DWARN("setsockopt %s (ignored)", "IPTOS_THROUGHPUT");
+		}
+	}
+#endif
+	return (0);
+ bad:
+	(void)close(data);
+	data = -1;
+	if (tmpno)
+		sendport = 1;
+	return (1);
+}
+
+FILE *
+dataconn(const char *lmode)
+{
+	struct sockinet	from;
+	int		s, flags, rv, timeout;
+	struct timeval	endtime, now, td;
+	struct pollfd	pfd[1];
+	socklen_t	fromlen;
+
+	if (passivemode)	/* passive data connection */
+		return (fdopen(data, lmode));
+
+				/* active mode data connection */
+
+	if ((flags = fcntl(data, F_GETFL, 0)) == -1)
+		goto dataconn_failed;		/* get current socket flags  */
+	if (fcntl(data, F_SETFL, flags | O_NONBLOCK) == -1)
+		goto dataconn_failed;		/* set non-blocking connect */
+
+		/* NOTE: we now must restore socket flags on successful exit */
+
+				/* limit time waiting on listening socket */
+	pfd[0].fd = data;
+	pfd[0].events = POLLIN;
+	(void)gettimeofday(&endtime, NULL);	/* determine end time */
+	endtime.tv_sec += (quit_time > 0) ? quit_time: 60;
+						/* without -q, default to 60s */
+	do {
+		(void)gettimeofday(&now, NULL);
+		timersub(&endtime, &now, &td);
+		timeout = td.tv_sec * 1000 + td.tv_usec/1000;
+		if (timeout < 0)
+			timeout = 0;
+		rv = ftp_poll(pfd, 1, timeout);
+	} while (rv == -1 && errno == EINTR);	/* loop until poll ! EINTR */
+	if (rv == -1) {
+		warn("Can't poll waiting before accept");
+		goto dataconn_failed;
+	}
+	if (rv == 0) {
+		warnx("Poll timeout waiting before accept");
+		goto dataconn_failed;
+	}
+
+				/* (non-blocking) accept the connection */
+	fromlen = myctladdr.su_len;
+	do {
+		s = accept(data, (struct sockaddr *) &from.si_su, &fromlen);
+	} while (s == -1 && errno == EINTR);	/* loop until accept ! EINTR */
+	if (s == -1) {
+		warn("Can't accept data connection");
+		goto dataconn_failed;
+	}
+
+	(void)close(data);
+	data = s;
+	if (fcntl(data, F_SETFL, flags) == -1)	/* restore socket flags */
+		goto dataconn_failed;
+
+#ifdef IPTOS_THROUGHPUT
+	if (from.su_family == AF_INET) {
+		int tos = IPTOS_THROUGHPUT;
+		if (setsockopt(s, IPPROTO_IP, IP_TOS,
+				(void *)&tos, sizeof(tos)) == -1) {
+			DWARN("setsockopt %s (ignored)", "IPTOS_THROUGHPUT");
+		}
+	}
+#endif
+	return (fdopen(data, lmode));
+
+ dataconn_failed:
+	(void)close(data);
+	data = -1;
+	return (NULL);
+}
+
+void
+psabort(int notused)
+{
+	int oerrno = errno;
+
+	sigint_raised = 1;
+	alarmtimer(0);
+	abrtflag++;
+	errno = oerrno;
+}
+
+void
+pswitch(int flag)
+{
+	sigfunc oldintr;
+	static struct comvars {
+		int connect;
+		char name[MAXHOSTNAMELEN];
+		struct sockinet mctl;
+		struct sockinet hctl;
+		FILE *in;
+		FILE *out;
+		int tpe;
+		int curtpe;
+		int cpnd;
+		int sunqe;
+		int runqe;
+		int mcse;
+		int ntflg;
+		char nti[17];
+		char nto[17];
+		int mapflg;
+		char mi[MAXPATHLEN];
+		char mo[MAXPATHLEN];
+	} proxstruct, tmpstruct;
+	struct comvars *ip, *op;
+
+	abrtflag = 0;
+	oldintr = xsignal(SIGINT, psabort);
+	if (flag) {
+		if (proxy)
+			return;
+		ip = &tmpstruct;
+		op = &proxstruct;
+		proxy++;
+	} else {
+		if (!proxy)
+			return;
+		ip = &proxstruct;
+		op = &tmpstruct;
+		proxy = 0;
+	}
+	ip->connect = connected;
+	connected = op->connect;
+	if (hostname)
+		(void)strlcpy(ip->name, hostname, sizeof(ip->name));
+	else
+		ip->name[0] = '\0';
+	hostname = op->name;
+	ip->hctl = hisctladdr;
+	hisctladdr = op->hctl;
+	ip->mctl = myctladdr;
+	myctladdr = op->mctl;
+	ip->in = cin;
+	cin = op->in;
+	ip->out = cout;
+	cout = op->out;
+	ip->tpe = type;
+	type = op->tpe;
+	ip->curtpe = curtype;
+	curtype = op->curtpe;
+	ip->cpnd = cpend;
+	cpend = op->cpnd;
+	ip->sunqe = sunique;
+	sunique = op->sunqe;
+	ip->runqe = runique;
+	runique = op->runqe;
+	ip->mcse = mcase;
+	mcase = op->mcse;
+	ip->ntflg = ntflag;
+	ntflag = op->ntflg;
+	(void)strlcpy(ip->nti, ntin, sizeof(ip->nti));
+	(void)strlcpy(ntin, op->nti, sizeof(ntin));
+	(void)strlcpy(ip->nto, ntout, sizeof(ip->nto));
+	(void)strlcpy(ntout, op->nto, sizeof(ntout));
+	ip->mapflg = mapflag;
+	mapflag = op->mapflg;
+	(void)strlcpy(ip->mi, mapin, sizeof(ip->mi));
+	(void)strlcpy(mapin, op->mi, sizeof(mapin));
+	(void)strlcpy(ip->mo, mapout, sizeof(ip->mo));
+	(void)strlcpy(mapout, op->mo, sizeof(mapout));
+	(void)xsignal(SIGINT, oldintr);
+	if (abrtflag) {
+		abrtflag = 0;
+		(*oldintr)(SIGINT);
+	}
+}
+
+void
+abortpt(int notused)
+{
+
+	sigint_raised = 1;
+	alarmtimer(0);
+	if (fromatty)
+		write(fileno(ttyout), "\n", 1);
+	ptabflg++;
+	mflag = 0;
+	abrtflag = 0;
+	siglongjmp(ptabort, 1);
+}
+
+void
+proxtrans(const char *cmd, const char *local, const char *remote)
+{
+	sigfunc volatile oldintr;
+	int prox_type, nfnd;
+	int volatile secndflag;
+	const char *volatile cmd2;
+
+	oldintr = NULL;
+	secndflag = 0;
+	if (strcmp(cmd, "RETR"))
+		cmd2 = "RETR";
+	else
+		cmd2 = runique ? "STOU" : "STOR";
+	if ((prox_type = type) == 0) {
+		if (unix_server && unix_proxy)
+			prox_type = TYPE_I;
+		else
+			prox_type = TYPE_A;
+	}
+	if (curtype != prox_type)
+		changetype(prox_type, 1);
+	if (command("PASV") != COMPLETE) {
+		fputs("proxy server does not support third party transfers.\n",
+		    ttyout);
+		return;
+	}
+	pswitch(0);
+	if (!connected) {
+		fputs("No primary connection.\n", ttyout);
+		pswitch(1);
+		code = -1;
+		return;
+	}
+	if (curtype != prox_type)
+		changetype(prox_type, 1);
+	if (command("PORT %s", pasv) != COMPLETE) {
+		pswitch(1);
+		return;
+	}
+	if (sigsetjmp(ptabort, 1))
+		goto abort;
+	oldintr = xsignal(SIGINT, abortpt);
+	if ((restart_point &&
+	    (command("REST " LLF, (LLT) restart_point) != CONTINUE))
+	    || (command("%s %s", cmd, remote) != PRELIM)) {
+		(void)xsignal(SIGINT, oldintr);
+		pswitch(1);
+		return;
+	}
+	sleep(2);
+	pswitch(1);
+	secndflag++;
+	if ((restart_point &&
+	    (command("REST " LLF, (LLT) restart_point) != CONTINUE))
+	    || (command("%s %s", cmd2, local) != PRELIM))
+		goto abort;
+	ptflag++;
+	(void)getreply(0);
+	pswitch(0);
+	(void)getreply(0);
+	(void)xsignal(SIGINT, oldintr);
+	pswitch(1);
+	ptflag = 0;
+	fprintf(ttyout, "local: %s remote: %s\n", local, remote);
+	return;
+ abort:
+	if (sigsetjmp(xferabort, 1)) {
+		(void)xsignal(SIGINT, oldintr);
+		return;
+	}
+	(void)xsignal(SIGINT, abort_squared);
+	ptflag = 0;
+	if (strcmp(cmd, "RETR") && !proxy)
+		pswitch(1);
+	else if (!strcmp(cmd, "RETR") && proxy)
+		pswitch(0);
+	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
+		if (command("%s %s", cmd2, local) != PRELIM) {
+			pswitch(0);
+			if (cpend)
+				abort_remote(NULL);
+		}
+		pswitch(1);
+		if (ptabflg)
+			code = -1;
+		(void)xsignal(SIGINT, oldintr);
+		return;
+	}
+	if (cpend)
+		abort_remote(NULL);
+	pswitch(!proxy);
+	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
+		if (command("%s %s", cmd2, local) != PRELIM) {
+			pswitch(0);
+			if (cpend)
+				abort_remote(NULL);
+			pswitch(1);
+			if (ptabflg)
+				code = -1;
+			(void)xsignal(SIGINT, oldintr);
+			return;
+		}
+	}
+	if (cpend)
+		abort_remote(NULL);
+	pswitch(!proxy);
+	if (cpend) {
+		if ((nfnd = empty(cin, NULL, 10)) <= 0) {
+			if (nfnd < 0)
+				warn("Error aborting proxy command");
+			if (ptabflg)
+				code = -1;
+			lostpeer(0);
+		}
+		(void)getreply(0);
+		(void)getreply(0);
+	}
+	if (proxy)
+		pswitch(0);
+	pswitch(1);
+	if (ptabflg)
+		code = -1;
+	(void)xsignal(SIGINT, oldintr);
+}
+
+void
+reset(int argc, char *argv[])
+{
+	int nfnd = 1;
+
+	if (argc == 0 && argv != NULL) {
+		UPRINTF("usage: %s\n", argv[0]);
+		code = -1;
+		return;
+	}
+	while (nfnd > 0) {
+		if ((nfnd = empty(cin, NULL, 0)) < 0) {
+			warn("Error resetting connection");
+			code = -1;
+			lostpeer(0);
+		} else if (nfnd)
+			(void)getreply(0);
+	}
+}
+
+char *
+gunique(const char *local)
+{
+	static char new[MAXPATHLEN];
+	char *cp = strrchr(local, '/');
+	int d, count=0, len;
+	char ext = '1';
+
+	if (cp)
+		*cp = '\0';
+	d = access(cp == local ? "/" : cp ? local : ".", W_OK);
+	if (cp)
+		*cp = '/';
+	if (d < 0) {
+		warn("Can't access `%s'", local);
+		return (NULL);
+	}
+	len = strlcpy(new, local, sizeof(new));
+	cp = &new[len];
+	*cp++ = '.';
+	while (!d) {
+		if (++count == 100) {
+			fputs("runique: can't find unique file name.\n",
+			    ttyout);
+			return (NULL);
+		}
+		*cp++ = ext;
+		*cp = '\0';
+		if (ext == '9')
+			ext = '0';
+		else
+			ext++;
+		if ((d = access(new, F_OK)) < 0)
+			break;
+		if (ext != '0')
+			cp--;
+		else if (*(cp - 2) == '.')
+			*(cp - 1) = '1';
+		else {
+			*(cp - 2) = *(cp - 2) + 1;
+			cp--;
+		}
+	}
+	return (new);
+}
+
+/*
+ * abort_squared --
+ *	aborts abort_remote(). lostpeer() is called because if the user is
+ *	too impatient to wait or there's another problem then ftp really
+ *	needs to get back to a known state.
+ */
+void
+abort_squared(int dummy)
+{
+	char msgbuf[100];
+	size_t len;
+
+	sigint_raised = 1;
+	alarmtimer(0);
+	len = strlcpy(msgbuf, "\nremote abort aborted; closing connection.\n",
+	    sizeof(msgbuf));
+	write(fileno(ttyout), msgbuf, len);
+	lostpeer(0);
+	siglongjmp(xferabort, 1);
+}
+
+void
+abort_remote(FILE *din)
+{
+	char buf[BUFSIZ];
+	int nfnd;
+
+	if (cout == NULL) {
+		warnx("Lost control connection for abort");
+		if (ptabflg)
+			code = -1;
+		lostpeer(0);
+		return;
+	}
+	/*
+	 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
+	 * after urgent byte rather than before as is protocol now
+	 */
+	buf[0] = IAC;
+	buf[1] = IP;
+	buf[2] = IAC;
+	if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
+		warn("Can't send abort message");
+	fprintf(cout, "%cABOR\r\n", DM);
+	(void)fflush(cout);
+	if ((nfnd = empty(cin, din, 10)) <= 0) {
+		if (nfnd < 0)
+			warn("Can't send abort message");
+		if (ptabflg)
+			code = -1;
+		lostpeer(0);
+	}
+	if (din && (nfnd & 2)) {
+		while (read(fileno(din), buf, BUFSIZ) > 0)
+			continue;
+	}
+	if (getreply(0) == ERROR && code == 552) {
+		/* 552 needed for nic style abort */
+		(void)getreply(0);
+	}
+	(void)getreply(0);
+}
+
+/*
+ * Ensure that ai->ai_addr is NOT an IPv4 mapped address.
+ * IPv4 mapped address complicates too many things in FTP
+ * protocol handling, as FTP protocol is defined differently
+ * between IPv4 and IPv6.
+ *
+ * This may not be the best way to handle this situation,
+ * since the semantics of IPv4 mapped address is defined in
+ * the kernel.  There are configurations where we should use
+ * IPv4 mapped address as native IPv6 address, not as
+ * "an IPv6 address that embeds IPv4 address" (namely, SIIT).
+ *
+ * More complete solution would be to have an additional
+ * getsockopt to grab "real" peername/sockname.  "real"
+ * peername/sockname will be AF_INET if IPv4 mapped address
+ * is used to embed IPv4 address, and will be AF_INET6 if
+ * we use it as native.  What a mess!
+ */
+void
+ai_unmapped(struct addrinfo *ai)
+{
+#ifdef INET6
+	struct sockaddr_in6 *sin6;
+	struct sockaddr_in sin;
+	socklen_t len;
+
+	if (ai->ai_family != AF_INET6)
+		return;
+	if (ai->ai_addrlen != sizeof(struct sockaddr_in6) ||
+	    sizeof(sin) > ai->ai_addrlen)
+		return;
+	sin6 = (struct sockaddr_in6 *)ai->ai_addr;
+	if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
+		return;
+
+	memset(&sin, 0, sizeof(sin));
+	sin.sin_family = AF_INET;
+	len = sizeof(struct sockaddr_in);
+	memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
+	    sizeof(sin.sin_addr));
+	sin.sin_port = sin6->sin6_port;
+
+	ai->ai_family = AF_INET;
+#if defined(HAVE_STRUCT_SOCKADDR_IN_SIN_LEN)
+	sin.sin_len = len;
+#endif
+	memcpy(ai->ai_addr, &sin, len);
+	ai->ai_addrlen = len;
+#endif
+}
+
+#ifdef NO_USAGE
+void
+xusage(void)
+{
+	fputs("Usage error\n", ttyout);
+}
+#endif

Added: vendor/NetBSD/tnftp/20100108/src/ftp_var.h
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/ftp_var.h	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/ftp_var.h	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,355 @@
+/*	$NetBSD: ftp_var.h,v 1.10 2009/05/20 12:53:47 lukem Exp $	*/
+/*	from	NetBSD: ftp_var.h,v 1.81 2009/04/12 10:18:52 lukem Exp	*/
+
+/*-
+ * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1985, 1989, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)ftp_var.h	8.4 (Berkeley) 10/9/94
+ */
+
+/*
+ * Copyright (C) 1997 and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * FTP global variables.
+ */
+
+#ifdef SMALL
+#undef	NO_EDITCOMPLETE
+#define	NO_EDITCOMPLETE
+#undef	NO_PROGRESS
+#define	NO_PROGRESS
+#endif
+
+#if 0	/* tnftp */
+
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <poll.h>
+
+#include <setjmp.h>
+#include <stringlist.h>
+
+#endif	/* tnftp */
+
+#ifndef NO_EDITCOMPLETE
+#include <histedit.h>
+#endif /* !NO_EDITCOMPLETE */
+
+#include "extern.h"
+#include "progressbar.h"
+
+/*
+ * Format of command table.
+ */
+struct cmd {
+	const char	*c_name;	/* name of command */
+	const char	*c_help;	/* help string */
+	char		c_bell;		/* give bell when command completes */
+	char		c_conn;		/* must be connected to use command */
+	char		c_proxy;	/* proxy server may execute */
+#ifndef NO_EDITCOMPLETE
+	const char	*c_complete;	/* context sensitive completion list */
+#endif /* !NO_EDITCOMPLETE */
+	void		(*c_handler)(int, char **); /* function to call */
+};
+
+#define MAX_C_NAME	12		/* maximum length of cmd.c_name */
+
+/*
+ * Format of macro table
+ */
+struct macel {
+	char	 mac_name[9];	/* macro name */
+	char	*mac_start;	/* start of macro in macbuf */
+	char	*mac_end;	/* end of macro in macbuf */
+};
+
+/*
+ * Format of option table
+ */
+struct option {
+	const char	*name;
+	char		*value;
+};
+
+/*
+ * Indices to features[]; an array containing status of remote server
+ * features; -1 not known (FEAT failed), 0 absent, 1 present.
+ */
+enum {
+	FEAT_FEAT = 0,		/* FEAT, OPTS */
+	FEAT_MDTM,		/* MDTM */
+	FEAT_MLST,		/* MLSD, MLST */
+	FEAT_REST_STREAM,	/* RESTart STREAM */
+	FEAT_SIZE,		/* SIZE */
+	FEAT_TVFS,		/* TVFS (not used) */
+	FEAT_max
+};
+
+
+/*
+ * Global defines
+ */
+#define	FTPBUFLEN	MAXPATHLEN + 200
+#define	MAX_IN_PORT_T	0xffffU
+
+#define	HASHBYTES	1024	/* default mark for `hash' command */
+#define	DEFAULTINCR	1024	/* default increment for `rate' command */
+
+#define	FTP_PORT	21	/* default if ! getservbyname("ftp/tcp") */
+#define	HTTP_PORT	80	/* default if ! getservbyname("http/tcp") */
+#ifndef	GATE_PORT
+#define	GATE_PORT	21	/* default if ! getservbyname("ftpgate/tcp") */
+#endif
+#ifndef	GATE_SERVER
+#define	GATE_SERVER	""	/* default server */
+#endif
+
+#define	DEFAULTPAGER	"more"	/* default pager if $PAGER isn't set */
+#define	DEFAULTPROMPT	"ftp> "	/* default prompt  if `set prompt' is empty */
+#define	DEFAULTRPROMPT	""	/* default rprompt if `set rprompt' is empty */
+
+#define	TMPFILE		"ftpXXXXXXXXXX"
+
+
+#ifndef	GLOBAL
+#define	GLOBAL	extern
+#endif
+
+/*
+ * Options and other state info.
+ */
+GLOBAL	int	trace;		/* trace packets exchanged */
+GLOBAL	int	hash;		/* print # for each buffer transferred */
+GLOBAL	int	mark;		/* number of bytes between hashes */
+GLOBAL	int	sendport;	/* use PORT/LPRT cmd for each data connection */
+GLOBAL	int	connected;	/* 1 = connected to server, -1 = logged in */
+GLOBAL	int	interactive;	/* interactively prompt on m* cmds */
+GLOBAL	int	confirmrest;	/* confirm rest of current m* cmd */
+GLOBAL	int	ftp_debug;	/* debugging level */
+GLOBAL	int	bell;		/* ring bell on cmd completion */
+GLOBAL	int	doglob;		/* glob local file names */
+GLOBAL	int	autologin;	/* establish user account on connection */
+GLOBAL	int	proxy;		/* proxy server connection active */
+GLOBAL	int	proxflag;	/* proxy connection exists */
+GLOBAL	int	gatemode;	/* use gate-ftp */
+GLOBAL	const char *gateserver;	/* server to use for gate-ftp */
+GLOBAL	int	sunique;	/* store files on server with unique name */
+GLOBAL	int	runique;	/* store local files with unique name */
+GLOBAL	int	mcase;		/* map upper to lower case for mget names */
+GLOBAL	int	ntflag;		/* use ntin ntout tables for name translation */
+GLOBAL	int	mapflag;	/* use mapin mapout templates on file names */
+GLOBAL	int	preserve;	/* preserve modification time on files */
+GLOBAL	int	code;		/* return/reply code for ftp command */
+GLOBAL	int	crflag;		/* if 1, strip car. rets. on ascii gets */
+GLOBAL	int	passivemode;	/* passive mode enabled */
+GLOBAL	int	activefallback;	/* fall back to active mode if passive fails */
+GLOBAL	char   *altarg;		/* argv[1] with no shell-like preprocessing  */
+GLOBAL	char	ntin[17];	/* input translation table */
+GLOBAL	char	ntout[17];	/* output translation table */
+GLOBAL	char	mapin[MAXPATHLEN]; /* input map template */
+GLOBAL	char	mapout[MAXPATHLEN]; /* output map template */
+GLOBAL	char	typename[32];	/* name of file transfer type */
+GLOBAL	int	type;		/* requested file transfer type */
+GLOBAL	int	curtype;	/* current file transfer type */
+GLOBAL	char	structname[32];	/* name of file transfer structure */
+GLOBAL	int	stru;		/* file transfer structure */
+GLOBAL	char	formname[32];	/* name of file transfer format */
+GLOBAL	int	form;		/* file transfer format */
+GLOBAL	char	modename[32];	/* name of file transfer mode */
+GLOBAL	int	mode;		/* file transfer mode */
+GLOBAL	char	bytename[32];	/* local byte size in ascii */
+GLOBAL	int	bytesize;	/* local byte size in binary */
+GLOBAL	int	anonftp;	/* automatic anonymous login */
+GLOBAL	int	dirchange;	/* remote directory changed by cd command */
+GLOBAL	int	flushcache;	/* set HTTP cache flush headers with request */
+GLOBAL	int	rate_get;	/* maximum get xfer rate */
+GLOBAL	int	rate_get_incr;	/* increment for get xfer rate */
+GLOBAL	int	rate_put;	/* maximum put xfer rate */
+GLOBAL	int	rate_put_incr;	/* increment for put xfer rate */
+GLOBAL	int	retry_connect;	/* seconds between retrying connection */
+GLOBAL	const char *tmpdir;	/* temporary directory */
+GLOBAL	int	epsv4;		/* use EPSV/EPRT on IPv4 connections */
+GLOBAL	int	epsv4bad;	/* EPSV doesn't work on the current server */
+GLOBAL	int	epsv6;		/* use EPSV/EPRT on IPv6 connections */
+GLOBAL	int	epsv6bad;	/* EPSV doesn't work on the current server */
+GLOBAL	int	editing;	/* command line editing enabled */
+GLOBAL	int	features[FEAT_max];	/* remote FEATures supported */
+
+#ifndef NO_EDITCOMPLETE
+GLOBAL	EditLine *el;		/* editline(3) status structure */
+GLOBAL	History  *hist;		/* editline(3) history structure */
+GLOBAL	char	 *cursor_pos;	/* cursor position we're looking for */
+GLOBAL	size_t	  cursor_argc;	/* location of cursor in margv */
+GLOBAL	size_t	  cursor_argo;	/* offset of cursor in margv[cursor_argc] */
+#endif /* !NO_EDITCOMPLETE */
+
+GLOBAL	char   *hostname;	/* name of host connected to */
+GLOBAL	int	unix_server;	/* server is unix, can use binary for ascii */
+GLOBAL	int	unix_proxy;	/* proxy is unix, can use binary for ascii */
+GLOBAL	char	localcwd[MAXPATHLEN];	/* local dir */
+GLOBAL	char	remotecwd[MAXPATHLEN];	/* remote dir */
+GLOBAL	char   *username;	/* name of user logged in as. (dynamic) */
+
+GLOBAL	sa_family_t family;	/* address family to use for connections */
+GLOBAL	const char *ftpport;	/* port number to use for FTP connections */
+GLOBAL	const char *httpport;	/* port number to use for HTTP connections */
+GLOBAL	const char *gateport;	/* port number to use for gateftp connections */
+GLOBAL	struct addrinfo *bindai; /* local address to bind as */
+
+GLOBAL	char   *outfile;	/* filename to output URLs to */
+GLOBAL	int	restartautofetch; /* restart auto-fetch */
+
+GLOBAL	char	line[FTPBUFLEN]; /* input line buffer */
+GLOBAL	char	*stringbase;	/* current scan point in line buffer */
+GLOBAL	char	argbuf[FTPBUFLEN]; /* argument storage buffer */
+GLOBAL	char	*argbase;	/* current storage point in arg buffer */
+GLOBAL	StringList *marg_sl;	/* stringlist containing margv */
+GLOBAL	int	margc;		/* count of arguments on input line */
+#define	margv (marg_sl->sl_str)	/* args parsed from input line */
+GLOBAL	int     cpend;		/* flag: if != 0, then pending server reply */
+GLOBAL	int	mflag;		/* flag: if != 0, then active multi command */
+
+GLOBAL	int	options;	/* used during socket creation */
+
+GLOBAL	int	sndbuf_size;	/* socket send buffer size */
+GLOBAL	int	rcvbuf_size;	/* socket receive buffer size */
+
+GLOBAL	int	macnum;		/* number of defined macros */
+GLOBAL	struct macel macros[16];
+GLOBAL	char	macbuf[4096];
+
+GLOBAL	char	*localhome;		/* local home directory */
+GLOBAL	char	*localname;		/* local user name */
+GLOBAL	char	 netrc[MAXPATHLEN];	/* path to .netrc file */
+GLOBAL	char	 reply_string[BUFSIZ];	/* first line of previous reply */
+GLOBAL	void	(*reply_callback)(const char *);
+					/*
+					 * function to call for each line in
+					 * the server's reply except for the
+					 * first (`xxx-') and last (`xxx ')
+					 */
+
+GLOBAL	volatile sig_atomic_t	sigint_raised;
+
+GLOBAL	FILE	*cin;
+GLOBAL	FILE	*cout;
+GLOBAL	int	 data;
+
+extern	struct cmd	cmdtab[];
+extern	struct option	optiontab[];
+
+
+#define	EMPTYSTRING(x)	((x) == NULL || (*(x) == '\0'))
+#define	FREEPTR(x)	if ((x) != NULL) { free(x); (x) = NULL; }
+
+#ifdef BSD4_4
+# define HAVE_STRUCT_SOCKADDR_IN_SIN_LEN	1
+#endif
+
+#ifdef NO_LONG_LONG
+# define STRTOLL(x,y,z)	strtol(x,y,z)
+#else
+# define STRTOLL(x,y,z)	strtoll(x,y,z)
+#endif
+
+#ifdef NO_DEBUG
+#define DPRINTF(...)
+#define DWARN(...)
+#else
+#define DPRINTF(...)	if (ftp_debug) (void)fprintf(ttyout, __VA_ARGS__)
+#define DWARN(...)	if (ftp_debug) warn(__VA_ARGS__)
+#endif
+
+#define STRorNULL(s)	((s) ? (s) : "<null>")
+
+#ifdef NO_USAGE
+void xusage(void);
+#define UPRINTF(...)	xusage()
+#else
+#define UPRINTF(...)	(void)fprintf(ttyout, __VA_ARGS__)
+#endif

Added: vendor/NetBSD/tnftp/20100108/src/main.c
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/main.c	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/main.c	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,1058 @@
+/*	$NetBSD: main.c,v 1.17 2009/11/15 10:12:37 lukem Exp $	*/
+/*	from	NetBSD: main.c,v 1.117 2009/07/13 19:05:41 roy Exp	*/
+
+/*-
+ * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1985, 1989, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (C) 1997 and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "tnftp.h"
+
+#if 0	/* tnftp */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1985, 1989, 1993, 1994\
+ The Regents of the University of California.  All rights reserved.\
+  Copyright 1996-2008 The NetBSD Foundation, Inc.  All rights reserved");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)main.c	8.6 (Berkeley) 10/9/94";
+#else
+__RCSID(" NetBSD: main.c,v 1.117 2009/07/13 19:05:41 roy Exp  ");
+#endif
+#endif /* not lint */
+
+/*
+ * FTP User Program -- Command Interface.
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <locale.h>
+
+#endif	/* tnftp */
+
+#define	GLOBAL		/* force GLOBAL decls in ftp_var.h to be declared */
+#include "ftp_var.h"
+
+#define	FTP_PROXY	"ftp_proxy"	/* env var with FTP proxy location */
+#define	HTTP_PROXY	"http_proxy"	/* env var with HTTP proxy location */
+#define	NO_PROXY	"no_proxy"	/* env var with list of non-proxied
+					 * hosts, comma or space separated */
+
+static void	setupoption(const char *, const char *, const char *);
+int		main(int, char *[]);
+
+int
+main(int volatile argc, char **volatile argv)
+{
+	int ch, rval;
+	struct passwd *pw;
+	char *cp, *ep, *anonpass, *upload_path, *src_addr;
+	const char *anonuser;
+	int dumbterm, isupload;
+	size_t len;
+
+	tzset();
+#if 0	/* tnftp */	/* XXX */
+	setlocale(LC_ALL, "");
+#endif	/* tnftp */
+	setprogname(argv[0]);
+
+	sigint_raised = 0;
+
+	ftpport = "ftp";
+	httpport = "http";
+	gateport = NULL;
+	cp = getenv("FTPSERVERPORT");
+	if (cp != NULL)
+		gateport = cp;
+	else
+		gateport = "ftpgate";
+	doglob = 1;
+	interactive = 1;
+	autologin = 1;
+	passivemode = 1;
+	activefallback = 1;
+	preserve = 1;
+	verbose = 0;
+	progress = 0;
+	gatemode = 0;
+	data = -1;
+	outfile = NULL;
+	restartautofetch = 0;
+#ifndef NO_EDITCOMPLETE
+	editing = 0;
+	el = NULL;
+	hist = NULL;
+#endif
+	bytes = 0;
+	mark = HASHBYTES;
+	rate_get = 0;
+	rate_get_incr = DEFAULTINCR;
+	rate_put = 0;
+	rate_put_incr = DEFAULTINCR;
+#ifdef INET6
+	epsv4 = 1;
+	epsv6 = 1;	
+#else
+	epsv4 = 0;
+	epsv6 = 0;	
+#endif
+	epsv4bad = 0;
+	epsv6bad = 0;
+	src_addr = NULL;
+	upload_path = NULL;
+	isupload = 0;
+	reply_callback = NULL;
+#ifdef INET6
+	family = AF_UNSPEC;
+#else
+	family = AF_INET;	/* force AF_INET if no INET6 support */
+#endif
+
+	netrc[0] = '\0';
+	cp = getenv("NETRC");
+	if (cp != NULL && strlcpy(netrc, cp, sizeof(netrc)) >= sizeof(netrc))
+		errx(1, "$NETRC `%s': %s", cp, strerror(ENAMETOOLONG));
+
+	marg_sl = ftp_sl_init();
+	if ((tmpdir = getenv("TMPDIR")) == NULL)
+		tmpdir = _PATH_TMP;
+
+	/* Set default operation mode based on FTPMODE environment variable */
+	if ((cp = getenv("FTPMODE")) != NULL) {
+		if (strcasecmp(cp, "passive") == 0) {
+			passivemode = 1;
+			activefallback = 0;
+		} else if (strcasecmp(cp, "active") == 0) {
+			passivemode = 0;
+			activefallback = 0;
+		} else if (strcasecmp(cp, "gate") == 0) {
+			gatemode = 1;
+		} else if (strcasecmp(cp, "auto") == 0) {
+			passivemode = 1;
+			activefallback = 1;
+		} else
+			warnx("Unknown $FTPMODE `%s'; using defaults", cp);
+	}
+
+	if (strcmp(getprogname(), "pftp") == 0) {
+		passivemode = 1;
+		activefallback = 0;
+	} else if (strcmp(getprogname(), "gate-ftp") == 0)
+		gatemode = 1;
+
+	gateserver = getenv("FTPSERVER");
+	if (gateserver == NULL || *gateserver == '\0')
+		gateserver = GATE_SERVER;
+	if (gatemode) {
+		if (*gateserver == '\0') {
+			warnx(
+"Neither $FTPSERVER nor GATE_SERVER is defined; disabling gate-ftp");
+			gatemode = 0;
+		}
+	}
+
+	cp = getenv("TERM");
+	if (cp == NULL || strcmp(cp, "dumb") == 0)
+		dumbterm = 1;
+	else
+		dumbterm = 0;
+	fromatty = isatty(fileno(stdin));
+	ttyout = stdout;
+	if (isatty(fileno(ttyout))) {
+		verbose = 1;		/* verbose if to a tty */
+		if (! dumbterm) {
+#ifndef NO_EDITCOMPLETE
+			if (fromatty)	/* editing mode on if tty is usable */
+				editing = 1;
+#endif
+#ifndef NO_PROGRESS
+			if (foregroundproc())
+				progress = 1;	/* progress bar on if fg */
+#endif
+		}
+	}
+
+	while ((ch = getopt(argc, argv, "46AadefginN:o:pP:q:r:Rs:tT:u:vV")) != -1) {
+		switch (ch) {
+		case '4':
+			family = AF_INET;
+			break;
+
+		case '6':
+#ifdef INET6
+			family = AF_INET6;
+#else
+			warnx("INET6 support is not available; ignoring -6");
+#endif
+			break;
+
+		case 'A':
+			activefallback = 0;
+			passivemode = 0;
+			break;
+
+		case 'a':
+			anonftp = 1;
+			break;
+
+		case 'd':
+			options |= SO_DEBUG;
+			ftp_debug++;
+			break;
+
+		case 'e':
+#ifndef NO_EDITCOMPLETE
+			editing = 0;
+#endif
+			break;
+
+		case 'f':
+			flushcache = 1;
+			break;
+
+		case 'g':
+			doglob = 0;
+			break;
+
+		case 'i':
+			interactive = 0;
+			break;
+
+		case 'n':
+			autologin = 0;
+			break;
+
+		case 'N':
+			if (strlcpy(netrc, optarg, sizeof(netrc))
+			    >= sizeof(netrc))
+				errx(1, "%s: %s", optarg,
+				    strerror(ENAMETOOLONG));
+			break;
+
+		case 'o':
+			outfile = optarg;
+			if (strcmp(outfile, "-") == 0)
+				ttyout = stderr;
+			break;
+
+		case 'p':
+			passivemode = 1;
+			activefallback = 0;
+			break;
+
+		case 'P':
+			ftpport = optarg;
+			break;
+
+		case 'q':
+			quit_time = strtol(optarg, &ep, 10);
+			if (quit_time < 1 || *ep != '\0')
+				errx(1, "Bad quit value: %s", optarg);
+			break;
+
+		case 'r':
+			retry_connect = strtol(optarg, &ep, 10);
+			if (retry_connect < 1 || *ep != '\0')
+				errx(1, "Bad retry value: %s", optarg);
+			break;
+
+		case 'R':
+			restartautofetch = 1;
+			break;
+
+		case 's':
+			src_addr = optarg;
+			break;
+
+		case 't':
+			trace = 1;
+			break;
+
+		case 'T':
+		{
+			int targc;
+			char *targv[6], *oac;
+			char cmdbuf[MAX_C_NAME];
+
+				/* look for `dir,max[,incr]' */
+			targc = 0;
+			(void)strlcpy(cmdbuf, "-T", sizeof(cmdbuf));
+			targv[targc++] = cmdbuf;
+			oac = ftp_strdup(optarg);
+
+			while ((cp = strsep(&oac, ",")) != NULL) {
+				if (*cp == '\0') {
+					warnx("Bad throttle value `%s'",
+					    optarg);
+					usage();
+					/* NOTREACHED */
+				}
+				targv[targc++] = cp;
+				if (targc >= 5)
+					break;
+			}
+			if (parserate(targc, targv, 1) == -1)
+				usage();
+			free(oac);
+			break;
+		}
+
+		case 'u':
+		{
+			isupload = 1;
+			interactive = 0;
+			upload_path = ftp_strdup(optarg);
+
+			break;
+		}
+
+		case 'v':
+			progress = verbose = 1;
+			break;
+
+		case 'V':
+			progress = verbose = 0;
+			break;
+
+		default:
+			usage();
+		}
+	}
+			/* set line buffering on ttyout */
+	setvbuf(ttyout, NULL, _IOLBF, 0);
+	argc -= optind;
+	argv += optind;
+
+	cpend = 0;	/* no pending replies */
+	proxy = 0;	/* proxy not active */
+	crflag = 1;	/* strip c.r. on ascii gets */
+	sendport = -1;	/* not using ports */
+
+	if (src_addr != NULL) {
+		struct addrinfo hints;
+		int error;
+
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_family = family;
+		hints.ai_socktype = SOCK_STREAM;
+		hints.ai_flags = AI_PASSIVE;
+		error = getaddrinfo(src_addr, NULL, &hints, &bindai);
+		if (error) {
+		    	errx(1, "Can't lookup `%s': %s", src_addr,
+			    (error == EAI_SYSTEM) ? strerror(errno)
+						  : gai_strerror(error));
+		}
+	}
+
+	/*
+	 * Cache the user name and home directory.
+	 */
+	localhome = NULL;
+	localname = NULL;
+	anonuser = "anonymous";
+	cp = getenv("HOME");
+	if (! EMPTYSTRING(cp))
+		localhome = ftp_strdup(cp);
+	pw = NULL;
+	cp = getlogin();
+	if (cp != NULL)
+		pw = getpwnam(cp);
+	if (pw == NULL)
+		pw = getpwuid(getuid());
+	if (pw != NULL) {
+		if (localhome == NULL && !EMPTYSTRING(pw->pw_dir))
+			localhome = ftp_strdup(pw->pw_dir);
+		localname = ftp_strdup(pw->pw_name);
+		anonuser = localname;
+	}
+	if (netrc[0] == '\0' && localhome != NULL) {
+		if (strlcpy(netrc, localhome, sizeof(netrc)) >= sizeof(netrc) ||
+		    strlcat(netrc, "/.netrc", sizeof(netrc)) >= sizeof(netrc)) {
+			warnx("%s/.netrc: %s", localhome,
+			    strerror(ENAMETOOLONG));
+			netrc[0] = '\0';
+		}
+	}
+	if (localhome == NULL)
+		localhome = ftp_strdup("/");
+
+	/*
+	 * Every anonymous FTP server I've encountered will accept the
+	 * string "username@", and will append the hostname itself. We
+	 * do this by default since many servers are picky about not
+	 * having a FQDN in the anonymous password.
+	 * - thorpej at NetBSD.org
+	 */
+	len = strlen(anonuser) + 2;
+	anonpass = ftp_malloc(len);
+	(void)strlcpy(anonpass, anonuser, len);
+	(void)strlcat(anonpass, "@",	  len);
+
+			/*
+			 * set all the defaults for options defined in
+			 * struct option optiontab[]  declared in cmdtab.c
+			 */
+	setupoption("anonpass",		getenv("FTPANONPASS"),	anonpass);
+	setupoption("ftp_proxy",	getenv(FTP_PROXY),	"");
+	setupoption("http_proxy",	getenv(HTTP_PROXY),	"");
+	setupoption("no_proxy",		getenv(NO_PROXY),	"");
+	setupoption("pager",		getenv("PAGER"),	DEFAULTPAGER);
+	setupoption("prompt",		getenv("FTPPROMPT"),	DEFAULTPROMPT);
+	setupoption("rprompt",		getenv("FTPRPROMPT"),	DEFAULTRPROMPT);
+
+	free(anonpass);
+
+	setttywidth(0);
+#ifdef SIGINFO
+	(void)xsignal(SIGINFO, psummary);
+#endif
+	(void)xsignal(SIGQUIT, psummary);
+	(void)xsignal(SIGUSR1, crankrate);
+	(void)xsignal(SIGUSR2, crankrate);
+	(void)xsignal(SIGWINCH, setttywidth);
+
+	if (argc > 0) {
+		if (isupload) {
+			rval = auto_put(argc, argv, upload_path);
+ sigint_or_rval_exit:
+			if (sigint_raised) {
+				(void)xsignal(SIGINT, SIG_DFL);
+				raise(SIGINT);
+			}
+			exit(rval);
+		} else if (strchr(argv[0], ':') != NULL
+			    && ! isipv6addr(argv[0])) {
+			rval = auto_fetch(argc, argv);
+			if (rval >= 0)		/* -1 == connected and cd-ed */
+				goto sigint_or_rval_exit;
+		} else {
+			char *xargv[4], *uuser, *host;
+			char cmdbuf[MAXPATHLEN];
+
+			if ((rval = sigsetjmp(toplevel, 1)))
+				goto sigint_or_rval_exit;
+			(void)xsignal(SIGINT, intr);
+			(void)xsignal(SIGPIPE, lostpeer);
+			uuser = NULL;
+			host = argv[0];
+			cp = strchr(host, '@');
+			if (cp) {
+				*cp = '\0';
+				uuser = host;
+				host = cp + 1;
+			}
+			(void)strlcpy(cmdbuf, getprogname(), sizeof(cmdbuf));
+			xargv[0] = cmdbuf;
+			xargv[1] = host;
+			xargv[2] = argv[1];
+			xargv[3] = NULL;
+			do {
+				int oautologin;
+
+				oautologin = autologin;
+				if (uuser != NULL) {
+					anonftp = 0;
+					autologin = 0;
+				}
+				setpeer(argc+1, xargv);
+				autologin = oautologin;
+				if (connected == 1 && uuser != NULL)
+					(void)ftp_login(host, uuser, NULL);
+				if (!retry_connect)
+					break;
+				if (!connected) {
+					macnum = 0;
+					fprintf(ttyout,
+					    "Retrying in %d seconds...\n",
+					    retry_connect);
+					sleep(retry_connect);
+				}
+			} while (!connected);
+			retry_connect = 0; /* connected, stop hiding msgs */
+		}
+	}
+	if (isupload)
+		usage();
+
+#ifndef NO_EDITCOMPLETE
+	controlediting();
+#endif /* !NO_EDITCOMPLETE */
+
+	(void)sigsetjmp(toplevel, 1);
+	(void)xsignal(SIGINT, intr);
+	(void)xsignal(SIGPIPE, lostpeer);
+	for (;;)
+		cmdscanner();
+}
+
+/*
+ * Generate a prompt
+ */
+char *
+prompt(void)
+{
+	static char	**promptopt;
+	static char	  buf[MAXPATHLEN];
+
+	if (promptopt == NULL) {
+		struct option *o;
+
+		o = getoption("prompt");
+		if (o == NULL)
+			errx(1, "prompt: no such option `prompt'");
+		promptopt = &(o->value);
+	}
+	formatbuf(buf, sizeof(buf), *promptopt ? *promptopt : DEFAULTPROMPT);
+	return (buf);
+}
+
+/*
+ * Generate an rprompt
+ */
+char *
+rprompt(void)
+{
+	static char	**rpromptopt;
+	static char	  buf[MAXPATHLEN];
+
+	if (rpromptopt == NULL) {
+		struct option *o;
+
+		o = getoption("rprompt");
+		if (o == NULL)
+			errx(1, "rprompt: no such option `rprompt'");
+		rpromptopt = &(o->value);
+	}
+	formatbuf(buf, sizeof(buf), *rpromptopt ? *rpromptopt : DEFAULTRPROMPT);
+	return (buf);
+}
+
+/*
+ * Command parser.
+ */
+void
+cmdscanner(void)
+{
+	struct cmd	*c;
+	char		*p;
+#ifndef NO_EDITCOMPLETE
+	int		 ch;
+	size_t		 num;
+#endif
+	int		 len;
+	char		 cmdbuf[MAX_C_NAME];
+
+	for (;;) {
+#ifndef NO_EDITCOMPLETE
+		if (!editing) {
+#endif /* !NO_EDITCOMPLETE */
+			if (fromatty) {
+				fputs(prompt(), ttyout);
+				p = rprompt();
+				if (*p)
+					fprintf(ttyout, "%s ", p);
+			}
+			(void)fflush(ttyout);
+			len = get_line(stdin, line, sizeof(line), NULL);
+			switch (len) {
+			case -1:	/* EOF */
+			case -2:	/* error */
+				if (fromatty)
+					putc('\n', ttyout);
+				quit(0, NULL);
+				/* NOTREACHED */
+			case -3:	/* too long; try again */
+				fputs("Sorry, input line is too long.\n",
+				    ttyout);
+				continue;
+			case 0:		/* empty; try again */
+				continue;
+			default:	/* all ok */
+				break;
+			}
+#ifndef NO_EDITCOMPLETE
+		} else {
+			const char *buf;
+			HistEvent ev;
+			cursor_pos = NULL;
+
+			buf = el_gets(el, &ch);
+			num = ch;
+			if (buf == NULL || num == 0) {
+				if (fromatty)
+					putc('\n', ttyout);
+				quit(0, NULL);
+			}
+			if (num >= sizeof(line)) {
+				fputs("Sorry, input line is too long.\n",
+				    ttyout);
+				break;
+			}
+			memcpy(line, buf, num);
+			if (line[--num] == '\n') {
+				line[num] = '\0';
+				if (num == 0)
+					break;
+			}
+			history(hist, &ev, H_ENTER, buf);
+		}
+#endif /* !NO_EDITCOMPLETE */
+
+		makeargv();
+		if (margc == 0)
+			continue;
+		c = getcmd(margv[0]);
+		if (c == (struct cmd *)-1) {
+			fputs("?Ambiguous command.\n", ttyout);
+			continue;
+		}
+		if (c == NULL) {
+#if !defined(NO_EDITCOMPLETE)
+			/*
+			 * attempt to el_parse() unknown commands.
+			 * any command containing a ':' would be parsed
+			 * as "[prog:]cmd ...", and will result in a
+			 * false positive if prog != "ftp", so treat
+			 * such commands as invalid.
+			 */
+			if (strchr(margv[0], ':') != NULL ||
+			    !editing ||
+			    el_parse(el, margc, (const char **)margv) != 0)
+#endif /* !NO_EDITCOMPLETE */
+				fputs("?Invalid command.\n", ttyout);
+			continue;
+		}
+		if (c->c_conn && !connected) {
+			fputs("Not connected.\n", ttyout);
+			continue;
+		}
+		confirmrest = 0;
+		(void)strlcpy(cmdbuf, c->c_name, sizeof(cmdbuf));
+		margv[0] = cmdbuf;
+		(*c->c_handler)(margc, margv);
+		if (bell && c->c_bell)
+			(void)putc('\007', ttyout);
+		if (c->c_handler != help)
+			break;
+	}
+	(void)xsignal(SIGINT, intr);
+	(void)xsignal(SIGPIPE, lostpeer);
+}
+
+struct cmd *
+getcmd(const char *name)
+{
+	const char *p, *q;
+	struct cmd *c, *found;
+	int nmatches, longest;
+
+	if (name == NULL)
+		return (0);
+
+	longest = 0;
+	nmatches = 0;
+	found = 0;
+	for (c = cmdtab; (p = c->c_name) != NULL; c++) {
+		for (q = name; *q == *p++; q++)
+			if (*q == 0)		/* exact match? */
+				return (c);
+		if (!*q) {			/* the name was a prefix */
+			if (q - name > longest) {
+				longest = q - name;
+				nmatches = 1;
+				found = c;
+			} else if (q - name == longest)
+				nmatches++;
+		}
+	}
+	if (nmatches > 1)
+		return ((struct cmd *)-1);
+	return (found);
+}
+
+/*
+ * Slice a string up into argc/argv.
+ */
+
+int slrflag;
+
+void
+makeargv(void)
+{
+	char *argp;
+
+	stringbase = line;		/* scan from first of buffer */
+	argbase = argbuf;		/* store from first of buffer */
+	slrflag = 0;
+	marg_sl->sl_cur = 0;		/* reset to start of marg_sl */
+	for (margc = 0; ; margc++) {
+		argp = slurpstring();
+		ftp_sl_add(marg_sl, argp);
+		if (argp == NULL)
+			break;
+	}
+#ifndef NO_EDITCOMPLETE
+	if (cursor_pos == line) {
+		cursor_argc = 0;
+		cursor_argo = 0;
+	} else if (cursor_pos != NULL) {
+		cursor_argc = margc;
+		cursor_argo = strlen(margv[margc-1]);
+	}
+#endif /* !NO_EDITCOMPLETE */
+}
+
+#ifdef NO_EDITCOMPLETE
+#define	INC_CHKCURSOR(x)	(x)++
+#else  /* !NO_EDITCOMPLETE */
+#define	INC_CHKCURSOR(x)	{ (x)++ ; \
+				if (x == cursor_pos) { \
+					cursor_argc = margc; \
+					cursor_argo = ap-argbase; \
+					cursor_pos = NULL; \
+				} }
+
+#endif /* !NO_EDITCOMPLETE */
+
+/*
+ * Parse string into argbuf;
+ * implemented with FSM to
+ * handle quoting and strings
+ */
+char *
+slurpstring(void)
+{
+	static char bangstr[2] = { '!', '\0' };
+	static char dollarstr[2] = { '$', '\0' };
+	int got_one = 0;
+	char *sb = stringbase;
+	char *ap = argbase;
+	char *tmp = argbase;		/* will return this if token found */
+
+	if (*sb == '!' || *sb == '$') {	/* recognize ! as a token for shell */
+		switch (slrflag) {	/* and $ as token for macro invoke */
+			case 0:
+				slrflag++;
+				INC_CHKCURSOR(stringbase);
+				return ((*sb == '!') ? bangstr : dollarstr);
+				/* NOTREACHED */
+			case 1:
+				slrflag++;
+				altarg = stringbase;
+				break;
+			default:
+				break;
+		}
+	}
+
+S0:
+	switch (*sb) {
+
+	case '\0':
+		goto OUT;
+
+	case ' ':
+	case '\t':
+		INC_CHKCURSOR(sb);
+		goto S0;
+
+	default:
+		switch (slrflag) {
+			case 0:
+				slrflag++;
+				break;
+			case 1:
+				slrflag++;
+				altarg = sb;
+				break;
+			default:
+				break;
+		}
+		goto S1;
+	}
+
+S1:
+	switch (*sb) {
+
+	case ' ':
+	case '\t':
+	case '\0':
+		goto OUT;	/* end of token */
+
+	case '\\':
+		INC_CHKCURSOR(sb);
+		goto S2;	/* slurp next character */
+
+	case '"':
+		INC_CHKCURSOR(sb);
+		goto S3;	/* slurp quoted string */
+
+	default:
+		*ap = *sb;	/* add character to token */
+		ap++;
+		INC_CHKCURSOR(sb);
+		got_one = 1;
+		goto S1;
+	}
+
+S2:
+	switch (*sb) {
+
+	case '\0':
+		goto OUT;
+
+	default:
+		*ap = *sb;
+		ap++;
+		INC_CHKCURSOR(sb);
+		got_one = 1;
+		goto S1;
+	}
+
+S3:
+	switch (*sb) {
+
+	case '\0':
+		goto OUT;
+
+	case '"':
+		INC_CHKCURSOR(sb);
+		goto S1;
+
+	default:
+		*ap = *sb;
+		ap++;
+		INC_CHKCURSOR(sb);
+		got_one = 1;
+		goto S3;
+	}
+
+OUT:
+	if (got_one)
+		*ap++ = '\0';
+	argbase = ap;			/* update storage pointer */
+	stringbase = sb;		/* update scan pointer */
+	if (got_one) {
+		return (tmp);
+	}
+	switch (slrflag) {
+		case 0:
+			slrflag++;
+			break;
+		case 1:
+			slrflag++;
+			altarg = NULL;
+			break;
+		default:
+			break;
+	}
+	return (NULL);
+}
+
+/*
+ * Help/usage command.
+ * Call each command handler with argc == 0 and argv[0] == name.
+ */
+void
+help(int argc, char *argv[])
+{
+	struct cmd *c;
+	char *nargv[1], *cmd;
+	const char *p;
+	int isusage;
+
+	cmd = argv[0];
+	isusage = (strcmp(cmd, "usage") == 0);
+	if (argc == 0 || (isusage && argc == 1)) {
+		UPRINTF("usage: %s [command [...]]\n", cmd);
+		return;
+	}
+	if (argc == 1) {
+		StringList *buf;
+
+		buf = ftp_sl_init();
+		fprintf(ttyout,
+		    "%sommands may be abbreviated.  Commands are:\n\n",
+		    proxy ? "Proxy c" : "C");
+		for (c = cmdtab; (p = c->c_name) != NULL; c++)
+			if (!proxy || c->c_proxy)
+				ftp_sl_add(buf, ftp_strdup(p));
+		list_vertical(buf);
+		sl_free(buf, 1);
+		return;
+	}
+
+#define	HELPINDENT ((int) sizeof("disconnect"))
+
+	while (--argc > 0) {
+		char *arg;
+		char cmdbuf[MAX_C_NAME];
+
+		arg = *++argv;
+		c = getcmd(arg);
+		if (c == (struct cmd *)-1)
+			fprintf(ttyout, "?Ambiguous %s command `%s'\n",
+			    cmd, arg);
+		else if (c == NULL)
+			fprintf(ttyout, "?Invalid %s command `%s'\n",
+			    cmd, arg);
+		else {
+			if (isusage) {
+				(void)strlcpy(cmdbuf, c->c_name, sizeof(cmdbuf));
+				nargv[0] = cmdbuf;
+				(*c->c_handler)(0, nargv);
+			} else
+				fprintf(ttyout, "%-*s\t%s\n", HELPINDENT,
+				    c->c_name, c->c_help);
+		}
+	}
+}
+
+struct option *
+getoption(const char *name)
+{
+	const char *p;
+	struct option *c;
+
+	if (name == NULL)
+		return (NULL);
+	for (c = optiontab; (p = c->name) != NULL; c++) {
+		if (strcasecmp(p, name) == 0)
+			return (c);
+	}
+	return (NULL);
+}
+
+char *
+getoptionvalue(const char *name)
+{
+	struct option *c;
+
+	if (name == NULL)
+		errx(1, "getoptionvalue: invoked with NULL name");
+	c = getoption(name);
+	if (c != NULL)
+		return (c->value);
+	errx(1, "getoptionvalue: invoked with unknown option `%s'", name);
+	/* NOTREACHED */
+}
+
+static void
+setupoption(const char *name, const char *value, const char *defaultvalue)
+{
+	set_option(name, value ? value : defaultvalue, 0);
+}
+
+void
+usage(void)
+{
+	const char *progname = getprogname();
+
+	(void)fprintf(stderr,
+"usage: %s [-46AadefginpRtVv] [-N netrc] [-o outfile] [-P port] [-q quittime]\n"
+"           [-r retry] [-s srcaddr] [-T dir,max[,inc]]\n"
+"           [[user@]host [port]] [host:path[/]] [file:///file]\n"
+"           [ftp://[user[:pass]@]host[:port]/path[/]]\n"
+"           [http://[user[:pass]@]host[:port]/path] [...]\n"
+"       %s -u URL file [...]\n", progname, progname);
+	exit(1);
+}

Added: vendor/NetBSD/tnftp/20100108/src/progressbar.c
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/progressbar.c	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/progressbar.c	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,493 @@
+/*	$NetBSD: progressbar.c,v 1.14 2009/05/20 12:53:47 lukem Exp $	*/
+/*	from	NetBSD: progressbar.c,v 1.21 2009/04/12 10:18:52 lukem Exp	*/
+
+/*-
+ * Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tnftp.h"
+
+#if 0	/* tnftp */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID(" NetBSD: progressbar.c,v 1.21 2009/04/12 10:18:52 lukem Exp  ");
+#endif /* not lint */
+
+/*
+ * FTP User Program -- Misc support routines
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+
+#endif	/* tnftp */
+
+#include "progressbar.h"
+
+#if !defined(NO_PROGRESS)
+/*
+ * return non-zero if we're the current foreground process
+ */
+int
+foregroundproc(void)
+{
+	static pid_t pgrp = -1;
+
+	if (pgrp == -1)
+#if GETPGRP_VOID
+		pgrp = getpgrp();
+#else /* ! GETPGRP_VOID */
+		pgrp = getpgrp(0);
+#endif /* ! GETPGRP_VOID */
+
+	return (tcgetpgrp(fileno(ttyout)) == pgrp);
+}
+#endif	/* !defined(NO_PROGRESS) */
+
+
+static void updateprogressmeter(int);
+
+/*
+ * SIGALRM handler to update the progress meter
+ */
+static void
+updateprogressmeter(int dummy)
+{
+	int oerrno = errno;
+
+	progressmeter(0);
+	errno = oerrno;
+}
+
+/*
+ * List of order of magnitude suffixes, per IEC 60027-2.
+ */
+static const char * const suffixes[] = {
+	"",	/* 2^0  (byte) */
+	"KiB",	/* 2^10 Kibibyte */
+	"MiB",	/* 2^20 Mebibyte */
+	"GiB",	/* 2^30 Gibibyte */
+	"TiB",	/* 2^40 Tebibyte */
+	"PiB",	/* 2^50 Pebibyte */
+	"EiB",	/* 2^60 Exbibyte */
+#if 0
+		/* The following are not necessary for signed 64-bit off_t */
+	"ZiB",	/* 2^70 Zebibyte */
+	"YiB",	/* 2^80 Yobibyte */
+#endif
+};
+#define NSUFFIXES	(int)(sizeof(suffixes) / sizeof(suffixes[0]))
+
+/*
+ * Display a transfer progress bar if progress is non-zero.
+ * SIGALRM is hijacked for use by this function.
+ * - Before the transfer, set filesize to size of file (or -1 if unknown),
+ *   and call with flag = -1. This starts the once per second timer,
+ *   and a call to updateprogressmeter() upon SIGALRM.
+ * - During the transfer, updateprogressmeter will call progressmeter
+ *   with flag = 0
+ * - After the transfer, call with flag = 1
+ */
+static struct timeval start;
+static struct timeval lastupdate;
+
+#define	BUFLEFT	(sizeof(buf) - len)
+
+void
+progressmeter(int flag)
+{
+	static off_t lastsize;
+	off_t cursize;
+	struct timeval now, wait;
+#ifndef NO_PROGRESS
+	struct timeval td;
+	off_t abbrevsize, bytespersec;
+	double elapsed;
+	int ratio, i, remaining, barlength;
+
+			/*
+			 * Work variables for progress bar.
+			 *
+			 * XXX:	if the format of the progress bar changes
+			 *	(especially the number of characters in the
+			 *	`static' portion of it), be sure to update
+			 *	these appropriately.
+			 */
+#endif
+	size_t		len;
+	char		buf[256];	/* workspace for progress bar */
+#ifndef NO_PROGRESS
+#define	BAROVERHEAD	45		/* non `*' portion of progress bar */
+					/*
+					 * stars should contain at least
+					 * sizeof(buf) - BAROVERHEAD entries
+					 */
+	static const char	stars[] =
+"*****************************************************************************"
+"*****************************************************************************"
+"*****************************************************************************";
+
+#endif
+
+	if (flag == -1) {
+		(void)gettimeofday(&start, NULL);
+		lastupdate = start;
+		lastsize = restart_point;
+	}
+
+	(void)gettimeofday(&now, NULL);
+	cursize = bytes + restart_point;
+	timersub(&now, &lastupdate, &wait);
+	if (cursize > lastsize) {
+		lastupdate = now;
+		lastsize = cursize;
+		wait.tv_sec = 0;
+	} else {
+#ifndef STANDALONE_PROGRESS
+		if (quit_time > 0 && wait.tv_sec > quit_time) {
+			len = snprintf(buf, sizeof(buf), "\r\n%s: "
+			    "transfer aborted because stalled for %lu sec.\r\n",
+			    getprogname(), (unsigned long)wait.tv_sec);
+			(void)write(fileno(ttyout), buf, len);
+			alarmtimer(0);
+			(void)xsignal(SIGALRM, SIG_DFL);
+			siglongjmp(toplevel, 1);
+		}
+#endif	/* !STANDALONE_PROGRESS */
+	}
+	/*
+	 * Always set the handler even if we are not the foreground process.
+	 */
+#ifdef STANDALONE_PROGRESS
+	if (progress) {
+#else
+	if (quit_time > 0 || progress) {
+#endif /* !STANDALONE_PROGRESS */
+		if (flag == -1) {
+			(void)xsignal_restart(SIGALRM, updateprogressmeter, 1);
+			alarmtimer(1);		/* set alarm timer for 1 Hz */
+		} else if (flag == 1) {
+			alarmtimer(0);
+			(void)xsignal(SIGALRM, SIG_DFL);
+		}
+	}
+#ifndef NO_PROGRESS
+	if (!progress)
+		return;
+	len = 0;
+
+	/*
+	 * print progress bar only if we are foreground process.
+	 */
+	if (! foregroundproc())
+		return;
+
+	len += snprintf(buf + len, BUFLEFT, "\r");
+	if (prefix)
+	  len += snprintf(buf + len, BUFLEFT, "%s", prefix);
+	if (filesize > 0) {
+		ratio = (int)((double)cursize * 100.0 / (double)filesize);
+		ratio = MAX(ratio, 0);
+		ratio = MIN(ratio, 100);
+		len += snprintf(buf + len, BUFLEFT, "%3d%% ", ratio);
+
+			/*
+			 * calculate the length of the `*' bar, ensuring that
+			 * the number of stars won't exceed the buffer size
+			 */
+		barlength = MIN((int)(sizeof(buf) - 1), ttywidth) - BAROVERHEAD;
+		if (prefix)
+			barlength -= (int)strlen(prefix);
+		if (barlength > 0) {
+			i = barlength * ratio / 100;
+			len += snprintf(buf + len, BUFLEFT,
+			    "|%.*s%*s|", i, stars, (int)(barlength - i), "");
+		}
+	}
+
+	abbrevsize = cursize;
+	for (i = 0; abbrevsize >= 100000 && i < NSUFFIXES; i++)
+		abbrevsize >>= 10;
+	if (i == NSUFFIXES)
+		i--;
+	len += snprintf(buf + len, BUFLEFT, " " LLFP("5") " %-3s ",
+	    (LLT)abbrevsize,
+	    suffixes[i]);
+
+	timersub(&now, &start, &td);
+	elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
+
+	bytespersec = 0;
+	if (bytes > 0) {
+		bytespersec = bytes;
+		if (elapsed > 0.0)
+			bytespersec /= elapsed;
+	}
+	for (i = 1; bytespersec >= 1024000 && i < NSUFFIXES; i++)
+		bytespersec >>= 10;
+	len += snprintf(buf + len, BUFLEFT,
+	    " " LLFP("3") ".%02d %.2sB/s ",
+	    (LLT)(bytespersec / 1024),
+	    (int)((bytespersec % 1024) * 100 / 1024),
+	    suffixes[i]);
+
+	if (filesize > 0) {
+		if (bytes <= 0 || elapsed <= 0.0 || cursize > filesize) {
+			len += snprintf(buf + len, BUFLEFT, "   --:-- ETA");
+		} else if (wait.tv_sec >= STALLTIME) {
+			len += snprintf(buf + len, BUFLEFT, " - stalled -");
+		} else {
+			remaining = (int)
+			    ((filesize - restart_point) / (bytes / elapsed) -
+			    elapsed);
+			if (remaining >= 100 * SECSPERHOUR)
+				len += snprintf(buf + len, BUFLEFT,
+				    "   --:-- ETA");
+			else {
+				i = remaining / SECSPERHOUR;
+				if (i)
+					len += snprintf(buf + len, BUFLEFT,
+					    "%2d:", i);
+				else
+					len += snprintf(buf + len, BUFLEFT,
+					    "   ");
+				i = remaining % SECSPERHOUR;
+				len += snprintf(buf + len, BUFLEFT,
+				    "%02d:%02d ETA", i / 60, i % 60);
+			}
+		}
+	}
+	if (flag == 1)
+		len += snprintf(buf + len, BUFLEFT, "\n");
+	(void)write(fileno(ttyout), buf, len);
+
+#endif	/* !NO_PROGRESS */
+}
+
+#ifndef STANDALONE_PROGRESS
+/*
+ * Display transfer statistics.
+ * Requires start to be initialised by progressmeter(-1),
+ * direction to be defined by xfer routines, and filesize and bytes
+ * to be updated by xfer routines
+ * If siginfo is nonzero, an ETA is displayed, and the output goes to stderr
+ * instead of ttyout.
+ */
+void
+ptransfer(int siginfo)
+{
+	struct timeval now, td, wait;
+	double elapsed;
+	off_t bytespersec;
+	int remaining, hh, i;
+	size_t len;
+
+	char buf[256];		/* Work variable for transfer status. */
+
+	if (!verbose && !progress && !siginfo)
+		return;
+
+	(void)gettimeofday(&now, NULL);
+	timersub(&now, &start, &td);
+	elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
+	bytespersec = 0;
+	if (bytes > 0) {
+		bytespersec = bytes;
+		if (elapsed > 0.0)
+			bytespersec /= elapsed;
+	}
+	len = 0;
+	len += snprintf(buf + len, BUFLEFT, LLF " byte%s %s in ",
+	    (LLT)bytes, bytes == 1 ? "" : "s", direction);
+	remaining = (int)elapsed;
+	if (remaining > SECSPERDAY) {
+		int days;
+
+		days = remaining / SECSPERDAY;
+		remaining %= SECSPERDAY;
+		len += snprintf(buf + len, BUFLEFT,
+		    "%d day%s ", days, days == 1 ? "" : "s");
+	}
+	hh = remaining / SECSPERHOUR;
+	remaining %= SECSPERHOUR;
+	if (hh)
+		len += snprintf(buf + len, BUFLEFT, "%2d:", hh);
+	len += snprintf(buf + len, BUFLEFT,
+	    "%02d:%02d ", remaining / 60, remaining % 60);
+
+	for (i = 1; bytespersec >= 1024000 && i < NSUFFIXES; i++)
+		bytespersec >>= 10;
+	if (i == NSUFFIXES)
+		i--;
+	len += snprintf(buf + len, BUFLEFT, "(" LLF ".%02d %.2sB/s)",
+	    (LLT)(bytespersec / 1024),
+	    (int)((bytespersec % 1024) * 100 / 1024),
+	    suffixes[i]);
+
+	if (siginfo && bytes > 0 && elapsed > 0.0 && filesize >= 0
+	    && bytes + restart_point <= filesize) {
+		remaining = (int)((filesize - restart_point) /
+				  (bytes / elapsed) - elapsed);
+		hh = remaining / SECSPERHOUR;
+		remaining %= SECSPERHOUR;
+		len += snprintf(buf + len, BUFLEFT, "  ETA: ");
+		if (hh)
+			len += snprintf(buf + len, BUFLEFT, "%2d:", hh);
+		len += snprintf(buf + len, BUFLEFT, "%02d:%02d",
+		    remaining / 60, remaining % 60);
+		timersub(&now, &lastupdate, &wait);
+		if (wait.tv_sec >= STALLTIME)
+			len += snprintf(buf + len, BUFLEFT, "  (stalled)");
+	}
+	len += snprintf(buf + len, BUFLEFT, "\n");
+	(void)write(siginfo ? STDERR_FILENO : fileno(ttyout), buf, len);
+}
+
+/*
+ * SIG{INFO,QUIT} handler to print transfer stats if a transfer is in progress
+ */
+void
+psummary(int notused)
+{
+	int oerrno = errno;
+
+	if (bytes > 0) {
+		if (fromatty)
+			write(fileno(ttyout), "\n", 1);
+		ptransfer(1);
+	}
+	errno = oerrno;
+}
+#endif	/* !STANDALONE_PROGRESS */
+
+
+/*
+ * Set the SIGALRM interval timer for wait seconds, 0 to disable.
+ */
+void
+alarmtimer(int wait)
+{
+	struct itimerval itv;
+
+	itv.it_value.tv_sec = wait;
+	itv.it_value.tv_usec = 0;
+	itv.it_interval = itv.it_value;
+	setitimer(ITIMER_REAL, &itv, NULL);
+}
+
+
+/*
+ * Install a POSIX signal handler, allowing the invoker to set whether
+ * the signal should be restartable or not
+ */
+sigfunc
+xsignal_restart(int sig, sigfunc func, int restartable)
+{
+#ifdef ultrix	/* XXX: this is lame - how do we test sigvec vs. sigaction? */
+	struct sigvec vec, ovec;
+
+	vec.sv_handler = func;
+	sigemptyset(&vec.sv_mask);
+	vec.sv_flags = 0;
+	if (sigvec(sig, &vec, &ovec) < 0)
+		return (SIG_ERR);
+	return (ovec.sv_handler);
+#else	/* ! ultrix */
+	struct sigaction act, oact;
+	act.sa_handler = func;
+
+	sigemptyset(&act.sa_mask);
+#if defined(SA_RESTART)			/* 4.4BSD, Posix(?), SVR4 */
+	act.sa_flags = restartable ? SA_RESTART : 0;
+#elif defined(SA_INTERRUPT)		/* SunOS 4.x */
+	act.sa_flags = restartable ? 0 : SA_INTERRUPT;
+#else
+#error "system must have SA_RESTART or SA_INTERRUPT"
+#endif
+	if (sigaction(sig, &act, &oact) < 0)
+		return (SIG_ERR);
+	return (oact.sa_handler);
+#endif	/* ! ultrix */
+}
+
+/*
+ * Install a signal handler with the `restartable' flag set dependent upon
+ * which signal is being set. (This is a wrapper to xsignal_restart())
+ */
+sigfunc
+xsignal(int sig, sigfunc func)
+{
+	int restartable;
+
+	/*
+	 * Some signals print output or change the state of the process.
+	 * There should be restartable, so that reads and writes are
+	 * not affected.  Some signals should cause program flow to change;
+	 * these signals should not be restartable, so that the system call
+	 * will return with EINTR, and the program will go do something
+	 * different.  If the signal handler calls longjmp() or siglongjmp(),
+	 * it doesn't matter if it's restartable.
+	 */
+
+	switch(sig) {
+#ifdef SIGINFO
+	case SIGINFO:
+#endif
+	case SIGQUIT:
+	case SIGUSR1:
+	case SIGUSR2:
+	case SIGWINCH:
+		restartable = 1;
+		break;
+
+	case SIGALRM:
+	case SIGINT:
+	case SIGPIPE:
+		restartable = 0;
+		break;
+
+	default:
+		/*
+		 * This is unpleasant, but I don't know what would be better.
+		 * Right now, this "can't happen"
+		 */
+		errx(1, "xsignal_restart: called with signal %d", sig);
+	}
+
+	return(xsignal_restart(sig, func, restartable));
+}

Added: vendor/NetBSD/tnftp/20100108/src/progressbar.h
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/progressbar.h	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/progressbar.h	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,102 @@
+/*	$NetBSD: progressbar.h,v 1.9 2009/05/20 12:53:47 lukem Exp $	*/
+/*	from	NetBSD: progressbar.h,v 1.8 2009/04/12 10:18:52 lukem Exp	*/
+
+/*-
+ * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef STANDALONE_PROGRESS
+#include <setjmp.h>
+#endif	/* !STANDALONE_PROGRESS */
+
+#ifndef	GLOBAL
+#define	GLOBAL	extern
+#endif
+
+
+#define	STALLTIME	5	/* # of seconds of no xfer before "stalling" */
+
+typedef void (*sigfunc)(int);
+
+
+GLOBAL	FILE   *ttyout;		/* stdout, or stderr if retrieving to stdout */
+
+GLOBAL	int	progress;	/* display transfer progress bar */
+GLOBAL	int	ttywidth;	/* width of tty */
+
+GLOBAL	off_t	bytes;		/* current # of bytes read */
+GLOBAL	off_t	filesize;	/* size of file being transferred */
+GLOBAL	off_t	restart_point;	/* offset to restart transfer */
+GLOBAL	char   *prefix;		/* Text written left of progress bar */
+
+
+#ifndef	STANDALONE_PROGRESS
+GLOBAL	int	fromatty;	/* input is from a terminal */
+GLOBAL	int	verbose;	/* print messages coming back from server */
+GLOBAL	int	quit_time;	/* maximum time to wait if stalled */
+
+GLOBAL	const char  *direction;	/* direction transfer is occurring */
+
+GLOBAL	sigjmp_buf toplevel;	/* non-local goto stuff for cmd scanner */
+#endif	/* !STANDALONE_PROGRESS */
+
+int	foregroundproc(void);
+void	alarmtimer(int);
+void	progressmeter(int);
+sigfunc	xsignal(int, sigfunc);
+sigfunc	xsignal_restart(int, sigfunc, int);
+
+#ifndef STANDALONE_PROGRESS
+void	psummary(int);
+void	ptransfer(int);
+#endif	/* !STANDALONE_PROGRESS */
+
+#ifdef NO_LONG_LONG
+# define LLF		"%ld"
+# define LLFP(x)	"%" x "ld"
+# define LLT		long
+# define ULLF		"%lu"
+# define ULLFP(x)	"%" x "lu"
+# define ULLT		unsigned long
+#else
+#if defined(HAVE_PRINTF_QD)
+# define LLF		"%qd"
+# define LLFP(x)	"%" x "qd"
+# define LLT		long long
+# define ULLF		"%qu"
+# define ULLFP(x)	"%" x "qu"
+# define ULLT		unsigned long long
+#else /* !defined(HAVE_PRINTF_QD) */
+# define LLF		"%lld"
+# define LLFP(x)	"%" x "lld"
+# define LLT		long long
+# define ULLF		"%llu"
+# define ULLFP(x)	"%" x "llu"
+# define ULLT		unsigned long long
+#endif /* !defined(HAVE_PRINTF_QD) */
+#endif

Added: vendor/NetBSD/tnftp/20100108/src/ruserpass.c
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/ruserpass.c	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/ruserpass.c	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,325 @@
+/*	$NetBSD: ruserpass.c,v 1.8 2007/08/06 04:33:24 lukem Exp $	*/
+/*	from	NetBSD: ruserpass.c,v 1.33 2007/04/17 05:52:04 lukem Exp	*/
+
+/*
+ * Copyright (c) 1985, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "tnftp.h"
+
+#if 0	/* tnftp */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ruserpass.c	8.4 (Berkeley) 4/27/95";
+#else
+__RCSID(" NetBSD: ruserpass.c,v 1.33 2007/04/17 05:52:04 lukem Exp  ");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#endif	/* tnftp */
+
+#include "ftp_var.h"
+
+static	int token(void);
+static	FILE *cfile;
+
+#define	DEFAULT	1
+#define	LOGIN	2
+#define	PASSWD	3
+#define	ACCOUNT	4
+#define	MACDEF	5
+#define	ID	10
+#define	MACH	11
+
+static char tokval[100];
+
+static struct toktab {
+	const char *tokstr;
+	int tval;
+} toktab[] = {
+	{ "default",	DEFAULT },
+	{ "login",	LOGIN },
+	{ "password",	PASSWD },
+	{ "passwd",	PASSWD },
+	{ "account",	ACCOUNT },
+	{ "machine",	MACH },
+	{ "macdef",	MACDEF },
+	{ NULL,		0 }
+};
+
+int
+ruserpass(const char *host, char **aname, char **apass, char **aacct)
+{
+	char *tmp;
+	const char *mydomain;
+	char myname[MAXHOSTNAMELEN + 1];
+	int t, i, c, usedefault = 0;
+	struct stat stb;
+
+	if (netrc[0] == '\0')
+		return (0);
+	cfile = fopen(netrc, "r");
+	if (cfile == NULL) {
+		if (errno != ENOENT)
+			warn("Can't read `%s'", netrc);
+		return (0);
+	}
+	if (gethostname(myname, sizeof(myname)) < 0)
+		myname[0] = '\0';
+	myname[sizeof(myname) - 1] = '\0';
+	if ((mydomain = strchr(myname, '.')) == NULL)
+		mydomain = "";
+ next:
+	while ((t = token()) > 0) switch(t) {
+
+	case DEFAULT:
+		usedefault = 1;
+		/* FALL THROUGH */
+
+	case MACH:
+		if (!usedefault) {
+			if ((t = token()) == -1)
+				goto bad;
+			if (t != ID)
+				continue;
+			/*
+			 * Allow match either for user's input host name
+			 * or official hostname.  Also allow match of
+			 * incompletely-specified host in local domain.
+			 */
+			if (strcasecmp(host, tokval) == 0)
+				goto match;
+			if (strcasecmp(hostname, tokval) == 0)
+				goto match;
+			if ((tmp = strchr(hostname, '.')) != NULL &&
+			    strcasecmp(tmp, mydomain) == 0 &&
+			    strncasecmp(hostname, tokval, tmp-hostname) == 0 &&
+			    tokval[tmp - hostname] == '\0')
+				goto match;
+			if ((tmp = strchr(host, '.')) != NULL &&
+			    strcasecmp(tmp, mydomain) == 0 &&
+			    strncasecmp(host, tokval, tmp - host) == 0 &&
+			    tokval[tmp - host] == '\0')
+				goto match;
+			continue;
+		}
+	match:
+		while ((t = token()) > 0 &&
+		    t != MACH && t != DEFAULT) switch(t) {
+
+		case LOGIN:
+			if ((t = token()) == -1)
+				goto bad;
+			if (t) {
+				if (*aname == NULL)
+					*aname = ftp_strdup(tokval);
+				else {
+					if (strcmp(*aname, tokval))
+						goto next;
+				}
+			}
+			break;
+		case PASSWD:
+			if ((*aname == NULL || strcmp(*aname, "anonymous")) &&
+			    fstat(fileno(cfile), &stb) >= 0 &&
+			    (stb.st_mode & 077) != 0) {
+	warnx("Error: .netrc file is readable by others");
+	warnx("Remove password or make file unreadable by others");
+				goto bad;
+			}
+			if ((t = token()) == -1)
+				goto bad;
+			if (t && *apass == NULL)
+				*apass = ftp_strdup(tokval);
+			break;
+		case ACCOUNT:
+			if (fstat(fileno(cfile), &stb) >= 0
+			    && (stb.st_mode & 077) != 0) {
+	warnx("Error: .netrc file is readable by others");
+	warnx("Remove account or make file unreadable by others");
+				goto bad;
+			}
+			if ((t = token()) == -1)
+				goto bad;
+			if (t && *aacct == NULL)
+				*aacct = ftp_strdup(tokval);
+			break;
+		case MACDEF:
+			if (proxy) {
+				(void)fclose(cfile);
+				return (0);
+			}
+			while ((c = getc(cfile)) != EOF)
+				if (c != ' ' && c != '\t')
+					break;
+			if (c == EOF || c == '\n') {
+				fputs("Missing macdef name argument.\n",
+				    ttyout);
+				goto bad;
+			}
+			if (macnum == 16) {
+				fputs(
+			    "Limit of 16 macros have already been defined.\n",
+				    ttyout);
+				goto bad;
+			}
+			tmp = macros[macnum].mac_name;
+			*tmp++ = c;
+			for (i = 0; i < 8 && (c = getc(cfile)) != EOF &&
+			    !isspace(c); ++i) {
+				*tmp++ = c;
+			}
+			if (c == EOF) {
+				fputs(
+			    "Macro definition missing null line terminator.\n",
+				    ttyout);
+				goto bad;
+			}
+			*tmp = '\0';
+			if (c != '\n') {
+				while ((c = getc(cfile)) != EOF && c != '\n');
+			}
+			if (c == EOF) {
+				fputs(
+			    "Macro definition missing null line terminator.\n",
+				    ttyout);
+				goto bad;
+			}
+			if (macnum == 0) {
+				macros[macnum].mac_start = macbuf;
+			}
+			else {
+				macros[macnum].mac_start =
+				    macros[macnum-1].mac_end + 1;
+			}
+			tmp = macros[macnum].mac_start;
+			while (tmp != macbuf + 4096) {
+				if ((c = getc(cfile)) == EOF) {
+					fputs(
+			    "Macro definition missing null line terminator.\n",
+					    ttyout);
+					goto bad;
+				}
+				*tmp = c;
+				if (*tmp == '\n') {
+					if (tmp == macros[macnum].mac_start) {
+						macros[macnum++].mac_end = tmp;
+						break;
+					} else if (*(tmp - 1) == '\0') {
+						macros[macnum++].mac_end =
+						    tmp - 1;
+						break;
+					}
+					*tmp = '\0';
+				}
+				tmp++;
+			}
+			if (tmp == macbuf + 4096) {
+				fputs("4K macro buffer exceeded.\n",
+				    ttyout);
+				goto bad;
+			}
+			break;
+		default:
+			warnx("Unknown .netrc keyword `%s'", tokval);
+			break;
+		}
+		goto done;
+	}
+ done:
+	if (t == -1)
+		goto bad;
+	(void)fclose(cfile);
+	return (0);
+ bad:
+	(void)fclose(cfile);
+	return (-1);
+}
+
+static int
+token(void)
+{
+	char *cp;
+	int c;
+	struct toktab *t;
+
+	if (feof(cfile) || ferror(cfile))
+		return (0);
+	while ((c = getc(cfile)) != EOF &&
+	    (c == '\n' || c == '\t' || c == ' ' || c == ','))
+		continue;
+	if (c == EOF)
+		return (0);
+	cp = tokval;
+	if (c == '"') {
+		while ((c = getc(cfile)) != EOF && c != '"') {
+			if (c == '\\')
+				if ((c = getc(cfile)) == EOF)
+					break;
+			*cp++ = c;
+			if (cp == tokval + sizeof(tokval)) {
+				warnx("Token in .netrc too long");
+				return (-1);
+			}
+		}
+	} else {
+		*cp++ = c;
+		while ((c = getc(cfile)) != EOF
+		    && c != '\n' && c != '\t' && c != ' ' && c != ',') {
+			if (c == '\\')
+				if ((c = getc(cfile)) == EOF)
+					break;
+			*cp++ = c;
+			if (cp == tokval + sizeof(tokval)) {
+				warnx("Token in .netrc too long");
+				return (-1);
+			}
+		}
+	}
+	*cp = 0;
+	if (tokval[0] == 0)
+		return (0);
+	for (t = toktab; t->tokstr; t++)
+		if (!strcmp(t->tokstr, tokval))
+			return (t->tval);
+	return (ID);
+}

Added: vendor/NetBSD/tnftp/20100108/src/util.c
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/util.c	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/util.c	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,1580 @@
+/*	$NetBSD: util.c,v 1.21 2009/11/15 10:12:37 lukem Exp $	*/
+/*	from	NetBSD: util.c,v 1.152 2009/07/13 19:05:41 roy Exp	*/
+
+/*-
+ * Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1985, 1989, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "tnftp.h"
+
+#if 0	/* tnftp */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID(" NetBSD: util.c,v 1.152 2009/07/13 19:05:41 roy Exp  ");
+#endif /* not lint */
+
+/*
+ * FTP User Program -- Misc support routines
+ */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/ftp.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <glob.h>
+#include <signal.h>
+#include <libgen.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+
+#endif	/* tnftp */
+
+#include "ftp_var.h"
+
+/*
+ * Connect to peer server and auto-login, if possible.
+ */
+void
+setpeer(int argc, char *argv[])
+{
+	char *host;
+	const char *port;
+
+	if (argc == 0)
+		goto usage;
+	if (connected) {
+		fprintf(ttyout, "Already connected to %s, use close first.\n",
+		    hostname);
+		code = -1;
+		return;
+	}
+	if (argc < 2)
+		(void)another(&argc, &argv, "to");
+	if (argc < 2 || argc > 3) {
+ usage:
+		UPRINTF("usage: %s host-name [port]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (gatemode)
+		port = gateport;
+	else
+		port = ftpport;
+	if (argc > 2)
+		port = argv[2];
+
+	if (gatemode) {
+		if (gateserver == NULL || *gateserver == '\0')
+			errx(1, "main: gateserver not defined");
+		host = hookup(gateserver, port);
+	} else
+		host = hookup(argv[1], port);
+
+	if (host) {
+		if (gatemode && verbose) {
+			fprintf(ttyout,
+			    "Connecting via pass-through server %s\n",
+			    gateserver);
+		}
+
+		connected = 1;
+		/*
+		 * Set up defaults for FTP.
+		 */
+		(void)strlcpy(typename, "ascii", sizeof(typename));
+		type = TYPE_A;
+		curtype = TYPE_A;
+		(void)strlcpy(formname, "non-print", sizeof(formname));
+		form = FORM_N;
+		(void)strlcpy(modename, "stream", sizeof(modename));
+		mode = MODE_S;
+		(void)strlcpy(structname, "file", sizeof(structname));
+		stru = STRU_F;
+		(void)strlcpy(bytename, "8", sizeof(bytename));
+		bytesize = 8;
+		if (autologin)
+			(void)ftp_login(argv[1], NULL, NULL);
+	}
+}
+
+static void
+parse_feat(const char *fline)
+{
+
+			/*
+			 * work-around broken ProFTPd servers that can't
+			 * even obey RFC2389.
+			 */
+	while (*fline && isspace((int)*fline))
+		fline++;
+
+	if (strcasecmp(fline, "MDTM") == 0)
+		features[FEAT_MDTM] = 1;
+	else if (strncasecmp(fline, "MLST", sizeof("MLST") - 1) == 0) {
+		features[FEAT_MLST] = 1;
+	} else if (strcasecmp(fline, "REST STREAM") == 0)
+		features[FEAT_REST_STREAM] = 1;
+	else if (strcasecmp(fline, "SIZE") == 0)
+		features[FEAT_SIZE] = 1;
+	else if (strcasecmp(fline, "TVFS") == 0)
+		features[FEAT_TVFS] = 1;
+}
+
+/*
+ * Determine the remote system type (SYST) and features (FEAT).
+ * Call after a successful login (i.e, connected = -1)
+ */
+void
+getremoteinfo(void)
+{
+	int overbose, i;
+
+	overbose = verbose;
+	if (ftp_debug == 0)
+		verbose = -1;
+
+			/* determine remote system type */
+	if (command("SYST") == COMPLETE) {
+		if (overbose) {
+			char *cp, c;
+
+			c = 0;
+			cp = strchr(reply_string + 4, ' ');
+			if (cp == NULL)
+				cp = strchr(reply_string + 4, '\r');
+			if (cp) {
+				if (cp[-1] == '.')
+					cp--;
+				c = *cp;
+				*cp = '\0';
+			}
+
+			fprintf(ttyout, "Remote system type is %s.\n",
+			    reply_string + 4);
+			if (cp)
+				*cp = c;
+		}
+		if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
+			if (proxy)
+				unix_proxy = 1;
+			else
+				unix_server = 1;
+			/*
+			 * Set type to 0 (not specified by user),
+			 * meaning binary by default, but don't bother
+			 * telling server.  We can use binary
+			 * for text files unless changed by the user.
+			 */
+			type = 0;
+			(void)strlcpy(typename, "binary", sizeof(typename));
+			if (overbose)
+			    fprintf(ttyout,
+				"Using %s mode to transfer files.\n",
+				typename);
+		} else {
+			if (proxy)
+				unix_proxy = 0;
+			else
+				unix_server = 0;
+			if (overbose &&
+			    !strncmp(reply_string, "215 TOPS20", 10))
+				fputs(
+"Remember to set tenex mode when transferring binary files from this machine.\n",
+				    ttyout);
+		}
+	}
+
+			/* determine features (if any) */
+	for (i = 0; i < FEAT_max; i++)
+		features[i] = -1;
+	reply_callback = parse_feat;
+	if (command("FEAT") == COMPLETE) {
+		for (i = 0; i < FEAT_max; i++) {
+			if (features[i] == -1)
+				features[i] = 0;
+		}
+		features[FEAT_FEAT] = 1;
+	} else
+		features[FEAT_FEAT] = 0;
+#ifndef NO_DEBUG
+	if (ftp_debug) {
+#define DEBUG_FEAT(x) fprintf(ttyout, "features[" #x "] = %d\n", features[(x)])
+		DEBUG_FEAT(FEAT_FEAT);
+		DEBUG_FEAT(FEAT_MDTM);
+		DEBUG_FEAT(FEAT_MLST);
+		DEBUG_FEAT(FEAT_REST_STREAM);
+		DEBUG_FEAT(FEAT_SIZE);
+		DEBUG_FEAT(FEAT_TVFS);
+#undef DEBUG_FEAT
+	}
+#endif
+	reply_callback = NULL;
+
+	verbose = overbose;
+}
+
+/*
+ * Reset the various variables that indicate connection state back to
+ * disconnected settings.
+ * The caller is responsible for issuing any commands to the remote server
+ * to perform a clean shutdown before this is invoked.
+ */
+void
+cleanuppeer(void)
+{
+
+	if (cout)
+		(void)fclose(cout);
+	cout = NULL;
+	connected = 0;
+	unix_server = 0;
+	unix_proxy = 0;
+			/*
+			 * determine if anonftp was specifically set with -a
+			 * (1), or implicitly set by auto_fetch() (2). in the
+			 * latter case, disable after the current xfer
+			 */
+	if (anonftp == 2)
+		anonftp = 0;
+	data = -1;
+	epsv4bad = 0;
+	epsv6bad = 0;
+	if (username)
+		free(username);
+	username = NULL;
+	if (!proxy)
+		macnum = 0;
+}
+
+/*
+ * Top-level signal handler for interrupted commands.
+ */
+void
+intr(int signo)
+{
+
+	sigint_raised = 1;
+	alarmtimer(0);
+	if (fromatty)
+		write(fileno(ttyout), "\n", 1);
+	siglongjmp(toplevel, 1);
+}
+
+/*
+ * Signal handler for lost connections; cleanup various elements of
+ * the connection state, and call cleanuppeer() to finish it off.
+ */
+void
+lostpeer(int dummy)
+{
+	int oerrno = errno;
+
+	alarmtimer(0);
+	if (connected) {
+		if (cout != NULL) {
+			(void)shutdown(fileno(cout), 1+1);
+			(void)fclose(cout);
+			cout = NULL;
+		}
+		if (data >= 0) {
+			(void)shutdown(data, 1+1);
+			(void)close(data);
+			data = -1;
+		}
+		connected = 0;
+	}
+	pswitch(1);
+	if (connected) {
+		if (cout != NULL) {
+			(void)shutdown(fileno(cout), 1+1);
+			(void)fclose(cout);
+			cout = NULL;
+		}
+		connected = 0;
+	}
+	proxflag = 0;
+	pswitch(0);
+	cleanuppeer();
+	errno = oerrno;
+}
+
+
+/*
+ * Login to remote host, using given username & password if supplied.
+ * Return non-zero if successful.
+ */
+int
+ftp_login(const char *host, const char *luser, const char *lpass)
+{
+	char tmp[80];
+	char *fuser, *pass, *facct, *p;
+	char emptypass[] = "";
+	const char *errormsg;
+	int n, aflag, rval, nlen;
+
+	aflag = rval = 0;
+	fuser = pass = facct = NULL;
+	if (luser)
+		fuser = ftp_strdup(luser);
+	if (lpass)
+		pass = ftp_strdup(lpass);
+
+	DPRINTF("ftp_login: user `%s' pass `%s' host `%s'\n",
+	    STRorNULL(fuser), STRorNULL(pass), STRorNULL(host));
+
+	/*
+	 * Set up arguments for an anonymous FTP session, if necessary.
+	 */
+	if (anonftp) {
+		FREEPTR(fuser);
+		fuser = ftp_strdup("anonymous");	/* as per RFC1635 */
+		FREEPTR(pass);
+		pass = ftp_strdup(getoptionvalue("anonpass"));
+	}
+
+	if (ruserpass(host, &fuser, &pass, &facct) < 0) {
+		code = -1;
+		goto cleanup_ftp_login;
+	}
+
+	while (fuser == NULL) {
+		if (localname)
+			fprintf(ttyout, "Name (%s:%s): ", host, localname);
+		else
+			fprintf(ttyout, "Name (%s): ", host);
+		errormsg = NULL;
+		nlen = get_line(stdin, tmp, sizeof(tmp), &errormsg);
+		if (nlen < 0) {
+			fprintf(ttyout, "%s; %s aborted.\n", errormsg, "login");
+			code = -1;
+			goto cleanup_ftp_login;
+		} else if (nlen == 0) {
+			fuser = ftp_strdup(localname);
+		} else {
+			fuser = ftp_strdup(tmp);
+		}
+	}
+
+	if (gatemode) {
+		char *nuser;
+		size_t len;
+
+		len = strlen(fuser) + 1 + strlen(host) + 1;
+		nuser = ftp_malloc(len);
+		(void)strlcpy(nuser, fuser, len);
+		(void)strlcat(nuser, "@",  len);
+		(void)strlcat(nuser, host, len);
+		FREEPTR(fuser);
+		fuser = nuser;
+	}
+
+	n = command("USER %s", fuser);
+	if (n == CONTINUE) {
+		if (pass == NULL) {
+			p = getpass("Password: ");
+			if (p == NULL)
+				p = emptypass;
+			pass = ftp_strdup(p);
+			memset(p, 0, strlen(p));
+		}
+		n = command("PASS %s", pass);
+		memset(pass, 0, strlen(pass));
+	}
+	if (n == CONTINUE) {
+		aflag++;
+		if (facct == NULL) {
+			p = getpass("Account: ");
+			if (p == NULL)
+				p = emptypass;
+			facct = ftp_strdup(p);
+			memset(p, 0, strlen(p));
+		}
+		if (facct[0] == '\0') {
+			warnx("Login failed");
+			goto cleanup_ftp_login;
+		}
+		n = command("ACCT %s", facct);
+		memset(facct, 0, strlen(facct));
+	}
+	if ((n != COMPLETE) ||
+	    (!aflag && facct != NULL && command("ACCT %s", facct) != COMPLETE)) {
+		warnx("Login failed");
+		goto cleanup_ftp_login;
+	}
+	rval = 1;
+	username = ftp_strdup(fuser);
+	if (proxy)
+		goto cleanup_ftp_login;
+
+	connected = -1;
+	getremoteinfo();
+	for (n = 0; n < macnum; ++n) {
+		if (!strcmp("init", macros[n].mac_name)) {
+			(void)strlcpy(line, "$init", sizeof(line));
+			makeargv();
+			domacro(margc, margv);
+			break;
+		}
+	}
+	updatelocalcwd();
+	updateremotecwd();
+
+ cleanup_ftp_login:
+	FREEPTR(fuser);
+	if (pass != NULL)
+		memset(pass, 0, strlen(pass));
+	FREEPTR(pass);
+	if (facct != NULL)
+		memset(facct, 0, strlen(facct));
+	FREEPTR(facct);
+	return (rval);
+}
+
+/*
+ * `another' gets another argument, and stores the new argc and argv.
+ * It reverts to the top level (via intr()) on EOF/error.
+ *
+ * Returns false if no new arguments have been added.
+ */
+int
+another(int *pargc, char ***pargv, const char *aprompt)
+{
+	const char	*errormsg;
+	int		ret, nlen;
+	size_t		len;
+
+	len = strlen(line);
+	if (len >= sizeof(line) - 3) {
+		fputs("Sorry, arguments too long.\n", ttyout);
+		intr(0);
+	}
+	fprintf(ttyout, "(%s) ", aprompt);
+	line[len++] = ' ';
+	errormsg = NULL;
+	nlen = get_line(stdin, line + len, sizeof(line)-len, &errormsg);
+	if (nlen < 0) {
+		fprintf(ttyout, "%s; %s aborted.\n", errormsg, "operation");
+		intr(0);
+	}
+	len += nlen;
+	makeargv();
+	ret = margc > *pargc;
+	*pargc = margc;
+	*pargv = margv;
+	return (ret);
+}
+
+/*
+ * glob files given in argv[] from the remote server.
+ * if errbuf isn't NULL, store error messages there instead
+ * of writing to the screen.
+ */
+char *
+remglob(char *argv[], int doswitch, const char **errbuf)
+{
+	static char buf[MAXPATHLEN];
+	static FILE *ftemp = NULL;
+	static char **args;
+	char temp[MAXPATHLEN];
+	int oldverbose, oldhash, oldprogress, fd;
+	char *cp;
+	const char *rmode;
+	size_t len;
+
+	if (!mflag || !connected) {
+		if (!doglob)
+			args = NULL;
+		else {
+			if (ftemp) {
+				(void)fclose(ftemp);
+				ftemp = NULL;
+			}
+		}
+		return (NULL);
+	}
+	if (!doglob) {
+		if (args == NULL)
+			args = argv;
+		if ((cp = *++args) == NULL)
+			args = NULL;
+		return (cp);
+	}
+	if (ftemp == NULL) {
+		len = strlcpy(temp, tmpdir, sizeof(temp));
+		if (temp[len - 1] != '/')
+			(void)strlcat(temp, "/", sizeof(temp));
+		(void)strlcat(temp, TMPFILE, sizeof(temp));
+		if ((fd = mkstemp(temp)) < 0) {
+			warn("Unable to create temporary file `%s'", temp);
+			return (NULL);
+		}
+		close(fd);
+		oldverbose = verbose;
+		verbose = (errbuf != NULL) ? -1 : 0;
+		oldhash = hash;
+		oldprogress = progress;
+		hash = 0;
+		progress = 0;
+		if (doswitch)
+			pswitch(!proxy);
+		for (rmode = "w"; *++argv != NULL; rmode = "a")
+			recvrequest("NLST", temp, *argv, rmode, 0, 0);
+		if ((code / 100) != COMPLETE) {
+			if (errbuf != NULL)
+				*errbuf = reply_string;
+		}
+		if (doswitch)
+			pswitch(!proxy);
+		verbose = oldverbose;
+		hash = oldhash;
+		progress = oldprogress;
+		ftemp = fopen(temp, "r");
+		(void)unlink(temp);
+		if (ftemp == NULL) {
+			if (errbuf == NULL)
+				warnx("Can't find list of remote files");
+			else
+				*errbuf =
+				    "Can't find list of remote files";
+			return (NULL);
+		}
+	}
+	if (fgets(buf, sizeof(buf), ftemp) == NULL) {
+		(void)fclose(ftemp);
+		ftemp = NULL;
+		return (NULL);
+	}
+	if ((cp = strchr(buf, '\n')) != NULL)
+		*cp = '\0';
+	return (buf);
+}
+
+/*
+ * Glob a local file name specification with the expectation of a single
+ * return value. Can't control multiple values being expanded from the
+ * expression, we return only the first.
+ * Returns NULL on error, or a pointer to a buffer containing the filename
+ * that's the caller's responsiblity to free(3) when finished with.
+ */
+char *
+globulize(const char *pattern)
+{
+	glob_t gl;
+	int flags;
+	char *p;
+
+	if (!doglob)
+		return (ftp_strdup(pattern));
+
+	flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
+	memset(&gl, 0, sizeof(gl));
+	if (glob(pattern, flags, NULL, &gl) || gl.gl_pathc == 0) {
+		warnx("Glob pattern `%s' not found", pattern);
+		globfree(&gl);
+		return (NULL);
+	}
+	p = ftp_strdup(gl.gl_pathv[0]);
+	globfree(&gl);
+	return (p);
+}
+
+/*
+ * determine size of remote file
+ */
+off_t
+remotesize(const char *file, int noisy)
+{
+	int overbose, r;
+	off_t size;
+
+	overbose = verbose;
+	size = -1;
+	if (ftp_debug == 0)
+		verbose = -1;
+	if (! features[FEAT_SIZE]) {
+		if (noisy)
+			fprintf(ttyout,
+			    "SIZE is not supported by remote server.\n");
+		goto cleanup_remotesize;
+	}
+	r = command("SIZE %s", file);
+	if (r == COMPLETE) {
+		char *cp, *ep;
+
+		cp = strchr(reply_string, ' ');
+		if (cp != NULL) {
+			cp++;
+			size = STRTOLL(cp, &ep, 10);
+			if (*ep != '\0' && !isspace((unsigned char)*ep))
+				size = -1;
+		}
+	} else {
+		if (r == ERROR && code == 500 && features[FEAT_SIZE] == -1)
+			features[FEAT_SIZE] = 0;
+		if (noisy && ftp_debug == 0) {
+			fputs(reply_string, ttyout);
+			putc('\n', ttyout);
+		}
+	}
+ cleanup_remotesize:
+	verbose = overbose;
+	return (size);
+}
+
+/*
+ * determine last modification time (in GMT) of remote file
+ */
+time_t
+remotemodtime(const char *file, int noisy)
+{
+	int	overbose, ocode, r;
+	time_t	rtime;
+
+	overbose = verbose;
+	ocode = code;
+	rtime = -1;
+	if (ftp_debug == 0)
+		verbose = -1;
+	if (! features[FEAT_MDTM]) {
+		if (noisy)
+			fprintf(ttyout,
+			    "MDTM is not supported by remote server.\n");
+		goto cleanup_parse_time;
+	}
+	r = command("MDTM %s", file);
+	if (r == COMPLETE) {
+		struct tm timebuf;
+		char *timestr, *frac;
+
+		/*
+		 * time-val = 14DIGIT [ "." 1*DIGIT ]
+		 *		YYYYMMDDHHMMSS[.sss]
+		 * mdtm-response = "213" SP time-val CRLF / error-response
+		 */
+		timestr = reply_string + 4;
+
+					/*
+					 * parse fraction.
+					 * XXX: ignored for now
+					 */
+		frac = strchr(timestr, '\r');
+		if (frac != NULL)
+			*frac = '\0';
+		frac = strchr(timestr, '.');
+		if (frac != NULL)
+			*frac++ = '\0';
+		if (strlen(timestr) == 15 && strncmp(timestr, "191", 3) == 0) {
+			/*
+			 * XXX:	Workaround for lame ftpd's that return
+			 *	`19100' instead of `2000'
+			 */
+			fprintf(ttyout,
+	    "Y2K warning! Incorrect time-val `%s' received from server.\n",
+			    timestr);
+			timestr++;
+			timestr[0] = '2';
+			timestr[1] = '0';
+			fprintf(ttyout, "Converted to `%s'\n", timestr);
+		}
+		memset(&timebuf, 0, sizeof(timebuf));
+		if (strlen(timestr) != 14 ||
+		    (strptime(timestr, "%Y%m%d%H%M%S", &timebuf) == NULL)) {
+ bad_parse_time:
+			fprintf(ttyout, "Can't parse time `%s'.\n", timestr);
+			goto cleanup_parse_time;
+		}
+		timebuf.tm_isdst = -1;
+		rtime = timegm(&timebuf);
+		if (rtime == -1) {
+			if (noisy || ftp_debug != 0)
+				goto bad_parse_time;
+			else
+				goto cleanup_parse_time;
+		} else {
+			DPRINTF("remotemodtime: parsed date `%s' as " LLF
+			    ", %s",
+			    timestr, (LLT)rtime,
+			    rfc2822time(localtime(&rtime)));
+		}
+	} else {
+		if (r == ERROR && code == 500 && features[FEAT_MDTM] == -1)
+			features[FEAT_MDTM] = 0;
+		if (noisy && ftp_debug == 0) {
+			fputs(reply_string, ttyout);
+			putc('\n', ttyout);
+		}
+	}
+ cleanup_parse_time:
+	verbose = overbose;
+	if (rtime == -1)
+		code = ocode;
+	return (rtime);
+}
+
+/*
+ * Format tm in an RFC2822 compatible manner, with a trailing \n.
+ * Returns a pointer to a static string containing the result.
+ */
+const char *
+rfc2822time(const struct tm *tm)
+{
+	static char result[50];
+
+	if (strftime(result, sizeof(result),
+	    "%a, %d %b %Y %H:%M:%S %z\n", tm) == 0)
+		errx(1, "Can't convert RFC2822 time: buffer too small");
+	return result;
+}
+
+/*
+ * Update global `localcwd', which contains the state of the local cwd
+ */
+void
+updatelocalcwd(void)
+{
+
+	if (getcwd(localcwd, sizeof(localcwd)) == NULL)
+		localcwd[0] = '\0';
+	DPRINTF("updatelocalcwd: got `%s'\n", localcwd);
+}
+
+/*
+ * Update global `remotecwd', which contains the state of the remote cwd
+ */
+void
+updateremotecwd(void)
+{
+	int	 overbose, ocode;
+	size_t	 i;
+	char	*cp;
+
+	overbose = verbose;
+	ocode = code;
+	if (ftp_debug == 0)
+		verbose = -1;
+	if (command("PWD") != COMPLETE)
+		goto badremotecwd;
+	cp = strchr(reply_string, ' ');
+	if (cp == NULL || cp[0] == '\0' || cp[1] != '"')
+		goto badremotecwd;
+	cp += 2;
+	for (i = 0; *cp && i < sizeof(remotecwd) - 1; i++, cp++) {
+		if (cp[0] == '"') {
+			if (cp[1] == '"')
+				cp++;
+			else
+				break;
+		}
+		remotecwd[i] = *cp;
+	}
+	remotecwd[i] = '\0';
+	DPRINTF("updateremotecwd: got `%s'\n", remotecwd);
+	goto cleanupremotecwd;
+ badremotecwd:
+	remotecwd[0]='\0';
+ cleanupremotecwd:
+	verbose = overbose;
+	code = ocode;
+}
+
+/*
+ * Ensure file is in or under dir.
+ * Returns 1 if so, 0 if not (or an error occurred).
+ */
+int
+fileindir(const char *file, const char *dir)
+{
+	char	parentdirbuf[PATH_MAX+1], *parentdir;
+	char	realdir[PATH_MAX+1];
+	size_t	dirlen;
+
+					/* determine parent directory of file */
+	(void)strlcpy(parentdirbuf, file, sizeof(parentdirbuf));
+	parentdir = dirname(parentdirbuf);
+	if (strcmp(parentdir, ".") == 0)
+		return 1;		/* current directory is ok */
+
+					/* find the directory */
+	if (realpath(parentdir, realdir) == NULL) {
+		warn("Unable to determine real path of `%s'", parentdir);
+		return 0;
+	}
+	if (realdir[0] != '/')		/* relative result is ok */
+		return 1;
+	dirlen = strlen(dir);
+	if (strncmp(realdir, dir, dirlen) == 0 &&
+	    (realdir[dirlen] == '/' || realdir[dirlen] == '\0'))
+		return 1;
+	return 0;
+}
+
+/*
+ * List words in stringlist, vertically arranged
+ */
+void
+list_vertical(StringList *sl)
+{
+	size_t i, j;
+	size_t columns, lines;
+	char *p;
+	size_t w, width;
+
+	width = 0;
+
+	for (i = 0 ; i < sl->sl_cur ; i++) {
+		w = strlen(sl->sl_str[i]);
+		if (w > width)
+			width = w;
+	}
+	width = (width + 8) &~ 7;
+
+	columns = ttywidth / width;
+	if (columns == 0)
+		columns = 1;
+	lines = (sl->sl_cur + columns - 1) / columns;
+	for (i = 0; i < lines; i++) {
+		for (j = 0; j < columns; j++) {
+			p = sl->sl_str[j * lines + i];
+			if (p)
+				fputs(p, ttyout);
+			if (j * lines + i + lines >= sl->sl_cur) {
+				putc('\n', ttyout);
+				break;
+			}
+			if (p) {
+				w = strlen(p);
+				while (w < width) {
+					w = (w + 8) &~ 7;
+					(void)putc('\t', ttyout);
+				}
+			}
+		}
+	}
+}
+
+/*
+ * Update the global ttywidth value, using TIOCGWINSZ.
+ */
+void
+setttywidth(int a)
+{
+	struct winsize winsize;
+	int oerrno = errno;
+
+	if (ioctl(fileno(ttyout), TIOCGWINSZ, &winsize) != -1 &&
+	    winsize.ws_col != 0)
+		ttywidth = winsize.ws_col;
+	else
+		ttywidth = 80;
+	errno = oerrno;
+}
+
+/*
+ * Change the rate limit up (SIGUSR1) or down (SIGUSR2)
+ */
+void
+crankrate(int sig)
+{
+
+	switch (sig) {
+	case SIGUSR1:
+		if (rate_get)
+			rate_get += rate_get_incr;
+		if (rate_put)
+			rate_put += rate_put_incr;
+		break;
+	case SIGUSR2:
+		if (rate_get && rate_get > rate_get_incr)
+			rate_get -= rate_get_incr;
+		if (rate_put && rate_put > rate_put_incr)
+			rate_put -= rate_put_incr;
+		break;
+	default:
+		err(1, "crankrate invoked with unknown signal: %d", sig);
+	}
+}
+
+
+/*
+ * Setup or cleanup EditLine structures
+ */
+#ifndef NO_EDITCOMPLETE
+void
+controlediting(void)
+{
+	if (editing && el == NULL && hist == NULL) {
+		HistEvent ev;
+		int editmode;
+
+		el = el_init(getprogname(), stdin, ttyout, stderr);
+		/* init editline */
+		hist = history_init();		/* init the builtin history */
+		history(hist, &ev, H_SETSIZE, 100);/* remember 100 events */
+		el_set(el, EL_HIST, history, hist);	/* use history */
+
+		el_set(el, EL_EDITOR, "emacs");	/* default editor is emacs */
+		el_set(el, EL_PROMPT, prompt);	/* set the prompt functions */
+		el_set(el, EL_RPROMPT, rprompt);
+
+		/* add local file completion, bind to TAB */
+		el_set(el, EL_ADDFN, "ftp-complete",
+		    "Context sensitive argument completion",
+		    complete);
+		el_set(el, EL_BIND, "^I", "ftp-complete", NULL);
+		el_source(el, NULL);	/* read ~/.editrc */
+		if ((el_get(el, EL_EDITMODE, &editmode) != -1) && editmode == 0)
+			editing = 0;	/* the user doesn't want editing,
+					 * so disable, and let statement
+					 * below cleanup */
+		else
+			el_set(el, EL_SIGNAL, 1);
+	}
+	if (!editing) {
+		if (hist) {
+			history_end(hist);
+			hist = NULL;
+		}
+		if (el) {
+			el_end(el);
+			el = NULL;
+		}
+	}
+}
+#endif /* !NO_EDITCOMPLETE */
+
+/*
+ * Convert the string `arg' to an int, which may have an optional SI suffix
+ * (`b', `k', `m', `g'). Returns the number for success, -1 otherwise.
+ */
+int
+strsuftoi(const char *arg)
+{
+	char *cp;
+	long val;
+
+	if (!isdigit((unsigned char)arg[0]))
+		return (-1);
+
+	val = strtol(arg, &cp, 10);
+	if (cp != NULL) {
+		if (cp[0] != '\0' && cp[1] != '\0')
+			 return (-1);
+		switch (tolower((unsigned char)cp[0])) {
+		case '\0':
+		case 'b':
+			break;
+		case 'k':
+			val <<= 10;
+			break;
+		case 'm':
+			val <<= 20;
+			break;
+		case 'g':
+			val <<= 30;
+			break;
+		default:
+			return (-1);
+		}
+	}
+	if (val < 0 || val > INT_MAX)
+		return (-1);
+
+	return (val);
+}
+
+/*
+ * Set up socket buffer sizes before a connection is made.
+ */
+void
+setupsockbufsize(int sock)
+{
+	socklen_t slen;
+
+	if (0 == rcvbuf_size) {
+		slen = sizeof(rcvbuf_size);
+		if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF,
+		    (void *)&rcvbuf_size, &slen) == -1)
+			err(1, "Unable to determine rcvbuf size");
+		if (rcvbuf_size <= 0)
+			rcvbuf_size = 8 * 1024;
+		if (rcvbuf_size > 8 * 1024 * 1024)
+			rcvbuf_size = 8 * 1024 * 1024;
+		DPRINTF("setupsockbufsize: rcvbuf_size determined as %d\n",
+		    rcvbuf_size);
+	}
+	if (0 == sndbuf_size) {
+		slen = sizeof(sndbuf_size);
+		if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF,
+		    (void *)&sndbuf_size, &slen) == -1)
+			err(1, "Unable to determine sndbuf size");
+		if (sndbuf_size <= 0)
+			sndbuf_size = 8 * 1024;
+		if (sndbuf_size > 8 * 1024 * 1024)
+			sndbuf_size = 8 * 1024 * 1024;
+		DPRINTF("setupsockbufsize: sndbuf_size determined as %d\n",
+		    sndbuf_size);
+	}
+
+	if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
+	    (void *)&sndbuf_size, sizeof(sndbuf_size)) == -1)
+		warn("Unable to set sndbuf size %d", sndbuf_size);
+
+	if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
+	    (void *)&rcvbuf_size, sizeof(rcvbuf_size)) == -1)
+		warn("Unable to set rcvbuf size %d", rcvbuf_size);
+}
+
+/*
+ * Copy characters from src into dst, \ quoting characters that require it
+ */
+void
+ftpvis(char *dst, size_t dstlen, const char *src, size_t srclen)
+{
+	size_t	di, si;
+
+	for (di = si = 0;
+	    src[si] != '\0' && di < dstlen && si < srclen;
+	    di++, si++) {
+		switch (src[si]) {
+		case '\\':
+		case ' ':
+		case '\t':
+		case '\r':
+		case '\n':
+		case '"':
+			dst[di++] = '\\';
+			if (di >= dstlen)
+				break;
+			/* FALLTHROUGH */
+		default:
+			dst[di] = src[si];
+		}
+	}
+	dst[di] = '\0';
+}
+
+/*
+ * Copy src into buf (which is len bytes long), expanding % sequences.
+ */
+void
+formatbuf(char *buf, size_t len, const char *src)
+{
+	const char	*p, *p2, *q;
+	size_t		 i;
+	int		 op, updirs, pdirs;
+
+#define ADDBUF(x) do { \
+		if (i >= len - 1) \
+			goto endbuf; \
+		buf[i++] = (x); \
+	} while (0)
+
+	p = src;
+	for (i = 0; *p; p++) {
+		if (*p != '%') {
+			ADDBUF(*p);
+			continue;
+		}
+		p++;
+
+		switch (op = *p) {
+
+		case '/':
+		case '.':
+		case 'c':
+			p2 = connected ? remotecwd : "";
+			updirs = pdirs = 0;
+
+			/* option to determine fixed # of dirs from path */
+			if (op == '.' || op == 'c') {
+				int skip;
+
+				q = p2;
+				while (*p2)		/* calc # of /'s */
+					if (*p2++ == '/')
+						updirs++;
+				if (p[1] == '0') {	/* print <x> or ... */
+					pdirs = 1;
+					p++;
+				}
+				if (p[1] >= '1' && p[1] <= '9') {
+							/* calc # to skip  */
+					skip = p[1] - '0';
+					p++;
+				} else
+					skip = 1;
+
+				updirs -= skip;
+				while (skip-- > 0) {
+					while ((p2 > q) && (*p2 != '/'))
+						p2--;	/* back up */
+					if (skip && p2 > q)
+						p2--;
+				}
+				if (*p2 == '/' && p2 != q)
+					p2++;
+			}
+
+			if (updirs > 0 && pdirs) {
+				if (i >= len - 5)
+					break;
+				if (op == '.') {
+					ADDBUF('.');
+					ADDBUF('.');
+					ADDBUF('.');
+				} else {
+					ADDBUF('/');
+					ADDBUF('<');
+					if (updirs > 9) {
+						ADDBUF('9');
+						ADDBUF('+');
+					} else
+						ADDBUF('0' + updirs);
+					ADDBUF('>');
+				}
+			}
+			for (; *p2; p2++)
+				ADDBUF(*p2);
+			break;
+
+		case 'M':
+		case 'm':
+			for (p2 = connected && hostname ? hostname : "-";
+			    *p2 ; p2++) {
+				if (op == 'm' && *p2 == '.')
+					break;
+				ADDBUF(*p2);
+			}
+			break;
+
+		case 'n':
+			for (p2 = connected ? username : "-"; *p2 ; p2++)
+				ADDBUF(*p2);
+			break;
+
+		case '%':
+			ADDBUF('%');
+			break;
+
+		default:		/* display unknown codes literally */
+			ADDBUF('%');
+			ADDBUF(op);
+			break;
+
+		}
+	}
+ endbuf:
+	buf[i] = '\0';
+}
+
+/*
+ * Determine if given string is an IPv6 address or not.
+ * Return 1 for yes, 0 for no
+ */
+int
+isipv6addr(const char *addr)
+{
+	int rv = 0;
+#ifdef INET6
+	struct addrinfo hints, *res;
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_INET6;
+	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
+	hints.ai_flags = AI_NUMERICHOST;
+	if (getaddrinfo(addr, "0", &hints, &res) != 0)
+		rv = 0;
+	else {
+		rv = 1;
+		freeaddrinfo(res);
+	}
+	DPRINTF("isipv6addr: got %d for %s\n", rv, addr);
+#endif
+	return (rv == 1) ? 1 : 0;
+}
+
+/*
+ * Read a line from the FILE stream into buf/buflen using fgets(), so up
+ * to buflen-1 chars will be read and the result will be NUL terminated.
+ * If the line has a trailing newline it will be removed.
+ * If the line is too long, excess characters will be read until
+ * newline/EOF/error.
+ * If EOF/error occurs or a too-long line is encountered and errormsg
+ * isn't NULL, it will be changed to a description of the problem.
+ * (The EOF message has a leading \n for cosmetic purposes).
+ * Returns:
+ *	>=0	length of line (excluding trailing newline) if all ok
+ *	-1	error occurred
+ *	-2	EOF encountered
+ *	-3	line was too long
+ */
+int
+get_line(FILE *stream, char *buf, size_t buflen, const char **errormsg)
+{
+	int	rv, ch;
+	size_t	len;
+
+	if (fgets(buf, buflen, stream) == NULL) {
+		if (feof(stream)) {	/* EOF */
+			rv = -2;
+			if (errormsg)
+				*errormsg = "\nEOF received";
+		} else  {		/* error */
+			rv = -1;
+			if (errormsg)
+				*errormsg = "Error encountered";
+		}
+		clearerr(stream);
+		return rv;
+	}
+	len = strlen(buf);
+	if (buf[len-1] == '\n') {	/* clear any trailing newline */
+		buf[--len] = '\0';
+	} else if (len == buflen-1) {	/* line too long */
+		while ((ch = getchar()) != '\n' && ch != EOF)
+			continue;
+		if (errormsg)
+			*errormsg = "Input line is too long";
+		clearerr(stream);
+		return -3;
+	}
+	if (errormsg)
+		*errormsg = NULL;
+	return len;
+}
+
+/*
+ * Internal version of connect(2); sets socket buffer sizes,
+ * binds to a specific local address (if set), and
+ * supports a connection timeout using a non-blocking connect(2) with
+ * a poll(2).
+ * Socket fcntl flags are temporarily updated to include O_NONBLOCK;
+ * these will not be reverted on connection failure.
+ * Returns 0 on success, or -1 upon failure (with an appropriate
+ * error message displayed.)
+ */
+int
+ftp_connect(int sock, const struct sockaddr *name, socklen_t namelen)
+{
+	int		flags, rv, timeout, error;
+	socklen_t	slen;
+	struct timeval	endtime, now, td;
+	struct pollfd	pfd[1];
+	char		hname[NI_MAXHOST];
+	char		sname[NI_MAXSERV];
+
+	setupsockbufsize(sock);
+	if (getnameinfo(name, namelen,
+	    hname, sizeof(hname), sname, sizeof(sname),
+	    NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
+		strlcpy(hname, "?", sizeof(hname));
+		strlcpy(sname, "?", sizeof(sname));
+	}
+
+	if (bindai != NULL) {			/* bind to specific addr */
+		struct addrinfo *ai;
+
+		for (ai = bindai; ai != NULL; ai = ai->ai_next) {
+			if (ai->ai_family == name->sa_family)
+				break;
+		}
+		if (ai == NULL)
+			ai = bindai;
+		if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
+			char	bname[NI_MAXHOST];
+			int	saveerr;
+
+			saveerr = errno;
+			if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
+			    bname, sizeof(bname), NULL, 0, NI_NUMERICHOST) != 0)
+				strlcpy(bname, "?", sizeof(bname));
+			errno = saveerr;
+			warn("Can't bind to `%s'", bname);
+			return -1;
+		}
+	}
+
+						/* save current socket flags */
+	if ((flags = fcntl(sock, F_GETFL, 0)) == -1) {
+		warn("Can't %s socket flags for connect to `%s:%s'",
+		    "save", hname, sname);
+		return -1;
+	}
+						/* set non-blocking connect */
+	if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) {
+		warn("Can't set socket non-blocking for connect to `%s:%s'",
+		    hname, sname);
+		return -1;
+	}
+
+	/* NOTE: we now must restore socket flags on successful exit */
+
+	pfd[0].fd = sock;
+	pfd[0].events = POLLIN|POLLOUT;
+
+	if (quit_time > 0) {			/* want a non default timeout */
+		(void)gettimeofday(&endtime, NULL);
+		endtime.tv_sec += quit_time;	/* determine end time */
+	}
+
+	rv = connect(sock, name, namelen);	/* inititate the connection */
+	if (rv == -1) {				/* connection error */
+		if (errno != EINPROGRESS) {	/* error isn't "please wait" */
+ connecterror:
+			warn("Can't connect to `%s:%s'", hname, sname);
+			return -1;
+		}
+
+						/* connect EINPROGRESS; wait */
+		do {
+			if (quit_time > 0) {	/* determine timeout */
+				(void)gettimeofday(&now, NULL);
+				timersub(&endtime, &now, &td);
+				timeout = td.tv_sec * 1000 + td.tv_usec/1000;
+				if (timeout < 0)
+					timeout = 0;
+			} else {
+				timeout = INFTIM;
+			}
+			pfd[0].revents = 0;
+			rv = ftp_poll(pfd, 1, timeout);
+						/* loop until poll ! EINTR */
+		} while (rv == -1 && errno == EINTR);
+
+		if (rv == 0) {			/* poll (connect) timed out */
+			errno = ETIMEDOUT;
+			goto connecterror;
+		}
+
+		if (rv == -1) {			/* poll error */
+			goto connecterror;
+		} else if (pfd[0].revents & (POLLIN|POLLOUT)) {
+			slen = sizeof(error);	/* OK, or pending error */
+			if (getsockopt(sock, SOL_SOCKET, SO_ERROR,
+			    &error, &slen) == -1) {
+						/* Solaris pending error */
+				goto connecterror;
+			} else if (error != 0) {
+				errno = error;	/* BSD pending error */
+				goto connecterror;
+			}
+		} else {
+			errno = EBADF;		/* this shouldn't happen ... */
+			goto connecterror;
+		}
+	}
+
+	if (fcntl(sock, F_SETFL, flags) == -1) {
+						/* restore socket flags */
+		warn("Can't %s socket flags for connect to `%s:%s'",
+		    "restore", hname, sname);
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * Internal version of listen(2); sets socket buffer sizes first.
+ */
+int
+ftp_listen(int sock, int backlog)
+{
+
+	setupsockbufsize(sock);
+	return (listen(sock, backlog));
+}
+
+/*
+ * Internal version of poll(2), to allow reimplementation by select(2)
+ * on platforms without the former.
+ */
+int
+ftp_poll(struct pollfd *fds, int nfds, int timeout)
+{
+#if defined(HAVE_POLL)
+	return poll(fds, nfds, timeout);
+
+#elif defined(HAVE_SELECT)
+		/* implement poll(2) using select(2) */
+	fd_set		rset, wset, xset;
+	const int	rsetflags = POLLIN | POLLRDNORM;
+	const int	wsetflags = POLLOUT | POLLWRNORM;
+	const int	xsetflags = POLLRDBAND;
+	struct timeval	tv, *ptv;
+	int		i, max, rv;
+
+	FD_ZERO(&rset);			/* build list of read & write events */
+	FD_ZERO(&wset);
+	FD_ZERO(&xset);
+	max = 0;
+	for (i = 0; i < nfds; i++) {
+		if (fds[i].fd > FD_SETSIZE) {
+			warnx("can't select fd %d", fds[i].fd);
+			errno = EINVAL;
+			return -1;
+		} else if (fds[i].fd > max)
+			max = fds[i].fd;
+		if (fds[i].events & rsetflags)
+			FD_SET(fds[i].fd, &rset);
+		if (fds[i].events & wsetflags)
+			FD_SET(fds[i].fd, &wset);
+		if (fds[i].events & xsetflags)
+			FD_SET(fds[i].fd, &xset);
+	}
+
+	ptv = &tv;			/* determine timeout */
+	if (timeout == -1) {		/* wait forever */
+		ptv = NULL;
+	} else if (timeout == 0) {	/* poll once */
+		ptv->tv_sec = 0;
+		ptv->tv_usec = 0;
+	}
+	else if (timeout != 0) {	/* wait timeout milliseconds */
+		ptv->tv_sec = timeout / 1000;
+		ptv->tv_usec = (timeout % 1000) * 1000;
+	}
+	rv = select(max + 1, &rset, &wset, &xset, ptv);
+	if (rv <= 0)			/* -1 == error, 0 == timeout */
+		return rv;
+
+	for (i = 0; i < nfds; i++) {	/* determine results */
+		if (FD_ISSET(fds[i].fd, &rset))
+			fds[i].revents |= (fds[i].events & rsetflags);
+		if (FD_ISSET(fds[i].fd, &wset))
+			fds[i].revents |= (fds[i].events & wsetflags);
+		if (FD_ISSET(fds[i].fd, &xset))
+			fds[i].revents |= (fds[i].events & xsetflags);
+	}
+	return rv;
+
+#else
+# error no way to implement xpoll
+#endif
+}
+
+/*
+ * malloc() with inbuilt error checking
+ */
+void *
+ftp_malloc(size_t size)
+{
+	void *p;
+
+	p = malloc(size);
+	if (p == NULL)
+		err(1, "Unable to allocate %ld bytes of memory", (long)size);
+	return (p);
+}
+
+/*
+ * sl_init() with inbuilt error checking
+ */
+StringList *
+ftp_sl_init(void)
+{
+	StringList *p;
+
+	p = sl_init();
+	if (p == NULL)
+		err(1, "Unable to allocate memory for stringlist");
+	return (p);
+}
+
+/*
+ * sl_add() with inbuilt error checking
+ */
+void
+ftp_sl_add(StringList *sl, char *i)
+{
+
+	if (sl_add(sl, i) == -1)
+		err(1, "Unable to add `%s' to stringlist", i);
+}
+
+/*
+ * strdup() with inbuilt error checking
+ */
+char *
+ftp_strdup(const char *str)
+{
+	char *s;
+
+	if (str == NULL)
+		errx(1, "ftp_strdup: called with NULL argument");
+	s = strdup(str);
+	if (s == NULL)
+		err(1, "Unable to allocate memory for string copy");
+	return (s);
+}

Added: vendor/NetBSD/tnftp/20100108/src/version.h
===================================================================
--- vendor/NetBSD/tnftp/20100108/src/version.h	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/src/version.h	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,39 @@
+/*	$NetBSD: version.h,v 1.4 2009/11/15 10:12:37 lukem Exp $	*/
+/*	from	NetBSD: version.h,v 1.80 2009/11/15 10:03:16 lukem Exp	*/
+
+/*-
+ * Copyright (c) 1999-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FTP_PRODUCT
+#define	FTP_PRODUCT	"NetBSD-ftp"
+#endif
+
+#ifndef FTP_VERSION
+#define	FTP_VERSION	"20090915"
+#endif

Added: vendor/NetBSD/tnftp/20100108/tnftp.h
===================================================================
--- vendor/NetBSD/tnftp/20100108/tnftp.h	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/tnftp.h	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,495 @@
+/*	$NetBSD: tnftp.h,v 1.33 2009/11/14 08:32:42 lukem Exp $	*/
+
+#define	FTP_PRODUCT	PACKAGE_NAME
+#define	FTP_VERSION	PACKAGE_VERSION
+
+#include "tnftp_config.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+#if defined(HAVE_SYS_TYPES_H)
+# include <sys/types.h>
+#endif
+#if defined(STDC_HEADERS)
+# include <stdarg.h>
+# include <stdlib.h>
+# include <string.h>
+#endif
+#if defined(HAVE_LIBGEN_H)
+# include <libgen.h>
+#endif
+#if defined(HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+#if defined(HAVE_POLL_H)
+# include <poll.h>
+#elif defined(HAVE_SYS_POLL_H)
+# include <sys/poll.h>
+#endif
+#if defined(HAVE_SYS_SOCKET_H)
+# include <sys/socket.h>
+#endif
+#if defined(HAVE_NETINET_IN_H)
+# include <netinet/in.h>
+#endif
+#if defined(HAVE_NETINET_IN_SYSTM_H)
+# include <netinet/in_systm.h>
+#endif
+#if defined(HAVE_NETINET_IP_H)
+# include <netinet/ip.h>
+#endif
+#if defined(HAVE_NETDB_H)
+# if HAVE_DECL_AI_NUMERICHOST
+#  include <netdb.h>
+# else	/* !HAVE_DECL_AI_NUMERICHOST */
+#  define getaddrinfo non_rfc2553_getaddrinfo
+#  include <netdb.h>
+#  undef getaddrinfo
+# endif	/* !HAVE_DECL_AI_NUMERICHOST */
+#endif
+#if defined(HAVE_ARPA_INET_H)
+# include <arpa/inet.h>
+#endif
+#if defined(HAVE_DIRENT_H)
+# include <dirent.h>
+#else
+# define dirent direct
+# if defined(HAVE_SYS_NDIR_H)
+#  include <sys/ndir.h>
+# endif
+# if defined(HAVE_SYS_DIR_H)
+#  include <sys/dir.h>
+# endif
+# if defined(HAVE_NDIR_H)
+#  include <ndir.h>
+# endif
+#endif
+
+#if defined(HAVE_SYS_IOCTL_H)
+# include <sys/ioctl.h>
+#endif
+#if defined(HAVE_SYS_PARAM_H)
+# include <sys/param.h>
+#endif
+#if defined(HAVE_SYS_STAT_H)
+# include <sys/stat.h>
+#endif
+#if defined(HAVE_SYS_SYSLIMITS_H)
+# include <sys/syslimits.h>
+#endif
+#if defined(HAVE_SYS_WAIT_H)
+# include <sys/wait.h>
+#endif
+
+#if defined(HAVE_ARPA_FTP_H)
+# include <arpa/ftp.h>
+#endif
+
+#if defined(HAVE_FCNTL_H)
+# include <fcntl.h>
+#endif
+#if defined(HAVE_LIMITS_H)
+# include <limits.h>
+#endif
+#if defined(HAVE_PWD_H)
+# include <pwd.h>
+#endif
+#if defined(HAVE_SETJMP_H)
+# include <setjmp.h>
+#endif
+#if defined(HAVE_SIGNAL_H)
+# include <signal.h>
+#endif
+#if defined(HAVE_STDDEF_H)
+# include <stddef.h>
+#endif
+#if defined(HAVE_TERMIOS_H)
+# include <termios.h>
+#endif
+
+#if defined(HAVE_POLL)
+/* we use poll */
+#elif defined(HAVE_SELECT)
+/* we use select */
+#else /* !defined(HAVE_POLL) && !defined(HAVE_SELECT) */
+# error "no poll() or select() found"
+#endif
+#if !defined(POLLIN)
+# define POLLIN		0x0001
+#endif
+#if !defined(POLLOUT)
+# define POLLOUT	0x0004
+#endif
+#if !defined(POLLRDNORM)
+# define POLLRDNORM	0x0040
+#endif
+#if !defined(POLLWRNORM)
+# define POLLWRNORM	POLLOUT
+#endif
+#if !defined(POLLRDBAND)
+# define POLLRDBAND	0x0080
+#endif
+#if !defined(INFTIM)
+# define INFTIM -1
+#endif
+#if !defined(HAVE_STRUCT_POLLFD)
+struct pollfd {
+	int	fd;
+	short	events;
+	short	revents;
+};
+#endif
+
+#if defined(TIME_WITH_SYS_TIME)
+# include <sys/time.h>
+# include <time.h>
+#else
+# if defined(HAVE_SYS_TIME_H)
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#if defined(HAVE_ERR_H)
+# include <err.h>
+#endif
+
+#if defined(USE_GLOB_H)	/* not set by configure; used by other build systems */
+# include <glob.h>
+#else
+# include "ftpglob.h"
+#endif
+
+#if defined(HAVE_PATHS_H)
+# include <paths.h>
+#endif
+#if !defined(_PATH_BSHELL)
+# define _PATH_BSHELL	"/bin/sh"
+#endif
+#if !defined(_PATH_TMP)
+# define _PATH_TMP	"/tmp/"
+#endif
+
+typedef struct _stringlist {
+	char	**sl_str;
+	size_t	  sl_max;
+	size_t	  sl_cur;
+} StringList;
+
+StringList *sl_init(void);
+int	 sl_add(StringList *, char *);
+void	 sl_free(StringList *, int);
+char	*sl_find(StringList *, char *);
+
+#if defined(HAVE_TERMCAP_H)
+# include <termcap.h>
+#else
+int	 tgetent(char *, const char *);
+char	*tgetstr(const char *, char **);
+int	 tgetflag(const char *);
+int	 tgetnum(const char *);
+char	*tgoto(const char *, int, int);
+void	 tputs(const char *, int, int (*)(int));
+#endif /* !HAVE_TERMCAP_H */
+
+#if defined(HAVE_VIS_H) && defined(HAVE_STRVIS) && defined(HAVE_STRUNVIS)
+# include <vis.h>
+#else
+# include "ftpvis.h"
+#endif
+
+#if !defined(HAVE_IN_PORT_T)
+typedef unsigned short in_port_t;
+#endif
+
+#if !defined(HAVE_SA_FAMILY_T)
+typedef unsigned short sa_family_t;
+#endif
+
+#if !defined(HAVE_SOCKLEN_T)
+typedef unsigned int socklen_t;
+#endif
+
+#if defined(USE_INET6)
+# define INET6
+#endif
+
+#if !HAVE_DECL_AI_NUMERICHOST
+
+				/* RFC 2553 */
+#undef	EAI_ADDRFAMILY
+#define	EAI_ADDRFAMILY	 1	/* address family for hostname not supported */
+#undef	EAI_AGAIN
+#define	EAI_AGAIN	 2	/* temporary failure in name resolution */
+#undef	EAI_BADFLAGS
+#define	EAI_BADFLAGS	 3	/* invalid value for ai_flags */
+#undef	EAI_FAIL
+#define	EAI_FAIL	 4	/* non-recoverable failure in name resolution */
+#undef	EAI_FAMILY
+#define	EAI_FAMILY	 5	/* ai_family not supported */
+#undef	EAI_MEMORY
+#define	EAI_MEMORY	 6	/* memory allocation failure */
+#undef	EAI_NODATA
+#define	EAI_NODATA	 7	/* no address associated with hostname */
+#undef	EAI_NONAME
+#define	EAI_NONAME	 8	/* hostname nor servname provided, or not known */
+#undef	EAI_SERVICE
+#define	EAI_SERVICE	 9	/* servname not supported for ai_socktype */
+#undef	EAI_SOCKTYPE
+#define	EAI_SOCKTYPE	10	/* ai_socktype not supported */
+#undef	EAI_SYSTEM
+#define	EAI_SYSTEM	11	/* system error returned in errno */
+
+				/* KAME extensions? */
+#undef	EAI_BADHINTS
+#define	EAI_BADHINTS	12
+#undef	EAI_PROTOCOL
+#define	EAI_PROTOCOL	13
+#undef	EAI_MAX
+#define	EAI_MAX		14
+
+				/* RFC 2553 */
+#undef	NI_MAXHOST
+#define	NI_MAXHOST	1025
+#undef	NI_MAXSERV
+#define	NI_MAXSERV	32
+
+#undef	NI_NOFQDN
+#define	NI_NOFQDN	0x00000001
+#undef	NI_NUMERICHOST
+#define	NI_NUMERICHOST	0x00000002
+#undef	NI_NAMEREQD
+#define	NI_NAMEREQD	0x00000004
+#undef	NI_NUMERICSERV
+#define	NI_NUMERICSERV	0x00000008
+#undef	NI_DGRAM
+#define	NI_DGRAM	0x00000010
+
+				/* RFC 2553 */
+#undef	AI_PASSIVE
+#define	AI_PASSIVE	0x00000001 /* get address to use bind() */
+#undef	AI_CANONNAME
+#define	AI_CANONNAME	0x00000002 /* fill ai_canonname */
+
+				/* KAME extensions ? */
+#undef	AI_NUMERICHOST
+#define	AI_NUMERICHOST	0x00000004 /* prevent name resolution */
+#undef	AI_MASK
+#define	AI_MASK		(AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST)
+
+				/* RFC 2553 */
+#undef	AI_ALL
+#define	AI_ALL		0x00000100 /* IPv6 and IPv4-mapped (with AI_V4MAPPED) */
+#undef	AI_V4MAPPED_CFG
+#define	AI_V4MAPPED_CFG	0x00000200 /* accept IPv4-mapped if kernel supports */
+#undef	AI_ADDRCONFIG
+#define	AI_ADDRCONFIG	0x00000400 /* only if any address is assigned */
+#undef	AI_V4MAPPED
+#define	AI_V4MAPPED	0x00000800 /* accept IPv4-mapped IPv6 address */
+
+#endif /* !HAVE_DECL_AI_NUMERICHOST */
+
+
+#if !HAVE_DECL_AI_NUMERICHOST && !defined(HAVE_STRUCT_ADDRINFO) \
+    && !defined(USE_SOCKS)
+
+struct addrinfo {
+	int		ai_flags;	/* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
+	int		ai_family;	/* PF_xxx */
+	int		ai_socktype;	/* SOCK_xxx */
+	int		ai_protocol;	/* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+	socklen_t	ai_addrlen;	/* length of ai_addr */
+	char		*ai_canonname;	/* canonical name for hostname */
+	struct sockaddr *ai_addr;	/* binary address */
+	struct addrinfo *ai_next;	/* next structure in linked list */
+};
+
+int	getaddrinfo(const char *, const char *,
+	    const struct addrinfo *, struct addrinfo **);
+int	getnameinfo(const struct sockaddr *, socklen_t,
+	    char *, size_t, char *, size_t, int);
+void	freeaddrinfo(struct addrinfo *);
+const char *gai_strerror(int);
+
+#endif /* !HAVE_DECL_AI_NUMERICHOST && !defined(HAVE_STRUCT_ADDRINFO) \
+	&& !defined(USE_SOCKS) */
+
+#if !defined(HAVE_STRUCT_DIRENT_D_NAMLEN)
+# define DIRENT_MISSING_D_NAMLEN
+#endif
+
+#if !HAVE_DECL_H_ERRNO
+extern int	h_errno;
+#endif
+#define HAVE_H_ERRNO	1		/* XXX: an assumption for now... */
+
+#if !HAVE_DECL_FCLOSE
+int	fclose(FILE *);
+#endif
+
+#if !HAVE_DECL_GETPASS
+char	*getpass(const char *);
+#endif
+
+#if !HAVE_DECL_OPTARG
+extern char    *optarg;
+#endif
+
+#if !HAVE_DECL_OPTIND
+extern int	optind;
+#endif
+
+#if !HAVE_DECL_PCLOSE
+int	pclose(FILE *);
+#endif
+
+#if !HAVE_DECL_DIRNAME
+char	*dirname(char *);
+#endif
+
+#if !defined(HAVE_ERR)
+void	err(int, const char *, ...);
+void	errx(int, const char *, ...);
+void	warn(const char *, ...);
+void	warnx(const char *, ...);
+#endif
+
+#if !defined(HAVE_FGETLN)
+char   *fgetln(FILE *, size_t *);
+#endif
+
+#if !defined(HAVE_FSEEKO)
+int	fseeko(FILE *, off_t, int);
+#endif
+
+#if !defined(HAVE_INET_NTOP)
+const char *inet_ntop(int, const void *, char *, socklen_t);
+#endif
+
+#if !defined(HAVE_INET_PTON)
+int inet_pton(int, const char *, void *);
+#endif
+
+#if !defined(HAVE_MKSTEMP)
+int	mkstemp(char *);
+#endif
+
+#if !defined(HAVE_SETPROGNAME)
+const char *getprogname(void);
+void	setprogname(const char *);
+#endif
+
+#if !defined(HAVE_SNPRINTF)
+int	snprintf(char *, size_t, const char *, ...);
+#endif
+
+#if !defined(HAVE_STRDUP)
+char   *strdup(const char *);
+#endif
+
+#if !defined(HAVE_STRERROR)
+char   *strerror(int);
+#endif
+
+#if !defined(HAVE_STRPTIME) || !HAVE_DECL_STRPTIME
+char   *strptime(const char *, const char *, struct tm *);
+#endif
+
+#if defined(HAVE_PRINTF_LONG_LONG) && defined(HAVE_LONG_LONG_INT)
+# if !defined(HAVE_STRTOLL)
+long long strtoll(const char *, char **, int);
+# endif
+# if !defined(LLONG_MIN)
+#  define LLONG_MIN	(-0x7fffffffffffffffLL-1)
+# endif
+# if !defined(LLONG_MAX)
+#  define LLONG_MAX	(0x7fffffffffffffffLL)
+# endif
+#else  /* !(defined(HAVE_PRINTF_LONG_LONG) && defined(HAVE_LONG_LONG_INT)) */
+# define NO_LONG_LONG	1
+#endif /* !(defined(HAVE_PRINTF_LONG_LONG) && defined(HAVE_LONG_LONG_INT)) */
+
+#if !defined(HAVE_TIMEGM)
+time_t	timegm(struct tm *);
+#endif
+
+#if !defined(HAVE_STRLCAT)
+size_t	strlcat(char *, const char *, size_t);
+#endif
+
+#if !defined(HAVE_STRLCPY)
+size_t	strlcpy(char *, const char *, size_t);
+#endif
+
+#if !defined(HAVE_STRSEP)
+char   *strsep(char **stringp, const char *delim);
+#endif
+
+#if !defined(HAVE_UTIMES)
+int utimes(const char *, const struct timeval *);
+#endif
+
+#if !defined(HAVE_MEMMOVE)
+# define memmove(a,b,c)	bcopy((b),(a),(c))
+	/* XXX: add others #defines for borken systems? */
+#endif
+
+#if defined(HAVE_GETPASSPHRASE)
+# define getpass getpassphrase
+#endif
+
+#if !defined(MIN)
+# define MIN(a, b)	((a) < (b) ? (a) : (b))
+#endif
+#if !defined(MAX)
+# define MAX(a, b)	((a) < (b) ? (b) : (a))
+#endif
+
+#if !defined(timersub)
+# define timersub(tvp, uvp, vvp)					\
+	do {								\
+		(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;		\
+		(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;	\
+		if ((vvp)->tv_usec < 0) {				\
+			(vvp)->tv_sec--;				\
+			(vvp)->tv_usec += 1000000;			\
+		}							\
+	} while (0)
+#endif
+
+#if !defined(S_ISLNK)
+# define S_ISLNK(m)	((m & S_IFMT) == S_IFLNK)
+#endif
+
+#define	EPOCH_YEAR	1970
+#define	SECSPERHOUR	3600
+#define	SECSPERDAY	86400
+#define	TM_YEAR_BASE	1900
+
+#if defined(USE_SOCKS)		/* (Dante) SOCKS5 */
+#define connect		Rconnect
+#define bind		Rbind
+#define getsockname	Rgetsockname
+#define getpeername	Rgetpeername
+#define accept		Raccept
+#define rresvport	Rrresvport
+#define bindresvport	Rbindresvport
+#define gethostbyname	Rgethostbyname
+#define gethostbyname2	Rgethostbyname2
+#define sendto		Rsendto
+#define recvfrom	Rrecvfrom
+#define recvfrom	Rrecvfrom
+#define write		Rwrite
+#define writev		Rwritev
+#define send		Rsend
+#define sendmsg		Rsendmsg
+#define read		Rread
+#define readv		Rreadv
+#define recv		Rrecv
+#define recvmsg		Rrecvmsg
+#define getaddrinfo	Rgetaddrinfo
+#define getipnodebyname	Rgetipnodebyname
+#endif /* defined(USE_SOCKS) */

Added: vendor/NetBSD/tnftp/20100108/todo
===================================================================
--- vendor/NetBSD/tnftp/20100108/todo	                        (rev 0)
+++ vendor/NetBSD/tnftp/20100108/todo	2014-10-31 22:45:22 UTC (rev 6904)
@@ -0,0 +1,25 @@
+$NetBSD: todo,v 1.12 2008/12/20 15:17:58 lukem Exp $
+
+Current Items
+-------------
+
+autoconf test for HAVE_DECL_GETADDRINFO if providing getaddrinfo() override.
+(required for UnixWare 7.1.1)
+
+Interix may need hack to fix detection of getpgrp() void args.
+(See pkgsrc/net/tnftp/files/src/progressbar.c 1.2)
+
+Old Items
+---------
+
+add locale autoconf checks
+
+in configure, check for ansi c compiler and barf if it fails
+
+check if we need #defines for memcpy() et al
+
+possibly install editline.3 and editrc.5
+
+system specific tests (to remove need for manual intervention):
+- sunos4
+	LIBS+= -lresolv



More information about the Midnightbsd-cvs mailing list