aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid E. O'Brien <obrien@FreeBSD.org>2001-07-19 16:26:14 +0000
committerDavid E. O'Brien <obrien@FreeBSD.org>2001-07-19 16:26:14 +0000
commite25f7def37f0ffffe46ea434abca403a1fa6f30c (patch)
treeb2e212d8817efdff7190924a6cf96f692ec3f76d
downloadsrc-e25f7def37f0ffffe46ea434abca403a1fa6f30c.tar.gz
src-e25f7def37f0ffffe46ea434abca403a1fa6f30c.zip
Import of LukeM's ftp client, version 1.5.vendor/tnftp/1.5vendor/NetBSD/lukemftp/1.5
Notes
Notes: svn path=/vendor/lukemftp/dist/; revision=79971 svn path=/vendor/tnftp/1.5/; revision=223303; tag=vendor/tnftp/1.5
-rw-r--r--contrib/lukemftp/COPYING47
-rw-r--r--contrib/lukemftp/ChangeLog878
-rw-r--r--contrib/lukemftp/INSTALL213
-rw-r--r--contrib/lukemftp/Makefile.in33
-rw-r--r--contrib/lukemftp/NEWS84
-rw-r--r--contrib/lukemftp/README61
-rw-r--r--contrib/lukemftp/THANKS30
-rw-r--r--contrib/lukemftp/acconfig.h89
-rw-r--r--contrib/lukemftp/aclocal.m4257
-rw-r--r--contrib/lukemftp/config.h.in266
-rwxr-xr-xcontrib/lukemftp/configure4129
-rw-r--r--contrib/lukemftp/configure.in283
-rwxr-xr-xcontrib/lukemftp/install-sh251
-rw-r--r--contrib/lukemftp/lukemftp.h379
-rw-r--r--contrib/lukemftp/src/Makefile.in43
-rw-r--r--contrib/lukemftp/src/cmds.c2673
-rw-r--r--contrib/lukemftp/src/cmdtab.c291
-rw-r--r--contrib/lukemftp/src/complete.c423
-rw-r--r--contrib/lukemftp/src/domacro.c133
-rw-r--r--contrib/lukemftp/src/extern.h266
-rw-r--r--contrib/lukemftp/src/fetch.c1738
-rw-r--r--contrib/lukemftp/src/ftp.12049
-rw-r--r--contrib/lukemftp/src/ftp.c2100
-rw-r--r--contrib/lukemftp/src/ftp_var.h353
-rw-r--r--contrib/lukemftp/src/main.c965
-rw-r--r--contrib/lukemftp/src/ruserpass.c284
-rw-r--r--contrib/lukemftp/src/util.c1620
-rw-r--r--contrib/lukemftp/src/version.h44
-rw-r--r--contrib/lukemftp/todo15
29 files changed, 19997 insertions, 0 deletions
diff --git a/contrib/lukemftp/COPYING b/contrib/lukemftp/COPYING
new file mode 100644
index 000000000000..31acb7415c36
--- /dev/null
+++ b/contrib/lukemftp/COPYING
@@ -0,0 +1,47 @@
+Copyright 1999, 2000 Luke Mewburn <lukem@netbsd.org>. 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. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+ This product includes software developed by Luke Mewburn.
+4. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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:
+ - Jaromir Dolecek
+ - Klaus Klein
+ - Luke Mewburn
+ - Jason R. Thorpe of the Numerical Aerospace Simulation
+ Facility, NASA Ames Research Center.
+
+ 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.
+
diff --git a/contrib/lukemftp/ChangeLog b/contrib/lukemftp/ChangeLog
new file mode 100644
index 000000000000..6b3555f97087
--- /dev/null
+++ b/contrib/lukemftp/ChangeLog
@@ -0,0 +1,878 @@
+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@mono.org>
+ - always include <netdb.h>, not just when INET6 is defined.
+ resolves PR [bin/10970] by Richard Earnshaw
+ <rearnsha@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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
diff --git a/contrib/lukemftp/INSTALL b/contrib/lukemftp/INSTALL
new file mode 100644
index 000000000000..9259bcb6fa29
--- /dev/null
+++ b/contrib/lukemftp/INSTALL
@@ -0,0 +1,213 @@
+INSTALLATION INTRODUCTION
+-------------------------
+
+This file describes how to compile and install lukemftp on your
+system.
+
+ ============================================
+ = =
+ = NOTE: You will need an ANSI C compiler. =
+ = =
+ ============================================
+
+
+For most systems, execute the following to compile and install
+lukemftp:
+ ./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. groff ships with this macro suite,
+but it has bugs. Try:
+ ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/share/tmac/
+for a more recent version.
+
+
+CONFIGURATION OPTIONS
+---------------------
+
+lukemftp 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.
+ --disable-editcomplete Turn off command line editing and completion
+ [default: enabled].
+ --enable-ipv6 Enable IPv6 support (if your OS supports it)
+ --disable-ipv6 Disable IPv6 support (even if your OS supports it.)
+ [default: enabled].
+ --with-socks Compile with SOCKS firewall traversal support.
+ --with-socks5[=PATH] Compile with SOCKS5 firewall traversal support.
+ --with-socks4[=PATH] Compile with SOCKS4 firewall traversal support.
+
+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. =
+ = =
+ ============================================
+
+
+PLATFORM SPECIFIC NOTES
+-----------------------
+
+The following platforms & compilers have been tested:
+
+- AIX 4.1.5:
+- AIX 4.2.1:
+ - Compiler: cc -qlanglvl=ansi
+ version: xlC 3.1.4.10 -- C for AIX Compiler
+
+ Configure with:
+ env CC="cc -qlanglvl=ansi" ./configure
+
+- BSD/OS 4.0.1 (x86)
+- BSD/OS 4.1 (x86)
+- BSD/OS 4.1 (sparc)
+- BSD/OS 4.2 (x86)
+ - Compiler: /bin/cc
+ version: gcc 2.7.2.1
+ version: gcc version 2.95.2 19991024
+
+- Digital UNIX 4.0b
+- Digital UNIX 4.0d
+- Digital UNIX 4.0f
+ - Compiler: cc -std
+ version: DEC C V5.2-036 on Digital UNIX V4.0 (Rev. 564)
+ version: DEC C V5.9-005 on Digital UNIX V4.0 (Rev. 1229)
+
+ Configure with
+ env CC="cc -std" ./configure
+
+ - Compiler: gcc
+ version: 2.95.1
+
+- Digital UNIX 5.0
+ - Compiler: cc
+ version: Compaq C V6.1-011 on Digital UNIX V5.0 (Rev. 910)
+
+- FreeBSD 3.4 (i386):
+- FreeBSD 3.5 (i386):
+- FreeBSD 4.1 (i386):
+ - Compiler: cc
+ version: gcc version 2.7.2.3
+ version: gcc version 2.95.2 19991024
+
+- HP/UX 10.20:
+- HP/UX 11.00:
+ - Compiler: /opt/ansic/bin/cc -Ae
+ version: A.10.32.03
+
+ Configure with
+ env CC="cc -Ae" ./configure
+
+ To generate code that will run on old architectures you
+ may need to add "+DAportable" to CC.
+
+
+- IRIX 6.5.4
+- IRIX 6.5.8
+ Compiler: /bin/cc
+ version: MIPSpro Compilers: Version 7.2.1
+ Compiler:
+ version: gcc version 2.95.2
+
+- HP/UX 11.00:
+- HP/UX 11.00 64 bit:
+ - Compiler: /opt/ansic/bin/cc -Ae
+ version: A.11.01.00
+
+ Configure with
+ env CC="cc -Ae" ./configure
+
+- NetBSD 1.3.3 (i386)
+ Compiler: /usr/bin/cc
+ Compiler: /usr/bin/cc
+
+ Ignore warnings about ``passing arg 3 of `tputs' from
+ incompatible pointer type''.
+
+- RedHat Linux 5.1 (?? i386)
+- RedHat Linux 5.2 (?? i386)
+- RedHat Linux 6.0 (Linux 2.2.10 i686)
+- RedHat Linux 6.1 (Linux 2.2.5-15 i686)
+- RedHat Linux 6.2 (Linux 2.2.16-3smp i686)
+ - Compiler: cc
+ version: egcs-1.1.2
+
+- Slackware (Linux 2.0.35 i686)
+ - Compiler: cc
+ version: 2.7.2.3
+
+- Solaris 2.6 (sparc)
+- Solaris 7 (sparc)
+ - Compiler: /opt/SUNWspro/bin/cc
+ version: WorkShop Compilers 5.0
+
+ - Compiler: gcc
+ version: egcs-1.1.2
+
+=============
+= OLD NOTES =
+=============
+
+XXX: clean up to match reality
+------------------------------
+
+- AIX 4.3.2:
+ Compiler: cc
+ version: ibmcxx 3.6.6.1 -- IBM C and C++ Compilers
+
+- RedHat Linux 5.0 (i386)
+ Compiler: cc
+
+- Solaris 2.5 (sparc)
+- Solaris 7 (x86)
+ Compiler: /opt/SUNWspro/bin/cc
+ version: SC3.0 15 Dec 1993
+ version: WorkShop Compilers 5.0
+ Compiler: gcc
+ version: egcs-1.1.2
+ version: gcc 2.8.1
+ version: gcc 2.95.1
+
+- Solaris 7 (sparc) 64 bit
+ Compiler: /opt/SUNWspro/bin/cc -xarch=v9
+ version: WorkShop Compilers 5.0
+
+- SunOS 4
+ Compiler: gcc -lresolv
+ version:
+
+- SuSE Linux
+ Compiler: gcc
+ version:
+
+ /usr/bin/ftp on SuSE Linux 6.4 is this ftp client.
+
+ May need `gcc -L/usr/lib/termcap' if tgetent() et al aren't found.
+
+- Ultrix 4.5
+ Compiler: cc
+ version: MIPS C Compiler 3.0
+ Compiler: gcc
+ version: 2.7.2.2
diff --git a/contrib/lukemftp/Makefile.in b/contrib/lukemftp/Makefile.in
new file mode 100644
index 000000000000..3e4f2984edfc
--- /dev/null
+++ b/contrib/lukemftp/Makefile.in
@@ -0,0 +1,33 @@
+# $Id: Makefile.in,v 1.6 1999/11/13 01:18:22 lukem Exp $
+#
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+SHELL = /bin/sh
+
+@SET_MAKE@
+
+
+SUBDIRS = libedit libukem src
+
+all: ftp
+
+ftp: @LIBEDIT@ @LIBUKEM@
+ ( cd src; ${MAKE} )
+
+libedit.a:
+ ( cd libedit; ${MAKE} )
+
+libukem.a:
+ ( cd libukem; ${MAKE} )
+
+install clean:
+ @for i in ${SUBDIRS}; do \
+ ( echo "$@ ===> $$i" ; cd $$i ; ${MAKE} $@ ); \
+ done
+
+distclean: clean
+ @for i in ${SUBDIRS}; do \
+ ( echo "$@ ===> $$i" ; cd $$i ; ${MAKE} $@ ); \
+ done
+ rm -f Makefile config.cache config.log config.status config.h
diff --git a/contrib/lukemftp/NEWS b/contrib/lukemftp/NEWS
new file mode 100644
index 000000000000..614dec090a88
--- /dev/null
+++ b/contrib/lukemftp/NEWS
@@ -0,0 +1,84 @@
+This is a brief description of the new features and fixes added to
+lukemftp-1.5 since the release of lukemftp-1.4. As always, the manual
+page (src/ftp.cat1) is the place to look for complete descriptions.
+
+* Add new commands:
+ features list remote features supported by servers
+ mlsd machine parseable directory listing
+ mlst machine parseable file listing
+ remopts set options on remote features
+
+ These require support in the remote server for the ftp extensions
+ described in RFC 2389 and draft-ietf-ftpext-mlst-11.
+
+* Fix support for the --program-prefix and --program-suffix configure
+ options.
+
+---
+This is a brief description of the new features and fixes added to
+lukemftp-1.4 since the release of lukemftp-1.3. As always, the manual
+page (src/ftp.cat1) is the place to look for complete descriptions.
+
+* Fix compilation problems on various non 4.4BSD derived platforms which
+ support IPv6, and on Linux systems which have strdup() as a macro.
+
+* During auto-fetch, don't attempt to autologin a second time if the first
+ time failed.
+
+---
+This is a brief description of the new features and fixes added to
+lukemftp-1.3 since the release of lukemftp-1.2. As always, the manual
+page (src/ftp.cat1) is the place to look for complete descriptions.
+
+* The `ls' command now uses the `LIST' directive instead of `NLST',
+ in order to be compatible with RFC959.
+
+* Add fget command, which reads a list of filenames to retrieve from
+ the given file.
+
+* Add support for uploading files on the command-line with `ftp -u'.
+
+* Various fixes to the IPv6 support.
+
+---
+This is a brief description of the new features and fixes added to
+lukemftp-1.2 since the release of lukemftp-1.1. As always, the manual
+page (src/ftp.cat1) is the place to look for complete descriptions.
+
+* During remote completion, only send ``NLST'' instead of ``NLST .''
+ when reading the list of files from the remote server; some servers
+ don't like the trailing `.'.
+
+* Support a leading ``[user@]'' for ``[user@]host[:][path]'' auto-fetches
+ and ``[user@]host'' connections.
+
+* Always compile in support for setting the type of service on transfers.
+ Should speed up transfers on Linux systems.
+
+* Improve performance of non-rate-limited transfers.
+
+* Work around ftp servers that aren't Y2K compliant in returning the
+ modification time of a file.
+
+* Update the libedit library to support automatic and magic margins,
+ allowing ftp's rprompt to move an extra character to the right.
+
+---
+This is a brief description of the new features and fixes added to
+lukemftp-1.1 since the release of lukemftp-1.0. As always, the manual
+page (src/ftp.cat1) is the place to look for complete descriptions.
+
+* Implemented `set prompt' and `set rprompt', which allow you to
+ configure the prompt and right side prompt (respectively).
+ Some tcsh(1) style `%' escapes are supported, including
+ %. %c %/ %m %M %n
+
+* Implemented restarting of file:/// and non-proxied http:// URLs
+ (using -R)
+
+* Correctly parse remote ports given as numbers that don't appear in
+ the services(5) database.
+
+* Prevent a couple of minor memory leaks
+
+* Add missing compilation setting for SOCKS
diff --git a/contrib/lukemftp/README b/contrib/lukemftp/README
new file mode 100644
index 000000000000..4b3a12c328fa
--- /dev/null
+++ b/contrib/lukemftp/README
@@ -0,0 +1,61 @@
+WHAT IS LUKEMFTP?
+-----------------
+
+`lukemftp' is what many users affectionately call the enhanced ftp
+client in NetBSD (http://www.netbsd.org). The `lukem' comes from
+the account name of the NetBSD developer who wrote most of the
+enhancements: Luke Mewburn <lukem@netbsd.org>.
+
+This package is a `port' of the NetBSD ftp client to other systems.
+
+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 (c.f: $http_proxy, $ftp_proxy)
+ - authentication
+ * configurable prompt
+ * context sensitive command and filename completion
+ * dynamic progress bar
+ * feature negotiation extensions from RFC 2389
+ (c.f: `feat' and `remopts')
+ * extensions to ftp from the IETF ftpext working group
+ (c.f: `mlsd' and `mlst')
+ * IPv6 support (from the WIDE project)
+ * modification time preservation
+ * paging of local and remote files, and of directory listings
+ (c.f: `lpage', `page', `pdir')
+ * passive mode support, with fallback to active mode
+ * retrieval of filenames listed in a given file (c.f: `fget')
+ * `set option' override of ftp environment variables
+ * socks4/socks5 support
+ * TIS Firewall Toolkit gate ftp proxy support (c.f: `gate')
+ * transfer-rate throttling (c.f: `-T', `rate')
+ * uploading of files on the command line (c.f: `-u')
+
+
+INSTALLATION
+------------
+
+Refer to `INSTALL' for more information on how to compile and install
+lukemftp.
+
+
+FEEDBACK / BUG REPORTS
+----------------------
+
+Please email feedback back to the maintainer: <lukem@netbsd.org>.
+
+
+COPYRIGHT
+---------
+
+lukemftp is covered by a BSD-style copyright notice. Please refer to
+the file `COPYING' for more information.
+
+
+AVAILABILITY
+------------
+
+The primary ftp site for lukemftp is:
+ ftp://ftp.netbsd.org/pub/NetBSD/misc/lukemftp/
diff --git a/contrib/lukemftp/THANKS b/contrib/lukemftp/THANKS
new file mode 100644
index 000000000000..45a49ed3e8d9
--- /dev/null
+++ b/contrib/lukemftp/THANKS
@@ -0,0 +1,30 @@
+Whilst a lot of the work in lukemftp (both the original sources in NetBSD
+and this port) was done by me (Luke Mewburn), it would not be as useable
+without the enhancements, fixes, or input from the following people:
+
+Brian Stark <bstark@siemens-psc.com>
+Chris G. Demetriou <cgd@netbsd.org>
+Christos Zoulas <christos@netbsd.org>
+Dan Winship <danw@mit.edu>
+Darren Reed <darrenr@pobox.com>
+David Carrel <carrel@netbsd.org>
+Giles Lean <giles@nemeton.com.au>
+Havard Eidnes <Havard.Eidnes@runit.sintef.no>
+ITOH Yasufumi <itohy@netbsd.org>
+Jason R. Thorpe <thorpej@netbsd.org>
+John Hawkinson <jhawk@mit.edu>
+Joseph S. Myers <jsm28@cam.ac.uk>
+Jun-ichiro itojun Hagino <itojun@netbsd.org>
+Kimmo Suominen <kim@tac.nyc.ny.us>
+Klaus Klein <kleink@netbsd.org>
+Luke Mewburn <lukem@netbsd.org>
+Marc Horowitz <marc@mit.edu>
+Matthew R. Green <mrg@eterna.com.au>
+Matthias Pfaller <leo@dachau.marco.de>
+Matthias Scheler <tron@zhadum.de>
+Michael L. Hitch <osymh@terra.oscs.montana.edu>
+Scott Aaron Bamford <sab@ansic.net>
+Simon Burge <simonb@thistledown.com.au>
+Todd C. Miller <Todd.Miller@courtesan.com>
+
+Apologies to anyone I've missed.
diff --git a/contrib/lukemftp/acconfig.h b/contrib/lukemftp/acconfig.h
new file mode 100644
index 000000000000..5c64cef9aeea
--- /dev/null
+++ b/contrib/lukemftp/acconfig.h
@@ -0,0 +1,89 @@
+/* $Id: acconfig.h,v 1.6 2000/09/17 23:29:12 lukem Exp $ */
+
+@TOP@
+@BOTTOM@
+
+/* Define if your compiler supports `long long' */
+#undef HAVE_LONG_LONG
+
+/* Define if in_port_t exists */
+#undef HAVE_IN_PORT_T
+
+/* Define if struct sockaddr.sa_len exists (implies sockaddr_in.sin_len, etc) */
+#undef HAVE_SOCKADDR_SA_LEN
+
+/* Define if socklen_t exists */
+#undef HAVE_SOCKLEN_T
+
+/* Define if AF_INET6 exists in <sys/socket.h> */
+#undef HAVE_AF_INET6
+
+/* Define if `struct sockaddr_in6' exists in <netinet/in.h> */
+#undef HAVE_SOCKADDR_IN6
+
+/* Define if `struct addrinfo' exists in <netdb.h> */
+#undef HAVE_ADDRINFO
+
+/*
+ * Define if <netdb.h> contains AI_NUMERICHOST et al.
+ * Systems which only implement RFC2133 will need this.
+ */
+#undef HAVE_RFC2553_NETDB
+
+/* Define if `struct direct' has a d_namlen element */
+#undef HAVE_D_NAMLEN
+
+/* Define if GLOB_BRACE exists in <glob.h> */
+#undef HAVE_GLOB_BRACE
+
+/* Define if h_errno exists in <netdb.h> */
+#undef HAVE_H_ERRNO_D
+
+/* Define if fclose() is declared in <stdio.h> */
+#undef HAVE_FCLOSE_D
+
+/* Define if getpass() is declared in <stdlib.h> or <unistd.h> */
+#undef HAVE_GETPASS_D
+
+/* Define if optarg is declared in <stdlib.h> or <unistd.h> */
+#undef HAVE_OPTARG_D
+
+/* Define if optind is declared in <stdlib.h> or <unistd.h> */
+#undef HAVE_OPTIND_D
+
+/* Define if pclose() is declared in <stdio.h> */
+#undef HAVE_PCLOSE_D
+
+/* Define if `long long' is supported and sizeof(off_t) >= 8 */
+#undef HAVE_QUAD_SUPPORT
+
+/* Define if strptime() is declared in <time.h> */
+#undef HAVE_STRPTIME_D
+
+/*
+ * Define this if compiling with SOCKS (the firewall traversal library).
+ * Also, you must define connect, getsockname, bind, accept, listen, and
+ * select to their R-versions.
+ */
+#undef SOCKS
+#undef SOCKS4
+#undef SOCKS5
+#undef connect
+#undef getsockname
+#undef bind
+#undef accept
+#undef listen
+#undef select
+#undef dup
+#undef dup2
+#undef fclose
+#undef gethostbyname
+#undef getpeername
+#undef read
+#undef recv
+#undef recvfrom
+#undef rresvport
+#undef send
+#undef sendto
+#undef shutdown
+#undef write
diff --git a/contrib/lukemftp/aclocal.m4 b/contrib/lukemftp/aclocal.m4
new file mode 100644
index 000000000000..3e275089625a
--- /dev/null
+++ b/contrib/lukemftp/aclocal.m4
@@ -0,0 +1,257 @@
+dnl $Id: aclocal.m4,v 1.5 1999/11/13 10:50:39 lukem Exp $
+dnl
+
+dnl
+dnl AC_MSG_TRY_COMPILE
+dnl
+dnl Written by Luke Mewburn <lukem@netbsd.org>
+dnl
+dnl Usage:
+dnl AC_MSG_TRY_COMPILE(Message, CacheVar, Includes, Code,
+dnl ActionPass [,ActionFail] )
+dnl
+dnl effectively does:
+dnl AC_CACHE_CHECK(Message, CacheVar,
+dnl AC_TRY_COMPILE(Includes, Code, CacheVar = yes, CacheVar = no)
+dnl if CacheVar == yes
+dnl AC_MESSAGE_RESULT(yes)
+dnl ActionPass
+dnl else
+dnl AC_MESSAGE_RESULT(no)
+dnl ActionFail
+dnl )
+dnl
+AC_DEFUN(AC_MSG_TRY_COMPILE, [
+ AC_CACHE_CHECK($1, $2, [
+ AC_TRY_COMPILE([ $3 ], [ $4; ], [ $2=yes ], [ $2=no ])
+ ])
+ if test "x[$]$2" = "xyes"; then
+ $5
+ else
+ $6
+ :
+ fi
+])
+
+dnl
+dnl AC_MSG_TRY_LINK
+dnl
+dnl Usage:
+dnl AC_MSG_TRY_LINK(Message, CacheVar, Includes, Code,
+dnl ActionPass [,ActionFail] )
+dnl
+dnl as AC_MSG_TRY_COMPILE, but uses AC_TRY_LINK instead of AC_TRY_COMPILE
+dnl
+AC_DEFUN(AC_MSG_TRY_LINK, [
+ AC_CACHE_CHECK($1, $2, [
+ AC_TRY_LINK([ $3 ], [ $4; ], [ $2=yes ], [ $2=no ])
+ ])
+ if test "x[$]$2" = "xyes"; then
+ $5
+ else
+ $6
+ :
+ fi
+])
+
+
+dnl
+dnl AC_LIBRARY_NET: #Id: net.m4,v 1.5 1997/11/09 21:36:54 jhawk Exp #
+dnl
+dnl Written by John Hawkinson <jhawk@mit.edu>. This code is in the Public
+dnl Domain.
+dnl
+dnl This test is for network applications that need socket() and
+dnl gethostbyname() -ish functions. Under Solaris, those applications need to
+dnl link with "-lsocket -lnsl". Under IRIX, they should *not* link with
+dnl "-lsocket" because libsocket.a breaks a number of things (for instance:
+dnl gethostbyname() under IRIX 5.2, and snoop sockets under most versions of
+dnl IRIX).
+dnl
+dnl Unfortunately, many application developers are not aware of this, and
+dnl mistakenly write tests that cause -lsocket to be used under IRIX. It is
+dnl also easy to write tests that cause -lnsl to be used under operating
+dnl systems where neither are necessary (or useful), such as SunOS 4.1.4, which
+dnl uses -lnsl for TLI.
+dnl
+dnl This test exists so that every application developer does not test this in
+dnl a different, and subtly broken fashion.
+dnl
+dnl It has been argued that this test should be broken up into two seperate
+dnl tests, one for the resolver libraries, and one for the libraries necessary
+dnl for using Sockets API. Unfortunately, the two are carefully intertwined and
+dnl allowing the autoconf user to use them independantly potentially results in
+dnl unfortunate ordering dependancies -- as such, such component macros would
+dnl have to carefully use indirection and be aware if the other components were
+dnl executed. Since other autoconf macros do not go to this trouble, and almost
+dnl no applications use sockets without the resolver, this complexity has not
+dnl been implemented.
+dnl
+dnl The check for libresolv is in case you are attempting to link statically
+dnl and happen to have a libresolv.a lying around (and no libnsl.a).
+dnl
+AC_DEFUN(AC_LIBRARY_NET, [
+ # Most operating systems have gethostbyname() in the default searched
+ # libraries (i.e. libc):
+ AC_CHECK_FUNC(gethostbyname, ,
+ # Some OSes (eg. Solaris) place it in libnsl:
+ AC_CHECK_LIB(nsl, gethostbyname, ,
+ # Some strange OSes (SINIX) have it in libsocket:
+ AC_CHECK_LIB(socket, gethostbyname, ,
+ # Unfortunately libsocket sometimes depends on libnsl.
+ # AC_CHECK_LIB's API is essentially broken so the following
+ # ugliness is necessary:
+ AC_CHECK_LIB(socket, gethostbyname,
+ LIBS="-lsocket -lnsl $LIBS",
+ AC_CHECK_LIB(resolv, gethostbyname),
+ -lnsl)
+ )
+ )
+ )
+ AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket, ,
+ AC_CHECK_LIB(socket, socket, LIBS="-lsocket -lnsl $LIBS", , -lnsl)))
+ ])
+
+
+dnl Checks for SOCKS firewall support.
+dnl
+dnl Written by Matthew R. Green <mrg@eterna.com.au>
+dnl
+AC_DEFUN(AC_LIBRARY_SOCKS, [
+ AC_MSG_CHECKING(whether to support SOCKS)
+ AC_ARG_WITH(socks,
+ [ --with-socks Compile with SOCKS firewall traversal support.],
+ [
+ case "$withval" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_CHECK_LIB(socks5, SOCKSconnect, [
+ socks=5
+ LIBS="-lsocks5 $LIBS"], [
+ AC_CHECK_LIB(socks, Rconnect, [
+ socks=4
+ LIBS="-lsocks $LIBS"], [
+ AC_MSG_ERROR(Could not find socks library. You must first install socks.) ] ) ] )
+ ;;
+ esac
+ ],
+ AC_MSG_RESULT(no)
+ )
+
+ if test "x$socks" = "x"; then
+ AC_MSG_CHECKING(whether to support SOCKS5)
+ AC_ARG_WITH(socks5,
+ [ --with-socks5[=PATH] Compile with SOCKS5 firewall traversal support.],
+ [
+ case "$withval" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ socks=5
+ if test "x$withval" = "xyes"; then
+ withval="-lsocks5"
+ else
+ if test -d "$withval"; then
+ if test -d "$withval/include"; then
+ CFLAGS="$CFLAGS -I$withval/include"
+ else
+ CFLAGS="$CFLAGS -I$withval"
+ fi
+ if test -d "$withval/lib"; then
+ withval="-L$withval/lib -lsocks5"
+ else
+ withval="-L$withval -lsocks5"
+ fi
+ fi
+ fi
+ LIBS="$withval $LIBS"
+ # If Socks was compiled with Kerberos support, we will need
+ # to link against kerberos libraries. Temporarily append
+ # to LIBS. This is harmless if there is no kerberos support.
+ TMPLIBS="$LIBS"
+ LIBS="$LIBS $KERBEROS_LIBS"
+ AC_TRY_LINK([],
+ [ SOCKSconnect(); ],
+ [],
+ [ AC_MSG_ERROR(Could not find the $withval library. You must first install socks5.) ])
+ LIBS="$TMPLIBS"
+ ;;
+ esac
+ ],
+ AC_MSG_RESULT(no)
+ )
+ fi
+
+ if test "x$socks" = "x"; then
+ AC_MSG_CHECKING(whether to support SOCKS4)
+ AC_ARG_WITH(socks4,
+ [ --with-socks4[=PATH] Compile with SOCKS4 firewall traversal support.],
+ [
+ case "$withval" in
+ no)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ socks=4
+ if test "x$withval" = "xyes"; then
+ withval="-lsocks"
+ else
+ if test -d "$withval"; then
+ withval="-L$withval -lsocks"
+ fi
+ fi
+ LIBS="$withval $LIBS"
+ AC_TRY_LINK([],
+ [ Rconnect(); ],
+ [],
+ [ AC_MSG_ERROR(Could not find the $withval library. You must first install socks.) ])
+ ;;
+ esac
+ ],
+ AC_MSG_RESULT(no)
+ )
+ fi
+
+ if test "x$socks" = "x4"; then
+ AC_DEFINE(SOCKS)
+ AC_DEFINE(SOCKS4)
+ AC_DEFINE(connect, Rconnect)
+ AC_DEFINE(getsockname, Rgetsockname)
+ AC_DEFINE(bind, Rbind)
+ AC_DEFINE(accept, Raccept)
+ AC_DEFINE(listen, Rlisten)
+ AC_DEFINE(select, Rselect)
+ fi
+
+ if test "x$socks" = "x5"; then
+ AC_DEFINE(SOCKS)
+ AC_DEFINE(SOCKS5)
+ AC_DEFINE(connect,SOCKSconnect)
+ AC_DEFINE(getsockname,SOCKSgetsockname)
+ AC_DEFINE(getpeername,SOCKSgetpeername)
+ AC_DEFINE(bind,SOCKSbind)
+ AC_DEFINE(accept,SOCKSaccept)
+ AC_DEFINE(listen,SOCKSlisten)
+ AC_DEFINE(select,SOCKSselect)
+ AC_DEFINE(recvfrom,SOCKSrecvfrom)
+ AC_DEFINE(sendto,SOCKSsendto)
+ AC_DEFINE(recv,SOCKSrecv)
+ AC_DEFINE(send,SOCKSsend)
+ AC_DEFINE(read,SOCKSread)
+ AC_DEFINE(write,SOCKSwrite)
+ AC_DEFINE(rresvport,SOCKSrresvport)
+ AC_DEFINE(shutdown,SOCKSshutdown)
+ AC_DEFINE(listen,SOCKSlisten)
+ AC_DEFINE(close,SOCKSclose)
+ AC_DEFINE(dup,SOCKSdup)
+ AC_DEFINE(dup2,SOCKSdup2)
+ AC_DEFINE(fclose,SOCKSfclose)
+ AC_DEFINE(gethostbyname,SOCKSgethostbyname)
+ fi
+])
diff --git a/contrib/lukemftp/config.h.in b/contrib/lukemftp/config.h.in
new file mode 100644
index 000000000000..2ca7e20e5b1a
--- /dev/null
+++ b/contrib/lukemftp/config.h.in
@@ -0,0 +1,266 @@
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+/* $Id: config.h.in,v 1.24 2000/09/18 00:40:12 lukem Exp $ */
+
+
+/* Define if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+
+/* Define if the closedir function returns void instead of int. */
+#undef CLOSEDIR_VOID
+
+/* Define if the `getpgrp' function takes no argument. */
+#undef GETPGRP_VOID
+
+/* Define if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Define if your Fortran 77 compiler doesn't accept -c and -o together. */
+#undef F77_NO_MINUS_C_MINUS_O
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+#undef off_t
+
+/* Define to the type of arg1 for select(). */
+#undef SELECT_TYPE_ARG1
+
+/* Define to the type of args 2, 3 and 4 for select(). */
+#undef SELECT_TYPE_ARG234
+
+/* Define to the type of arg5 for select(). */
+#undef SELECT_TYPE_ARG5
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if the closedir function returns void instead of int. */
+#undef VOID_CLOSEDIR
+
+/* The number of bytes in a off_t. */
+#undef SIZEOF_OFF_T
+
+/* Define if you have the err function. */
+#undef HAVE_ERR
+
+/* Define if you have the fgetln function. */
+#undef HAVE_FGETLN
+
+/* Define if you have the fparseln function. */
+#undef HAVE_FPARSELN
+
+/* Define if you have the getaddrinfo function. */
+#undef HAVE_GETADDRINFO
+
+/* Define if you have the gethostbyname2 function. */
+#undef HAVE_GETHOSTBYNAME2
+
+/* Define if you have the getnameinfo function. */
+#undef HAVE_GETNAMEINFO
+
+/* Define if you have the getpassphrase function. */
+#undef HAVE_GETPASSPHRASE
+
+/* Define if you have the getpgrp function. */
+#undef HAVE_GETPGRP
+
+/* Define if you have the glob function. */
+#undef HAVE_GLOB
+
+/* Define if you have the inet_ntop function. */
+#undef HAVE_INET_NTOP
+
+/* Define if you have the inet_pton function. */
+#undef HAVE_INET_PTON
+
+/* Define if you have the issetugid function. */
+#undef HAVE_ISSETUGID
+
+/* Define if you have the memmove function. */
+#undef HAVE_MEMMOVE
+
+/* Define if you have the mkstemp function. */
+#undef HAVE_MKSTEMP
+
+/* Define if you have the poll function. */
+#undef HAVE_POLL
+
+/* Define if you have the select function. */
+#undef HAVE_SELECT
+
+/* Define if you have the sl_init function. */
+#undef HAVE_SL_INIT
+
+/* Define if you have the snprintf function. */
+#undef HAVE_SNPRINTF
+
+/* Define if you have the strdup function. */
+#undef HAVE_STRDUP
+
+/* Define if you have the strerror function. */
+#undef HAVE_STRERROR
+
+/* Define if you have the strlcat function. */
+#undef HAVE_STRLCAT
+
+/* Define if you have the strlcpy function. */
+#undef HAVE_STRLCPY
+
+/* Define if you have the strptime function. */
+#undef HAVE_STRPTIME
+
+/* Define if you have the strsep function. */
+#undef HAVE_STRSEP
+
+/* Define if you have the strtoll function. */
+#undef HAVE_STRTOLL
+
+/* Define if you have the strunvis function. */
+#undef HAVE_STRUNVIS
+
+/* Define if you have the strvis function. */
+#undef HAVE_STRVIS
+
+/* Define if you have the timegm function. */
+#undef HAVE_TIMEGM
+
+/* Define if you have the usleep function. */
+#undef HAVE_USLEEP
+
+/* Define if you have the <dirent.h> header file. */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <err.h> header file. */
+#undef HAVE_ERR_H
+
+/* Define if you have the <ndir.h> header file. */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <paths.h> header file. */
+#undef HAVE_PATHS_H
+
+/* Define if you have the <poll.h> header file. */
+#undef HAVE_POLL_H
+
+/* Define if you have the <regex.h> header file. */
+#undef HAVE_REGEX_H
+
+/* Define if you have the <sys/dir.h> header file. */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ndir.h> header file. */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/poll.h> header file. */
+#undef HAVE_SYS_POLL_H
+
+/* Define if you have the <termcap.h> header file. */
+#undef HAVE_TERMCAP_H
+
+/* Define if you have the <util.h> header file. */
+#undef HAVE_UTIL_H
+
+/* Define if you have the <vis.h> header file. */
+#undef HAVE_VIS_H
+
+/* Define if you have the nsl library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define if you have the socket library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define if you have the tinfo library (-ltinfo). */
+#undef HAVE_LIBTINFO
+
+/* Define if you have the util library (-lutil). */
+#undef HAVE_LIBUTIL
+
+/* Define if your compiler supports `long long' */
+#undef HAVE_LONG_LONG
+
+/* Define if in_port_t exists */
+#undef HAVE_IN_PORT_T
+
+/* Define if struct sockaddr.sa_len exists (implies sockaddr_in.sin_len, etc) */
+#undef HAVE_SOCKADDR_SA_LEN
+
+/* Define if socklen_t exists */
+#undef HAVE_SOCKLEN_T
+
+/* Define if AF_INET6 exists in <sys/socket.h> */
+#undef HAVE_AF_INET6
+
+/* Define if `struct sockaddr_in6' exists in <netinet/in.h> */
+#undef HAVE_SOCKADDR_IN6
+
+/* Define if `struct addrinfo' exists in <netdb.h> */
+#undef HAVE_ADDRINFO
+
+/*
+ * Define if <netdb.h> contains AI_NUMERICHOST et al.
+ * Systems which only implement RFC2133 will need this.
+ */
+#undef HAVE_RFC2553_NETDB
+
+/* Define if `struct direct' has a d_namlen element */
+#undef HAVE_D_NAMLEN
+
+/* Define if GLOB_BRACE exists in <glob.h> */
+#undef HAVE_GLOB_BRACE
+
+/* Define if h_errno exists in <netdb.h> */
+#undef HAVE_H_ERRNO_D
+
+/* Define if fclose() is declared in <stdio.h> */
+#undef HAVE_FCLOSE_D
+
+/* Define if getpass() is declared in <stdlib.h> or <unistd.h> */
+#undef HAVE_GETPASS_D
+
+/* Define if optarg is declared in <stdlib.h> or <unistd.h> */
+#undef HAVE_OPTARG_D
+
+/* Define if optind is declared in <stdlib.h> or <unistd.h> */
+#undef HAVE_OPTIND_D
+
+/* Define if pclose() is declared in <stdio.h> */
+#undef HAVE_PCLOSE_D
+
+/* Define if `long long' is supported and sizeof(off_t) >= 8 */
+#undef HAVE_QUAD_SUPPORT
+
+/* Define if strptime() is declared in <time.h> */
+#undef HAVE_STRPTIME_D
+
+/*
+ * Define this if compiling with SOCKS (the firewall traversal library).
+ * Also, you must define connect, getsockname, bind, accept, listen, and
+ * select to their R-versions.
+ */
+#undef SOCKS
+#undef SOCKS4
+#undef SOCKS5
+#undef connect
+#undef getsockname
+#undef bind
+#undef accept
+#undef listen
+#undef select
+#undef dup
+#undef dup2
+#undef fclose
+#undef gethostbyname
+#undef getpeername
+#undef read
+#undef recv
+#undef recvfrom
+#undef rresvport
+#undef send
+#undef sendto
+#undef shutdown
+#undef write
diff --git a/contrib/lukemftp/configure b/contrib/lukemftp/configure
new file mode 100755
index 000000000000..b1d179df04e9
--- /dev/null
+++ b/contrib/lukemftp/configure
@@ -0,0 +1,4129 @@
+#! /bin/sh
+
+# From configure.in Revision: 1.31
+
+
+
+
+
+
+
+
+
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+\
+ --enable-editcomplete Turn on command line editing and completion.
+ --disable-editcomplete Turn off command line editing and completion
+ [default: enabled]."
+ac_help="$ac_help
+\
+ --enable-ipv6 Enable IPv6 support (if your OS supports it).
+ --disable-ipv6 Disable IPv6 support (even if your OS supports it)
+ [default: enabled]."
+ac_help="$ac_help
+ --with-socks Compile with SOCKS firewall traversal support."
+ac_help="$ac_help
+ --with-socks5[=PATH] Compile with SOCKS5 firewall traversal support."
+ac_help="$ac_help
+ --with-socks4[=PATH] Compile with SOCKS4 firewall traversal support."
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=lukemftp.h
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+if test "$program_transform_name" = s,x,x,; then
+ program_transform_name=
+else
+ # Double any \ or $. echo might interpret backslashes.
+ cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+ program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+ rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+ program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+# Check whether --enable-editcomplete or --disable-editcomplete was given.
+if test "${enable_editcomplete+set}" = set; then
+ enableval="$enable_editcomplete"
+ opt_editcomplete=$enableval
+else
+ opt_editcomplete=yes
+fi
+
+# Check whether --enable-ipv6 or --disable-ipv6 was given.
+if test "${enable_ipv6+set}" = set; then
+ enableval="$enable_ipv6"
+ opt_ipv6=$enableval
+else
+ opt_ipv6=yes
+fi
+
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:590: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftestmake <<\EOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ SET_MAKE=
+else
+ echo "$ac_t""no" 1>&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:619: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:649: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:700: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:732: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 743 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:748: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:774: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:779: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:788: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:807: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+
+for ac_prog in mawk gawk nawk awk
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:843: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_AWK="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+AWK="$ac_cv_prog_AWK"
+if test -n "$AWK"; then
+ echo "$ac_t""$AWK" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$AWK" && break
+done
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:903: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:958: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_RANLIB="ranlib"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+ echo "$ac_t""$RANLIB" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+for ac_prog in ar
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:990: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_AR="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+AR="$ac_cv_prog_AR"
+if test -n "$AR"; then
+ echo "$ac_t""$AR" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$AR" && break
+done
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1020: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 1035 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1041: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 1052 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1058: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 1069 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1075: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for AIX""... $ac_c" 1>&6
+echo "configure:1100: checking for AIX" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1102 "configure"
+#include "confdefs.h"
+#ifdef _AIX
+ yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ rm -rf conftest*
+ echo "$ac_t""yes" 1>&6; cat >> confdefs.h <<\EOF
+#define _ALL_SOURCE 1
+EOF
+
+else
+ rm -rf conftest*
+ echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+
+
+
+
+echo $ac_n "checking for fparseln in -lutil""... $ac_c" 1>&6
+echo "configure:1126: checking for fparseln in -lutil" >&5
+ac_lib_var=`echo util'_'fparseln | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lutil $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1134 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char fparseln();
+
+int main() {
+fparseln()
+; return 0; }
+EOF
+if { (eval echo configure:1145: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo util | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lutil $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test $opt_editcomplete = yes; then
+ echo $ac_n "checking for tgetent in -ltinfo""... $ac_c" 1>&6
+echo "configure:1174: checking for tgetent in -ltinfo" >&5
+ac_lib_var=`echo tinfo'_'tgetent | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ltinfo $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1182 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char tgetent();
+
+int main() {
+tgetent()
+; return 0; }
+EOF
+if { (eval echo configure:1193: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo tinfo | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-ltinfo $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for tgetent in -ltermcap""... $ac_c" 1>&6
+echo "configure:1219: checking for tgetent in -ltermcap" >&5
+ac_lib_var=`echo termcap'_'tgetent | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ltermcap $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1227 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char tgetent();
+
+int main() {
+tgetent()
+; return 0; }
+EOF
+if { (eval echo configure:1238: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo termcap | sed -e 's/^a-zA-Z0-9_/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-ltermcap $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for tgetent in -lcurses""... $ac_c" 1>&6
+echo "configure:1264: checking for tgetent in -lcurses" >&5
+ac_lib_var=`echo curses'_'tgetent | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lcurses $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1272 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char tgetent();
+
+int main() {
+tgetent()
+; return 0; }
+EOF
+if { (eval echo configure:1283: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo curses | sed -e 's/^a-zA-Z0-9_/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lcurses $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for tgetent in -lncurses""... $ac_c" 1>&6
+echo "configure:1309: checking for tgetent in -lncurses" >&5
+ac_lib_var=`echo ncurses'_'tgetent | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lncurses $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1317 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char tgetent();
+
+int main() {
+tgetent()
+; return 0; }
+EOF
+if { (eval echo configure:1328: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo ncurses | sed -e 's/^a-zA-Z0-9_/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lncurses $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+fi
+
+fi
+
+
+echo $ac_n "checking for library containing el_init""... $ac_c" 1>&6
+echo "configure:1363: checking for library containing el_init" >&5
+if eval "test \"`echo '$''{'ac_cv_search_el_init'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_func_search_save_LIBS="$LIBS"
+ac_cv_search_el_init="no"
+cat > conftest.$ac_ext <<EOF
+#line 1370 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char el_init();
+
+int main() {
+el_init()
+; return 0; }
+EOF
+if { (eval echo configure:1381: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_cv_search_el_init="none required"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+test "$ac_cv_search_el_init" = "no" && for i in edit; do
+LIBS="-l$i $ac_func_search_save_LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1392 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char el_init();
+
+int main() {
+el_init()
+; return 0; }
+EOF
+if { (eval echo configure:1403: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_cv_search_el_init="-l$i"
+break
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+LIBS="$ac_func_search_save_LIBS"
+fi
+
+echo "$ac_t""$ac_cv_search_el_init" 1>&6
+if test "$ac_cv_search_el_init" != "no"; then
+ test "$ac_cv_search_el_init" = "none required" || LIBS="$ac_cv_search_el_init $LIBS"
+ have_libedit=yes
+else :
+ have_libedit=no
+fi
+fi
+
+ # Most operating systems have gethostbyname() in the default searched
+ # libraries (i.e. libc):
+ echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6
+echo "configure:1428: checking for gethostbyname" >&5
+if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1433 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char gethostbyname(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_gethostbyname) || defined (__stub___gethostbyname)
+choke me
+#else
+gethostbyname();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1456: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_gethostbyname=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_gethostbyname=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+# Some OSes (eg. Solaris) place it in libnsl:
+ echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6
+echo "configure:1475: checking for gethostbyname in -lnsl" >&5
+ac_lib_var=`echo nsl'_'gethostbyname | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lnsl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1483 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:1494: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/^a-zA-Z0-9_/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lnsl $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+# Some strange OSes (SINIX) have it in libsocket:
+ echo $ac_n "checking for gethostbyname in -lsocket""... $ac_c" 1>&6
+echo "configure:1521: checking for gethostbyname in -lsocket" >&5
+ac_lib_var=`echo socket'_'gethostbyname | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocket $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1529 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:1540: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/^a-zA-Z0-9_/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsocket $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+# Unfortunately libsocket sometimes depends on libnsl.
+ # AC_CHECK_LIB's API is essentially broken so the following
+ # ugliness is necessary:
+ echo $ac_n "checking for gethostbyname in -lsocket""... $ac_c" 1>&6
+echo "configure:1569: checking for gethostbyname in -lsocket" >&5
+ac_lib_var=`echo socket'_'gethostbyname | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocket -lnsl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1577 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:1588: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="-lsocket -lnsl $LIBS"
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for gethostbyname in -lresolv""... $ac_c" 1>&6
+echo "configure:1607: checking for gethostbyname in -lresolv" >&5
+ac_lib_var=`echo resolv'_'gethostbyname | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lresolv $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1615 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:1626: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo resolv | sed -e 's/^a-zA-Z0-9_/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lresolv $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ echo $ac_n "checking for socket""... $ac_c" 1>&6
+echo "configure:1665: checking for socket" >&5
+if eval "test \"`echo '$''{'ac_cv_func_socket'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1670 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char socket(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_socket) || defined (__stub___socket)
+choke me
+#else
+socket();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1693: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_socket=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_socket=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'socket`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
+echo "configure:1711: checking for socket in -lsocket" >&5
+ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocket $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1719 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket();
+
+int main() {
+socket()
+; return 0; }
+EOF
+if { (eval echo configure:1730: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/^a-zA-Z0-9_/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsocket $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
+echo "configure:1756: checking for socket in -lsocket" >&5
+ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocket -lnsl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1764 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket();
+
+int main() {
+socket()
+; return 0; }
+EOF
+if { (eval echo configure:1775: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="-lsocket -lnsl $LIBS"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+fi
+
+
+
+ echo $ac_n "checking whether to support SOCKS""... $ac_c" 1>&6
+echo "configure:1802: checking whether to support SOCKS" >&5
+ # Check whether --with-socks or --without-socks was given.
+if test "${with_socks+set}" = set; then
+ withval="$with_socks"
+
+ case "$withval" in
+ no)
+ echo "$ac_t""no" 1>&6
+ ;;
+ yes)
+ echo "$ac_t""yes" 1>&6
+ echo $ac_n "checking for SOCKSconnect in -lsocks5""... $ac_c" 1>&6
+echo "configure:1814: checking for SOCKSconnect in -lsocks5" >&5
+ac_lib_var=`echo socks5'_'SOCKSconnect | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocks5 $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1822 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char SOCKSconnect();
+
+int main() {
+SOCKSconnect()
+; return 0; }
+EOF
+if { (eval echo configure:1833: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+
+ socks=5
+ LIBS="-lsocks5 $LIBS"
+else
+ echo "$ac_t""no" 1>&6
+
+ echo $ac_n "checking for Rconnect in -lsocks""... $ac_c" 1>&6
+echo "configure:1855: checking for Rconnect in -lsocks" >&5
+ac_lib_var=`echo socks'_'Rconnect | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocks $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1863 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char Rconnect();
+
+int main() {
+Rconnect()
+; return 0; }
+EOF
+if { (eval echo configure:1874: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+
+ socks=4
+ LIBS="-lsocks $LIBS"
+else
+ echo "$ac_t""no" 1>&6
+
+ { echo "configure: error: Could not find socks library. You must first install socks." 1>&2; exit 1; }
+fi
+
+fi
+
+ ;;
+ esac
+
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+
+ if test "x$socks" = "x"; then
+ echo $ac_n "checking whether to support SOCKS5""... $ac_c" 1>&6
+echo "configure:1911: checking whether to support SOCKS5" >&5
+ # Check whether --with-socks5 or --without-socks5 was given.
+if test "${with_socks5+set}" = set; then
+ withval="$with_socks5"
+
+ case "$withval" in
+ no)
+ echo "$ac_t""no" 1>&6
+ ;;
+ *)
+ echo "$ac_t""yes" 1>&6
+ socks=5
+ if test "x$withval" = "xyes"; then
+ withval="-lsocks5"
+ else
+ if test -d "$withval"; then
+ if test -d "$withval/include"; then
+ CFLAGS="$CFLAGS -I$withval/include"
+ else
+ CFLAGS="$CFLAGS -I$withval"
+ fi
+ if test -d "$withval/lib"; then
+ withval="-L$withval/lib -lsocks5"
+ else
+ withval="-L$withval -lsocks5"
+ fi
+ fi
+ fi
+ LIBS="$withval $LIBS"
+ # If Socks was compiled with Kerberos support, we will need
+ # to link against kerberos libraries. Temporarily append
+ # to LIBS. This is harmless if there is no kerberos support.
+ TMPLIBS="$LIBS"
+ LIBS="$LIBS $KERBEROS_LIBS"
+ cat > conftest.$ac_ext <<EOF
+#line 1946 "configure"
+#include "confdefs.h"
+
+int main() {
+ SOCKSconnect();
+; return 0; }
+EOF
+if { (eval echo configure:1953: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ { echo "configure: error: Could not find the $withval library. You must first install socks5." 1>&2; exit 1; }
+fi
+rm -f conftest*
+ LIBS="$TMPLIBS"
+ ;;
+ esac
+
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+ fi
+
+ if test "x$socks" = "x"; then
+ echo $ac_n "checking whether to support SOCKS4""... $ac_c" 1>&6
+echo "configure:1975: checking whether to support SOCKS4" >&5
+ # Check whether --with-socks4 or --without-socks4 was given.
+if test "${with_socks4+set}" = set; then
+ withval="$with_socks4"
+
+ case "$withval" in
+ no)
+ echo "$ac_t""no" 1>&6
+ ;;
+ *)
+ echo "$ac_t""yes" 1>&6
+ socks=4
+ if test "x$withval" = "xyes"; then
+ withval="-lsocks"
+ else
+ if test -d "$withval"; then
+ withval="-L$withval -lsocks"
+ fi
+ fi
+ LIBS="$withval $LIBS"
+ cat > conftest.$ac_ext <<EOF
+#line 1996 "configure"
+#include "confdefs.h"
+
+int main() {
+ Rconnect();
+; return 0; }
+EOF
+if { (eval echo configure:2003: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ { echo "configure: error: Could not find the $withval library. You must first install socks." 1>&2; exit 1; }
+fi
+rm -f conftest*
+ ;;
+ esac
+
+else
+ echo "$ac_t""no" 1>&6
+
+fi
+
+ fi
+
+ if test "x$socks" = "x4"; then
+ cat >> confdefs.h <<\EOF
+#define SOCKS 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define SOCKS4 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define connect Rconnect
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define getsockname Rgetsockname
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define bind Rbind
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define accept Raccept
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define listen Rlisten
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define select Rselect
+EOF
+
+ fi
+
+ if test "x$socks" = "x5"; then
+ cat >> confdefs.h <<\EOF
+#define SOCKS 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define SOCKS5 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define connect SOCKSconnect
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define getsockname SOCKSgetsockname
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define getpeername SOCKSgetpeername
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define bind SOCKSbind
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define accept SOCKSaccept
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define listen SOCKSlisten
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define select SOCKSselect
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define recvfrom SOCKSrecvfrom
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define sendto SOCKSsendto
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define recv SOCKSrecv
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define send SOCKSsend
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define read SOCKSread
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define write SOCKSwrite
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define rresvport SOCKSrresvport
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define shutdown SOCKSshutdown
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define listen SOCKSlisten
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define close SOCKSclose
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define dup SOCKSdup
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define dup2 SOCKSdup2
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define fclose SOCKSfclose
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define gethostbyname SOCKSgethostbyname
+EOF
+
+ fi
+
+
+
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:2160: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2165 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:2173: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:2198: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldir $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2206 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:2217: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -ldir"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:2239: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lx $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2247 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:2258: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lx"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:2281: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2286 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2294: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 2311 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 2329 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2350 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:2361: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in err.h regex.h paths.h poll.h sys/poll.h termcap.h util.h vis.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2388: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2393 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2398: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:2427: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2432 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:2441: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_time=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+ cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking for off_t""... $ac_c" 1>&6
+echo "configure:2462: checking for off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2467 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_off_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+if test $ac_cv_type_off_t = no; then
+ cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+fi
+
+echo $ac_n "checking size of off_t""... $ac_c" 1>&6
+echo "configure:2495: checking size of off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_off_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_sizeof_off_t=0
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2503 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ fprintf(f, "%d\n", sizeof(off_t));
+ exit(0);
+}
+EOF
+if { (eval echo configure:2514: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_sizeof_off_t=`cat conftestval`
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_sizeof_off_t=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_off_t" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_OFF_T $ac_cv_sizeof_off_t
+EOF
+
+
+
+ echo $ac_n "checking for long long""... $ac_c" 1>&6
+echo "configure:2535: checking for long long" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_LONG_LONG'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2541 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+int main() {
+
+long long X = 2, Y = 1, Z;
+Z = X / Y; ;
+; return 0; }
+EOF
+if { (eval echo configure:2551: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ftp_cv_HAVE_LONG_LONG=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_LONG_LONG=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_LONG_LONG" 1>&6
+ if test "x$ftp_cv_HAVE_LONG_LONG" = "xyes"; then
+
+cat >> confdefs.h <<\EOF
+#define HAVE_LONG_LONG 1
+EOF
+
+have_long_long=yes
+ else
+ have_long_long=no
+ :
+ fi
+
+
+
+ echo $ac_n "checking for in_port_t""... $ac_c" 1>&6
+echo "configure:2580: checking for in_port_t" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_IN_PORT_T'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2586 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+int main() {
+ in_port_t X ;
+; return 0; }
+EOF
+if { (eval echo configure:2595: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_IN_PORT_T=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_IN_PORT_T=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_IN_PORT_T" 1>&6
+ if test "x$ftp_cv_HAVE_IN_PORT_T" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_IN_PORT_T 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for sockaddr_in.sin_len""... $ac_c" 1>&6
+echo "configure:2622: checking for sockaddr_in.sin_len" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_SOCKADDR_SA_LEN'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2628 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+int main() {
+
+ struct sockaddr_in sin;
+ int X = sin.sin_len ;
+; return 0; }
+EOF
+if { (eval echo configure:2640: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_SOCKADDR_SA_LEN=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_SOCKADDR_SA_LEN=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_SOCKADDR_SA_LEN" 1>&6
+ if test "x$ftp_cv_HAVE_SOCKADDR_SA_LEN" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SOCKADDR_SA_LEN 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for socklen_t""... $ac_c" 1>&6
+echo "configure:2667: checking for socklen_t" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_SOCKLEN_T'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2673 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+int main() {
+ socklen_t X ;
+; return 0; }
+EOF
+if { (eval echo configure:2682: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_SOCKLEN_T=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_SOCKLEN_T=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_SOCKLEN_T" 1>&6
+ if test "x$ftp_cv_HAVE_SOCKLEN_T" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SOCKLEN_T 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+if test $opt_ipv6 = yes; then
+
+
+ echo $ac_n "checking for AF_INET6""... $ac_c" 1>&6
+echo "configure:2711: checking for AF_INET6" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_AF_INET6'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2717 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+int main() {
+ int X = AF_INET6 ;
+; return 0; }
+EOF
+if { (eval echo configure:2726: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_AF_INET6=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_AF_INET6=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_AF_INET6" 1>&6
+ if test "x$ftp_cv_HAVE_AF_INET6" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_AF_INET6 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for struct sockaddr_in6""... $ac_c" 1>&6
+echo "configure:2753: checking for struct sockaddr_in6" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_SOCKADDR_IN6'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2759 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+int main() {
+ struct sockaddr_in6 X ;
+; return 0; }
+EOF
+if { (eval echo configure:2768: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_SOCKADDR_IN6=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_SOCKADDR_IN6=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_SOCKADDR_IN6" 1>&6
+ if test "x$ftp_cv_HAVE_SOCKADDR_IN6" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SOCKADDR_IN6 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+fi
+
+
+ echo $ac_n "checking for struct addrinfo""... $ac_c" 1>&6
+echo "configure:2797: checking for struct addrinfo" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_ADDRINFO'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2803 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+int main() {
+ struct addrinfo X ;
+; return 0; }
+EOF
+if { (eval echo configure:2813: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_ADDRINFO=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_ADDRINFO=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_ADDRINFO" 1>&6
+ if test "x$ftp_cv_HAVE_ADDRINFO" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ADDRINFO 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for d_namlen in struct dirent""... $ac_c" 1>&6
+echo "configure:2840: checking for d_namlen in struct dirent" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_D_NAMLEN'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2846 "configure"
+#include "confdefs.h"
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+#else
+# define dirent direct
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+int main() {
+
+ struct dirent dp;
+ int X = dp.d_namlen; ;
+; return 0; }
+EOF
+if { (eval echo configure:2869: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_D_NAMLEN=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_D_NAMLEN=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_D_NAMLEN" 1>&6
+ if test "x$ftp_cv_HAVE_D_NAMLEN" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_D_NAMLEN 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for GLOB_BRACE""... $ac_c" 1>&6
+echo "configure:2896: checking for GLOB_BRACE" >&5
+if eval "test \"`echo '$''{'ftp_cv_have_glob_brace'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2902 "configure"
+#include "confdefs.h"
+
+#include <glob.h>
+int main() {
+ int X = GLOB_BRACE ;
+; return 0; }
+EOF
+if { (eval echo configure:2910: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_have_glob_brace=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_have_glob_brace=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_have_glob_brace" 1>&6
+ if test "x$ftp_cv_have_glob_brace" = "xyes"; then
+ :
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for h_errno declaration""... $ac_c" 1>&6
+echo "configure:2934: checking for h_errno declaration" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_H_ERRNO_D'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2940 "configure"
+#include "confdefs.h"
+
+#include <netdb.h>
+int main() {
+ int X = h_errno ;
+; return 0; }
+EOF
+if { (eval echo configure:2948: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_H_ERRNO_D=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_H_ERRNO_D=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_H_ERRNO_D" 1>&6
+ if test "x$ftp_cv_HAVE_H_ERRNO_D" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_H_ERRNO_D 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for fclose() declaration""... $ac_c" 1>&6
+echo "configure:2975: checking for fclose() declaration" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_FCLOSE_D'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 2981 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+int main() {
+ int (*X)() = fclose ;
+; return 0; }
+EOF
+if { (eval echo configure:2989: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_FCLOSE_D=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_FCLOSE_D=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_FCLOSE_D" 1>&6
+ if test "x$ftp_cv_HAVE_FCLOSE_D" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_FCLOSE_D 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for getpass() declaration""... $ac_c" 1>&6
+echo "configure:3016: checking for getpass() declaration" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_GETPASS_D'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3022 "configure"
+#include "confdefs.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+int main() {
+ char *(*X)() = getpass ;
+; return 0; }
+EOF
+if { (eval echo configure:3031: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_GETPASS_D=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_GETPASS_D=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_GETPASS_D" 1>&6
+ if test "x$ftp_cv_HAVE_GETPASS_D" = "xyes"; then
+
+ cat >> confdefs.h <<\EOF
+#define HAVE_GETPASS_D 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for optarg declaration""... $ac_c" 1>&6
+echo "configure:3059: checking for optarg declaration" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_OPTARG_D'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3065 "configure"
+#include "confdefs.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+int main() {
+ char *X = optarg ;
+; return 0; }
+EOF
+if { (eval echo configure:3074: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_OPTARG_D=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_OPTARG_D=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_OPTARG_D" 1>&6
+ if test "x$ftp_cv_HAVE_OPTARG_D" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_OPTARG_D 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for optind declaration""... $ac_c" 1>&6
+echo "configure:3101: checking for optind declaration" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_OPTIND_D'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3107 "configure"
+#include "confdefs.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+int main() {
+ int X = optind ;
+; return 0; }
+EOF
+if { (eval echo configure:3116: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_OPTIND_D=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_OPTIND_D=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_OPTIND_D" 1>&6
+ if test "x$ftp_cv_HAVE_OPTIND_D" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_OPTIND_D 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+ echo $ac_n "checking for pclose() declaration""... $ac_c" 1>&6
+echo "configure:3143: checking for pclose() declaration" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_PCLOSE_D'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3149 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+int main() {
+ int (*X)() = pclose ;
+; return 0; }
+EOF
+if { (eval echo configure:3157: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_PCLOSE_D=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_PCLOSE_D=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_PCLOSE_D" 1>&6
+ if test "x$ftp_cv_HAVE_PCLOSE_D" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_PCLOSE_D 1
+EOF
+
+ else
+
+ :
+ fi
+
+
+
+for ac_func in err fgetln fparseln getaddrinfo getnameinfo glob inet_ntop \
+ inet_pton mkstemp sl_init snprintf strdup strerror strlcat \
+ strlcpy strptime strsep strunvis strvis timegm usleep
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3188: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3193 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3216: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}"
+fi
+done
+
+
+for ac_func in gethostbyname2 getpassphrase getpgrp issetugid memmove poll \
+ select
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3246: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3251 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3274: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+if test $ac_cv_func_getpgrp = yes; then
+ echo $ac_n "checking whether getpgrp takes no argument""... $ac_c" 1>&6
+echo "configure:3300: checking whether getpgrp takes no argument" >&5
+if eval "test \"`echo '$''{'ac_cv_func_getpgrp_void'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: cannot check getpgrp if cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3308 "configure"
+#include "confdefs.h"
+
+/*
+ * If this system has a BSD-style getpgrp(),
+ * which takes a pid argument, exit unsuccessfully.
+ *
+ * Snarfed from Chet Ramey's bash pgrp.c test program
+ */
+#include <stdio.h>
+#include <sys/types.h>
+
+int pid;
+int pg1, pg2, pg3, pg4;
+int ng, np, s, child;
+
+main()
+{
+ pid = getpid();
+ pg1 = getpgrp(0);
+ pg2 = getpgrp();
+ pg3 = getpgrp(pid);
+ pg4 = getpgrp(1);
+
+ /*
+ * If all of these values are the same, it's pretty sure that
+ * we're on a system that ignores getpgrp's first argument.
+ */
+ if (pg2 == pg4 && pg1 == pg3 && pg2 == pg3)
+ exit(0);
+
+ child = fork();
+ if (child < 0)
+ exit(1);
+ else if (child == 0) {
+ np = getpid();
+ /*
+ * If this is Sys V, this will not work; pgrp will be
+ * set to np because setpgrp just changes a pgrp to be
+ * the same as the pid.
+ */
+ setpgrp(np, pg1);
+ ng = getpgrp(0); /* Same result for Sys V and BSD */
+ if (ng == pg1) {
+ exit(1);
+ } else {
+ exit(0);
+ }
+ } else {
+ wait(&s);
+ exit(s>>8);
+ }
+}
+
+EOF
+if { (eval echo configure:3363: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_func_getpgrp_void=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_func_getpgrp_void=no
+fi
+rm -fr conftest*
+fi
+
+
+fi
+
+echo "$ac_t""$ac_cv_func_getpgrp_void" 1>&6
+if test $ac_cv_func_getpgrp_void = yes; then
+ cat >> confdefs.h <<\EOF
+#define GETPGRP_VOID 1
+EOF
+
+fi
+
+fi
+
+if test $ac_cv_func_strptime = yes; then
+
+ echo $ac_n "checking for strptime() declaration""... $ac_c" 1>&6
+echo "configure:3391: checking for strptime() declaration" >&5
+if eval "test \"`echo '$''{'ftp_cv_HAVE_STRPTIME_D'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3397 "configure"
+#include "confdefs.h"
+
+ #include <time.h>
+int main() {
+ char *X = strptime("", "", NULL) ;
+; return 0; }
+EOF
+if { (eval echo configure:3405: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_HAVE_STRPTIME_D=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_HAVE_STRPTIME_D=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_HAVE_STRPTIME_D" 1>&6
+ if test "x$ftp_cv_HAVE_STRPTIME_D" = "xyes"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_STRPTIME_D 1
+EOF
+
+ else
+
+ :
+ fi
+
+fi
+
+echo $ac_n "checking for GLOB_BRACE support in glob""... $ac_c" 1>&6
+echo "configure:3432: checking for GLOB_BRACE support in glob" >&5
+if test $ftp_cv_have_glob_brace = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_GLOB_BRACE 1
+EOF
+
+ echo "$ac_t""yes" 1>&6
+else
+ echo "$ac_t""no, using my own" 1>&6
+ LIBOBJS="$LIBOBJS glob.o"
+fi
+
+if test $have_long_long = yes -a $ac_cv_sizeof_off_t -ge 8; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_QUAD_SUPPORT 1
+EOF
+
+ for ac_func in strtoll
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3452: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3457 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3480: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}"
+fi
+done
+
+
+ echo $ac_n "checking snprintf support for %lld""... $ac_c" 1>&6
+echo "configure:3507: checking snprintf support for %lld" >&5
+ if test $ac_cv_func_snprintf = yes; then
+ if test "$cross_compiling" = yes; then
+
+ echo "$ac_t""cross-compiling" 1>&6
+ have_snprintf_lld=no
+
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3516 "configure"
+#include "confdefs.h"
+
+ #include <stdio.h>
+ int main() {
+ char buf[100];
+ snprintf(buf, sizeof(buf), "%lld",
+ 4294967300LL);
+ return (strcmp(buf, "4294967300"));
+ }
+
+EOF
+if { (eval echo configure:3528: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+
+ echo "$ac_t""yes" 1>&6
+ have_snprintf_lld=yes
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+
+ echo "$ac_t""no" 1>&6
+ have_snprintf_lld=no
+
+fi
+rm -fr conftest*
+fi
+
+ if test $have_snprintf_lld = no; then
+ LIBOBJS="$LIBOBJS snprintf.o"
+ fi
+ else
+ echo "$ac_t""using local version" 1>&6
+ fi
+fi
+
+
+if test $opt_editcomplete = yes; then
+ if test $have_libedit = yes; then
+
+ echo $ac_n "checking for EL_RPROMPT in libedit""... $ac_c" 1>&6
+echo "configure:3559: checking for EL_RPROMPT in libedit" >&5
+if eval "test \"`echo '$''{'ftp_cv_have_libedit'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3565 "configure"
+#include "confdefs.h"
+
+ #include <histedit.h>
+int main() {
+ int X = EL_RPROMPT ;
+; return 0; }
+EOF
+if { (eval echo configure:3573: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_have_libedit=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_have_libedit=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_have_libedit" 1>&6
+ if test "x$ftp_cv_have_libedit" = "xyes"; then
+ :
+ else
+ have_libedit=no
+ :
+ fi
+
+ fi
+
+ echo $ac_n "checking for working libedit""... $ac_c" 1>&6
+echo "configure:3597: checking for working libedit" >&5
+ if test $have_libedit = no; then
+ echo "$ac_t""no, using my own" 1>&6
+ INCLUDES="-I\${srcdir}/../libedit $INCLUDES"
+ LDFLAGS="-L../libedit $LDFLAGS"
+ LIBS="-ledit $LIBS"
+ LIBEDIT=libedit.a
+ LIBDEPENDS="$LIBDEPENDS ../libedit/libedit.a"
+ else
+ echo "$ac_t""yes" 1>&6
+ fi
+else
+ CFLAGS="-DNO_EDITCOMPLETE $CFLAGS"
+fi
+
+if test $ac_cv_func_sl_init = yes; then
+
+ echo $ac_n "checking if sl_add() returns int""... $ac_c" 1>&6
+echo "configure:3615: checking if sl_add() returns int" >&5
+if eval "test \"`echo '$''{'ftp_cv_INT_SL_ADD'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3621 "configure"
+#include "confdefs.h"
+
+ #include <stringlist.h>
+int main() {
+ int f = sl_add((StringList *)0, "foo") ;
+; return 0; }
+EOF
+if { (eval echo configure:3629: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_INT_SL_ADD=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_INT_SL_ADD=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_INT_SL_ADD" 1>&6
+ if test "x$ftp_cv_INT_SL_ADD" = "xyes"; then
+ :
+ else
+ LIBOBJS="$LIBOBJS sl_init.o"
+ :
+ fi
+
+fi
+
+
+have_rfc2553_netdb=no
+if test $ac_cv_func_getaddrinfo = yes; then
+
+ echo $ac_n "checking for AI_NUMERICHOST""... $ac_c" 1>&6
+echo "configure:3657: checking for AI_NUMERICHOST" >&5
+if eval "test \"`echo '$''{'ftp_cv_have_ai_numerichost'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3663 "configure"
+#include "confdefs.h"
+
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netdb.h>
+int main() {
+ int X = AI_NUMERICHOST ;
+; return 0; }
+EOF
+if { (eval echo configure:3673: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_have_ai_numerichost=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_have_ai_numerichost=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_have_ai_numerichost" 1>&6
+ if test "x$ftp_cv_have_ai_numerichost" = "xyes"; then
+ have_rfc2553_netdb=yes
+ else
+
+ :
+ fi
+
+fi
+if test $have_rfc2553_netdb = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_RFC2553_NETDB 1
+EOF
+
+else
+ if test $ac_cv_func_getaddrinfo = yes; then
+ LIBOBJS="$LIBOBJS getaddrinfo.o"
+ fi
+fi
+
+
+if test $ac_cv_header_vis_h = yes; then
+
+ echo $ac_n "checking for VIS_WHITE in vis.h""... $ac_c" 1>&6
+echo "configure:3710: checking for VIS_WHITE in vis.h" >&5
+if eval "test \"`echo '$''{'ftp_cv_have_vis_white'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ cat > conftest.$ac_ext <<EOF
+#line 3716 "configure"
+#include "confdefs.h"
+
+ #include <sys/types.h>
+ #include <vis.h>
+int main() {
+ int X = VIS_WHITE ;
+; return 0; }
+EOF
+if { (eval echo configure:3725: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ftp_cv_have_vis_white=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ftp_cv_have_vis_white=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ftp_cv_have_vis_white" 1>&6
+ if test "x$ftp_cv_have_vis_white" = "xyes"; then
+ :
+ else
+ ac_cv_header_vis_h=no
+ :
+ fi
+
+fi
+
+
+if test -n "$LIBOBJS"; then
+ INCLUDES="$INCLUDES -I\${srcdir}/../libukem"
+ LDFLAGS="$LDFLAGS -L../libukem"
+ LIBS="$LIBS -lukem"
+ LIBUKEM=libukem.a
+ LIBDEPENDS="$LIBDEPENDS ../libukem/libukem.a"
+fi
+
+
+
+
+
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile libedit/Makefile libedit/makelist libukem/Makefile \
+ src/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@CC@%$CC%g
+s%@AWK@%$AWK%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@RANLIB@%$RANLIB%g
+s%@AR@%$AR%g
+s%@CPP@%$CPP%g
+s%@LIBOBJS@%$LIBOBJS%g
+s%@INCLUDES@%$INCLUDES%g
+s%@LIBEDIT@%$LIBEDIT%g
+s%@LIBUKEM@%$LIBUKEM%g
+s%@LIBDEPENDS@%$LIBDEPENDS%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile libedit/Makefile libedit/makelist libukem/Makefile \
+ src/Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/contrib/lukemftp/configure.in b/contrib/lukemftp/configure.in
new file mode 100644
index 000000000000..edc823813095
--- /dev/null
+++ b/contrib/lukemftp/configure.in
@@ -0,0 +1,283 @@
+dnl $Id: configure.in,v 1.32 2000/09/18 00:10:43 lukem Exp $
+dnl
+dnl configure.in --
+dnl process this file with autoconf to produce a configure script.
+dnl
+
+AC_REVISION($Revision: 1.32 $)dnl
+
+AC_INIT(lukemftp.h)
+
+dnl Arguments for which features are included
+dnl
+AC_ARG_PROGRAM
+AC_ARG_ENABLE(editcomplete, [\
+ --enable-editcomplete Turn on command line editing and completion.
+ --disable-editcomplete Turn off command line editing and completion
+ [default: enabled].],
+ opt_editcomplete=$enableval,
+ opt_editcomplete=yes)
+AC_ARG_ENABLE(ipv6, [\
+ --enable-ipv6 Enable IPv6 support (if your OS supports it).
+ --disable-ipv6 Disable IPv6 support (even if your OS supports it)
+ [default: enabled].],
+ opt_ipv6=$enableval,
+ opt_ipv6=yes)
+
+dnl Checks for programs.
+dnl
+AC_PROG_MAKE_SET
+AC_PROG_CC
+AC_PROG_AWK
+AC_PROG_INSTALL
+AC_PROG_RANLIB
+AC_CHECK_PROGS(AR, ar)
+AC_AIX
+
+
+dnl Checks for libraries.
+dnl
+dnl XXX: we check fparseln twice; probably best to fix that
+AC_CHECK_LIB(util, fparseln)
+if test $opt_editcomplete = yes; then
+ AC_CHECK_LIB(tinfo, tgetent, ,
+ AC_CHECK_LIB(termcap, tgetent, ,
+ AC_CHECK_LIB(curses, tgetent, ,
+ AC_CHECK_LIB(ncurses, tgetent))))
+ AC_SEARCH_LIBS(el_init, edit, have_libedit=yes, have_libedit=no)
+fi
+AC_LIBRARY_NET
+AC_LIBRARY_SOCKS
+
+
+dnl Checks for header files.
+dnl
+AC_CONFIG_HEADER(config.h)
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_CHECK_HEADERS(err.h regex.h paths.h poll.h sys/poll.h termcap.h util.h vis.h)
+
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+dnl
+AC_HEADER_TIME
+AC_TYPE_OFF_T
+AC_CHECK_SIZEOF(off_t, 0)
+AC_MSG_TRY_LINK(for long long, ftp_cv_HAVE_LONG_LONG, [
+#include <sys/types.h>] , [
+long long X = 2, Y = 1, Z;
+Z = X / Y; ], [
+AC_DEFINE(HAVE_LONG_LONG, 1)
+have_long_long=yes], [have_long_long=no])
+
+AC_MSG_TRY_COMPILE(for in_port_t, ftp_cv_HAVE_IN_PORT_T, [
+#include <sys/types.h>
+#include <netinet/in.h> ], [ in_port_t X ], [AC_DEFINE(HAVE_IN_PORT_T, 1)])
+
+AC_MSG_TRY_COMPILE(for sockaddr_in.sin_len, ftp_cv_HAVE_SOCKADDR_SA_LEN, [
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h> ], [
+ struct sockaddr_in sin;
+ int X = sin.sin_len ], [AC_DEFINE(HAVE_SOCKADDR_SA_LEN, 1)])
+
+AC_MSG_TRY_COMPILE(for socklen_t, ftp_cv_HAVE_SOCKLEN_T, [
+#include <sys/types.h>
+#include <sys/socket.h> ], [ socklen_t X ], [AC_DEFINE(HAVE_SOCKLEN_T, 1)])
+
+if test $opt_ipv6 = yes; then
+
+ AC_MSG_TRY_COMPILE(for AF_INET6, ftp_cv_HAVE_AF_INET6, [
+#include <sys/types.h>
+#include <sys/socket.h> ],
+ [ int X = AF_INET6 ], [AC_DEFINE(HAVE_AF_INET6, 1)])
+
+ AC_MSG_TRY_COMPILE(for struct sockaddr_in6, ftp_cv_HAVE_SOCKADDR_IN6, [
+#include <sys/types.h>
+#include <netinet/in.h> ],
+ [ struct sockaddr_in6 X ], [AC_DEFINE(HAVE_SOCKADDR_IN6, 1)])
+
+fi
+
+AC_MSG_TRY_COMPILE(for struct addrinfo, ftp_cv_HAVE_ADDRINFO, [
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h> ],
+ [ struct addrinfo X ], [AC_DEFINE(HAVE_ADDRINFO, 1)])
+
+AC_MSG_TRY_COMPILE(for d_namlen in struct dirent, ftp_cv_HAVE_D_NAMLEN, [
+#if HAVE_DIRENT_H
+# include <dirent.h>
+#else
+# define dirent direct
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif ], [
+ struct dirent dp;
+ int X = dp.d_namlen; ], [AC_DEFINE(HAVE_D_NAMLEN, 1)])
+
+AC_MSG_TRY_COMPILE(for GLOB_BRACE, ftp_cv_have_glob_brace, [
+#include <glob.h> ], [ int X = GLOB_BRACE ], [:])
+
+AC_MSG_TRY_COMPILE(for h_errno declaration, ftp_cv_HAVE_H_ERRNO_D, [
+#include <netdb.h> ], [ int X = h_errno ], [AC_DEFINE(HAVE_H_ERRNO_D, 1)])
+
+AC_MSG_TRY_COMPILE(for fclose() declaration, ftp_cv_HAVE_FCLOSE_D, [
+#include <stdio.h> ], [ int (*X)() = fclose ], [AC_DEFINE(HAVE_FCLOSE_D, 1)])
+
+AC_MSG_TRY_COMPILE(for getpass() declaration, ftp_cv_HAVE_GETPASS_D, [
+#include <stdlib.h>
+#include <unistd.h> ], [ char *(*X)() = getpass ], [
+ AC_DEFINE(HAVE_GETPASS_D, 1)])
+
+AC_MSG_TRY_COMPILE(for optarg declaration, ftp_cv_HAVE_OPTARG_D, [
+#include <stdlib.h>
+#include <unistd.h> ], [ char *X = optarg ], [AC_DEFINE(HAVE_OPTARG_D, 1)])
+
+AC_MSG_TRY_COMPILE(for optind declaration, ftp_cv_HAVE_OPTIND_D, [
+#include <stdlib.h>
+#include <unistd.h> ], [ int X = optind ], [AC_DEFINE(HAVE_OPTIND_D, 1)])
+
+AC_MSG_TRY_COMPILE(for pclose() declaration, ftp_cv_HAVE_PCLOSE_D, [
+#include <stdio.h> ], [ int (*X)() = pclose ], [AC_DEFINE(HAVE_PCLOSE_D, 1)])
+
+
+dnl Checks for library functions.
+dnl
+AC_REPLACE_FUNCS(err fgetln fparseln getaddrinfo getnameinfo glob inet_ntop \
+ inet_pton mkstemp sl_init snprintf strdup strerror strlcat \
+ strlcpy strptime strsep strunvis strvis timegm usleep)
+AC_CHECK_FUNCS(gethostbyname2 getpassphrase getpgrp issetugid memmove poll \
+ select)
+if test $ac_cv_func_getpgrp = yes; then
+ AC_FUNC_GETPGRP
+fi
+
+if test $ac_cv_func_strptime = yes; then
+ AC_MSG_TRY_COMPILE(for strptime() declaration, ftp_cv_HAVE_STRPTIME_D, [
+ #include <time.h> ], [ char *X = strptime("", "", NULL) ],
+ [AC_DEFINE(HAVE_STRPTIME_D, 1)])
+fi
+
+AC_MSG_CHECKING(for GLOB_BRACE support in glob)
+if test $ftp_cv_have_glob_brace = yes; then
+ AC_DEFINE(HAVE_GLOB_BRACE, 1)
+ AC_MSG_RESULT(yes)
+else
+ AC_MSG_RESULT([no, using my own])
+ LIBOBJS="$LIBOBJS glob.o"
+fi
+
+if test $have_long_long = yes -a $ac_cv_sizeof_off_t -ge 8; then
+ AC_DEFINE(HAVE_QUAD_SUPPORT, 1)
+ AC_REPLACE_FUNCS(strtoll)
+ AC_MSG_CHECKING(snprintf support for %lld)
+ if test $ac_cv_func_snprintf = yes; then
+ AC_TRY_RUN([
+ #include <stdio.h>
+ int main() {
+ char buf[100];
+ snprintf(buf, sizeof(buf), "%lld",
+ 4294967300LL);
+ return (strcmp(buf, "4294967300"));
+ }
+ ], [
+ AC_MSG_RESULT(yes)
+ have_snprintf_lld=yes
+ ], [
+ AC_MSG_RESULT(no, using local version)
+ have_snprintf_lld=no
+ ], [
+ AC_MSG_RESULT(cross-compiling, using local version)
+ have_snprintf_lld=no
+ ])
+ if test $have_snprintf_lld = no; then
+ LIBOBJS="$LIBOBJS snprintf.o"
+ fi
+ else
+ AC_MSG_RESULT(using local version)
+ fi
+fi
+
+
+if test $opt_editcomplete = yes; then
+ if test $have_libedit = yes; then
+ AC_MSG_TRY_COMPILE(for EL_RPROMPT in libedit,
+ ftp_cv_have_libedit, [
+ #include <histedit.h> ], [ int X = EL_RPROMPT ], [:],
+ have_libedit=no )
+ fi
+
+ AC_MSG_CHECKING(for working libedit)
+ if test $have_libedit = no; then
+ AC_MSG_RESULT([no, using my own])
+ INCLUDES="-I\${srcdir}/../libedit $INCLUDES"
+ LDFLAGS="-L../libedit $LDFLAGS"
+ LIBS="-ledit $LIBS"
+ LIBEDIT=libedit.a
+ LIBDEPENDS="$LIBDEPENDS ../libedit/libedit.a"
+ else
+ AC_MSG_RESULT(yes)
+ fi
+else
+ CFLAGS="-DNO_EDITCOMPLETE $CFLAGS"
+fi
+
+if test $ac_cv_func_sl_init = yes; then
+ AC_MSG_TRY_COMPILE(if sl_add() returns int, ftp_cv_INT_SL_ADD, [
+ #include <stringlist.h> ], [ int f = sl_add((StringList *)0, "foo") ],
+ [:] , [LIBOBJS="$LIBOBJS sl_init.o"])
+fi
+
+
+have_rfc2553_netdb=no
+if test $ac_cv_func_getaddrinfo = yes; then
+ AC_MSG_TRY_COMPILE(for AI_NUMERICHOST, ftp_cv_have_ai_numerichost, [
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netdb.h> ],
+ [ int X = AI_NUMERICHOST ], [ have_rfc2553_netdb=yes ])
+fi
+if test $have_rfc2553_netdb = yes; then
+ AC_DEFINE(HAVE_RFC2553_NETDB, 1)
+else
+ if test $ac_cv_func_getaddrinfo = yes; then
+ LIBOBJS="$LIBOBJS getaddrinfo.o"
+ fi
+fi
+
+
+if test $ac_cv_header_vis_h = yes; then
+ AC_MSG_TRY_COMPILE(for VIS_WHITE in vis.h,
+ ftp_cv_have_vis_white, [
+ #include <sys/types.h>
+ #include <vis.h> ], [ int X = VIS_WHITE ], [:],
+ ac_cv_header_vis_h=no )
+fi
+
+
+if test -n "$LIBOBJS"; then
+ INCLUDES="$INCLUDES -I\${srcdir}/../libukem"
+ LDFLAGS="$LDFLAGS -L../libukem"
+ LIBS="$LIBS -lukem"
+ LIBUKEM=libukem.a
+ LIBDEPENDS="$LIBDEPENDS ../libukem/libukem.a"
+fi
+
+dnl Create the Makefiles
+dnl
+
+AC_SUBST(INCLUDES)
+AC_SUBST(LIBEDIT)
+AC_SUBST(LIBUKEM)
+AC_SUBST(LIBDEPENDS)
+
+AC_OUTPUT(Makefile libedit/Makefile libedit/makelist libukem/Makefile \
+ src/Makefile)
diff --git a/contrib/lukemftp/install-sh b/contrib/lukemftp/install-sh
new file mode 100755
index 000000000000..e9de23842dcd
--- /dev/null
+++ b/contrib/lukemftp/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/contrib/lukemftp/lukemftp.h b/contrib/lukemftp/lukemftp.h
new file mode 100644
index 000000000000..065ccba3a053
--- /dev/null
+++ b/contrib/lukemftp/lukemftp.h
@@ -0,0 +1,379 @@
+/* $Id: lukemftp.h,v 1.36 2000/10/11 03:07:36 lukem Exp $ */
+
+#define FTP_PRODUCT "lukemftp"
+#define FTP_VERSION "1.5"
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <arpa/ftp.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#if HAVE_POLL
+# if HAVE_POLL_H
+# include <poll.h>
+# elif HAVE_SYS_POLL_H
+# include <sys/poll.h>
+# endif
+#elif HAVE_SELECT
+# define USE_SELECT
+#else
+# error "no poll() or select() found"
+#endif
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+#else
+# define dirent direct
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#if HAVE_ERR_H
+# include <err.h>
+#endif
+
+#if HAVE_GLOB_BRACE
+# include <glob.h>
+#else
+# include "ftpglob.h"
+#endif
+
+#if HAVE_PATHS_H
+# include <paths.h>
+#else
+# define _PATH_BSHELL "/bin/sh"
+# 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 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
+
+#if HAVE_UTIL_H
+# include <util.h>
+#endif
+
+#if HAVE_VIS_H
+# include <vis.h>
+#else
+# include "ftpvis.h"
+#endif
+
+#if ! HAVE_IN_PORT_T
+typedef unsigned short in_port_t;
+#endif
+
+#if ! HAVE_SOCKLEN_T
+typedef unsigned int socklen_t;
+#endif
+
+#if HAVE_AF_INET6 && HAVE_SOCKADDR_IN6
+# define INET6
+#endif
+
+
+#if ! HAVE_RFC2553_NETDB
+
+ /* 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_RFC2553_NETDB */
+
+
+#if ! HAVE_RFC2553_NETDB && ! HAVE_ADDRINFO
+
+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 */
+ size_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 *);
+char *gai_strerror(int);
+
+#endif /* ! HAVE_RFC2553_NETDB && ! HAVE_ADDRINFO */
+
+
+#if ! HAVE_D_NAMLEN
+# define DIRENT_MISSING_D_NAMLEN
+#endif
+
+#if ! HAVE_H_ERRNO_D
+extern int h_errno;
+#endif
+#define HAVE_H_ERRNO 1 /* XXX: an assumption for now... */
+
+#if ! HAVE_FCLOSE_D
+int fclose(FILE *);
+#endif
+
+#if ! HAVE_GETPASS_D
+char *getpass(const char *);
+#endif
+
+#if ! HAVE_OPTARG_D
+extern char *optarg;
+#endif
+
+#if ! HAVE_OPTIND_D
+extern int optind;
+#endif
+
+#if ! HAVE_PCLOSE_D
+int pclose(FILE *);
+#endif
+
+#if ! HAVE_ERR
+void err(int, const char *, ...);
+void errx(int, const char *, ...);
+void warn(const char *, ...);
+void warnx(const char *, ...);
+#endif
+
+#if ! HAVE_FGETLN
+char *fgetln(FILE *, size_t *);
+#endif
+
+#if ! HAVE_FPARSELN
+# define FPARSELN_UNESCESC 0x01
+# define FPARSELN_UNESCCONT 0x02
+# define FPARSELN_UNESCCOMM 0x04
+# define FPARSELN_UNESCREST 0x08
+# define FPARSELN_UNESCALL 0x0f
+char *fparseln(FILE *, size_t *, size_t *, const char[3], int);
+#endif
+
+#if ! HAVE_INET_NTOP
+const char *inet_ntop(int, const void *, char *, size_t);
+#endif
+
+#if ! HAVE_MKSTEMP
+int mkstemp(char *);
+#endif
+
+#if ! HAVE_SNPRINTF
+int snprintf(char *, size_t, const char *, ...);
+#endif
+
+#if ! HAVE_STRDUP
+char *strdup(const char *);
+#endif
+
+#if ! HAVE_STRERROR
+char *strerror(int);
+#endif
+
+#if ! HAVE_STRPTIME || ! HAVE_STRPTIME_D
+char *strptime(const char *, const char *, struct tm *);
+#endif
+
+#if HAVE_QUAD_SUPPORT
+# if ! HAVE_STRTOLL && HAVE_LONG_LONG
+long long strtoll(const char *, char **, int);
+# if ! defined(QUAD_MIN)
+# define QUAD_MIN (-0x7fffffffffffffffL-1)
+# endif
+# if ! defined(QUAD_MAX)
+# define QUAD_MAX (0x7fffffffffffffffL)
+# endif
+# endif
+#else /* ! HAVE_QUAD_SUPPORT */
+# define NO_LONG_LONG 1
+#endif /* ! HAVE_QUAD_SUPPORT */
+
+#if ! HAVE_TIMEGM
+time_t timegm(struct tm *);
+#endif
+
+#if ! HAVE_HSTRERROR
+char *strerror(int);
+#endif
+
+#if ! HAVE_STRLCAT
+size_t strlcat(char *, const char *, size_t);
+#endif
+
+#if ! HAVE_STRLCPY
+size_t strlcpy(char *, const char *, size_t);
+#endif
+
+#if ! HAVE_STRSEP
+char *strsep(char **stringp, const char *delim);
+#endif
+
+#if ! HAVE_MEMMOVE
+# define memmove(a,b,c) bcopy((b),(a),(c))
+ /* XXX: add others #defines for borken systems? */
+#endif
+
+#if 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
diff --git a/contrib/lukemftp/src/Makefile.in b/contrib/lukemftp/src/Makefile.in
new file mode 100644
index 000000000000..bb60f1086764
--- /dev/null
+++ b/contrib/lukemftp/src/Makefile.in
@@ -0,0 +1,43 @@
+#
+# $Id: Makefile.in,v 1.8 2000/08/08 07:04:27 lukem Exp $
+#
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+SHELL = /bin/sh
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+mandir = @mandir@
+transform = @program_transform_name@
+
+mandircat1 = ${mandir}/cat1
+
+CC = @CC@
+CFLAGS = -I${srcdir} -I${srcdir}/.. -I. -I.. @INCLUDES@ @CFLAGS@
+LIBS = @LIBS@
+LDFLAGS = @LDFLAGS@
+
+INSTALL = @INSTALL@
+
+PROG = ftp
+OBJS = cmds.o cmdtab.o complete.o domacro.o fetch.o ftp.o main.o \
+ ruserpass.o util.o
+
+all: ${PROG}
+
+install: all
+ -mkdir -p ${bindir}
+ ${INSTALL} -m 555 ${PROG} ${bindir}/`echo ${PROG}|sed '$(transform)'`
+ -mkdir -p ${mandircat1}
+ ${INSTALL} -m 444 ${srcdir}/${PROG}.cat1 ${mandircat1}/`echo ${PROG}|sed '$(transform)'`.1
+
+${PROG}: ${OBJS} @LIBDEPENDS@
+ ${CC} ${CFLAGS} ${LDFLAGS} -o ${PROG} ${OBJS} ${LIBS}
+
+clean:
+ rm -f core ${PROG} ${OBJS}
+
+distclean: clean
+ rm -f Makefile
diff --git a/contrib/lukemftp/src/cmds.c b/contrib/lukemftp/src/cmds.c
new file mode 100644
index 000000000000..d72a1f8893f6
--- /dev/null
+++ b/contrib/lukemftp/src/cmds.c
@@ -0,0 +1,2673 @@
+/* $NetBSD: cmds.c,v 1.90 2000/08/01 22:47:25 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1996-2000 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.
+ * 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.
+ */
+
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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.
+ */
+
+/*
+ * FTP User Program -- Command Routines.
+ */
+
+#include "lukemftp.h"
+
+#include "ftp_var.h"
+#include "version.h"
+
+struct types {
+ char *t_name;
+ char *t_mode;
+ int t_type;
+ 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 }
+};
+
+sigjmp_buf jabort;
+char *mname;
+
+static int confirm(const char *, const char *);
+
+static int
+confirm(const char *cmd, const char *file)
+{
+ char line[BUFSIZ];
+
+ if (!interactive || confirmrest)
+ return (1);
+ while (1) {
+ fprintf(ttyout, "%s %s [anpqy?]? ", cmd, file);
+ (void)fflush(ttyout);
+ if (fgets(line, sizeof(line), stdin) == NULL) {
+ mflag = 0;
+ fprintf(ttyout, "\nEOF received; %s aborted\n", mname);
+ clearerr(stdin);
+ return (0);
+ }
+ switch (tolower(*line)) {
+ 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", mname);
+ /* 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;
+ int comret;
+
+ if (argc == 0 || argc > 2) {
+ char *sep;
+
+ fprintf(ttyout, "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;
+ }
+ for (p = types; p->t_name; p++)
+ if (strcmp(argv[1], p->t_name) == 0)
+ break;
+ if (p->t_name == 0) {
+ fprintf(ttyout, "%s: unknown mode.\n", argv[1]);
+ 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 (debug == 0 && show == 0)
+ verbose = 0;
+ for (p = types; p->t_name; p++)
+ if (newtype == p->t_type)
+ break;
+ if (p->t_name == 0) {
+ warnx("internal error: unknown type %d.", newtype);
+ return;
+ }
+ 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;
+}
+
+char *stype[] = {
+ "type",
+ "",
+ 0
+};
+
+/*
+ * Set binary transfer type.
+ */
+/*VARARGS*/
+void
+setbinary(int argc, char *argv[])
+{
+
+ if (argc == 0) {
+ fprintf(ttyout, "usage: %s\n", argv[0]);
+ code = -1;
+ return;
+ }
+ stype[1] = "binary";
+ settype(2, stype);
+}
+
+/*
+ * Set ascii transfer type.
+ */
+/*VARARGS*/
+void
+setascii(int argc, char *argv[])
+{
+
+ if (argc == 0) {
+ fprintf(ttyout, "usage: %s\n", argv[0]);
+ code = -1;
+ return;
+ }
+ stype[1] = "ascii";
+ settype(2, stype);
+}
+
+/*
+ * Set tenex transfer type.
+ */
+/*VARARGS*/
+void
+settenex(int argc, char *argv[])
+{
+
+ if (argc == 0) {
+ fprintf(ttyout, "usage: %s\n", argv[0]);
+ code = -1;
+ return;
+ }
+ stype[1] = "tenex";
+ settype(2, stype);
+}
+
+/*
+ * Set file transfer mode.
+ */
+/*ARGSUSED*/
+void
+setftmode(int argc, char *argv[])
+{
+
+ if (argc != 2) {
+ fprintf(ttyout, "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) {
+ fprintf(ttyout, "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) {
+ fprintf(ttyout, "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 *cmd;
+ int loc = 0;
+ char *locfile, *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:
+ fprintf(ttyout, "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");
+ if (loc && ntflag)
+ remfile = dotrans(remfile);
+ if (loc && mapflag)
+ remfile = domap(remfile);
+ sendrequest(cmd, locfile, remfile,
+ locfile != argv[1] || remfile != argv[2]);
+ free(locfile);
+}
+
+/*
+ * Send multiple files.
+ */
+void
+mput(int argc, char *argv[])
+{
+ int i;
+ sigfunc oldintr;
+ int ointer;
+ char *tp;
+
+ if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-files"))) {
+ fprintf(ttyout, "usage: %s local-files\n", argv[0]);
+ code = -1;
+ return;
+ }
+ mname = argv[0];
+ mflag = 1;
+ oldintr = xsignal(SIGINT, mintr);
+ if (sigsetjmp(jabort, 1))
+ mabort();
+ if (proxy) {
+ char *cp;
+
+ while ((cp = remglob(argv, 0, NULL)) != NULL) {
+ if (*cp == '\0' || !connected) {
+ mflag = 0;
+ continue;
+ }
+ if (mflag && confirm(argv[0], cp)) {
+ tp = cp;
+ if (mcase)
+ tp = docase(tp);
+ if (ntflag)
+ tp = dotrans(tp);
+ if (mapflag)
+ tp = domap(tp);
+ sendrequest((sunique) ? "STOU" : "STOR",
+ cp, tp, cp != tp || !interactive);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with", "mput")) {
+ 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])) {
+ tp = (ntflag) ? dotrans(argv[i]) : argv[i];
+ tp = (mapflag) ? domap(tp) : tp;
+ sendrequest((sunique) ? "STOU" : "STOR",
+ argv[i], tp, tp != argv[i] || !interactive);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with", "mput")) {
+ 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("%s: not found", argv[i]);
+ globfree(&gl);
+ continue;
+ }
+ for (cpp = gl.gl_pathv; cpp && *cpp != NULL && connected;
+ cpp++) {
+ if (mflag && confirm(argv[0], *cpp)) {
+ tp = (ntflag) ? dotrans(*cpp) : *cpp;
+ tp = (mapflag) ? domap(tp) : tp;
+ sendrequest((sunique) ? "STOU" : "STOR",
+ *cpp, tp, *cpp != tp || !interactive);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with", "mput")) {
+ mflag++;
+ }
+ interactive = ointer;
+ }
+ }
+ }
+ globfree(&gl);
+ }
+ cleanupmput:
+ (void)xsignal(SIGINT, oldintr);
+ mflag = 0;
+}
+
+void
+reget(int argc, char *argv[])
+{
+
+ (void)getit(argc, argv, 1, "r+w");
+}
+
+void
+get(int argc, char *argv[])
+{
+
+ (void)getit(argc, argv, 0, restart_point ? "r+w" : "w" );
+}
+
+/*
+ * Receive one file.
+ */
+int
+getit(int argc, char *argv[], int restartit, const char *mode)
+{
+ int loc = 0;
+ int rval = 0;
+ char *remfile, *locfile, *olocfile;
+
+ 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:
+ fprintf(ttyout, "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 = olocfile;
+ if (loc && mcase)
+ locfile = docase(locfile);
+ if (loc && ntflag)
+ locfile = dotrans(locfile);
+ if (loc && mapflag)
+ locfile = domap(locfile);
+ 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("local: %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, mode,
+ remfile != argv[1] || locfile != argv[2], loc);
+ restart_point = 0;
+ freegetit:
+ (void)free(olocfile);
+ return (rval);
+}
+
+/* ARGSUSED */
+void
+mintr(int signo)
+{
+
+ alarmtimer(0);
+ if (fromatty)
+ write(fileno(ttyout), "\n", 1);
+ siglongjmp(jabort, 1);
+}
+
+void
+mabort(void)
+{
+ int ointer, oconf;
+
+ if (mflag && fromatty) {
+ ointer = interactive;
+ oconf = confirmrest;
+ interactive = 1;
+ confirmrest = 0;
+ if (confirm("Continue with", mname)) {
+ interactive = ointer;
+ confirmrest = oconf;
+ return;
+ }
+ interactive = ointer;
+ confirmrest = oconf;
+ }
+ mflag = 0;
+}
+
+/*
+ * Get multiple files.
+ */
+void
+mget(int argc, char *argv[])
+{
+ sigfunc oldintr;
+ int ch, ointer;
+ char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
+
+ if (argc == 0 ||
+ (argc == 1 && !another(&argc, &argv, "remote-files"))) {
+ fprintf(ttyout, "usage: %s remote-files\n", argv[0]);
+ code = -1;
+ return;
+ }
+ mname = argv[0];
+ mflag = 1;
+ oldintr = xsignal(SIGINT, mintr);
+ if (sigsetjmp(jabort, 1))
+ mabort();
+ while ((cp = remglob(argv, proxy, NULL)) != NULL) {
+ if (*cp == '\0' || !connected) {
+ mflag = 0;
+ continue;
+ }
+ if (mflag && confirm(argv[0], cp)) {
+ tp = cp;
+ if (mcase) {
+ for (tp2 = tmpbuf; (ch = *tp++) != 0; )
+ *tp2++ = isupper(ch) ? tolower(ch) : ch;
+ *tp2 = '\0';
+ tp = tmpbuf;
+ }
+ if (ntflag) {
+ tp = dotrans(tp);
+ }
+ if (mapflag) {
+ tp = domap(tp);
+ }
+ recvrequest("RETR", tp, cp, "w",
+ tp != cp || !interactive, 1);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with", "mget")) {
+ 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[])
+{
+ char *buf, *mode;
+ FILE *fp;
+
+ if (argc != 2) {
+ fprintf(ttyout, "usage: %s localfile\n", argv[0]);
+ code = -1;
+ return;
+ }
+
+ fp = fopen(argv[1], "r");
+ if (fp == NULL) {
+ fprintf(ttyout, "Cannot open source file %s\n", argv[1]);
+ code = -1;
+ return;
+ }
+
+ argv[0] = "get";
+ mode = restart_point ? "r+w" : "w";
+
+ for (;
+ (buf = fparseln(fp, NULL, NULL, "\0\0\0", 0)) != NULL;
+ free(buf)) {
+ if (buf[0] == '\0')
+ continue;
+ argv[1] = buf;
+ (void)getit(argc, argv, 0, mode);
+ }
+ fclose(fp);
+}
+
+char *
+onoff(int bool)
+{
+
+ return (bool ? "on" : "off");
+}
+
+/*
+ * Show status.
+ */
+/*ARGSUSED*/
+void
+status(int argc, char *argv[])
+{
+ int i;
+
+ if (argc == 0) {
+ fprintf(ttyout, "usage: %s\n", argv[0]);
+ code = -1;
+ return;
+ }
+ 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, "Command line editing: %s.\n",
+#ifdef NO_EDITCOMPLETE
+ "support not compiled in"
+#else /* !def NO_EDITCOMPLETE */
+ onoff(editing)
+#endif /* !def NO_EDITCOMPLETE */
+ );
+ fprintf(ttyout, "Version: %s %s\n", FTP_PRODUCT, FTP_VERSION);
+ if (macnum > 0) {
+ fputs("Macros:\n", ttyout);
+ for (i=0; i<macnum; i++) {
+ fprintf(ttyout, "\t%s\n", macros[i].mac_name);
+ }
+ }
+ 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 {
+ fprintf(ttyout, "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) {
+ fprintf(ttyout, "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) {
+ fprintf(ttyout, "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) {
+ fprintf(ttyout,
+ "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 = 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) {
+ fprintf(ttyout, "usage: %s [ on | off | debuglevel ]\n",
+ argv[0]);
+ code = -1;
+ return;
+ } else if (argc == 2) {
+ if (strcasecmp(argv[1], "on") == 0)
+ debug = 1;
+ else if (strcasecmp(argv[1], "off") == 0)
+ debug = 0;
+ else {
+ int val;
+
+ val = strsuftoi(argv[1]);
+ if (val < 0) {
+ fprintf(ttyout, "%s: bad debugging value.\n",
+ argv[1]);
+ code = -1;
+ return;
+ }
+ debug = val;
+ }
+ } else
+ debug = !debug;
+ if (debug)
+ options |= SO_DEBUG;
+ else
+ options &= ~SO_DEBUG;
+ fprintf(ttyout, "Debugging %s (debug=%d).\n", onoff(debug), debug);
+ code = 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"))) {
+ fprintf(ttyout, "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;
+ updateremotepwd();
+ }
+}
+
+/*
+ * Set current working directory on local machine.
+ */
+void
+lcd(int argc, char *argv[])
+{
+ char buf[MAXPATHLEN];
+ char *locdir;
+
+ code = -1;
+ if (argc == 1) {
+ argc++;
+ argv[1] = home;
+ }
+ if (argc != 2) {
+ fprintf(ttyout, "usage: %s [local-directory]\n", argv[0]);
+ return;
+ }
+ if ((locdir = globulize(argv[1])) == NULL)
+ return;
+ if (chdir(locdir) < 0)
+ warn("local: %s", locdir);
+ else {
+ if (getcwd(buf, sizeof(buf)) != NULL) {
+ fprintf(ttyout, "Local directory now %s\n", buf);
+ code = 0;
+ } else
+ warn("getcwd: %s", locdir);
+ }
+ (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"))) {
+ fprintf(ttyout, "usage: %s remote-file\n", argv[0]);
+ code = -1;
+ return;
+ }
+ (void)command("DELE %s", argv[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"))) {
+ fprintf(ttyout, "usage: %s [remote-files]\n", argv[0]);
+ code = -1;
+ return;
+ }
+ mname = argv[0];
+ mflag = 1;
+ oldintr = xsignal(SIGINT, mintr);
+ if (sigsetjmp(jabort, 1))
+ mabort();
+ while ((cp = remglob(argv, 0, NULL)) != NULL) {
+ if (*cp == '\0') {
+ mflag = 0;
+ continue;
+ }
+ if (mflag && confirm(argv[0], cp)) {
+ (void)command("DELE %s", cp);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with", "mdelete")) {
+ 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:
+ fprintf(ttyout, "usage: %s from-name to-name\n", argv[0]);
+ code = -1;
+ return;
+ }
+ if (command("RNFR %s", argv[1]) == CONTINUE)
+ (void)command("RNTO %s", argv[2]);
+}
+
+/*
+ * Get a directory listing of remote files.
+ * Supports being invoked as:
+ * cmd runs
+ * --- ----
+ * dir, ls LIST
+ * mlsd MLSD
+ * nlist NLST
+ * pdir, pls LIST |$PAGER
+ * mmlsd MLSD |$PAGER
+ */
+void
+ls(int argc, char *argv[])
+{
+ const char *cmd;
+ char *remdir, *locfile;
+ int freelocfile, pagecmd, mlsdcmd;
+
+ remdir = NULL;
+ locfile = "-";
+ freelocfile = 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)
+ fprintf(ttyout,
+ "usage: %s [remote-path]\n", argv[0]);
+ else
+ fprintf(ttyout,
+ "usage: %s [remote-path [local-file]]\n",
+ argv[0]);
+ code = -1;
+ goto freels;
+ }
+
+ if (pagecmd) {
+ char *p;
+ int len;
+
+ p = getoptionvalue("pager");
+ if (EMPTYSTRING(p))
+ p = DEFAULTPAGER;
+ len = strlen(p) + 2;
+ locfile = xmalloc(len);
+ locfile[0] = '|';
+ (void)strlcpy(locfile + 1, p, len - 1);
+ freelocfile = 1;
+ } else if ((strcmp(locfile, "-") != 0) && *locfile != '|') {
+ if ((locfile = globulize(locfile)) == NULL ||
+ !confirm("output to local-file:", locfile)) {
+ code = -1;
+ goto freels;
+ }
+ freelocfile = 1;
+ }
+ recvrequest(cmd, locfile, remdir, "w", 0, 0);
+ freels:
+ if (freelocfile && locfile)
+ (void)free(locfile);
+}
+
+/*
+ * Get a directory listing of multiple remote files.
+ */
+void
+mls(int argc, char *argv[])
+{
+ sigfunc oldintr;
+ int ointer, i;
+ int dolist;
+ char mode[1], *dest, *odest;
+
+ if (argc == 0)
+ goto usage;
+ if (argc < 2 && !another(&argc, &argv, "remote-files"))
+ goto usage;
+ if (argc < 3 && !another(&argc, &argv, "local-file")) {
+ usage:
+ fprintf(ttyout, "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");
+ mname = argv[0];
+ mflag = 1;
+ oldintr = xsignal(SIGINT, mintr);
+ if (sigsetjmp(jabort, 1))
+ mabort();
+ for (i = 1; mflag && i < argc-1 && connected; i++) {
+ *mode = (i == 1) ? 'w' : 'a';
+ recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], mode,
+ 0, 0);
+ if (!mflag && fromatty) {
+ ointer = interactive;
+ interactive = 1;
+ if (confirm("Continue with", argv[0])) {
+ 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 old1;
+ char shellnam[MAXPATHLEN], *shell, *namep;
+ int wait_status;
+
+ if (argc == 0) {
+ fprintf(ttyout, "usage: %s [command [args]]\n", argv[0]);
+ code = -1;
+ return;
+ }
+ old1 = xsignal(SIGINT, SIG_IGN);
+ if ((pid = fork()) == 0) {
+ for (pid = 3; pid < 20; pid++)
+ (void)close(pid);
+ (void)xsignal(SIGINT, SIG_DFL);
+ shell = getenv("SHELL");
+ if (shell == NULL)
+ shell = _PATH_BSHELL;
+ namep = strrchr(shell, '/');
+ if (namep == NULL)
+ namep = shell;
+ else
+ namep++;
+ (void)strlcpy(shellnam, namep, sizeof(shellnam));
+ if (debug) {
+ fputs(shell, ttyout);
+ putc('\n', ttyout);
+ }
+ if (argc > 1) {
+ execl(shell, shellnam, "-c", altarg, (char *)0);
+ }
+ else {
+ execl(shell, shellnam, (char *)0);
+ }
+ warn("%s", shell);
+ code = -1;
+ exit(1);
+ }
+ if (pid > 0)
+ while (wait(&wait_status) != pid)
+ ;
+ (void)xsignal(SIGINT, old1);
+ if (pid == -1) {
+ warn("Try again later");
+ code = -1;
+ } else
+ code = 0;
+}
+
+/*
+ * Send new user information (re-login)
+ */
+void
+user(int argc, char *argv[])
+{
+ char acct[80];
+ int n, aflag = 0;
+
+ if (argc == 0)
+ goto usage;
+ if (argc < 2)
+ (void)another(&argc, &argv, "username");
+ if (argc < 2 || argc > 4) {
+ usage:
+ fprintf(ttyout, "usage: %s username [password [account]]\n",
+ argv[0]);
+ code = -1;
+ return;
+ }
+ n = command("USER %s", argv[1]);
+ if (n == CONTINUE) {
+ if (argc < 3) {
+ argv[2] = getpass("Password: ");
+ argc++;
+ }
+ n = command("PASS %s", argv[2]);
+ }
+ if (n == CONTINUE) {
+ if (argc < 4) {
+ (void)fputs("Account: ", ttyout);
+ (void)fflush(ttyout);
+ if (fgets(acct, sizeof(acct) - 1, stdin) == NULL) {
+ fprintf(ttyout,
+ "\nEOF received; login aborted.\n");
+ clearerr(stdin);
+ code = -1;
+ return;
+ }
+ acct[strlen(acct) - 1] = '\0';
+ argv[3] = acct; argc++;
+ }
+ n = command("ACCT %s", argv[3]);
+ aflag++;
+ }
+ if (n != COMPLETE) {
+ fputs("Login failed.\n", ttyout);
+ return;
+ }
+ if (!aflag && argc == 4) {
+ (void)command("ACCT %s", argv[3]);
+ }
+ connected = -1;
+ getremoteinfo();
+}
+
+/*
+ * Print working directory on remote machine.
+ */
+/*VARARGS*/
+void
+pwd(int argc, char *argv[])
+{
+ int oldverbose = verbose;
+
+ if (argc == 0) {
+ fprintf(ttyout, "usage: %s\n", argv[0]);
+ code = -1;
+ return;
+ }
+ verbose = 1; /* If we aren't verbose, this doesn't do anything! */
+ if (command("PWD") == ERROR && code == 500) {
+ fputs("PWD command not recognized, trying XPWD.\n", ttyout);
+ (void)command("XPWD");
+ }
+ verbose = oldverbose;
+}
+
+/*
+ * Print working directory on local machine.
+ */
+void
+lpwd(int argc, char *argv[])
+{
+ char buf[MAXPATHLEN];
+
+ if (argc == 0) {
+ fprintf(ttyout, "usage: %s\n", argv[0]);
+ code = -1;
+ return;
+ }
+ if (getcwd(buf, sizeof(buf)) != NULL) {
+ fprintf(ttyout, "Local directory %s\n", buf);
+ code = 0;
+ } else {
+ warn("getcwd");
+ code = -1;
+ }
+}
+
+/*
+ * Make a directory.
+ */
+void
+makedir(int argc, char *argv[])
+{
+
+ if (argc == 0 || argc > 2 ||
+ (argc == 1 && !another(&argc, &argv, "directory-name"))) {
+ fprintf(ttyout, "usage: %s directory-name\n", argv[0]);
+ code = -1;
+ return;
+ }
+ if (command("MKD %s", argv[1]) == ERROR && code == 500) {
+ if (verbose)
+ fputs("MKD command not recognized, trying XMKD.\n",
+ ttyout);
+ (void)command("XMKD %s", argv[1]);
+ }
+}
+
+/*
+ * Remove a directory.
+ */
+void
+removedir(int argc, char *argv[])
+{
+
+ if (argc == 0 || argc > 2 ||
+ (argc == 1 && !another(&argc, &argv, "directory-name"))) {
+ fprintf(ttyout, "usage: %s directory-name\n", argv[0]);
+ code = -1;
+ return;
+ }
+ if (command("RMD %s", argv[1]) == ERROR && code == 500) {
+ if (verbose)
+ fputs("RMD command not recognized, trying XRMD.\n",
+ ttyout);
+ (void)command("XRMD %s", argv[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"))) {
+ fprintf(ttyout, "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"))){
+ fprintf(ttyout, "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;
+ }
+}
+
+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:
+ fprintf(ttyout, "usage: %s mode remote-file\n", argv[0]);
+ code = -1;
+ return;
+ }
+ (void)command("SITE CHMOD %s %s", argv[1], argv[2]);
+}
+
+void
+do_umask(int argc, char *argv[])
+{
+ int oldverbose = verbose;
+
+ if (argc == 0) {
+ fprintf(ttyout, "usage: %s [umask]\n", argv[0]);
+ code = -1;
+ return;
+ }
+ verbose = 1;
+ (void)command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
+ verbose = oldverbose;
+}
+
+void
+idlecmd(int argc, char *argv[])
+{
+ int oldverbose = verbose;
+
+ if (argc < 1 || argc > 2) {
+ fprintf(ttyout, "usage: %s [seconds]\n", argv[0]);
+ code = -1;
+ return;
+ }
+ verbose = 1;
+ (void)command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
+ verbose = oldverbose;
+}
+
+/*
+ * Ask the other side for help.
+ */
+void
+rmthelp(int argc, char *argv[])
+{
+ int oldverbose = verbose;
+
+ if (argc == 0) {
+ fprintf(ttyout, "usage: %s\n", argv[0]);
+ code = -1;
+ return;
+ }
+ verbose = 1;
+ (void)command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
+ 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) {
+ fprintf(ttyout, "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) {
+ fprintf(ttyout, "usage: %s\n", argv[0]);
+ code = -1;
+ return;
+ }
+ if (!connected)
+ return;
+ (void)command("QUIT");
+ cleanuppeer();
+}
+
+void
+account(int argc, char *argv[])
+{
+ char *ap;
+
+ if (argc == 0 || argc > 2) {
+ fprintf(ttyout, "usage: %s [password]\n", argv[0]);
+ code = -1;
+ return;
+ }
+ else if (argc == 2)
+ ap = argv[1];
+ else
+ ap = getpass("Account:");
+ (void)command("ACCT %s", ap);
+}
+
+sigjmp_buf abortprox;
+
+void
+proxabort(int notused)
+{
+
+ 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;
+
+ if (argc == 0 || (argc == 1 && !another(&argc, &argv, "command"))) {
+ fprintf(ttyout, "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);
+ (*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
+ */
+char *
+docase(char *name)
+{
+ static char new[MAXPATHLEN];
+ int i, dochange;
+
+ dochange = 1;
+ for (i = 0; name[i] != '\0' && i < sizeof(new) - 1; i++) {
+ new[i] = name[i];
+ if (islower((unsigned char)new[i]))
+ dochange = 0;
+ }
+ new[i] = '\0';
+
+ if (dochange) {
+ for (i = 0; new[i] != '\0'; i++)
+ if (isupper((unsigned char)new[i]))
+ new[i] = tolower(new[i]);
+ }
+ return (new);
+}
+
+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) {
+ fprintf(ttyout, "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));
+}
+
+char *
+dotrans(char *name)
+{
+ static char new[MAXPATHLEN];
+ char *cp1, *cp2 = new;
+ int i, ostop, found;
+
+ for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
+ continue;
+ for (cp1 = name; *cp1; cp1++) {
+ found = 0;
+ for (i = 0; *(ntin + i) && i < 16; i++) {
+ if (*cp1 == *(ntin + i)) {
+ found++;
+ if (i < ostop) {
+ *cp2++ = *(ntout + i);
+ }
+ break;
+ }
+ }
+ if (!found) {
+ *cp2++ = *cp1;
+ }
+ }
+ *cp2 = '\0';
+ return (new);
+}
+
+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) {
+ fprintf(ttyout, "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);
+}
+
+char *
+domap(char *name)
+{
+ static char new[MAXPATHLEN];
+ char *cp1 = name, *cp2 = mapin;
+ 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;
+ }
+ cp1 = new;
+ *cp1 = '\0';
+ cp2 = mapout;
+ while (*cp2) {
+ match = 0;
+ switch (*cp2) {
+ case '\\':
+ if (*(cp2 + 1)) {
+ *cp1++ = *++cp2;
+ }
+ break;
+ case '[':
+LOOP:
+ if (*++cp2 == '$' &&
+ isdigit((unsigned char)*(cp2+1))) {
+ if (*++cp2 == '0') {
+ char *cp3 = name;
+
+ while (*cp3) {
+ *cp1++ = *cp3++;
+ }
+ match = 1;
+ }
+ else if (toks[toknum = *cp2 - '1']) {
+ char *cp3 = tp[toknum];
+
+ while (cp3 != te[toknum]) {
+ *cp1++ = *cp3++;
+ }
+ match = 1;
+ }
+ }
+ else {
+ while (*cp2 && *cp2 != ',' &&
+ *cp2 != ']') {
+ if (*cp2 == '\\') {
+ cp2++;
+ }
+ else if (*cp2 == '$' &&
+ isdigit((unsigned char)*(cp2+1))) {
+ if (*++cp2 == '0') {
+ char *cp3 = name;
+
+ while (*cp3) {
+ *cp1++ = *cp3++;
+ }
+ }
+ else if (toks[toknum =
+ *cp2 - '1']) {
+ char *cp3=tp[toknum];
+
+ while (cp3 !=
+ te[toknum]) {
+ *cp1++ = *cp3++;
+ }
+ }
+ }
+ else if (*cp2) {
+ *cp1++ = *cp2++;
+ }
+ }
+ if (!*cp2) {
+ fputs(
+ "nmap: unbalanced brackets.\n",
+ ttyout);
+ return (name);
+ }
+ match = 1;
+ cp2--;
+ }
+ if (match) {
+ while (*++cp2 && *cp2 != ']') {
+ if (*cp2 == '\\' && *(cp2 + 1)) {
+ cp2++;
+ }
+ }
+ if (!*cp2) {
+ fputs(
+ "nmap: unbalanced brackets.\n",
+ ttyout);
+ return (name);
+ }
+ break;
+ }
+ switch (*++cp2) {
+ case ',':
+ goto LOOP;
+ case ']':
+ break;
+ default:
+ cp2--;
+ goto LOOP;
+ }
+ break;
+ case '$':
+ if (isdigit((unsigned char)*(cp2 + 1))) {
+ if (*++cp2 == '0') {
+ char *cp3 = name;
+
+ while (*cp3) {
+ *cp1++ = *cp3++;
+ }
+ }
+ else if (toks[toknum = *cp2 - '1']) {
+ char *cp3 = tp[toknum];
+
+ while (cp3 != te[toknum]) {
+ *cp1++ = *cp3++;
+ }
+ }
+ break;
+ }
+ /* intentional drop through */
+ default:
+ *cp1++ = *cp2;
+ break;
+ }
+ cp2++;
+ }
+ *cp1 = '\0';
+ if (!*new) {
+ return (name);
+ }
+ return (new);
+}
+
+void
+setpassive(int argc, char *argv[])
+{
+
+ if (argc == 1) {
+ passivemode = !passivemode;
+ activefallback = passivemode;
+ } else if (argc != 2) {
+ passiveusage:
+ fprintf(ttyout, "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
+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)
+ fprintf(ttyout,
+ "usage: %s (all|get|put),maximum-bytes[,increment-bytes]]\n",
+ argv[0]);
+ else
+ fprintf(ttyout,
+ "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) {
+ fprintf(ttyout, "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;
+ updateremotepwd();
+ }
+}
+
+/*
+ * Restart transfer at specific point
+ */
+void
+restart(int argc, char *argv[])
+{
+
+ if (argc == 0 || argc > 2) {
+ fprintf(ttyout, "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) {
+ fprintf(ttyout, "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:
+ fprintf(ttyout, "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"))) {
+ fprintf(ttyout, "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"))) {
+ fprintf(ttyout, "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], asctime(localtime(&mtime)));
+ code = (mtime > 0);
+}
+
+/*
+ * Show status on remote machine
+ */
+void
+rmtstatus(int argc, char *argv[])
+{
+
+ if (argc == 0) {
+ fprintf(ttyout, "usage: %s [remote-file]\n", argv[0]);
+ code = -1;
+ return;
+ }
+ (void)command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
+}
+
+/*
+ * 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[])
+{
+ int len;
+ char *p, *pager, *locfile;
+
+ if (argc == 0 || argc > 2 ||
+ (argc == 1 && !another(&argc, &argv, "local-file"))) {
+ fprintf(ttyout, "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 = xmalloc(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, len;
+ char *p, *pager;
+
+ if (argc == 0 || argc > 2 ||
+ (argc == 1 && !another(&argc, &argv, "remote-file"))) {
+ fprintf(ttyout, "usage: %s remote-file\n", argv[0]);
+ code = -1;
+ return;
+ }
+ p = getoptionvalue("pager");
+ if (EMPTYSTRING(p))
+ p = DEFAULTPAGER;
+ len = strlen(p) + 2;
+ pager = xmalloc(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+w", 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:
+ fprintf(ttyout, "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)) {
+ fprintf(ttyout, "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 {
+ o = getoption(argv[1]);
+ if (o == NULL) {
+ fprintf(ttyout, "No such option `%s'.\n", argv[1]);
+ return;
+ }
+ FREEPTR(o->value);
+ o->value = xstrdup(argv[2]);
+ if (verbose)
+ fprintf(ttyout, "Setting `%s' to `%s'.\n",
+ o->name, o->value);
+ }
+ code = 0;
+}
+
+/*
+ * Unset an option
+ */
+void
+unsetoption(int argc, char *argv[])
+{
+ struct option *o;
+
+ code = -1;
+ if (argc == 0 || argc != 2) {
+ fprintf(ttyout, "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) {
+ fprintf(ttyout, "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) {
+ fprintf(ttyout, "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! */
+ (void)command(argc == 1 ? "MLST" : "MLST %s", argv[1]);
+ verbose = oldverbose;
+}
+
+void
+opts(int argc, char *argv[])
+{
+ int oldverbose = verbose;
+
+ if (argc < 2 || argc > 3) {
+ fprintf(ttyout, "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! */
+ (void)command(argc == 2 ? "OPTS %s" : "OPTS %s %s", argv[1], argv[2]);
+ verbose = oldverbose;
+}
diff --git a/contrib/lukemftp/src/cmdtab.c b/contrib/lukemftp/src/cmdtab.c
new file mode 100644
index 000000000000..492f7bd54449
--- /dev/null
+++ b/contrib/lukemftp/src/cmdtab.c
@@ -0,0 +1,291 @@
+/* $NetBSD: cmdtab.c,v 1.38 2000/09/14 13:48:33 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1996-2000 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.
+ * 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.
+ */
+
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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 "lukemftp.h"
+
+#include "ftp_var.h"
+
+/*
+ * User FTP -- Command Tables.
+ */
+
+char accounthelp[] = "send account command to remote server";
+char appendhelp[] = "append to a file";
+char asciihelp[] = "set ascii transfer type";
+char beephelp[] = "beep when command completed";
+char binaryhelp[] = "set binary transfer type";
+char casehelp[] = "toggle mget upper/lower case id mapping";
+char cdhelp[] = "change remote working directory";
+char cduphelp[] = "change remote working directory to parent directory";
+char chmodhelp[] = "change file permissions of remote file";
+char connecthelp[] = "connect to remote ftp server";
+char crhelp[] = "toggle carriage return stripping on ascii gets";
+char debughelp[] = "toggle/set debugging mode";
+char deletehelp[] = "delete remote file";
+char disconhelp[] = "terminate ftp session";
+char domachelp[] = "execute macro";
+char edithelp[] = "toggle command line editing";
+char epsv4help[] = "toggle use of EPSV/EPRT on IPv4 ftp";
+char feathelp[] = "show FEATures supported by remote system";
+char formhelp[] = "set file transfer format";
+char gatehelp[] = "toggle gate-ftp; specify host[:port] to change proxy";
+char globhelp[] = "toggle metacharacter expansion of local file names";
+char hashhelp[] = "toggle printing `#' marks; specify number to set size";
+char helphelp[] = "print local help information";
+char idlehelp[] = "get (set) idle timer on remote side";
+char lcdhelp[] = "change local working directory";
+char lpagehelp[] = "view a local file through your pager";
+char lpwdhelp[] = "print local working directory";
+char lshelp[] = "list contents of remote path";
+char macdefhelp[] = "define a macro";
+char mdeletehelp[] = "delete multiple files";
+char mgethelp[] = "get multiple files";
+char fgethelp[] = "get files using a localfile as a source of names";
+char mkdirhelp[] = "make directory on the remote machine";
+char mlshelp[] = "list contents of multiple remote directories";
+char mlsdhelp[] = "list contents of remote directory in a machine "
+ "parsable form";
+char mlsthelp[] = "list remote path in a machine parsable form";
+char modehelp[] = "set file transfer mode";
+char modtimehelp[] = "show last modification time of remote file";
+char mputhelp[] = "send multiple files";
+char newerhelp[] = "get file if remote file is newer than local file ";
+char nmaphelp[] = "set templates for default file name mapping";
+char ntranshelp[] = "set translation table for default file name mapping";
+char optshelp[] = "show or set options for remote commands";
+char pagehelp[] = "view a remote file through your pager";
+char passivehelp[] = "enter passive transfer mode";
+char plshelp[] = "list contents of remote path through your pager";
+char pmlsdhelp[] = "list contents of remote directory in a machine "
+ "parsable form through your pager";
+char porthelp[] = "toggle use of PORT/LPRT cmd for each data connection";
+char preservehelp[] ="toggle preservation of modification time of "
+ "retrieved files";
+char progresshelp[] ="toggle transfer progress meter";
+char prompthelp[] = "force interactive prompting on multiple commands";
+char proxyhelp[] = "issue command on alternate connection";
+char pwdhelp[] = "print working directory on remote machine";
+char quithelp[] = "terminate ftp session and exit";
+char quotehelp[] = "send arbitrary ftp command";
+char ratehelp[] = "set transfer rate limit (in bytes/second)";
+char receivehelp[] = "receive file";
+char regethelp[] = "get file restarting at end of local file";
+char remotehelp[] = "get help from remote server";
+char renamehelp[] = "rename file";
+char resethelp[] = "clear queued command replies";
+char restarthelp[]= "restart file transfer at bytecount";
+char rmdirhelp[] = "remove directory on the remote machine";
+char rmtstatushelp[]="show status of remote machine";
+char runiquehelp[] = "toggle store unique for local files";
+char sendhelp[] = "send one file";
+char sethelp[] = "set or display options";
+char shellhelp[] = "escape to the shell";
+char sitehelp[] = "send site specific command to remote server\n"
+ "\t\tTry \"rhelp site\" or \"site help\" "
+ "for more information";
+char sizecmdhelp[] = "show size of remote file";
+char statushelp[] = "show current status";
+char structhelp[] = "set file transfer structure";
+char suniquehelp[] = "toggle store unique on remote machine";
+char systemhelp[] = "show remote system type";
+char tenexhelp[] = "set tenex file transfer type";
+char tracehelp[] = "toggle packet tracing";
+char typehelp[] = "set file transfer type";
+char umaskhelp[] = "get (set) umask on remote side";
+char unsethelp[] = "unset an option";
+char usagehelp[] = "show command usage";
+char userhelp[] = "send new user information";
+char verbosehelp[] = "toggle verbose mode";
+char xferbufhelp[] = "set socket send/receive buffer size";
+
+#ifdef NO_EDITCOMPLETE
+#define CMPL(x)
+#define CMPL0
+#else /* !NO_EDITCOMPLETE */
+#define CMPL(x) #x,
+#define CMPL0 "",
+#endif /* !NO_EDITCOMPLETE */
+
+struct cmd cmdtab[] = {
+ { "!", shellhelp, 0, 0, 0, CMPL0 shell },
+ { "$", domachelp, 1, 0, 0, CMPL0 domacro },
+ { "account", accounthelp, 0, 1, 1, CMPL0 account},
+ { "append", appendhelp, 1, 1, 1, CMPL(lr) put },
+ { "ascii", asciihelp, 0, 1, 1, CMPL0 setascii },
+ { "bell", beephelp, 0, 0, 0, CMPL0 setbell },
+ { "binary", binaryhelp, 0, 1, 1, CMPL0 setbinary },
+ { "bye", quithelp, 0, 0, 0, CMPL0 quit },
+ { "case", casehelp, 0, 0, 1, CMPL0 setcase },
+ { "cd", cdhelp, 0, 1, 1, CMPL(r) cd },
+ { "cdup", cduphelp, 0, 1, 1, CMPL0 cdup },
+ { "chmod", chmodhelp, 0, 1, 1, CMPL(nr) do_chmod },
+ { "close", disconhelp, 0, 1, 1, CMPL0 disconnect },
+ { "cr", crhelp, 0, 0, 0, CMPL0 setcr },
+ { "debug", debughelp, 0, 0, 0, CMPL0 setdebug },
+ { "delete", deletehelp, 0, 1, 1, CMPL(r) delete },
+ { "dir", lshelp, 1, 1, 1, CMPL(rl) ls },
+ { "disconnect", disconhelp, 0, 1, 1, CMPL0 disconnect },
+ { "edit", edithelp, 0, 0, 0, CMPL0 setedit },
+ { "epsv4", epsv4help, 0, 0, 0, CMPL0 setepsv4 },
+ { "exit", quithelp, 0, 0, 0, CMPL0 quit },
+ { "features", feathelp, 0, 1, 1, CMPL0 feat },
+ { "fget", fgethelp, 1, 1, 1, CMPL(l) fget },
+ { "form", formhelp, 0, 1, 1, CMPL0 setform },
+ { "ftp", connecthelp, 0, 0, 1, CMPL0 setpeer },
+ { "gate", gatehelp, 0, 0, 0, CMPL0 setgate },
+ { "get", receivehelp, 1, 1, 1, CMPL(rl) get },
+ { "glob", globhelp, 0, 0, 0, CMPL0 setglob },
+ { "hash", hashhelp, 0, 0, 0, CMPL0 sethash },
+ { "help", helphelp, 0, 0, 1, CMPL(C) help },
+ { "idle", idlehelp, 0, 1, 1, CMPL0 idlecmd },
+ { "image", binaryhelp, 0, 1, 1, CMPL0 setbinary },
+ { "lcd", lcdhelp, 0, 0, 0, CMPL(l) lcd },
+ { "less", pagehelp, 1, 1, 1, CMPL(r) page },
+ { "lpage", lpagehelp, 0, 0, 0, CMPL(l) lpage },
+ { "lpwd", lpwdhelp, 0, 0, 0, CMPL0 lpwd },
+ { "ls", lshelp, 1, 1, 1, CMPL(rl) ls },
+ { "macdef", macdefhelp, 0, 0, 0, CMPL0 macdef },
+ { "mdelete", mdeletehelp, 1, 1, 1, CMPL(R) mdelete },
+ { "mdir", mlshelp, 1, 1, 1, CMPL(R) mls },
+ { "mget", mgethelp, 1, 1, 1, CMPL(R) mget },
+ { "mkdir", mkdirhelp, 0, 1, 1, CMPL(r) makedir },
+ { "mls", mlshelp, 1, 1, 1, CMPL(R) mls },
+ { "mlsd", mlsdhelp, 1, 1, 1, CMPL(r) ls },
+ { "mlst", mlsthelp, 1, 1, 1, CMPL(r) mlst },
+ { "mode", modehelp, 0, 1, 1, CMPL0 setftmode },
+ { "modtime", modtimehelp, 0, 1, 1, CMPL(r) modtime },
+ { "more", pagehelp, 1, 1, 1, CMPL(r) page },
+ { "mput", mputhelp, 1, 1, 1, CMPL(L) mput },
+ { "msend", mputhelp, 1, 1, 1, CMPL(L) mput },
+ { "newer", newerhelp, 1, 1, 1, CMPL(r) newer },
+ { "nlist", lshelp, 1, 1, 1, CMPL(rl) ls },
+ { "nmap", nmaphelp, 0, 0, 1, CMPL0 setnmap },
+ { "ntrans", ntranshelp, 0, 0, 1, CMPL0 setntrans },
+ { "open", connecthelp, 0, 0, 1, CMPL0 setpeer },
+ { "page", pagehelp, 1, 1, 1, CMPL(r) page },
+ { "passive", passivehelp, 0, 0, 0, CMPL0 setpassive },
+ { "pdir", plshelp, 1, 1, 1, CMPL(r) ls },
+ { "pls", plshelp, 1, 1, 1, CMPL(r) ls },
+ { "pmlsd", pmlsdhelp, 1, 1, 1, CMPL(r) ls },
+ { "preserve", preservehelp, 0, 0, 0, CMPL0 setpreserve },
+ { "progress", progresshelp, 0, 0, 0, CMPL0 setprogress },
+ { "prompt", prompthelp, 0, 0, 0, CMPL0 setprompt },
+ { "proxy", proxyhelp, 0, 0, 1, CMPL(c) doproxy },
+ { "put", sendhelp, 1, 1, 1, CMPL(lr) put },
+ { "pwd", pwdhelp, 0, 1, 1, CMPL0 pwd },
+ { "quit", quithelp, 0, 0, 0, CMPL0 quit },
+ { "quote", quotehelp, 1, 1, 1, CMPL0 quote },
+ { "rate", ratehelp, 0, 0, 0, CMPL0 setrate },
+ { "rcvbuf", xferbufhelp, 0, 0, 0, CMPL0 setxferbuf },
+ { "recv", receivehelp, 1, 1, 1, CMPL(rl) get },
+ { "reget", regethelp, 1, 1, 1, CMPL(rl) reget },
+ { "remopts", optshelp, 0, 1, 1, CMPL0 opts },
+ { "rename", renamehelp, 0, 1, 1, CMPL(rr) renamefile },
+ { "reset", resethelp, 0, 1, 1, CMPL0 reset },
+ { "restart", restarthelp, 1, 1, 1, CMPL0 restart },
+ { "rhelp", remotehelp, 0, 1, 1, CMPL0 rmthelp },
+ { "rmdir", rmdirhelp, 0, 1, 1, CMPL(r) removedir },
+ { "rstatus", rmtstatushelp, 0, 1, 1, CMPL(r) rmtstatus },
+ { "runique", runiquehelp, 0, 0, 1, CMPL0 setrunique },
+ { "send", sendhelp, 1, 1, 1, CMPL(lr) put },
+ { "sendport", porthelp, 0, 0, 0, CMPL0 setport },
+ { "set", sethelp, 0, 0, 0, CMPL(o) setoption },
+ { "site", sitehelp, 0, 1, 1, CMPL0 site },
+ { "size", sizecmdhelp, 1, 1, 1, CMPL(r) sizecmd },
+ { "sndbuf", xferbufhelp, 0, 0, 0, CMPL0 setxferbuf },
+ { "status", statushelp, 0, 0, 1, CMPL0 status },
+ { "struct", structhelp, 0, 1, 1, CMPL0 setstruct },
+ { "sunique", suniquehelp, 0, 0, 1, CMPL0 setsunique },
+ { "system", systemhelp, 0, 1, 1, CMPL0 syst },
+ { "tenex", tenexhelp, 0, 1, 1, CMPL0 settenex },
+ { "throttle", ratehelp, 0, 0, 0, CMPL0 setrate },
+ { "trace", tracehelp, 0, 0, 0, CMPL0 settrace },
+ { "type", typehelp, 0, 1, 1, CMPL0 settype },
+ { "umask", umaskhelp, 0, 1, 1, CMPL0 do_umask },
+ { "unset", unsethelp, 0, 0, 0, CMPL(o) unsetoption },
+ { "usage", usagehelp, 0, 0, 1, CMPL(C) help },
+ { "user", userhelp, 0, 1, 1, CMPL0 user },
+ { "verbose", verbosehelp, 0, 0, 0, CMPL0 setverbose },
+ { "xferbuf", xferbufhelp, 0, 0, 0, CMPL0 setxferbuf },
+ { "?", helphelp, 0, 0, 1, CMPL(C) help },
+ { 0 },
+};
+
+struct option optiontab[] = {
+ { "anonpass", NULL },
+ { "ftp_proxy", NULL },
+ { "http_proxy", NULL },
+ { "no_proxy", NULL },
+ { "pager", NULL },
+ { "prompt", NULL },
+ { "rprompt", NULL },
+ { 0 },
+};
diff --git a/contrib/lukemftp/src/complete.c b/contrib/lukemftp/src/complete.c
new file mode 100644
index 000000000000..5d68361ee76a
--- /dev/null
+++ b/contrib/lukemftp/src/complete.c
@@ -0,0 +1,423 @@
+/* $NetBSD: complete.c,v 1.38 2000/05/01 10:35:17 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1997-2000 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.
+ * 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.
+ */
+
+/*
+ * FTP user program - command and file completion routines
+ */
+
+#include "lukemftp.h"
+
+#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 **)a, *(const char **)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;
+ int 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 = xsl_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)
+ xsl_add(words, c->c_name);
+ }
+
+ rv = complete_ambiguous(word, list, words);
+ if (rv == CC_REFRESH) {
+ if (el_insertstr(el, " ") == -1)
+ rv = CC_ERROR;
+ }
+ sl_free(words, 0);
+ 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 = xsl_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 = xstrdup(dp->d_name);
+ xsl_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 = xsl_init();
+ wordlen = strlen(word);
+
+ for (o = optiontab; o->name != NULL; o++) {
+ if (wordlen > strlen(o->name))
+ continue;
+ if (strncmp(word, o->name, wordlen) == 0)
+ xsl_add(words, o->name);
+ }
+
+ rv = complete_ambiguous(word, list, words);
+ if (rv == CC_REFRESH) {
+ if (el_insertstr(el, " ") == -1)
+ rv = CC_ERROR;
+ }
+ sl_free(words, 0);
+ 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;
+ int i;
+ unsigned char rv;
+
+ char *dummyargv[] = { "complete", NULL, NULL };
+ 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 */
+ char *emesg;
+
+ if (dirlist != NULL)
+ sl_free(dirlist, 1);
+ dirlist = xsl_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 = xstrdup(tcp);
+ xsl_add(dirlist, tcp);
+ }
+ if (emesg != NULL) {
+ fprintf(ttyout, "\n%s\n", emesg);
+ return (CC_REDISPLAY);
+ }
+ (void)strlcpy(lastdir, dir, sizeof(lastdir));
+ dirchange = 0;
+ }
+
+ words = xsl_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)
+ xsl_add(words, cp);
+ }
+ rv = complete_ambiguous(file, list, words);
+ sl_free(words, 0);
+ return (rv);
+}
+
+/*
+ * Generic complete routine
+ */
+unsigned char
+complete(EditLine *el, int ch)
+{
+ static char word[FTPBUFLEN];
+ static int lastc_argc, lastc_argo;
+
+ struct cmd *c;
+ const LineInfo *lf;
+ int celems, dolist, cmpltype;
+ size_t len;
+
+ lf = el_line(el);
+ 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 < 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, "unknown complete type `%c'", cmpltype);
+ return (CC_ERROR);
+ }
+ /* NOTREACHED */
+}
+
+#endif /* !NO_EDITCOMPLETE */
diff --git a/contrib/lukemftp/src/domacro.c b/contrib/lukemftp/src/domacro.c
new file mode 100644
index 000000000000..f42011c4f814
--- /dev/null
+++ b/contrib/lukemftp/src/domacro.c
@@ -0,0 +1,133 @@
+/* $NetBSD: domacro.c,v 1.17 2000/07/18 06:45:03 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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 "lukemftp.h"
+
+#include "ftp_var.h"
+
+void
+domacro(int argc, char *argv[])
+{
+ int i, j, count = 2, loopflg = 0;
+ char *cp1, *cp2, line2[200];
+ struct cmd *c;
+
+ if ((argc == 0 && argv != NULL) ||
+ (argc < 2 && !another(&argc, &argv, "macro name"))) {
+ fprintf(ttyout, "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)strcpy(line2, line);
+ 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)strcpy(cp2, argv[j+1]);
+ cp2 += strlen(argv[j+1]);
+ }
+ break;
+ }
+ if (*(cp1+1) == 'i') {
+ loopflg = 1;
+ cp1++;
+ if (count < argc) {
+ (void)strcpy(cp2, argv[count]);
+ 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);
+ }
+ (*c->c_handler)(margc, margv);
+ if (bell && c->c_bell)
+ (void)putc('\007', ttyout);
+ (void)strcpy(line, line2);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ if (cp1 != macros[i].mac_end)
+ cp1++;
+ }
+ if (loopflg && ++count < argc)
+ goto TOP;
+}
diff --git a/contrib/lukemftp/src/extern.h b/contrib/lukemftp/src/extern.h
new file mode 100644
index 000000000000..ba8402b9d13c
--- /dev/null
+++ b/contrib/lukemftp/src/extern.h
@@ -0,0 +1,266 @@
+/* $NetBSD: extern.h,v 1.59 2000/08/06 08:51:22 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1996-2000 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.
+ * 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.
+ */
+
+/*-
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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 *);
+void alarmtimer(int);
+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 **);
+char *docase(char *);
+void domacro(int, char **);
+char *domap(char *);
+void doproxy(int, char **);
+char *dotrans(char *);
+void feat(int, char **);
+void fget(int, 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 *);
+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(char *, 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 mabort(void);
+void macdef(int, char **);
+void makeargv(void);
+void makedir(int, char **);
+void mdelete(int, char **);
+void mget(int, char **);
+void mintr(int);
+void mls(int, char **);
+void mlst(int, char **);
+void modtime(int, char **);
+void mput(int, char **);
+char *onoff(int);
+void opts(int, char **);
+void newer(int, char **);
+void page(int, char **);
+int parseport(const char *, int);
+int parserate(int, char **, int);
+void progressmeter(int);
+char *prompt(void);
+void proxabort(int);
+void proxtrans(const char *, const char *, const char *);
+void psabort(int);
+void psummary(int);
+void pswitch(int);
+void ptransfer(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, 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 **);
+void rmthelp(int, char **);
+void rmtstatus(int, char **);
+char *rprompt(void);
+int ruserpass(const char *, const char **, const char **,
+ const 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 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 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 updateremotepwd(void);
+void usage(void);
+void user(int, char **);
+int xconnect(int, const struct sockaddr *, int);
+int xlisten(int, int);
+void *xmalloc(size_t);
+StringList *xsl_init(void);
+void xsl_add(StringList *, char *);
+char *xstrdup(const char *);
+sigfunc xsignal(int, sigfunc);
+sigfunc xsignal_restart(int, sigfunc, int);
diff --git a/contrib/lukemftp/src/fetch.c b/contrib/lukemftp/src/fetch.c
new file mode 100644
index 000000000000..dfb1c0cf3564
--- /dev/null
+++ b/contrib/lukemftp/src/fetch.c
@@ -0,0 +1,1738 @@
+/* $NetBSD: fetch.c,v 1.125 2000/09/28 12:29:23 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1997-2000 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.
+ * 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.
+ */
+
+/*
+ * FTP User Program -- Command line file retrieval
+ */
+
+#include "lukemftp.h"
+
+#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);
+static int auth_url(const char *, char **, const char *, const char *);
+static void base64_encode(const char *, size_t, char *);
+static int go_fetch(const char *);
+static int fetch_ftp(const char *);
+static int fetch_url(const char *, const char *, char *, 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 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 */
+
+
+/*
+ * 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)
+{
+ char *cp, *ep, *clear, *line, *realm, *scheme;
+ char user[BUFSIZ], *pass;
+ int rval;
+ size_t len, clen, rlen;
+
+ *response = NULL;
+ clear = realm = scheme = NULL;
+ rval = -1;
+ line = xstrdup(challenge);
+ cp = line;
+
+ if (debug)
+ fprintf(ttyout, "auth_url: challenge `%s'\n", challenge);
+
+ scheme = strsep(&cp, " ");
+#define SCHEME_BASIC "Basic"
+ if (strncasecmp(scheme, SCHEME_BASIC, sizeof(SCHEME_BASIC) - 1) != 0) {
+ warnx("Unsupported WWW Authentication challenge - `%s'",
+ challenge);
+ goto cleanup_auth_url;
+ }
+ cp += strspn(cp, " ");
+
+#define REALM "realm=\""
+ if (strncasecmp(cp, REALM, sizeof(REALM) - 1) == 0)
+ cp += sizeof(REALM) - 1;
+ else {
+ warnx("Unsupported WWW Authentication challenge - `%s'",
+ challenge);
+ goto cleanup_auth_url;
+ }
+ if ((ep = strchr(cp, '\"')) != NULL) {
+ size_t len = ep - cp;
+
+ realm = (char *)xmalloc(len + 1);
+ (void)strlcpy(realm, cp, len + 1);
+ } else {
+ warnx("Unsupported WWW Authentication challenge - `%s'",
+ challenge);
+ goto cleanup_auth_url;
+ }
+
+ if (guser != NULL)
+ (void)strlcpy(user, guser, sizeof(user));
+ else {
+ fprintf(ttyout, "Username for `%s': ", realm);
+ (void)fflush(ttyout);
+ if (fgets(user, sizeof(user) - 1, stdin) == NULL) {
+ clearerr(stdin);
+ goto cleanup_auth_url;
+ }
+ user[strlen(user) - 1] = '\0';
+ }
+ if (gpass != NULL)
+ pass = (char *)gpass;
+ else
+ pass = getpass("Password: ");
+
+ clen = strlen(user) + strlen(pass) + 2; /* user + ":" + pass + "\0" */
+ clear = (char *)xmalloc(clen);
+ (void)strlcpy(clear, user, clen);
+ (void)strlcat(clear, ":", clen);
+ (void)strlcat(clear, pass, clen);
+ if (gpass == NULL)
+ memset(pass, 0, strlen(pass));
+
+ /* scheme + " " + enc + "\0" */
+ rlen = strlen(scheme) + 1 + (clen + 2) * 4 / 3 + 1;
+ *response = (char *)xmalloc(rlen);
+ (void)strlcpy(*response, scheme, rlen);
+ len = strlcat(*response, " ", rlen);
+ base64_encode(clear, clen, *response + len);
+ memset(clear, 0, clen);
+ rval = 0;
+
+ cleanup_auth_url:
+ FREEPTR(clear);
+ FREEPTR(line);
+ 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 char *clear, size_t len, char *encoded)
+{
+ static const char enc[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ char *cp;
+ int 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) = '=';
+}
+
+/*
+ * 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:
+ * <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://.
+ *
+ * If <host> is surrounded by `[' and ']', it's parsed as an
+ * IPv6 address (as per RFC 2732).
+ *
+ * XXX: this is not totally RFC 1738 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
+ * --------- -----------
+ * "ftp://host" NULL
+ * "http://host/" NULL
+ * "file://host/dir/file" "dir/file"
+ * "ftp://host/" ""
+ * "ftp://host//" NULL
+ * "ftp://host//dir/file" "/dir/file"
+ */
+static int
+parse_url(const char *url, const char *desc, url_t *type,
+ char **user, char **pass, char **host, char **port,
+ in_port_t *portnum, char **path)
+{
+ const char *origurl;
+ char *cp, *ep, *thost, *tport;
+ size_t len;
+
+ if (url == NULL || desc == NULL || type == NULL || user == NULL
+ || pass == NULL || host == NULL || port == NULL || portnum == NULL
+ || path == NULL)
+ errx(1, "parse_url: invoked with NULL argument!");
+
+ origurl = url;
+ *type = UNKNOWN_URL_T;
+ *user = *pass = *host = *port = *path = NULL;
+ *portnum = 0;
+ tport = NULL;
+
+ if (strncasecmp(url, HTTP_URL, sizeof(HTTP_URL) - 1) == 0) {
+ url += sizeof(HTTP_URL) - 1;
+ *type = HTTP_URL_T;
+ *portnum = HTTP_PORT;
+ tport = httpport;
+ } else if (strncasecmp(url, FTP_URL, sizeof(FTP_URL) - 1) == 0) {
+ url += sizeof(FTP_URL) - 1;
+ *type = FTP_URL_T;
+ *portnum = FTP_PORT;
+ tport = ftpport;
+ } else if (strncasecmp(url, FILE_URL, sizeof(FILE_URL) - 1) == 0) {
+ url += sizeof(FILE_URL) - 1;
+ *type = FILE_URL_T;
+ } else {
+ warnx("Invalid %s `%s'", desc, url);
+ cleanup_parse_url:
+ FREEPTR(*user);
+ 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 = xstrdup(url);
+ else {
+ len = ep - url;
+ thost = (char *)xmalloc(len + 1);
+ (void)strlcpy(thost, url, len + 1);
+ if (*type == FTP_URL_T) /* skip first / for ftp URLs */
+ ep++;
+ *path = xstrdup(ep);
+ }
+
+ cp = strchr(thost, '@'); /* look for user[:pass]@ in URLs */
+ if (cp != NULL) {
+ if (*type == FTP_URL_T)
+ anonftp = 0; /* disable anonftp */
+ *user = thost;
+ *cp = '\0';
+ thost = xstrdup(cp + 1);
+ cp = strchr(*user, ':');
+ if (cp != NULL) {
+ *cp = '\0';
+ *pass = xstrdup(cp + 1);
+ }
+ }
+
+#ifdef INET6
+ /*
+ * Check if thost is an encoded IPv6 address, as per
+ * RFC 2732:
+ * `[' 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) {
+ long nport;
+
+ nport = parseport(cp, -1);
+ if (nport == -1) {
+ warnx("Unknown port `%s' in %s `%s'",
+ cp, desc, origurl);
+ goto cleanup_parse_url;
+ }
+ *portnum = nport;
+ tport = cp;
+ }
+
+ if (tport != NULL)
+ *port = xstrdup(tport);
+ if (*path == NULL)
+ *path = xstrdup("");
+
+ if (debug)
+ fprintf(ttyout,
+ "parse_url: user `%s' pass `%s' host %s port %s(%d) "
+ "path `%s'\n",
+ *user ? *user : "<null>", *pass ? *pass : "<null>",
+ *host ? *host : "<null>", *port ? *port : "<null>",
+ *portnum ? *portnum : -1, *path ? *path : "<null>");
+
+ 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;
+ char hbuf[NI_MAXHOST];
+ volatile sigfunc oldintr, oldintp;
+ volatile int s;
+ struct stat sb;
+ int ischunked, isproxy, rval, hcode;
+ size_t len;
+ static size_t bufsize;
+ static char *xferbuf;
+ char *cp, *ep, *buf, *savefile;
+ char *auth, *location, *message;
+ char *user, *pass, *host, *port, *path, *decodedpath;
+ char *puser, *ppass;
+ off_t hashbytes, rangestart, rangeend, entitylen;
+ int (*closefunc)(FILE *);
+ FILE *fin, *fout;
+ time_t mtime;
+ url_t urltype;
+ in_port_t portnum;
+
+ oldintr = oldintp = NULL;
+ closefunc = NULL;
+ fin = fout = NULL;
+ s = -1;
+ buf = savefile = NULL;
+ auth = location = message = NULL;
+ ischunked = isproxy = hcode = 0;
+ rval = 1;
+ user = pass = host = path = decodedpath = puser = ppass = NULL;
+
+#ifdef __GNUC__ /* shut up gcc warnings */
+ (void)&closefunc;
+ (void)&fin;
+ (void)&fout;
+ (void)&buf;
+ (void)&savefile;
+ (void)&rval;
+ (void)&isproxy;
+ (void)&hcode;
+ (void)&ischunked;
+ (void)&message;
+ (void)&location;
+ (void)&auth;
+ (void)&decodedpath;
+#endif
+
+ if (parse_url(url, "URL", &urltype, &user, &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 = xstrdup(path);
+ url_decode(decodedpath);
+
+ if (outfile)
+ savefile = xstrdup(outfile);
+ else {
+ cp = strrchr(decodedpath, '/'); /* find savefile */
+ if (cp != NULL)
+ savefile = xstrdup(cp + 1);
+ else
+ savefile = xstrdup(decodedpath);
+ }
+ if (EMPTYSTRING(savefile)) {
+ if (urltype == FTP_URL_T) {
+ rval = fetch_ftp(url);
+ goto cleanup_fetch_url;
+ }
+ warnx("Invalid URL (no file after directory) `%s'", url);
+ goto cleanup_fetch_url;
+ } else {
+ if (debug)
+ fprintf(ttyout, "got savefile as `%s'\n", savefile);
+ }
+
+ 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("Cannot open file `%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 lseek 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 */
+ 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;
+
+ isproxy = 1;
+
+ /* check URL against list of no_proxied sites */
+ no_proxy = getoptionvalue("no_proxy");
+ if (! EMPTYSTRING(no_proxy)) {
+ char *np, *np_copy;
+ long np_port;
+ size_t hlen, plen;
+
+ np_copy = xstrdup(no_proxy);
+ hlen = strlen(host);
+ while ((cp = strsep(&np_copy, " ,")) != NULL) {
+ if (*cp == '\0')
+ continue;
+ if ((np = strrchr(cp, ':')) != NULL) {
+ *np = '\0';
+ np_port =
+ strtol(np + 1, &ep, 10);
+ if (*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) {
+ if (parse_url(proxyenv, "proxy URL", &purltype,
+ &puser, &ppass, &phost, &pport, &portnum,
+ &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 = xstrdup(url);
+ FREEPTR(ppath);
+ }
+ } /* ! EMPTYSTRING(proxyenv) */
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = 0;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ error = getaddrinfo(host, NULL, &hints, &res0);
+ if (error) {
+ warnx("%s", 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) {
+ /*
+ * see comment in hookup()
+ */
+ ai_unmapped(res);
+ if (getnameinfo(res->ai_addr, res->ai_addrlen,
+ hbuf, sizeof(hbuf), NULL, 0,
+ NI_NUMERICHOST) != 0)
+ strncpy(hbuf, "invalid", sizeof(hbuf));
+
+ if (verbose && res != res0)
+ fprintf(ttyout, "Trying %s...\n", hbuf);
+
+ ((struct sockaddr_in *)res->ai_addr)->sin_port =
+ htons(portnum);
+ s = socket(res->ai_family, SOCK_STREAM,
+ res->ai_protocol);
+ if (s < 0) {
+ warn("Can't create socket");
+ continue;
+ }
+
+ if (xconnect(s, res->ai_addr, res->ai_addrlen) < 0) {
+ warn("Connect to address `%s'", hbuf);
+ close(s);
+ s = -1;
+ continue;
+ }
+
+ /* success */
+ break;
+ }
+ freeaddrinfo(res0);
+
+ if (s < 0) {
+ warn("Can't connect to %s", host);
+ 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 = xstrdup(host);
+ if (isipv6addr(h) &&
+ (p = strchr(h, '%')) != NULL) {
+ *p = '\0';
+ }
+ fprintf(fin, "Host: [%s]:%d\r\n", h, portnum);
+ free(h);
+ } else
+ fprintf(fin, "Host: %s:%d\r\n", host, portnum);
+ 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");
+ }
+ 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 */
+ if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0)) == NULL) {
+ warn("Receiving HTTP reply");
+ goto cleanup_fetch_url;
+ }
+ while (len > 0 && (buf[len-1] == '\r' || buf[len-1] == '\n'))
+ buf[--len] = '\0';
+ if (debug)
+ fprintf(ttyout, "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 = xstrdup(cp);
+
+ /* Read the rest of the header. */
+ FREEPTR(buf);
+ while (1) {
+ if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0))
+ == NULL) {
+ warn("Receiving HTTP reply");
+ goto cleanup_fetch_url;
+ }
+ while (len > 0 &&
+ (buf[len-1] == '\r' || buf[len-1] == '\n'))
+ buf[--len] = '\0';
+ if (len == 0)
+ break;
+ if (debug)
+ fprintf(ttyout, "received `%s'\n", buf);
+
+ /* Look for some headers */
+ cp = buf;
+
+#define CONTENTLEN "Content-Length: "
+ if (strncasecmp(cp, CONTENTLEN,
+ sizeof(CONTENTLEN) - 1) == 0) {
+ cp += sizeof(CONTENTLEN) - 1;
+ filesize = STRTOLL(cp, &ep, 10);
+ if (filesize < 0 || *ep != '\0')
+ goto improper;
+ if (debug)
+ fprintf(ttyout,
+ "parsed len as: " LLF "\n",
+ (LLT)filesize);
+
+#define CONTENTRANGE "Content-Range: bytes "
+ } else if (strncasecmp(cp, CONTENTRANGE,
+ sizeof(CONTENTRANGE) - 1) == 0) {
+ cp += sizeof(CONTENTRANGE) - 1;
+ rangestart = STRTOLL(cp, &ep, 10);
+ if (rangestart < 0 || *ep != '-')
+ goto improper;
+ cp = ep + 1;
+ rangeend = STRTOLL(cp, &ep, 10);
+ if (rangeend < 0 || *ep != '/' ||
+ rangeend < rangestart)
+ goto improper;
+ cp = ep + 1;
+ entitylen = STRTOLL(cp, &ep, 10);
+ if (entitylen < 0 || *ep != '\0')
+ goto improper;
+
+ if (debug)
+ fprintf(ttyout,
+ "parsed range as: "
+ LLF "-" LLF "/" LLF "\n",
+ (LLT)rangestart,
+ (LLT)rangeend,
+ (LLT)entitylen);
+ if (! restart_point) {
+ warnx(
+ "Received unexpected Content-Range header");
+ goto cleanup_fetch_url;
+ }
+
+#define LASTMOD "Last-Modified: "
+ } else if (strncasecmp(cp, LASTMOD,
+ sizeof(LASTMOD) - 1) == 0) {
+ struct tm parsed;
+ char *t;
+
+ cp += sizeof(LASTMOD) - 1;
+ /* RFC 1123 */
+ if ((t = strptime(cp,
+ "%a, %d %b %Y %H:%M:%S GMT",
+ &parsed))
+ /* RFC 850 */
+ || (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);
+ if (debug && mtime != -1) {
+ fprintf(ttyout,
+ "parsed date as: %s",
+ ctime(&mtime));
+ }
+ }
+
+#define LOCATION "Location: "
+ } else if (strncasecmp(cp, LOCATION,
+ sizeof(LOCATION) - 1) == 0) {
+ cp += sizeof(LOCATION) - 1;
+ location = xstrdup(cp);
+ if (debug)
+ fprintf(ttyout,
+ "parsed location as: %s\n", cp);
+
+#define TRANSENC "Transfer-Encoding: "
+ } else if (strncasecmp(cp, TRANSENC,
+ sizeof(TRANSENC) - 1) == 0) {
+ cp += sizeof(TRANSENC) - 1;
+ if (strcasecmp(cp, "binary") == 0) {
+ warnx(
+ "Bogus transfer encoding - `%s' (fetching anyway)",
+ cp);
+ continue;
+ }
+ if (strcasecmp(cp, "chunked") != 0) {
+ warnx(
+ "Unsupported transfer encoding - `%s'",
+ cp);
+ goto cleanup_fetch_url;
+ }
+ ischunked++;
+ if (debug)
+ fprintf(ttyout,
+ "using chunked encoding\n");
+
+#define PROXYAUTH "Proxy-Authenticate: "
+ } else if (strncasecmp(cp, PROXYAUTH,
+ sizeof(PROXYAUTH) - 1) == 0) {
+ cp += sizeof(PROXYAUTH) - 1;
+ FREEPTR(auth);
+ auth = xstrdup(cp);
+ if (debug)
+ fprintf(ttyout,
+ "parsed proxy-auth as: %s\n", cp);
+
+#define WWWAUTH "WWW-Authenticate: "
+ } else if (strncasecmp(cp, WWWAUTH,
+ sizeof(WWWAUTH) - 1) == 0) {
+ cp += sizeof(WWWAUTH) - 1;
+ FREEPTR(auth);
+ auth = xstrdup(cp);
+ if (debug)
+ fprintf(ttyout,
+ "parsed www-auth as: %s\n", cp);
+
+ }
+
+ }
+ /* finished parsing header */
+ FREEPTR(buf);
+
+ 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:
+ 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;
+ case 401:
+ case 407:
+ {
+ char **authp;
+ char *auser, *apass;
+
+ fprintf(ttyout, "%s\n", message);
+ if (EMPTYSTRING(auth)) {
+ warnx(
+ "No authentication challenge provided by server");
+ goto cleanup_fetch_url;
+ }
+ if (hcode == 401) {
+ authp = &wwwauth;
+ auser = user;
+ apass = pass;
+ } else {
+ authp = &proxyauth;
+ auser = puser;
+ apass = ppass;
+ }
+ if (*authp != NULL) {
+ char reply[10];
+
+ fprintf(ttyout,
+ "Authorization failed. Retry (y/n)? ");
+ if (fgets(reply, sizeof(reply), stdin)
+ == NULL) {
+ clearerr(stdin);
+ goto cleanup_fetch_url;
+ } else {
+ if (tolower(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;
+ }
+ 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 run `%s'", savefile + 1);
+ goto cleanup_fetch_url;
+ }
+ closefunc = pclose;
+ } else {
+ if (restart_point){
+ if (entitylen != -1)
+ filesize = entitylen;
+ if (rangestart != -1 && 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 (rcvbuf_size > bufsize) {
+ if (xferbuf)
+ (void)free(xferbuf);
+ bufsize = rcvbuf_size;
+ xferbuf = xmalloc(bufsize);
+ }
+
+ bytes = 0;
+ hashbytes = mark;
+ progressmeter(-1);
+
+ /* Finally, suck down the file. */
+ do {
+ long chunksize;
+
+ chunksize = 0;
+ /* read chunksize */
+ if (ischunked) {
+ if (fgets(xferbuf, bufsize, fin) == NULL) {
+ warnx("Unexpected EOF reading chunksize");
+ goto cleanup_fetch_url;
+ }
+ chunksize = strtol(xferbuf, &ep, 16);
+
+ /*
+ * XXX: Work around bug in Apache 1.3.9 and
+ * 1.3.11, which incorrectly put trailing
+ * space after the chunksize.
+ */
+ while (*ep == ' ')
+ ep++;
+
+ if (strcmp(ep, "\r\n") != 0) {
+ warnx("Unexpected data following chunksize");
+ goto cleanup_fetch_url;
+ }
+ if (debug)
+ fprintf(ttyout, "got chunksize of " LLF "\n",
+ (LLT)chunksize);
+ if (chunksize == 0)
+ break;
+ }
+ /* 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 : bufsize;
+ if (ischunked)
+ bufrem = MIN(chunksize, bufrem);
+ while (bufrem > 0) {
+ len = fread(xferbuf, sizeof(char),
+ MIN(bufsize, bufrem), fin);
+ if (len <= 0)
+ goto chunkdone;
+ bytes += len;
+ bufrem -= len;
+ if (fwrite(xferbuf, sizeof(char), len, fout)
+ != len) {
+ 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 -= len;
+ 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)
+ break;
+ if (strcmp(xferbuf, "\r\n") != 0) {
+ warnx("Unexpected data following chunk");
+ goto cleanup_fetch_url;
+ }
+ }
+ } while (ischunked);
+ 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);
+ bytes = 0;
+ (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",
+ asctime(localtime(&mtime)));
+ }
+ }
+ if (bytes > 0)
+ ptransfer(0);
+
+ rval = 0;
+ goto cleanup_fetch_url;
+
+ improper:
+ warnx("Improper response from `%s'", host);
+
+ 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);
+ FREEPTR(savefile);
+ FREEPTR(user);
+ FREEPTR(pass);
+ FREEPTR(host);
+ FREEPTR(port);
+ FREEPTR(path);
+ FREEPTR(decodedpath);
+ FREEPTR(puser);
+ FREEPTR(ppass);
+ FREEPTR(buf);
+ FREEPTR(auth);
+ FREEPTR(location);
+ FREEPTR(message);
+ return (rval);
+}
+
+/*
+ * Abort a HTTP retrieval
+ */
+void
+aborthttp(int notused)
+{
+ char msgbuf[100];
+ int len;
+
+ 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, *user, *pass;
+ char *port;
+ int dirhasglob, filehasglob, oautologin, rval, type, xargc;
+ in_port_t portnum;
+ url_t urltype;
+
+ host = path = dir = file = user = pass = NULL;
+ port = NULL;
+ rval = 1;
+ type = TYPE_I;
+
+ if (strncasecmp(url, FTP_URL, sizeof(FTP_URL) - 1) == 0) {
+ if ((parse_url(url, "URL", &urltype, &user, &pass,
+ &host, &port, &portnum, &path) == -1) ||
+ (user != NULL && *user == '\0') ||
+ (pass != NULL && *pass == '\0') ||
+ EMPTYSTRING(host)) {
+ warnx("Invalid URL `%s'", url);
+ goto cleanup_fetch_ftp;
+ }
+ url_decode(user);
+ url_decode(pass);
+ /*
+ * 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)
+ type = TYPE_A;
+ else if (strcasecmp(cp, ";type=i") == 0)
+ type = 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 = xstrdup(url);
+ cp = strchr(host, '@');
+ if (cp != NULL) {
+ *cp = '\0';
+ user = host;
+ anonftp = 0; /* disable anonftp */
+ host = xstrdup(cp + 1);
+ }
+ cp = strchr(host, ':');
+ if (cp != NULL) {
+ *cp = '\0';
+ path = xstrdup(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;
+ dir = "/";
+ } 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) */
+ }
+ if (debug)
+ fprintf(ttyout,
+ "fetch_ftp: user `%s' pass `%s' host %s port %s "
+ "path `%s' dir `%s' file `%s'\n",
+ user ? user : "<null>", pass ? pass : "<null>",
+ host ? host : "<null>", port ? port : "<null>",
+ path ? path : "<null>",
+ dir ? dir : "<null>", file ? file : "<null>");
+
+ 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 */
+ if (connected)
+ disconnect(0, NULL);
+ xargv[0] = __progname;
+ 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, user, pass))) {
+ warnx("Can't connect or login to host `%s'", host);
+ goto cleanup_fetch_ftp;
+ }
+
+ switch (type) {
+ case TYPE_A:
+ setascii(1, xargv);
+ break;
+ case TYPE_I:
+ setbinary(1, xargv);
+ break;
+ default:
+ errx(1, "fetch_ftp: unknown transfer type %d", type);
+ }
+
+ /*
+ * 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 RFC 1738 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 RFC 1738 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;
+ if (debug)
+ fprintf(ttyout, "dir `%s', nextpart `%s'\n",
+ dir ? dir : "<null>",
+ nextpart ? nextpart : "<null>");
+ if (urltype == FTP_URL_T || *dir != '\0') {
+ xargv[0] = "cd";
+ 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"
+" RFC 1738 to support the empty directory in the URL pathname (`//'),\n"
+" conflicts with the server's conformance to RFC 959.\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;
+ xargv[0] = "get";
+ xargv[1] = file;
+ xargv[2] = NULL;
+ if (dirhasglob || filehasglob) {
+ int ointeractive;
+
+ ointeractive = interactive;
+ interactive = 0;
+ xargv[0] = "mget";
+ 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(host);
+ FREEPTR(path);
+ FREEPTR(user);
+ 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 *proxy;
+
+ /*
+ * Check for about:*
+ */
+ if (strncasecmp(url, ABOUT_URL, sizeof(ABOUT_URL) - 1) == 0) {
+ url += sizeof(ABOUT_URL) -1;
+ if (strcasecmp(url, "ftp") == 0) {
+ fputs(
+"This version of ftp has been enhanced by Luke Mewburn <lukem@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@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/index.html\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);
+ }
+
+ /*
+ * Check for file:// and http:// URLs.
+ */
+ if (strncasecmp(url, HTTP_URL, sizeof(HTTP_URL) - 1) == 0 ||
+ strncasecmp(url, FILE_URL, sizeof(FILE_URL) - 1) == 0)
+ 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().
+ */
+ proxy = getoptionvalue("ftp_proxy");
+ if (!EMPTYSTRING(proxy) &&
+ strncasecmp(url, FTP_URL, sizeof(FTP_URL) - 1) == 0)
+ 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;
+ int rval;
+
+ argpos = 0;
+
+ if (sigsetjmp(toplevel, 1)) {
+ if (connected)
+ disconnect(0, NULL);
+ return (argpos + 1);
+ }
+ (void)xsignal(SIGINT, intr);
+ (void)xsignal(SIGPIPE, lostpeer);
+
+ /*
+ * Loop through as long as there's files to fetch.
+ */
+ for (rval = 0; (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);
+}
+
+
+int
+auto_put(int argc, char **argv, const char *uploadserver)
+{
+ char *uargv[4], *path, *pathsep;
+ int uargc, rval, len;
+
+ uargc = 0;
+ uargv[uargc++] = "mput";
+ uargv[uargc++] = argv[0];
+ uargv[2] = uargv[3] = NULL;
+ pathsep = NULL;
+ rval = 1;
+
+ if (debug)
+ fprintf(ttyout, "auto_put: target `%s'\n", uploadserver);
+
+ path = xstrdup(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 */
+ int len;
+
+ len = strlen(uploadserver) + 2; /* path + "/" + "\0" */
+ free(path);
+ path = (char *)xmalloc(len);
+ (void)strlcpy(path, uploadserver, len);
+ (void)strlcat(path, "/", len);
+ } else { /* single file to upload */
+ uargv[0] = "put";
+ pathsep = strrchr(path, '/');
+ if (pathsep == NULL) {
+ pathsep = strrchr(path, ':');
+ if (pathsep == NULL) {
+ warnx("Invalid URL `%s'", path);
+ goto cleanup_auto_put;
+ }
+ pathsep++;
+ uargv[2] = xstrdup(pathsep);
+ pathsep[0] = '/';
+ } else
+ uargv[2] = xstrdup(pathsep + 1);
+ pathsep[1] = '\0';
+ uargc++;
+ }
+ }
+ if (debug)
+ fprintf(ttyout, "auto_put: url `%s' argv[2] `%s'\n",
+ path, uargv[2] ? uargv[2] : "<null>");
+
+ /* connect and cwd */
+ rval = auto_fetch(1, &path);
+ free(path);
+ if(rval >= 0)
+ goto cleanup_auto_put;
+
+ /* XXX : is this the best way? */
+ if (uargc == 3) {
+ uargv[1] = argv[0];
+ put(uargc, uargv);
+ goto cleanup_auto_put;
+ }
+
+ for(; argv[0] != NULL; argv++) {
+ uargv[1] = argv[0];
+ mput(uargc, uargv);
+ }
+ rval = 0;
+
+ cleanup_auto_put:
+ FREEPTR(uargv[2]);
+ return (rval);
+}
diff --git a/contrib/lukemftp/src/ftp.1 b/contrib/lukemftp/src/ftp.1
new file mode 100644
index 000000000000..d4ca1b3fbba5
--- /dev/null
+++ b/contrib/lukemftp/src/ftp.1
@@ -0,0 +1,2049 @@
+.\" $NetBSD: ftp.1,v 1.73 2000/09/28 12:26:19 lukem Exp $
+.\"
+.\" Copyright (c) 1996-2000 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.
+.\" 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.
+.\"
+.\"
+.\" 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. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. 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 September 28, 2000
+.Dt FTP 1
+.Os
+.Sh NAME
+.Nm ftp
+.Nd
+Internet file transfer program
+.Sh SYNOPSIS
+.Nm ""
+.Op Fl AadefginpRtvV
+.Bk -words
+.Op Fl o Ar output
+.Ek
+.Bk -words
+.Op Fl P Ar port
+.Ek
+.Bk -words
+.Op Fl r Ar retry
+.Ek
+.Bk -words
+.Oo
+.Fl T
+.Sm off
+.Xo
+.Ar dir ,
+.Ar max
+.Op , Ar inc
+.Xc
+.Sm on
+.Oc
+.Ek
+.Bk -words
+.Oo
+[\fIuser\fR@]\fIhost\fR
+.Op Ar port
+.Oc
+.Ek
+.Bk -words
+[\fIuser\fR@]\fIhost\fR:[\fIpath\fR][/]
+.Ek
+.Bk -words
+.Op file:///\fIpath\fR
+.Ek
+.Bk -words
+.Op ftp://[\fIuser\fR[:\fIpassword\fR]@]\fIhost\fR[:\fIport\fR]/\fIpath\fR[/]
+.Ek
+.Bk -words
+.Op http://[\fIuser\fR[:\fIpassword\fR]@]\fIhost\fR[:\fIport\fR]/\fIpath\fR
+.Ek
+.Op Ar \&.\&.\&.
+.Nm ""
+.Fl u Ar url
+.\".Ar ftp://[\fIuser\fR[:\fIpassword\fR]@]\fIhost\fR[:\fIport\fR]/\fIpath\fR[/[file]]
+.\"|
+.\".Ar [\fIuser\fR@]\fIhost\fR:[\fIpath\fR][/[\fIfile\fR]]
+.Bk -words
+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 "port "
+.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
+Restrains
+.Nm
+from attempting
+.Dq auto-login
+upon initial connection.
+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.
+.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
+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 P Ar port
+Sets the port number to
+.Ar port .
+.It Fl r Ar wait
+Retry the connection attempt if it failed, pausing for
+.Ar wait
+seconds.
+.It Fl R
+Restart all non-proxied auto-fetches.
+.It Fl t
+Enables packet tracing.
+.It Xo
+.Fl T
+.Sm off
+.Ar direction ,
+.Ar maximum
+.Op , Ar increment
+.Sm on
+.Xc
+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
+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.
+.It Fl V
+Disable
+.Ic verbose
+and
+.Ic progress ,
+overriding the default of enabled when output is to a terminal.
+.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>
+is provided to the user.
+The following commands are recognized
+by
+.Nm ftp :
+.Bl -tag -width Fl
+.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 mget
+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 debug Op Ar debug-value
+Toggle debugging mode.
+If an optional
+.Ar 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 \-\->
+.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 epsv4
+Toggle the use of the extended
+.Dv EPSV
+and
+.Dv EPRT
+commands on IPv4 connections; 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 epsv4
+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 format is
+.Dq file .
+.It Ic ftp Ar host Op Ar port
+A synonym for
+.Ic open .
+.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
+and
+.Ic mput .
+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
+and
+.Ic mget ,
+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
+and
+.Ic mput
+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 (``#'') 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.
+Macros remain defined until a
+.Ic close
+command is executed.
+The macro processor interprets `$' and `\e' as special characters.
+A `$' followed by a number (or numbers) is replaced by the
+corresponding argument on the macro invocation command line.
+A `$' followed by an `i' signals that macro processor that the
+executing macro is to be looped.
+On the first pass `$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 `\e' followed by any character is replaced by that character.
+Use the `\e' to prevent special treatment of the `$'.
+.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 mode is
+.Dq stream
+mode.
+.It Ic modtime Ar remote-file
+Show the last modification time of the file on the remote machine.
+.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 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 `$1', `$2', ..., `$9' in
+.Ar inpattern .
+Use `\\' to prevent this special treatment of the `$' 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 `$1', `$2', ...., `$9' are replaced by any value resulting
+from the
+.Ar inpattern
+template.
+The sequence `$0' is replace by the original filename.
+Additionally, the sequence
+.Ql 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: `nmap $1 sed "s/ *$//" > $1' .
+Use the `\e' character to prevent special treatment
+of the `$','[',']', and `,' 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 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 Ic auto
+Toggle passive mode (if no arguments are given).
+If
+.Ic 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 RFC 1123, 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 Ic a
+Answer
+.Sq yes
+to the current file, and automatically answer
+.Sq yes
+to any remaining files for the current command.
+.It Ic n
+Answer
+.Sq no ,
+and do not transfer the file.
+.It Ic p
+Answer
+.Sq yes
+to the current file, and turn off prompt mode
+(as is
+.Dq prompt off
+had been given).
+.It Ic q
+Terminate the current operation.
+.It Ic y
+Answer
+.Sq yes ,
+and transfer the file.
+.It Ic ?
+Display a help message.
+.El
+.Pp
+Any other reponse 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 Xo
+.Ic rate Ar direction
+.Op Ar maximum Op Ar increment
+.Xc
+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 Ic all
+Both directions.
+.It Ic get
+Incoming transfers.
+.It Ic put
+Outgoing transfers.
+.El
+.Pp
+.Ar maximum
+can by modified on the fly by
+.Ar increment
+bytes (default: 1024) each time a given signal is received:
+.B
+.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 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 anonpass
+Defaults to
+.Ev $FTPANONPASS
+.It ftp_proxy
+Defaults to
+.Ev $ftp_proxy .
+.It http_proxy
+Defaults to
+.Ev $http_proxy .
+.It no_proxy
+Defaults to
+.Ev $no_proxy .
+.It pager
+Defaults to
+.Ev $PAGER .
+.It prompt
+Defaults to
+.Ev $FTPPROMPT .
+.It rprompt
+Defaults to
+.Ev $FTPRPROMPT .
+.El
+.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 site Ar arg1 arg2 ...
+The arguments specified are sent, verbatim, to the remote
+.Tn FTP
+server as a
+.Dv SITE
+command.
+.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 .
+By default
+.Dq stream
+structure is used.
+.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 Xo
+.Ic user Ar user-name
+.Op Ar password Op Ar account
+.Xc
+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 `"' 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 b
+Causes no modification. (Optional)
+.It k
+Kilo; multiply the argument by 1024
+.It m
+Mega; multiply the argument by 1048576
+.It 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 "
+.It [user@]host:[path][/]
+.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.
+.It ftp://[user[:password]@]host[:port]/path[/][;type=X]
+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
+In order to be compliant with
+.Cm RFC 1738 ,
+.Nm
+strips the leading
+.Sq /
+from
+.Ar path ,
+resulting in a transfer relative from the default login directory of
+the 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
+.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.
+.It http://[user[:password]@]host[:port]/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
+authorisation 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.
+.It file:///path
+A local URL, copied from
+.Ar /path .
+.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 .
+.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 ``globbing'' is enabled,
+local file names are expanded
+according to the rules used in the
+.Xr csh 1 ;
+c.f. 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.
+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@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.
+If a macro named
+.Ic init
+is defined, it is automatically executed as the last step in the
+auto-login process.
+.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> "
+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 %/
+The current remote working directory.
+.It %c[[0]\fIn\fR], %.[[0]\fIn\fR]
+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
+.Dq /\fI<skipped>\fRtrailing
+(for
+.Sq %c )
+or
+.Dq ...trailing
+(for
+.Sq %. ) .
+.It %M
+The remote host name.
+.It %m
+The remote host name, up to the first
+.Sq \&. .
+.It %n
+The remote user name.
+.It %%
+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 active
+active mode
+.Tn FTP
+only
+.It auto
+automatic determination of passive or active (this is the default)
+.It gate
+gate-ftp mode
+.It passive
+passive mode
+.Tn FTP
+only
+.El
+.It Ev FTPPROMPT
+Command-line prompt to use.
+Defaults to
+.Dq "ftp> " .
+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 HOME
+For default location of a
+.Pa .netrc
+file, if one exists.
+.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).
+.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
+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 ).
+.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 SEE ALSO
+.Xr getservbyname 3 ,
+.Xr editrc 5 ,
+.Xr services 5 ,
+.Xr ftpd 8
+.Sh STANDARDS
+.Nm
+attempts to be compliant with
+.Cm RFC 959 ,
+.Cm RFC 1123 ,
+.Cm RFC 1738 ,
+.Cm RFC 2068 ,
+.Cm RFC 2389 ,
+.Cm RFC 2428 ,
+.Cm RFC 2732 ,
+and
+.Cm draft-ietf-ftpext-mlst-11 .
+.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 Luke Mewburn <lukem@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.
diff --git a/contrib/lukemftp/src/ftp.c b/contrib/lukemftp/src/ftp.c
new file mode 100644
index 000000000000..b627b2b534b0
--- /dev/null
+++ b/contrib/lukemftp/src/ftp.c
@@ -0,0 +1,2100 @@
+/* $NetBSD: ftp.c,v 1.109 2000/09/28 12:29:24 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1996-2000 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.
+ * 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.
+ */
+
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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 "lukemftp.h"
+
+#include <arpa/telnet.h>
+
+#include "ftp_var.h"
+
+volatile int abrtflag = 0;
+volatile int timeoutflag = 0;
+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 !HAVE_SOCKADDR_SA_LEN
+ int si_len;
+#endif
+};
+
+#if !HAVE_SOCKADDR_SA_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(char *host, char *port)
+{
+ int s = -1, len, error, portnum;
+ struct addrinfo hints, *res, *res0;
+ char hbuf[MAXHOSTNAMELEN];
+ static char hostnamebuf[MAXHOSTNAMELEN];
+ char *cause = "unknown";
+
+ memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
+ memset((char *)&myctladdr, 0, sizeof (myctladdr));
+ memset(&hints, 0, sizeof(hints));
+ portnum = parseport(port, FTP_PORT);
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ error = getaddrinfo(host, NULL, &hints, &res0);
+ if (error) {
+ warnx("%s", 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) {
+ /*
+ * make sure that 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!
+ */
+ ai_unmapped(res);
+#if 0 /*old behavior*/
+ if (res != res0) /* not on the first address */
+#else
+ if (res0->ai_next) /* if we have multiple possibilities */
+#endif
+ {
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
+ fprintf(ttyout, "Trying %s...\n", hbuf);
+ }
+ ((struct sockaddr_in *)res->ai_addr)->sin_port = htons(portnum);
+ s = socket(res->ai_family, SOCK_STREAM, res->ai_protocol);
+ if (s < 0) {
+ cause = "socket";
+ continue;
+ }
+ while ((error = xconnect(s, res->ai_addr, res->ai_addrlen)) < 0
+ && errno == EINTR) {
+ ;
+ }
+ if (error) {
+ /* this "if" clause is to prevent print warning twice */
+ if (res->ai_next) {
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ hbuf, sizeof(hbuf), NULL, 0,
+ NI_NUMERICHOST);
+ warn("connect to address %s", hbuf);
+ }
+ cause = "connect";
+ close(s);
+ s = -1;
+ continue;
+ }
+
+ /* finally we got one */
+ break;
+ }
+ if (s < 0) {
+ warn("%s", cause);
+ 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) < 0) {
+ warn("getsockname");
+ 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, (char *)&tos,
+ sizeof(int)) < 0)
+ warn("setsockopt TOS (ignored)");
+ }
+#endif
+ cin = fdopen(s, "r");
+ cout = fdopen(s, "w");
+ if (cin == NULL || cout == NULL) {
+ warnx("fdopen failed.");
+ 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;
+ }
+ {
+ int on = 1;
+
+ if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
+ < 0 && debug) {
+ warn("setsockopt");
+ }
+ }
+
+ return (hostname);
+ bad:
+ (void)close(s);
+ return (NULL);
+}
+
+void
+cmdabort(int notused)
+{
+ int oerrno = errno;
+
+ 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;
+
+ if (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);
+ }
+ 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);
+}
+
+int
+getreply(int expecteof)
+{
+ char current_line[BUFSIZ]; /* last line of previous reply */
+ int c, n, line;
+ 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 (line = 0 ;; line++) {
+ dig = n = code = 0;
+ cp = current_line;
+ while (alarmtimer(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) {
+ if (reply_timeoutflag)
+ fputs(
+ "421 Service not available, remote server timed out. Connection closed\n",
+ ttyout);
+ else if (reply_abrtflag)
+ fputs(
+ "421 Service not available, user interrupt. Connection closed.\n",
+ ttyout);
+ else
+ fputs(
+ "421 Service not available, remote server has closed connection.\n",
+ ttyout);
+ (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 != ')')
+ *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 (line == 0)
+ (void)strlcpy(reply_string, current_line,
+ sizeof(reply_string));
+ if (line > 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 *cin, FILE *din, int sec)
+{
+ int nr;
+ int nfd = 0;
+
+#ifdef USE_SELECT
+ struct timeval t;
+ fd_set rmask;
+
+ FD_ZERO(&rmask);
+ if (cin) {
+ if (nfd < fileno(cin))
+ nfd = fileno(cin);
+ FD_SET(fileno(cin), &rmask);
+ }
+ if (din) {
+ if (nfd < fileno(din))
+ nfd = fileno(din);
+ FD_SET(fileno(din), &rmask);
+ }
+
+ t.tv_sec = (long) sec;
+ t.tv_usec = 0;
+ if ((nr = select(nfd, &rmask, NULL, NULL, &t)) <= 0)
+ return nr;
+
+ nr = 0;
+ if (cin)
+ nr |= FD_ISSET(fileno(cin), &rmask) ? 1 : 0;
+ if (din)
+ nr |= FD_ISSET(fileno(din), &rmask) ? 2 : 0;
+
+#else
+ struct pollfd pfd[2];
+
+ if (cin) {
+ pfd[nfd].fd = fileno(cin);
+ pfd[nfd++].events = POLLIN;
+ }
+
+ if (din) {
+ pfd[nfd].fd = fileno(din);
+ pfd[nfd++].events = POLLIN;
+ }
+
+ if ((nr = poll(pfd, nfd, sec * 1000)) <= 0)
+ return nr;
+
+ nr = 0;
+ nfd = 0;
+ if (cin)
+ nr |= (pfd[nfd++].revents & POLLIN) ? 1 : 0;
+ if (din)
+ nr |= (pfd[nfd++].revents & POLLIN) ? 2 : 0;
+#endif
+ return nr;
+}
+
+sigjmp_buf xferabort;
+
+void
+abortxfer(int notused)
+{
+ char msgbuf[100];
+ int len;
+
+ 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 called with 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);
+}
+
+void
+sendrequest(const char *cmd, const char *local, const char *remote,
+ int printnames)
+{
+ struct stat st;
+ int c, d;
+ FILE *fin, *dout;
+ int (*closefunc)(FILE *);
+ sigfunc oldintr, oldintp;
+ volatile off_t hashbytes;
+ char *lmode, *bufp;
+ static size_t bufsize;
+ static char *buf;
+ int oprogress;
+
+#ifdef __GNUC__ /* to shut up gcc warnings */
+ (void)&fin;
+ (void)&dout;
+ (void)&closefunc;
+ (void)&oldintr;
+ (void)&oldintp;
+ (void)&lmode;
+#endif
+
+ hashbytes = mark;
+ direction = "sent";
+ dout = NULL;
+ bytes = 0;
+ filesize = -1;
+ oprogress = progress;
+ if (verbose && printnames) {
+ if (local && *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("%s", local + 1);
+ code = -1;
+ goto cleanupsend;
+ }
+ progress = 0;
+ closefunc = pclose;
+ } else {
+ fin = fopen(local, "r");
+ if (fin == NULL) {
+ warn("local: %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 = fseek(fin, (long) restart_point, SEEK_SET);
+ break;
+ case TYPE_I:
+ case TYPE_L:
+ rc = lseek(fileno(fin), restart_point, SEEK_SET);
+ break;
+ }
+ if (rc < 0) {
+ warn("local: %s", local);
+ goto cleanupsend;
+ }
+ if (command("REST " LLF, (LLT)restart_point) != CONTINUE)
+ goto cleanupsend;
+ lmode = "r+w";
+ }
+ if (remote) {
+ if (command("%s %s", cmd, remote) != PRELIM)
+ goto cleanupsend;
+ } else {
+ if (command("%s", cmd) != PRELIM)
+ goto cleanupsend;
+ }
+ dout = dataconn(lmode);
+ if (dout == NULL)
+ goto abort;
+
+ if (sndbuf_size > bufsize) {
+ if (buf)
+ (void)free(buf);
+ bufsize = sndbuf_size;
+ buf = xmalloc(bufsize);
+ }
+
+ progressmeter(-1);
+ oldintp = xsignal(SIGPIPE, SIG_IGN);
+
+ switch (curtype) {
+
+ case TYPE_I:
+ case TYPE_L:
+ if (rate_put) { /* rate limited */
+ while (1) {
+ struct timeval then, now, td;
+ off_t bufrem;
+
+ (void)gettimeofday(&then, NULL);
+ errno = c = d = 0;
+ bufrem = rate_put;
+ while (bufrem > 0) {
+ if ((c = read(fileno(fin), buf,
+ MIN(bufsize, bufrem))) <= 0)
+ goto senddone;
+ bytes += c;
+ bufrem -= c;
+ for (bufp = buf; c > 0;
+ c -= d, bufp += d)
+ if ((d = write(fileno(dout),
+ bufp, c)) <= 0)
+ break;
+ if (d < 0)
+ goto senddone;
+ if (hash &&
+ (!progress || filesize < 0) ) {
+ while (bytes >= hashbytes) {
+ (void)putc('#', ttyout);
+ hashbytes += mark;
+ }
+ (void)fflush(ttyout);
+ }
+ }
+ while (1) {
+ (void)gettimeofday(&now, NULL);
+ timersub(&now, &then, &td);
+ if (td.tv_sec > 0)
+ break;
+ usleep(1000000 - td.tv_usec);
+ }
+ }
+ } else { /* simpler/faster; no rate limit */
+ while (1) {
+ errno = c = d = 0;
+ if ((c = read(fileno(fin), buf, bufsize)) <= 0)
+ goto senddone;
+ bytes += c;
+ for (bufp = buf; c > 0; c -= d, bufp += d)
+ if ((d = write(fileno(dout), bufp, c))
+ <= 0)
+ break;
+ if (d < 0)
+ goto senddone;
+ if (hash && (!progress || filesize < 0) ) {
+ while (bytes >= hashbytes) {
+ (void)putc('#', ttyout);
+ hashbytes += mark;
+ }
+ (void)fflush(ttyout);
+ }
+ }
+ }
+ senddone:
+ if (hash && (!progress || filesize < 0) && bytes > 0) {
+ if (bytes < mark)
+ (void)putc('#', ttyout);
+ (void)putc('\n', ttyout);
+ }
+ if (c < 0)
+ warn("local: %s", local);
+ if (d < 0) {
+ if (errno != EPIPE)
+ warn("netout");
+ bytes = -1;
+ }
+ break;
+
+ case TYPE_A:
+ while ((c = getc(fin)) != EOF) {
+ if (c == '\n') {
+ while (hash && (!progress || filesize < 0) &&
+ (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 RFC */
+ if (c == '\r') {
+ (void)putc('\0', dout);
+ bytes++;
+ }
+#endif
+ }
+ if (hash && (!progress || filesize < 0)) {
+ if (bytes < hashbytes)
+ (void)putc('#', ttyout);
+ (void)putc('\n', ttyout);
+ }
+ if (ferror(fin))
+ warn("local: %s", local);
+ if (ferror(dout)) {
+ if (errno != EPIPE)
+ warn("netout");
+ 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 *local, const char *remote,
+ const char *lmode, int printnames, int ignorespecial)
+{
+ FILE *fout, *din;
+ int (*closefunc)(FILE *);
+ sigfunc oldintr, oldintp;
+ int c, d;
+ volatile int is_retr, tcrflag, bare_lfs;
+ static size_t bufsize;
+ static char *buf;
+ volatile off_t hashbytes;
+ struct stat st;
+ time_t mtime;
+ struct timeval tval[2];
+ int oprogress;
+ int opreserve;
+
+#ifdef __GNUC__ /* to shut up gcc warnings */
+ (void)&local;
+ (void)&fout;
+ (void)&din;
+ (void)&closefunc;
+ (void)&oldintr;
+ (void)&oldintp;
+#endif
+
+ 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 (local && (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("local: %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("local: %s", local);
+ code = -1;
+ goto cleanuprecv;
+ }
+ if (!runique && errno == EACCES &&
+ chmod(local, (S_IRUSR|S_IWUSR)) < 0) {
+ warn("local: %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("%s", local+1);
+ goto abort;
+ }
+ progress = 0;
+ preserve = 0;
+ closefunc = pclose;
+ } else {
+ fout = fopen(local, lmode);
+ if (fout == NULL) {
+ warn("local: %s", local);
+ goto abort;
+ }
+ closefunc = fclose;
+ }
+
+ if (fstat(fileno(fout), &st) != -1 && !S_ISREG(st.st_mode)) {
+ progress = 0;
+ preserve = 0;
+ }
+ if (rcvbuf_size > bufsize) {
+ if (buf)
+ (void)free(buf);
+ bufsize = rcvbuf_size;
+ buf = xmalloc(bufsize);
+ }
+
+ progressmeter(-1);
+
+ switch (curtype) {
+
+ case TYPE_I:
+ case TYPE_L:
+ if (is_retr && restart_point &&
+ lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
+ warn("local: %s", local);
+ goto cleanuprecv;
+ }
+ if (rate_get) { /* rate limiting */
+ while (1) {
+ struct timeval then, now, td;
+ off_t bufrem;
+
+ (void)gettimeofday(&then, NULL);
+ errno = c = d = 0;
+ for (bufrem = rate_get; bufrem > 0; ) {
+ if ((c = read(fileno(din), buf,
+ MIN(bufsize, bufrem))) <= 0)
+ goto recvdone;
+ bytes += c;
+ bufrem -=c;
+ if ((d = write(fileno(fout), buf, c))
+ != c)
+ goto recvdone;
+ if (hash &&
+ (!progress || filesize < 0)) {
+ while (bytes >= hashbytes) {
+ (void)putc('#', ttyout);
+ hashbytes += mark;
+ }
+ (void)fflush(ttyout);
+ }
+ }
+ /* sleep until time is up */
+ while (1) {
+ (void)gettimeofday(&now, NULL);
+ timersub(&now, &then, &td);
+ if (td.tv_sec > 0)
+ break;
+ usleep(1000000 - td.tv_usec);
+ }
+ }
+ } else { /* faster code (no limiting) */
+ while (1) {
+ errno = c = d = 0;
+ if ((c = read(fileno(din), buf, bufsize)) <= 0)
+ goto recvdone;
+ bytes += c;
+ if ((d = write(fileno(fout), buf, c)) != c)
+ goto recvdone;
+ if (hash && (!progress || filesize < 0)) {
+ while (bytes >= hashbytes) {
+ (void)putc('#', ttyout);
+ hashbytes += mark;
+ }
+ (void)fflush(ttyout);
+ }
+ }
+ }
+ recvdone:
+ if (hash && (!progress || filesize < 0) && bytes > 0) {
+ if (bytes < mark)
+ (void)putc('#', ttyout);
+ (void)putc('\n', ttyout);
+ }
+ if (c < 0) {
+ if (errno != EPIPE)
+ warn("netin");
+ bytes = -1;
+ }
+ if (d < c) {
+ if (d < 0)
+ warn("local: %s", local);
+ else
+ warnx("%s: short write", local);
+ }
+ break;
+
+ case TYPE_A:
+ if (is_retr && restart_point) {
+ int ch;
+ long i, n;
+
+ if (fseek(fout, 0L, SEEK_SET) < 0)
+ goto done;
+ n = (long)restart_point;
+ for (i = 0; i++ < n;) {
+ if ((ch = getc(fout)) == EOF)
+ goto done;
+ if (ch == '\n')
+ i++;
+ }
+ if (fseek(fout, 0L, SEEK_CUR) < 0) {
+ done:
+ warn("local: %s", local);
+ goto cleanuprecv;
+ }
+ }
+ while ((c = getc(din)) != EOF) {
+ if (c == '\n')
+ bare_lfs++;
+ while (c == '\r') {
+ while (hash && (!progress || filesize < 0) &&
+ (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 && (!progress || filesize < 0)) {
+ if (bytes < hashbytes)
+ (void)putc('#', ttyout);
+ (void)putc('\n', ttyout);
+ }
+ if (ferror(din)) {
+ if (errno != EPIPE)
+ warn("netin");
+ bytes = -1;
+ }
+ if (ferror(fout))
+ warn("local: %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, asctime(localtime(&mtime)));
+ }
+ }
+ }
+ }
+ goto cleanuprecv;
+
+ abort:
+ /*
+ * abort using RFC 959 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, len, tmpno = 0;
+ int on = 1;
+ int error;
+ u_int addr[16], port[2];
+ u_int af, hal, pal;
+ char *pasvcmd = NULL;
+
+#ifdef INET6
+ if (myctladdr.su_family == AF_INET6 && 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 address can be troublesome");
+ }
+#endif
+ reinit:
+ if (passivemode) {
+ data_addr = myctladdr;
+ data = socket(data_addr.su_family, SOCK_STREAM, 0);
+ if (data < 0) {
+ warn("socket");
+ return (1);
+ }
+ if ((options & SO_DEBUG) &&
+ setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
+ sizeof(on)) < 0)
+ warn("setsockopt (ignored)");
+ result = COMPLETE + 1;
+ switch (data_addr.su_family) {
+ case AF_INET:
+ if (epsv4 && !epsv4bad) {
+ result = command(pasvcmd = "EPSV");
+ 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;
+ if (debug)
+ fputs(
+ "disabling epsv4 for this connection\n",
+ ttyout);
+ }
+ }
+ if (result != COMPLETE) {
+ result = command(pasvcmd = "PASV");
+ if (!connected)
+ return (1);
+ }
+ break;
+#ifdef INET6
+ case AF_INET6:
+ result = command(pasvcmd = "EPSV");
+ 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)
+ result = command(pasvcmd = "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);
+ {
+ int 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;
+
+ while (xconnect(data, (struct sockaddr *)&data_addr.si_su,
+ data_addr.su_len) < 0) {
+ if (errno == EINTR)
+ continue;
+ if (activefallback) {
+ (void)close(data);
+ data = -1;
+ passivemode = 0;
+#if 0
+ activefallback = 0;
+#endif
+ goto reinit;
+ }
+ warn("connect");
+ goto bad;
+ }
+#ifdef IPTOS_THROUGHPUT
+ if (data_addr.su_family == AF_INET) {
+ on = IPTOS_THROUGHPUT;
+ if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
+ sizeof(int)) < 0)
+ warn("setsockopt TOS (ignored)");
+ }
+#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("socket");
+ if (tmpno)
+ sendport = 1;
+ return (1);
+ }
+ if (!sendport)
+ if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
+ sizeof(on)) < 0) {
+ warn("setsockopt (reuse address)");
+ goto bad;
+ }
+ if (bind(data, (struct sockaddr *)&data_addr.si_su,
+ data_addr.su_len) < 0) {
+ warn("bind");
+ goto bad;
+ }
+ if (options & SO_DEBUG &&
+ setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
+ sizeof(on)) < 0)
+ warn("setsockopt (ignored)");
+ len = sizeof(data_addr.si_su);
+ memset((char *)&data_addr, 0, sizeof (data_addr));
+ if (getsockname(data, (struct sockaddr *)&data_addr.si_su, &len) < 0) {
+ warn("getsockname");
+ goto bad;
+ }
+ data_addr.su_len = len;
+ if (xlisten(data, 1) < 0)
+ warn("listen");
+
+ if (sendport) {
+#ifdef INET6
+ char hname[INET6_ADDRSTRLEN];
+ int af;
+#endif
+
+ switch (data_addr.su_family) {
+ case AF_INET:
+ if (!epsv4 || epsv4bad) {
+ result = COMPLETE + 1;
+ break;
+ }
+ /* FALLTHROUGH */
+#ifdef INET6
+ case AF_INET6:
+ af = (data_addr.su_family == AF_INET) ? 1 : 2;
+ if (getnameinfo((struct sockaddr *)&data_addr.si_su,
+ data_addr.su_len, hname, sizeof(hname), NULL, 0,
+ NI_NUMERICHOST)) {
+ result = ERROR;
+ } else {
+ result = command("EPRT |%d|%s|%d|", af, hname,
+ ntohs(data_addr.su_port));
+ if (!connected)
+ return (1);
+ if (result != COMPLETE) {
+ epsv4bad = 1;
+ if (debug)
+ fputs(
+ "disabling epsv4 for this connection\n",
+ ttyout);
+ }
+ }
+ break;
+#endif
+ 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, (char *)&on,
+ sizeof(int)) < 0)
+ warn("setsockopt TOS (ignored)");
+ }
+#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, fromlen = myctladdr.su_len;
+
+ if (passivemode)
+ return (fdopen(data, lmode));
+
+ s = accept(data, (struct sockaddr *) &from.si_su, &fromlen);
+ if (s < 0) {
+ warn("accept");
+ (void)close(data), data = -1;
+ return (NULL);
+ }
+ (void)close(data);
+ data = s;
+#ifdef IPTOS_THROUGHPUT
+ if (from.su_family == AF_INET) {
+ int tos = IPTOS_THROUGHPUT;
+ if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
+ sizeof(int)) < 0) {
+ warn("setsockopt TOS (ignored)");
+ }
+ }
+#endif
+ return (fdopen(data, lmode));
+}
+
+void
+psabort(int notused)
+{
+ int oerrno = errno;
+
+ 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)
+{
+
+ 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 oldintr;
+ int prox_type, nfnd;
+ volatile int secndflag;
+ char *cmd2;
+
+#ifdef __GNUC__ /* to shut up gcc warnings */
+ (void)&oldintr;
+ (void)&cmd2;
+#endif
+
+ 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("abort");
+ 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) {
+ fprintf(ttyout, "usage: %s\n", argv[0]);
+ code = -1;
+ return;
+ }
+ while (nfnd > 0) {
+ if ((nfnd = empty(cin, NULL, 0)) < 0) {
+ warn("reset");
+ 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("local: %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];
+ int len;
+
+ 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("abort");
+ fprintf(cout, "%cABOR\r\n", DM);
+ (void)fflush(cout);
+ if ((nfnd = empty(cin, din, 10)) <= 0) {
+ if (nfnd < 0)
+ warn("abort");
+ 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);
+}
+
+void
+ai_unmapped(struct addrinfo *ai)
+{
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+ struct sockaddr_in sin;
+ int 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 HAVE_SOCKADDR_SA_LEN
+ sin.sin_len = len;
+#endif
+ memcpy(ai->ai_addr, &sin, len);
+ ai->ai_addrlen = len;
+#endif
+}
diff --git a/contrib/lukemftp/src/ftp_var.h b/contrib/lukemftp/src/ftp_var.h
new file mode 100644
index 000000000000..ac6963820f74
--- /dev/null
+++ b/contrib/lukemftp/src/ftp_var.h
@@ -0,0 +1,353 @@
+/* $NetBSD: ftp_var.h,v 1.58 2000/08/01 22:47:28 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1996-2000 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.
+ * 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.
+ */
+
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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
+
+#ifndef NO_EDITCOMPLETE
+#include <histedit.h>
+#endif /* !NO_EDITCOMPLETE */
+
+typedef void (*sigfunc)(int);
+
+#include "extern.h"
+
+
+/*
+ * Format of command table.
+ */
+struct cmd {
+ char *c_name; /* name of command */
+ 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
+ char *c_complete; /* context sensitive completion list */
+#endif /* !NO_EDITCOMPLETE */
+ void (*c_handler)(int, char **); /* function to call */
+};
+
+/*
+ * 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 {
+ 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 STALLTIME 5 /* # of seconds of no xfer before "stalling" */
+
+#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 verbose; /* print messages coming back from server */
+GLOBAL int connected; /* 1 = connected to server, -1 = logged in */
+GLOBAL int fromatty; /* input is from a terminal */
+GLOBAL int interactive; /* interactively prompt on m* cmds */
+GLOBAL int confirmrest; /* confirm rest of current m* cmd */
+GLOBAL int 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 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 progress; /* display transfer progress bar */
+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 int ttywidth; /* width of tty */
+GLOBAL char *tmpdir; /* temporary directory */
+GLOBAL FILE *ttyout; /* stdout, or stderr if retrieving to stdout */
+GLOBAL int epsv4; /* use EPSV/EPRT on IPv4 connections */
+GLOBAL int epsv4bad; /* 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 off_t bytes; /* current # of bytes read */
+GLOBAL off_t filesize; /* size of file being transferred */
+GLOBAL char *direction; /* direction transfer is occurring */
+GLOBAL off_t restart_point; /* offset to restart transfer */
+
+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 remotepwd[MAXPATHLEN]; /* remote dir */
+GLOBAL char *username; /* name of user logged in as. (dynamic) */
+
+GLOBAL char *ftpport; /* port number to use for FTP connections */
+GLOBAL char *httpport; /* port number to use for HTTP connections */
+GLOBAL char *gateport; /* port number to use for gateftp connections */
+
+GLOBAL char *outfile; /* filename to output URLs to */
+GLOBAL int restartautofetch; /* restart auto-fetch */
+
+GLOBAL sigjmp_buf toplevel; /* non-local goto stuff for cmd scanner */
+
+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 home[MAXPATHLEN]; /* home directory (for lcd) */
+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 FILE *cin;
+GLOBAL FILE *cout;
+GLOBAL int data;
+
+extern struct cmd cmdtab[];
+extern struct option optiontab[];
+
+extern char *__progname; /* from crt0.o */
+
+
+#define EMPTYSTRING(x) ((x) == NULL || (*(x) == '\0'))
+#define FREEPTR(x) if ((x) != NULL) { free(x); (x) = NULL; }
+
+#ifdef BSD4_4
+# define HAVE_SOCKADDR_SA_LEN 1
+#endif
+
+#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
+# define STRTOLL(x,y,z) strtol(x,y,z)
+#else
+# 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
+# define STRTOLL(x,y,z) strtoll(x,y,z)
+#endif
diff --git a/contrib/lukemftp/src/main.c b/contrib/lukemftp/src/main.c
new file mode 100644
index 000000000000..d28a08f1e822
--- /dev/null
+++ b/contrib/lukemftp/src/main.c
@@ -0,0 +1,965 @@
+/* $NetBSD: main.c,v 1.73 2000/07/18 07:16:56 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1996-2000 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.
+ * 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.
+ */
+
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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.
+ */
+
+/*
+ * FTP User Program -- Command Interface.
+ */
+
+#include "lukemftp.h"
+
+#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 */
+
+char * __progname;
+
+static void setupoption(char *, char *, char *);
+int main(int, char *[]);
+
+int
+main(int argc, char *argv[])
+{
+ int ch, rval;
+ struct passwd *pw = NULL;
+ char *cp, *ep, *anonuser, *anonpass, *upload_path;
+ int dumbterm, s, len, isupload;
+
+ __progname = strrchr(argv[0], '/');
+ if (__progname == NULL)
+ __progname = argv[0];
+ else
+ __progname++;
+
+ 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;
+#else
+ epsv4 = 0;
+#endif
+ epsv4bad = 0;
+ upload_path = NULL;
+ isupload = 0;
+ reply_callback = NULL;
+
+ /*
+ * Get the default socket buffer sizes if we don't already have them.
+ * It doesn't matter which socket we do this to, because on the first
+ * call no socket buffer sizes will have been modified, so we are
+ * guaranteed to get the system defaults.
+ */
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s == -1)
+ err(1, "can't create socket");
+ len = sizeof(rcvbuf_size);
+ if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, (void *) &rcvbuf_size, &len)
+ < 0)
+ err(1, "unable to get default rcvbuf size");
+ len = sizeof(sndbuf_size);
+ if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, (void *) &sndbuf_size, &len)
+ < 0)
+ err(1, "unable to get default sndbuf size");
+ (void)close(s);
+ /* sanity check returned buffer sizes */
+ if (rcvbuf_size <= 0)
+ rcvbuf_size = 8192;
+ if (sndbuf_size <= 0)
+ sndbuf_size = 8192;
+
+ marg_sl = xsl_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(__progname, "pftp") == 0) {
+ passivemode = 1;
+ activefallback = 0;
+ } else if (strcmp(__progname, "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, "Aadefgino:pP:r:RtT:u:vV")) != -1) {
+ switch (ch) {
+ case 'A':
+ activefallback = 0;
+ passivemode = 0;
+ break;
+
+ case 'a':
+ anonftp = 1;
+ break;
+
+ case 'd':
+ options |= SO_DEBUG;
+ 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 'o':
+ outfile = optarg;
+ if (strcmp(outfile, "-") == 0)
+ ttyout = stderr;
+ break;
+
+ case 'p':
+ passivemode = 1;
+ activefallback = 0;
+ break;
+
+ case 'P':
+ ftpport = 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 't':
+ trace = 1;
+ break;
+
+ case 'T':
+ {
+ int targc;
+ char *targv[6], *oac;
+
+ /* look for `dir,max[,incr]' */
+ targc = 0;
+ targv[targc++] = "-T";
+ oac = xstrdup(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 = xstrdup(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 */
+ /*
+ * Set up the home directory in case we're globbing.
+ */
+ cp = getlogin();
+ if (cp != NULL)
+ pw = getpwnam(cp);
+ if (pw == NULL)
+ pw = getpwuid(getuid());
+ if (pw != NULL) {
+ (void)strlcpy(home, pw->pw_dir, sizeof(home));
+ anonuser = pw->pw_name;
+ } else {
+ (void)strlcpy(home, "/", sizeof(home));
+ anonuser = "anonymous";
+ }
+
+ /*
+ * 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@netbsd.org
+ */
+ len = strlen(anonuser) + 2;
+ anonpass = xmalloc(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);
+
+#ifdef __GNUC__ /* to shut up gcc warnings */
+ (void)&argc;
+ (void)&argv;
+#endif
+
+ if (argc > 0) {
+ if (isupload) {
+ rval = auto_put(argc, argv, upload_path);
+ exit(rval);
+ } else if (strchr(argv[0], ':') != NULL
+ && ! isipv6addr(argv[0])) {
+ rval = auto_fetch(argc, argv);
+ if (rval >= 0) /* -1 == connected and cd-ed */
+ exit(rval);
+ } else {
+ char *xargv[4], *user, *host;
+
+ if (sigsetjmp(toplevel, 1))
+ exit(0);
+ (void)xsignal(SIGINT, intr);
+ (void)xsignal(SIGPIPE, lostpeer);
+ user = NULL;
+ host = argv[0];
+ cp = strchr(host, '@');
+ if (cp) {
+ *cp = '\0';
+ user = host;
+ host = cp + 1;
+ }
+ xargv[0] = __progname;
+ xargv[1] = host;
+ xargv[2] = argv[1];
+ xargv[3] = NULL;
+ do {
+ int oautologin;
+
+ oautologin = autologin;
+ if (user != NULL) {
+ anonftp = 0;
+ autologin = 0;
+ }
+ setpeer(argc+1, xargv);
+ autologin = oautologin;
+ if (connected == 1 && user != NULL)
+ (void)ftp_login(host, user, 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 **prompt;
+ static char buf[MAXPATHLEN];
+
+ if (prompt == NULL) {
+ struct option *o;
+
+ o = getoption("prompt");
+ if (o == NULL)
+ errx(1, "no such option `prompt'");
+ prompt = &(o->value);
+ }
+ formatbuf(buf, sizeof(buf), *prompt ? *prompt : DEFAULTPROMPT);
+ return (buf);
+}
+
+/*
+ * Generate an rprompt
+ */
+char *
+rprompt(void)
+{
+ static char **rprompt;
+ static char buf[MAXPATHLEN];
+
+ if (rprompt == NULL) {
+ struct option *o;
+
+ o = getoption("rprompt");
+ if (o == NULL)
+ errx(1, "no such option `rprompt'");
+ rprompt = &(o->value);
+ }
+ formatbuf(buf, sizeof(buf), *rprompt ? *rprompt : DEFAULTRPROMPT);
+ return (buf);
+}
+
+/*
+ * Command parser.
+ */
+void
+cmdscanner(void)
+{
+ struct cmd *c;
+ char *p;
+ int num;
+
+ 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);
+ }
+ if (fgets(line, sizeof(line), stdin) == NULL) {
+ if (fromatty)
+ putc('\n', ttyout);
+ quit(0, NULL);
+ }
+ num = strlen(line);
+ if (num == 0)
+ break;
+ if (line[--num] == '\n') {
+ if (num == 0)
+ break;
+ line[num] = '\0';
+ } else if (num == sizeof(line) - 2) {
+ fputs("sorry, input line too long.\n", ttyout);
+ while ((num = getchar()) != '\n' && num != EOF)
+ /* void */;
+ break;
+ } /* else it was a line without a newline */
+#ifndef NO_EDITCOMPLETE
+ } else {
+ const char *buf;
+ HistEvent ev;
+ cursor_pos = NULL;
+
+ if ((buf = el_gets(el, &num)) == NULL || num == 0) {
+ if (fromatty)
+ putc('\n', ttyout);
+ quit(0, NULL);
+ }
+ if (buf[--num] == '\n') {
+ if (num == 0)
+ break;
+ } else if (num >= sizeof(line)) {
+ fputs("sorry, input line too long.\n", ttyout);
+ break;
+ }
+ memcpy(line, buf, num);
+ line[num] = '\0';
+ 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 ||
+ el_parse(el, margc, margv) != 0)
+#endif /* !NO_EDITCOMPLETE */
+ fputs("?Invalid command.\n", ttyout);
+ continue;
+ }
+ if (c->c_conn && !connected) {
+ fputs("Not connected.\n", ttyout);
+ continue;
+ }
+ confirmrest = 0;
+ (*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();
+ xsl_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)
+{
+ 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 == '!') ? "!" : "$");
+ /* 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], *p, *cmd;
+ int isusage;
+
+ cmd = argv[0];
+ isusage = (strcmp(cmd, "usage") == 0);
+ if (argc == 0 || (isusage && argc == 1)) {
+ fprintf(ttyout, "usage: %s [command [...]]\n", cmd);
+ return;
+ }
+ if (argc == 1) {
+ StringList *buf;
+
+ buf = xsl_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)
+ xsl_add(buf, p);
+ list_vertical(buf);
+ sl_free(buf, 0);
+ return;
+ }
+
+#define HELPINDENT ((int) sizeof("disconnect"))
+
+ while (--argc > 0) {
+ char *arg;
+
+ 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) {
+ nargv[0] = arg;
+ (*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(char *name, char *value, char *defaultvalue)
+{
+ char *nargv[3];
+ int overbose;
+
+ nargv[0] = "setupoption()";
+ nargv[1] = name;
+ nargv[2] = (value ? value : defaultvalue);
+ overbose = verbose;
+ verbose = 0;
+ setoption(3, nargv);
+ verbose = overbose;
+}
+
+void
+usage(void)
+{
+ (void)fprintf(stderr,
+"usage: %s [-AadefginpRtvV] [-o outfile] [-P port] [-r retry]\n"
+" [-T dir,max[,inc][[user@]host [port]]] [host:path[/]]\n"
+" [file:///file] [ftp://[user[:pass]@]host[:port]/path[/]]\n"
+" [http://[user[:pass]@]host[:port]/path] [...]\n"
+" %s -u url file [...]\n", __progname, __progname);
+ exit(1);
+}
diff --git a/contrib/lukemftp/src/ruserpass.c b/contrib/lukemftp/src/ruserpass.c
new file mode 100644
index 000000000000..1b2bf843d274
--- /dev/null
+++ b/contrib/lukemftp/src/ruserpass.c
@@ -0,0 +1,284 @@
+/* $NetBSD: ruserpass.c,v 1.27 2000/07/18 06:47:02 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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 "lukemftp.h"
+
+#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 {
+ 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, const char **aname, const char **apass,
+ const char **aacct)
+{
+ char *hdir, buf[BUFSIZ], *tmp;
+ char myname[MAXHOSTNAMELEN + 1], *mydomain;
+ int t, i, c, usedefault = 0;
+ struct stat stb;
+
+ hdir = getenv("HOME");
+ if (hdir == NULL)
+ hdir = ".";
+ if (strlcpy(buf, hdir, sizeof(buf)) >= sizeof(buf) ||
+ strlcat(buf, "/.netrc", sizeof(buf)) >= sizeof(buf)) {
+ warnx("%s/.netrc: %s", hdir, strerror(ENAMETOOLONG));
+ return (0);
+ }
+ cfile = fopen(buf, "r");
+ if (cfile == NULL) {
+ if (errno != ENOENT)
+ warn("%s", buf);
+ 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())) switch(t) {
+
+ case DEFAULT:
+ usedefault = 1;
+ /* FALL THROUGH */
+
+ case MACH:
+ if (!usedefault) {
+ if (token() != 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()) && t != MACH && t != DEFAULT) switch(t) {
+
+ case LOGIN:
+ if (token()) {
+ if (*aname == NULL)
+ *aname = xstrdup(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 (token() && *apass == NULL)
+ *apass = xstrdup(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 (token() && *aacct == NULL)
+ *aacct = xstrdup(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-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:
+ (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 == '\\')
+ c = getc(cfile);
+ *cp++ = c;
+ }
+ } else {
+ *cp++ = c;
+ while ((c = getc(cfile)) != EOF
+ && c != '\n' && c != '\t' && c != ' ' && c != ',') {
+ if (c == '\\')
+ c = getc(cfile);
+ *cp++ = c;
+ }
+ }
+ *cp = 0;
+ if (tokval[0] == 0)
+ return (0);
+ for (t = toktab; t->tokstr; t++)
+ if (!strcmp(t->tokstr, tokval))
+ return (t->tval);
+ return (ID);
+}
diff --git a/contrib/lukemftp/src/util.c b/contrib/lukemftp/src/util.c
new file mode 100644
index 000000000000..d1ce22646b28
--- /dev/null
+++ b/contrib/lukemftp/src/util.c
@@ -0,0 +1,1620 @@
+/* $NetBSD: util.c,v 1.102 2000/09/08 11:54:53 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1997-2000 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.
+ * 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.
+ */
+
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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 User Program -- Misc support routines
+ */
+
+#include "lukemftp.h"
+
+#include "ftp_var.h"
+
+/*
+ * Connect to peer server and auto-login, if possible.
+ */
+void
+setpeer(int argc, char *argv[])
+{
+ char *host;
+ 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:
+ fprintf(ttyout, "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, "gateserver not defined (shouldn't happen)");
+ 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 *line)
+{
+
+ if (strcasecmp(line, " MDTM") == 0)
+ features[FEAT_MDTM] = 1;
+ else if (strncasecmp(line, " MLST", sizeof(" MLST") - 1) == 0) {
+ features[FEAT_MLST] = 1;
+ } else if (strcasecmp(line, " REST STREAM") == 0)
+ features[FEAT_REST_STREAM] = 1;
+ else if (strcasecmp(line, " SIZE") == 0)
+ features[FEAT_SIZE] = 1;
+ else if (strcasecmp(line, " 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 (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;
+ if (debug)
+ for (i = 0; i < FEAT_max; i++)
+ printf("features[%d] = %d\n", i, features[i]);
+ 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;
+ if (username)
+ free(username);
+ username = NULL;
+ if (!proxy)
+ macnum = 0;
+}
+
+/*
+ * Top-level signal handler for interrupted commands.
+ */
+void
+intr(int dummy)
+{
+
+ 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 *user, const char *pass)
+{
+ char tmp[80];
+ const char *acct;
+ struct passwd *pw;
+ int n, aflag, rval, freeuser, freepass, freeacct;
+
+ acct = NULL;
+ aflag = rval = freeuser = freepass = freeacct = 0;
+
+ if (debug)
+ fprintf(ttyout, "ftp_login: user `%s' pass `%s' host `%s'\n",
+ user ? user : "<null>", pass ? pass : "<null>",
+ host ? host : "<null>");
+
+
+ /*
+ * Set up arguments for an anonymous FTP session, if necessary.
+ */
+ if (anonftp) {
+ user = "anonymous"; /* as per RFC 1635 */
+ pass = getoptionvalue("anonpass");
+ }
+
+ if (user == NULL)
+ freeuser = 1;
+ if (pass == NULL)
+ freepass = 1;
+ freeacct = 1;
+ if (ruserpass(host, &user, &pass, &acct) < 0) {
+ code = -1;
+ goto cleanup_ftp_login;
+ }
+
+ while (user == NULL) {
+ const char *myname = getlogin();
+
+ if (myname == NULL && (pw = getpwuid(getuid())) != NULL)
+ myname = pw->pw_name;
+ if (myname)
+ fprintf(ttyout, "Name (%s:%s): ", host, myname);
+ else
+ fprintf(ttyout, "Name (%s): ", host);
+ *tmp = '\0';
+ if (fgets(tmp, sizeof(tmp) - 1, stdin) == NULL) {
+ fprintf(ttyout, "\nEOF received; login aborted.\n");
+ clearerr(stdin);
+ code = -1;
+ goto cleanup_ftp_login;
+ }
+ tmp[strlen(tmp) - 1] = '\0';
+ freeuser = 0;
+ if (*tmp == '\0')
+ user = myname;
+ else
+ user = tmp;
+ }
+
+ if (gatemode) {
+ char *nuser;
+ int len;
+
+ len = strlen(user) + 1 + strlen(host) + 1;
+ nuser = xmalloc(len);
+ (void)strlcpy(nuser, user, len);
+ (void)strlcat(nuser, "@", len);
+ (void)strlcat(nuser, host, len);
+ freeuser = 1;
+ user = nuser;
+ }
+
+ n = command("USER %s", user);
+ if (n == CONTINUE) {
+ if (pass == NULL) {
+ freepass = 0;
+ pass = getpass("Password:");
+ }
+ n = command("PASS %s", pass);
+ }
+ if (n == CONTINUE) {
+ aflag++;
+ if (acct == NULL) {
+ freeacct = 0;
+ acct = getpass("Account:");
+ }
+ if (acct[0] == '\0') {
+ warnx("Login failed.");
+ goto cleanup_ftp_login;
+ }
+ n = command("ACCT %s", acct);
+ }
+ if ((n != COMPLETE) ||
+ (!aflag && acct != NULL && command("ACCT %s", acct) != COMPLETE)) {
+ warnx("Login failed.");
+ goto cleanup_ftp_login;
+ }
+ rval = 1;
+ username = xstrdup(user);
+ 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;
+ }
+ }
+ updateremotepwd();
+
+ cleanup_ftp_login:
+ if (user != NULL && freeuser)
+ free((char *)user);
+ if (pass != NULL && freepass)
+ free((char *)pass);
+ if (acct != NULL && freeacct)
+ free((char *)acct);
+ 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 *prompt)
+{
+ int len = strlen(line), ret;
+
+ if (len >= sizeof(line) - 3) {
+ fputs("sorry, arguments too long.\n", ttyout);
+ intr(0);
+ }
+ fprintf(ttyout, "(%s) ", prompt);
+ line[len++] = ' ';
+ if (fgets(&line[len], sizeof(line) - len, stdin) == NULL) {
+ clearerr(stdin);
+ intr(0);
+ }
+ len += strlen(&line[len]);
+ if (len > 0 && line[len - 1] == '\n')
+ line[len - 1] = '\0';
+ 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, char **errbuf)
+{
+ char temp[MAXPATHLEN];
+ static char buf[MAXPATHLEN];
+ static FILE *ftemp = NULL;
+ static char **args;
+ int oldverbose, oldhash, fd, len;
+ char *cp, *mode;
+
+ 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;
+ hash = 0;
+ if (doswitch)
+ pswitch(!proxy);
+ for (mode = "w"; *++argv != NULL; mode = "a")
+ recvrequest("NLST", temp, *argv, mode, 0, 0);
+ if ((code / 100) != COMPLETE) {
+ if (errbuf != NULL)
+ *errbuf = reply_string;
+ }
+ if (doswitch)
+ pswitch(!proxy);
+ verbose = oldverbose;
+ hash = oldhash;
+ ftemp = fopen(temp, "r");
+ (void)unlink(temp);
+ if (ftemp == NULL) {
+ if (errbuf == NULL)
+ fputs(
+ "can't find list of remote files, oops.\n",
+ ttyout);
+ else
+ *errbuf =
+ "can't find list of remote files, oops.";
+ 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 (xstrdup(pattern));
+
+ flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
+ memset(&gl, 0, sizeof(gl));
+ if (glob(pattern, flags, NULL, &gl) || gl.gl_pathc == 0) {
+ warnx("%s: not found", pattern);
+ globfree(&gl);
+ return (NULL);
+ }
+ p = xstrdup(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 (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 && 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 (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;
+ int yy, mo, day, hour, min, sec;
+
+ /*
+ * 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);
+ }
+ if (strlen(timestr) != 14 ||
+ sscanf(timestr, "%04d%02d%02d%02d%02d%02d",
+ &yy, &mo, &day, &hour, &min, &sec) != 6) {
+ bad_parse_time:
+ fprintf(ttyout, "Can't parse time `%s'.\n", timestr);
+ goto cleanup_parse_time;
+ }
+ memset(&timebuf, 0, sizeof(timebuf));
+ timebuf.tm_sec = sec;
+ timebuf.tm_min = min;
+ timebuf.tm_hour = hour;
+ timebuf.tm_mday = day;
+ timebuf.tm_mon = mo - 1;
+ timebuf.tm_year = yy - TM_YEAR_BASE;
+ timebuf.tm_isdst = -1;
+ rtime = timegm(&timebuf);
+ if (rtime == -1) {
+ if (noisy || debug != 0)
+ goto bad_parse_time;
+ else
+ goto cleanup_parse_time;
+ } else if (debug)
+ fprintf(ttyout, "parsed date as: %s", ctime(&rtime));
+ } else {
+ if (r == ERROR && code == 500 && features[FEAT_MDTM] == -1)
+ features[FEAT_MDTM] = 0;
+ if (noisy && debug == 0) {
+ fputs(reply_string, ttyout);
+ putc('\n', ttyout);
+ }
+ }
+ cleanup_parse_time:
+ verbose = overbose;
+ if (rtime == -1)
+ code = ocode;
+ return (rtime);
+}
+
+/*
+ * update global `remotepwd', which contains the state of the remote cwd
+ */
+void
+updateremotepwd(void)
+{
+ int overbose, ocode, i;
+ char *cp;
+
+ overbose = verbose;
+ ocode = code;
+ if (debug == 0)
+ verbose = -1;
+ if (command("PWD") != COMPLETE)
+ goto badremotepwd;
+ cp = strchr(reply_string, ' ');
+ if (cp == NULL || cp[0] == '\0' || cp[1] != '"')
+ goto badremotepwd;
+ cp += 2;
+ for (i = 0; *cp && i < sizeof(remotepwd) - 1; i++, cp++) {
+ if (cp[0] == '"') {
+ if (cp[1] == '"')
+ cp++;
+ else
+ break;
+ }
+ remotepwd[i] = *cp;
+ }
+ remotepwd[i] = '\0';
+ if (debug)
+ fprintf(ttyout, "got remotepwd as `%s'\n", remotepwd);
+ goto cleanupremotepwd;
+ badremotepwd:
+ remotepwd[0]='\0';
+ cleanupremotepwd:
+ verbose = overbose;
+ code = ocode;
+}
+
+#ifndef 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);
+}
+
+
+static void updateprogressmeter(int);
+
+/*
+ * SIGALRM handler to update the progress meter
+ */
+static void
+updateprogressmeter(int dummy)
+{
+ int oerrno = errno;
+
+ progressmeter(0);
+ errno = oerrno;
+}
+#endif /* NO_PROGRESS */
+
+
+/*
+ * List of order of magnitude prefixes.
+ * The last is `P', as 2^64 = 16384 Petabytes
+ */
+static const char prefixes[] = " KMGTP";
+
+/*
+ * 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;
+#ifndef NO_PROGRESS
+ struct timeval now, td, wait;
+ off_t cursize, abbrevsize, bytespersec;
+ double elapsed;
+ int ratio, barlength, i, len, remaining;
+
+ /*
+ * 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.
+ */
+ char buf[256]; /* workspace for progress bar */
+#define BAROVERHEAD 43 /* non `*' portion of progress bar */
+ /*
+ * stars should contain at least
+ * sizeof(buf) - BAROVERHEAD entries
+ */
+ const char stars[] =
+"*****************************************************************************"
+"*****************************************************************************"
+"*****************************************************************************";
+
+#endif
+
+ if (flag == -1) {
+ (void)gettimeofday(&start, NULL);
+ lastupdate = start;
+ lastsize = restart_point;
+ }
+#ifndef NO_PROGRESS
+ len = 0;
+ if (!progress || filesize <= 0)
+ return;
+
+ /*
+ * print progress bar only if we are foreground process.
+ */
+ if (! foregroundproc())
+ return;
+
+ (void)gettimeofday(&now, NULL);
+ cursize = bytes + restart_point;
+ timersub(&now, &lastupdate, &wait);
+ if (cursize > lastsize) {
+ lastupdate = now;
+ lastsize = cursize;
+ wait.tv_sec = 0;
+ }
+
+ ratio = (int)((double)cursize * 100.0 / (double)filesize);
+ ratio = MAX(ratio, 0);
+ ratio = MIN(ratio, 100);
+ len += snprintf(buf + len, BUFLEFT, "\r%3d%% ", ratio);
+
+ /*
+ * calculate the length of the `*' bar, ensuring that
+ * the number of stars won't exceed the buffer size
+ */
+ barlength = MIN(sizeof(buf) - 1, ttywidth) - BAROVERHEAD;
+ if (barlength > 0) {
+ i = barlength * ratio / 100;
+ len += snprintf(buf + len, BUFLEFT,
+ "|%.*s%*s|", i, stars, barlength - i, "");
+ }
+
+ abbrevsize = cursize;
+ for (i = 0; abbrevsize >= 100000 && i < sizeof(prefixes); i++)
+ abbrevsize >>= 10;
+ len += snprintf(buf + len, BUFLEFT, " " LLFP("5") " %c%c ",
+ (LLT)abbrevsize,
+ prefixes[i],
+ i == 0 ? ' ' : 'B');
+
+ 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 < sizeof(prefixes); i++)
+ bytespersec >>= 10;
+ len += snprintf(buf + len, BUFLEFT,
+ " " LLFP("3") ".%02d %cB/s ",
+ (LLT)(bytespersec / 1024),
+ (int)((bytespersec % 1024) * 100 / 1024),
+ prefixes[i]);
+
+ 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);
+
+ if (flag == -1) {
+ (void)xsignal_restart(SIGALRM, updateprogressmeter, 1);
+ alarmtimer(1); /* set alarm timer for 1 Hz */
+ } else if (flag == 1) {
+ (void)xsignal(SIGALRM, SIG_DFL);
+ alarmtimer(0);
+ }
+#endif /* !NO_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, 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 < sizeof(prefixes); i++)
+ bytespersec >>= 10;
+ len += snprintf(buf + len, BUFLEFT, "(" LLF ".%02d %cB/s)",
+ (LLT)(bytespersec / 1024),
+ (int)((bytespersec % 1024) * 100 / 1024),
+ prefixes[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;
+}
+
+/*
+ * List words in stringlist, vertically arranged
+ */
+void
+list_vertical(StringList *sl)
+{
+ int i, j, w;
+ int columns, width, lines;
+ char *p;
+
+ 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;
+ }
+ 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);
+ }
+}
+
+
+/*
+ * 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);
+}
+
+/*
+ * Setup or cleanup EditLine structures
+ */
+#ifndef NO_EDITCOMPLETE
+void
+controlediting(void)
+{
+ if (editing && el == NULL && hist == NULL) {
+ HistEvent ev;
+ int editmode;
+
+ el = el_init(__progname, 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)
+{
+
+ if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *) &sndbuf_size,
+ sizeof(rcvbuf_size)) < 0)
+ warn("unable to set sndbuf size %d", sndbuf_size);
+
+ if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *) &rcvbuf_size,
+ sizeof(rcvbuf_size)) < 0)
+ 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)
+{
+ int 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;
+ char *p2, *q;
+ int i, 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 ? remotepwd : "";
+ 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 : "-"; *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';
+}
+
+/*
+ * Parse `port' into a TCP port number, defaulting to `defport' if `port' is
+ * an unknown service name. If defport != -1, print a warning upon bad parse.
+ */
+int
+parseport(const char *port, int defport)
+{
+ int rv;
+ long nport;
+ char *p, *ep;
+
+ p = xstrdup(port);
+ nport = strtol(p, &ep, 10);
+ if (*ep != '\0' && ep == p) {
+ struct servent *svp;
+
+ svp = getservbyname(port, "tcp");
+ if (svp == NULL) {
+ badparseport:
+ if (defport != -1)
+ warnx("Unknown port `%s', using port %d",
+ port, defport);
+ rv = defport;
+ } else
+ rv = ntohs(svp->s_port);
+ } else if (nport < 1 || nport > MAX_IN_PORT_T || *ep != '\0')
+ goto badparseport;
+ else
+ rv = nport;
+ free(p);
+ return (rv);
+}
+
+/*
+ * 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 = PF_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);
+ }
+ if (debug)
+ fprintf(ttyout, "isipv6addr: got %d for %s\n", rv, addr);
+#endif
+ return (rv == 1) ? 1 : 0;
+}
+
+
+/*
+ * Internal version of connect(2); sets socket buffer sizes first.
+ */
+int
+xconnect(int sock, const struct sockaddr *name, int namelen)
+{
+
+ setupsockbufsize(sock);
+ return (connect(sock, name, namelen));
+}
+
+/*
+ * Internal version of listen(2); sets socket buffer sizes first.
+ */
+int
+xlisten(int sock, int backlog)
+{
+
+ setupsockbufsize(sock);
+ return (listen(sock, backlog));
+}
+
+/*
+ * malloc() with inbuilt error checking
+ */
+void *
+xmalloc(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 *
+xsl_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
+xsl_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 *
+xstrdup(const char *str)
+{
+ char *s;
+
+ if (str == NULL)
+ errx(1, "xstrdup() called with NULL argument");
+ s = strdup(str);
+ if (s == NULL)
+ err(1, "Unable to allocate memory for string copy");
+ return (s);
+}
+
+/*
+ * 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));
+}
diff --git a/contrib/lukemftp/src/version.h b/contrib/lukemftp/src/version.h
new file mode 100644
index 000000000000..91c93098d57e
--- /dev/null
+++ b/contrib/lukemftp/src/version.h
@@ -0,0 +1,44 @@
+/* $NetBSD: version.h,v 1.21 2000/09/28 12:29:24 lukem Exp $ */
+/*-
+ * Copyright (c) 1999, 2000 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.
+ * 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.
+ */
+
+#ifndef FTP_PRODUCT
+#define FTP_PRODUCT "NetBSD-ftp"
+#endif
+
+#ifndef FTP_VERSION
+#define FTP_VERSION "20000928"
+#endif
diff --git a/contrib/lukemftp/todo b/contrib/lukemftp/todo
new file mode 100644
index 000000000000..6670b1393940
--- /dev/null
+++ b/contrib/lukemftp/todo
@@ -0,0 +1,15 @@
+$Id: todo,v 1.25 2000/09/19 22:25:50 lukem Exp $
+
+in configure, check for ansi c compiler and barf if it fails
+
+check if we need #defines for memcpy() et al
+
+we check for fparseln twice; once in libutil and once in general
+
+check for utimes() decls [which system?]
+
+possibly install editline.3 and editrc.5
+
+system specific tests (to remove need for manual intervention):
+- sunos4
+ LIBS+= -lresolv