Radix cross Linux

The main Radix cross Linux repository contains the build scripts of packages, which have the most complete and common functionality for desktop machines

452 Commits   2 Branches   1 Tag
Index: create.patch.sh
===================================================================
--- create.patch.sh	(nonexistent)
+++ create.patch.sh	(revision 5)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=0.17
+
+tar --files-from=file.list -xzvf ../netkit-ftp-$VERSION.tar.gz
+mv netkit-ftp-$VERSION netkit-ftp-$VERSION-orig
+
+cp -rf ./netkit-ftp-$VERSION-new ./netkit-ftp-$VERSION
+
+diff --unified -Nr  netkit-ftp-$VERSION-orig  netkit-ftp-$VERSION > netkit-ftp-$VERSION.patch
+
+mv netkit-ftp-$VERSION.patch ../patches
+
+rm -rf ./netkit-ftp-$VERSION
+rm -rf ./netkit-ftp-$VERSION-orig

Property changes on: create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: file.list
===================================================================
--- file.list	(nonexistent)
+++ file.list	(revision 5)
@@ -0,0 +1,12 @@
+netkit-ftp-0.17/ChangeLog
+netkit-ftp-0.17/configure
+netkit-ftp-0.17/ftp/Makefile
+netkit-ftp-0.17/ftp/cmds.c
+netkit-ftp-0.17/ftp/cmdtab.c
+netkit-ftp-0.17/ftp/domacro.c
+netkit-ftp-0.17/ftp/ftp.1
+netkit-ftp-0.17/ftp/ftp.c
+netkit-ftp-0.17/ftp/ftp_var.h
+netkit-ftp-0.17/ftp/glob.c
+netkit-ftp-0.17/ftp/main.c
+netkit-ftp-0.17/ftp/ruserpass.c
Index: netkit-ftp-0.17-new/ChangeLog
===================================================================
--- netkit-ftp-0.17-new/ChangeLog	(nonexistent)
+++ netkit-ftp-0.17-new/ChangeLog	(revision 5)
@@ -0,0 +1,116 @@
+28-Nov-2000:
+	IPv6 support. (Hiroyuki YAMAMORI <h-yamamo@db3.so-net.ne.jp>)
+
+8-Jul-2000:
+	Fix misused printf-function call (not %n-exploitable though).
+
+14-Dec-1999:
+	netkit-ftp-0.16 is released.
+
+13-Dec-1999:
+	Add fix from Olaf Kirch for some rather severe lossage with
+	aliased file descriptors.
+
+12-Dec-1999:
+	Add Olaf Kirch's ftp mget fix on top of the existing one.
+	Portions of the old fix probably ought to be backed out.
+	However, what's really needed is a massive cleanup of the
+	code...
+
+14-Sep-1999:
+	Extensive small fixes and cleanups. (Alan Curry, pacman@londo.cqc.com)
+	Security fix relating to passive mode. (Alan Cox, alan@redhat.com)
+
+1-Aug-1999:
+	Complete y2k and y2038 audit.
+
+31-Jul-1999:
+	Redid makefiles/config stuff for new confgen version.
+
+23-Sep-1997:
+	Fix some suspicious strncpys.
+	Don't print an uninitialized buffer if someone EOFs at the
+	  username prompt. (Olaf Kirch, okir@ns.lst.de)
+	Added a netrc(5) man page.
+	Added -h option to ftp for help, and -e option to inhibit 
+	  editing support. Cleaned up readline handling.
+	Various fixes to the ftp(1) man page. (Larry Doolittle, 
+	  ldoolitt@jlab.org)
+
+17-Aug-1997:
+	Fixed security holes: automatically generated local file paths
+	(those that are supplied by the server or copies of server
+	filenames) are filtered so that they cannot:
+	   1. be pipes or "-" for standard output.
+	   2. be absolute paths.
+	   3. contain ".." path elements.
+
+12-Jun-1997:
+	netkit-ftp-0.10 released.
+
+08-Jun-1997:
+	Fixed doc for "newer" command. (Roderick Schertler,
+	  roderick@argon.org) 
+
+05-Apr-1997:
+	Added configure script to generate MCONFIG.
+	glibc fixes from HJ Lu.
+
+20-Mar-1997:
+	If using readline, pass it the terminal type, so certain .inputrc
+	  constructions work. (Christian Groessler, chris@fast-ag.de)
+
+08-Mar-1997: 
+	Split from full NetKit package. 
+	Generated this change log from NetKit's.
+
+07-Mar-1997
+	Changed order of includes in ftp/cmds.c due to a report of
+	  breakage with libc 5.4.x.
+	Fixed crash in ftp caused by certain syntax errors in .netrc.
+	Fix symbol name conflict on "trace" between ftp and ncurses.
+
+29-Dec-1996
+	NetKit-0.09 released.
+	Assorted alpha/glibc patches. (Erik Troan, ewt@redhat.com)
+	Assorted bug fixes from Debian. (Peter Tobias, 
+	  tobias@et-inf.fho-emden.de)
+	Hardened programs against DNS h_length spoofing attacks.
+	Use inet_aton() everywhere instead of inet_addr().
+	Fixed crash in ftp if you did "lcd" with no args.
+	Fixed bug in ftp where you couldn't abort an mget.
+	Fixed /tmp security problem in ftp.
+
+22-Aug-1996
+	NetKit-B-0.08 released.
+	(almost) everything now compiles with lots of warnings turned on.
+	Fixed some memory allocation bugs in ftp.
+
+25-Jul-1996
+	NetKit-B-0.07A released.
+
+23-Jul-1996
+	NetKit-B-0.07 released.
+	Integrated a collection of patches that had been lurking on the net,
+	  including the 256-ptys support for telnetd and passive mode ftp.
+	Major security fixes, including to fingerd, lpr, rlogin, rsh, talkd, 
+	  and telnetd. Do *not* use the sliplogin from earlier versions of this
+	  package, either.
+	Much of the code builds without libbsd.a or bsd includes.
+	Massive code cleanup. Almost everything compiles clean with gcc
+	  -Wall now. rusers and rusersd do not; patches to rpcgen to fix
+	  this would be appreciated if anyone feels like it.
+	New maintainer:  David A. Holland, dholland@hcs.harvard.edu
+
+date not known
+	NetKit-B-0.06 released.
+
+date not known
+	NetKit-B-0.05 released.
+
+date not known
+	NetKit-B-0.04 released.
+
+date not known
+	NetKit-B-0.03 released.
+
Index: netkit-ftp-0.17-new/configure
===================================================================
--- netkit-ftp-0.17-new/configure	(nonexistent)
+++ netkit-ftp-0.17-new/configure	(revision 5)
@@ -0,0 +1,485 @@
+#!/bin/sh
+#
+# This file was generated by confgen version 2.
+# Do not edit.
+#
+
+PREFIX='/usr'
+#EXECPREFIX='$PREFIX'
+INSTALLROOT=''
+BINMODE='755'
+MANMODE='644'
+
+while [ x$1 != x ]; do case $1 in
+
+	--help)
+	cat <<EOF
+Usage: configure [options]
+    --help                Show this message
+    --with-debug          Enable debugging
+    --without-readline    Disable readline support
+    --prefix=path         Prefix for location of files [/usr]
+    --exec-prefix=path    Location for arch-depedent files [prefix]
+    --installroot=root    Top of filesystem tree to install in [/]
+    --binmode=mode        Mode for binaries [755]
+    --manmode=mode        Mode for manual pages [644]
+    --with-c-compiler=cc  Program for compiling C source [guessed]
+    --enable-ipv6         Enable IPv6 support
+EOF
+	exit 0;;
+	--verbose) ;;
+	--quiet) ;;
+
+	--subdir) . ../configure.defs;;
+
+	--with-debug|--debug) DEBUG=1;;
+	--prefix=*) PREFIX=`echo $1 | sed 's/^[^=]*=//'` ;;
+	--exec-prefix=*) EXECPREFIX=`echo $1 | sed 's/^[^=]*=//'` ;;
+	--installroot=*) INSTALLROOT=`echo $1 | sed 's/^[^=]*=//'` ;;
+	--binmode=*) BINMODE=`echo $1 | sed 's/^[^=]*=//'` ;;
+	--manmode=*) MANMODE=`echo $1 | sed 's/^[^=]*=//'` ;;
+	--with-c-compiler=*) CC=`echo $1 | sed 's/^[^=]*=//'` ;;
+	--without-readline|--disable-readline) WITHOUT_READLINE=1;;
+
+	--disable-ipv6) ENABLE_IPV6=no;;
+	--enable-ipv6=*) ENABLE_IPV6=`echo $1 | sed 's/^[^=]*=//'`;;
+	--enable-ipv6) ENABLE_IPV6=yes;;
+
+	*) echo "Unrecognized option: $1"; exit 1;;
+esac 
+shift
+done
+
+if [ x$EXECPREFIX = x ]; then 
+	EXECPREFIX="$PREFIX"
+fi
+
+BINDIR="$EXECPREFIX/bin"
+MANDIR="$PREFIX/share/man"
+
+echo "Directories: $BINDIR $MANDIR "
+
+if [ x$INSTALLROOT != x ]; then
+    echo "Installing in chroot tree rooted at $INSTALLROOT"
+fi
+
+##################################################
+
+WARNINGS='-Wall -W -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline '
+
+cat << EOF > __conftest.c
+    int main() { int class=0; return class; }
+EOF
+
+if [ x"$CC" = x ]; then
+    echo -n 'Looking for a C compiler... '
+    for TRY in egcs gcc g++ CC c++ cc; do
+       (
+           $TRY __conftest.c -o __conftest || exit 1;
+#           ./__conftest || exit 1;
+       ) >/dev/null 2>&1 || continue;
+       CC=$TRY
+       break;
+    done
+    if [ x"$CC" = x ]; then
+        echo 'failed.'
+        echo 'Cannot find a C compiler. Run configure with --with-c-compiler.'
+        rm -f __conftest*
+        exit
+    fi
+    echo "$CC"
+else
+    echo -n 'Checking if C compiler works... '
+    if (
+          $CC __conftest.c -o __conftest || exit 1
+#          ./__conftest || exit 1
+       ) >/dev/null 2>&1; then
+         echo 'yes'
+     else
+         echo 'no'
+         echo 'Compiler '"$CC"' does not exist or cannot compile C; try another.'
+         rm -f __conftest*
+         exit
+     fi
+fi
+
+echo -n "Checking if $CC accepts gcc warnings... "
+if (
+    $CC $WARNINGS __conftest.c -o __conftest || exit 1
+   ) >/dev/null 2>&1; then
+     echo 'yes'
+     CC_WARNINGS=1
+else
+     echo 'no'
+fi
+
+if [ x$DEBUG = x ]; then
+    echo -n "Checking if $CC accepts -O2... "
+    if (
+         $CC -O2 __conftest.c -o __conftest
+       ) >/dev/null 2>&1; then
+         echo 'yes'
+         CFLAGS="$CFLAGS -O2"
+    else
+         echo 'no'
+         echo -n "Checking if $CC accepts -O... "
+         if (
+              $CC -O __conftest.c -o __conftest
+            ) >/dev/null 2>&1; then
+              echo 'yes'
+              CFLAGS="$CFLAGS -O"
+         else
+              echo 'no'
+         fi
+    fi
+
+else
+    echo -n "Checking if $CC accepts -g... "
+    if (
+         $CC -g __conftest.c -o __conftest
+       ) >/dev/null 2>&1; then
+         echo 'yes'
+         CFLAGS="$CFLAGS -g"
+    else
+         echo 'no'
+    fi
+
+fi
+
+LDFLAGS=$LDFLAGS
+LIBS=$LIBS
+
+rm -f __conftest*
+
+##################################################
+## Enable IPv6
+echo -n "Whether to enable IPv6 support... "
+if [ x"$ENABLE_IPV6" = x"yes" ]; then
+    echo yes
+    CFLAGS="$CFLAGS -DINET6"
+else
+    echo no
+fi
+
+rm -f __conftest*
+
+## Search IPv6 Library / Headers
+if [ x"$ENABLE_IPV6" = x"yes" ]; then
+    echo -n "Search for IPv6 library... "
+    inet6libdirs="/usr/local/v6/lib /usr/local/lib /usr /usr/inet6/lib"
+    inet6libs="inet6"
+    inet6found=no
+    for inet6libdir in $inet6libdirs; do
+        for inet6lib in $inet6libs; do
+            if [ -d $inet6libdir ] && [ -f $inet6libdir/lib$inet6lib.a ]; then
+                inet6found=yes
+                break 2
+            fi
+        done
+    done
+    if [ x"$inet6found" = x"yes" ]; then
+        echo "$inet6libdir/lib$inet6lib.a"
+        LIBS="$LIBS -L$inet6libdir -l$inet6lib"
+    else
+        echo "not found"
+    fi
+fi
+
+rm -f __conftest*
+
+##################################################
+
+echo -n 'Checking for BSD signal semantics... '
+cat <<EOF >__conftest.c
+#include <unistd.h>
+#include <signal.h>
+volatile int count=0;
+void handle(int foo) { count++; write(1,"X",1);}
+int main() {
+    int pid=getpid();
+    signal(SIGINT, handle);
+    kill(pid,SIGINT);
+    kill(pid,SIGINT);
+    kill(pid,SIGINT);
+    if (count!=3) return 1;
+    return 0;
+}
+
+EOF
+if (
+      $CC $CFLAGS  __conftest.c  -o __conftest || exit 1
+#      ./__conftest || exit 1
+   ); then
+    echo 'yes'
+else
+    if (
+          $CC $CFLAGS -D__USE_BSD_SIGNAL __conftest.c  -o __conftest || exit 1
+#          ./__conftest || exit 1
+       ); then
+        echo '-D__USE_BSD_SIGNAL'
+        CFLAGS="$CFLAGS -D__USE_BSD_SIGNAL"
+    else
+        echo 'no'
+        echo '***WARNING***: This package needs BSD signal semantics to run.'
+	echo '***WARNING***: Assuming its just ia64 buildroot breakage.'
+        CFLAGS="$CFLAGS -D__USE_BSD_SIGNAL"
+    fi
+fi
+rm -f __conftest*
+
+##################################################
+
+echo -n 'Checking for ncurses... '
+cat <<EOF >__conftest.c
+#include <stdio.h>
+#include <curses.h>
+#ifndef KEY_DOWN
+syntax error. /* not ncurses */
+#endif
+int main() {
+    endwin();
+    return 0;
+}
+
+EOF
+if (
+      $CC $CFLAGS  __conftest.c -lncurses -o __conftest || exit 1
+   ) >/dev/null 2>&1; then
+    echo 'yes'
+    NCURSES=1
+else
+    if (
+          $CC $CFLAGS -I/usr/include/ncurses __conftest.c -lncurses -o __conftest || exit 1
+       ) >/dev/null 2>&1; then
+        echo '-I/usr/include/ncurses'
+        CFLAGS="$CFLAGS -I/usr/include/ncurses"
+        NCURSES=1
+    else
+        echo 'no'
+    fi
+fi
+
+if [ x$NCURSES != x ]; then
+    LIBTERMCAP=-lncurses
+else
+    echo -n 'Checking for traditional termcap... '
+cat <<EOF >__conftest.c
+#include <stdio.h>
+#include <termcap.h>
+int main() {
+    tgetent(NULL, NULL); return 0;
+}
+
+EOF
+    if (
+          $CC $CFLAGS  __conftest.c -ltermcap -o __conftest || exit 1
+       ) >/dev/null 2>&1; then
+        echo '-ltermcap'
+        LIBTERMCAP=-ltermcap
+    else
+        echo 'not found'
+        echo 'This package needs termcap to run.'
+        rm -f __conftest*
+        exit
+    fi
+fi
+rm -f __conftest*
+
+##################################################
+
+echo -n 'Checking for GNU libc... '
+cat <<EOF >__conftest.c
+#include <stdio.h>
+#if defined(__GLIBC__) && (__GLIBC__ >= 2)
+int tester;
+#endif
+int main() { tester=6; return 0; }
+
+EOF
+if (
+      $CC $CFLAGS  __conftest.c  -o __conftest || exit 1
+   ) >/dev/null 2>&1; then
+    echo 'yes'
+    USE_GLIBC=1
+else
+    echo 'no'
+fi
+rm -f __conftest*
+
+##################################################
+
+echo -n 'Checking for libreadline... '
+if [ x$WITHOUT_READLINE != x ]; then
+    echo disabled
+else
+cat <<EOF >__conftest.c
+#include <stdio.h>
+#include <readline/readline.h>
+#include <readline/tilde.h>
+int main() { readline("foo"); return 0; }
+
+EOF
+if (
+      $CC $CFLAGS  __conftest.c -lreadline $LIBTERMCAP -o __conftest || exit 1
+   ) >/dev/null 2>&1; then
+        echo 'yes'
+        USE_READLINE=1
+    else
+        echo 'no'
+    fi
+fi
+rm -f __conftest*
+
+##################################################
+
+echo -n 'Checking for socklen_t... '
+cat <<EOF >__conftest.c
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+int main() {
+    struct sockaddr_in sn;
+    socklen_t len = sizeof(sn);
+    getpeername(0, (struct sockaddr *)&sn, &len);
+    return 0;
+}
+
+EOF
+if (
+      $CC $CFLAGS  __conftest.c  -o __conftest || exit 1
+   ) >/dev/null 2>&1; then
+    echo 'yes'
+else
+    if (
+          $CC $CFLAGS -Dsocklen_t=int __conftest.c  -o __conftest || exit 1
+       ) >/dev/null 2>&1; then
+        echo 'int'
+        CFLAGS="$CFLAGS -Dsocklen_t=int"
+    else
+        if (
+              $CC $CFLAGS -Dsocklen_t=size_t __conftest.c  -o __conftest || exit 1
+           ) >/dev/null 2>&1; then
+            echo 'size_t'
+            CFLAGS="$CFLAGS -Dsocklen_t=size_t"
+        else
+            echo 'no'
+            echo 'Cannot work out what to use for socklen_t. Help...'
+            rm -f __conftest*
+            exit
+        fi
+    fi
+fi
+rm -f __conftest*
+
+##################################################
+
+echo -n 'Checking for snprintf declaration... '
+cat <<EOF >__conftest.c
+#include <stdio.h>
+int main() {
+    void *x = (void *)snprintf;
+    printf("%lx", (long)x);
+    return 0;
+}
+
+EOF
+if (
+      $CC $CFLAGS  __conftest.c  -o __conftest || exit 1
+   ) >/dev/null 2>&1; then
+    echo 'ok'
+else
+    if (
+          $CC $CFLAGS -D_GNU_SOURCE __conftest.c  -o __conftest || exit 1
+#          ./__conftest || exit 1
+       ) >/dev/null 2>&1; then
+        echo '-D_GNU_SOURCE'
+        CFLAGS="$CFLAGS -D_GNU_SOURCE"
+    else
+        echo 'manual'
+        CFLAGS="$CFLAGS -DDECLARE_SNPRINTF"
+    fi
+fi
+rm -f __conftest*
+
+echo -n 'Checking for snprintf implementation... '
+cat <<EOF >__conftest.c
+#include <stdio.h>
+#include <string.h>
+#ifdef DECLARE_SNPRINTF
+#ifdef __cplusplus
+extern "C"
+#endif /*__cplusplus*/
+int snprintf(char *, int, const char *, ...);
+#endif /*DECLARE_SNPRINTF*/
+int main() {
+    char buf[32];
+    snprintf(buf, 8, "%s", "1234567890");
+    if (strlen(buf)!=7) return 1;
+    return 0;
+}
+
+EOF
+if (
+      $CC $CFLAGS  __conftest.c $LIBBSD -o __conftest || exit 1
+#      ./__conftest || exit 1
+   ) >/dev/null 2>&1; then
+    echo 'ok'
+else
+    if (
+          $CC $CFLAGS  __conftest.c -lsnprintf $LIBBSD -o __conftest || exit 1
+#          ./__conftest || exit 1
+       ) >/dev/null 2>&1; then
+        echo '-lsnprintf'
+        LIBS="$LIBS -lsnprintf"
+    else
+        if (
+              $CC $CFLAGS  __conftest.c -ldb $LIBBSD -o __conftest || exit 1
+#              ./__conftest || exit 1
+           ) >/dev/null 2>&1; then
+            echo '-ldb'
+            LIBS="$LIBS -ldb"
+        else
+            echo 'missing'
+            echo 'This package requires snprintf.'
+            rm -f __conftest*
+            exit
+        fi
+    fi
+fi
+rm -f __conftest*
+
+##################################################
+
+## libbsd should go last in case it's broken
+if [ "x$LIBBSD" != x ]; then
+    LIBS="$LIBS $LIBBSD"
+fi
+
+echo 'Generating MCONFIG...'
+(
+    echo -n '# Generated by configure (confgen version 2) on '
+    date
+    echo '#'
+    echo
+
+    echo "BINDIR=$BINDIR"
+    echo "MANDIR=$MANDIR"
+    echo "BINMODE=$BINMODE"
+    echo "MANMODE=$MANMODE"
+    echo "PREFIX=$PREFIX"
+    echo "EXECPREFIX=$EXECPREFIX"
+    echo "INSTALLROOT=$INSTALLROOT"
+    echo "CC=$CC"
+    if [ x$CC_WARNINGS != x ]; then
+        CFLAGS="$CFLAGS $WARNINGS"
+    fi
+
+    echo "CFLAGS=$CFLAGS" | sed 's/= */=/'
+    echo "LDFLAGS=$LDFLAGS" | sed 's/= */=/'
+    echo "LIBS=$LIBS" | sed 's/= */=/'
+
+    echo "LIBTERMCAP=$LIBTERMCAP"
+    echo "USE_GLIBC=$USE_GLIBC"
+    echo "USE_READLINE=$USE_READLINE"
+) > MCONFIG
+

Property changes on: netkit-ftp-0.17-new/configure
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: netkit-ftp-0.17-new/ftp/Makefile
===================================================================
--- netkit-ftp-0.17-new/ftp/Makefile	(nonexistent)
+++ netkit-ftp-0.17-new/ftp/Makefile	(revision 5)
@@ -0,0 +1,30 @@
+all: ftp
+
+include ../MCONFIG
+include ../MRULES
+
+ifeq ($(USE_READLINE),1)
+CFLAGS += -D__USE_READLINE__
+LIBS += -lreadline $(LIBTERMCAP)
+endif
+
+ftp: cmds.o cmdtab.o domacro.o ftp.o glob.o main.o ruserpass.o
+	$(CC) $(LDFLAGS) $^ $(LIBS) -o $@
+
+domacro.o ftp.o glob.o main.o ruserpass.o: ftp_var.h pathnames.h
+cmds.o cmdtab.o: ftp_var.h pathnames.h cmds.h
+cmds.o glob.o: glob.h
+
+install: ftp
+	install -p -d $(INSTALLROOT)$(BINDIR)
+	install -p -m$(BINMODE) ftp $(INSTALLROOT)$(BINDIR)
+	ln -sf ftp $(INSTALLROOT)$(BINDIR)/pftp
+	install -p -d $(INSTALLROOT)$(MANDIR)/man1
+	install -p -m$(MANMODE) ftp.1 $(INSTALLROOT)$(MANDIR)/man1
+	ln -sf ftp.1 $(INSTALLROOT)$(MANDIR)/man1/pftp.1
+	install -p -d $(INSTALLROOT)$(MANDIR)/man5
+	install -p -m$(MANMODE) netrc.5 $(INSTALLROOT)$(MANDIR)/man5
+
+clean:
+	rm -f *.o ftp
+
Index: netkit-ftp-0.17-new/ftp/cmds.c
===================================================================
--- netkit-ftp-0.17-new/ftp/cmds.c	(nonexistent)
+++ netkit-ftp-0.17-new/ftp/cmds.c	(revision 5)
@@ -0,0 +1,2380 @@
+/* $USAGI$ */
+
+/*
+ * Copyright (c) 1985, 1989 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.
+ */
+
+/*
+ * from: @(#)cmds.c	5.26 (Berkeley) 3/5/91
+ */
+char cmds_rcsid[] = 
+   "$Id: cmds.c,v 1.3 2001/01/12 21:36:27 sekiya Exp $";
+
+/*
+ * FTP User Program -- Command Routines.
+ */
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <arpa/ftp.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <limits.h>	/* for PATH_MAX */
+#include <time.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef __USE_READLINE__
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+
+#include "ftp_var.h"
+#include "pathnames.h"
+#include "cmds.h"
+#include "glob.h"
+
+void intr(int);
+
+extern FILE *cout;
+extern int data;
+extern const char *home;
+extern off_t restart_point;
+extern char reply_string[];
+
+static char *mname;
+static sigjmp_buf jabort;
+static sigjmp_buf abortprox;
+
+static char *remglob(char *argv[], int doswitch);
+static int checkglob(int fd, const char *pattern);
+static char *dotrans(char *name);
+static char *domap(char *name);
+static char *globulize(char *str);
+static int confirm(const char *cmd, const char *file);
+static int getit(int argc, char *argv[], int restartit, const char *modestr);
+static void quote1(const char *initial, int argc, char **argv);
+
+
+/*
+ * pipeprotect: protect against "special" local filenames by prepending
+ * "./". Special local filenames are "-" and "|..." AND "/...".
+ */
+static char *pipeprotect(char *name) 
+{
+	char *nu;
+	if (strcmp(name, "-") && *name!='|' && *name!='/') {
+		return name;
+	}
+
+	/* We're going to leak this memory. XXX. */
+	nu = malloc(strlen(name)+3);
+	if (nu==NULL) {
+		perror("malloc");
+		code = -1;
+		return NULL;
+	}
+	strcpy(nu, ".");
+	if (*name != '/') strcat(nu, "/");
+	strcat(nu, name);
+	return nu;
+}
+
+/*
+ * Look for embedded ".." in a pathname and change it to "!!", printing
+ * a warning.
+ */
+static char *pathprotect(char *name)
+{
+	int gotdots=0, i, len;
+	
+	/* Convert null terminator to trailing / to catch a trailing ".." */
+	len = strlen(name)+1;
+	name[len-1] = '/';
+
+	/*
+	 * State machine loop. gotdots is < 0 if not looking at dots,
+	 * 0 if we just saw a / and thus might start getting dots,
+	 * and the count of dots seen so far if we have seen some.
+	 */
+	for (i=0; i<len; i++) {
+		if (name[i]=='.' && gotdots>=0) gotdots++;
+		else if (name[i]=='/' && gotdots<0) gotdots=0;
+		else if (name[i]=='/' && gotdots==2) {
+		    fprintf(stderr, "Warning: embedded .. in %.*s (changing to !!)\n",
+			   len-1, name);
+		    name[i-1] = '!';
+		    name[i-2] = '!';
+		    gotdots = 0;
+		}
+		else if (name[i]=='/') gotdots = 0;
+		else gotdots = -1;
+	}
+	name[len-1] = 0;
+	return name;
+}
+
+
+/*
+ * `Another' gets another argument, and stores the new argc and argv.
+ * It reverts to the top level (via main.c's intr()) on EOF/error.
+ *
+ * Returns false if no new arguments have been added.
+ */
+int
+another(int *pargc, char ***pargv, const char *prompt)
+{
+	int margc;
+	char **margv;
+
+	unsigned len = strlen(line);
+	int ret;
+
+	if (len >= sizeof(line) - 3) {
+		fprintf(stderr, "sorry, arguments too long\n");
+		intr(0);
+	}
+	printf("(%s) ", prompt);
+	line[len++] = ' ';
+	if (fgets(&line[len], sizeof(line) - len, stdin) == NULL)
+		intr(0);
+	len += strlen(&line[len]);
+	if (len > 0 && line[len - 1] == '\n')
+		line[len - 1] = '\0';
+	margv = makeargv(&margc, NULL);
+	ret = margc > *pargc;
+	*pargc = margc;
+	*pargv = margv;
+	return ret;
+}
+
+/*
+ * Connect to peer server and
+ * auto-login, if possible.
+ */
+void
+setpeer(int argc, char *argv[])
+{
+	char *host;
+	char *port;
+
+	if (connected) {
+		fprintf(stderr, "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) {
+		printf("usage: %s host-name [port]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	port = NULL;
+	if (argc > 2) {
+		port = argv[2];
+	}
+	host = hookup(argv[1], port);
+	if (host) {
+		int overbose;
+
+		connected = 1;
+		try_epsv = 1;
+		try_eprt = 1;
+		/*
+		 * Set up defaults for FTP.
+		 */
+		(void) strcpy(typename, "ascii"), type = TYPE_A;
+		curtype = TYPE_A;
+		(void) strcpy(formname, "non-print"), form = FORM_N;
+		(void) strcpy(modename, "stream"), mode = MODE_S;
+		(void) strcpy(structname, "file"), stru = STRU_F;
+		(void) strcpy(bytename, "8"), bytesize = 8;
+		if (autologin)
+			(void) dologin(argv[1]);
+
+#if defined(__unix__) && CHAR_BIT == 8
+/*
+ * this ifdef is to keep someone form "porting" this to an incompatible
+ * system and not checking this out. This way they have to think about it.
+ */
+		overbose = verbose;
+		if (debug == 0)
+			verbose = -1;
+		if (command("SYST") == COMPLETE && overbose) {
+			register char *cp, c = 0;
+			cp = index(reply_string+4, ' ');
+			if (cp == NULL)
+				cp = index(reply_string+4, '\r');
+			if (cp) {
+				if (cp[-1] == '.')
+					cp--;
+				c = *cp;
+				*cp = '\0';
+			}
+
+			printf("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) strcpy(typename, "binary");
+			if (overbose)
+			    printf("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))
+				fprintf(stderr, 
+"Remember to set tenex mode when transfering binary files from this machine.\n");
+		}
+		verbose = overbose;
+#else
+#warning "Unix auto-mode code skipped"
+#endif /* unix */
+	}
+}
+
+struct	types {
+	const char *t_name;
+	const char *t_mode;
+	int t_type;
+	const char *t_arg;
+} types[] = {
+	{ "ascii",	"A",	TYPE_A,	NULL },
+	{ "binary",	"I",	TYPE_I,	NULL },
+	{ "image",	"I",	TYPE_I,	NULL },
+	{ "ebcdic",	"E",	TYPE_E,	NULL },
+	{ "tenex",	"L",	TYPE_L,	bytename },
+	{ NULL, NULL, 0, NULL }
+};
+
+/*
+ * Set transfer type.
+ */
+static 
+void
+do_settype(const char *thetype) 
+{
+	struct types *p;
+	int comret;
+
+	for (p = types; p->t_name; p++)
+		if (strcmp(thetype, p->t_name) == 0)
+			break;
+	if (p->t_name == 0) {
+		fprintf(stderr, "%s: unknown mode\n", thetype);
+		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) strcpy(typename, p->t_name);
+		curtype = type = p->t_type;
+	}
+}
+
+void
+settype(int argc, char *argv[])
+{
+	struct types *p;
+	if (argc > 2) {
+		const char *sep;
+
+		printf("usage: %s [", argv[0]);
+		sep = " ";
+		for (p = types; p->t_name; p++) {
+			printf("%s%s", sep, p->t_name);
+			sep = " | ";
+		}
+		printf(" ]\n");
+		code = -1;
+		return;
+	}
+	if (argc < 2) {
+		printf("Using %s mode to transfer files.\n", typename);
+		code = 0;
+		return;
+	}
+	do_settype(argv[1]);
+}
+
+/*
+ * 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)
+{
+	register struct types *p;
+	int comret, oldverbose = verbose;
+	int oldtick = tick;
+
+	if (newtype == 0)
+		newtype = TYPE_I;
+	if (newtype == curtype)
+		return;
+	if (debug == 0 && show == 0)
+		verbose = 0;
+	tick = 0;
+	for (p = types; p->t_name; p++)
+		if (newtype == p->t_type)
+			break;
+	if (p->t_name == 0) {
+		fprintf(stderr, "ftp: internal error: unknown type %d\n", 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;
+	tick = oldtick;
+}
+
+/*
+ * Set binary transfer type.
+ */
+/*VARARGS*/
+void
+setbinary(void)
+{
+	do_settype("binary");
+}
+
+/*
+ * Set ascii transfer type.
+ */
+/*VARARGS*/
+void
+setascii(void)
+{
+	do_settype("ascii");
+}
+
+/*
+ * Set tenex transfer type.
+ */
+/*VARARGS*/
+void
+settenex(void)
+{
+	do_settype("tenex");
+}
+
+/*
+ * Set file transfer mode.
+ */
+/*ARGSUSED*/
+void
+setmode(void)
+{
+	fprintf(stderr, "We only support %s mode, sorry.\n", modename);
+	code = -1;
+}
+
+/*
+ * Set file transfer format.
+ */
+/*ARGSUSED*/
+void
+setform(void)
+{
+	fprintf(stderr, "We only support %s format, sorry.\n", formname);
+	code = -1;
+}
+
+/*
+ * Set file transfer structure.
+ */
+void
+setstruct(void)
+{
+	fprintf(stderr, "We only support %s structure, sorry.\n", structname);
+	code = -1;
+}
+
+/*
+ * Send a single file.
+ */
+void
+put(int argc, char *argv[])
+{
+	const char *cmd;
+	int loc = 0;
+	char *oldargv1, *oldargv2;
+
+	if (argc == 2) {
+		argc++;
+		argv[2] = argv[1];
+		loc++;
+	}
+	if (argc < 2 && !another(&argc, &argv, "local-file"))
+		goto usage;
+	if (argc < 3 && !another(&argc, &argv, "remote-file")) {
+usage:
+		printf("usage: %s local-file remote-file\n", argv[0]);
+		code = -1;
+		return;
+	}
+	oldargv1 = argv[1];
+	oldargv2 = argv[2];
+	argv[1] = globulize(argv[1]);
+	if (!argv[1]) {
+		code = -1;
+		return;
+	}
+	/*
+	 * If "globulize" modifies argv[1], and argv[2] is a copy of
+	 * the old argv[1], make it a copy of the new argv[1].
+	 */
+	if (argv[1] != oldargv1 && argv[2] == oldargv1) {
+		argv[2] = argv[1];
+	}
+	cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
+	if (loc && ntflag) {
+		argv[2] = dotrans(argv[2]);
+	}
+	if (loc && mapflag) {
+		argv[2] = domap(argv[2]);
+	}
+	sendrequest(cmd, argv[1], argv[2],
+	    argv[1] != oldargv1 || argv[2] != oldargv2);
+	if (argv[1] != oldargv1) {
+		free(argv[1]);
+	}
+}
+
+void mabort(int);
+
+/*
+ * Send multiple files.
+ */
+void
+mput(int argc, char *argv[])
+{
+	register int i;
+	void (*oldintr)(int);
+	int ointer;
+	char *tp;
+
+	if (argc < 2 && !another(&argc, &argv, "local-files")) {
+		printf("usage: %s local-files\n", argv[0]);
+		code = -1;
+		return;
+	}
+	mname = argv[0];
+	mflag = 1;
+	oldintr = signal(SIGINT, mabort);
+	(void) sigsetjmp(jabort, 1);
+	if (proxy) {
+		char *cp, *tp2, tmpbuf[PATH_MAX];
+
+		while ((cp = remglob(argv,0)) != NULL) {
+			if (*cp == 0) {
+				mflag = 0;
+				continue;
+			}
+			if (mflag && confirm(argv[0], cp)) {
+				tp = cp;
+				if (mcase) {
+					while (*tp && !islower(*tp)) {
+						tp++;
+					}
+					if (!*tp) {
+						tp = cp;
+						tp2 = tmpbuf;
+						while ((*tp2 = *tp) != '\0') {
+						     if (isupper(*tp2)) {
+						        *tp2 = 'a' + *tp2 - 'A';
+						     }
+						     tp++;
+						     tp2++;
+						}
+					}
+					tp = tmpbuf;
+				}
+				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;
+				}
+			}
+		}
+		(void) signal(SIGINT, oldintr);
+		mflag = 0;
+		return;
+	}
+	for (i = 1; i < argc; i++) {
+		register char **cpp, **gargs;
+
+		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;
+		}
+		gargs = ftpglob(argv[i]);
+		if (globerr != NULL) {
+			fprintf(stderr, "%s\n", globerr);
+			if (gargs) {
+				blkfree(gargs);
+				free((char *)gargs);
+			}
+			continue;
+		}
+		for (cpp = gargs; cpp && *cpp != NULL; 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;
+				}
+			}
+		}
+		if (gargs != NULL) {
+			blkfree(gargs);
+			free((char *)gargs);
+		}
+	}
+	(void) signal(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.
+ */
+static int
+getit(int argc, char *argv[], int restartit, const char *modestr)
+{
+	int loc = 0;
+	char *oldargv1, *oldargv2;
+
+	if (argc == 2) {
+		argc++;
+		/* 
+		 * Protect the user from accidentally retrieving special
+		 * local names.
+		 */
+		argv[2] = pipeprotect(argv[1]);
+		if (!argv[2]) {
+			code = -1;
+			return 0;
+		}
+		loc++;
+	}
+	if (argc < 2 && !another(&argc, &argv, "remote-file"))
+		goto usage;
+	if (argc < 3 && !another(&argc, &argv, "local-file")) {
+usage:
+		printf("usage: %s remote-file [ local-file ]\n", argv[0]);
+		code = -1;
+		return (0);
+	}
+	oldargv1 = argv[1];
+	oldargv2 = argv[2];
+	argv[2] = globulize(argv[2]);
+	if (!argv[2]) {
+		code = -1;
+		return (0);
+	}
+	if (loc && mcase) {
+		char *tp = argv[1], *tp2, tmpbuf[PATH_MAX];
+
+		while (*tp && !islower(*tp)) {
+			tp++;
+		}
+		if (!*tp) {
+			tp = argv[2];
+			tp2 = tmpbuf;
+			while ((*tp2 = *tp) != '\0') {
+				if (isupper(*tp2)) {
+					*tp2 = 'a' + *tp2 - 'A';
+				}
+				tp++;
+				tp2++;
+			}
+			argv[2] = tmpbuf;
+		}
+	}
+	if (loc && ntflag)
+		argv[2] = dotrans(argv[2]);
+	if (loc && mapflag)
+		argv[2] = domap(argv[2]);
+	if (restartit) {
+		struct stat stbuf;
+		int ret;
+
+		ret = stat(argv[2], &stbuf);
+		if (restartit == 1) {
+			if (ret < 0) {
+				fprintf(stderr, "local: %s: %s\n", argv[2],
+					strerror(errno));
+				return (0);
+			}
+			restart_point = stbuf.st_size;
+		} else {
+			if (ret == 0) {
+				int overbose;
+
+				overbose = verbose;
+				if (debug == 0)
+					verbose = -1;
+				if (command("MDTM %s", argv[1]) == COMPLETE) {
+					int yy, mo, day, hour, min, sec;
+					struct tm *tm;
+					verbose = overbose;
+					sscanf(reply_string,
+					    "%*s %04d%02d%02d%02d%02d%02d",
+					    &yy, &mo, &day, &hour, &min, &sec);
+					tm = gmtime(&stbuf.st_mtime);
+					tm->tm_mon++;
+/* Indentation is misleading, but changes keep small. */
+/* 
+ * I think the indentation and braces are now correct. Whoever put this
+ * in the way it was originally should be prohibited by law.
+ */
+					if (tm->tm_year+1900 > yy)
+					    	return (1);
+					if (tm->tm_year+1900 == yy) {
+					   if (tm->tm_mon > mo)
+					      return (1);
+					   if (tm->tm_mon == mo) {
+					      if (tm->tm_mday > day)
+						 return (1);
+					      if (tm->tm_mday == day) {
+						 if (tm->tm_hour > hour)
+							return (1);
+						 if (tm->tm_hour == hour) {
+						    if (tm->tm_min > min)
+						       return (1);
+						    if (tm->tm_min == min) {
+						       if (tm->tm_sec > sec)
+							  return (1);
+						    }
+						 }
+					      }
+					   }
+					}
+				} else {
+					printf("%s\n", reply_string);
+					verbose = overbose;
+					return (0);
+				}
+			}
+		}
+	}
+
+	recvrequest("RETR", argv[2], argv[1], modestr,
+		    argv[1] != oldargv1 || argv[2] != oldargv2);
+	(void) close(data), data = -1;
+	restart_point = 0;
+	return (0);
+}
+
+void
+mabort(int ignore)
+{
+	int ointer;
+
+	(void)ignore;
+
+	printf("\n");
+	(void) fflush(stdout);
+	if (mflag && fromatty) {
+		ointer = interactive;
+		interactive = 1;
+		if (confirm("Continue with", mname)) {
+			interactive = ointer;
+			siglongjmp(jabort,0);
+		}
+		interactive = ointer;
+	}
+	mflag = 0;
+	siglongjmp(jabort,0);
+}
+
+/*
+ * Get multiple files.
+ */
+void
+mget(int argc, char **argv)
+{
+	void (*oldintr)(int);
+	int ointer;
+	char *cp, *tp, *tp2, tmpbuf[PATH_MAX];
+
+	if (argc < 2 && !another(&argc, &argv, "remote-files")) {
+		printf("usage: %s remote-files\n", argv[0]);
+		code = -1;
+		return;
+	}
+	mname = argv[0];
+	mflag = 1;
+	oldintr = signal(SIGINT,mabort);
+	(void) sigsetjmp(jabort, 1);
+	while ((cp = remglob(argv,proxy)) != NULL) {
+		if (*cp == '\0') {
+			mflag = 0;
+			continue;
+		}
+		if (mflag && confirm(argv[0], cp)) {
+			tp = cp;
+			if (mcase) {
+				while (*tp && !islower(*tp)) {
+					tp++;
+				}
+				if (!*tp) {
+					tp = cp;
+					tp2 = tmpbuf;
+					while ((*tp2 = *tp) != '\0') {
+						if (isupper(*tp2)) {
+							*tp2 = 'a' + *tp2 - 'A';
+						}
+						tp++;
+						tp2++;
+					}
+					tp = tmpbuf;
+				}
+				else {
+					tp = cp;
+				}
+			}
+			if (ntflag) {
+				tp = dotrans(tp);
+			}
+			if (mapflag) {
+				tp = domap(tp);
+			}
+			/* Reject embedded ".." */
+			tp = pathprotect(tp);
+
+			/* Prepend ./ to "-" or "!*" or leading "/" */
+			tp = pipeprotect(tp);
+			if (tp == NULL) {
+				/* hmm... how best to handle this? */
+				mflag = 0;
+			}
+			else {
+				recvrequest("RETR", tp, cp, "w",
+					    tp != cp || !interactive);
+			}
+			if (!mflag && fromatty) {
+				ointer = interactive;
+				interactive = 1;
+				if (confirm("Continue with","mget")) {
+					mflag++;
+				}
+				interactive = ointer;
+			}
+		}
+	}
+	(void) signal(SIGINT,oldintr);
+	mflag = 0;
+}
+
+char *
+remglob(char *argv[], int doswitch)
+{
+	char temp[16];
+	static char buf[PATH_MAX];
+	static FILE *ftemp = NULL;
+	static char **args;
+	int oldverbose, oldhash, badglob = 0;
+	char *cp;
+
+	if (!mflag) {
+		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) {
+		int oldumask, fd;
+		(void) strcpy(temp, _PATH_TMP);
+
+		/* libc 5.2.18 creates with mode 0666, which is dumb */
+		oldumask = umask(077);
+		fd = mkstemp(temp);
+		umask(oldumask);
+
+		if (fd<0) {
+			fprintf(stderr, "Error creating temporary file, oops\n");
+			return NULL;
+		}
+		
+		oldverbose = verbose, verbose = 0;
+		oldhash = hash, hash = 0;
+		if (doswitch) {
+			pswitch(!proxy);
+		}
+		while (*++argv != NULL) {
+			int	dupfd = dup(fd);
+
+			recvrequest ("NLST", temp, *argv, "a", 0);
+			if (!checkglob(dupfd, *argv)) {
+				badglob = 1;
+				break;
+			}
+		}
+		unlink(temp);
+
+		if (doswitch) {
+			pswitch(!proxy);
+		}
+		verbose = oldverbose; hash = oldhash;
+		if (badglob) {
+			fprintf(stderr, "Refusing to handle insecure file list\n");
+			close(fd);
+			return NULL;
+		}
+		ftemp = fdopen(fd, "r");
+		if (ftemp == NULL) {
+			fprintf(stderr, "fdopen failed, oops\n");
+			return NULL;
+		}
+		rewind(ftemp);
+	}
+	if (fgets(buf, sizeof (buf), ftemp) == NULL) {
+		(void) fclose(ftemp), ftemp = NULL;
+		return (NULL);
+	}
+	if ((cp = index(buf, '\n')) != NULL)
+		*cp = '\0';
+	return (buf);
+}
+
+/*
+ * Check whether given pattern matches `..'
+ * We assume only a glob pattern starting with a dot will match
+ * dot entries on the server.
+ */
+static int
+isdotdotglob(const char *pattern)
+{
+	int	havedot = 0;
+	char	c;
+
+	if (*pattern++ != '.')
+		return 0;
+	while ((c = *pattern++) != '\0' && c != '/') {
+		if (c == '*' || c == '?')
+			continue;
+		if (c == '.' && havedot++)
+			return 0;
+	}
+	return 1;
+}
+
+/*
+ * This function makes sure the list of globbed files returned from
+ * the server doesn't contain anything dangerous such as
+ * /home/<yourname>/.forward, or ../.forward,
+ * or |mail foe@doe </etc/passwd, etc.
+ * Covered areas:
+ *  -	returned name starts with / but glob pattern doesn't
+ *  -	glob pattern starts with / but returned name doesn't
+ *  -	returned name starts with |
+ *  -	returned name contains .. in a position where glob
+ *	pattern doesn't match ..
+ *	I.e. foo/.* allows foo/../bar but not foo/.bar/../fly
+ *
+ * Note that globbed names starting with / should really be stored
+ * under the current working directory; this is handled in mget above.
+ *						--okir
+ */
+static int
+checkglob(int fd, const char *pattern)
+{
+	const char	*sp;
+	char		buffer[MAXPATHLEN], dotdot[MAXPATHLEN];
+	int		okay = 1, nrslash, initial, nr;
+	FILE		*fp;
+
+	/* Find slashes in glob pattern, and verify whether component
+	 * matches `..'
+	 */
+	initial = (pattern[0] == '/');
+	for (sp = pattern, nrslash = 0; sp != 0; sp = strchr(sp, '/')) {
+		while (*sp == '/')
+			sp++;
+		if (nrslash >= MAXPATHLEN) {
+			fprintf(stderr, "Incredible pattern: %s\n", pattern);
+			return 0;
+		}
+		dotdot[nrslash++] = isdotdotglob(sp);
+	}
+
+	fp = fdopen(fd, "r");
+	while (okay && fgets(buffer, sizeof(buffer), fp) != NULL) {
+		char	*sp;
+
+		if ((sp = strchr(buffer, '\n')) != 0) {
+			*sp = '\0';
+		} else {
+			fprintf(stderr, "Extremely long filename from server: %s",
+				buffer);
+			okay = 0;
+			break;
+		}
+		if (buffer[0] == '|'
+		 || (buffer[0] != '/' && initial)
+		 || (buffer[0] == '/' && !initial))
+			okay = 0;
+		for (sp = buffer, nr = 0; sp; sp = strchr(sp, '/'), nr++) {
+			while (*sp == '/')
+				sp++;
+			if (sp[0] == '.' && !strncmp(sp, "../", 3)
+			 && (nr >= nrslash || !dotdot[nr]))
+				okay = 0;
+		}
+	}
+
+	if (!okay)
+		fprintf(stderr, "Filename provided by server "
+		       "doesn't match pattern `%s': %s\n", pattern, buffer);
+
+	fclose(fp);
+	return okay;
+}
+
+static const char *
+onoff(int bool)
+{
+	return (bool ? "on" : "off");
+}
+
+/*
+ * Show status.
+ */
+void
+status(void)
+{
+	int i;
+	if (connected) 
+		printf("Connected to %s.\n", hostname);
+	else 
+		fprintf(stderr, "Not connected.\n");
+	if (!proxy) {
+		pswitch(1);
+		if (connected) {
+			printf("Connected for proxy commands to %s.\n", hostname);
+		}
+		else {
+			fprintf(stderr, "No proxy connection.\n");
+		}
+		pswitch(0);
+	}
+	printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
+		modename, typename, formname, structname);
+	printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 
+		onoff(verbose), onoff(bell), onoff(interactive),
+		onoff(doglob));
+	printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
+		onoff(runique));
+	printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
+	if (ntflag) {
+		printf("Ntrans: (in) %s (out) %s\n",ntin,ntout);
+	}
+	else {
+		printf("Ntrans: off\n");
+	}
+	if (mapflag) {
+		printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
+	}
+	else {
+		printf("Nmap: off\n");
+	}
+	printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
+		onoff(hash), onoff(sendport));
+	printf("Tick counter printing: %s\n", onoff(tick));
+	if (macnum > 0) {
+		printf("Macros:\n");
+		for (i=0; i<macnum; i++) {
+			printf("\t%s\n",macros[i].mac_name);
+		}
+	}
+	code = 0;
+}
+
+/*
+ * Set beep on cmd completed mode.
+ */
+void
+setbell(void)
+{
+
+	bell = !bell;
+	printf("Bell mode %s.\n", onoff(bell));
+	code = bell;
+}
+
+/*
+ * Turn on packet tracing.
+ */
+void
+settrace(void)
+{
+	traceflag = !traceflag;
+	printf("Packet tracing %s.\n", onoff(traceflag));
+	code = traceflag;
+}
+
+/*
+ * Toggle hash mark printing during transfers.
+ */
+void
+sethash(void)
+{
+	hash = !hash;
+	if (hash && tick)
+		settick();
+ 
+	printf("Hash mark printing %s", onoff(hash));
+	code = hash;
+	if (hash)
+		printf(" (%d bytes/hash mark)", 1024);
+	printf(".\n");
+}
+
+/*
+ * Toggle tick counter printing during transfers.
+ */
+void
+settick(void)
+{
+	tick = !tick;
+	if (hash && tick)
+		sethash();
+	printf("Tick counter printing %s", onoff(tick));
+	code = tick;
+	if (tick)
+		printf(" (%d bytes/tick increment)", TICKBYTES);
+	printf(".\n");
+}
+
+/*
+ * Turn on printing of server echos.
+ */
+void
+setverbose(void)
+{
+	verbose = !verbose;
+	printf("Verbose mode %s.\n", onoff(verbose));
+	code = verbose;
+}
+
+/*
+ * Toggle PORT cmd use before each data connection.
+ */
+void
+setport(void)
+{
+	sendport = !sendport;
+	printf("Use of PORT cmds %s.\n", onoff(sendport));
+	code = sendport;
+}
+
+/*
+ * Turn on interactive prompting
+ * during mget, mput, and mdelete.
+ */
+void
+setprompt(void)
+{
+	interactive = !interactive;
+	printf("Interactive mode %s.\n", onoff(interactive));
+	code = interactive;
+}
+
+/*
+ * Toggle metacharacter interpretation
+ * on local file names.
+ */
+void
+setglob(void)
+{
+	doglob = !doglob;
+	printf("Globbing %s.\n", onoff(doglob));
+	code = doglob;
+}
+
+/*
+ * Set debugging mode on/off and/or
+ * set level of debugging.
+ */
+void
+setdebug(int argc, char *argv[])
+{
+	int val;
+
+	if (argc > 1) {
+		val = atoi(argv[1]);
+		if (val < 0) {
+			fprintf(stderr, "%s: bad debugging value.\n", argv[1]);
+			code = -1;
+			return;
+		}
+	} else
+		val = !debug;
+	debug = val;
+	if (debug)
+		options |= SO_DEBUG;
+	else
+		options &= ~SO_DEBUG;
+	printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
+	code = debug > 0;
+}
+
+/*
+ * Set current working directory
+ * on remote machine.
+ */
+void
+cd(int argc, char *argv[])
+{
+
+	if (argc < 2 && !another(&argc, &argv, "remote-directory")) {
+		printf("usage: %s remote-directory\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (command("CWD %s", argv[1]) == ERROR && code == 500) {
+		if (verbose)
+			fprintf(stderr, "CWD command not recognized, trying XCWD\n");
+		(void) command("XCWD %s", argv[1]);
+	}
+}
+
+/*
+ * Set current working directory
+ * on local machine.
+ */
+void
+lcd(int argc, char *argv[])
+{
+	char buf[PATH_MAX];
+	const char *dir = NULL;
+
+	if (argc == 1) {
+	    /*dir = home;*/
+	    dir = ".";
+	}
+	else if (argc != 2) {
+		printf("usage: %s local-directory\n", argv[0]);
+		code = -1;
+		return;
+	}
+	else {
+	    dir = globulize(argv[1]);
+	}
+	if (!dir) {
+		code = -1;
+		return;
+	}
+	if (chdir(dir) < 0) {
+		fprintf(stderr, "local: %s: %s\n", dir, strerror(errno));
+		code = -1;
+		return;
+	}
+	if (!getcwd(buf, sizeof(buf))) {
+	    if (errno==ERANGE) strcpy(buf, "<too long>");
+	    else strcpy(buf, "???");
+	}
+	printf("Local directory now %s\n", buf);
+	code = 0;
+}
+
+/*
+ * Delete a single file.
+ */
+void
+delete_cmd(int argc, char *argv[])
+{
+
+	if (argc < 2 && !another(&argc, &argv, "remote-file")) {
+		printf("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[])
+{
+	void (*oldintr)(int);
+	int ointer;
+	char *cp;
+
+	if (argc < 2 && !another(&argc, &argv, "remote-files")) {
+		printf("usage: %s remote-files\n", argv[0]);
+		code = -1;
+		return;
+	}
+	mname = argv[0];
+	mflag = 1;
+	oldintr = signal(SIGINT, mabort);
+	(void) sigsetjmp(jabort, 1);
+	while ((cp = remglob(argv,0)) != 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) signal(SIGINT, oldintr);
+	mflag = 0;
+}
+
+/*
+ * Rename a remote file.
+ */
+void
+renamefile(int argc, char *argv[])
+{
+
+	if (argc < 2 && !another(&argc, &argv, "from-name"))
+		goto usage;
+	if (argc < 3 && !another(&argc, &argv, "to-name")) {
+usage:
+		printf("%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.
+ */
+void
+ls(int argc, char *argv[])
+{
+	static char foo[2] = "-";
+	const char *cmd;
+
+	if (argc < 2) {
+		argc++, argv[1] = NULL;
+	}
+	if (argc < 3) {
+		argc++, argv[2] = foo;
+	}
+	if (argc > 3) {
+		printf("usage: %s remote-directory local-file\n", argv[0]);
+		code = -1;
+		return;
+	}
+	cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
+	if (strcmp(argv[2], "-") && (argv[2] = globulize(argv[2]))==NULL) {
+		code = -1;
+		return;
+	}
+	if (strcmp(argv[2], "-") && *argv[2] != '|')
+		if ((argv[2] = globulize(argv[2]))==NULL || 
+		    !confirm("output to local-file:", argv[2])) {
+			code = -1;
+			return;
+	}
+	recvrequest(cmd, argv[2], argv[1], "w", 0);
+}
+
+/*
+ * Get a directory listing
+ * of multiple remote files.
+ */
+void
+mls(int argc, char *argv[])
+{
+	void (*oldintr)(int);
+	int ointer, i;
+	const char *volatile cmd;
+	char *volatile dest;
+	const char *modestr;
+
+	if (argc < 2 && !another(&argc, &argv, "remote-files"))
+		goto usage;
+	if (argc < 3 && !another(&argc, &argv, "local-file")) {
+usage:
+		printf("usage: %s remote-files local-file\n", argv[0]);
+		code = -1;
+		return;
+	}
+	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;
+	}
+	cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
+	mname = argv[0];
+	mflag = 1;
+	oldintr = signal(SIGINT, mabort);
+
+	/*
+	 * This just plain seems wrong.
+	 */
+	(void) sigsetjmp(jabort, 1);
+
+	for (i = 1; mflag && i < argc-1; ++i) {
+		modestr = (i == 1) ? "w" : "a";
+		recvrequest(cmd, dest, argv[i], modestr, 0);
+		if (!mflag && fromatty) {
+			ointer = interactive;
+			interactive = 1;
+			if (confirm("Continue with", argv[0])) {
+				mflag ++;
+			}
+			interactive = ointer;
+		}
+	}
+	(void) signal(SIGINT, oldintr);
+	mflag = 0;
+}
+
+/*
+ * Do a shell escape
+ */
+void
+shell(const char *arg)
+{
+	int pid;
+	void (*old1)(int);
+	void (*old2)(int);
+	char shellnam[40];
+	const char *theshell, *namep; 
+
+	old1 = signal (SIGINT, SIG_IGN);
+	old2 = signal (SIGQUIT, SIG_IGN);
+	if ((pid = fork()) == 0) {
+		for (pid = 3; pid < 20; pid++)
+			(void) close(pid);
+		(void) signal(SIGINT, SIG_DFL);
+		(void) signal(SIGQUIT, SIG_DFL);
+		theshell = getenv("SHELL");
+		if (theshell == NULL)
+			theshell = _PATH_BSHELL;
+		namep = strrchr(theshell, '/');
+		if (namep == NULL)
+			namep = theshell;
+		else 
+			namep++;
+		(void) strcpy(shellnam,"-");
+		(void) strcat(shellnam, namep);
+		if (strcmp(namep, "sh") != 0)
+			shellnam[0] = '+';
+		if (debug) {
+			printf("%s\n", theshell);
+			(void) fflush (stdout);
+		}
+		if (arg) {
+			execl(theshell, shellnam, "-c", arg, NULL);
+		}
+		else {
+			execl(theshell, shellnam, NULL);
+		}
+		perror(theshell);
+		code = -1;
+		exit(1);
+	}
+	if (pid > 0) while (wait(NULL) != pid);
+
+	(void) signal(SIGINT, old1);
+	(void) signal(SIGQUIT, old2);
+	if (pid == -1) {
+		perror("Try again later");
+		code = -1;
+	}
+	else {
+		code = 0;
+	}
+}
+
+/*
+ * Send new user information (re-login)
+ */
+void
+user(int argc, char *argv[])
+{
+	char theacct[80];
+	int n, aflag = 0;
+
+	if (argc < 2)
+		(void) another(&argc, &argv, "username");
+	if (argc < 2 || argc > 4) {
+		printf("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) {
+			printf("Account: "); (void) fflush(stdout);
+			fgets(theacct, sizeof(theacct), stdin);
+			argv[3] = theacct; argc++;
+		}
+		n = command("ACCT %s", argv[3]);
+		aflag++;
+	}
+	if (n != COMPLETE) {
+		fprintf(stderr, "Login failed.\n");
+		return;
+	}
+	if (!aflag && argc == 4) {
+		(void) command("ACCT %s", argv[3]);
+	}
+}
+
+/*
+ * Print working directory.
+ */
+void
+pwd(void)
+{
+	int oldverbose = verbose;
+
+	/*
+	 * If we aren't verbose, this doesn't do anything!
+	 */
+	verbose = 1;
+	if (command("PWD") == ERROR && code == 500) {
+		fprintf(stderr, "PWD command not recognized, trying XPWD\n");
+		(void) command("XPWD");
+	}
+	verbose = oldverbose;
+}
+
+/*
+ * Make a directory.
+ */
+void
+makedir(int argc, char *argv[])
+{
+
+	if (argc < 2 && !another(&argc, &argv, "directory-name")) {
+		printf("usage: %s directory-name\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (command("MKD %s", argv[1]) == ERROR && code == 500) {
+		if (verbose)
+			fprintf(stderr, "MKD command not recognized, trying XMKD\n");
+		(void) command("XMKD %s", argv[1]);
+	}
+}
+
+/*
+ * Remove a directory.
+ */
+void
+removedir(int argc, char *argv[])
+{
+
+	if (argc < 2 && !another(&argc, &argv, "directory-name")) {
+		printf("usage: %s directory-name\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (command("RMD %s", argv[1]) == ERROR && code == 500) {
+		if (verbose)
+			fprintf(stderr, "RMD command not recognized, trying XRMD\n");
+		(void) command("XRMD %s", argv[1]);
+	}
+}
+
+/*
+ * Send a line, verbatim, to the remote machine.
+ */
+void
+quote(int argc, char *argv[])
+{
+	if (argc < 2 && !another(&argc, &argv, "command line to send")) {
+		printf("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 < 2 && !another(&argc, &argv, "arguments to SITE command")) {
+		printf("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.
+ */
+static void
+quote1(const char *initial, int argc, char **argv)
+{
+	register int i, len;
+	char buf[BUFSIZ];		/* must be >= sizeof(line) */
+
+	if (strncmp(argv[1],"size",4) == 0)
+	    changetype(TYPE_I, 1);
+	(void) strcpy(buf, initial);
+	if (argc > 1) {
+		len = strlen(buf);
+		len += strlen(strcpy(&buf[len], argv[1]));
+		for (i = 2; i < argc; i++) {
+			buf[len++] = ' ';
+			len += strlen(strcpy(&buf[len], argv[i]));
+		}
+	}
+	if (command("%s", buf) == PRELIM) {
+		while (getreply(0) == PRELIM);
+	}
+}
+
+void
+do_chmod(int argc, char *argv[])
+{
+
+	if (argc < 2 && !another(&argc, &argv, "mode"))
+		goto usage;
+	if (argc < 3 && !another(&argc, &argv, "file-name")) {
+usage:
+		printf("usage: %s mode file-name\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;
+
+	verbose = 1;
+	(void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
+	verbose = oldverbose;
+}
+
+void
+idle_cmd(int argc, char *argv[])
+{
+	int oldverbose = verbose;
+
+	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;
+
+	verbose = 1;
+	(void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
+	verbose = oldverbose;
+}
+
+/*
+ * Terminate session and exit.
+ */
+void
+quit(void)
+{
+
+	if (connected)
+		disconnect();
+	pswitch(1);
+	if (connected) {
+		disconnect();
+	}
+	exit(0);
+}
+
+/*
+ * Terminate session, but don't exit.
+ */
+void
+disconnect(void)
+{
+	if (!connected)
+		return;
+	(void) command("QUIT");
+	if (cout) {
+		(void) fclose(cout);
+	}
+	cout = NULL;
+	connected = 0;
+	data = -1;
+	if (!proxy) {
+		macnum = 0;
+	}
+}
+
+static int
+confirm(const char *cmd, const char *file)
+{
+	char lyne[BUFSIZ];
+
+	if (!interactive)
+		return (1);
+
+#ifdef __USE_READLINE__
+	if (fromatty && !rl_inhibit) {
+		char *lineread;
+		snprintf(lyne, BUFSIZ, "%s %s? ", cmd, file);
+		lineread = readline(lyne);
+		if (!lineread) return 0;
+		strcpy(lyne, lineread);
+		free(lineread);
+	}
+	else {
+#endif
+		printf("%s %s? ", cmd, file);
+		fflush(stdout);
+		if (fgets(lyne, sizeof(lyne), stdin) == NULL) {
+		    return 0;
+		}
+#ifdef __USE_READLINE__
+	}
+#endif
+	return (*lyne != 'n' && *lyne != 'N');
+}
+
+void
+fatal(const char *msg)
+{
+
+	fprintf(stderr, "ftp: %s\n", msg);
+	exit(1);
+}
+
+/*
+ * 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.
+ */
+static 
+char *
+globulize(char *cpp)
+{
+	char **globbed;
+	char *rv = cpp;
+
+	if (!doglob) return cpp;
+
+	globbed = ftpglob(cpp);
+	if (globerr != NULL) {
+		printf("%s: %s\n", cpp, globerr);
+		if (globbed) {
+			blkfree(globbed);
+			free(globbed);
+		}
+		return NULL;
+	}
+	if (globbed) {
+		rv = globbed[0];
+		/* don't waste too much memory */
+		if (globbed[0]) {
+			blkfree(globbed+1);
+		}
+		free(globbed);
+	}
+	return rv;
+}
+
+void
+account(int argc, char *argv[])
+{
+	char buf[128], *ap;
+
+	if (argc > 1) {
+		*buf = 0;
+		while (argc > 1) {
+			--argc;
+			++argv;
+			strncat(buf, *argv, sizeof(buf)-strlen(buf)-1);
+		}
+		ap = buf;
+	}
+	else {
+		ap = getpass("Account:");
+	}
+	command("ACCT %s", ap);
+}
+
+static 
+void
+proxabort(int ignore)
+{
+	(void)ignore;
+
+	if (!proxy) {
+		pswitch(1);
+	}
+	if (connected) {
+		proxflag = 1;
+	}
+	else {
+		proxflag = 0;
+	}
+	pswitch(0);
+	siglongjmp(abortprox,1);
+}
+
+void
+doproxy(int argc, char *argv[])
+{
+	register struct cmd *c;
+	void (*oldintr)(int);
+
+	if (argc < 2 && !another(&argc, &argv, "command")) {
+		printf("usage: %s command\n", argv[0]);
+		code = -1;
+		return;
+	}
+	c = getcmd(argv[1]);
+	if (c == (struct cmd *) -1) {
+		printf("?Ambiguous command\n");
+		(void) fflush(stdout);
+		code = -1;
+		return;
+	}
+	if (c == 0) {
+		printf("?Invalid command\n");
+		(void) fflush(stdout);
+		code = -1;
+		return;
+	}
+	if (!c->c_proxy) {
+		printf("?Invalid proxy command\n");
+		(void) fflush(stdout);
+		code = -1;
+		return;
+	}
+	if (sigsetjmp(abortprox, 1)) {
+		code = -1;
+		return;
+	}
+	oldintr = signal(SIGINT, proxabort);
+	pswitch(1);
+	if (c->c_conn && !connected) {
+		printf("Not connected\n");
+		(void) fflush(stdout);
+		pswitch(0);
+		(void) signal(SIGINT, oldintr);
+		code = -1;
+		return;
+	}
+
+	if (c->c_handler_v) c->c_handler_v(argc-1, argv+1);
+	else if (c->c_handler_0) c->c_handler_0();
+	else c->c_handler_1(NULL);  /* should not reach this */
+
+	if (connected) {
+		proxflag = 1;
+	}
+	else {
+		proxflag = 0;
+	}
+	pswitch(0);
+	(void) signal(SIGINT, oldintr);
+}
+
+void
+setcase(void)
+{
+	mcase = !mcase;
+	printf("Case mapping %s.\n", onoff(mcase));
+	code = mcase;
+}
+
+void
+setcr(void)
+{
+	crflag = !crflag;
+	printf("Carriage Return stripping %s.\n", onoff(crflag));
+	code = crflag;
+}
+
+void
+setntrans(int argc, char *argv[])
+{
+	if (argc == 1) {
+		ntflag = 0;
+		printf("Ntrans off.\n");
+		code = ntflag;
+		return;
+	}
+	ntflag++;
+	code = ntflag;
+	(void) strncpy(ntin, argv[1], NTRANS_MAX);
+	ntin[NTRANS_MAX] = '\0';
+	if (argc == 2) {
+		ntout[0] = '\0';
+		return;
+	}
+	(void) strncpy(ntout, argv[2], NTRANS_MAX);
+ 	ntout[NTRANS_MAX] = '\0';
+}
+
+static char *
+dotrans(char *name)
+{
+	static char new[PATH_MAX];
+	char *cp1, *cp2 = new;
+	register int i, ostop, found;
+
+	for (ostop = 0; *(ntout + ostop) && ostop < NTRANS_MAX; ostop++);
+	for (cp1 = name; *cp1; cp1++) {
+		found = 0;
+		for (i = 0; *(ntin + i) && i < NTRANS_MAX; 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;
+		printf("Nmap off.\n");
+		code = mapflag;
+		return;
+	}
+	if (argc < 3 && !another(&argc, &argv, "mapout")) {
+		printf("Usage: %s [mapin mapout]\n",argv[0]);
+		code = -1;
+		return;
+	}
+	mapflag = 1;
+	code = 1;
+	cp = index(altarg, ' ');
+	if (proxy) {
+		while(*++cp == ' ');
+		altarg = cp;
+		cp = index(altarg, ' ');
+	}
+	*cp = '\0';
+	(void) strncpy(mapin, altarg, PATH_MAX - 1);
+	mapin[PATH_MAX-1] = 0;
+	while (*++cp == ' ');
+	(void) strncpy(mapout, cp, PATH_MAX - 1);
+	mapout[PATH_MAX-1] = 0;
+}
+
+static
+char *
+domap(char *name)
+{
+	static char new[PATH_MAX];
+	register 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)) {
+						toknum = *cp2 - '1';
+						toks[toknum]++;
+						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(*(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(*(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) {
+						printf("nmap: unbalanced brackets\n");
+						return(name);
+					}
+					match = 1;
+					cp2--;
+				}
+				if (match) {
+					while (*++cp2 && *cp2 != ']') {
+					      if (*cp2 == '\\' && *(cp2 + 1)) {
+							cp2++;
+					      }
+					}
+					if (!*cp2) {
+						printf("nmap: unbalanced brackets\n");
+						return(name);
+					}
+					break;
+				}
+				switch (*++cp2) {
+					case ',':
+						goto LOOP;
+					case ']':
+						break;
+					default:
+						cp2--;
+						goto LOOP;
+				}
+				break;
+			case '$':
+				if (isdigit(*(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
+setsunique(void)
+{
+	sunique = !sunique;
+	printf("Store unique %s.\n", onoff(sunique));
+	code = sunique;
+}
+
+void
+setrunique(void)
+{
+	runique = !runique;
+	printf("Receive unique %s.\n", onoff(runique));
+	code = runique;
+}
+
+/* change directory to parent directory */
+void
+cdup(void)
+{
+	if (command("CDUP") == ERROR && code == 500) {
+		if (verbose)
+			fprintf(stderr, "CDUP command not recognized, trying XCUP\n");
+		(void) command("XCUP");
+	}
+}
+
+/* restart transfer at specific point */
+void
+restart(int argc, char *argv[])
+{
+	if (argc != 2)
+		printf("restart: offset not specified\n");
+	else {
+		restart_point = atol(argv[1]);
+		printf("restarting at %ld. %s\n", (long)restart_point,
+		    "execute get, put or append to initiate transfer");
+	}
+}
+
+/* show remote system type */
+void
+syst(void)
+{
+	command("SYST");
+}
+
+void
+macdef(int argc, char *argv[])
+{
+	char *tmp;
+	int c;
+
+	if (macnum == 16) {
+		printf("Limit of 16 macros have already been defined\n");
+		code = -1;
+		return;
+	}
+	if (argc < 2 && !another(&argc, &argv, "macro name")) {
+		printf("Usage: %s macro_name\n",argv[0]);
+		code = -1;
+		return;
+	}
+	if (interactive) {
+		printf("Enter macro line by line, terminating it with a null line\n");
+	}
+	(void) strncpy(macros[macnum].mac_name, argv[1], 8);
+	macros[macnum].mac_name[8] = 0;
+	if (macnum == 0) {
+		macros[macnum].mac_start = macbuf;
+	}
+	else {
+		macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
+	}
+	tmp = macros[macnum].mac_start;
+	/* stepping over the end of the array, remember to take away 1! */
+	while (tmp != macbuf+MACBUF_SIZE) {
+		if ((c = getchar()) == EOF) {
+			printf("macdef:end of file encountered\n");
+			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') {
+			printf("Macro not defined - 4k buffer exceeded\n");
+			code = -1;
+			return;
+		}
+	}
+}
+
+/*
+ * Start up passive mode interaction
+ */
+void
+setpassive(void)
+{
+        passivemode = !passivemode;
+        printf("Passive mode %s.\n", onoff(passivemode));
+        code = passivemode;
+}
+
+/*
+ * get size of file on remote machine
+ */
+void
+sizecmd(int argc, char *argv[])
+{
+
+	if (argc < 2 && !another(&argc, &argv, "filename")) {
+		printf("usage: %s filename\n", argv[0]);
+		code = -1;
+		return;
+	}
+	(void) command("SIZE %s", argv[1]);
+}
+
+/*
+ * get last modification time of file on remote machine
+ */
+void
+modtime(int argc, char *argv[])
+{
+	int overbose;
+
+	if (argc < 2 && !another(&argc, &argv, "filename")) {
+		printf("usage: %s filename\n", argv[0]);
+		code = -1;
+		return;
+	}
+	overbose = verbose;
+	if (debug == 0)
+		verbose = -1;
+	if (command("MDTM %s", argv[1]) == COMPLETE) {
+		int yy, mo, day, hour, min, sec;
+		sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
+			&day, &hour, &min, &sec);
+		/* might want to print this in local time */
+		printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
+			mo, day, yy, hour, min, sec);
+	} else
+		printf("%s\n", reply_string);
+	verbose = overbose;
+}
+
+/*
+ * show status on remote machine
+ */
+void
+rmtstatus(int argc, char *argv[])
+{
+	(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")) {
+		/* This should be controlled by some verbose flag */
+		printf("Local file \"%s\" is newer than remote file \"%s\"\n",
+			argv[2], argv[1]);
+	}
+}
Index: netkit-ftp-0.17-new/ftp/cmdtab.c
===================================================================
--- netkit-ftp-0.17-new/ftp/cmdtab.c	(nonexistent)
+++ netkit-ftp-0.17-new/ftp/cmdtab.c	(revision 5)
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 1985, 1989 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.
+ */
+
+/*
+ * from: @(#)cmdtab.c	5.10 (Berkeley) 6/1/90
+ */
+char cmdtab_rcsid[] = 
+  "$Id: cmdtab.c,v 1.1.1.1 2000/11/03 19:18:15 mk Exp $";
+
+#include <string.h>   /* for NULL */
+#include "ftp_var.h"
+#include "cmds.h"
+
+/*
+ * User FTP -- Command Tables.
+ */
+
+const char accounthelp[] = "send account command to remote server";
+const char appendhelp[] =  "append to a file";
+const char asciihelp[] =   "set ascii transfer type";
+const char beephelp[] =    "beep when command completed";
+const char binaryhelp[] =  "set binary transfer type";
+const char casehelp[] =    "toggle mget upper/lower case id mapping";
+const char cdhelp[] =      "change remote working directory";
+const char cduphelp[] = "change remote working directory to parent directory";
+const char chmodhelp[] =   "change file permissions of remote file";
+const char connecthelp[] = "connect to remote ftp";
+const char crhelp[] =      "toggle carriage return stripping on ascii gets";
+const char deletehelp[] =  "delete remote file";
+const char debughelp[] =   "toggle/set debugging mode";
+const char dirhelp[] =     "list contents of remote directory";
+const char disconhelp[] =  "terminate ftp session";
+const char domachelp[] =   "execute macro";
+const char formhelp[] =	"set file transfer format";
+const char globhelp[] =	"toggle metacharacter expansion of local file names";
+const char hashhelp[] =	"toggle printing `#' for each buffer transferred";
+const char helphelp[] =	"print local help information";
+const char idlehelp[] =	"get (set) idle timer on remote side";
+const char lcdhelp[] =	"change local working directory";
+const char lshelp[] =	"list contents of remote directory";
+const char macdefhelp[] =  "define a macro";
+const char mdeletehelp[] = "delete multiple files";
+const char mdirhelp[] =    "list contents of multiple remote directories";
+const char mgethelp[] =    "get multiple files";
+const char mkdirhelp[] =   "make directory on the remote machine";
+const char mlshelp[] =     "list contents of multiple remote directories";
+const char modtimehelp[] = "show last modification time of remote file";
+const char modehelp[] =    "set file transfer mode";
+const char mputhelp[] =    "send multiple files";
+const char newerhelp[] =   "get file if remote file is newer than local file ";
+const char nlisthelp[] =   "nlist contents of remote directory";
+const char nmaphelp[] =    "set templates for default file name mapping";
+const char ntranshelp[] ="set translation table for default file name mapping";
+const char passivehelp[] = "enter passive transfer mode";
+const char porthelp[] =	   "toggle use of PORT cmd for each data connection";
+const char prompthelp[] =  "force interactive prompting on multiple commands";
+const char proxyhelp[] =   "issue command on alternate connection";
+const char pwdhelp[] =     "print working directory on remote machine";
+const char quithelp[] =    "terminate ftp session and exit";
+const char quotehelp[] =   "send arbitrary ftp command";
+const char receivehelp[] = "receive file";
+const char regethelp[] =   "get file restarting at end of local file";
+const char remotehelp[] =  "get help from remote server";
+const char renamehelp[] =  "rename file";
+const char restarthelp[] = "restart file transfer at bytecount";
+const char rmdirhelp[] =   "remove directory on the remote machine";
+const char rmtstatushelp[]="show status of remote machine";
+const char runiquehelp[] = "toggle store unique for local files";
+const char resethelp[] =   "clear queued command replies";
+const char sendhelp[] =    "send one file";
+const char sitehelp[] =    "send site specific command to remote server\n"
+	    "\t\tTry \"rhelp site\" or \"site help\" for more information";
+const char shellhelp[] =   "escape to the shell";
+const char sizecmdhelp[] = "show size of remote file";
+const char statushelp[] =  "show current status";
+const char structhelp[] =  "set file transfer structure";
+const char suniquehelp[] = "toggle store unique on remote machine";
+const char systemhelp[] =  "show remote system type";
+const char tenexhelp[] =   "set tenex file transfer type";
+const char tickhelp[] =    "toggle printing byte counter during transfers";
+const char tracehelp[] =   "toggle packet tracing";
+const char typehelp[] =    "set file transfer type";
+const char umaskhelp[] =   "get (set) umask on remote side";
+const char userhelp[] =    "send new user information";
+const char verbosehelp[] = "toggle verbose mode";
+
+struct cmd cmdtab[] = {
+	{ "!",		shellhelp,	0, 0, 0, NULL, NULL, shell },
+	{ "$",		domachelp,	1, 0, 0, domacro, NULL, NULL },
+	{ "account",	accounthelp,	0, 1, 1, account, NULL, NULL },
+	{ "append",	appendhelp,	1, 1, 1, put, NULL, NULL },
+	{ "ascii",	asciihelp,	0, 1, 1, NULL, setascii, NULL },
+	{ "bell",	beephelp,	0, 0, 0, NULL, setbell, NULL },
+	{ "binary",	binaryhelp,	0, 1, 1, NULL, setbinary, NULL },
+	{ "bye",	quithelp,	0, 0, 0, NULL, quit, NULL },
+	{ "case",	casehelp,	0, 0, 1, NULL, setcase, NULL },
+	{ "cd",		cdhelp,		0, 1, 1, cd, NULL, NULL },
+	{ "cdup",	cduphelp,	0, 1, 1, NULL, cdup, NULL },
+	{ "chmod",	chmodhelp,	0, 1, 1, do_chmod, NULL, NULL },
+	{ "close",	disconhelp,	0, 1, 1, NULL, disconnect, NULL },
+	{ "cr",		crhelp,		0, 0, 0, NULL, setcr, NULL },
+	{ "delete",	deletehelp,	0, 1, 1, delete_cmd, NULL, NULL },
+	{ "debug",	debughelp,	0, 0, 0, setdebug, NULL, NULL },
+	{ "dir",	dirhelp,	1, 1, 1, ls, NULL, NULL },
+	{ "disconnect",	disconhelp,	0, 1, 1, NULL, disconnect, NULL },
+	{ "exit",	quithelp,	0, 0, 0, NULL, quit, NULL },
+	{ "form",	formhelp,	0, 1, 1, NULL, setform, NULL },
+	{ "get",	receivehelp,	1, 1, 1, get, NULL, NULL },
+	{ "glob",	globhelp,	0, 0, 0, NULL, setglob, NULL },
+	{ "hash",	hashhelp,	0, 0, 0, NULL, sethash, NULL },
+	{ "help",	helphelp,	0, 0, 1, help, NULL, NULL },
+	{ "idle",	idlehelp,	0, 1, 1, idle_cmd, NULL, NULL },
+	{ "image",	binaryhelp,	0, 1, 1, NULL, setbinary, NULL },
+	{ "lcd",	lcdhelp,	0, 0, 0, lcd, NULL, NULL },
+	{ "ls",		lshelp,		1, 1, 1, ls, NULL, NULL },
+	{ "macdef",	macdefhelp,	0, 0, 0, macdef, NULL, NULL },
+	{ "mdelete",	mdeletehelp,	1, 1, 1, mdelete, NULL, NULL },
+	{ "mdir",	mdirhelp,	1, 1, 1, mls, NULL, NULL },
+	{ "mget",	mgethelp,	1, 1, 1, mget, NULL, NULL },
+	{ "mkdir",	mkdirhelp,	0, 1, 1, makedir, NULL, NULL },
+	{ "mls",	mlshelp,	1, 1, 1, mls, NULL, NULL },
+	{ "mode",	modehelp,	0, 1, 1, NULL, setmode, NULL },
+	{ "modtime",	modtimehelp,	0, 1, 1, modtime, NULL, NULL },
+	{ "mput",	mputhelp,	1, 1, 1, mput, NULL, NULL },
+	{ "newer",	newerhelp,	1, 1, 1, newer, NULL, NULL },
+	{ "nmap",	nmaphelp,	0, 0, 1, setnmap, NULL, NULL },
+	{ "nlist",	nlisthelp,	1, 1, 1, ls, NULL, NULL },
+	{ "ntrans",	ntranshelp,	0, 0, 1, setntrans, NULL, NULL },
+	{ "open",	connecthelp,	0, 0, 1, setpeer, NULL, NULL },
+	{ "prompt",	prompthelp,	0, 0, 0, NULL, setprompt, NULL },
+        { "passive",    passivehelp,    0, 0, 0, NULL, setpassive, NULL },
+	{ "proxy",	proxyhelp,	0, 0, 1, doproxy, NULL, NULL },
+	{ "sendport",	porthelp,	0, 0, 0, NULL, setport, NULL },
+	{ "put",	sendhelp,	1, 1, 1, put, NULL, NULL },
+	{ "pwd",	pwdhelp,	0, 1, 1, NULL, pwd, NULL },
+	{ "quit",	quithelp,	0, 0, 0, NULL, quit, NULL },
+	{ "quote",	quotehelp,	1, 1, 1, quote, NULL, NULL },
+	{ "recv",	receivehelp,	1, 1, 1, get, NULL, NULL },
+	{ "reget",	regethelp,	1, 1, 1, reget, NULL, NULL },
+	{ "rstatus",	rmtstatushelp,	0, 1, 1, rmtstatus, NULL, NULL },
+	{ "rhelp",	remotehelp,	0, 1, 1, rmthelp, NULL, NULL },
+	{ "rename",	renamehelp,	0, 1, 1, renamefile, NULL, NULL },
+	{ "reset",	resethelp,	0, 1, 1, NULL, reset, NULL },
+	{ "restart",	restarthelp,	1, 1, 1, restart, NULL, NULL },
+	{ "rmdir",	rmdirhelp,	0, 1, 1, removedir, NULL, NULL },
+	{ "runique",	runiquehelp,	0, 0, 1, NULL, setrunique, NULL },
+	{ "send",	sendhelp,	1, 1, 1, put, NULL, NULL },
+	{ "site",	sitehelp,	0, 1, 1, site, NULL, NULL },
+	{ "size",	sizecmdhelp,	1, 1, 1, sizecmd, NULL, NULL },
+	{ "status",	statushelp,	0, 0, 1, NULL, status, NULL },
+	{ "struct",	structhelp,	0, 1, 1, NULL, setstruct, NULL },
+	{ "system",	systemhelp,	0, 1, 1, NULL, syst, NULL },
+	{ "sunique",	suniquehelp,	0, 0, 1, NULL, setsunique, NULL },
+	{ "tenex",	tenexhelp,	0, 1, 1, NULL, settenex, NULL },
+	{ "tick",	tickhelp,	0, 0, 0, NULL, settick, NULL },
+	{ "trace",	tracehelp,	0, 0, 0, NULL, settrace, NULL },
+	{ "type",	typehelp,	0, 1, 1, settype, NULL, NULL },
+	{ "user",	userhelp,	0, 1, 1, user, NULL, NULL },
+	{ "umask",	umaskhelp,	0, 1, 1, do_umask, NULL, NULL },
+	{ "verbose",	verbosehelp,	0, 0, 0, NULL, setverbose, NULL },
+	{ "?",		helphelp,	0, 0, 1, help, NULL, NULL },
+	{ 0, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+int	NCMDS = (sizeof (cmdtab) / sizeof (cmdtab[0])) - 1;
Index: netkit-ftp-0.17-new/ftp/domacro.c
===================================================================
--- netkit-ftp-0.17-new/ftp/domacro.c	(nonexistent)
+++ netkit-ftp-0.17-new/ftp/domacro.c	(revision 5)
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 1985 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.
+ */
+
+/*
+ * from: @(#)domacro.c	1.8 (Berkeley) 9/28/90
+ */
+char domacro_rcsid[] = 
+  "$Id: domacro.c,v 1.1.1.1 2000/11/03 19:18:15 mk Exp $";
+
+#include <errno.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ftp_var.h"
+
+void
+domacro(int argc, char *argv[])
+{
+	int margc;
+	char *marg;
+	char **margv;
+	register int i, j;
+	register char *cp1, *cp2;
+	int count = 2, loopflg = 0;
+	char line2[LINELEN];
+	struct cmd *c;
+
+	if (argc < 2 && !another(&argc, &argv, "macro name")) {
+		printf("Usage: %s macro_name.\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) {
+		printf("'%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(*cp1)) {
+			cp1++;
+		}
+		cp2 = line;
+		while (*cp1 != '\0') {
+		      switch(*cp1) {
+		   	    case '\\':
+				 *cp2++ = *++cp1;
+				 break;
+			    case '$':
+				 if (isdigit(*(cp1+1))) {
+				    j = 0;
+				    while (isdigit(*++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';
+		margv = makeargv(&margc, &marg);
+		c = getcmd(margv[0]);
+		if (c == (struct cmd *)-1) {
+			printf("?Ambiguous command\n");
+			code = -1;
+		}
+		else if (c == NULL) {
+			printf("?Invalid command\n");
+			code = -1;
+		}
+		else if (c->c_conn && !connected) {
+			printf("Not connected.\n");
+			code = -1;
+		}
+		else {
+			if (verbose) {
+				printf("%s\n",line);
+			}
+			if (c->c_handler_v) c->c_handler_v(margc, margv);
+			else if (c->c_handler_0) c->c_handler_0();
+			else c->c_handler_1(marg);
+
+			if (bell && c->c_bell) {
+				(void) putchar('\007');
+			}
+			(void) strcpy(line, line2);
+			margv = makeargv(&margc, &marg);
+			argc = margc;
+			argv = margv;
+		}
+		if (cp1 != macros[i].mac_end) {
+			cp1++;
+		}
+	}
+	if (loopflg && ++count < argc) {
+		goto TOP;
+	}
+}
Index: netkit-ftp-0.17-new/ftp/ftp.1
===================================================================
--- netkit-ftp-0.17-new/ftp/ftp.1	(nonexistent)
+++ netkit-ftp-0.17-new/ftp/ftp.1	(revision 5)
@@ -0,0 +1,1061 @@
+.\" Copyright (c) 1985, 1989, 1990 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.
+.\"
+.\"	from: @(#)ftp.1	6.18 (Berkeley) 7/30/91
+.\"	$Id: ftp.1,v 1.1.1.1 2000/11/03 19:18:15 mk Exp $
+.\"
+.Dd August 15, 1999
+.Dt FTP 1
+.Os "Linux NetKit (0.17)"
+.Sh NAME
+.Nm ftp
+.Nd
+.Tn Internet
+file transfer program
+.Sh SYNOPSIS
+.Nm ftp
+.Op Fl pinegvd
+.Op Ar host
+.Nm pftp
+.Op Fl inegvd
+.Op Ar host
+.Sh DESCRIPTION
+.Nm Ftp
+is the user interface to the
+.Tn Internet
+standard File Transfer Protocol.
+The program allows a user to transfer files to and from a
+remote network site.
+.Pp
+Options may be specified at the command line, or to the
+command interpreter.
+.Bl -tag -width flag
+.It Fl A
+Use active mode for data transfers. This is useful for transmissions
+to servers which do not support passive connections (for whatever reason.)
+.It Fl p
+Use passive mode for data transfers. Allows use of ftp in environments
+where a firewall prevents connections from the outside world back to
+the client machine. Requires that the ftp server support the PASV
+command. This is the default now for
+.Nm all
+clients (ftp and pftp) due to security concerns using the PORT transfer mode.
+The flag is kept for compatibility only and has no effect anymore.
+.It Fl i
+Turns off interactive prompting during multiple file transfers.
+.It Fl n
+Restrains
+.Nm ftp
+from attempting \*(Lqauto-login\*(Rq upon initial connection.
+If auto-login is enabled,
+.Nm ftp
+will check the
+.Pa .netrc
+(see 
+.Xr netrc 5) 
+file in the user's home directory for an entry describing
+an account on the remote machine.
+If no entry exists,
+.Nm ftp
+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 e
+Disables command editing and history support, if it was compiled into
+the
+.Nm ftp
+executable. Otherwise, does nothing.
+.It Fl g
+Disables file name globbing.
+.It Fl m
+The default requires that ftp explicitly binds to the same interface for the data
+channel as the control channel in passive mode. Useful on multi-homed
+clients. This option disables this behavior.
+.It Fl v
+Verbose option forces
+.Nm ftp
+to show all responses from the remote server, as well
+as report on data transfer statistics.
+.It Fl d
+Enables debugging.
+.El
+.Pp
+The client host with which
+.Nm ftp
+is to communicate may be specified on the command line.
+If this is done,
+.Nm ftp
+will immediately attempt to establish a connection to an
+.Tn FTP
+server on that host; otherwise,
+.Nm ftp
+will enter its command interpreter and await instructions
+from the user.
+When
+.Nm ftp
+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 file-name
+Change the permission modes of the file
+.Ar file-name
+on the remote
+system to
+.Ar mode  .
+.It Ic close
+Terminate the
+.Tn FTP
+session with the remote server, and
+return to the command interpreter.
+Any defined macros are erased.
+.It Ic \&cr
+Toggle carriage return stripping during
+ascii type file retrieval.
+Records are denoted by a carriage return/linefeed sequence
+during ascii type file transfer.
+When
+.Ic \&cr
+is on (the default), carriage returns are stripped from this
+sequence to conform with the
+.Ux
+single linefeed record
+delimiter.
+Records on
+.Pf non\- Ns Ux
+remote systems may contain single linefeeds;
+when an ascii type transfer is made, these linefeeds may be
+distinguished from a record delimiter only when
+.Ic \&cr
+is off.
+.It Ic delete Ar remote-file
+Delete the file
+.Ar remote-file
+on the remote machine.
+.It Ic 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 ftp
+prints each command sent to the remote machine, preceded
+by the string
+.Ql \-\->
+.It Xo
+.Ic dir
+.Op Ar remote-directory
+.Op Ar local-file
+.Xc
+Print a listing of the directory contents in the
+directory,
+.Ar remote-directory  ,
+and, optionally, placing the output in
+.Ar local-file  .
+If interactive prompting is on,
+.Nm ftp
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.Ic dir
+output.
+If no directory is specified, the current working
+directory on the remote machine is used.
+If no local
+file is specified, or
+.Ar local-file
+is
+.Fl  ,
+output comes to the terminal.
+.It Ic disconnect
+A synonym for
+.Ar close  .
+.It Ic form Ar format
+Set the file transfer
+.Ic form
+to
+.Ar format  .
+The default format is \*(Lqfile\*(Rq.
+.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
+Toggle hash-sign (``#'') printing for each data block
+transferred.
+The size of a data block is 1024 bytes.
+.It Ic help Op Ar command
+Print an informative message about the meaning of
+.Ar command  .
+If no argument is given,
+.Nm ftp
+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 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 Xo
+.Ic \&ls
+.Op Ar remote-directory
+.Op Ar local-file
+.Xc
+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 .
+(See also
+.Ic nlist . )
+If
+.Ar remote-directory
+is left unspecified, the current working directory is used.
+If interactive prompting is on,
+.Nm ftp
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.Ic \&ls
+output.
+If no local file is specified, or if
+.Ar local-file
+is
+.Sq Fl ,
+the output is sent to the terminal.
+.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 ftp
+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 nlist  ,
+except multiple remote files may be specified,
+and the
+.Ar local-file
+must be specified.
+If interactive prompting is on,
+.Nm ftp
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.Ic mls
+output.
+.It Ic mode Op Ar mode-name
+Set the file transfer
+.Ic mode
+to
+.Ar mode-name  .
+The default mode is \*(Lqstream\*(Rq mode.
+.It Ic modtime Ar file-name
+Show the last modification time of the file on the remote machine.
+.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 newer Ar file-name 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 Xo
+.Ic nlist
+.Op Ar remote-directory
+.Op Ar local-file
+.Xc
+Print a  list of the files in a
+directory on the remote machine.
+If
+.Ar remote-directory
+is left unspecified, the current working directory is used.
+If interactive prompting is on,
+.Nm ftp
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.Ic nlist
+output.
+If no local file is specified, or if
+.Ar local-file
+is
+.Fl  ,
+the output is sent to the terminal.
+.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 ftp
+will attempt to contact an
+.Tn FTP
+server at that port.
+If the
+.Ic auto-login
+option is on (default),
+.Nm ftp
+will also attempt to automatically log the user in to
+the
+.Tn FTP
+server (see below).
+.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.
+.It Ic proxy Ar ftp-command
+Execute an ftp command on a secondary control connection.
+This command allows simultaneous connection to two remote 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 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 ftp protocol
+.Dv PASV
+command by the server on the secondary control connection.
+.It Ic put Ar local-file Op Ar remote-file
+Store a local file on the remote machine.
+If
+.Ar remote-file
+is left unspecified, the local file name is used
+after processing according to any
+.Ic ntrans
+or
+.Ic nmap
+settings
+in naming the remote file.
+File transfer uses the
+current settings for
+.Ic type  ,
+.Ic format ,
+.Ic mode  ,
+and
+.Ic structure  .
+.It Ic pwd
+Print the name of the current working directory on the remote
+machine.
+.It Ic quit
+A synonym for
+.Ic bye  .
+.It Ic quote Ar arg1 arg2 ...
+The arguments specified are sent, verbatim, to the remote
+.Tn FTP
+server.
+.It Ic recv Ar remote-file Op Ar local-file
+A synonym for get.
+.It Ic reget Ar remote-file Op Ar local-file
+Reget acts like 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 remotehelp 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 remotestatus Op Ar file-name
+With no arguments, show status of remote machine.
+If
+.Ar file-name
+is specified, show status of
+.Ar file-name
+on remote machine.
+.It Xo
+.Ic rename
+.Op Ar from
+.Op Ar to
+.Xc
+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
+ftp server.
+Resynchronization may be necessary following a violation of the 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 rmdir Ar directory-name
+Delete a directory on the 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 put.
+.It Ic sendport
+Toggle the use of
+.Dv PORT
+commands.
+By default,
+.Nm ftp
+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 ftp
+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 site Ar arg1 arg2 ...
+The arguments specified are sent, verbatim, to the remote
+.Tn FTP
+server as a
+.Dv SITE
+command.
+.It Ic size Ar file-name
+Return size of
+.Ar file-name
+on remote machine.
+.It Ic status
+Show the current status of
+.Nm ftp  .
+.It Ic struct Op Ar struct-name
+Set the file transfer
+.Ar structure
+to
+.Ar struct-name .
+By default \*(Lqstream\*(Rq structure is used.
+.It Ic sunique
+Toggle storing of files on remote machine under unique file names.
+Remote ftp server must support 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 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 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 ftp
+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 ftp
+is invoked with \*(Lqauto-login\*(Rq 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 ? Op Ar command
+A synonym for help.
+.El
+.Pp
+Command arguments which have embedded spaces may be quoted with
+quote `"' marks.
+.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 a 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, an
+.Ql ftp>
+prompt will not appear until the remote server has completed
+sending the requested file.
+.Pp
+The terminal interrupt key sequence will be ignored when
+.Nm ftp
+has completed any local processing and is awaiting a reply
+from the remote server.
+A long delay in this mode may result from the ABOR processing described
+above, or from unexpected behavior by the remote server, including
+violations of the ftp protocol.
+If the delay results from unexpected remote server behavior, the local
+.Nm ftp
+program must be killed by hand.
+.Sh FILE NAMING CONVENTIONS
+Files specified as arguments to
+.Nm ftp
+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 Ftp
+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.
+\*(Lq" ls -lt"\*(Rq.
+A particularly
+useful example of this mechanism is: \*(Lqdir more\*(Rq.
+.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 ftp
+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 FTP specification specifies many parameters which may
+affect a file transfer.
+The
+.Ic type
+may be one of \*(Lqascii\*(Rq, \*(Lqimage\*(Rq (binary),
+\*(Lqebcdic\*(Rq, and \*(Lqlocal byte size\*(Rq (for
+.Tn PDP Ns -10's
+and
+.Tn PDP Ns -20's
+mostly).
+.Nm Ftp
+supports the ascii and image types of file transfer,
+plus local byte size 8 for
+.Ic tenex
+mode transfers.
+.Pp
+.Nm Ftp
+supports only the default values for the remaining
+file transfer parameters:
+.Ic mode  ,
+.Ic form ,
+and
+.Ic struct  .
+.Sh ENVIRONMENT
+.Nm Ftp
+utilizes the following environment variables.
+.Bl -tag -width Fl
+.It Ev HOME
+For default location of a
+.Pa .netrc
+file, if one exists.
+.It Ev SHELL
+For default shell.
+.El
+.Sh SEE ALSO
+.Xr ftpd 8 ,
+RFC 959
+.Sh HISTORY
+The
+.Nm ftp
+command appeared in
+.Bx 4.2 .
+.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.
Index: netkit-ftp-0.17-new/ftp/ftp.c
===================================================================
--- netkit-ftp-0.17-new/ftp/ftp.c	(nonexistent)
+++ netkit-ftp-0.17-new/ftp/ftp.c	(revision 5)
@@ -0,0 +1,2001 @@
+/* $USAGI$ */
+
+/*
+ * 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.
+ */
+
+/*
+ * Copyright (c) 1985, 1989 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.
+ */
+
+/* 
+ * From: @(#)ftp.c	5.38 (Berkeley) 4/22/91
+ */
+char ftp_rcsid[] = 
+  "$Id: ftp.c,v 1.11 2001/02/11 12:26:59 yoshfuji Exp $";
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sys/poll.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/ftp.h>
+#include <arpa/telnet.h>
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdarg.h>
+
+#include "ftp_var.h"
+#include "cmds.h"
+
+#ifdef _USAGI
+#include "version.h"
+#else
+#include "../version.h"
+#endif
+
+union sockunion {
+	struct sockinet {
+		u_short	si_family;
+		u_short	si_port;
+	} su_si;
+	struct	sockaddr		su_sa;
+	struct	sockaddr_in  		su_sin;
+#ifdef INET6
+	struct	sockaddr_in6 		su_sin6;
+#endif
+};
+#define	su_family	su_sa.sa_family
+#define	su_port		su_si.si_port
+
+#ifdef INET6
+#define ex_af2prot(a) (a == AF_INET ? 1 : (a == AF_INET6 ? 2 : 0))
+#else
+#define ex_af2prot(a) (a == AF_INET ? 1 : 0)
+#endif
+
+int data = -1;
+off_t restart_point = 0;
+
+static union sockunion hisctladdr;
+static union sockunion data_addr;
+static union sockunion myctladdr;
+static int ptflag = 0;
+static sigjmp_buf recvabort;
+static sigjmp_buf sendabort;
+static sigjmp_buf ptabort;
+static int ptabflg = 0;
+static int abrtflag = 0;
+struct sockaddr_storage source;
+
+void lostpeer(int);
+extern int connected;
+
+static char *gunique(char *);
+static void proxtrans(const char *cmd, char *local, char *remote);
+static int initconn(void);
+static void ptransfer(const char *direction, long long bytes, 
+		      const struct timeval *t0, 
+		      const struct timeval *t1);
+static void tvsub(struct timeval *tdiff, 
+		  const struct timeval *t1, 
+		  const struct timeval *t0);
+static void abort_remote(FILE *din);
+
+FILE *cin, *cout;
+static FILE *dataconn(const char *);
+
+char *
+hookup(const char *host, const char *port)
+{
+	int s, tos, error;
+	socklen_t len, alen;
+	static char hostnamebuf[256];
+	struct addrinfo hints, *res, *res0;
+	char hbuf[MAXHOSTNAMELEN], pbuf[NI_MAXSERV];
+	char *cause = "ftp: unknown";
+
+	if (port) {
+		strncpy(pbuf, port, sizeof(pbuf) - 1);
+		pbuf[sizeof(pbuf) - 1] = '\0';
+	} else {
+		sprintf(pbuf, "%d", ntohs(ftp_port));
+	}
+	memset(&hisctladdr, 0, sizeof(hisctladdr));
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_flags = AI_CANONNAME;
+	hints.ai_socktype = SOCK_STREAM;
+	error = getaddrinfo(host, pbuf, &hints, &res0);
+	if (error) {
+		if (port) {
+			strcpy(hbuf, " ");
+		} else {
+			hbuf[0] = '\0';
+			pbuf[0] = '\0';
+		}
+		fprintf(stderr, "ftp: %s%s%s: %s\n", host, hbuf, pbuf,
+						gai_strerror(error));
+		code = -1;
+		return (0);
+	}
+
+	if (res0->ai_canonname) {
+		struct addrinfo h, *a;
+		memset(&h, 0, sizeof(h));
+		h.ai_family = PF_UNSPEC;
+		h.ai_socktype = SOCK_STREAM;
+		h.ai_flags = AI_NUMERICHOST;
+		if (!getaddrinfo(res0->ai_canonname, NULL, &h, &a)) {
+			strncpy(hostnamebuf, res0->ai_canonname, sizeof(hostnamebuf));
+			freeaddrinfo(a);
+		} else
+			strncpy(hostnamebuf, host, sizeof(hostnamebuf));
+	}
+	else
+		strncpy(hostnamebuf, host, sizeof(hostnamebuf));
+	hostnamebuf[sizeof(hostnamebuf) - 1] = '\0';
+	hostname = hostnamebuf;
+	
+	s = -1;
+	for (res = res0; res; res = res->ai_next) {
+		if (!ex_af2prot(res->ai_family)) {
+			cause = "ftp: mismatch address family";
+			errno = EPROTONOSUPPORT;
+			continue;
+		}
+		if ((size_t)res->ai_addrlen > sizeof(hisctladdr)) {
+			cause = "ftp: mismatch struct sockaddr size";
+			errno = EPROTO;
+			continue;
+		}
+		if (getnameinfo(res->ai_addr, res->ai_addrlen,
+				hbuf, sizeof(hbuf), NULL, 0,
+				NI_NUMERICHOST))
+			strcpy(hbuf, "???");
+		if (res0->ai_next)	/* if we have multiple possibilities */
+			fprintf(stdout, "Trying %s...\n", hbuf);
+		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+		if (s < 0) {
+			cause = "ftp: socket";
+			continue;
+		}
+		while ((error = connect(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) {
+				fprintf(stderr,
+					"ftp: connect to address %s", hbuf);
+				perror("");
+			}
+			cause = "ftp: connect";
+			close(s);
+			s = -1;
+			continue;
+		}
+		/* finally we got one */
+		break;
+	}
+	if (s < 0) {
+		perror(cause);
+		code = -1;
+		freeaddrinfo(res0);
+		return NULL;
+	}
+	len = res->ai_addrlen;
+	memcpy(&hisctladdr, res->ai_addr, len);
+	freeaddrinfo(res0);
+	if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
+		perror("ftp: getsockname");
+		code = -1;
+		goto bad;
+	}
+#ifdef IP_TOS
+	if (hisctladdr.su_family == AF_INET)
+	{
+	tos = IPTOS_LOWDELAY;
+	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
+		perror("ftp: setsockopt TOS (ignored)");
+	}
+#endif
+	cin = fdopen(s, "r");
+	cout = fdopen(s, "w");
+	if (cin == NULL || cout == NULL) {
+		fprintf(stderr, "ftp: fdopen failed.\n");
+		if (cin)
+			(void) fclose(cin);
+		if (cout)
+			(void) fclose(cout);
+		code = -1;
+		goto bad;
+	}
+	if (verbose)
+		printf("Connected to %s (%s).\n", hostname, hbuf);
+	alen = sizeof(source);
+	getsockname(s,(struct sockaddr*)&source, &alen);
+	switch (source.ss_family) {
+	    /* We just want the addr, not the port */
+	    case AF_INET:
+		((struct sockaddr_in *) &source)->sin_port = 0;
+	        break;
+	    case AF_INET6:
+		((struct sockaddr_in6 *) &source)->sin6_port = 0;
+	        break;
+	}
+
+	if (getreply(0) > 2) { 	/* read startup message from server    */
+		if (cin)
+			(void) fclose(cin);
+		if (cout)
+			(void) fclose(cout);
+		code = -1;
+		goto bad;
+	}
+#ifdef SO_OOBINLINE
+	{
+	int on = 1;
+
+	if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
+		< 0 && debug) {
+			perror("ftp: setsockopt");
+		}
+	}
+#endif /* SO_OOBINLINE */
+
+	return (hostname);
+bad:
+	(void) close(s);
+	return ((char *)0);
+}
+
+int
+dologin(const char *host)
+{
+	char tmp[80];
+	char *luser, *pass, *zacct;
+	int n, aflag = 0;
+
+	luser = pass = zacct = 0;
+	if (xruserpass(host, &luser, &pass, &zacct) < 0) {
+		code = -1;
+		return(0);
+	}
+	while (luser == NULL) {
+		char *myname = NULL;
+
+		struct passwd *pp = getpwuid(getuid());
+
+		if (pp != NULL)
+			myname = pp->pw_name;
+		if (myname)
+			printf("Name (%s:%s): ", host, myname);
+		else
+			printf("Name (%s): ", host);
+		if (fgets(tmp, sizeof(tmp) - 1, stdin)==NULL) {
+			fprintf(stderr, "\nLogin failed.\n");
+			return 0;
+		}
+		tmp[strlen(tmp) - 1] = '\0';
+		if (*tmp == '\0')
+			luser = myname;
+		else
+			luser = tmp;
+	}
+	n = command("USER %s", luser);
+	if (n == CONTINUE) {
+		if (pass == NULL) {
+			/* fflush(stdout); */
+			pass = getpass("Password:");
+		}
+		n = command("PASS %s", pass);
+	}
+	if (n == CONTINUE) {
+		aflag++;
+		/* fflush(stdout); */
+		if(zacct==NULL)
+			zacct = getpass("Account:");
+		n = command("ACCT %s", zacct);
+	}
+	if (n != COMPLETE) {
+		fprintf(stderr, "Login failed.\n");
+		return (0);
+	}
+	if (!aflag && zacct != NULL)
+		(void) command("ACCT %s", zacct);
+	if (proxy)
+		return(1);
+	for (n = 0; n < macnum; ++n) {
+		if (!strcmp("init", macros[n].mac_name)) {
+			int margc;
+			char **margv;
+			strcpy(line, "$init");
+			margv = makeargv(&margc, NULL);
+			domacro(margc, margv);
+			break;
+		}
+	}
+	return (1);
+}
+
+
+static void
+cmdabort(int ignore)
+{
+	(void)ignore;
+
+	printf("\n");
+	fflush(stdout);
+	abrtflag++;
+	if (ptflag) siglongjmp(ptabort,1);
+}
+
+int
+command(const char *fmt, ...)
+{
+	va_list ap;
+	int r;
+	void (*oldintr)(int);
+
+	abrtflag = 0;
+	if (debug) {
+		printf("---> ");
+		va_start(ap, fmt);
+		if (strncmp("PASS ", fmt, 5) == 0)
+			printf("PASS XXXX");
+		else 
+			vfprintf(stdout, fmt, ap);
+		va_end(ap);
+		printf("\n");
+		(void) fflush(stdout);
+	}
+	if (cout == NULL) {
+		perror ("No control connection for command");
+		code = -1;
+		return (0);
+	}
+	oldintr = signal(SIGINT, cmdabort);
+	va_start(ap, fmt);
+	vfprintf(cout, fmt, ap);
+	va_end(ap);
+	fprintf(cout, "\r\n");
+	(void) fflush(cout);
+	cpend = 1;
+	r = getreply(!strcmp(fmt, "QUIT"));
+	if (abrtflag && oldintr != SIG_IGN)
+		(*oldintr)(SIGINT);
+	(void) signal(SIGINT, oldintr);
+	return(r);
+}
+
+char reply_string[BUFSIZ];		/* last line of previous reply */
+
+#include <ctype.h>
+
+int
+getreply(int expecteof)
+{
+	register int c, n;
+	register int dig;
+	register char *cp;
+	int originalcode = 0, continuation = 0;
+	void (*oldintr)(int);
+	int pflag = 0;
+	size_t px = 0;
+	size_t psize = sizeof(pasv);
+
+	oldintr = signal(SIGINT, cmdabort);
+	for (;;) {
+		dig = n = code = 0;
+		cp = reply_string;
+		while ((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) {
+				if (expecteof) {
+					(void) signal(SIGINT,oldintr);
+					code = 221;
+					return (0);
+				}
+				lostpeer(0);
+				if (cout) {
+					fclose(cout);
+					cout = NULL;
+				}
+				if (verbose) {
+					printf("421 Service not available, remote server has closed connection\n");
+					(void) fflush(stdout);
+				}
+				code = 421;
+				return(4);
+			}
+			if (c != '\r' && (verbose > 0 ||
+			    (verbose > -1 && n == '5' && dig > 4))) {
+				if (proxflag &&
+				   (dig == 1 || (dig == 5 && verbose == 0)))
+					printf("%s:",hostname);
+				(void) putchar(c);
+			}
+			if (dig < 4 && isdigit(c))
+				code = code * 10 + (c - '0');
+			if (!pflag && (code == 227 || code == 228))
+				pflag = 1;
+			else if (!pflag && code == 229)
+				pflag = 100;
+			if (dig > 4 && pflag == 1 && isdigit(c))
+				pflag = 2;
+			if (pflag == 2) {
+				if (c != '\r' && c != ')') {
+					if (px < psize-1) pasv[px++] = c;
+				}
+				else {
+					pasv[px] = '\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 < &reply_string[sizeof(reply_string) - 1])
+				*cp++ = c;
+		}
+		if (verbose > 0 || (verbose > -1 && n == '5')) {
+			(void) putchar(c);
+			(void) fflush (stdout);
+		}
+		if (continuation && code != originalcode) {
+			if (originalcode == 0)
+				originalcode = code;
+			continue;
+		}
+		*cp = '\0';
+		if (n != '1')
+			cpend = 0;
+		(void) signal(SIGINT,oldintr);
+		if (code == 421 || originalcode == 421)
+		{
+			lostpeer(0);
+			if(cout)
+			{
+				fclose(cout);
+				cout = NULL;
+			}
+		}
+		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
+			(*oldintr)(SIGINT);
+		return (n - '0');
+	}
+}
+
+static int
+empty(fd_set *mask, int hifd, int sec)
+{
+	struct timeval t;
+
+	t.tv_sec = (long) sec;
+	t.tv_usec = 0;
+	return(select(hifd+1, mask, (fd_set *) 0, (fd_set *) 0, &t));
+}
+
+static void
+abortsend(int ignore)
+{
+	(void)ignore;
+
+	mflag = 0;
+	abrtflag = 0;
+	printf("\nsend aborted\nwaiting for remote to finish abort\n");
+	(void) fflush(stdout);
+	siglongjmp(sendabort, 1);
+}
+
+#define HASHBYTES 1024
+
+void
+sendrequest(const char *cmd, char *local, char *remote, int printnames)
+{
+	struct stat st;
+	struct timeval start, stop;
+	register int c, d;
+	FILE *volatile fin, *volatile dout = 0;
+	int (*volatile closefunc)(FILE *);
+	void (*volatile oldintr)(int);
+	void (*volatile oldintp)(int);
+	volatile long long bytes = 0, hashbytes = HASHBYTES;
+	char buf[BUFSIZ], *bufp;
+	const char *volatile lmode;
+        int old_code_l;
+
+	if (verbose && printnames) {
+		if (local && *local != '-')
+			printf("local: %s ", local);
+		if (remote)
+			printf("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(sendabort, 1)) {
+		while (cpend) {
+			(void) getreply(0);
+		}
+		if (data >= 0) {
+			(void) close(data);
+			data = -1;
+		}
+		if (oldintr)
+			(void) signal(SIGINT,oldintr);
+		if (oldintp)
+			(void) signal(SIGPIPE,oldintp);
+		code = -1;
+		return;
+	}
+	oldintr = signal(SIGINT, abortsend);
+	if (strcmp(local, "-") == 0)
+		fin = stdin;
+	else if (*local == '|') {
+		oldintp = signal(SIGPIPE,SIG_IGN);
+		fin = popen(local + 1, "r");
+		if (fin == NULL) {
+			perror(local + 1);
+			(void) signal(SIGINT, oldintr);
+			(void) signal(SIGPIPE, oldintp);
+			code = -1;
+			return;
+		}
+		closefunc = pclose;
+	} else {
+		fin = fopen(local, "r");
+		if (fin == NULL) {
+			fprintf(stderr, "local: %s: %s\n", local,
+				strerror(errno));
+			(void) signal(SIGINT, oldintr);
+			code = -1;
+			return;
+		}
+		closefunc = fclose;
+		if (fstat(fileno(fin), &st) < 0 ||
+		    (st.st_mode&S_IFMT) != S_IFREG) {
+			fprintf(stdout, "%s: not a plain file.\n", local);
+			(void) signal(SIGINT, oldintr);
+			fclose(fin);
+			code = -1;
+			return;
+		}
+	}
+	if (initconn()) {
+		(void) signal(SIGINT, oldintr);
+		if (oldintp)
+			(void) signal(SIGPIPE, oldintp);
+		code = -1;
+		if (closefunc != NULL)
+			(*closefunc)(fin);
+		return;
+	}
+	if (sigsetjmp(sendabort, 1))
+		goto abort;
+
+	if (restart_point &&
+	    (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
+		if (fseek(fin, (long) restart_point, 0) < 0) {
+			fprintf(stderr, "local: %s: %s\n", local,
+				strerror(errno));
+			restart_point = 0;
+			if (closefunc != NULL)
+				(*closefunc)(fin);
+			return;
+		}
+		if (command("REST %ld", (long) restart_point)
+			!= CONTINUE) {
+			restart_point = 0;
+			if (closefunc != NULL)
+				(*closefunc)(fin);
+			return;
+		}
+		restart_point = 0;
+		lmode = "r+w";
+	}
+	if (remote) {
+		if (command("%s %s", cmd, remote) != PRELIM) {
+			(void) signal(SIGINT, oldintr);
+			if (oldintp)
+				(void) signal(SIGPIPE, oldintp);
+			if (closefunc != NULL)
+				(*closefunc)(fin);
+			return;
+		}
+	} else
+		if (command("%s", cmd) != PRELIM) {
+			(void) signal(SIGINT, oldintr);
+			if (oldintp)
+				(void) signal(SIGPIPE, oldintp);
+			if (closefunc != NULL)
+				(*closefunc)(fin);
+			return;
+		}
+	dout = dataconn(lmode);
+	if (dout == NULL)
+		goto abort;
+	(void) gettimeofday(&start, (struct timezone *)0);
+	oldintp = signal(SIGPIPE, SIG_IGN);
+	switch (curtype) {
+
+	case TYPE_I:
+	case TYPE_L:
+		errno = d = 0;
+		while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) {
+			bytes += c;
+			for (bufp = buf; c > 0; c -= d, bufp += d)
+				if ((d = write(fileno(dout), bufp, c)) <= 0)
+					break;
+			if (hash) {
+				while (bytes >= hashbytes) {        /* <-- 'long long' signed overflow is  */
+					(void) putchar('#');        /* possible. In this case, we can      */
+					hashbytes += HASHBYTES;     /* 'cycle' there for very long time.   */
+				}                                   /* Search 'hasbytes' in file down,     */
+				(void) fflush(stdout);              /* there are similar parts.            */
+			}                                           /*           <praszyk@redhat.com>      */
+			if (tick && (bytes >= hashbytes)) {
+				printf("\rBytes transferred: %lld", bytes);
+				(void) fflush(stdout);
+				while (bytes >= hashbytes)
+					hashbytes += TICKBYTES;
+			}
+		}
+		if (hash && (bytes > 0)) {
+			if (bytes < HASHBYTES)
+				(void) putchar('#');
+			(void) putchar('\n');
+			(void) fflush(stdout);
+		}
+		if (tick) {
+			(void) printf("\rBytes transferred: %lld\n", bytes);
+			(void) fflush(stdout);
+		}
+		if (c < 0)
+			fprintf(stderr, "local: %s: %s\n", local,
+				strerror(errno));
+		if (d < 0) {
+			if (errno != EPIPE) 
+				perror("netout");
+			bytes = -1;
+		}
+		break;
+
+	case TYPE_A:
+		while ((c = getc(fin)) != EOF) {
+			if (c == '\n') {
+				while (hash && (bytes >= hashbytes)) {
+					(void) putchar('#');
+					(void) fflush(stdout);
+					hashbytes += HASHBYTES;
+				}
+				if (tick && (bytes >= hashbytes)) {
+					(void) printf("\rBytes transferred: %lld",
+						bytes);
+					(void) fflush(stdout);
+					while (bytes >= hashbytes)
+						hashbytes += TICKBYTES;
+				}
+				if (ferror(dout))
+					break;
+				(void) putc('\r', dout);
+				bytes++;
+			}
+			(void) putc(c, dout);
+			bytes++;
+	/*		if (c == '\r') {			  	*/
+	/*		(void)	putc('\0', dout);  (* this violates rfc */
+	/*			bytes++;				*/
+	/*		}                          			*/     
+		}
+		if (hash) {
+			if (bytes < hashbytes)
+				(void) putchar('#');
+			(void) putchar('\n');
+			(void) fflush(stdout);
+		}
+		if (tick) {
+			(void) printf("\rBytes transferred: %lld\n", bytes);
+			(void) fflush(stdout);
+		}
+		if (ferror(fin))
+			fprintf(stderr, "local: %s: %s\n", local,
+				strerror(errno));
+		if (ferror(dout)) {
+			if (errno != EPIPE)
+				perror("netout");
+			bytes = -1;
+		}
+		break;
+	}
+	(void) gettimeofday(&stop, (struct timezone *)0);
+	if (closefunc != NULL)
+		(*closefunc)(fin);
+	(void) fclose(dout);
+	/* closes data as well, so discard it */
+	data = -1;
+	old_code_l = code;
+	(void) getreply(0);
+
+	/* Following "if" will avoid a bug #165083 in ftp-server */
+	/* It can be later removed.                              */
+	if (old_code_l == 150 && code == 150 && cpend == 1
+	    && sunique == 1 && cin !=  NULL && fileno (cin) >=  0 ) {
+		struct pollfd  fds_events_l [2] ;
+		int rc;
+
+		fds_events_l [0] .fd = fileno (cin);
+		fds_events_l [0] .events = POLLIN | POLLERR | POLLHUP;
+           
+		rc = poll (fds_events_l, 1, 5000);
+		switch (rc) {
+		case  1:
+			(void) getreply (0);
+			break;
+		case  0:
+			fprintf (stderr, "ftp: no answer from ftp-server "
+			                 "(more than 5 sec).\n");
+			break;
+		case -1:
+			perror("ftp: poll");
+			break;
+		}
+	}
+
+	(void) signal(SIGINT, oldintr);
+	if (oldintp)
+		(void) signal(SIGPIPE, oldintp);
+	if (bytes > 0)
+		ptransfer("sent", bytes, &start, &stop);
+	return;
+abort:
+	(void) gettimeofday(&stop, (struct timezone *)0);
+	(void) signal(SIGINT, oldintr);
+	if (oldintp)
+		(void) signal(SIGPIPE, oldintp);
+	if (!cpend) {
+		code = -1;
+		return;
+	}
+	if (dout) {
+		(void) fclose(dout);
+	}
+	if (data >= 0) {
+		/* if it just got closed with dout, again won't hurt */
+		(void) close(data);
+		data = -1;
+	}
+	(void) getreply(0);
+	code = -1;
+	if (closefunc != NULL && fin != NULL)
+		(*closefunc)(fin);
+	if (bytes > 0)
+		ptransfer("sent", bytes, &start, &stop);
+}
+
+static void
+abortrecv(int ignore)
+{
+	(void)ignore;
+
+	mflag = 0;
+	abrtflag = 0;
+	printf("\nreceive aborted\nwaiting for remote to finish abort\n");
+	(void) fflush(stdout);
+	siglongjmp(recvabort, 1);
+}
+
+void
+recvrequest(const char *cmd, 
+	    char *volatile local, char *remote, 
+	    const char *lmode, int printnames)
+{
+	FILE *volatile fout, *volatile din = 0;
+	int (*volatile closefunc)(FILE *);
+	void (*volatile oldintp)(int);
+	void (*volatile oldintr)(int);
+	volatile int is_retr, tcrflag, bare_lfs = 0;
+	static unsigned bufsize=0;
+	static char *buf;
+	volatile long long bytes = 0, hashbytes = HASHBYTES;
+	register int c, d;
+	struct timeval start, stop;
+	struct stat st;
+
+	is_retr = strcmp(cmd, "RETR") == 0;
+	if (is_retr && verbose && printnames) {
+		if (local && *local != '-')
+			printf("local: %s ", local);
+		if (remote)
+			printf("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(recvabort, 1)) {
+		while (cpend) {
+			(void) getreply(0);
+		}
+		if (data >= 0) {
+			(void) close(data);
+			data = -1;
+		}
+		if (oldintr)
+			(void) signal(SIGINT, oldintr);
+		code = -1;
+		return;
+	}
+	oldintr = signal(SIGINT, abortrecv);
+	if (strcmp(local, "-") && *local != '|') {
+		if (access(local, W_OK) < 0) {
+			char *dir = rindex(local, '/');
+
+			if (errno != ENOENT && errno != EACCES) {
+				fprintf(stderr, "local: %s: %s\n", local,
+					strerror(errno));
+				(void) signal(SIGINT, oldintr);
+				code = -1;
+				return;
+			}
+			if (dir != NULL)
+				*dir = 0;
+			d = access(dir ? local : ".", W_OK);
+			if (dir != NULL)
+				*dir = '/';
+			if (d < 0) {
+				fprintf(stderr, "local: %s: %s\n", local,
+					strerror(errno));
+				(void) signal(SIGINT, oldintr);
+				code = -1;
+				return;
+			}
+			if (!runique && errno == EACCES &&
+			    chmod(local, 0600) < 0) {
+				fprintf(stderr, "local: %s: %s\n", local,
+					strerror(errno));
+				/*
+				 * Believe it or not, this was actually
+				 * repeated in the original source.
+				 */
+				(void) signal(SIGINT, oldintr);
+				/*(void) signal(SIGINT, oldintr);*/
+				code = -1;
+				return;
+			}
+			if (runique && errno == EACCES &&
+			   (local = gunique(local)) == NULL) {
+				(void) signal(SIGINT, oldintr);
+				code = -1;
+				return;
+			}
+		}
+		else if (runique && (strcmp(cmd, "NLST") != 0) && 
+			 (local = gunique(local)) == NULL)
+		{
+			(void) signal(SIGINT, oldintr);
+			code = -1;
+			return;
+		}
+	}
+	if (!is_retr) {
+		if (curtype != TYPE_A)
+			changetype(TYPE_A, 0);
+	} 
+	else if (curtype != type) {
+		changetype(type, 0);
+	}
+	if (initconn()) {
+		(void) signal(SIGINT, oldintr);
+		code = -1;
+		return;
+	}
+	if (sigsetjmp(recvabort, 1))
+		goto abort;
+	if (is_retr && restart_point &&
+	    command("REST %ld", (long) restart_point) != CONTINUE)
+		return;
+	if (remote) {
+		if (command("%s %s", cmd, remote) != PRELIM) {
+			(void) signal(SIGINT, oldintr);
+			return;
+		}
+	} 
+	else {
+		if (command("%s", cmd) != PRELIM) {
+			(void) signal(SIGINT, oldintr);
+			return;
+		}
+	}
+	din = dataconn("r");
+	if (din == NULL)
+		goto abort;
+	if (strcmp(local, "-") == 0)
+		fout = stdout;
+	else if (*local == '|') {
+		oldintp = signal(SIGPIPE, SIG_IGN);
+		fout = popen(local + 1, "w");
+		if (fout == NULL) {
+			perror(local+1);
+			goto abort;
+		}
+		closefunc = pclose;
+	} 
+	else {
+		fout = fopen(local, lmode);
+		if (fout == NULL) {
+			fprintf(stderr, "local: %s: %s\n", local,
+				strerror(errno));
+			goto abort;
+		}
+		closefunc = fclose;
+	}
+	if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
+		st.st_blksize = BUFSIZ;
+	if ((unsigned)st.st_blksize > bufsize) {
+		if (buf)
+			(void) free(buf);
+		buf = malloc((unsigned)st.st_blksize);
+		if (buf == NULL) {
+			perror("malloc");
+			bufsize = 0;
+			goto abort;
+		}
+		bufsize = st.st_blksize;
+	}
+	(void) gettimeofday(&start, (struct timezone *)0);
+	switch (curtype) {
+
+	case TYPE_I:
+	case TYPE_L:
+		if (restart_point &&
+		    lseek(fileno(fout), (long) restart_point, L_SET) < 0) {
+			fprintf(stderr, "local: %s: %s\n", local,
+				strerror(errno));
+			if (closefunc != NULL)
+				(*closefunc)(fout);
+			return;
+		}
+		errno = d = 0;
+		while ((c = read(fileno(din), buf, bufsize)) > 0) {
+			if ((d = write(fileno(fout), buf, c)) != c)
+				break;
+			bytes += c;
+			if (hash && is_retr) {
+				while (bytes >= hashbytes) {
+					(void) putchar('#');
+					hashbytes += HASHBYTES;
+				}
+				(void) fflush(stdout);
+			}
+			if (tick && (bytes >= hashbytes) && is_retr) {
+				(void) printf("\rBytes transferred: %lld",
+					bytes);
+				(void) fflush(stdout);
+				while (bytes >= hashbytes)
+					hashbytes += TICKBYTES;
+			}
+		}
+		if (hash && bytes > 0) {
+			if (bytes < HASHBYTES)
+				(void) putchar('#');
+			(void) putchar('\n');
+			(void) fflush(stdout);
+		}
+		if (tick && is_retr) {
+			(void) printf("\rBytes transferred: %lld\n", bytes);
+			(void) fflush(stdout);
+		}
+		if (c < 0) {
+			if (errno != EPIPE)
+				perror("netin");
+			bytes = -1;
+		}
+		if (d < c) {
+			if (d < 0)
+				fprintf(stderr, "local: %s: %s\n", local,
+					strerror(errno));
+			else
+				fprintf(stderr, "%s: short write\n", local);
+		}
+		break;
+
+	case TYPE_A:
+		if (restart_point) {
+			register int i, n, ch;
+
+			if (fseek(fout, 0L, L_SET) < 0)
+				goto done;
+			n = restart_point;
+			for (i = 0; i++ < n;) {
+				if ((ch = getc(fout)) == EOF)
+					goto done;
+				if (ch == '\n')
+					i++;
+			}
+			if (fseek(fout, 0L, L_INCR) < 0) {
+done:
+				fprintf(stderr, "local: %s: %s\n", local,
+					strerror(errno));
+				if (closefunc != NULL)
+					(*closefunc)(fout);
+				return;
+			}
+		}
+		while ((c = getc(din)) != EOF) {
+			if (c == '\n')
+				bare_lfs++;
+			while (c == '\r') {
+				while (hash && (bytes >= hashbytes)
+					&& is_retr) {
+					(void) putchar('#');
+					(void) fflush(stdout);
+					hashbytes += HASHBYTES;
+				}
+				if (tick && (bytes >= hashbytes) && is_retr) {
+					printf("\rBytes transferred: %lld",
+						bytes);
+					fflush(stdout);
+					while (bytes >= hashbytes)
+						hashbytes += TICKBYTES;
+				}
+				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 && is_retr) {
+			if (bytes < hashbytes)
+				(void) putchar('#');
+			(void) putchar('\n');
+			(void) fflush(stdout);
+		}
+		if (tick && is_retr) {
+			(void) printf("\rBytes transferred: %lld\n", bytes);
+			(void) fflush(stdout);
+		}
+		if (bare_lfs) {
+			printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs);
+			printf("File may not have transferred correctly.\n");
+		}
+		if (ferror(din)) {
+			if (errno != EPIPE)
+				perror("netin");
+			bytes = -1;
+		}
+		if (ferror(fout))
+			fprintf(stderr, "local: %s: %s\n", local,
+				strerror(errno));
+		break;
+	}
+	if (closefunc != NULL)
+		(*closefunc)(fout);
+	(void) signal(SIGINT, oldintr);
+	if (oldintp)
+		(void) signal(SIGPIPE, oldintp);
+	(void) gettimeofday(&stop, (struct timezone *)0);
+	(void) fclose(din);
+	/* closes data as well, so discard it */
+	data = -1;
+	(void) getreply(0);
+	if (bytes > 0 && is_retr)
+		ptransfer("received", bytes, &start, &stop);
+	return;
+abort:
+
+/* abort using RFC959 recommended IP,SYNC sequence  */
+
+	(void) gettimeofday(&stop, (struct timezone *)0);
+	if (oldintp)
+		(void) signal(SIGPIPE, oldintp);
+	(void) signal(SIGINT, SIG_IGN);
+	if (!cpend) {
+		code = -1;
+		(void) signal(SIGINT, oldintr);
+		return;
+	}
+
+	abort_remote(din);
+	code = -1;
+	if (closefunc != NULL && fout != NULL)
+		(*closefunc)(fout);
+	if (din) {
+		(void) fclose(din);
+	}
+	if (data >= 0) {
+		/* if it just got closed with din, again won't hurt */
+		(void) close(data);
+		data = -1;
+	}
+	if (bytes > 0)
+		ptransfer("received", bytes, &start, &stop);
+	(void) signal(SIGINT, oldintr);
+}
+
+/*
+ * Need to start a listen on the data channel before we send the command,
+ * otherwise the server's connect may fail.
+ */
+static int
+initconn(void)
+{
+	int rc;
+	u_char *p, *a;
+	int result, tmpno = 0;
+	socklen_t len;
+	int on = 1;
+	int tos, error = 0;
+	u_int ad[16], po[2], af, alen, plen;
+	char *pasvcmd = NULL;
+	char hbuf[MAXHOSTNAMELEN], pbuf[NI_MAXSERV];
+	struct timeval timeout;
+
+	timeout.tv_sec = 30;
+	timeout.tv_usec = 0;
+
+#ifdef INET6
+	if (myctladdr.su_family == AF_INET6
+	 && (IN6_IS_ADDR_LINKLOCAL(&myctladdr.su_sin6.sin6_addr)
+	  || IN6_IS_ADDR_SITELOCAL(&myctladdr.su_sin6.sin6_addr))) {
+		fprintf(stderr, "use of scoped address can be troublesome\n");
+	}
+#endif
+	if (passivemode) {
+		if (data >= 0){
+			rc = close (data);
+			data = -1;
+			if (rc == -1){
+				perror ("ftp: close");
+			}
+		}
+		data_addr = hisctladdr;
+		data = socket(data_addr.su_family, SOCK_STREAM, 0);
+		if (data < 0) {
+			perror("ftp: socket");
+			return(1);
+		}
+		if((multihome) &&
+                       bind(data, (struct sockaddr *)&source, sizeof(source)) == -1) {
+                       close(data);
+                       data = -1;
+                       perror("ftp multihome bind");
+                       return(1);
+                }
+		if (options & SO_DEBUG &&
+		    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
+			       sizeof (on)) < 0)
+			perror("ftp: setsockopt (ignored)");
+		switch (data_addr.su_family) {
+		case AF_INET:
+#if 0
+/*@*/			if (try_epsv) {
+/*@*/				result = command(pasvcmd = "EPSV 1");
+/*@*/				if (code / 10 == 22 && code != 229) {
+/*@*/					fprintf(stderr,
+/*@*/				  "wrong server: return code must be 229\n");
+/*@*/					result = COMPLETE + 1;
+/*@*/				}
+/*@*/			} else {
+#endif
+			result = COMPLETE + 1;
+
+			if (result != COMPLETE) {
+				try_epsv = 0;
+				result = command(pasvcmd = "PASV");
+			}
+			break;
+#ifdef INET6
+		case AF_INET6:
+			if (try_epsv) {
+				result = command(pasvcmd = "EPSV 2");
+				if (code / 10 == 22 && code != 229) {
+					fprintf(stderr,
+				  "wrong server: return code must be 229\n");
+					result = COMPLETE + 1;
+				}
+			} else {
+				result = COMPLETE + 1;
+			}
+			if (result != COMPLETE) {
+				try_epsv = 0;
+				result = command(pasvcmd = "LPSV");
+			}
+			break;
+#endif
+		default:
+			result = COMPLETE + 1;
+			break;
+		}
+		if (result != COMPLETE) {
+			printf("Passive mode refused.\n");
+			goto bad;
+		}
+
+#define pack2(var) \
+	(((var[0] & 0xff) << 8) | ((var[1] & 0xff) << 0))
+#define pack4(var) \
+	((((var)[0] & 0xff) << 24) | (((var)[1] & 0xff) << 16) | \
+	 (((var)[2] & 0xff) << 8) | (((var)[3] & 0xff) << 0))
+
+		/*
+		 * What we've got at this point is a string of comma separated
+		 * one-byte unsigned integer values, separated by commas.
+		 */
+		error = 0;
+		if (strcmp(pasvcmd, "PASV") == 0) {
+			if (data_addr.su_family != AF_INET) {
+				error = 2;
+				goto psv_done;
+			}
+			if (code / 10 == 22 && code != 227) {
+				error = 227;
+				goto psv_done;
+			}
+			if (sscanf(pasv, "%u,%u,%u,%u,%u,%u",
+					&ad[0], &ad[1], &ad[2], &ad[3],
+					&po[0], &po[1]) != 6) {
+				error = 1;
+				goto psv_done;
+			}
+			data_addr.su_sin.sin_addr.s_addr = htonl(pack4(ad));
+			data_addr.su_port = htons(pack2(po));
+		} else
+		    if (strcmp(pasvcmd, "LPSV") == 0) {
+			if (code / 10 == 22 && code != 228) {
+				error = 228;
+				goto psv_done;
+			}
+			switch (data_addr.su_family) {
+			case AF_INET:
+				if (sscanf(pasv, "%u,%u,%u,%u,%u,%u,%u,%u,%u",
+						&af, &alen,
+						&ad[0], &ad[1], &ad[2], &ad[3],
+						&plen, &po[0], &po[1]) != 9) {
+					error = 1;
+					goto psv_done;
+				}
+				if (af != 4 || alen != 4 || plen != 2) {
+					error = 2;
+					goto psv_done;
+				}
+				data_addr.su_sin.sin_addr.s_addr =
+							htonl(pack4(ad));
+				data_addr.su_port = htons(pack2(po));
+				break;
+#ifdef INET6
+			case AF_INET6:
+				if (sscanf(pasv,
+	"%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
+				  &af, &alen,
+				  &ad[0], &ad[1], &ad[2], &ad[3],
+				  &ad[4], &ad[5], &ad[6], &ad[7],
+				  &ad[8], &ad[9], &ad[10], &ad[11],
+				  &ad[12], &ad[13], &ad[14], &ad[15],
+				  &plen, &po[0], &po[1]) != 21) {
+					error = 1;
+					goto psv_done;
+				}
+				if (af != 6 || alen != 16 || plen != 2) {
+					error = 2;
+					goto psv_done;
+				}
+				data_addr.su_sin6.sin6_addr.s6_addr32[0] =
+							htonl(pack4(ad));
+				data_addr.su_sin6.sin6_addr.s6_addr32[1] =
+							htonl(pack4(ad+4));
+				data_addr.su_sin6.sin6_addr.s6_addr32[2] =
+							htonl(pack4(ad+8));
+				data_addr.su_sin6.sin6_addr.s6_addr32[3] =
+							htonl(pack4(ad+12));
+				data_addr.su_port = htons(pack2(po));
+				break;
+#endif
+			default:
+				error = 1;
+			}
+		} else if (strncmp(pasvcmd, "EPSV", 4) == 0) {
+			char delim[4];
+			u_int epsvpo;
+
+			if (code / 10 == 22 && code != 229) {
+				error = 229;
+				goto psv_done;
+			}
+			if (sscanf(pasv, "%c%c%c%u%c", &delim[0], &delim[1],
+					&delim[2], &epsvpo, &delim[3]) != 5) {
+				error = 1;
+				goto psv_done;
+			}
+			if (delim[0] != delim[1] || delim[0] != delim[2]
+			 || delim[0] != delim[3]) {
+				error = 1;
+				goto psv_done;
+			}
+			data_addr.su_port = htons(epsvpo);
+		} else {
+			error = 1;
+		}
+psv_done:
+		switch (error) {
+		case 0:
+			break;
+		case 1:
+			fprintf(stderr,
+		  "Passive mode address scan failure. Shouldn't happen!\n");
+			goto bad;
+		case 2:
+			fprintf(stderr,
+			  "Passive mode AF mismatch. Shouldn't happen!\n");
+			goto bad;
+		case 227:
+		case 228:
+		case 229:
+			fprintf(stderr,
+			  "wrong server: return code must be %d\n", error);
+			goto bad;
+		default:
+			fprintf(stderr, "Bug\n");
+		}
+
+		if (connect(data, (struct sockaddr *) &data_addr,
+			    (data_addr.su_family == AF_INET ?
+			     sizeof(data_addr.su_sin) :
+			     sizeof(data_addr.su_sin6)))<0) {
+			perror("ftp: connect");
+			return(1);
+		}
+#ifdef IP_TOS
+		if (data_addr.su_family == AF_INET)
+		{
+		tos = IPTOS_THROUGHPUT;
+		if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&tos,
+		    sizeof(tos)) < 0)
+			perror("ftp: 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) {
+		perror("ftp: socket");
+		if (tmpno)
+			sendport = 1;
+		return (1);
+	}
+	if (!sendport)
+		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
+			perror("ftp: setsockopt (reuse address)");
+			goto bad;
+		}
+	if (setsockopt (data, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
+                sizeof(timeout)) < 0) {
+		perror("ftp: setsockopt failed\n");
+	}
+	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
+		perror("ftp: bind");
+		goto bad;
+	}
+	if (options & SO_DEBUG &&
+	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
+		perror("ftp: setsockopt (ignored)");
+	len = sizeof (data_addr);
+	if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
+		perror("ftp: getsockname");
+		goto bad;
+	}
+	if (listen(data, 1) < 0)
+		perror("ftp: listen");
+	if (sendport) {
+		af = ex_af2prot(data_addr.su_family);
+		if (try_eprt && af > 1) {      /* only IPv6 */
+			if (getnameinfo((struct sockaddr *)&data_addr, len,
+					hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
+					NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
+				result = command("EPRT |%d|%s|%s|",
+							af, hbuf, pbuf);
+				if (result != COMPLETE) {
+					try_eprt = 0;
+				}
+			} else {
+				result = ERROR;
+			}
+		} else {
+			result = COMPLETE + 1;
+		}
+		if (result == COMPLETE)
+			goto prt_done;
+
+		p = (u_char *)&data_addr.su_port;
+		switch (data_addr.su_family) {
+		case AF_INET:
+			a = (u_char *)&data_addr.su_sin.sin_addr;
+			result = command("PORT %u,%u,%u,%u,%u,%u",
+				a[0], a[1], a[2], a[3], p[0], p[1]);
+			break;
+#ifdef INET6
+		case AF_INET6:
+			a = (u_char *)&data_addr.su_sin6.sin6_addr;
+			result = command(
+	"LPRT 6,16,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,2,%d,%d",
+				a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
+				a[8], a[9],a[10],a[11],a[12],a[13],a[14],a[15],
+				p[0], p[1]);
+			break;
+#endif
+		default:
+			result = COMPLETE + 1; /* xxx */
+		}
+
+	prt_done:
+		if (result == ERROR && sendport == -1) {
+			sendport = 0;
+			tmpno = 1;
+			goto noport;
+		}
+		return (result != COMPLETE);
+	}
+	if (tmpno)
+		sendport = 1;
+#ifdef IP_TOS
+	if (data_addr.su_family == AF_INET)
+	{
+	on = IPTOS_THROUGHPUT;
+	if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
+		perror("ftp: setsockopt TOS (ignored)");
+	}
+#endif
+	return (0);
+bad:
+	(void) close(data), data = -1;
+	if (tmpno)
+		sendport = 1;
+	return (1);
+}
+
+static FILE *
+dataconn(const char *lmode)
+{
+	union sockunion from;
+	int s, tos;
+	socklen_t fromlen = sizeof(from);
+
+        if (passivemode)
+            return (fdopen(data, lmode));
+
+	s = accept(data, (struct sockaddr *) &from, &fromlen);
+	if (s < 0) {
+		perror("ftp: accept");
+		(void) close(data), data = -1;
+		return (NULL);
+	}
+	(void) close(data);
+	data = s;
+#ifdef IP_TOS
+	if (from.su_family == AF_INET)
+	{
+	tos = IPTOS_THROUGHPUT;
+	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
+		perror("ftp: setsockopt TOS (ignored)");
+	}
+#endif
+	return (fdopen(data, lmode));
+}
+
+static void
+ptransfer(const char *direction, long long bytes, 
+	  const struct timeval *t0, 
+	  const struct timeval *t1)
+{
+	struct timeval td;
+	float s, bs;
+
+	if (verbose) {
+		tvsub(&td, t1, t0);
+		s = td.tv_sec + (td.tv_usec / 1000000.);
+#define	nz(x)	((x) == 0 ? 1 : (x))
+		bs = bytes / nz(s);
+		printf("%lld bytes %s in %.3g secs (%.2f Kbytes/sec)\n",
+		    bytes, direction, s, bs / 1000.0);
+	}
+}
+
+#if 0
+tvadd(tsum, t0)
+	struct timeval *tsum, *t0;
+{
+
+	tsum->tv_sec += t0->tv_sec;
+	tsum->tv_usec += t0->tv_usec;
+	if (tsum->tv_usec > 1000000)
+		tsum->tv_sec++, tsum->tv_usec -= 1000000;
+}
+#endif
+
+static void
+tvsub(struct timeval *tdiff, 
+      const struct timeval *t1, 
+      const struct timeval *t0)
+{
+
+	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
+	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
+	if (tdiff->tv_usec < 0)
+		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
+}
+
+static 
+void
+psabort(int ignore)
+{
+	(void)ignore;
+	abrtflag++;
+}
+
+void
+pswitch(int flag)
+{
+	void (*oldintr)(int);
+	static struct comvars {
+		int connect;
+		char name[MAXHOSTNAMELEN];
+		union sockunion mctl;
+		union sockunion hctl;
+		FILE *in;
+		FILE *out;
+		int tpe;
+		int curtpe;
+		int cpnd;
+		int sunqe;
+		int runqe;
+		int mcse;
+		int ntflg;
+		char nti[NTRANS_MAX+1];
+		char nto[NTRANS_MAX+1];
+		int mapflg;
+		char mi[MAXPATHLEN];
+		char mo[MAXPATHLEN];
+	} proxstruct, tmpstruct;
+	struct comvars *ip, *op;
+
+	abrtflag = 0;
+	oldintr = signal(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) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
+		ip->name[sizeof(ip->name) - 1] = '\0';
+	} 
+	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) strncpy(ip->nti, ntin, NTRANS_MAX);
+	(ip->nti)[NTRANS_MAX] = '\0';		/* shouldn't use strlen */
+	(void) strcpy(ntin, op->nti);
+	(void) strncpy(ip->nto, ntout, NTRANS_MAX);
+	(ip->nto)[NTRANS_MAX] = '\0';
+	(void) strcpy(ntout, op->nto);
+	ip->mapflg = mapflag;
+	mapflag = op->mapflg;
+	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
+	(ip->mi)[MAXPATHLEN - 1] = '\0';
+	(void) strcpy(mapin, op->mi);
+	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
+	(ip->mo)[MAXPATHLEN - 1] = '\0';
+	(void) strcpy(mapout, op->mo);
+	(void) signal(SIGINT, oldintr);
+	if (abrtflag) {
+		abrtflag = 0;
+		(*oldintr)(SIGINT);
+	}
+}
+
+static
+void
+abortpt(int ignore)
+{
+	(void)ignore;
+	printf("\n");
+	fflush(stdout);
+	ptabflg++;
+	mflag = 0;
+	abrtflag = 0;
+	siglongjmp(ptabort, 1);
+}
+
+static void
+proxtrans(const char *cmd, char *local, char *remote)
+{
+	void (*volatile oldintr)(int);
+	volatile int secndflag = 0, prox_type, nfnd;
+	const char *volatile cmd2;
+	fd_set mask;
+
+	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) {
+		printf("proxy server does not support third party transfers.\n");
+		return;
+	}
+	pswitch(0);
+	if (!connected) {
+		printf("No primary connection\n");
+		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 = signal(SIGINT, abortpt);
+	if (command("%s %s", cmd, remote) != PRELIM) {
+		(void) signal(SIGINT, oldintr);
+		pswitch(1);
+		return;
+	}
+	sleep(2);
+	pswitch(1);
+	secndflag++;
+	if (command("%s %s", cmd2, local) != PRELIM)
+		goto abort;
+	ptflag++;
+	(void) getreply(0);
+	pswitch(0);
+	(void) getreply(0);
+	(void) signal(SIGINT, oldintr);
+	pswitch(1);
+	ptflag = 0;
+	printf("local: %s remote: %s\n", local, remote);
+	return;
+abort:
+	(void) signal(SIGINT, SIG_IGN);
+	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((FILE *) NULL);
+		}
+		pswitch(1);
+		if (ptabflg)
+			code = -1;
+		(void) signal(SIGINT, oldintr);
+		return;
+	}
+	if (cpend)
+		abort_remote((FILE *) 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((FILE *) NULL);
+			pswitch(1);
+			if (ptabflg)
+				code = -1;
+			(void) signal(SIGINT, oldintr);
+			return;
+		}
+	}
+	if (cpend)
+		abort_remote((FILE *) NULL);
+	pswitch(!proxy);
+	if (cpend) {
+		FD_ZERO(&mask);
+		FD_SET(fileno(cin), &mask);
+		if ((nfnd = empty(&mask, fileno(cin), 10)) <= 0) {
+			if (nfnd < 0) {
+				perror("abort");
+			}
+			if (ptabflg)
+				code = -1;
+			lostpeer(0);
+			if(cout != NULL)
+			{
+				fclose(cout);
+				cout = NULL;
+			}
+		}
+		(void) getreply(0);
+		(void) getreply(0);
+	}
+	if (proxy)
+		pswitch(0);
+	pswitch(1);
+	if (ptabflg)
+		code = -1;
+	(void) signal(SIGINT, oldintr);
+}
+
+void
+reset(void)
+{
+	fd_set mask;
+	int nfnd = 1;
+
+	FD_ZERO(&mask);
+	while (nfnd > 0) {
+		FD_SET(fileno(cin), &mask);
+		if ((nfnd = empty(&mask, fileno(cin), 0)) < 0) {
+			perror("reset");
+			code = -1;
+			lostpeer(0);
+			if(cout != NULL)
+			{
+				fclose(cout);
+				cout = NULL;
+			}
+		}
+		else if (nfnd) {
+			(void) getreply(0);
+		}
+	}
+}
+
+static char *
+gunique(char *local)
+{
+	static char new[MAXPATHLEN];
+	char *cp = rindex(local, '/');
+	int d, count=0;
+	char ext = '1';
+
+	if (cp)
+		*cp = '\0';
+	d = access(cp ? local : ".", W_OK);
+	if (cp)
+		*cp = '/';
+	if (d < 0) {
+		fprintf(stderr, "local: %s: %s\n", local, strerror(errno));
+		return((char *) 0);
+	}
+	(void) strcpy(new, local);
+	cp = new + strlen(new);
+	*cp++ = '.';
+	while (!d) {
+		if (++count == 100) {
+			printf("runique: can't find unique file name.\n");
+			return((char *) 0);
+		}
+		*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);
+}
+
+static void
+abort_remote(FILE *din)
+{
+	char buf[BUFSIZ];
+	int nfnd, hifd;
+	fd_set mask;
+
+	/*
+	 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
+	 * after urgent byte rather than before as is protocol now
+	 */
+	snprintf(buf, sizeof(buf), "%c%c%c", IAC, IP, IAC);
+	if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
+		perror("abort");
+	fprintf(cout,"%cABOR\r\n", DM);
+	(void) fflush(cout);
+	FD_ZERO(&mask);
+	FD_SET(fileno(cin), &mask);
+	hifd = fileno(cin);
+	if (din) { 
+		FD_SET(fileno(din), &mask);
+		if (hifd < fileno(din)) hifd = fileno(din);
+	}
+	if ((nfnd = empty(&mask, hifd, 10)) <= 0) {
+		if (nfnd < 0) {
+			perror("abort");
+		}
+		if (ptabflg)
+			code = -1;
+		lostpeer(0);
+		if(cout != NULL)
+		{
+			fclose(cout);
+			cout = NULL;
+		}
+	}
+	if (din && FD_ISSET(fileno(din), &mask)) {
+		while (read(fileno(din), buf, BUFSIZ) > 0)
+			/* LOOP */;
+	}
+	if (getreply(0) == ERROR && code == 552) {
+		/* 552 needed for nic style abort */
+		(void) getreply(0);
+	}
+	(void) getreply(0);
+}
Index: netkit-ftp-0.17-new/ftp/ftp_var.h
===================================================================
--- netkit-ftp-0.17-new/ftp/ftp_var.h	(nonexistent)
+++ netkit-ftp-0.17-new/ftp/ftp_var.h	(revision 5)
@@ -0,0 +1,167 @@
+/* $USAGI$ */
+
+/*
+ * Copyright (c) 1985, 1989 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.
+ *
+ *	from: @(#)ftp_var.h	5.9 (Berkeley) 6/1/90
+ *	$Id: ftp_var.h,v 1.3 2001/01/12 21:36:27 sekiya Exp $
+ */
+
+/*
+ * FTP global variables.
+ */
+
+#include <setjmp.h>
+#include <sys/param.h>
+#define NTRANS_MAX	64
+
+/*
+ * Tick counter step size.
+ */
+#define TICKBYTES     10240
+
+#ifndef Extern
+#define Extern extern
+#endif
+
+#define LINELEN PATH_MAX+200
+
+/*
+ * Options and other state info.
+ */
+Extern int	rl_inhibit;	/* disable readline support */
+Extern int	traceflag;	/* trace packets exchanged */
+Extern int	hash;		/* print # for each buffer transferred */
+Extern int	tick;		/* print byte counter during transfers */
+Extern int	sendport;	/* use PORT cmd for each data connection */
+Extern int	verbose;	/* print messages coming back from server */
+Extern int	connected;	/* connected to server */
+Extern int	fromatty;	/* input is from a terminal */
+Extern int	interactive;	/* interactively prompt on m* cmds */
+Extern int	debug;		/* debugging level */
+Extern int	bell;		/* ring bell on cmd completion */
+Extern int	doglob;		/* glob local file names */
+Extern int	autologin;	/* establish user account on connection */
+Extern int	multihome;	/* multi homed host, use same interface for cmd and data channels */
+Extern int	proxy;		/* proxy server connection active */
+Extern int	proxflag;	/* proxy connection exists */
+Extern int	sunique;	/* store files on server with unique name */
+Extern int	runique;	/* store local files with unique name */
+Extern int	mcase;		/* map upper to lower case for mget names */
+Extern int	ntflag;		/* use ntin ntout tables for name xlation */
+Extern int	mapflag;	/* use mapin mapout templates on file names */
+Extern int	code;		/* return/reply code for ftp command */
+Extern int	crflag;		/* if 1, strip car. rets. on ascii gets */
+Extern char     pasv[64];       /* passive port for proxy data connection */
+Extern int      passivemode;    /* passive mode enabled */
+Extern char	*altarg;	/* argv[1] with no shell-like preprocessing  */
+Extern char	ntin[NTRANS_MAX+1];	/* input translation table */
+Extern char	ntout[NTRANS_MAX+1];	/* output translation table */
+Extern char	mapin[MAXPATHLEN];	/* input map template */
+Extern char	mapout[MAXPATHLEN];	/* output map template */
+Extern char	typename[32];		/* name of file transfer type */
+Extern int	type;			/* requested file transfer type */
+Extern int	curtype;		/* current file transfer type */
+Extern char	structname[32];		/* name of file transfer structure */
+Extern int	stru;			/* file transfer structure */
+Extern char	formname[32];		/* name of file transfer format */
+Extern int	form;			/* file transfer format */
+Extern char	modename[32];		/* name of file transfer mode */
+Extern int	mode;			/* file transfer mode */
+Extern char	bytename[32];		/* local byte size in ascii */
+Extern int	bytesize;		/* local byte size in binary */
+
+Extern char	*hostname;	/* name of host connected to */
+Extern int	unix_server;	/* server is unix, can use binary for ascii */
+Extern int	unix_proxy;	/* proxy is unix, can use binary for ascii */
+
+/*Extern struct	servent *sp;*/	/* service spec for tcp/ftp */
+Extern int	ftp_port;	/* htons'd port number for ftp service */
+
+Extern sigjmp_buf toplevel;	/* non-local goto stuff for cmd scanner */
+
+Extern char	line[LINELEN];	/* input line buffer */
+Extern char	*stringbase;	/* current scan point in line buffer */
+Extern char	argbuf[LINELEN];	/* argument storage buffer */
+Extern char	*argbase;	/* current storage point in arg buffer */
+Extern int	cpend;		/* flag: if != 0, then pending server reply */
+Extern int	mflag;		/* flag: if != 0, then active multi command */
+
+Extern int	options;	/* used during socket creation */
+Extern int	try_epsv;	/* try EPSV for this session */
+Extern int	try_eprt;	/* try EPRT for this session */
+
+/*
+ * Format of command table.
+ */
+struct cmd {
+	const char *c_name;	/* name of command */
+	const char *c_help;	/* help string */
+	char c_bell;		/* give bell when command completes */
+	char c_conn;		/* must be connected to use command */
+	char c_proxy;		/* proxy server may execute */
+
+        /* Exactly one of these should be non-NULL. */
+	void (*c_handler_v)(int, char **); /* function to call */
+	void (*c_handler_0)(void);
+	void (*c_handler_1)(const char *);
+};
+
+struct macel {
+	char mac_name[9];	/* macro name */
+	char *mac_start;	/* start of macro in macbuf */
+	char *mac_end;		/* end of macro in macbuf */
+};
+
+Extern int macnum;			/* number of defined macros */
+Extern struct macel macros[16];
+Extern char macbuf[4096];
+#define MACBUF_SIZE 4096
+
+char *hookup(const char *host, const char *port);
+struct cmd *getcmd(const char *);
+char **makeargv(int *pargc, char **parg);
+int dologin(const char *host);
+int command(const char *fmt, ...);
+void sendrequest(const char *cmd, char *local, char *remote, int printnames);
+void recvrequest(const char *cmd, char *local, char *remote, 
+		 const char *lmode, int printnames);
+int another(int *pargc, char ***pargv, const char *prompt);
+void blkfree(char **av0);
+void fatal(const char *msg);
+int getreply(int expecteof);
+void domacro(int argc, char *argv[]);
+void pswitch(int flag);
+int xruserpass(const char *host, char **aname, char **apass, char **aacct);
+void setpeer(int argc, char *argv[]);
+void quit(void);
+void changetype(int newtype, int show);
Index: netkit-ftp-0.17-new/ftp/glob.c
===================================================================
--- netkit-ftp-0.17-new/ftp/glob.c	(nonexistent)
+++ netkit-ftp-0.17-new/ftp/glob.c	(revision 5)
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 1980 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.
+ */
+
+/*
+ * From: @(#)glob.c	5.9 (Berkeley) 2/25/91
+ */
+char glob_rcsid[] = 
+  "$Id: glob.c,v 1.9 1999/10/02 13:25:23 netbug Exp $";
+
+/*
+ * C-shell glob for random programs.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include <pwd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ftp_var.h"  /* for protos only */
+#include "glob.h"
+
+#define	QUOTE 0200
+#define	TRIM 0177
+#define	eq(a,b)		(strcmp(a, b)==0)
+#define	GAVSIZ		(sysconf(_SC_ARG_MAX)/6)
+#define	isdir(d)	((d.st_mode & S_IFMT) == S_IFDIR)
+
+const char *globerr;
+extern const char *home;
+
+typedef struct {
+    const char *text;
+} centry;
+
+typedef struct {
+    char *text;
+} entry;
+
+static entry *gargv;	/* Pointer to the (stack) arglist */
+static entry *sortbas;
+static int gargc;	/* Number args in gargv */
+static int gnleft;      /* space left before we hit max args length */
+
+static short gflag;
+
+static int globcnt;
+static const char *globchars = "`{[*?";
+
+static char *gpath;
+static char *gpathp, *lastgpathp;
+static int globbed;
+static const char *entp;
+
+static int tglob(char c);
+static char *strspl(const char *, const char *);
+static char *strend(char *);
+static char **copyblk(entry *);
+static char **cloneblk(const centry *);
+
+static void addpath(char c);
+static void acollect(const char *);
+static void collect(const char *);
+static void expand(const char *);
+static void Gcat(const char *, const char *);
+static void ginit(entry *);
+static void matchdir(const char *);
+static void rscan(centry *, int (*f)(char));
+static void sort(void);
+static void efree(entry *);
+static int amatch(const char *, const char *);
+static int execbrc(const char *, const char *);
+static int match(const char *, const char *);
+
+static int gethdir(char *homedir);
+static int letter(char c);
+static int digit(char c);
+static int any(int c, const char *s);
+
+char **
+ftpglob(const char *v)
+{
+	char agpath[BUFSIZ];
+	entry *agargv;
+	centry vv[2];
+	vv[0].text = v;
+	vv[1].text = NULL;
+	gflag = 0;
+	rscan(vv, tglob);
+	if (gflag == 0) {
+		return cloneblk(vv);
+	}
+
+	globerr = 0;
+
+	gpath = agpath; 
+	gpathp = gpath; 
+	*gpathp = 0;
+	/* added ()'s to sizeof, (ambigious math for the compiler) */
+	lastgpathp = agpath + (sizeof(agpath)- 2);
+
+	agargv = (entry *)malloc(sizeof (entry) * GAVSIZ);
+	if (agargv == NULL) fatal("Out of memory");
+	ginit(agargv); 
+	globcnt = 0;
+	collect(v);
+	if (globcnt == 0 && (gflag&1)) {
+		efree(gargv);
+		gargv = NULL;
+		return NULL;
+	} 
+	else {
+		char **rv = copyblk(gargv);
+		gargv = NULL;
+		return rv;
+	}
+}
+
+static 
+void
+ginit(entry *agargv)
+{
+	agargv[0].text = NULL; 
+	gargv = agargv; 
+	sortbas = agargv; 
+	gargc = 0;
+	gnleft = sysconf(_SC_ARG_MAX) - 4;
+}
+
+static 
+void
+collect(const char *as)
+{
+	if (eq(as, "{") || eq(as, "{}")) {
+		Gcat(as, "");
+		sort();
+	} 
+	else {
+		acollect(as);
+	}
+}
+
+static 
+void
+acollect(const char *as)
+{
+	int ogargc = gargc;
+
+	gpathp = gpath; *gpathp = 0; globbed = 0;
+	expand(as);
+	if (gargc != ogargc)
+		sort();
+}
+
+static 
+void
+sort(void)
+{
+	entry *p1, *p2, c;
+	entry *Gvp = &gargv[gargc];
+
+	p1 = sortbas;
+	while (p1 < Gvp-1) {
+		p2 = p1;
+		while (++p2 < Gvp)
+			if (strcmp(p1->text, p2->text) > 0)
+				c = *p1, *p1 = *p2, *p2 = c;
+		p1++;
+	}
+	sortbas = Gvp;
+}
+
+static 
+void
+expand(const char *as)
+{
+	const char *cs;
+	const char *oldcs;
+	char *sgpathp;
+	struct stat stb;
+
+	sgpathp = gpathp;
+	cs = as;
+	if (*cs == '~' && gpathp == gpath) {
+		addpath('~');
+		for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
+			addpath(*cs++);
+		if (!*cs || *cs == '/') {
+			if (gpathp != gpath + 1) {
+				*gpathp = 0;
+				if (gethdir(gpath + 1))
+					globerr = "Unknown user name after ~";
+				/*
+				 * Was: strcpy(gpath, gpath + 1);
+				 * but that's WRONG
+				 */
+				memmove(gpath, gpath+1, strlen(gpath+1)+1);
+			} 
+			else {
+				(void) strcpy(gpath, home);
+			}
+			gpathp = strend(gpath);
+		}
+	}
+	while (!any(*cs, globchars)) {
+		if (*cs == 0) {
+			if (!globbed)
+				Gcat(gpath, "");
+			else if (stat(gpath, &stb) >= 0) {
+				Gcat(gpath, "");
+				globcnt++;
+			}
+			goto endit;
+		}
+		addpath(*cs++);
+	}
+	oldcs = cs;
+	while (cs > as && *cs != '/')
+		cs--, gpathp--;
+	if (*cs == '/')
+		cs++, gpathp++;
+	*gpathp = 0;
+	if (*oldcs == '{') {
+		(void) execbrc(cs, ((char *)0));
+		return;
+	}
+	matchdir(cs);
+endit:
+	gpathp = sgpathp;
+	*gpathp = 0;
+}
+
+static 
+void
+matchdir(const char *pattern)
+{
+	struct stat stb;
+	register struct dirent *dp;
+	DIR *dirp;
+
+#if 0
+#ifdef	__linux__
+	if (gpath == NULL || *gpath == '\0')
+		gpath = "./";
+#endif
+#endif
+	dirp = opendir((!gpath || !*gpath) ? "./" : gpath);
+	if (dirp == NULL) {
+		if (globbed)
+			return;
+		goto patherr2;
+	}
+	if (fstat(dirfd(dirp), &stb) < 0)
+		goto patherr1;
+	if (!isdir(stb)) {
+		errno = ENOTDIR;
+		goto patherr1;
+	}
+	while ((dp = readdir(dirp)) != NULL) {
+		if (dp->d_ino == 0)
+			continue;
+		if (match(dp->d_name, pattern)) {
+			Gcat(gpath, dp->d_name);
+			globcnt++;
+		}
+	}
+	closedir(dirp);
+	return;
+
+patherr1:
+	closedir(dirp);
+patherr2:
+	globerr = "Bad directory components";
+}
+
+static 
+int
+execbrc(const char *p, const char *s)
+{
+	char restbuf[BUFSIZ + 2];
+	const char *pe, *pm, *pl;
+	int brclev = 0;
+	char *lm, *sgpathp;
+
+	for (lm = restbuf; *p != '{'; *lm++ = *p++)
+		continue;
+	for (pe = ++p; *pe; pe++)
+	switch (*pe) {
+
+	case '{':
+		brclev++;
+		continue;
+
+	case '}':
+		if (brclev == 0)
+			goto pend;
+		brclev--;
+		continue;
+
+	case '[':
+		for (pe++; *pe && *pe != ']'; pe++)
+			continue;
+		continue;
+	}
+pend:
+	brclev = 0;
+	for (pl = pm = p; pm <= pe; pm++)
+	switch (*pm & (QUOTE|TRIM)) {
+
+	case '{':
+		brclev++;
+		continue;
+
+	case '}':
+		if (brclev) {
+			brclev--;
+			continue;
+		}
+		goto doit;
+
+	case ','|QUOTE:
+	case ',':
+		if (brclev)
+			continue;
+doit:
+#if 0
+		savec = *pm;
+		*pm = 0;
+		strcpy(lm, pl);
+		*pm = savec;
+#else
+		strncpy(lm, pl, pm-pl);
+		lm[pm-pl] = 0;
+#endif
+		(void) strcat(restbuf, pe + 1);
+		if (s == 0) {
+			sgpathp = gpathp;
+			expand(restbuf);
+			gpathp = sgpathp;
+			*gpathp = 0;
+		} 
+		else if (amatch(s, restbuf)) {
+			return (1);
+		}
+		sort();
+		pl = pm + 1;
+		if (brclev)
+			return (0);
+		continue;
+
+	case '[':
+		for (pm++; *pm && *pm != ']'; pm++)
+			continue;
+		if (!*pm)
+			pm--;
+		continue;
+	}
+	if (brclev)
+		goto doit;
+	return (0);
+}
+
+static 
+int
+match(const char *s, const char *p)
+{
+	int c;
+	const char *sentp;
+	char sglobbed = globbed;
+
+	if (*s == '.' && *p != '.')
+		return (0);
+	sentp = entp;
+	entp = s;
+	c = amatch(s, p);
+	entp = sentp;
+	globbed = sglobbed;
+	return (c);
+}
+
+static 
+int
+amatch(const char *s, const char *p)
+{
+	register int scc;
+	int ok, lc;
+	char *sgpathp;
+	struct stat stb;
+	int c, cc;
+
+	globbed = 1;
+	for (;;) {
+		scc = *s++ & TRIM;
+		switch (c = *p++) {
+
+		case '{':
+			return (execbrc(p - 1, s - 1));
+
+		case '[':
+			ok = 0;
+			lc = 077777;
+			while ((cc = *p++) != 0) {
+				if (cc == ']') {
+					if (ok)
+						break;
+					return (0);
+				}
+				if (cc == '-') {
+					if (lc <= scc && scc <= *p++)
+						ok++;
+				} else
+					if (scc == (lc = cc))
+						ok++;
+			}
+			if (cc == 0) {
+				if (ok)
+					p--;
+				else
+					return 0;
+			}
+			continue;
+
+		case '*':
+			if (!*p)
+				return (1);
+			if (*p == '/') {
+				p++;
+				goto slash;
+			}
+			s--;
+			do {
+				if (amatch(s, p))
+					return (1);
+			} while (*s++);
+			return (0);
+
+		case 0:
+			return (scc == 0);
+
+		default:
+			if (c != scc)
+				return (0);
+			continue;
+
+		case '?':
+			if (scc == 0)
+				return (0);
+			continue;
+
+		case '/':
+			if (scc)
+				return (0);
+slash:
+			s = entp;
+			sgpathp = gpathp;
+			while (*s)
+				addpath(*s++);
+			addpath('/');
+			if (stat(gpath, &stb) == 0 && isdir(stb)) {
+				if (*p == 0) {
+					Gcat(gpath, "");
+					globcnt++;
+				} else {
+					expand(p);
+				}
+			}
+			gpathp = sgpathp;
+			*gpathp = 0;
+			return (0);
+		}
+	}
+}
+
+#if 0 /* dead code */
+static 
+int
+Gmatch(const char *s, const char *p)
+{
+	register int scc;
+	int ok, lc;
+	int c, cc;
+
+	for (;;) {
+		scc = *s++ & TRIM;
+		switch (c = *p++) {
+
+		case '[':
+			ok = 0;
+			lc = 077777;
+			while ((cc = *p++) != 0) {
+				if (cc == ']') {
+					if (ok)
+						break;
+					return (0);
+				}
+				if (cc == '-') {
+					if (lc <= scc && scc <= *p++)
+						ok++;
+				} else
+					if (scc == (lc = cc))
+						ok++;
+			}
+			if (cc == 0)
+				if (ok)
+					p--;
+				else
+					return 0;
+			continue;
+
+		case '*':
+			if (!*p)
+				return (1);
+			for (s--; *s; s++)
+				if (Gmatch(s, p))
+					return (1);
+			return (0);
+
+		case 0:
+			return (scc == 0);
+
+		default:
+			if ((c & TRIM) != scc)
+				return (0);
+			continue;
+
+		case '?':
+			if (scc == 0)
+				return (0);
+			continue;
+
+		}
+	}
+}
+#endif
+
+static 
+void
+Gcat(const char *s1, const char *s2)
+{
+	int len = strlen(s1) + strlen(s2) + 1;
+
+	if (len >= gnleft || gargc >= GAVSIZ - 1) {
+		globerr = "Arguments too long";
+	}
+	else {
+		gargc++;
+		gnleft -= len;
+		gargv[gargc].text = NULL;
+		gargv[gargc - 1].text = strspl(s1, s2);
+	}
+}
+
+static 
+void
+addpath(char c)
+{
+
+	if (gpathp >= lastgpathp)
+		globerr = "Pathname too long";
+	else {
+		*gpathp++ = c;
+		*gpathp = 0;
+	}
+}
+
+static void
+rscan(centry *t, int (*f)(char))
+{
+	const char *p;
+	char c;
+
+	while ((p = (t++)->text) != NULL) {
+		if (f == tglob) {
+			if (*p == '~')
+				gflag |= 2;
+			else if (eq(p, "{") || eq(p, "{}"))
+				continue;
+		}
+		while ((c = *p++) != 0)
+			(*f)(c);
+	}
+}
+
+static 
+int
+tglob(char c)
+{
+
+	if (any(c, globchars))
+		gflag |= c == '{' ? 2 : 1;
+	return (c);
+}
+
+static int
+letter(char c)
+{
+	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
+}
+
+static int
+digit(char c)
+{
+	return (c >= '0' && c <= '9');
+}
+
+static 
+int
+any(int c, const char *s)
+{
+	while (*s) if (*s++ == c) return 1;
+	return 0;
+}
+
+static 
+int
+cblklen(const centry *av)
+{
+	int i = 0;
+	while ((av++)->text) i++;
+	return i;
+}
+
+static 
+int
+blklen(const entry *av)
+{
+	int i = 0;
+	while ((av++)->text) i++;
+	return i;
+}
+
+void
+blkfree(char **av)
+{
+	int i;
+	for (i=0; av[i]; i++) free(av[i]);
+}
+
+static
+void 
+efree(entry *av) 
+{
+    int i;
+    for (i=0; av[i].text; i++) free(av[i].text);
+    free((void *)av);
+}
+
+static
+char *
+strspl(const char *cp, const char *dp)
+{
+	char *ep = malloc(strlen(cp) + strlen(dp) + 1);
+	if (ep == NULL)	fatal("Out of memory");
+
+	strcpy(ep, cp);
+	strcat(ep, dp);
+	return ep;
+}
+
+static 
+char **
+copyblk(entry *v)
+{
+	int i;
+	char **nv = malloc((blklen(v) + 1) * sizeof(char **));
+	if (nv == NULL) fatal("Out of memory");
+
+	for (i=0; v[i].text; i++) {
+	    nv[i] = v[i].text;
+	    v[i].text = NULL;
+	}
+	nv[i] = NULL;
+
+	return nv;
+}
+
+static
+char **
+cloneblk(const centry *v)
+{
+	int i;
+	char **nv = malloc((cblklen(v) + 1) * sizeof(char **));
+	if (nv == NULL) fatal("Out of memory");
+
+	for (i=0; v[i].text; i++) {
+	    nv[i] = strdup(v[i].text);
+	}
+	nv[i] = NULL;
+
+	return nv;
+}
+
+static
+char *
+strend(char *cp)
+{
+	while (*cp)
+		cp++;
+	return (cp);
+}
+/*
+ * Extract a home directory from the password file
+ * The argument points to a buffer where the name of the
+ * user whose home directory is sought is currently.
+ * We write the home directory of the user back there.
+ *
+ * XXX, this needs buffer length checking and stuff.
+ */
+static 
+int
+gethdir(char *homedir)
+{
+	register struct passwd *pp = getpwnam(homedir);
+
+	if (!pp || homedir + strlen(pp->pw_dir) >= lastgpathp)
+		return 1;
+	strcpy(homedir, pp->pw_dir);
+	return 0;
+}
Index: netkit-ftp-0.17-new/ftp/main.c
===================================================================
--- netkit-ftp-0.17-new/ftp/main.c	(nonexistent)
+++ netkit-ftp-0.17-new/ftp/main.c	(revision 5)
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c) 1985, 1989 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.
+ */
+
+char copyright[] =
+  "@(#) Copyright (c) 1985, 1989 Regents of the University of California.\n"
+  "All rights reserved.\n";
+
+/*
+ * from: @(#)main.c	5.18 (Berkeley) 3/1/91
+ */
+char main_rcsid[] = 
+  "$Id: main.c,v 1.15 1999/10/02 13:25:23 netbug Exp $";
+
+
+/*
+ * FTP User Program -- Command Interface.
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+/* #include <arpa/ftp.h>	<--- unused? */
+
+#include <locale.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <pwd.h>
+#ifdef	__USE_READLINE__
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+
+#define Extern
+#include "ftp_var.h"
+int traceflag = 0;
+const char *home = "/";
+
+extern FILE *cout;
+extern int data;
+extern struct cmd cmdtab[];
+extern int NCMDS;
+
+void intr(int);
+void lostpeer(int);
+void help(int argc, char *argv[]);
+
+static void cmdscanner(int top);
+static char *slurpstring(void);
+
+static
+void
+usage(void)
+{
+	printf("\n\tUsage: { ftp | pftp } [-Apinegvtd] [hostname]\n");
+	printf("\t   -A: enable active mode\n");
+	printf("\t   -p: enable passive mode (default for ftp and pftp)\n");
+	printf("\t   -i: turn off prompting during mget\n");
+	printf("\t   -n: inhibit auto-login\n");
+	printf("\t   -e: disable readline support, if present\n");
+	printf("\t   -g: disable filename globbing\n");
+	printf("\t   -m: don't force data channel interface to the same as control channel\n");
+	printf("\t   -v: verbose mode\n");
+	printf("\t   -t: enable packet tracing [nonfunctional]\n");
+	printf("\t   -d: enable debugging\n");
+	printf("\n");
+}
+
+int
+main(volatile int argc, char **volatile argv)
+{
+	register char *cp;
+	struct servent *sp;
+	int top;
+	struct passwd *pw = NULL;
+	char homedir[MAXPATHLEN];
+
+	tick = 0;
+
+	setlocale (LC_ALL, "");
+	sp = getservbyname("ftp", "tcp");
+	if (sp == 0) {
+		fprintf(stderr, "ftp: ftp/tcp: unknown service\n");
+		exit(1);
+	}
+	ftp_port = sp->s_port;
+	doglob = 1;
+	interactive = 1;
+	autologin = 1;
+	multihome = 1;
+	passivemode = 1;
+
+        cp = strrchr(argv[0], '/');
+        cp = (cp == NULL) ? argv[0] : cp+1;
+        if (strcmp(cp, "pftp") == 0)
+            passivemode = 1;
+
+#ifdef __USE_READLINE__
+	/* 
+	 * Set terminal type so libreadline can parse .inputrc correctly
+	 */
+	rl_terminal_name = getenv("TERM");
+#endif
+
+	argc--, argv++;
+	while (argc > 0 && **argv == '-') {
+		for (cp = *argv + 1; *cp; cp++)
+			switch (*cp) {
+
+			case 'd':
+				options |= SO_DEBUG;
+				debug++;
+				break;
+			
+			case 'v':
+				verbose++;
+				break;
+
+			case 't':
+				traceflag++;
+				break;
+
+			case 'i':
+				interactive = 0;
+				break;
+
+			case 'n':
+				autologin = 0;
+				break;
+
+			case 'p':
+				passivemode = 1;
+				break;
+
+			case 'A':
+				passivemode = 0;
+				break;
+
+			case 'g':
+				doglob = 0;
+				break;
+				
+			case 'e':
+				rl_inhibit = 1;
+				break;
+				
+			case 'm':
+				multihome = 0;
+				break;
+
+			case 'h':
+				usage();
+				exit(0);
+
+			default:
+				fprintf(stdout,
+				  "ftp: %c: unknown option\n", *cp);
+				exit(1);
+			}
+		argc--, argv++;
+	}
+	fromatty = isatty(fileno(stdin));
+	if (fromatty)
+		verbose++;
+	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.
+	 */
+	pw = getpwuid(getuid());
+	if (pw != NULL) {
+		strncpy(homedir, pw->pw_dir, sizeof(homedir));
+		homedir[sizeof(homedir)-1] = 0;
+		home = homedir;
+	}
+	if (argc > 0) {
+		if (sigsetjmp(toplevel, 1))
+			exit(0);
+		(void) signal(SIGINT, intr);
+		(void) signal(SIGPIPE, lostpeer);
+		setpeer(argc + 1, argv - 1);
+	}
+	top = sigsetjmp(toplevel, 1) == 0;
+	if (top) {
+		(void) signal(SIGINT, intr);
+		(void) signal(SIGPIPE, lostpeer);
+	}
+	for (;;) {
+		cmdscanner(top);
+		top = 1;
+	}
+}
+
+void
+intr(int ignore)
+{
+	(void)ignore;
+	siglongjmp(toplevel, 1);
+}
+
+void
+lostpeer(int ignore)
+{
+	(void)ignore;
+
+	if (connected) {
+		if (cout != NULL) {
+			shutdown(fileno(cout), 1+1);
+		}
+		if (data >= 0) {
+			shutdown(data, 1+1);
+			close(data);
+			data = -1;
+		}
+		connected = 0;
+	}
+	pswitch(1);
+	if (connected) {
+		if (cout != NULL) {
+			shutdown(fileno(cout), 1+1);
+		}
+		connected = 0;
+	}
+	proxflag = 0;
+	pswitch(0);
+}
+
+/*char *
+tail(filename)
+	char *filename;
+{
+	register char *s;
+	
+	while (*filename) {
+		s = rindex(filename, '/');
+		if (s == NULL)
+			break;
+		if (s[1])
+			return (s + 1);
+		*s = '\0';
+	}
+	return (filename);
+}
+*/
+
+static char *get_input_line(char *buf, int buflen)
+{
+#ifdef __USE_READLINE__
+	if (fromatty && !rl_inhibit) {
+		char *lineread = readline("ftp> ");
+		if (!lineread) return NULL;
+		strncpy(buf, lineread, buflen);
+		buf[buflen-1] = 0;
+		if (lineread[0]) add_history(lineread);
+		free(lineread);
+		return buf;
+	}
+#endif
+	if (fromatty) {
+		printf("ftp> ");
+		fflush(stdout);
+	}
+	return fgets(buf, buflen, stdin);
+}
+
+
+/*
+ * Command parser.
+ */
+static void
+cmdscanner(int top)
+{
+	int margc;
+	char *marg;
+	char **margv;
+	register struct cmd *c;
+	register int l;
+
+	if (!top)
+		(void) putchar('\n');
+	for (;;) {
+		if (!get_input_line(line, sizeof(line))) {
+			quit();
+		}
+		l = strlen(line);
+		if (l == 0)
+			break;
+		if (line[--l] == '\n') {
+			if (l == 0)
+				break;
+			line[l] = '\0';
+		} 
+		else if (l == sizeof(line) - 2) {
+			printf("sorry, input line too long\n");
+			while ((l = getchar()) != '\n' && l != EOF)
+				/* void */;
+			break;
+		} /* else it was a line without a newline */
+		margv = makeargv(&margc, &marg);
+		if (margc == 0) {
+			continue;
+		}
+		c = getcmd(margv[0]);
+		if (c == (struct cmd *)-1) {
+			printf("?Ambiguous command\n");
+			continue;
+		}
+		if (c == NULL) {
+			printf("?Invalid command\n");
+			continue;
+		}
+		if (c->c_conn && !connected) {
+			printf("Not connected.\n");
+			continue;
+		}
+		if (c->c_handler_v) c->c_handler_v(margc, margv);
+		else if (c->c_handler_0) c->c_handler_0();
+		else c->c_handler_1(marg);
+
+		if (bell && c->c_bell) putchar('\007');
+		if (c->c_handler_v != help)
+			break;
+	}
+	(void) signal(SIGINT, intr);
+	(void) signal(SIGPIPE, lostpeer);
+}
+
+struct cmd *
+getcmd(const char *name)
+{
+	const char *p, *q;
+	struct cmd *c, *found;
+	int nmatches, longest;
+
+	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;
+
+char **
+makeargv(int *pargc, char **parg)
+{
+	static char *rargv[20];
+	int rargc = 0;
+	char **argp;
+
+	argp = rargv;
+	stringbase = line;		/* scan from first of buffer */
+	argbase = argbuf;		/* store from first of buffer */
+	slrflag = 0;
+	while ((*argp++ = slurpstring())!=NULL)
+		rargc++;
+
+	*pargc = rargc;
+	if (parg) *parg = altarg;
+	return rargv;
+}
+
+/*
+ * Parse string into argbuf;
+ * implemented with FSM to
+ * handle quoting and strings
+ */
+static
+char *
+slurpstring(void)
+{
+	static char excl[] = "!", dols[] = "$";
+
+	int got_one = 0;
+	register char *sb = stringbase;
+	register 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++;
+				stringbase++;
+				return ((*sb == '!') ? excl : dols);
+				/* NOTREACHED */
+			case 1:
+				slrflag++;
+				altarg = stringbase;
+				break;
+			default:
+				break;
+		}
+	}
+
+S0:
+	switch (*sb) {
+
+	case '\0':
+		goto OUT;
+
+	case ' ':
+	case '\t':
+		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 '\\':
+		sb++; goto S2;	/* slurp next character */
+
+	case '"':
+		sb++; goto S3;	/* slurp quoted string */
+
+	default:
+		*ap++ = *sb++;	/* add character to token */
+		got_one = 1;
+		goto S1;
+	}
+
+S2:
+	switch (*sb) {
+
+	case '\0':
+		goto OUT;
+
+	default:
+		*ap++ = *sb++;
+		got_one = 1;
+		goto S1;
+	}
+
+S3:
+	switch (*sb) {
+
+	case '\0':
+		goto OUT;
+
+	case '"':
+		sb++; goto S1;
+
+	default:
+		*ap++ = *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;
+}
+
+#define HELPINDENT ((int) sizeof ("directory"))
+
+/*
+ * Help command.
+ * Call each command handler with argc == 0 and argv[0] == name.
+ */
+void
+help(int argc, char *argv[])
+{
+	struct cmd *c;
+
+	if (argc == 1) {
+		int i, j, w;
+		unsigned k;
+		int columns, width = 0, lines;
+
+		printf("Commands may be abbreviated.  Commands are:\n\n");
+		for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
+			int len = strlen(c->c_name);
+
+			if (len > width)
+				width = len;
+		}
+		width = (width + 8) &~ 7;
+		columns = 80 / width;
+		if (columns == 0)
+			columns = 1;
+		lines = (NCMDS + columns - 1) / columns;
+		for (i = 0; i < lines; i++) {
+			for (j = 0; j < columns; j++) {
+				c = cmdtab + j * lines + i;
+				if (c->c_name && (!proxy || c->c_proxy)) {
+					printf("%s", c->c_name);
+				}
+				else if (c->c_name) {
+					for (k=0; k < strlen(c->c_name); k++) {
+						(void) putchar(' ');
+					}
+				}
+				if (c + lines >= &cmdtab[NCMDS]) {
+					printf("\n");
+					break;
+				}
+				w = strlen(c->c_name);
+				while (w < width) {
+					w = (w + 8) &~ 7;
+					(void) putchar('\t');
+				}
+			}
+		}
+		return;
+	}
+	while (--argc > 0) {
+		register char *arg;
+		arg = *++argv;
+		c = getcmd(arg);
+		if (c == (struct cmd *)-1)
+			printf("?Ambiguous help command %s\n", arg);
+		else if (c == NULL)
+			printf("?Invalid help command %s\n", arg);
+		else
+			printf("%-*s\t%s\n", HELPINDENT,
+				c->c_name, c->c_help);
+	}
+}
Index: netkit-ftp-0.17-new/ftp/ruserpass.c
===================================================================
--- netkit-ftp-0.17-new/ftp/ruserpass.c	(nonexistent)
+++ netkit-ftp-0.17-new/ftp/ruserpass.c	(revision 5)
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 1985 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.
+ */
+
+/*
+ * from: @(#)ruserpass.c	5.3 (Berkeley) 3/1/91
+ */
+char ruserpass_rcsid[] = 
+  "$Id: ruserpass.c,v 1.9 1999/10/02 19:12:33 dholland Exp $";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <utmp.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include "ftp_var.h"
+
+static FILE *cfile;
+static int token(void);
+
+#define	DEFAULT	1
+#define	LOGIN	2
+#define	PASSWD	3
+#define	ACCOUNT 4
+#define MACDEF  5
+#define	ID	10
+#define	MACH	11
+
+#define MAXTOKENLEN 4096
+static char tokval[MAXTOKENLEN];
+
+static struct toktab {
+	const char *tokstr;
+	int tval;
+} toktab[]= {
+	{ "default",	DEFAULT },
+	{ "login",	LOGIN },
+	{ "password",	PASSWD },
+	{ "passwd",	PASSWD },
+	{ "account",	ACCOUNT },
+	{ "machine",	MACH },
+	{ "macdef",	MACDEF },
+	{ NULL,		0 }
+};
+
+int
+xruserpass(const char *host, char **aname, char **apass, char **aacct)
+{
+	const char *hdir;
+	char buf[BUFSIZ], *tmp;
+	char myname[MAXHOSTNAMELEN];
+	const char *mydomain;
+	int t, i, c, usedefault = 0;
+	struct stat stb;
+
+	hdir = getenv("HOME");
+	if (hdir == NULL)
+		hdir = ".";
+	snprintf(buf, sizeof(buf), "%s/.netrc", hdir);
+	cfile = fopen(buf, "r");
+	if (cfile == NULL) {
+		if (errno != ENOENT)
+			perror(buf);
+		return(0);
+	}
+	if (gethostname(myname, sizeof(myname)) < 0)
+		myname[0] = '\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 = index(hostname, '.')) != NULL &&
+			    strcasecmp(tmp, mydomain) == 0 &&
+			    strncasecmp(hostname, tokval, tmp-hostname) == 0 &&
+			    tokval[tmp - hostname] == '\0')
+				goto match;
+			if ((tmp = index(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 == 0) { 
+					*aname = malloc((unsigned) strlen(tokval) + 1);
+					if (*aname != NULL)
+						(void) strcpy(*aname, tokval);
+				} else {
+					if (strcmp(*aname, tokval))
+						goto next;
+				}
+			}
+			break;
+		case PASSWD:
+			if (*aname==NULL) {
+	fprintf(stderr, "Error: `password' must follow `login' in .netrc\n");
+				goto bad;
+			}
+			if (strcmp(*aname, "anonymous") &&
+			    fstat(fileno(cfile), &stb) >= 0 &&
+			    (stb.st_mode & 077) != 0) {
+	fprintf(stderr, "Error - .netrc file not correct permissions.\n");
+	fprintf(stderr, "Remove password or correct mode (should be 600).\n");
+				goto bad;
+			}
+			if (token() && *apass == 0) {
+				*apass = malloc((unsigned) strlen(tokval) + 1);
+				if (*apass != NULL)
+					(void) strcpy(*apass, tokval);
+			}
+			break;
+		case ACCOUNT:
+			if (fstat(fileno(cfile), &stb) >= 0
+			    && (stb.st_mode & 077) != 0) {
+	fprintf(stderr, "Error - .netrc file not correct permissions.\n");
+	fprintf(stderr, "Remove account or correct mode (should be 600).\n");
+				goto bad;
+			}
+			if (token() && *aacct == 0) {
+				*aacct = malloc((unsigned) strlen(tokval) + 1);
+				if (*aacct != NULL)
+					(void) strcpy(*aacct, tokval);
+			}
+			break;
+		case MACDEF:
+			if (proxy) {
+				(void) fclose(cfile);
+				return(0);
+			}
+			while ((c=getc(cfile)) != EOF && (c == ' ' || c == '\t'));
+			if (c == EOF || c == '\n') {
+				printf("Missing macdef name argument.\n");
+				goto bad;
+			}
+			if (macnum == 16) {
+				printf("Limit of 16 macros have already been defined\n");
+				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) {
+				printf("Macro definition missing null line terminator.\n");
+				goto bad;
+			}
+			*tmp = '\0';
+			if (c != '\n') {
+				while ((c=getc(cfile)) != EOF && c != '\n');
+			}
+			if (c == EOF) {
+				printf("Macro definition missing null line terminator.\n");
+				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 + MACBUF_SIZE) {
+				if ((c=getc(cfile)) == EOF) {
+				printf("Macro definition missing null line terminator.\n");
+					goto bad;
+				}
+				*tmp = c;
+				if (*tmp == '\n') {
+					if (*(tmp-1) == '\0') {
+					   macros[macnum++].mac_end = tmp - 1;
+					   break;
+					}
+					*tmp = '\0';
+				}
+				tmp++;
+			}
+			if (tmp == macbuf + MACBUF_SIZE) {
+				printf("4K macro buffer exceeded\n");
+				goto bad;
+			}
+			break;
+		default:
+	fprintf(stderr, "Unknown .netrc keyword %s\n", 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;
+	size_t toklen = 0;
+	int showwarn = 1;
+	int quote = 0;
+
+	if (feof(cfile))
+		return (0);
+	while ((c = getc(cfile)) != EOF &&
+	    (c == '\n' || c == '\t' || c == ' ' || c == ','))
+		continue;
+	if (c == EOF)
+		return (0);
+	cp = tokval;
+	if (c == '"') {
+		quote = 1;
+	}
+	else {
+		*cp++ = c;
+		toklen++;
+	}
+	while ((c = getc(cfile)) != EOF) {
+		if (c == '"') {
+			break;
+		}
+		if (c == '\\') {
+			c = getc(cfile);
+		}
+		if (!quote && (c == '\n' || c == '\t' || c == ' ' || c == ',')) {
+			break;
+		}
+		if (toklen >= MAXTOKENLEN) {
+			if (showwarn) {
+				fprintf(stderr,
+						"Warning: .netrc token too long, will be trunctated to %zd characters\n",
+						toklen);
+				showwarn = 0;
+			}
+			continue;
+		}
+		*cp++ = c;
+		toklen++;
+	}
+
+	*cp = 0;
+	if (tokval[0] == 0)
+		return (0);
+	for (t = toktab; t->tokstr; t++)
+		if (!strcmp(t->tokstr, tokval))
+			return (t->tval);
+	return (ID);
+}
Index: netkit-ftp-0.17-new/ftp
===================================================================
--- netkit-ftp-0.17-new/ftp	(nonexistent)
+++ netkit-ftp-0.17-new/ftp	(revision 5)

Property changes on: netkit-ftp-0.17-new/ftp
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: netkit-ftp-0.17-new
===================================================================
--- netkit-ftp-0.17-new	(nonexistent)
+++ netkit-ftp-0.17-new	(revision 5)

Property changes on: netkit-ftp-0.17-new
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: .
===================================================================
--- .	(nonexistent)
+++ .	(revision 5)

Property changes on: .
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~