From de04b33937683b680ddd19ab1ebebdbad119bfe7 Mon Sep 17 00:00:00 2001 From: Steven Edwards Date: Thu, 20 Dec 2001 18:50:07 +0000 Subject: [PATCH] ncftp for win32 3.0.3 svn path=/trunk/; revision=2434 --- reactos/apps/utils/net/ncftp/Strn/Dynscat.c | 54 + reactos/apps/utils/net/ncftp/Strn/Makefile.in | 115 + reactos/apps/utils/net/ncftp/Strn/Strn.h | 52 + reactos/apps/utils/net/ncftp/Strn/Strncat.c | 44 + reactos/apps/utils/net/ncftp/Strn/Strncpy.c | 45 + reactos/apps/utils/net/ncftp/Strn/Strnpcat.c | 54 + reactos/apps/utils/net/ncftp/Strn/Strnpcpy.c | 54 + reactos/apps/utils/net/ncftp/Strn/Strntok.c | 179 + reactos/apps/utils/net/ncftp/Strn/config.h.in | 10 + .../apps/utils/net/ncftp/Strn/configure.in | 19 + reactos/apps/utils/net/ncftp/Strn/strtokc.c | 240 ++ reactos/apps/utils/net/ncftp/Strn/tester.c | 135 + reactos/apps/utils/net/ncftp/Strn/version.c | 1 + .../apps/utils/net/ncftp/autoconf/acconfig.h | 389 ++ .../apps/utils/net/ncftp/autoconf/aclocal.m4 | 2391 +++++++++++ reactos/apps/utils/net/ncftp/ftp.rc | 39 + .../apps/utils/net/ncftp/libncftp/Makefile.in | 144 + .../apps/utils/net/ncftp/libncftp/Readme.txt | 73 + reactos/apps/utils/net/ncftp/libncftp/cmds.c | 1700 ++++++++ .../apps/utils/net/ncftp/libncftp/config.h.in | 207 + .../utils/net/ncftp/libncftp/configure.in | 292 ++ .../apps/utils/net/ncftp/libncftp/dos2unix.sh | 33 + reactos/apps/utils/net/ncftp/libncftp/errno.c | 163 + reactos/apps/utils/net/ncftp/libncftp/ftp.c | 1362 ++++++ reactos/apps/utils/net/ncftp/libncftp/ftp.h | 22 + reactos/apps/utils/net/ncftp/libncftp/glob.c | 1760 ++++++++ reactos/apps/utils/net/ncftp/libncftp/io.c | 2824 +++++++++++++ .../utils/net/ncftp/libncftp/libncftp.dsp | 160 + .../utils/net/ncftp/libncftp/libncftp.dsw | 29 + .../apps/utils/net/ncftp/libncftp/linelist.c | 783 ++++ .../apps/utils/net/ncftp/libncftp/mksrctar.sh | 97 + .../utils/net/ncftp/libncftp/mksrczip.bat | 19 + reactos/apps/utils/net/ncftp/libncftp/ncftp.h | 691 +++ .../utils/net/ncftp/libncftp/ncftp_errno.h | 113 + reactos/apps/utils/net/ncftp/libncftp/open.c | 1137 +++++ reactos/apps/utils/net/ncftp/libncftp/rcmd.c | 1038 +++++ .../apps/utils/net/ncftp/libncftp/syshdrs.h | 237 ++ reactos/apps/utils/net/ncftp/libncftp/util.c | 1048 +++++ reactos/apps/utils/net/ncftp/libncftp/util.h | 108 + .../apps/utils/net/ncftp/libncftp/util2.cpp | 34 + .../apps/utils/net/ncftp/libncftp/wincfg.h | 33 + reactos/apps/utils/net/ncftp/makefile | 105 + .../apps/utils/net/ncftp/ncftp/Makefile.in | 89 + reactos/apps/utils/net/ncftp/ncftp/bookmark.c | 845 ++++ reactos/apps/utils/net/ncftp/ncftp/bookmark.h | 59 + reactos/apps/utils/net/ncftp/ncftp/cmdlist.c | 527 +++ reactos/apps/utils/net/ncftp/ncftp/cmds.c | 3701 +++++++++++++++++ reactos/apps/utils/net/ncftp/ncftp/cmds.h | 63 + reactos/apps/utils/net/ncftp/ncftp/getline.c | 2473 +++++++++++ reactos/apps/utils/net/ncftp/ncftp/getline.h | 50 + reactos/apps/utils/net/ncftp/ncftp/getopt.c | 82 + reactos/apps/utils/net/ncftp/ncftp/getopt.h | 12 + reactos/apps/utils/net/ncftp/ncftp/log.c | 124 + reactos/apps/utils/net/ncftp/ncftp/log.h | 18 + reactos/apps/utils/net/ncftp/ncftp/ls.c | 779 ++++ reactos/apps/utils/net/ncftp/ncftp/ls.h | 29 + reactos/apps/utils/net/ncftp/ncftp/main.c | 477 +++ reactos/apps/utils/net/ncftp/ncftp/main.h | 11 + reactos/apps/utils/net/ncftp/ncftp/pref.c | 791 ++++ reactos/apps/utils/net/ncftp/ncftp/pref.h | 74 + reactos/apps/utils/net/ncftp/ncftp/preffw.c | 338 ++ reactos/apps/utils/net/ncftp/ncftp/progress.c | 498 +++ reactos/apps/utils/net/ncftp/ncftp/progress.h | 17 + reactos/apps/utils/net/ncftp/ncftp/readln.c | 831 ++++ reactos/apps/utils/net/ncftp/ncftp/readln.h | 31 + reactos/apps/utils/net/ncftp/ncftp/resource.h | 16 + reactos/apps/utils/net/ncftp/ncftp/shell.c | 607 +++ reactos/apps/utils/net/ncftp/ncftp/shell.h | 78 + reactos/apps/utils/net/ncftp/ncftp/spool.c | 496 +++ reactos/apps/utils/net/ncftp/ncftp/spool.h | 24 + reactos/apps/utils/net/ncftp/ncftp/syshdrs.h | 194 + reactos/apps/utils/net/ncftp/ncftp/trace.c | 178 + reactos/apps/utils/net/ncftp/ncftp/trace.h | 25 + reactos/apps/utils/net/ncftp/ncftp/util.c | 1139 +++++ reactos/apps/utils/net/ncftp/ncftp/util.h | 84 + reactos/apps/utils/net/ncftp/ncftp/version.c | 22 + reactos/apps/utils/net/ncftp/sio/Makefile.in | 194 + reactos/apps/utils/net/ncftp/sio/PRead.c | 71 + reactos/apps/utils/net/ncftp/sio/PWrite.c | 55 + reactos/apps/utils/net/ncftp/sio/SAcceptA.c | 52 + reactos/apps/utils/net/ncftp/sio/SAcceptS.c | 47 + reactos/apps/utils/net/ncftp/sio/SBind.c | 63 + reactos/apps/utils/net/ncftp/sio/SClose.c | 217 + reactos/apps/utils/net/ncftp/sio/SConnect.c | 196 + .../apps/utils/net/ncftp/sio/SConnectByName.c | 13 + reactos/apps/utils/net/ncftp/sio/SError.c | 171 + reactos/apps/utils/net/ncftp/sio/SNew.c | 81 + reactos/apps/utils/net/ncftp/sio/SRead.c | 213 + reactos/apps/utils/net/ncftp/sio/SReadline.c | 157 + reactos/apps/utils/net/ncftp/sio/SRecv.c | 184 + reactos/apps/utils/net/ncftp/sio/SRecvfrom.c | 127 + reactos/apps/utils/net/ncftp/sio/SRecvmsg.c | 137 + reactos/apps/utils/net/ncftp/sio/SSelect.c | 74 + reactos/apps/utils/net/ncftp/sio/SSend.c | 172 + reactos/apps/utils/net/ncftp/sio/SSendto.c | 137 + .../apps/utils/net/ncftp/sio/SSendtoByName.c | 149 + reactos/apps/utils/net/ncftp/sio/SWait.c | 108 + reactos/apps/utils/net/ncftp/sio/SWrite.c | 180 + reactos/apps/utils/net/ncftp/sio/SocketUtil.c | 203 + reactos/apps/utils/net/ncftp/sio/StrAddr.c | 221 + reactos/apps/utils/net/ncftp/sio/UAcceptA.c | 49 + reactos/apps/utils/net/ncftp/sio/UAcceptS.c | 50 + reactos/apps/utils/net/ncftp/sio/UBind.c | 57 + reactos/apps/utils/net/ncftp/sio/UConnect.c | 35 + .../apps/utils/net/ncftp/sio/UConnectByName.c | 18 + reactos/apps/utils/net/ncftp/sio/UNew.c | 106 + reactos/apps/utils/net/ncftp/sio/URecvfrom.c | 63 + reactos/apps/utils/net/ncftp/sio/USendto.c | 63 + .../apps/utils/net/ncftp/sio/USendtoByName.c | 66 + reactos/apps/utils/net/ncftp/sio/config.h.in | 63 + reactos/apps/utils/net/ncftp/sio/configure.in | 105 + reactos/apps/utils/net/ncftp/sio/main.c | 49 + reactos/apps/utils/net/ncftp/sio/sio.h | 243 ++ reactos/apps/utils/net/ncftp/sio/sio.html | 1086 +++++ reactos/apps/utils/net/ncftp/sio/srltest.c | 118 + reactos/apps/utils/net/ncftp/sio/syshdrs.h | 203 + reactos/apps/utils/net/ncftp/sio/usio.h | 48 + reactos/apps/utils/net/ncftp/sio/wincfg.h | 63 + 118 files changed, 38522 insertions(+) create mode 100644 reactos/apps/utils/net/ncftp/Strn/Dynscat.c create mode 100644 reactos/apps/utils/net/ncftp/Strn/Makefile.in create mode 100644 reactos/apps/utils/net/ncftp/Strn/Strn.h create mode 100644 reactos/apps/utils/net/ncftp/Strn/Strncat.c create mode 100644 reactos/apps/utils/net/ncftp/Strn/Strncpy.c create mode 100644 reactos/apps/utils/net/ncftp/Strn/Strnpcat.c create mode 100644 reactos/apps/utils/net/ncftp/Strn/Strnpcpy.c create mode 100644 reactos/apps/utils/net/ncftp/Strn/Strntok.c create mode 100644 reactos/apps/utils/net/ncftp/Strn/config.h.in create mode 100644 reactos/apps/utils/net/ncftp/Strn/configure.in create mode 100644 reactos/apps/utils/net/ncftp/Strn/strtokc.c create mode 100644 reactos/apps/utils/net/ncftp/Strn/tester.c create mode 100644 reactos/apps/utils/net/ncftp/Strn/version.c create mode 100644 reactos/apps/utils/net/ncftp/autoconf/acconfig.h create mode 100644 reactos/apps/utils/net/ncftp/autoconf/aclocal.m4 create mode 100644 reactos/apps/utils/net/ncftp/ftp.rc create mode 100644 reactos/apps/utils/net/ncftp/libncftp/Makefile.in create mode 100644 reactos/apps/utils/net/ncftp/libncftp/Readme.txt create mode 100644 reactos/apps/utils/net/ncftp/libncftp/cmds.c create mode 100644 reactos/apps/utils/net/ncftp/libncftp/config.h.in create mode 100644 reactos/apps/utils/net/ncftp/libncftp/configure.in create mode 100644 reactos/apps/utils/net/ncftp/libncftp/dos2unix.sh create mode 100644 reactos/apps/utils/net/ncftp/libncftp/errno.c create mode 100644 reactos/apps/utils/net/ncftp/libncftp/ftp.c create mode 100644 reactos/apps/utils/net/ncftp/libncftp/ftp.h create mode 100644 reactos/apps/utils/net/ncftp/libncftp/glob.c create mode 100644 reactos/apps/utils/net/ncftp/libncftp/io.c create mode 100644 reactos/apps/utils/net/ncftp/libncftp/libncftp.dsp create mode 100644 reactos/apps/utils/net/ncftp/libncftp/libncftp.dsw create mode 100644 reactos/apps/utils/net/ncftp/libncftp/linelist.c create mode 100644 reactos/apps/utils/net/ncftp/libncftp/mksrctar.sh create mode 100644 reactos/apps/utils/net/ncftp/libncftp/mksrczip.bat create mode 100644 reactos/apps/utils/net/ncftp/libncftp/ncftp.h create mode 100644 reactos/apps/utils/net/ncftp/libncftp/ncftp_errno.h create mode 100644 reactos/apps/utils/net/ncftp/libncftp/open.c create mode 100644 reactos/apps/utils/net/ncftp/libncftp/rcmd.c create mode 100644 reactos/apps/utils/net/ncftp/libncftp/syshdrs.h create mode 100644 reactos/apps/utils/net/ncftp/libncftp/util.c create mode 100644 reactos/apps/utils/net/ncftp/libncftp/util.h create mode 100644 reactos/apps/utils/net/ncftp/libncftp/util2.cpp create mode 100644 reactos/apps/utils/net/ncftp/libncftp/wincfg.h create mode 100644 reactos/apps/utils/net/ncftp/makefile create mode 100644 reactos/apps/utils/net/ncftp/ncftp/Makefile.in create mode 100644 reactos/apps/utils/net/ncftp/ncftp/bookmark.c create mode 100644 reactos/apps/utils/net/ncftp/ncftp/bookmark.h create mode 100644 reactos/apps/utils/net/ncftp/ncftp/cmdlist.c create mode 100644 reactos/apps/utils/net/ncftp/ncftp/cmds.c create mode 100644 reactos/apps/utils/net/ncftp/ncftp/cmds.h create mode 100644 reactos/apps/utils/net/ncftp/ncftp/getline.c create mode 100644 reactos/apps/utils/net/ncftp/ncftp/getline.h create mode 100644 reactos/apps/utils/net/ncftp/ncftp/getopt.c create mode 100644 reactos/apps/utils/net/ncftp/ncftp/getopt.h create mode 100644 reactos/apps/utils/net/ncftp/ncftp/log.c create mode 100644 reactos/apps/utils/net/ncftp/ncftp/log.h create mode 100644 reactos/apps/utils/net/ncftp/ncftp/ls.c create mode 100644 reactos/apps/utils/net/ncftp/ncftp/ls.h create mode 100644 reactos/apps/utils/net/ncftp/ncftp/main.c create mode 100644 reactos/apps/utils/net/ncftp/ncftp/main.h create mode 100644 reactos/apps/utils/net/ncftp/ncftp/pref.c create mode 100644 reactos/apps/utils/net/ncftp/ncftp/pref.h create mode 100644 reactos/apps/utils/net/ncftp/ncftp/preffw.c create mode 100644 reactos/apps/utils/net/ncftp/ncftp/progress.c create mode 100644 reactos/apps/utils/net/ncftp/ncftp/progress.h create mode 100644 reactos/apps/utils/net/ncftp/ncftp/readln.c create mode 100644 reactos/apps/utils/net/ncftp/ncftp/readln.h create mode 100644 reactos/apps/utils/net/ncftp/ncftp/resource.h create mode 100644 reactos/apps/utils/net/ncftp/ncftp/shell.c create mode 100644 reactos/apps/utils/net/ncftp/ncftp/shell.h create mode 100644 reactos/apps/utils/net/ncftp/ncftp/spool.c create mode 100644 reactos/apps/utils/net/ncftp/ncftp/spool.h create mode 100644 reactos/apps/utils/net/ncftp/ncftp/syshdrs.h create mode 100644 reactos/apps/utils/net/ncftp/ncftp/trace.c create mode 100644 reactos/apps/utils/net/ncftp/ncftp/trace.h create mode 100644 reactos/apps/utils/net/ncftp/ncftp/util.c create mode 100644 reactos/apps/utils/net/ncftp/ncftp/util.h create mode 100644 reactos/apps/utils/net/ncftp/ncftp/version.c create mode 100644 reactos/apps/utils/net/ncftp/sio/Makefile.in create mode 100644 reactos/apps/utils/net/ncftp/sio/PRead.c create mode 100644 reactos/apps/utils/net/ncftp/sio/PWrite.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SAcceptA.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SAcceptS.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SBind.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SClose.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SConnect.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SConnectByName.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SError.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SNew.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SRead.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SReadline.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SRecv.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SRecvfrom.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SRecvmsg.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SSelect.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SSend.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SSendto.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SSendtoByName.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SWait.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SWrite.c create mode 100644 reactos/apps/utils/net/ncftp/sio/SocketUtil.c create mode 100644 reactos/apps/utils/net/ncftp/sio/StrAddr.c create mode 100644 reactos/apps/utils/net/ncftp/sio/UAcceptA.c create mode 100644 reactos/apps/utils/net/ncftp/sio/UAcceptS.c create mode 100644 reactos/apps/utils/net/ncftp/sio/UBind.c create mode 100644 reactos/apps/utils/net/ncftp/sio/UConnect.c create mode 100644 reactos/apps/utils/net/ncftp/sio/UConnectByName.c create mode 100644 reactos/apps/utils/net/ncftp/sio/UNew.c create mode 100644 reactos/apps/utils/net/ncftp/sio/URecvfrom.c create mode 100644 reactos/apps/utils/net/ncftp/sio/USendto.c create mode 100644 reactos/apps/utils/net/ncftp/sio/USendtoByName.c create mode 100644 reactos/apps/utils/net/ncftp/sio/config.h.in create mode 100644 reactos/apps/utils/net/ncftp/sio/configure.in create mode 100644 reactos/apps/utils/net/ncftp/sio/main.c create mode 100644 reactos/apps/utils/net/ncftp/sio/sio.h create mode 100644 reactos/apps/utils/net/ncftp/sio/sio.html create mode 100644 reactos/apps/utils/net/ncftp/sio/srltest.c create mode 100644 reactos/apps/utils/net/ncftp/sio/syshdrs.h create mode 100644 reactos/apps/utils/net/ncftp/sio/usio.h create mode 100644 reactos/apps/utils/net/ncftp/sio/wincfg.h diff --git a/reactos/apps/utils/net/ncftp/Strn/Dynscat.c b/reactos/apps/utils/net/ncftp/Strn/Dynscat.c new file mode 100644 index 00000000000..a34137995f8 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/Strn/Dynscat.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include "Strn.h" + +/*VARARGS*/ +char * +Dynscat(char **dst, ...) +{ + va_list ap; + const char *src; + char *newdst, *dcp; + size_t curLen, catLen, srcLen; + + if (dst == (char **) 0) + return NULL; + + catLen = 0; + va_start(ap, dst); + src = va_arg(ap, char *); + while (src != NULL) { + catLen += strlen(src); + src = va_arg(ap, char *); + } + va_end(ap); + + if ((*dst == NULL) || (**dst == '\0')) + curLen = 0; + else + curLen = strlen(*dst); + + if (*dst == NULL) + newdst = malloc(curLen + catLen + 2); + else + newdst = realloc(*dst, curLen + catLen + 2); + if (newdst == NULL) + return NULL; + + dcp = newdst + curLen; + va_start(ap, dst); + src = va_arg(ap, char *); + while (src != NULL) { + srcLen = strlen(src); + memcpy(dcp, src, srcLen); + dcp += srcLen; + src = va_arg(ap, char *); + } + va_end(ap); + *dcp = '\0'; + + *dst = newdst; + return (newdst); +} /* Dynscat */ diff --git a/reactos/apps/utils/net/ncftp/Strn/Makefile.in b/reactos/apps/utils/net/ncftp/Strn/Makefile.in new file mode 100644 index 00000000000..e7135490ff2 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/Strn/Makefile.in @@ -0,0 +1,115 @@ +# +# Strn makefile +# +VER=2.2.0 +PREFIX=@prefix@ +MAN=@prefix@/man +SHELL=/bin/sh +.SUFFIXES: .c .o .so +LIB=libStrn.a +LIBSO=libStrn.so.1 +LIBSOS=libStrn.so +CC=@CC@ +CPPFLAGS= +#CFLAGS=-O2 +CFLAGS=@CFLAGS@ +DEFS=-DSTRNP_ZERO_PAD=0 -DSTRN_ZERO_PAD=1 + +OBJS=Dynscat.o Strncpy.o Strncat.o Strntok.o Strnpcpy.o Strnpcat.o strtokc.o version.o +SOBJS=Dynscat.so Strncpy.so Strncat.so Strntok.so Strnpcpy.so Strnpcat.so strtokc.so version.so + +all: static + -@echo "Done making Strn." + +static: $(LIB) + +$(LIB): $(OBJS) + ar rv $(LIB) $(OBJS) + chmod 644 "$(LIB)" + -ranlib "$(LIB)" + echo "$(VER)" > Strn.version + -@/bin/ls -l "$(LIB)" + +.c.o: + $(CC) $(CFLAGS) $(DEFS) $(CPPFLAGS) $< -c + +.c.so: + $(CC) -fpic $(CFLAGS) $(CPPFLAGS) $(DEFS) $*.c -c -o $*.so + +dynamic: $(LIBSO) + +shared: $(LIBSO) + +so: $(LIBSO) + +$(LIBSO): $(SOBJS) + /bin/rm -f "$(LIBSO)" + gcc -shared "-Wl,-soname,$(LIBSO)" -o "$(LIBSO)" $(SOBJS) + /bin/ln -s "$(LIBSO)" "$(LIBSOS)" + -@/bin/ls -l "$(LIBSOS)" "$(LIBSO)" + +soinstall: $(LIBSO) + cp "$(LIBSO)" "$(PREFIX)/lib/$(LIBSO)" + ( cd "$(PREFIX)/lib" ; /bin/ln -s "$(LIBSO)" "$(LIBSOS)" ) + cp Strn.h "$(PREFIX)/include/Strn.h" + -chmod a+r "$(PREFIX)/lib/$(LIBSO)" "$(PREFIX)/include/Strn.h" + +tester: $(LIB) tester.c + $(CC) $(CFLAGS) tester.c -o tester -I. -L. -lStrn + +clean: + /bin/rm -f "$(LIB)" "$(LIBSO)" $(OBJS) $(SOBJS) + +install: + if test ! -d $(PREFIX)/include ; then mkdir -p "$(PREFIX)/include" ; fi + if test ! -d $(PREFIX)/lib ; then mkdir -p "$(PREFIX)/lib" ; fi + cp "$(LIB)" Strn.version "$(PREFIX)/lib" + cp Strn.h "$(PREFIX)/include/Strn.h" + -chmod 664 "$(PREFIX)/include/Strn.h" "$(PREFIX)/lib/Strn.version" "$(PREFIX)/lib/$(LIB)" + -cp Strn.3 "$(MAN)/man3/Strn.3" + -chmod 664 "$(MAN)/man3/Strn.3" + -ln "$(MAN)/man3/Strn.3" "$(MAN)/man3/Strncpy.3" + -ln "$(MAN)/man3/Strn.3" "$(MAN)/man3/Strncat.3" + +uninstall: + /bin/rm -f "$(PREFIX)/lib/$(LIB)" "$(PREFIX)/include/Strn.h" + +PACKAGE=configure Makefile.in configure.in Strn.dsp Strn.dsw Dynscat.c Strncpy.c Strncat.c Strnpcpy.c Strnpcat.c Strntok.c strtokc.c Strn.h Strn.3 tester.c version.c Strn.version + +TMPDIR=/tmp +TARDIR=Strn +TARFILE=$(TARDIR).tar +TGZFILE=$(TARDIR).tgz + +tarcp: + -@mkdir -p $(TMPDIR)/TAR/$(TARDIR) + -@chmod ga+r $(PACKAGE) + -@chmod 755 $(TMPDIR)/TAR/$(TARDIR) + cp -pr $(PACKAGE) $(TMPDIR)/TAR/$(TARDIR) + +tar: $(PACKAGE) + -@mkdir $(TMPDIR)/TAR + -@mkdir $(TMPDIR)/TAR/$(TARDIR) + -@chmod ga+r $(PACKAGE) + -@chmod 755 $(TMPDIR)/TAR/$(TARDIR) + cp -pr $(PACKAGE) $(TMPDIR)/TAR/$(TARDIR) + ( cd $(TMPDIR)/TAR ; tar cf $(TARFILE) ./$(TARDIR) ) + cp $(TMPDIR)/TAR/$(TARFILE) . + -@chmod 644 $(TARFILE) + -@rm -rf $(TMPDIR)/TAR + -@ls -l $(TARFILE) + +gz: tar + gzip -c $(TARFILE) > $(TGZFILE) + -@rm $(TARFILE) + -@chmod 644 $(TGZFILE) + -@ls -l $(TGZFILE) + +Dynscat.o: Dynscat.c Strn.h +Strncat.o: Strncat.c Strn.h +Strncpy.o: Strncpy.c Strn.h +Strnpcat.o: Strnpcat.c Strn.h +Strnpcpy.o: Strnpcpy.c Strn.h +Strntok.o: Strntok.c Strn.h +strtokc.o: strtokc.c Strn.h +version.o: version.c diff --git a/reactos/apps/utils/net/ncftp/Strn/Strn.h b/reactos/apps/utils/net/ncftp/Strn/Strn.h new file mode 100644 index 00000000000..3f8be368340 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/Strn/Strn.h @@ -0,0 +1,52 @@ +/* Strn.h */ + +#ifndef _Strn_h_ +#define _Strn_h_ 1 + +/* You should define this from the Makefile. */ +#ifndef STRN_ZERO_PAD +# define STRN_ZERO_PAD 1 +#endif + +/* You should define this from the Makefile. */ +#ifndef STRNP_ZERO_PAD +# define STRNP_ZERO_PAD 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Strncat.c */ +char *Strncat(char *const, const char *const, const size_t); + +/* Strncpy.c */ +char *Strncpy(char *const, const char *const, const size_t); + +/* Strnpcat.c */ +char *Strnpcat(char *const, const char *const, size_t); + +/* Strnpcpy.c */ +char *Strnpcpy(char *const, const char *const, size_t); + +/* Strntok.c */ +char *Strtok(char *, const char *); +int Strntok(char *, size_t, char *, const char *); + +/* strtokc.c */ +char *strtokc(char *, const char *, char **); +int strntokc(char *, size_t, char *, const char *, char **); + +/* Dynscat.c */ +char * Dynscat(char **dst, ...); + +#ifdef __cplusplus +} +#endif + +#define STRNCPY(d,s) Strncpy((d), (s), (size_t) sizeof(d)) +#define STRNCAT(d,s) Strncat((d), (s), (size_t) sizeof(d)) + +#endif /* _Strn_h_ */ + +/* eof Strn.h */ diff --git a/reactos/apps/utils/net/ncftp/Strn/Strncat.c b/reactos/apps/utils/net/ncftp/Strn/Strncat.c new file mode 100644 index 00000000000..051555588f6 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/Strn/Strncat.c @@ -0,0 +1,44 @@ +#include +#include +#include "Strn.h" + +/* + * Concatenate src on the end of dst. The resulting string will have at most + * n-1 characters, not counting the NUL terminator which is always appended + * unlike strncat. The other big difference is that strncpy uses n as the + * max number of characters _appended_, while this routine uses n to limit + * the overall length of dst. + */ +char * +Strncat(char *const dst, const char *const src, const size_t n) +{ + register size_t i; + register char *d; + register const char *s; + + if (n != 0 && ((i = strlen(dst)) < (n - 1))) { + d = dst + i; + s = src; + /* If they specified a maximum of n characters, use n - 1 chars to + * hold the copy, and the last character in the array as a NUL. + * This is the difference between the regular strncpy routine. + * strncpy doesn't guarantee that your new string will have a + * NUL terminator, but this routine does. + */ + for (++i; i +#include +#include "Strn.h" + + +/* + * Copy src to dst, truncating or null-padding to always copy n-1 bytes. + * Return dst. + */ +char * +Strncpy(char *const dst, const char *const src, const size_t n) +{ + register char *d; + register const char *s; + register size_t i; + + d = dst; + *d = 0; + if (n != 0) { + s = src; + /* If they specified a maximum of n characters, use n - 1 chars to + * hold the copy, and the last character in the array as a NUL. + * This is the difference between the regular strncpy routine. + * strncpy doesn't guarantee that your new string will have a + * NUL terminator, but this routine does. + */ + for (i=1; i +#include +#include "Strn.h" + +/* + * Concatenate src on the end of dst. The resulting string will have at most + * n-1 characters, not counting the NUL terminator which is always appended + * unlike strncat. The other big difference is that strncpy uses n as the + * max number of characters _appended_, while this routine uses n to limit + * the overall length of dst. + * + * This routine also differs in that it returns a pointer to the end + * of the buffer, instead of strncat which returns a pointer to the start. + */ +char * +Strnpcat(char *const dst, const char *const src, size_t n) +{ + register size_t i; + register char *d; + register const char *s; + register char c; + char *ret; + + if (n != 0 && ((i = strlen(dst)) < (n - 1))) { + d = dst + i; + s = src; + /* If they specified a maximum of n characters, use n - 1 chars to + * hold the copy, and the last character in the array as a NUL. + * This is the difference between the regular strncpy routine. + * strncpy doesn't guarantee that your new string will have a + * NUL terminator, but this routine does. + */ + for (++i; i +#include +#include "Strn.h" + +/* + * Copy src to dst, truncating or null-padding to always copy n-1 bytes. + * + * This routine differs from strncpy in that it returns a pointer to the end + * of the buffer, instead of strncat which returns a pointer to the start. + */ +char * +Strnpcpy(char *const dst, const char *const src, size_t n) +{ + register char *d; + register const char *s; + register char c; + char *ret; + register size_t i; + + d = dst; + if (n != 0) { + s = src; + /* If they specified a maximum of n characters, use n - 1 chars to + * hold the copy, and the last character in the array as a NUL. + * This is the difference between the regular strncpy routine. + * strncpy doesn't guarantee that your new string will have a + * NUL terminator, but this routine does. + */ + for (i=1; i +#include "Strn.h" + +/* This version of Strtok differs from the regular ANSI strtok in that + * an empty token can be returned, and consecutive delimiters are not + * ignored like ANSI does. Example: + * + * Parse String = ",,mike,gleason,-West Interactive,402-573-1000" + * Delimiters = ",-" + * + * (ANSI strtok:) + * strtok 1=[mike] length=4 + * strtok 2=[gleason] length=7 + * strtok 3=[West Interactive] length=16 + * strtok 4=[402] length=3 + * strtok 5=[573] length=3 + * strtok 6=[1000] length=4 + * + * (Strtok:) + * Strtok 1=[] length=0 + * Strtok 2=[] length=0 + * Strtok 3=[mike] length=4 + * Strtok 4=[gleason] length=7 + * Strtok 5=[] length=0 + * Strtok 6=[West Interactive] length=16 + * Strtok 7=[402] length=3 + * Strtok 8=[573] length=3 + * Strtok 9=[1000] length=4 + * + */ + +char * +Strtok(char *buf, const char *delims) +{ + static char *p = NULL; + char *start, *end; + + if (buf != NULL) { + p = buf; + } else { + if (p == NULL) + return (NULL); /* No more tokens. */ + } + for (start = p, end = p; ; end++) { + if (*end == '\0') { + p = NULL; /* This is the last token. */ + break; + } + if (strchr(delims, (int) *end) != NULL) { + *end++ = '\0'; + p = end; + break; + } + } + return (start); +} /* Strtok */ + + + + +/* This is a bounds-safe version of Strtok, where you also pass a pointer + * to the token to write into, and its size. Using the example above, + * with a char token[8], you get the following. Notice that the token + * is not overrun, and is always nul-terminated: + * + * Strntok 1=[] length=0 + * Strntok 2=[] length=0 + * Strntok 3=[mike] length=4 + * Strntok 4=[gleason] length=7 + * Strntok 5=[] length=0 + * Strntok 6=[West In] length=7 + * Strntok 7=[402] length=3 + * Strntok 8=[573] length=3 + * Strntok 9=[1000] length=4 + */ + +int +Strntok(char *dstTokenStart, size_t tokenSize, char *buf, const char *delims) +{ + static char *p = NULL; + char *end; + char *lim; + char *dst; + int len; + + dst = dstTokenStart; + lim = dst + tokenSize - 1; /* Leave room for nul byte. */ + + if (buf != NULL) { + p = buf; + } else { + if (p == NULL) { + *dst = '\0'; + return (-1); /* No more tokens. */ + } + } + + for (end = p; ; end++) { + if (*end == '\0') { + p = NULL; /* This is the last token. */ + break; + } + if (strchr(delims, (int) *end) != NULL) { + ++end; + p = end; + break; + } + if (dst < lim) /* Don't overrun token size. */ + *dst++ = *end; + } + *dst = '\0'; + len = (int) (dst - dstTokenStart); /* Return length of token. */ + +#if (STRN_ZERO_PAD == 1) + /* Pad with zeros. */ + for (++dst; dst <= lim; ) + *dst++ = 0; +#endif /* STRN_ZERO_PAD */ + + return (len); +} /* Strntok */ + + + +#ifdef TESTING_STRTOK +#include + +void +main(int argc, char **argv) +{ + char buf[256]; + int i; + char *t; + char token[8]; + int tokenLen; + + if (argc < 3) { + fprintf(stderr, "Usage: test \"buffer,with,delims\" \n"); + exit(1); + } + strcpy(buf, argv[1]); + i = 1; + t = strtok(buf, argv[2]); + if (t == NULL) + exit(0); + do { + printf("strtok %d=[%s] length=%d\n", i, t, (int) strlen(t)); + t = strtok(NULL, argv[2]); + ++i; + } while (t != NULL); + + printf("------------------------------------------------\n"); + strcpy(buf, argv[1]); + i = 1; + t = Strtok(buf, argv[2]); + if (t == NULL) + exit(0); + do { + printf("Strtok %d=[%s] length=%d\n", i, t, (int) strlen(t)); + t = Strtok(NULL, argv[2]); + ++i; + } while (t != NULL); + + printf("------------------------------------------------\n"); + strcpy(buf, argv[1]); + i = 1; + tokenLen = Strntok(token, sizeof(token), buf, argv[2]); + if (tokenLen < 0) + exit(0); + do { + printf("Strntok %d=[%s] length=%d\n", i, token, tokenLen); + tokenLen = Strntok(token, sizeof(token), NULL, argv[2]); + ++i; + } while (tokenLen >= 0); + exit(0); +} +#endif diff --git a/reactos/apps/utils/net/ncftp/Strn/config.h.in b/reactos/apps/utils/net/ncftp/Strn/config.h.in new file mode 100644 index 00000000000..2122b45102e --- /dev/null +++ b/reactos/apps/utils/net/ncftp/Strn/config.h.in @@ -0,0 +1,10 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define to `unsigned' if doesn't define. */ +#undef size_t + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS diff --git a/reactos/apps/utils/net/ncftp/Strn/configure.in b/reactos/apps/utils/net/ncftp/Strn/configure.in new file mode 100644 index 00000000000..be5b9460009 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/Strn/configure.in @@ -0,0 +1,19 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(Strn.h) +wi_ARG_ENABLE_DEBUG + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_LN_S +AC_PROG_RANLIB + +dnl Checks for header files. +AC_HEADER_STDC + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_SIZE_T + +dnl Checks for library functions. + +AC_OUTPUT(Makefile) diff --git a/reactos/apps/utils/net/ncftp/Strn/strtokc.c b/reactos/apps/utils/net/ncftp/Strn/strtokc.c new file mode 100644 index 00000000000..ee1841d2869 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/Strn/strtokc.c @@ -0,0 +1,240 @@ +/* strtokc.c */ + +#include +#include "Strn.h" + +char * +strtokc(char *parsestr, const char *delims, char **context) +{ + char *cp; + const char *cp2; + char c, c2; + char *start; + + if (parsestr == NULL) + start = *context; + else + start = parsestr; + + if ((start == NULL) || (delims == NULL)) { + *context = NULL; + return NULL; + } + + /* Eat leading delimiters. */ + for (cp = start; ; ) { +next1: + c = *cp++; + if (c == '\0') { + /* No more tokens. */ + *context = NULL; + return (NULL); + } + for (cp2 = delims; ; ) { + c2 = (char) *cp2++; + if (c2 == '\0') { + /* This character was not a delimiter. + * The token starts here. + */ + start = cp - 1; + goto starttok; + } + if (c2 == c) { + /* This char was a delimiter. */ + /* Skip it, look at next character. */ + goto next1; + } + } + /*NOTREACHED*/ + } + +starttok: + for ( ; ; cp++) { + c = *cp; + if (c == '\0') { + /* Token is finished. */ + *context = cp; + break; + } + for (cp2 = delims; ; ) { + c2 = (char) *cp2++; + if (c2 == '\0') { + /* This character was not a delimiter. + * Keep it as part of current token. + */ + break; + } + if (c2 == c) { + /* This char was a delimiter. */ + /* End of token. */ + *cp++ = '\0'; + *context = cp; + return (start); + } + } + } + return (start); +} /* strtokc */ + + + + +/* Same as strtokc, only you specify the destination buffer to write + * the token in along with its size. strntokc will write to the dst + * buffer, always nul-terminating it. + * + * It also returns the length of the token, or zero if there was no + * token. This differs from strtokc, which returns a pointer to the + * token or NULL for no token. + */ + +int +strntokc(char *dstTokenStart, size_t tokenSize, char *parsestr, const char *delims, char **context) +{ + char *cp; + const char *cp2; + char c, c2; + char *start; + int len; + char *dst, *lim; + + dst = dstTokenStart; + lim = dst + tokenSize - 1; /* Leave room for nul byte. */ + + if (parsestr == NULL) + start = *context; + else + start = parsestr; + + if ((start == NULL) || (delims == NULL)) { + *context = NULL; + goto done; + } + + /* Eat leading delimiters. */ + for (cp = start; ; ) { +next1: + c = *cp++; + if (c == '\0') { + /* No more tokens. */ + *context = NULL; + goto done; + } + for (cp2 = delims; ; ) { + c2 = (char) *cp2++; + if (c2 == '\0') { + /* This character was not a delimiter. + * The token starts here. + */ + start = cp - 1; + if (dst < lim) + *dst++ = c; + goto starttok; + } + if (c2 == c) { + /* This char was a delimiter. */ + /* Skip it, look at next character. */ + goto next1; + } + } + /*NOTREACHED*/ + } + +starttok: + for ( ; ; cp++) { + c = *cp; + if (c == '\0') { + /* Token is finished. */ + *context = cp; + break; + } + for (cp2 = delims; ; ) { + c2 = (char) *cp2++; + if (c2 == '\0') { + /* This character was not a delimiter. + * Keep it as part of current token. + */ + break; + } + if (c2 == c) { + /* This char was a delimiter. */ + /* End of token. */ + *cp++ = '\0'; + *context = cp; + goto done; + } + } + if (dst < lim) /* Don't overrun token size. */ + *dst++ = c; + } + +done: + *dst = '\0'; + len = (int) (dst - dstTokenStart); /* Return length of token. */ + +#if (STRN_ZERO_PAD == 1) + /* Pad with zeros. */ + for (++dst; dst <= lim; ) + *dst++ = 0; +#endif /* STRN_ZERO_PAD */ + + return (len); +} /* strntokc */ + + + + +#ifdef TESTING_STRTOK +#include + +void +main(int argc, char **argv) +{ + char buf[256]; + int i; + char *t; + char token[8]; + int tokenLen; + char *context; + + if (argc < 3) { + fprintf(stderr, "Usage: test \"buffer,with,delims\" \n"); + exit(1); + } + strcpy(buf, argv[1]); + i = 1; + t = strtok(buf, argv[2]); + if (t == NULL) + exit(0); + do { + printf("strtok %d=[%s] length=%d\n", i, t, (int) strlen(t)); + t = strtok(NULL, argv[2]); + ++i; + } while (t != NULL); + + printf("------------------------------------------------\n"); + strcpy(buf, argv[1]); + i = 1; + t = strtokc(buf, argv[2], &context); + if (t == NULL) + exit(0); + do { + printf("strtokc %d=[%s] length=%d\n", i, t, (int) strlen(t)); + t = strtokc(NULL, argv[2], &context); + ++i; + } while (t != NULL); + + printf("------------------------------------------------\n"); + strcpy(buf, argv[1]); + i = 1; + tokenLen = strntokc(token, sizeof(token), buf, argv[2], &context); + if (tokenLen <= 0) + exit(0); + do { + printf("strntokc %d=[%s] length=%d\n", i, token, tokenLen); + tokenLen = strntokc(token, sizeof(token), NULL, argv[2], &context); + ++i; + } while (tokenLen > 0); + exit(0); +} +#endif diff --git a/reactos/apps/utils/net/ncftp/Strn/tester.c b/reactos/apps/utils/net/ncftp/Strn/tester.c new file mode 100644 index 00000000000..66e3034f53d --- /dev/null +++ b/reactos/apps/utils/net/ncftp/Strn/tester.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + char a[8]; + char pad1[32]; + char *b; + char c[37]; + char pad2[23]; + int i; + int len1, len2; + + b = Strncpy(a, "hello", sizeof(a)); + b = Strncat(b, "world", sizeof(a)); + printf("1: result=[%s] should be=[%s]\n", + b, + "hellowo" + ); + + for (i=0; i. */ +#undef DGUX + +/* Define if you have . */ +#undef DIRENT + +/* Define to the type of elements in the array set by `getgroups'. + Usually this is either `int' or `gid_t'. */ +#undef GETGROUPS_T + +/* Define if the `getloadavg' function needs to be run setuid or setgid. */ +#undef GETLOADAVG_PRIVILEGED + +/* Define if the `getpgrp' function takes no argument. */ +#undef GETPGRP_VOID + +/* Define to `int' if doesn't define. */ +#undef gid_t + +/* Define if you have alloca, as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define if you have and it should be used (not on Ultrix). */ +#undef HAVE_ALLOCA_H + +/* Define if your curses library has this functionality. */ +#undef HAVE_BEEP + +#undef HAVE_CURSES_H + +/* Define if you don't have vprintf but do have _doprnt. */ +#undef HAVE_DOPRNT + +/* Define if your system has a working fnmatch function. */ +#undef HAVE_FNMATCH + +/* Define if your curses library has this functionality. */ +#undef HAVE_GETBEGX + +/* Define if your system has its own `getloadavg' function. */ +#undef HAVE_GETLOADAVG + +/* Define if your curses library has this functionality. */ +#undef HAVE_GETMAXX + +/* Define if your curses library has this functionality. */ +#undef HAVE_GETMAXYX + +/* Define if you have the getmntent function. */ +#undef HAVE_GETMNTENT + +/* Define if you have . */ +#undef HAVE_HPSECURITY_H + +/* Define if you have the curses library. */ +#undef HAVE_LIBCURSES + +/* Define if you want to use the Hpwd library, and you also have it's corresponding database library (such as *dbm). */ +#undef HAVE_LIBHPWD + +/* Define if you have the ncurses library. */ +#undef HAVE_LIBNCURSES + +/* Define if you have the readline library, version 2.0 or higher. */ +#undef HAVE_LIBREADLINE + +/* Define if the `long double' type works. */ +#undef HAVE_LONG_DOUBLE + +/* Define if you support file names longer than 14 characters. */ +#undef HAVE_LONG_FILE_NAMES + +/* Define if your compiler supports the "long long" integral type. */ +#undef HAVE_LONG_LONG + +/* Most system's curses library uses a _maxx field instead of maxx. */ +#undef HAVE__MAXX + +/* Define if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +#undef HAVE_MSGHDR_ACCRIGHTS + +#undef HAVE_MSGHDR_CONTROL + +#undef HAVE_PR_PASSWD_FG_OLDCRYPT + +/* Define if you have a _res global variable used by resolve routines. */ +#undef HAVE__RES_DEFDNAME + +/* Define if system calls automatically restart after interruption + by a signal. */ +#undef HAVE_RESTARTABLE_SYSCALLS + +/* Define if you have sigsetjmp and siglongjmp. */ +#undef HAVE_SIGSETJMP + +#undef HAVE_SOCKADDR_UN_SUN_LEN + +#undef HAVE_STATFS_F_BAVAIL + +/* Define if your struct stat has st_blksize. */ +#undef HAVE_ST_BLKSIZE + +/* Define if your struct stat has st_blocks. */ +#undef HAVE_ST_BLOCKS + +/* Define if you have the strcoll function and it is properly defined. */ +#undef HAVE_STRCOLL + +/* Define if your struct stat has st_rdev. */ +#undef HAVE_ST_RDEV + +/* Define if you have the strftime function. */ +#undef HAVE_STRFTIME + +/* Define if you have the ANSI # stringizing operator in cpp. */ +#undef HAVE_STRINGIZE + +#undef HAVE_STRUCT_CMSGDHR + +#undef HAVE_STRUCT_STAT64 + +/* Define if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define if your curses library has this functionality. */ +#undef HAVE_TOUCHWIN + +/* Define if your struct tm has tm_zone. */ +#undef HAVE_TM_ZONE + +/* Define if you don't have tm_zone but do have the external array + tzname. */ +#undef HAVE_TZNAME + +/* Define if you have . */ +#undef HAVE_UNISTD_H + +/* Define if utime(file, NULL) sets file's timestamp to the present. */ +#undef HAVE_UTIME_NULL + +/* Define if you have a ut_host field in your struct utmp. */ +#undef HAVE_UTMP_UT_HOST + +#undef HAVE_UTMP_UT_NAME + +#undef HAVE_UTMP_UT_USER + +#undef HAVE_UTMP_UT_PID + +#undef HAVE_UTMP_UT_TIME + +#undef HAVE_UTMPX_UT_SYSLEN + +/* Define if you have . */ +#undef HAVE_VFORK_H + +/* Define if you have the vprintf function. */ +#undef HAVE_VPRINTF + +/* Define if you have the wait3 system call. */ +#undef HAVE_WAIT3 + +/* Define as __inline if that's what the C compiler calls it. */ +#undef inline + +/* Define if chown is promiscuous (regular user can give away ownership) */ +#undef INSECURE_CHOWN + +/* Define if int is 16 bits instead of 32. */ +#undef INT_16_BITS + +/* Define if long int is 64 bits. */ +#undef LONG_64_BITS + +/* Define if major, minor, and makedev are declared in . */ +#undef MAJOR_IN_MKDEV + +/* Define if major, minor, and makedev are declared in . */ +#undef MAJOR_IN_SYSMACROS + +/* Define if on MINIX. */ +#undef _MINIX + +/* Define to `int' if doesn't define. */ +#undef mode_t + +/* Define if you don't have , but have . */ +#undef NDIR + +/* Define if you have , and doesn't declare the + mem* functions. */ +#undef NEED_MEMORY_H + +/* Define if your struct nlist has an n_un member. */ +#undef NLIST_NAME_UNION + +/* Define if you have . */ +#undef NLIST_STRUCT + +/* Define if your C compiler doesn't accept -c and -o together. */ +#undef NO_MINUS_C_MINUS_O + +/* Define if your Fortran 77 compiler doesn't accept -c and -o together. */ +#undef F77_NO_MINUS_C_MINUS_O + +/* Define to `long' if doesn't define. */ +#undef off_t + +#undef OS + +/* Define to `int' if doesn't define. */ +#undef pid_t + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +#undef _POSIX_1_SOURCE + +/* Define if you need to in order for stat and other things to work. */ +#undef _POSIX_SOURCE + +/* Format string for the printf() family for 64 bit integers. */ +#undef PRINTF_LONG_LONG + +/* Define if printing a "long long" with "%lld" works . */ +#undef PRINTF_LONG_LONG_LLD + +/* Define if printing a "long long" with "%qd" works . */ +#undef PRINTF_LONG_LONG_QD + +/* Define if your C compiler supports ANSI C function prototyping. */ +#undef PROTOTYPES + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* Format string for the scanf() family for 64 bit integers. */ +#undef SCANF_LONG_LONG + +/* Define if scanning a "long long" with "%lld" works. */ +#undef SCANF_LONG_LONG_LLD + +/* Define if scanning a "long long" with "%qd" works. */ +#undef SCANF_LONG_LONG_QD + +/* Define to the type of arg1 for select(). */ +#undef SELECT_TYPE_ARG1 + +/* Define to the type of args 2, 3 and 4 for select(). */ +#undef SELECT_TYPE_ARG234 + +/* Define to the type of arg5 for select(). */ +#undef SELECT_TYPE_ARG5 + +/* Define if the `setpgrp' function takes no argument. */ +#undef SETPGRP_VOID + +/* Define if the setvbuf function takes the buffering type as its second + argument and the buffer pointer as the third, as on System V + before release 3. */ +#undef SETVBUF_REVERSED + +/* Define to `int' if doesn't define. */ +#undef sig_atomic_t + +/* Define to `unsigned' if doesn't define. */ +#undef size_t + +#undef SNPRINTF_TERMINATES + +#undef SPRINTF_RETURNS_PTR + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +#undef STACK_DIRECTION + +/* Define if the `S_IS*' macros in do not work properly. */ +#undef STAT_MACROS_BROKEN + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define on System V Release 4. */ +#undef SVR4 + +/* Define if you don't have , but have . */ +#undef SYSDIR + +/* Define if you don't have , but have . */ +#undef SYSNDIR + +/* Define if `sys_siglist' is declared by . */ +#undef SYS_SIGLIST_DECLARED + +/* Define to the full path of the Tar program, if you have it. */ +#undef TAR + +/* Define if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Define if your declares struct tm. */ +#undef TM_IN_SYS_TIME + +/* Define to `int' if doesn't define. */ +#undef uid_t + +/* Define for Encore UMAX. */ +#undef UMAX + +/* Result of "uname -a" */ +#undef UNAME + +/* Define for Encore UMAX 4.3 that has + instead of . */ +#undef UMAX4_3 + +/* Define if you do not have , index, bzero, etc.. */ +#undef USG + +/* Define vfork as fork if vfork does not work. */ +#undef vfork + +/* Define if the closedir function returns void instead of int. */ +#undef VOID_CLOSEDIR + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN + +/* Define if the X Window System is missing or not being used. */ +#undef X_DISPLAY_MISSING + +/* Define if lex declares yytext as a char * by default, not a char[]. */ +#undef YYTEXT_POINTER + + +/* Leave that blank line there!! Autoheader needs it. + If you're adding to this file, keep in mind: + The entries are in sort -df order: alphabetical, case insensitive, + ignoring punctuation (such as underscores). */ diff --git a/reactos/apps/utils/net/ncftp/autoconf/aclocal.m4 b/reactos/apps/utils/net/ncftp/autoconf/aclocal.m4 new file mode 100644 index 00000000000..1c5a95ee2d5 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/autoconf/aclocal.m4 @@ -0,0 +1,2391 @@ +AC_DEFUN(wi_ARG_ENABLE_DEBUG, [ +# if DEBUGBUILD is yes, other macros try to set up a compilation environment +# with debugging symbols enabled. Example macros which are affected are +# wi_CFLAGS and wi_SFLAG. +# +DEBUGBUILD=no +DEBUGCONFIGUREFLAG="" +AC_ARG_ENABLE(debug, +[ --enable-debug enable debugging symbols], +[ + DEBUGBUILD=yes + DEBUGCONFIGUREFLAG="--enable-debug" +],[ + DEBUGBUILD=no + DEBUGCONFIGUREFLAG="" +]) +]) +dnl +dnl +dnl +dnl +AC_DEFUN(wi_EXTRA_IDIR, [ +incdir="$1" +if test -r $incdir ; then + case "$CPPFLAGS" in + *${incdir}*) + # echo " + already had $incdir" 1>&6 + ;; + *) + if test "$CPPFLAGS" = "" ; then + CPPFLAGS="-I$incdir" + else + CPPFLAGS="$CPPFLAGS -I$incdir" + fi + echo " + found $incdir" 1>&6 + ;; + esac +fi +]) +dnl +dnl +dnl +dnl +AC_DEFUN(wi_PROG_TAR, [ +TAR="" +AC_PATH_PROG(TAR, "tar") +if test -x "$TAR" ; then + AC_DEFINE_UNQUOTED(TAR, "$TAR") +fi +]) +dnl +dnl +dnl +dnl +AC_DEFUN(wi_EXTRA_LDIR, [ +libdir="$1" +if test -r $libdir ; then + case "$LDFLAGS" in + *${libdir}*) + # echo " + already had $libdir" 1>&6 + ;; + *) + if test "$LDFLAGS" = "" ; then + LDFLAGS="-L$libdir" + else + LDFLAGS="$LDFLAGS -L$libdir" + fi + echo " + found $libdir" 1>&6 + ;; + esac +fi +]) +dnl +dnl +dnl +dnl +AC_DEFUN(wi_GNU_LD, [ +AC_MSG_CHECKING([for GNU ld]) +wi_cv_prog_ld="ld" +result="no" +x=`ld --version 2>/dev/null | fgrep GNU` +if test "$x" != "" ; then + wi_cv_prog_ld="gld" + result="yes" +fi +AC_MSG_RESULT($result) +]) +dnl +dnl +dnl +dnl +AC_DEFUN(wi_LD_READONLY_TEXT, [ +if test "$SYS$wi_cv_prog_ld" = "linuxgld" ; then + LDFLAGS="$LDFLAGS -Xlinker -n" +fi +]) +dnl +dnl +dnl +dnl +AC_DEFUN(wi_EXTRA_SYSV_SUNOS_DIRS, [ +AC_MSG_CHECKING([for System V compatibility directories]) +AC_MSG_RESULT([]) +wi_EXTRA_IDIR("/usr/5include") +wi_EXTRA_LDIR("/usr/5lib") +]) +dnl +dnl +dnl If you want to also look for include and lib subdirectories in the +dnl $HOME tree, you supply "yes" as the first argument to this macro. +dnl +dnl If you want to look for subdirectories in include/lib directories, +dnl you pass the names in argument 3, otherwise pass a dash. +dnl +AC_DEFUN(wi_EXTRA_DIRS, [ +AC_MSG_CHECKING([for extra include and lib directories]) +AC_MSG_RESULT([]) +ifelse([$1], yes, [dnl +b1=`cd .. ; pwd` +b2=`cd ../.. ; pwd` +exdirs="$HOME $j $b1 $b2 $prefix $2" +if test -x "$HOME/bin/OS" ; then + b3=`$HOME/bin/OS` + b3="$HOME/$b3" + if test -d "$b3" ; then + exdirs="$b3 $exdirs" + fi +fi +],[dnl +exdirs="$prefix $2" +]) +subexdirs="$3" +if test "$subexdirs" = "" ; then + subexdirs="-" +fi +for subexdir in $subexdirs ; do +if test "$subexdir" = "-" ; then + subexdir="" +else + subexdir="/$subexdir" +fi +for exdir in $exdirs ; do + case "$exdir" in + "/usr"|"/"|"//") + if test "$exdir" = "//" ; then exdir="/" ; fi + if test "$subexdir" != ""; then + incdir="${exdir}/include${subexdir}" + wi_EXTRA_IDIR($incdir) + + libdir="${exdir}/lib${subexdir}" + wi_EXTRA_LDIR($libdir) + fi + ;; + *) + if test "$subexdir" = ""; then + incdir="${exdir}/include${subexdir}" + wi_EXTRA_IDIR($incdir) + + libdir="${exdir}/lib${subexdir}" + wi_EXTRA_LDIR($libdir) + fi + ;; + esac +done +done +]) +dnl +dnl +dnl +AC_DEFUN(wi_HPUX_CFLAGS, +[AC_MSG_CHECKING(if HP-UX ansi C compiler flags are needed) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([wi_OS_VAR]) +ac_cv_hpux_flags=no +if test "$os" = hp-ux ; then + if test "$ac_cv_prog_gcc" = yes ; then + if test "$CFLAGS" != "" ; then + # Shouldn't be in there. +changequote(<<, >>)dnl + CFLAGS=`echo "$CFLAGS" | sed 's/-A[ae]//g'` +changequote([, ])dnl + case "$CFLAGS" in + *_HPUX_SOURCE*) + ;; + *) + # This is required for the extended + # namespace. + # + CFLAGS="-D_HPUX_SOURCE $CFLAGS" + ;; + esac + fi + else + # If you're not using gcc, then you better have a cc/c89 + # that is usable. If you have the barebones compiler, it + # won't work. The good compiler uses -Aa for the ANSI + # compatible stuff. +changequote(<<, >>)dnl + x=`echo "$CFLAGS" | grep 'A[ae]' 2>/dev/null` +changequote([, ])dnl + if test "$x" = "" ; then + CFLAGS="$CFLAGS -Ae" + fi + fi + ac_cv_hpux_flags=yes +fi +AC_MSG_RESULT($ac_cv_hpux_flags) +]) +dnl +dnl +dnl +AC_DEFUN(wi_SFLAG, [AC_REQUIRE([AC_PROG_CC]) +STRIP="strip" +if test "$SFLAG" = "" ; then + SFLAG="-s" + case "$OS" in + macosx*) + SFLAG='-Wl,-x' + ;; + esac +fi +# +# Was it ./configure --enable-debug ? +# +if test "$DEBUGBUILD" = yes ; then + SFLAG="" + STRIP=":" +fi +case "$CFLAGS" in + "-g"|"-g "*|*" -g"|*" -g "*|*"-g"[0-9]*) + # SFLAG="# $SFLAG" + SFLAG="" + STRIP=":" + ;; +esac +STRIPFLAG="$SFLAG" +]) +dnl +dnl +dnl +AC_DEFUN(wi_REQUEST_NO_Y2K_WARNINGS, [ + wi_cv_request_no_y2k=yes +]) +dnl +dnl +dnl +AC_DEFUN(wi_CFLAGS_NO_Y2K_WARNINGS, [AC_REQUIRE([AC_PROG_CC]) +if test "$ac_cv_prog_gcc" = yes ; then + case "$CFLAGS" in + *-Wno-format-y2k*) + ;; + *) + oldCFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wno-format-y2k" + # + # Now check if this version of GCC + # accepts this flag... + # +AC_TRY_COMPILE([],[int junk;],[],[CFLAGS="$oldCFLAGS"]) + unset oldCFLAGS + ;; + esac +fi +]) +dnl +dnl +dnl +AC_DEFUN(wi_CFLAGS, [AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE_CPP() +wi_HPUX_CFLAGS + if test "$CFLAGS" = "" ; then + AC_MSG_WARN([Your CFLAGS environment variable was not set. A default of \"-g\" will be used.]) + CFLAGS="-g" + fi + if test "x$wi_cv_request_no_y2k" = xyes ; then + wi_CFLAGS_NO_Y2K_WARNINGS + fi + if test "$NOOPTCFLAGS" = "" ; then +changequote(<<, >>)dnl + NOOPTCFLAGS=`echo "$CFLAGS" | sed 's/[-+]O[0-9A-Za-z]*//g;s/-xO[0-9]//g;s/-Wc,-O3//g;s/-IPA//g;s/\ \ */ /g;s/^\ *//;s/\ *$//;'` +changequote([, ])dnl + fi + if test "$DEBUGCFLAGS" = "" ; then + DEBUGCFLAGS="-g $NOOPTCFLAGS" + fi + # + # Was it ./configure --enable-debug ? + # + AC_MSG_CHECKING([if this is a debug build]) + if test "$DEBUGBUILD" = yes ; then + AC_MSG_RESULT(yes) + CFLAGS="$DEBUGCFLAGS" + SFLAG="" + STRIPFLAG="" + STRIP=":" + else + AC_MSG_RESULT(no) + fi + AC_MSG_CHECKING([NOOPTCFLAGS]) + AC_MSG_RESULT($NOOPTCFLAGS) + AC_MSG_CHECKING([DEBUGCFLAGS]) + AC_MSG_RESULT($DEBUGCFLAGS) + AC_MSG_CHECKING([CFLAGS]) + AC_MSG_RESULT($CFLAGS) +]) +dnl +dnl +dnl +AC_DEFUN(wi_CFLAGS_LFS64, [AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([wi_OS_VAR]) +wi_CFLAGS +if test "os_${os}_gcc_${ac_cv_prog_gcc}" = os_hp-ux_gcc_yes ; then + case "$CFLAGS" in + *__STDC_EXT__*) + ;; + *) + # This is required for the extended + # namespace symbols for Large Files. + # + CFLAGS="-D__STDC_EXT__ $CFLAGS" + ;; + esac +fi +case "$CFLAGS" in + *-D_LARGEFILE64_SOURCE*) + ;; + *) + CFLAGS="-D_LARGEFILE64_SOURCE $CFLAGS" + ;; +esac +AC_MSG_CHECKING([additional CFLAGS for LFS64 support]) +AC_MSG_RESULT($CFLAGS) +]) +dnl +dnl +dnl +AC_DEFUN(wi_PROTOTYPES, [ +AC_MSG_CHECKING(if the compiler supports function prototypes) +AC_TRY_COMPILE(,[extern void exit(int status);],[wi_cv_prototypes=yes +AC_DEFINE(PROTOTYPES)],wi_cv_prototypes=no) +AC_MSG_RESULT($wi_cv_prototypes) +]) +dnl +dnl +dnl +AC_DEFUN(wi_INSECURE_CHOWN, [ +AC_MSG_CHECKING(if chown can be used to subvert security) +AC_TRY_RUN([ +#include +#include +#include + +main() +{ + int result; + char fn[64]; + FILE *fp; + struct stat st; + + setuid(1); /* if you're root, try set to someone else. */ + sprintf(fn, "/tmp/fu%06ld", (long) getpid()); + unlink(fn); + fp = fopen(fn, "w"); + if (fp == NULL) + exit(1); /* assume the worst */ + fprintf(fp, "%s\n", "hello world"); + fclose(fp); + + result = chown(fn, 0, 0); + if (stat(fn, &st) < 0) { + unlink(fn); + exit((result == 0) ? 0 : 1); + } + unlink(fn); + + /* exit(0) if the insecure chown to uid 0 succeeded. */ + exit((st.st_uid == 0) ? 0 : 1); +}],[ + # action if true + wi_cv_insecure_chown=yes + AC_DEFINE(INSECURE_CHOWN) +],[ + # action if false + wi_cv_insecure_chown=no +],[ + # action if cross-compiling, guess + wi_cv_insecure_chown=no +]) + +AC_MSG_RESULT($wi_cv_insecure_chown) +]) +dnl +dnl +dnl +AC_DEFUN(wi_LIB_SNPRINTF, [ +if test "$ac_cv_func_snprintf" = "no" ; then + AC_CHECK_LIB(snprintf,snprintf) + if test "$ac_cv_lib_snprintf_snprintf" = yes ; then + unset ac_cv_func_snprintf + AC_CHECK_FUNCS(snprintf) + fi +fi +]) +dnl +dnl +dnl +AC_DEFUN(wi_SNPRINTF_TERMINATES, [ +if test "$ac_cv_func_snprintf" != "no" ; then +AC_MSG_CHECKING(if snprintf always NUL terminates) + if test "$ac_cv_func_snprintf" = "no" ; then + AC_CHECK_LIB(snprintf,snprintf) + fi +AC_TRY_RUN([ + /* program */ +#include +#include + +main() +{ + char s[10]; + int i, result; + + for (i=0; i<(int)(sizeof(s)/sizeof(char)); i++) + s[i] = 'x'; + result = (int) snprintf(s, sizeof(s), "%s %s!", "hello", "world"); + if (s[sizeof(s) - 1] == '\0') + exit(0); + exit(1); + +} +],[ + # action if true + wi_cv_snprintf_terminates=no + AC_DEFINE(SNPRINTF_TERMINATES) + x="yes"; +],[ + # action if false + wi_cv_snprintf_terminates=yes + x="no"; +],[ + # action if cross compiling + wi_cv_snprintf_terminates=no + x="unknown"; +]) +AC_MSG_RESULT($x) +fi +]) +dnl +dnl +dnl +AC_DEFUN(wi_SNPRINTF, [ +wi_SPRINTF_RETVAL +dnl Uncache these -- config.cache doesn't cache it right for this case. +unset ac_cv_func_snprintf +unset ac_cv_func_vsnprintf + +AC_CHECK_FUNCS(snprintf vsnprintf) +wi_SNPRINTF_TERMINATES + +AC_CHECK_HEADERS(snprintf.h) +wi_LIB_SNPRINTF +]) +dnl +dnl +dnl +AC_DEFUN(wi_HEADER_HPSECURITY_H, [ +AC_MSG_CHECKING(for hpsecurity.h) +wi_cv_header_hpsecurity_h=no +if test -f /usr/include/hpsecurity.h ; then + wi_cv_header_hpsecurity_h=yes + AC_DEFINE(HAVE_HPSECURITY_H) +fi +AC_MSG_RESULT($wi_cv_header_hpsecurity_h) +]) +dnl +dnl +dnl +AC_DEFUN(wi_HEADER_SYS_SELECT_H, [ +# See if is includable after +if test "$ac_cv_header_sys_time_h" = no ; then +AC_CHECK_HEADERS(sys/time.h sys/select.h) +else +AC_CHECK_HEADERS(sys/select.h) +fi +if test "$ac_cv_header_sys_select_h" = yes ; then + AC_MSG_CHECKING([if is compatible with ]) + selecth=yes + if test "$ac_cv_header_sys_time_h" = yes ; then + AC_TRY_COMPILE([ +#if defined(_AIX) || defined(__aix) || defined(__AIX) +# define _ALL_SOURCE 1 +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include ],[ + fd_set a; + struct timeval tmval; + + tmval.tv_sec = 0;],selecth=yes,selecth=no) + fi + if test "$selecth" = yes ; then + AC_DEFINE(CAN_USE_SYS_SELECT_H) + fi + AC_MSG_RESULT($selecth) +fi +]) +dnl +dnl +dnl +AC_DEFUN(wi_LIB_44BSD, [ +AC_CHECK_FUNC(strerror,[a=yes],[a=no]) +if test "$a" = no ; then + # Not in libc, try lib44bsd. + AC_CHECK_LIB(44bsd,strerror) +fi +]) +dnl +dnl +dnl +AC_DEFUN(wi_LIB_NSL, [ +dnl Note: Check for socket lib first, then nsl. + +case "$OS" in + hpux1[123456789]*) + # HP-UX 11 uses NSL for YP services + AC_CHECK_LIB(nsl,getpwent) + ;; + + *) + AC_CHECK_FUNC(gethostbyname,[a=yes],[a=no]) + if test "$a" = no ; then + # Not in libc, try libnsl. + AC_CHECK_LIB(nsl,gethostbyname) + fi + ;; +esac + +]) +dnl +dnl +dnl +AC_DEFUN(wi_LIB_SOCKET, [ +AC_CHECK_FUNC(socket,[a=yes],[a=no]) +if test "$a" = no ; then + # Not in libc, try libsocket. + AC_CHECK_LIB(socket,socket) +fi +]) +dnl +dnl +dnl +AC_DEFUN(wi_LIB_RESOLV, [ +# See if we could access two well-known sites without help of any special +# libraries, like resolv. +dnl +AC_MSG_WARN([the following check may take several minutes if networking is not up. You may want to bring it up now and restart configure, otherwise please be patient.]) +dnl +AC_MSG_CHECKING([if we need to look for -lresolv]) +AC_TRY_RUN([ +#include +#include +#include +#include + +main() +{ + struct hostent *hp1, *hp2; + int result; + + hp1 = gethostbyname("gatekeeper.dec.com"); + hp2 = gethostbyname("ftp.ncsa.uiuc.edu"); + result = ((hp1 != (struct hostent *) 0) && (hp2 != (struct hostent *) 0)); + exit(! result); +}],look_for_resolv=no,look_for_resolv=yes,look_for_resolv=yes) + +AC_MSG_RESULT($look_for_resolv) +if test "$look_for_resolv" = yes ; then +AC_CHECK_LIB(resolv,main) +else + ac_cv_lib_resolv=no +fi +]) +dnl +dnl +dnl +AC_DEFUN(wi_LIB_TCP_WRAPPERS, [ +AC_MSG_CHECKING([for tcp wrappers library (libwrap)]) + +AC_TRY_LINK([ + /* includes */ +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include + +/* These are needed if libwrap.a was compiled with + * PROCESS_OPTIONS defined. + */ +int allow_severity = 1; /* arbitrary for this test */ +int deny_severity = 2; /* arbitrary for this test */ + +],[ + /* function-body */ + exit((allow_severity == deny_severity) ? 1 : 0); +],[ +dnl ...Don't bother defining this symbol... +dnl ...Check for tcpd.h instead... +dnl AC_DEFINE(HAVE_LIBWRAP) +dnl +dnl ...Don't modify LIBS, instead set WRAPLIB... +dnl LIBS="-lwrap $LIBS" +dnl + WRAPLIB="-lwrap" + wi_cv_lib_wrap_hosts_access=yes +],[ + WRAPLIB="" + wi_cv_lib_wrap_hosts_access=no +]) +AC_MSG_RESULT($wi_cv_lib_wrap_hosts_access) +]) +dnl +dnl +dnl +AC_DEFUN(wi_NET_LIBS, [ +# Mostly for SunOS 4 -- needs to come first because other libs depend on it +wi_LIB_44BSD + +wi_LIB_SOCKET + +if test "$SYS" = unixware ; then + # So far, only UnixWare needs this. + AC_CHECK_LIB(gen,syslog) + + case "$OS" in + unixware2*) + if test -f /usr/ucblib/libucb.a ; then + LDFLAGS="$LDFLAGS -L/usr/ucblib" + LIBS="$LIBS -lucb" + fi + if test -f /usr/include/unistd.h ; then + ac_cv_header_unistd_h=yes + fi + + # UnixWare 2 needs both lsocket and lnsl, and configure + # script won't detect this condition properly because + # the libraries are interdependent. + # + LIBS="$LIBS -lsocket -lnsl" + + # Now look for socket() + # + # AC_CHECK_FUNC(socket,[a=yes],[a=no]) + # + AC_CHECK_FUNC(socket,[a=yes],[a=no]) + ;; + *) + ;; + esac +fi + +dnl AC_CHECK_LIB(inet,main) + +wi_LIB_NSL +wi_LIB_RESOLV + +if test "$SYS" = dynixptx ; then + LIBS="$LIBS -lsocket -lnsl" +fi + +]) +dnl +dnl +dnl +dnl +AC_DEFUN(wi_DEFINE_UNAME, [ +# Get first 127 chars of all uname information. Some folks have +# way too much stuff there, so grab only the first 127. +unam=`uname -a 2>/dev/null | cut -c1-127` +if test "$unam" != "" ; then + AC_DEFINE_UNQUOTED(UNAME, "$unam") +fi +]) +dnl +dnl +dnl +AC_DEFUN(wi_FUNC_SIGSETJMP, [ +AC_MSG_CHECKING([for sigsetjmp and siglongjmp]) + +AC_TRY_LINK([ + /* includes */ +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include +],[ + /* function-body */ + sigjmp_buf sjb; + + if (sigsetjmp(sjb, 1) != 0) + siglongjmp(sjb, 1); /* bogus code, of course. */ + exit(0); +],[ + AC_DEFINE(HAVE_SIGSETJMP) + wi_cv_func_sigsetjmp=yes +],[ + wi_cv_func_sigsetjmp=no +]) +AC_MSG_RESULT($wi_cv_func_sigsetjmp) +]) +dnl +dnl +dnl +AC_DEFUN(wi_UTMP_UT_NAME, [ +AC_MSG_CHECKING([for ut_name field in struct utmp]) +AC_TRY_LINK([ + /* includes */ +#include +#include +#include +],[ +struct utmp u; + +u.ut_name[0] = '\0'; +exit(((int) &u.ut_name) & 0xff); /* bogus code, of course. */ +],[ + wi_cv_utmp_ut_name=yes + AC_DEFINE(HAVE_UTMP_UT_NAME) +],[ + wi_cv_utmp_ut_name=no +]) +AC_MSG_RESULT($wi_cv_utmp_ut_name) +]) +dnl +dnl +dnl +AC_DEFUN(wi_UTMPX_UT_SYSLEN, [ +AC_MSG_CHECKING([for ut_syslen field in struct utmpx]) +AC_TRY_LINK([ + /* includes */ +#include +#include +#include +],[ +struct utmpx u; + +u.ut_syslen = 0; +exit(((int) &u.ut_syslen) & 0xff); /* bogus code, of course. */ +],[ + wi_cv_utmpx_ut_syslen=yes + AC_DEFINE(HAVE_UTMPX_UT_SYSLEN) +],[ + wi_cv_utmpx_ut_syslen=no +]) +AC_MSG_RESULT($wi_cv_utmpx_ut_syslen) +]) +dnl +dnl +dnl +AC_DEFUN(wi_UTMP_UT_USER, [ +AC_MSG_CHECKING([for ut_user field in struct utmp]) +AC_TRY_LINK([ + /* includes */ +#include +#include +#include +],[ +struct utmp u; + +u.ut_user[0] = '\0'; +exit(((int) &u.ut_user) & 0xff); /* bogus code, of course. */ +],[ + wi_cv_utmp_ut_user=yes + AC_DEFINE(HAVE_UTMP_UT_USER) +],[ + wi_cv_utmp_ut_user=no +]) +AC_MSG_RESULT($wi_cv_utmp_ut_user) +]) +dnl +dnl +dnl +AC_DEFUN(wi_UTMP_UT_PID, [ +AC_MSG_CHECKING([for ut_pid field in struct utmp]) +AC_TRY_LINK([ + /* includes */ +#include +#include +#include +],[ +struct utmp u; + +u.ut_pid = 1; +exit(((int) &u.ut_pid) & 0xff); /* bogus code, of course. */ +],[ + wi_cv_utmp_ut_pid=yes + AC_DEFINE(HAVE_UTMP_UT_PID) +],[ + wi_cv_utmp_ut_pid=no +]) +AC_MSG_RESULT($wi_cv_utmp_ut_pid) +]) + +dnl +dnl +dnl +AC_DEFUN(wi_UTMP_UT_TIME, [ +AC_MSG_CHECKING([for ut_time field in struct utmp]) +AC_TRY_LINK([ + /* includes */ +#include +#include +#include +],[ +struct utmp u; + +u.ut_time = 1; +exit(((int) &u.ut_time) & 0xff); /* bogus code, of course. */ +],[ + wi_cv_utmp_ut_time=yes + AC_DEFINE(HAVE_UTMP_UT_TIME) +],[ + wi_cv_utmp_ut_time=no +]) +AC_MSG_RESULT($wi_cv_utmp_ut_time) +]) +dnl +dnl +dnl +AC_DEFUN(wi_UTMP_UT_HOST, [ +AC_MSG_CHECKING([for ut_host field in struct utmp]) +AC_TRY_LINK([ + /* includes */ +#include +#include +#include +],[ +struct utmp u; + +u.ut_host[0] = '\0'; +exit(((int) &u.ut_host) & 0xff); /* bogus code, of course. */ +],[ + wi_cv_utmp_ut_host=yes + AC_DEFINE(HAVE_UTMP_UT_HOST) +],[ + wi_cv_utmp_ut_host=no +]) +AC_MSG_RESULT($wi_cv_utmp_ut_host) +]) +dnl +dnl +dnl +AC_DEFUN(wi_STRUCT_STAT64, [ +AC_MSG_CHECKING([for struct stat64]) +AC_TRY_LINK([ + /* includes */ +#include +#include +#include +],[ +struct stat64 st; + +st.st_size = 0; +exit(((int) &st.st_size) & 0xff); /* bogus code, of course. */ +],[ + wi_cv_struct_stat64=yes + AC_DEFINE(HAVE_STRUCT_STAT64) +],[ + wi_cv_struct_stat64=no +]) +AC_MSG_RESULT($wi_cv_struct_stat64) +]) +dnl +dnl +dnl +AC_DEFUN(wi_STRUCT_CMSGHDR, [ +AC_MSG_CHECKING([for struct cmsghdr]) +AC_TRY_LINK([ + /* includes */ +#include +#include +#include +#include +#include +],[ +struct cmsghdr cm; + +cm.cmsg_len = 0; +cm.cmsg_level = 0; +cm.cmsg_type = 0; +exit(((int) &cm.cmsg_type) & 0xff); /* bogus code, of course. */ +],[ + wi_cv_struct_cmsghdr=yes + AC_DEFINE(HAVE_STRUCT_CMSGDHR) +],[ + wi_cv_struct_cmsghdr=no +]) +AC_MSG_RESULT($wi_cv_struct_cmsghdr) +]) +dnl +dnl +dnl +AC_DEFUN(wi_MSGHDR_CONTROL, [ +AC_MSG_CHECKING([for msg_control field in struct msghdr]) +AC_TRY_LINK([ + /* includes */ +#include +#include +#include +#include +#include +],[ +struct msghdr m; + +m.msg_control = &m; +m.msg_controllen = sizeof(m); +exit(((int) &m.msg_control) & 0xff); /* bogus code, of course. */ +],[ + wi_cv_msghdr_control=yes + AC_DEFINE(HAVE_MSGHDR_CONTROL) +],[ + wi_cv_msghdr_control=no +]) +AC_MSG_RESULT($wi_cv_msghdr_control) +]) +dnl +dnl +dnl +AC_DEFUN(wi_MSGHDR_ACCRIGHTS, [ +AC_MSG_CHECKING([for msg_accrights field in struct msghdr]) +AC_TRY_LINK([ + /* includes */ +#include +#include +#include +#include +#include +],[ +struct msghdr m; + +m.msg_accrights = &m; +m.msg_accrightslen = sizeof(m); +exit(((int) &m.msg_accrights) & 0xff); /* bogus code, of course. */ +],[ + wi_cv_msghdr_accrights=yes + AC_DEFINE(HAVE_MSGHDR_ACCRIGHTS) +],[ + wi_cv_msghdr_accrights=no +]) +AC_MSG_RESULT($wi_cv_msghdr_accrights) +]) +dnl +dnl +dnl +AC_DEFUN(wi_PR_PASSWD_FG_OLDCRYPT, [ +AC_MSG_CHECKING([for fg_oldcrypt field in struct pr_passwd]) +AC_TRY_LINK([ + /* includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(HAVE_USERPW_H) && defined(HAVE_GETUSERPW) /* AIX */ +# include +#elif defined(HAVE_PWDADJ_H) && defined(HAVE_GETPWANAM) /* SunOS */ +# include +# ifdef HAVE_SYS_AUDIT_H +# include +# endif +# include +#elif defined(HAVE_GETESPWNAM) /* Digital UNIX 4 */ +# ifdef HAVE_SYS_SECDEFINES_H +# include +# endif +# ifdef HAVE_SYS_SECURITY_H +# include +# endif +# ifdef HAVE_SYS_AUDIT_H +# include +# endif +# ifdef HAVE_KRB_H +# include +# endif +# ifdef HAVE_PROT_H +# include +# endif +#elif defined(HAVE_GETPRPWNAM) /* SCO Open Server V, Digital UNIX 3, HP-UX 10 */ +# ifdef HAVE_SYS_SECDEFINES_H +# include +# endif +# ifdef HAVE_SYS_SECURITY_H +# include +# endif +# ifdef HAVE_SYS_AUDIT_H +# include +# endif +# ifdef HAVE_HPSECURITY_H +# include +# endif +# ifdef HAVE_KRB_H +# include +# endif +# ifdef HAVE_PROT_H +# include +# endif +#endif +],[ + struct pr_passwd xu; + memset(&xu, 0, sizeof(xu)); + if (xu.uflg.fg_oldcrypt != 0) + xu.uflg.fg_oldcrypt++; /* bogus code, of course */ + exit(0); +],[ + wi_cv_pr_passwd_fg_oldcrypt=yes + AC_DEFINE(HAVE_PR_PASSWD_FG_OLDCRYPT) +],[ + wi_cv_pr_passwd_fg_oldcrypt=no +]) +AC_MSG_RESULT($wi_cv_pr_passwd_fg_oldcrypt) +]) +dnl +dnl +dnl +AC_DEFUN(wi_SOCKADDR_UN_SUN_LEN, [ +AC_MSG_CHECKING([for sun_len field in struct sockaddr_un]) +AC_TRY_LINK([ + /* includes */ +#include +#include +#include +#include +#include +],[ +struct sockaddr_un uaddr; + +uaddr.sun_len = strlen("/tmp/test.sock"); +exit(((int) uaddr.sun_len); /* bogus code, of course. */ +],[ + wi_cv_sockaddr_un_sun_len=yes + AC_DEFINE(HAVE_SOCKADDR_UN_SUN_LEN) +],[ + wi_cv_sockaddr_un_sun_len=no +]) +AC_MSG_RESULT($wi_cv_sockaddr_un_sun_len) +]) +dnl +dnl +dnl +AC_DEFUN(wi_STATFS_F_BAVAIL, [ +AC_MSG_CHECKING([for f_bavail field in struct statfs]) +AC_TRY_LINK([ + /* includes */ +#include +#include +#ifdef HAVE_SYS_STATFS_H +# include +#elif defined(HAVE_SYS_VFS_H) +# include +#endif +],[ +struct statfs st; + +st.f_bavail = 1; +exit((int) st.f_bavail); /* bogus code, of course. */ +],[ + wi_cv_statfs_f_bavail=yes + AC_DEFINE(HAVE_STATFS_F_BAVAIL) +],[ + wi_cv_statfs_f_bavail=no +]) +AC_MSG_RESULT($wi_cv_statfs_f_bavail) +]) +dnl +dnl +dnl +AC_DEFUN(wi_SPRINTF_RETVAL, [ +AC_MSG_CHECKING([what sprintf() returns]) +AC_TRY_RUN([ + /* program */ +#include +#include + +main() +{ + int result; + char s[8]; + + result = (int) sprintf(s, "%d", 22); + if (result == 2) + exit(0); + exit(1); + +} +],[ + # action if true + wi_cv_sprintf_returns_ptr=no + x="length of data written"; +],[ + # action if false + wi_cv_sprintf_returns_ptr=yes + AC_DEFINE(SPRINTF_RETURNS_PTR) + x="pointer to data"; +],[ + # action if cross compiling + wi_cv_sprintf_returns_ptr=no + x="unknown"; +]) +AC_MSG_RESULT($x) +]) +dnl +dnl +dnl +AC_DEFUN(wi_LIB_CRYPT, [ +AC_MSG_CHECKING([which library has usable crypt() function]) +ac_save_LIBS="$LIBS" +crypt_lib=NONE + +for lib in "c" "crypt" "descrypt" "des" +do + +if test "$lib" = "c" ; then + LIBS="$ac_save_LIBS" +else + LIBS="$ac_save_LIBS -l${lib}" +fi + +AC_TRY_RUN([ + /* program */ +#include +#include + +extern char *crypt(const char *key, const char *salt); + +main() +{ + char cleartext[256]; + char *cp; + + memset(cleartext, 0, sizeof(cleartext)); + strcpy(cleartext, "password"); + + cp = crypt(cleartext, "xx"); + if ((cp != NULL) && (strcmp(cp, "xxj31ZMTZzkVA") == 0)) { + /* printf("PASS\n"); */ + exit(0); + } + /* printf("FAIL\n"); */ + exit(1); +} +],[ + # action if true + crypt_lib="$lib" +],[ + # action if false + : +],[ + # action if cross compiling + : +]) + + +if test "$crypt_lib" != NONE ; then + break +fi + +done + + +LIBS="$ac_save_LIBS" + +if test "$crypt_lib" = NONE ; then + crypt_lib=c + AC_MSG_RESULT([none?]) +else + AC_MSG_RESULT([lib${crypt_lib}]) +fi +if test "$crypt_lib" != c ; then + AC_CHECK_LIB(${lib},crypt) +fi +]) +dnl +dnl +dnl +AC_DEFUN(wi_TEST, [ +changequote(<^, ^>)dnl +changequote([, ])dnl +]) +dnl +dnl +dnl +AC_DEFUN(wi__RES_DEFDNAME, [ +AC_MSG_CHECKING([for useable _res global variable]) +AC_TRY_LINK([ + /* includes */ +#include +#include +#include +#include +#include +#include +#ifdef HAVE_ARPA_NAMESER_H +# include +#endif +#ifdef HAVE_RESOLV_H +# include +#endif +],[ + /* function-body */ + int len; + + res_init(); + len = (int) strlen(_res.defdname); +],[ + wi_cv__res_defdname=yes + AC_DEFINE(HAVE__RES_DEFDNAME) +],[ + wi_cv__res_defdname=no +]) +AC_MSG_RESULT($wi_cv__res_defdname) +]) +dnl +dnl +dnl +dnl +AC_DEFUN(wi_TYPE_SIG_ATOMIC_T, [ +AC_MSG_CHECKING([for sig_atomic_t]) +AC_TRY_LINK([ + /* includes */ +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include /* MG: for IRIX */ +#if STDC_HEADERS +#include +#include +#endif +],[ + /* function-body */ + sig_atomic_t sample; + + sample = (sig_atomic_t) getpid(); /* bogus code, of course */ + exit((sample > 0) ? 0 : 1); +],[ + ac_cv_type_sig_atomic_t=yes +],[ + ac_cv_type_sig_atomic_t=no +]) +AC_MSG_RESULT($ac_cv_type_sig_atomic_t) +if test $ac_cv_type_sig_atomic_t = no ; then + AC_DEFINE(sig_atomic_t, int) +fi +]) +dnl +dnl +dnl +dnl +AC_DEFUN(wi_LIB_READLINE, [ +AC_MSG_CHECKING([for GNU Readline library, version 2.0 or newer]) + +wi_cv_lib_readline=no +wi_cv_lib_readline_result=no +ac_save_LIBS="$LIBS" +# Note: $LIBCURSES is permitted to be empty. +for LIBREADLINE in "-lreadline" "-lreadline $LIBCURSES" "-lreadline -ltermcap" "-lreadline -lncurses" "-lreadline -lcurses" +do + LIBS="$ac_save_LIBS $LIBREADLINE" + AC_TRY_RUN([ + /* program */ +#include +#include + +main(int argc, char **argv) +{ + /* Note: don't actually call readline, since it may block; + * We just want to see if it (dynamic) linked in okay. + */ + if (argc == 0) /* never true */ + readline(0); + exit(0); +} +],[ + # action if true + wi_cv_lib_readline=yes +],[ + # action if false + wi_cv_lib_readline=no +],[ + # action if cross compiling + wi_cv_lib_readline=no +]) + + if test "$wi_cv_lib_readline" = yes ; then break ; fi +done + +# Now try it again, to be sure it is recent enough. +# rl_function_of_keyseq appeared in version 2.0 +# +dnl AC_CHECK_FUNC(rl_function_of_keyseq, [wi_cv_lib_readline=yes],[ +dnl wi_cv_lib_readline=no;wi_cv_lib_readline_result="no (it is present but too old to use)" +dnl ]) + AC_TRY_LINK([ + /* includes */ + ],[ + /* function-body */ + readline(0); + rl_function_of_keyseq(0); + ],[ + wi_cv_lib_readline=yes + ],[ + wi_cv_lib_readline=no + wi_cv_lib_readline_result="no (it is present but too old to use)" + ]) + +if test "$wi_cv_lib_readline" = no ; then + LIBREADLINE="" + # restore LIBS + LIBS="$ac_save_LIBS" +else + /bin/rm -f readline.ver + touch readline.ver + + AC_TRY_RUN([ + /* program */ +#include +#include +#include + +extern char *rl_library_version; + +main() +{ + FILE *fp; + double d; + + sscanf(rl_library_version, "%lf", &d); + fp = fopen("readline.ver", "w"); + if (fp == NULL) exit(1); + if (fprintf(fp, "%s\n", rl_library_version) < 0) exit(1); + if (fprintf(fp, "%03d\n", (int) (d * 100.0)) < 0) exit(1); + if (fclose(fp) < 0) exit(1); + exit(0); +} + ],[ + # action if true + rl_library_version=`sed -n 1,1p readline.ver 2>/dev/null` + rlver=`sed -n 2,2p readline.ver 2>/dev/null` + /bin/rm -f readline.ver + ],[ + # action if false + rl_library_version='' + rlver='' + /bin/rm -f readline.ver + ],[ + # action if cross compiling + rl_library_version='' + rlver='' + /bin/rm -f readline.ver + ]) + + case "$rlver" in + ???) + wi_cv_lib_readline_result="yes, installed version is $rl_library_version" + ;; + *) + # Test using current LIBS. + AC_TRY_LINK([ + /* includes */ + extern int rl_completion_append_character; + ],[ + /* function-body */ + readline(0); + rl_completion_append_character = 0; + ],[ + rlver="210" + ],[ + rlver="200" + ]) + + if test "$rlver" = "210" ; then + wi_cv_lib_readline_result="yes, version 2.1 or higher" + else + wi_cv_lib_readline_result="yes, version 2.0" + fi + ;; + esac + + wi_cv_lib_readline=yes + # restore LIBS + LIBS="$ac_save_LIBS" +fi +AC_MSG_RESULT($wi_cv_lib_readline_result) +AC_SUBST(LIBREADLINE) + +if test "$wi_cv_lib_readline" = yes ; then + # Now verify that all the headers are installed. + # + AC_REQUIRE_CPP() + unset ac_cv_header_readline_chardefs_h + unset ac_cv_header_readline_history_h + unset ac_cv_header_readline_keymaps_h + unset ac_cv_header_readline_readline_h + unset ac_cv_header_readline_tilde_h + AC_CHECK_HEADERS([readline/chardefs.h readline/history.h readline/keymaps.h readline/readline.h readline/tilde.h]) + + for xxwi in \ + "$ac_cv_header_readline_chardefs_h" \ + "$ac_cv_header_readline_history_h" \ + "$ac_cv_header_readline_keymaps_h" \ + "$ac_cv_header_readline_readline_h" \ + "$ac_cv_header_readline_tilde_h" + do + if test "$xxwi" = no ; then + break + fi + done + + if test "$xxwi" = no ; then + AC_MSG_WARN([GNU Readline headers are not installed or could not be found -- GNU Readline will not be used.]) + wi_cv_lib_readline=no + wi_cv_lib_readline_result="no (headers not installed)" + else + AC_DEFINE_UNQUOTED(HAVE_LIBREADLINE, $rlver) + fi +fi +]) +dnl +dnl +dnl +AC_DEFUN(wi_USE_LONG_LONG, [ +AC_MSG_CHECKING([for 64-bit integral type: long long]) +LONGEST_INT="long" +AC_TRY_RUN([ + /* program */ +#include +#include +#include + +long long hugeNumvar = 1; + +main() +{ + long long hugeNumtoo = 2; + + if (hugeNumtoo > hugeNumvar) + hugeNumvar++; + if (sizeof(hugeNumvar) < 8) + exit(1); + exit(0); +} + +],[ + # action if true + wi_cv_type_long_long=yes + LONGEST_INT="long long" +],[ + # action if false + wi_cv_type_long_long=no +],[ + # action if cross compiling + wi_cv_type_long_long=no +]) +AC_MSG_RESULT($wi_cv_type_long_long) + +if test "$wi_cv_type_long_long" = yes ; then + +AC_MSG_CHECKING([how to print a 64-bit integral type]) +wi_cv_printf_long_long=fail + +AC_TRY_RUN([ + /* program */ +#include +#include +#include +#include +#include + +main() +{ + char s[80]; + long long hugeNum; + + hugeNum = (long long) 1000000000; + hugeNum = hugeNum * (long long) 99; + hugeNum = hugeNum + (long long) 1; + + (void) sprintf(s, "%lld", hugeNum); + exit((strcmp(s, "99000000001") == 0) ? 0 : 1); +} +],[ + # action if true + wi_cv_printf_long_long="%lld" +],[ + # action if false + : +],[ + # action if cross compiling + : +]) + + +if test "$wi_cv_printf_long_long" = fail ; then + +AC_TRY_RUN([ + /* program */ +#include +#include +#include +#include +#include + +main() +{ + char s[80]; + long long hugeNum; + + hugeNum = (long long) 1000000000; + hugeNum = hugeNum * (long long) 99; + hugeNum = hugeNum + (long long) 1; + + (void) sprintf(s, "%qd", hugeNum); + exit((strcmp(s, "99000000001") == 0) ? 0 : 1); +} +],[ + # action if true + wi_cv_printf_long_long="%qd" +],[ + # action if false + : +],[ + # action if cross compiling + : +]) +fi + +if test "$wi_cv_printf_long_long" = fail ; then + wi_cv_printf_long_long_msg_result='cannot print' +else + wi_cv_printf_long_long_msg_result="$wi_cv_printf_long_long" +fi + +AC_MSG_RESULT($wi_cv_printf_long_long_msg_result) + + +AC_MSG_CHECKING([how to scan a 64-bit integral type]) +wi_cv_scanf_long_long=fail + +AC_TRY_RUN([ + /* program */ +#include +#include +#include +#include +#include + +main() +{ + long long hugeNum, justAsHugeNum; + + hugeNum = (long long) 1000000000; + hugeNum = hugeNum * (long long) 99; + hugeNum = hugeNum + (long long) 1; + + justAsHugeNum = (long long) 0; + --justAsHugeNum; + sscanf("99000000001", "%lld", &justAsHugeNum); + if (memcmp(&hugeNum, &justAsHugeNum, sizeof(hugeNum)) == 0) + exit(0); + exit(1); +} +],[ + # action if true + wi_cv_scanf_long_long="%lld" +],[ + # action if false + : +],[ + # action if cross compiling + : +]) + + +if test "$wi_cv_scanf_long_long" = fail ; then + +AC_TRY_RUN([ + /* program */ +#include +#include +#include +#include +#include + +main() +{ + long long hugeNum, justAsHugeNum; + + hugeNum = (long long) 1000000000; + hugeNum = hugeNum * (long long) 99; + hugeNum = hugeNum + (long long) 1; + + justAsHugeNum = (long long) 0; + --justAsHugeNum; + sscanf("99000000001", "%qd", &justAsHugeNum); + if (memcmp(&hugeNum, &justAsHugeNum, sizeof(hugeNum)) == 0) + exit(0); + exit(1); +} +],[ + # action if true + wi_cv_scanf_long_long="%qd" +],[ + # action if false + : +],[ + # action if cross compiling + : +]) +fi + +if test "$wi_cv_scanf_long_long" = fail ; then + wi_cv_scanf_long_long_msg_result='cannot scan' +else + wi_cv_scanf_long_long_msg_result="$wi_cv_scanf_long_long" +fi + +AC_MSG_RESULT($wi_cv_scanf_long_long_msg_result) + +fi + +AC_MSG_CHECKING([if everything was available to use the 64-bit integral type]) + +if test "$wi_cv_type_long_long" = no ; then + wi_cv_use_long_long_msg_result="no (long long type not available)" + wi_cv_use_long_long="no" + wi_cv_scanf_long_long="fail" + wi_cv_prihtf_long_long="fail" + LONGEST_INT="long" +elif test "$wi_cv_printf_long_long" = fail ; then + wi_cv_use_long_long_msg_result="no (libc printf() does not support them)" + wi_cv_use_long_long="no" + wi_cv_scanf_long_long="fail" + wi_cv_prihtf_long_long="fail" + LONGEST_INT="long" +elif test "$wi_cv_scanf_long_long" = fail ; then + wi_cv_use_long_long_msg_result="no (libc scanf() does not support them)" + wi_cv_use_long_long="no" + wi_cv_scanf_long_long="fail" + wi_cv_prihtf_long_long="fail" + LONGEST_INT="long" +else + AC_DEFINE(HAVE_LONG_LONG) + if test "$wi_cv_printf_long_long$wi_cv_scanf_long_long" = "%lld%qd" ; then + # FreeBSD 3.2 has %lld and %qd, but we want to + # run on 3.1 and 3.0. + # + wi_cv_printf_long_long="%qd" + fi + AC_DEFINE_UNQUOTED(PRINTF_LONG_LONG, "$wi_cv_printf_long_long") + AC_DEFINE_UNQUOTED(SCANF_LONG_LONG , "$wi_cv_scanf_long_long") + if test "$wi_cv_printf_long_long" = "%qd" ; then + AC_DEFINE(PRINTF_LONG_LONG_QD) + else + AC_DEFINE(PRINTF_LONG_LONG_LLD) + fi + if test "$wi_cv_scanf_long_long" = "%qd" ; then + AC_DEFINE(SCANF_LONG_LONG_QD) + else + AC_DEFINE(SCANF_LONG_LONG_LLD) + fi + wi_cv_use_long_long="yes" + wi_cv_use_long_long_msg_result="yes" +fi +AC_MSG_RESULT($wi_cv_use_long_long_msg_result) +]) +dnl +dnl +dnl +dnl +AC_DEFUN(wi_CREATE_TAR_FILES, [ +AC_MSG_CHECKING([how to create TAR files]) +changequote(<<, >>)dnl +TAR=/usr/bin/tar +if [ ! -f /usr/bin/tar ] && [ -f /bin/tar ] ; then + TAR=/bin/tar +fi +x="" +if [ -x /usr/bin/what ] ; then + x=`/usr/bin/what "$TAR" 2>&1 | sed -n 's/.*pax.*/pax/g;/pax/p'` +elif [ -x /bin/what ] ; then + x=`/bin/what "$TAR" 2>&1 | sed -n 's/.*pax.*/pax/g;/pax/p'` +fi +if [ "x$x" != "xpax" ] ; then + # The junk above is because Mac OS X Server's tar freaks out + # and does not exit if you do "tar --help". + # + x=`$TAR --help 2>&1 | sed -n 's/.*owner=NAME.*/owner=NAME/g;/owner=NAME/p'` +fi +case "$x" in + *owner=NAME*) + TARFLAGS="-c --owner=root --group=bin --verbose -f" + ;; + *) + TARFLAGS="cvf" + x2=`gtar --help 2>&1 | sed -n 's/.*owner=NAME.*/owner=NAME/g;/owner=NAME/p'` + case "$x2" in + *owner=NAME*) + TARFLAGS="-c --owner=root --group=bin --verbose -f" + TAR=gtar + ;; + esac + ;; +esac +changequote([, ])dnl +AC_SUBST(TARFLAGS) +AC_SUBST(TAR) +AC_MSG_RESULT([$TAR $TARFLAGS]) +]) +dnl +dnl +dnl +dnl +AC_DEFUN(wi_HEADER_CURSES, [ +AC_MSG_CHECKING([for curses library headers]) +if test "$nc_cv_ncurses" != "no" ; then + AC_CHECK_HEADERS(ncurses.h curses.h) +else + AC_CHECK_HEADERS(curses.h) +fi +dnl needed for Solaris 7 +if test "$ac_cv_header_curses_h" = no ; then + if test -f /usr/include/curses.h ; then + AC_DEFINE(HAVE_CURSES_H) + ac_cv_header_curses_h=yes + fi +fi +]) +dnl +dnl +dnl +dnl +AC_DEFUN(wi_LIB_CURSES, [ +wi_HEADER_CURSES +AC_MSG_CHECKING([for curses library]) + +wi_cv_lib_curses=no +wi_cv_lib_curses_result=no +ac_save_LIBS="$LIBS" +for LIBCURSES in "-lncurses" "-lcurses" "-lcurses -ltermcap" "-ltermcap -lcurses" +do + if test "x$LIBCURSES-$nc_cv_ncurses" = "x-lncurses-no" ; then + # This should never work + LIBCURSES="-lkdfjkdjfs" + fi + LIBS="$ac_save_LIBS $LIBCURSES" + AC_TRY_RUN([ + /* program */ +#include +#include + +#ifdef HAVE_NCURSES_H +# include +#else +# include +#endif + + +main(int argc, char **argv) +{ + /* Note: don't actually call curses, since it may block; + * We just want to see if it (dynamic) linked in okay. + */ + if (argc == 4) + initscr(); + exit(0); +} +],[ + # action if true + wi_cv_lib_curses=yes + wi_cv_lib_curses_result="yes" +],[ + # action if false + wi_cv_lib_curses=no +],[ + # action if cross compiling + wi_cv_lib_curses=no +]) + + if test "$wi_cv_lib_curses" = yes ; then break ; fi +done + +# restore LIBS +LIBS="$ac_save_LIBS" + +if test "$wi_cv_lib_curses_result" != "no" ; then + case "$LIBCURSES" in + "-lncurses") + AC_DEFINE(HAVE_LIBNCURSES) + ;; + "-lcurses") + AC_DEFINE(HAVE_LIBCURSES) + ;; + "-lcurses -ltermcap") + AC_DEFINE(HAVE_LIBCURSES) + ;; + "-ltermcap -lcurses") + AC_DEFINE(HAVE_LIBCURSES) + ;; + esac +else + LIBCURSES='' +fi + +AC_SUBST(LIBCURSES) +AC_MSG_RESULT([$wi_cv_lib_curses_result]) +]) +dnl +dnl +dnl +dnl +AC_DEFUN(wi_CURSES_FEATURES, [ +if test "$wi_cv_lib_curses" = "yes" ; then + # Then $LIBCURSES is a list of curses and support libraries. + ac_save_LIBS="$LIBS"; + LIBS="$LIBS $LIBCURSES"; + + + # maxx or _maxx + AC_MSG_CHECKING([whether curses structure has maxx or _maxx field]) + AC_TRY_COMPILE([ + /* includes */ +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include + +#ifdef HAVE_NCURSES_H +# include +#else +# include +#endif +],[ + WINDOW *w; + + w = newwin(10, 10, 1, 1); + w->maxx = 0; +],[ +AC_MSG_RESULT([maxx]) +],[ +AC_DEFINE(HAVE__MAXX) +AC_MSG_RESULT([_maxx]) +]) + + AC_CHECK_FUNCS(__getmaxx __getmaxy __getbegx __getbegy) + + # getbegx + AC_MSG_CHECKING([for getbegx() functionality in curses library]) + AC_TRY_LINK([ + /* includes */ +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include + +#ifdef HAVE_NCURSES_H +# include +#else +# include +#endif + +],[ + /* function-body */ + WINDOW *junk = 0; + int mx = 0; + + mx = getbegx(junk); + exit(0); +],[ + AC_DEFINE(HAVE_GETBEGX) + AC_MSG_RESULT([yes]) +],[ + AC_MSG_RESULT([no]) +]) + + + # getmaxx + AC_MSG_CHECKING([for getmaxx() functionality in curses library]) + AC_TRY_LINK([ + /* includes */ +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include + +#ifdef HAVE_NCURSES_H +# include +#else +# include +#endif +],[ + /* function-body */ + WINDOW *junk = 0; + int mx = 0; + + mx = getmaxx(junk); + exit(0); +],[ + AC_DEFINE(HAVE_GETMAXX) + AC_MSG_RESULT([yes]) +],[ + AC_MSG_RESULT([no]) +]) + + # getmaxyx + AC_MSG_CHECKING([for getmaxyx() functionality in curses library]) + AC_TRY_LINK([ + /* includes */ +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include + +#ifdef HAVE_NCURSES_H +# include +#else +# include +#endif +],[ + /* function-body */ + WINDOW *junk = 0; + int mx = 0, my = 0; + + getmaxyx(junk, my, mx); + exit(my < 0 ? my : 0); +],[ + AC_DEFINE(HAVE_GETMAXYX) + AC_MSG_RESULT([yes]) +],[ + AC_MSG_RESULT([no]) +]) + + # touchwin + AC_MSG_CHECKING([for touchwin() functionality in curses library]) + AC_TRY_LINK([ + /* includes */ +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include + +#ifdef HAVE_NCURSES_H +# include +#else +# include +#endif +],[ + /* function-body */ + WINDOW *junk = 0; + touchwin(junk); + exit(0); +],[ + AC_DEFINE(HAVE_TOUCHWIN) + AC_MSG_RESULT([yes]) +],[ + AC_MSG_RESULT([no]) +]) + + # beep + AC_MSG_CHECKING([for beep() functionality in curses library]) + AC_TRY_LINK([ + /* includes */ +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include + +#ifdef HAVE_NCURSES_H +# include +#else +# include +#endif +],[ + /* function-body */ + beep(); + exit(getpid() & 1); +],[ + AC_DEFINE(HAVE_BEEP) + AC_MSG_RESULT([yes]) +],[ + AC_MSG_RESULT([no]) +]) + + AC_CHECK_FUNCS(keypad nodelay curs_set doupdate wnoutrefresh) + + LIBS="$ac_save_LIBS"; +fi +]) +dnl +dnl +dnl +AC_DEFUN(wi_SHADOW_FUNCS, [ +AC_CHECK_FUNCS(md5_crypt md5crypt bcrypt getspnam) + +# UnixWare 7 +if test "$ac_cv_func_getspnam" = no ; then + unset ac_cv_func_getspnam + AC_CHECK_LIB(gen,getspnam) + if test "$ac_cv_lib_gen_getspnam" = yes ; then + AC_CHECK_FUNCS(getspnam) + fi +fi + +# AIX +# +case "$SYS" in + "aix"|"") + AC_CHECK_FUNCS(getuserpw) + ;; + *) + ;; +esac + +# C2: SCO Open Server 5; Digital UNIX +AC_CHECK_FUNCS(set_auth_parameters bigcrypt) + +# C2: Digital UNIX 3.2, 4.0; SCO Open Server 5; HP-UX 11 +AC_CHECK_FUNCS(getprpwnam) + +# Digital UNIX 4.0 +AC_CHECK_FUNCS(getespwnam get_num_crypts get_crypt_name) + +# Digital Unix 4.0 +AC_CHECK_FUNCS(dispcrypt) + +# SunOS +AC_CHECK_FUNCS(getpwanam) +]) +dnl +dnl +dnl +AC_DEFUN(wi_SHADOW_HEADERS, [ +AC_CHECK_HEADERS(shadow.h crypt.h) + +# AIX +AC_CHECK_HEADERS(userpw.h) + +# SunOS +AC_CHECK_HEADERS(pwdadj.h) + +# HP-UX +# +# Bug in header on these version 10 which cause is it not +# to get detected. +# +wi_HEADER_HPSECURITY_H + +# SCO Open Server, Digital UNIX +AC_CHECK_HEADERS(sys/security.h sys/audit.h krb.h prot.h) + +# Digital UNIX +AC_CHECK_HEADERS(sys/secdefines.h) + +# Digital UNIX +wi_PR_PASSWD_FG_OLDCRYPT +]) +dnl +dnl +dnl +AC_DEFUN(wi_SHADOW_LIBS, [ +check_for_libcrypt=yes + +# AIX security library is libs.a +AC_CHECK_LIB(s,getuserpw) +if test "$ac_cv_lib_s" = yes ; then + check_for_libcrypt=no +elif test "$ac_cv_lib_s_getuserpw" = yes ; then + check_for_libcrypt=no +fi + +# SCO OpenServer 5 stuff for shadow password +AC_CHECK_LIB(x,nap) +AC_CHECK_LIB(prot,getprpwnam) + +# Digital UNIX +AC_CHECK_LIB(security,endprpwent) + +# HP-UX +AC_CHECK_LIB(sec,getprpwnam) + +if test "$ac_cv_lib_sec_getprpwnam" = no ; then + # DYNIX/ptx + AC_CHECK_LIB(sec,getspnam) +fi + +if test "$check_for_libcrypt" = yes ; then + wi_LIB_CRYPT +fi +AC_CHECK_FUNCS(crypt) +]) +dnl +dnl +dnl +AC_DEFUN(wi_OS_VAR, [ +changequote(!@, @!)dnl +if [ -x "$HOME/bin/OS" ] ; then + HOME_OS=`$HOME/bin/OS` + HOME_OS="$HOME/$HOME_OS" +fi +host=`uname -n 2>/dev/null | tr '[A-Z]' '[a-z]'` +os=`uname -s 2>/dev/null | tr '[A-Z]' '[a-z]'` +dnl work around inability to use $1 +os_v=`uname -v 2>/dev/null | sed 's/^[^0-9.]*//;s/[^0-9.]*$//;s/pre.*//;s/test.*//' | awk '-F[-/: ]' '{n = 1; print $n; }'` +os_r=`uname -r 2>/dev/null | sed 's/^[^0-9.]*//;s/[^0-9.]*$//;s/pre.*//;s/test.*//' | awk '-F[-/: ]' '{n = 1; print $n; }'` +os_r1=`echo "${os_r}" | cut -c1` +arch=`uname -m 2>/dev/null | tr '[A-Z]' '[a-z]'` +archp=`uname -p 2>/dev/null | tr '[A-Z]' '[a-z]'` +OS='' +SYS='' +NDEFS='' + +# Special case a few systems where if your CFLAGS appear +# to want to generate for 32 bit, use that mode rather +# than 64 bit. +# +case "$os,$CFLAGS" in + irix64,*-n32*) + os=irix + # then go to regular "irix" instead of "irix64" below. + ;; +esac + +case "$os" in + osf1) + case "$os_r" in + 3*|4*) + OS="digitalunix${os_r}-$arch" + SYS=digitalunix + ;; + *) + OS="tru64unix${os_r}-$arch" + SYS=tru64unix + ;; + esac + NDEFS="$NDEFS -DDIGITAL_UNIX=$os_r1" + ;; + aix) + OS="aix${os_v}.${os_r}" + SYS=aix + NDEFS="$NDEFS -DAIX=${os_v}" + ;; + irix) + OS="irix${os_r}" + SYS=irix + NDEFS="$NDEFS -DIRIX=$os_r1" + ;; + irix64) + OS="irix64_${os_r}" + SYS=irix64 + NDEFS="$NDEFS -DIRIX=$os_r1 -DIRIX64=$os_r1" + ;; + hp-ux) + os_r=`echo "${os_r}" | cut -d. -f2-` + os_r1=`echo "$os_r" | cut -d. -f1` + os_r2=`echo "${os_r}" | cut -d. -f2` + os_int=`expr "$os_r1" '*' 100 + "$os_r2"` + OS="hpux${os_r}" + SYS=hpux + NDEFS="$NDEFS -DHPUX=$os_int" + ;; + freebsd) + OS="freebsd${os_r}-$arch" + os_r1=`echo "$os_r" | cut -d. -f1` + os_r2=`echo "$os_r" | cut -d. -f2` + os_r3=`echo "$os_r" | cut -d. -f3` + if [ "$os_r3" = "" ] ; then os_r3=0 ; fi + os_int=`expr "$os_r1" '*' 100 + "$os_r2" '*' 10 + "$os_r3"` + SYS=freebsd + NDEFS="$NDEFS -DFREEBSD=$os_int" + ;; + netbsd) + OS="netbsd${os_r}-$arch" + NDEFS="$NDEFS -DNETBSD=$os_r1" + SYS=netbsd + ;; + openbsd) + OS="openbsd${os_r}-$arch" + SYS=openbsd + NDEFS="$NDEFS -DOPENBSD=$os_r1" + ;; + sco*) + OS=scosv + SYS=sco + NDEFS="$NDEFS -DSCO=$os_r1" + ;; + dynix*) + OS="dynixptx${os_v}" + SYS=dynixptx + os_v1=`echo "$os_v" | cut -d. -f1` + os_v2=`echo "$os_v" | cut -d. -f2` + os_v3=`echo "$os_v" | cut -d. -f3` + if [ "$os_v3" = "" ] ; then os_v3=0 ; fi + os_int=`expr "$os_v1" '*' 100 + "$os_v2" '*' 10 + "$os_v3"` + NDEFS="$NDEFS -DDYNIX=$os_int" + ;; + linux) + case "$arch" in + *86) + arch=x86 + ;; + esac + + libc="" + os_r1=`echo "$os_r" | cut -d. -f1` + os_r2=`echo "$os_r" | cut -d. -f2` + os_r3=`echo "$os_r" | cut -d- -f1 | cut -d. -f3` + os_int=`expr "$os_r1" '*' 10000 + "$os_r2" '*' 1000 + "$os_r3"` + NDEFS="$NDEFS -DLINUX=$os_int" + + vertest="./vertest.$$" + /bin/rm -f "$vertest" "$vertest.c" + cat < "$vertest.c" +#include +#include + +main() +{ + const char *ver = gnu_get_libc_version(); + const char *rel = gnu_get_libc_release(); + + fprintf(stdout, "glibc%s\n", ver); + exit(0); +} +EOF + echo $ac_n "checking version of C library""... $ac_c" 1>&6 + echo "configure:: checking version of C library" >&5 + ${CC-cc} $DEFS $CPPFLAGS $CFLAGS "$vertest.c" -o "$vertest" >/dev/null 2>&1 + if [ -x "$vertest" ] ; then libc=`$vertest` ; fi + /bin/rm -f "$vertest" "$vertest.c" + + case "$libc" in + glibc*) + echo "$libc" 1>&6 + glibc_r=`echo "$libc" | sed 's/glibc//'` + glibc_r1=`echo "$glibc_r" | cut -d. -f1` + glibc_r2=`echo "$glibc_r" | cut -d. -f2` + glibc_r3=`echo "$glibc_r" | cut -d- -f1 | cut -d. -f3` + glibc_int=`expr "$glibc_r1" '*' 10000 + "$glibc_r2" '*' 1000 + "$glibc_r3"` + NDEFS="$NDEFS -DLINUX_GLIBC=$glibc_int" + libc="glibc${glibc_r1}.${glibc_r2}" + OS="linux-$arch" + ;; + *) + if test -f /lib/libc-2.2.2.so ; then + NDEFS="$NDEFS -DLINUX_GLIBC=22002" + libc="glibc2.2" + OS="linux-$arch" + elif test -f /lib/libc-2.2.1.so ; then + NDEFS="$NDEFS -DLINUX_GLIBC=22001" + libc="glibc2.2" + OS="linux-$arch" + elif test -f /lib/libc-2.2.0.so ; then + NDEFS="$NDEFS -DLINUX_GLIBC=22000" + libc="glibc2.1" + OS="linux-$arch" + elif test -f /lib/libc-2.1.3.so ; then + NDEFS="$NDEFS -DLINUX_GLIBC=21003" + libc="glibc2.1" + OS="linux-$arch" + elif test -f /lib/libc-2.1.2.so ; then + NDEFS="$NDEFS -DLINUX_GLIBC=21002" + libc="glibc2.1" + OS="linux-$arch" + elif test -f /lib/libc-2.1.1.so ; then + NDEFS="$NDEFS -DLINUX_GLIBC=21001" + libc="glibc2.1" + OS="linux-$arch" + elif test -f /lib/libc.so.6 ; then + NDEFS="$NDEFS -DLINUX_GLIBC=20000" + libc="glibc2.0" + OS="linux-$arch" + elif test -f /lib/libc.so.6.1 ; then + NDEFS="$NDEFS -DLINUX_GLIBC=20001" + libc="glibc2.0" + OS="linux-$arch" + else + NDEFS="$NDEFS -DLINUX_LIBC=5" + libc="libc5" + OS="linux-$arch" + fi + echo "$libc" 1>&6 + ;; + esac + SYS=linux + ;; + bsd/os) + OS="bsdos${os_r}" + SYS=bsdos + NDEFS="$NDEFS -DBSDOS=$os_r1" + ;; + ultrix) + OS="ultrix-$arch" + SYS=ultrix + ;; + unixware|eeyore) + OS="unixware${os_v}" + SYS=unixware + ;; + macos*|darwin|rhapsody) + OS="macosx" + SYS="macosx" + ;; + sunos) + if [ "$arch" = "" ] ; then arch="sparc" ; fi + if [ "$archp" = "" ] ; then archp="$arch" ; fi + case "$os_r" in + 5.[789]*) + os_r=`echo "$os_r" | cut -c3-` + OS="solaris${os_r}-$archp" + NDEFS="$NDEFS -DSOLARIS=\\\"$os_r\\\"" + SYS=solaris + ;; + 5.[0123456]*) + maj=`echo "$os_r" | cut -c1-1` + maj=`expr "$maj" - 3` + os_r=`echo "$os_r" | cut -c2-` + os_r="${maj}${os_r}" + OS="solaris${os_r}-$archp" + NDEFS="$NDEFS -DSOLARIS=\\\"$os_r\\\"" + SYS=solaris + ;; + 4.*) + OS="sunos${os_r}-sparc" + NDEFS="$NDEFS -DSUNOS=\\\"$os_r\\\"" + SYS=sunos + ;; + *) + OS="solaris${os_r}-$archp" + NDEFS="$NDEFS -DSOLARIS=\\\"$os_r\\\"" + SYS=solaris + ;; + esac + ;; + *) + OS="$os" + SYS="$os" + + if grep Novell /usr/include/sys/types.h ; then + OS="unixware${os_v}" + SYS="unixware" + fi + ;; +esac + +changequote([, ]) + +AC_SUBST(NDEFS) +AC_SUBST(OS) +AC_SUBST(host) +AC_SUBST(SYS) +AC_SUBST(HOME_OS) +]) diff --git a/reactos/apps/utils/net/ncftp/ftp.rc b/reactos/apps/utils/net/ncftp/ftp.rc new file mode 100644 index 00000000000..b51db8f7d16 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/ftp.rc @@ -0,0 +1,39 @@ +#include +#include + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +VS_VERSION_INFO VERSIONINFO + FILEVERSION RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD + PRODUCTVERSION RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", RES_STR_COMPANY_NAME + VALUE "FileDescription", "Ncftp for Win32\0" + VALUE "FileVersion", RES_STR_FILE_VERSION + VALUE "InternalName", "ncftp\0" + VALUE "LegalCopyright", RES_STR_LEGAL_COPYRIGHT + VALUE "OriginalCopyright", "Anonymous sources found at http://www.ncftp.org/\0" + VALUE "OriginalFilename", "ncftp.exe\0" + VALUE "ProductName", RES_STR_PRODUCT_NAME + VALUE "ProductVersion", RES_STR_PRODUCT_VERSION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + diff --git a/reactos/apps/utils/net/ncftp/libncftp/Makefile.in b/reactos/apps/utils/net/ncftp/libncftp/Makefile.in new file mode 100644 index 00000000000..4810f0abd2e --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/Makefile.in @@ -0,0 +1,144 @@ +#----------------------------------------------------------------------------- +# +# LibNcFTP makefile for the platform @OS@, on the host @host@. +# +#----------------------------------------------------------------------------- +PKGNAME=libncftp +VERSION=3.0.1 +PREFIX=@prefix@ + +CC=@CC@ +CFLAGS=@CFLAGS@ +#CC=gcc +#CFLAGS=-g -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wshadow -Wbad-function-cast -Wwrite-strings -Wconversion +VPATH=@srcdir@ +CPPFLAGS=-I. -I../Strn -I../sio @CPPFLAGS@ + +LIB=libncftp.a +LIBSO=libncftp.so.2 +LIBSOS=libncftp.so + +# Any -D definitions: +DEFS=@DEFS@@NDEFS@ + +CFILES=open.c cmds.c util.c rcmd.c ftp.c io.c errno.c linelist.c glob.c +OBJS=open.o cmds.o util.o rcmd.o ftp.o io.o errno.o linelist.o glob.o +SOBJS=open.so cmds.so util.so rcmd.so ftp.so io.so errno.so linelist.so glob.so + +# LIBSET=@LIBSET@ +LIBSET=$(LIB) + +SHELL=/bin/sh +.SUFFIXES: .c .o .so + +all: $(LIBSET) + ( cd ../sio ; $(MAKE) ) + ( cd ../Strn ; $(MAKE) ) + -[ -d ./samples/minincftp ] && cd ./samples/minincftp && $(MAKE) + -[ -d ./samples/misc ] && cd ./samples/misc && $(MAKE) + -[ -d ./samples/monkey ] && cd ./samples/monkey && $(MAKE) + -[ -d ./samples/ncftpget ] && cd ./samples/ncftpget && $(MAKE) + -[ -d ./samples/ncftpls ] && cd ./samples/ncftpls && $(MAKE) + -[ -d ./samples/ncftpput ] && cd ./samples/ncftpput && $(MAKE) + -[ -d ./samples/ncftpsyncput ] && cd ./samples/ncftpsyncput && $(MAKE) + @echo 'Done.' + +$(LIB): $(OBJS) + -@/bin/rm -f $(LIB) + ar rv $(LIB) $(OBJS) + -@chmod 644 $(LIB) + -@@RANLIB@ $(LIB) + @/bin/ls -l $(LIB) + +shared: $(LIBSO) + +so: $(LIBSO) + +$(LIBSO): $(SOBJS) + /bin/rm -f $(LIBSO) $(LIBSOS) + gcc -shared -Wl,-soname,$(LIBSO) -o $(LIBSO) $(SOBJS) + /bin/ln -s $(LIBSO) $(LIBSOS) + -@/bin/ls -l $(LIBSOS) $(LIBSO) + +soinstall: $(LIBSO) + [ -d "$(PREFIX)/lib" ] || mkdir -m 755 "$(PREFIX)/lib" + [ -d "$(PREFIX)/include" ] || mkdir -m 755 "$(PREFIX)/include" + cp $(LIBSO) $(PREFIX)/lib/$(LIBSO) + ( cd $(PREFIX)/lib ; /bin/rm -f $(LIBSOS) ; /bin/ln -s $(LIBSO) $(LIBSOS) ) + cp ncftp.h ncftp_errno.h $(PREFIX)/include + -chmod a+r $(PREFIX)/lib/$(LIBSO) $(PREFIX)/include/ncftp.h $(PREFIX)/include/ncftp_errno.h + +install: $(LIB) + [ -d "$(PREFIX)/lib" ] || mkdir -m 755 "$(PREFIX)/lib" + [ -d "$(PREFIX)/include" ] || mkdir -m 755 "$(PREFIX)/include" + cp $(LIB) $(PREFIX)/lib/$(LIB) + cp ncftp.h ncftp_errno.h $(PREFIX)/include + -chmod a+r $(LIB) $(PREFIX)/lib/$(LIB) $(PREFIX)/include/ncftp.h $(PREFIX)/include/ncftp_errno.h + ( cd ../sio ; $(MAKE) "PREFIX=$(PREFIX)" install ) + ( cd ../Strn ; $(MAKE) "PREFIX=$(PREFIX)" install ) + +install_samples: + ( cd ./samples ; $(MAKE) install ) + +.c.o: + $(CC) $(CFLAGS) $(DEFS) $(CPPFLAGS) $< -c + +.c.so: + $(CC) -fpic $(CFLAGS) $(CPPFLAGS) $(DEFS) $*.c -c -o $*.so + +test: test.c $(OBJS) + $(CC) $(CFLAGS) $(DEFS) $(CPPFLAGS) test.c $(OBJS) -o test $(LDFLAGS) $(LIBS) + +### Archiving ################################################################# + +TARDIR=libncftp-$(VERSION) +TMPDIR=/tmp +STGZFILE=libncftp-$(VERSION)-src.tar.gz + +gz sgz: $(PACKAGE) + ./mksrctar.sh $(TARDIR) $(STGZFILE) + +### Cleaning supplies ######################################################## + +clean: + -/bin/rm -f $(OBJS) $(SOBJS) core $(LIB) $(LIBSO) $(LIBSOS) + -[ -d ./samples/minincftp ] && cd ./samples/minincftp && $(MAKE) clean + -[ -d ./samples/monkey ] && cd ./samples/monkey && $(MAKE) clean + -[ -d ./samples/ncftpget ] && cd ./samples/ncftpget && $(MAKE) clean + -[ -d ./samples/ncftpls ] && cd ./samples/ncftpls && $(MAKE) clean + -[ -d ./samples/ncftpput ] && cd ./samples/ncftpput && $(MAKE) clean + -[ -d ./samples/ncftpsyncput ] && cd ./samples/ncftpsyncput && $(MAKE) clean + ( sleep 2 ; cd ../sio ; $(MAKE) clean ) + ( sleep 2 ; cd ../Strn ; $(MAKE) clean ) + +### Dependencies ############################################################# + +dep: + gcc -MM $(CPPFLAGS) $(CFILES) + +open.o: open.c syshdrs.h ncftp.h ncftp_errno.h util.h ftp.h +open.so: open.c syshdrs.h ncftp.h ncftp_errno.h util.h ftp.h + +cmds.o: cmds.c syshdrs.h ncftp.h ncftp_errno.h util.h ftp.h +cmds.so: cmds.c syshdrs.h ncftp.h ncftp_errno.h util.h ftp.h + +util.o: util.c syshdrs.h ncftp.h ncftp_errno.h util.h +util.so: util.c syshdrs.h ncftp.h ncftp_errno.h util.h + +rcmd.o: rcmd.c syshdrs.h ncftp.h ncftp_errno.h util.h ftp.h +rcmd.so: rcmd.c syshdrs.h ncftp.h ncftp_errno.h util.h ftp.h + +ftp.o: ftp.c syshdrs.h ncftp.h ncftp_errno.h ftp.h util.h +ftp.so: ftp.c syshdrs.h ncftp.h ncftp_errno.h ftp.h util.h + +io.o: io.c syshdrs.h ncftp.h ncftp_errno.h util.h ftp.h +io.so: io.c syshdrs.h ncftp.h ncftp_errno.h util.h ftp.h + +errno.o: errno.c syshdrs.h ncftp.h ncftp_errno.h +errno.so: errno.c syshdrs.h ncftp.h ncftp_errno.h + +linelist.o: linelist.c syshdrs.h ncftp.h ncftp_errno.h util.h +linelist.so: linelist.c syshdrs.h ncftp.h ncftp_errno.h util.h + +glob.o: glob.c syshdrs.h ncftp.h ncftp_errno.h util.h +glob.so: glob.c syshdrs.h ncftp.h ncftp_errno.h util.h diff --git a/reactos/apps/utils/net/ncftp/libncftp/Readme.txt b/reactos/apps/utils/net/ncftp/libncftp/Readme.txt new file mode 100644 index 00000000000..265ea888f26 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/Readme.txt @@ -0,0 +1,73 @@ +Since you have the source distribution, you will need to compile the +libraries before you can install them. + +UNIX INSTRUCTIONS: +------------------ + +Go to the source directory you extracted (here). There is a script you +must run which will checks your system for certain features, so that the +library can be compiled on a variety of UNIX systems. Run this script +by typing "./configure" in that directory. After that, you can look at +the Makefile it made if you like, and then you run "make" to create the +"libncftp.a" and "libStrn.a" library files. + +Finally, install the libraries and headers, by doing "make install". + +View the libncftp.html file for the rest of the documentation. An easy +way to do that is use a URL of file://Localhost/path/to/libncftp.html +with your favorite browser. + + +WINDOWS INSTRUCTIONS: +--------------------- + +You will need Visual C++ 6.0 or greater to build the library and sample +programs. This version includes two supplementary libraries which you +must build and link with your applications: a string utility library +(Strn) and a Winsock utility library (sio). Unlike the UNIX version of +LibNcFTP, where the library can be built with or without the sio library, +the sio library is required for the Windows version. + +Keep the source hierarchy intact, so that the samples and libraries +build without problems. Build the Strn library first, then the sio +library, and then the LibNcFTP library. To do that, open the appropriate +.dsw file within Visual Studio, and then select "Rebuild All" from the +"Build" menu. Be sure to build both the Debug and the Release versions +for each library. + +When that is complete you should be able to build the sample programs, +which are in the libncftp\samples directory. + +View the libncftp.html file for the rest of the documentation. An easy +way to do that is use a URL of file://Localhost/path/to/libncftp.html +with your favorite browser. Note that there may be UNIX-specific +instructions which you should ignore. + +To build your own applications using LibNcFTP, you'll need to make sure +you configure your project to find the header files and library files. + +Your application may not use the sio or Strn libraries directly, but +you still need to link with them. For example, the "simpleget" sample +uses "..\..\Debug,..\..\..\Strn\Debug,..\..\..\sio\Debug" in the +project option for additional library paths for the linker, and +"kernel32.lib user32.lib gdi32.lib advapi32.lib shell32.lib + ws2_32.lib Strn.lib sio.lib libncftp.lib" for the list of libraries +to link with. Note that LibNcFTP uses advapi32 and shell32, in +addition to the usual "kernel32.lib user32.lib gdi32.lib". Of course, +it also needs to link with Winsock (ws2_32.lib). + +Similarly, you'll need to make sure one of your additional include +directories points to the LibNcFTP directory containing ncftp.h. The +"simpleget" sample uses "..\.." since it is in a subdirectory of the +library itself. If you actually use functions from Strn or sio (as +some of the samples do), you'll need to have your project look in +their directories for their headers as well. + +About Winsock2: This version of the library was designed for use with +Winsock version 2. Note that older versions of Windows 95 do not include +Winsock version 2, but can be upgraded by getting the updater from +Microsoft: http://www.microsoft.com/windows95/downloads/contents/wuadmintools/s_wunetworkingtools/w95sockets2/default.asp + +However, the library should also work with Winsock 1.1. That is left as +an exercise to the coder to change the Winsock initialization to use 1.1 +and to link with the 1.1 library (wsock32.lib). \ No newline at end of file diff --git a/reactos/apps/utils/net/ncftp/libncftp/cmds.c b/reactos/apps/utils/net/ncftp/libncftp/cmds.c new file mode 100644 index 00000000000..13804ac7560 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/cmds.c @@ -0,0 +1,1700 @@ +/* cmds.c + * + * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft. + * All rights reserved. + * + */ + +#include "syshdrs.h" + +int +FTPChdir(const FTPCIPtr cip, const char *const cdCwd) +{ + int result; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if (cdCwd == NULL) { + result = kErrInvalidDirParam; + cip->errNo = kErrInvalidDirParam; + } else { + if (cdCwd[0] == '\0') /* But allow FTPChdir(cip, ".") to go through. */ + result = 2; + else if (strcmp(cdCwd, "..") == 0) + result = FTPCmd(cip, "CDUP"); + else + result = FTPCmd(cip, "CWD %s", cdCwd); + if (result >= 0) { + if (result == 2) { + result = kNoErr; + } else { + result = kErrCWDFailed; + cip->errNo = kErrCWDFailed; + } + } + } + return (result); +} /* FTPChdir */ + + + + +int +FTPChmod(const FTPCIPtr cip, const char *const pattern, const char *const mode, const int doGlob) +{ + LineList fileList; + LinePtr filePtr; + char *file; + int onceResult, batchResult; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + batchResult = FTPRemoteGlob(cip, &fileList, pattern, doGlob); + if (batchResult != kNoErr) + return (batchResult); + + for (batchResult = kNoErr, filePtr = fileList.first; + filePtr != NULL; + filePtr = filePtr->next) + { + file = filePtr->line; + if (file == NULL) { + batchResult = kErrBadLineList; + cip->errNo = kErrBadLineList; + break; + } + onceResult = FTPCmd(cip, "SITE CHMOD %s %s", mode, file); + if (onceResult < 0) { + batchResult = onceResult; + break; + } + if (onceResult != 2) { + batchResult = kErrChmodFailed; + cip->errNo = kErrChmodFailed; + } + } + DisposeLineListContents(&fileList); + return (batchResult); +} /* FTPChmod */ + + + + +static int +FTPRmdirRecursiveL2(const FTPCIPtr cip) +{ + LineList fileList; + LinePtr filePtr; + char *file; + int result; + + result = FTPRemoteGlob(cip, &fileList, "**", kGlobYes); + if (result != kNoErr) { + return (result); + } + + for (filePtr = fileList.first; + filePtr != NULL; + filePtr = filePtr->next) + { + file = filePtr->line; + if (file == NULL) { + cip->errNo = kErrBadLineList; + break; + } + + if ((file[0] == '.') && ((file[1] == '\0') || ((file[1] == '.') && (file[2] == '\0')))) + continue; /* Skip . and .. */ + + if (FTPChdir(cip, file) == kNoErr) { + /* It was a directory. + * Go in and wax it. + */ + result = FTPRmdirRecursiveL2(cip); + + if (FTPChdir(cip, "..") != kNoErr) { + /* Panic -- we can no longer + * cd back to the directory + * we were in before. + */ + result = kErrCannotGoToPrevDir; + cip->errNo = kErrCannotGoToPrevDir; + return (result); + } + + if ((result < 0) && (result != kErrGlobNoMatch)) + return (result); + + result = FTPRmdir(cip, file, kRecursiveNo, kGlobNo); + if (result != kNoErr) { + /* Well, we couldn't remove the empty + * directory. Perhaps we screwed up + * and the directory wasn't empty. + */ + return (result); + } + } else { + /* Assume it was a file -- remove it. */ + result = FTPDelete(cip, file, kRecursiveNo, kGlobNo); + /* Try continuing to remove the rest, + * even if this failed. + */ + } + } + DisposeLineListContents(&fileList); + + return (result); +} /* FTPRmdirRecursiveL2 */ + + + +static int +FTPRmdirRecursive(const FTPCIPtr cip, const char *const dir) +{ + int result, result2; + + /* Preserve old working directory. */ + (void) FTPGetCWD(cip, cip->buf, cip->bufSize); + + result = FTPChdir(cip, dir); + if (result != kNoErr) { + return (result); + } + + result = FTPRmdirRecursiveL2(cip); + + if (FTPChdir(cip, cip->buf) != kNoErr) { + /* Could not cd back to the original user directory -- bad. */ + if (result != kNoErr) { + result = kErrCannotGoToPrevDir; + cip->errNo = kErrCannotGoToPrevDir; + } + return (result); + } + + /* Now rmdir the last node, the root of the tree + * we just went through. + */ + result2 = FTPRmdir(cip, dir, kRecursiveNo, kGlobNo); + if ((result2 != kNoErr) && (result == kNoErr)) + result = result2; + + return (result); +} /* FTPRmdirRecursive */ + + + + +int +FTPDelete(const FTPCIPtr cip, const char *const pattern, const int recurse, const int doGlob) +{ + LineList fileList; + LinePtr filePtr; + char *file; + int onceResult, batchResult; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + batchResult = FTPRemoteGlob(cip, &fileList, pattern, doGlob); + if (batchResult != kNoErr) + return (batchResult); + + for (batchResult = kNoErr, filePtr = fileList.first; + filePtr != NULL; + filePtr = filePtr->next) + { + file = filePtr->line; + if (file == NULL) { + batchResult = kErrBadLineList; + cip->errNo = kErrBadLineList; + break; + } + onceResult = FTPCmd(cip, "DELE %s", file); + if (onceResult < 0) { + batchResult = onceResult; + break; + } + if (onceResult != 2) { + if (recurse != kRecursiveYes) { + batchResult = kErrDELEFailed; + cip->errNo = kErrDELEFailed; + } else { + onceResult = FTPCmd(cip, "RMD %s", file); + if (onceResult < 0) { + batchResult = onceResult; + break; + } + if (onceResult != 2) { + onceResult = FTPRmdirRecursive(cip, file); + if (onceResult < 0) { + batchResult = kErrRMDFailed; + cip->errNo = kErrRMDFailed; + } + } + } + } + } + DisposeLineListContents(&fileList); + return (batchResult); +} /* FTPDelete */ + + + + +int +FTPGetCWD(const FTPCIPtr cip, char *const newCwd, const size_t newCwdSize) +{ + ResponsePtr rp; + char *l, *r; + int result; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if ((newCwd == NULL) || (newCwdSize == 0)) { + result = kErrInvalidDirParam; + cip->errNo = kErrInvalidDirParam; + } else { + rp = InitResponse(); + if (rp == NULL) { + result = kErrMallocFailed; + cip->errNo = kErrMallocFailed; + Error(cip, kDontPerror, "Malloc failed.\n"); + } else { + result = RCmd(cip, rp, "PWD"); + if (result == 2) { + if ((r = strrchr(rp->msg.first->line, '"')) != NULL) { + /* "xxxx" is current directory. + * Strip out just the xxxx to copy into the remote cwd. + */ + l = strchr(rp->msg.first->line, '"'); + if ((l != NULL) && (l != r)) { + *r = '\0'; + ++l; + (void) Strncpy(newCwd, l, newCwdSize); + *r = '"'; /* Restore, so response prints correctly. */ + } + } else { + /* xxxx is current directory. + * Mostly for VMS. + */ + if ((r = strchr(rp->msg.first->line, ' ')) != NULL) { + *r = '\0'; + (void) Strncpy(newCwd, (rp->msg.first->line), newCwdSize); + *r = ' '; /* Restore, so response prints correctly. */ + } + } + result = kNoErr; + } else if (result > 0) { + result = kErrPWDFailed; + cip->errNo = kErrPWDFailed; + } + DoneWithResponse(cip, rp); + } + } + return (result); +} /* FTPGetCWD */ + + + + +int +FTPChdirAndGetCWD(const FTPCIPtr cip, const char *const cdCwd, char *const newCwd, const size_t newCwdSize) +{ + ResponsePtr rp; + char *l, *r; + int result; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if ((newCwd == NULL) || (cdCwd == NULL)) { + result = kErrInvalidDirParam; + cip->errNo = kErrInvalidDirParam; + } else { + if (cdCwd[0] == '\0') { /* But allow FTPChdir(cip, ".") to go through. */ + result = FTPGetCWD(cip, newCwd, newCwdSize); + return (result); + } + rp = InitResponse(); + if (rp == NULL) { + result = kErrMallocFailed; + cip->errNo = kErrMallocFailed; + Error(cip, kDontPerror, "Malloc failed.\n"); + } else { + if (strcmp(cdCwd, "..") == 0) + result = RCmd(cip, rp, "CDUP"); + else + result = RCmd(cip, rp, "CWD %s", cdCwd); + if (result == 2) { + l = strchr(rp->msg.first->line, '"'); + if ((l == rp->msg.first->line) && ((r = strrchr(rp->msg.first->line, '"')) != NULL) && (l != r)) { + /* "xxxx" is current directory. + * Strip out just the xxxx to copy into the remote cwd. + * + * This is nice because we didn't have to do a PWD. + */ + *r = '\0'; + ++l; + (void) Strncpy(newCwd, l, newCwdSize); + *r = '"'; /* Restore, so response prints correctly. */ + DoneWithResponse(cip, rp); + result = kNoErr; + } else { + DoneWithResponse(cip, rp); + result = FTPGetCWD(cip, newCwd, newCwdSize); + } + } else if (result > 0) { + result = kErrCWDFailed; + cip->errNo = kErrCWDFailed; + DoneWithResponse(cip, rp); + } else { + DoneWithResponse(cip, rp); + } + } + } + return (result); +} /* FTPChdirAndGetCWD */ + + + + +int +FTPChdir3(FTPCIPtr cip, const char *const cdCwd, char *const newCwd, const size_t newCwdSize, int flags) +{ + char *cp, *startcp; + int result; + int lastSubDir; + int mkd, pwd; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if (cdCwd == NULL) { + result = kErrInvalidDirParam; + cip->errNo = kErrInvalidDirParam; + return result; + } + + if (flags == kChdirOnly) + return (FTPChdir(cip, cdCwd)); + if (flags == kChdirAndGetCWD) { + return (FTPChdirAndGetCWD(cip, cdCwd, newCwd, newCwdSize)); + } else if (flags == kChdirAndMkdir) { + result = FTPMkdir(cip, cdCwd, kRecursiveYes); + if (result == kNoErr) + result = FTPChdir(cip, cdCwd); + return result; + } else if (flags == (kChdirAndMkdir|kChdirAndGetCWD)) { + result = FTPMkdir(cip, cdCwd, kRecursiveYes); + if (result == kNoErr) + result = FTPChdirAndGetCWD(cip, cdCwd, newCwd, newCwdSize); + return result; + } + + /* else: (flags | kChdirOneSubdirAtATime) == true */ + + cp = cip->buf; + cp[cip->bufSize - 1] = '\0'; + (void) Strncpy(cip->buf, cdCwd, cip->bufSize); + if (cp[cip->bufSize - 1] != '\0') + return (kErrBadParameter); + + mkd = (flags & kChdirAndMkdir); + pwd = (flags & kChdirAndGetCWD); + + if ((cdCwd[0] == '\0') || (strcmp(cdCwd, ".") == 0)) { + result = 0; + if (flags == kChdirAndGetCWD) + result = FTPGetCWD(cip, newCwd, newCwdSize); + return (result); + } + + lastSubDir = 0; + do { + startcp = cp; + cp = StrFindLocalPathDelim(cp); + if (cp != NULL) { + /* If this is the first slash in an absolute + * path, then startcp will be empty. We will + * use this below to treat this as the root + * directory. + */ + *cp++ = '\0'; + } else { + lastSubDir = 1; + } + if (strcmp(startcp, ".") == 0) { + result = 0; + if ((lastSubDir != 0) && (pwd != 0)) + result = FTPGetCWD(cip, newCwd, newCwdSize); + } else if ((lastSubDir != 0) && (pwd != 0)) { + result = FTPChdirAndGetCWD(cip, (*startcp != '\0') ? startcp : "/", newCwd, newCwdSize); + } else { + result = FTPChdir(cip, (*startcp != '\0') ? startcp : "/"); + } + if (result < 0) { + if ((mkd != 0) && (*startcp != '\0')) { + if (FTPCmd(cip, "MKD %s", startcp) == 2) { + result = FTPChdir(cip, startcp); + } else { + /* couldn't change nor create */ + cip->errNo = result; + } + } else { + cip->errNo = result; + } + } + } while ((!lastSubDir) && (result == 0)); + + return (result); +} /* FTPChdir3 */ + + + + +int +FTPMkdir2(const FTPCIPtr cip, const char *const newDir, const int recurse, const char *const curDir) +{ + int result, result2; + char *cp, *newTreeStart, *cp2; + char dir[512]; + char dir2[512]; + char c; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if ((newDir == NULL) || (newDir[0] == '\0')) { + cip->errNo = kErrInvalidDirParam; + return (kErrInvalidDirParam); + } + + /* Preserve old working directory. */ + if ((curDir == NULL) || (curDir[0] == '\0')) { + /* This hack is nice so you can eliminate an + * unnecessary "PWD" command on the server, + * since if you already knew what directory + * you're in. We want to minimize the number + * of client-server exchanges when feasible. + */ + (void) FTPGetCWD(cip, cip->buf, cip->bufSize); + } + + result = FTPChdir(cip, newDir); + if (result == kNoErr) { + /* Directory already exists -- but we + * must now change back to where we were. + */ + result2 = FTPChdir(cip, ((curDir == NULL) || (curDir[0] == '\0')) ? cip->buf : curDir); + if (result2 < 0) { + result = kErrCannotGoToPrevDir; + cip->errNo = kErrCannotGoToPrevDir; + return (result); + } + + /* Don't need to create it. */ + return (kNoErr); + } + + if (recurse == kRecursiveNo) { + result = FTPCmd(cip, "MKD %s", newDir); + if (result > 0) { + if (result != 2) { + Error(cip, kDontPerror, "MKD %s failed; [%s]\n", newDir, cip->lastFTPCmdResultStr); + result = kErrMKDFailed; + cip->errNo = kErrMKDFailed; + return (result); + } else { + result = kNoErr; + } + } + } else { + (void) STRNCPY(dir, newDir); + + /* Strip trailing slashes. */ + cp = dir + strlen(dir) - 1; + for (;;) { + if (cp <= dir) { + if ((newDir == NULL) || (newDir[0] == '\0')) { + cip->errNo = kErrInvalidDirParam; + result = kErrInvalidDirParam; + return (result); + } + } + if ((*cp != '/') && (*cp != '\\')) { + cp[1] = '\0'; + break; + } + --cp; + } + (void) STRNCPY(dir2, dir); + + if ((strrchr(dir, '/') == dir) || (strrchr(dir, '\\') == dir)) { + /* Special case "mkdir /subdir" */ + result = FTPCmd(cip, "MKD %s", dir); + if (result < 0) { + return (result); + } + if (result != 2) { + Error(cip, kDontPerror, "MKD %s failed; [%s]\n", dir, cip->lastFTPCmdResultStr); + result = kErrMKDFailed; + cip->errNo = kErrMKDFailed; + return (result); + } + /* Haven't chdir'ed, don't need to goto goback. */ + return (kNoErr); + } + + for (;;) { + cp = strrchr(dir, '/'); + if (cp == NULL) + cp = strrchr(dir, '\\'); + if (cp == NULL) { + cp = dir + strlen(dir) - 1; + if (dir[0] == '\0') { + result = kErrMKDFailed; + cip->errNo = kErrMKDFailed; + return (result); + } + /* Note: below we will refer to cp + 1 + * which is why we set cp to point to + * the byte before the array begins! + */ + cp = dir - 1; + break; + } + if (cp == dir) { + result = kErrMKDFailed; + cip->errNo = kErrMKDFailed; + return (result); + } + *cp = '\0'; + result = FTPChdir(cip, dir); + if (result == 0) { + break; /* Found a valid parent dir. */ + /* from this point, we need to preserve old dir. */ + } + } + + newTreeStart = dir2 + ((cp + 1) - dir); + for (cp = newTreeStart; ; ) { + cp2 = cp; + cp = strchr(cp2, '/'); + c = '/'; + if (cp == NULL) + cp = strchr(cp2, '\\'); + if (cp != NULL) { + c = *cp; + *cp = '\0'; + if (cp[1] == '\0') { + /* Done, if they did "mkdir /tmp/dir/" */ + break; + } + } + result = FTPCmd(cip, "MKD %s", newTreeStart); + if (result < 0) { + return (result); + } + if (result != 2) { + Error(cip, kDontPerror, "Cwd=%s; MKD %s failed; [%s]\n", cip->buf, newTreeStart, cip->lastFTPCmdResultStr); + result = kErrMKDFailed; + cip->errNo = kErrMKDFailed; + goto goback; + } + if (cp == NULL) + break; /* No more to make, done. */ + *cp++ = c; + } + result = kNoErr; + +goback: + result2 = FTPChdir(cip, ((curDir == NULL) || (curDir[0] == '\0')) ? cip->buf : curDir); + if ((result == 0) && (result2 < 0)) { + result = kErrCannotGoToPrevDir; + cip->errNo = kErrCannotGoToPrevDir; + } + } + return (result); +} /* FTPMkdir2 */ + + + +int +FTPMkdir(const FTPCIPtr cip, const char *const newDir, const int recurse) +{ + return (FTPMkdir2(cip, newDir, recurse, NULL)); +} /* FTPMkdir */ + + + +int +FTPFileModificationTime(const FTPCIPtr cip, const char *const file, time_t *const mdtm) +{ + int result; + ResponsePtr rp; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if ((mdtm == NULL) || (file == NULL)) + return (kErrBadParameter); + *mdtm = kModTimeUnknown; + + if (cip->hasMDTM == kCommandNotAvailable) { + cip->errNo = kErrMDTMNotAvailable; + result = kErrMDTMNotAvailable; + } else { + rp = InitResponse(); + if (rp == NULL) { + result = kErrMallocFailed; + cip->errNo = kErrMallocFailed; + Error(cip, kDontPerror, "Malloc failed.\n"); + } else { + result = RCmd(cip, rp, "MDTM %s", file); + if (result < 0) { + DoneWithResponse(cip, rp); + return (result); + } else if (strncmp(rp->msg.first->line, "19100", 5) == 0) { + Error(cip, kDontPerror, "Warning: Server has Y2K Bug in \"MDTM\" command.\n"); + cip->errNo = kErrMDTMFailed; + result = kErrMDTMFailed; + } else if (result == 2) { + *mdtm = UnMDTMDate(rp->msg.first->line); + cip->hasMDTM = kCommandAvailable; + result = kNoErr; + } else if (UNIMPLEMENTED_CMD(rp->code)) { + cip->hasMDTM = kCommandNotAvailable; + cip->errNo = kErrMDTMNotAvailable; + result = kErrMDTMNotAvailable; + } else { + cip->errNo = kErrMDTMFailed; + result = kErrMDTMFailed; + } + DoneWithResponse(cip, rp); + } + } + return (result); +} /* FTPFileModificationTime */ + + + + +int +FTPRename(const FTPCIPtr cip, const char *const oldname, const char *const newname) +{ + int result; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + if ((oldname == NULL) || (oldname[0] == '\0')) + return (kErrBadParameter); + if ((newname == NULL) || (oldname[0] == '\0')) + return (kErrBadParameter); + + + result = FTPCmd(cip, "RNFR %s", oldname); + if (result < 0) + return (result); + if (result != 3) { + cip->errNo = kErrRenameFailed; + return (cip->errNo); + } + + result = FTPCmd(cip, "RNTO %s", newname); + if (result < 0) + return (result); + if (result != 2) { + cip->errNo = kErrRenameFailed; + return (cip->errNo); + } + return (kNoErr); +} /* FTPRename */ + + + + +int +FTPRemoteHelp(const FTPCIPtr cip, const char *const pattern, const LineListPtr llp) +{ + int result; + ResponsePtr rp; + + if ((cip == NULL) || (llp == NULL)) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + InitLineList(llp); + rp = InitResponse(); + if (rp == NULL) { + result = kErrMallocFailed; + cip->errNo = kErrMallocFailed; + Error(cip, kDontPerror, "Malloc failed.\n"); + } else { + if ((pattern == NULL) || (*pattern == '\0')) + result = RCmd(cip, rp, "HELP"); + else + result = RCmd(cip, rp, "HELP %s", pattern); + if (result < 0) { + DoneWithResponse(cip, rp); + return (result); + } else if (result == 2) { + if (CopyLineList(llp, &rp->msg) < 0) { + result = kErrMallocFailed; + cip->errNo = kErrMallocFailed; + Error(cip, kDontPerror, "Malloc failed.\n"); + } else { + result = kNoErr; + } + } else { + cip->errNo = kErrHELPFailed; + result = kErrHELPFailed; + } + DoneWithResponse(cip, rp); + } + return (result); +} /* FTPRemoteHelp */ + + + + +int +FTPRmdir(const FTPCIPtr cip, const char *const pattern, const int recurse, const int doGlob) +{ + LineList fileList; + LinePtr filePtr; + char *file; + int onceResult, batchResult; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + batchResult = FTPRemoteGlob(cip, &fileList, pattern, doGlob); + if (batchResult != kNoErr) + return (batchResult); + + for (batchResult = kNoErr, filePtr = fileList.first; + filePtr != NULL; + filePtr = filePtr->next) + { + file = filePtr->line; + if (file == NULL) { + batchResult = kErrBadLineList; + cip->errNo = kErrBadLineList; + break; + } + onceResult = FTPCmd(cip, "RMD %s", file); + if (onceResult < 0) { + batchResult = onceResult; + break; + } + if (onceResult != 2) { + if (recurse == kRecursiveYes) { + onceResult = FTPRmdirRecursive(cip, file); + if (onceResult < 0) { + batchResult = kErrRMDFailed; + cip->errNo = kErrRMDFailed; + } + } else { + batchResult = kErrRMDFailed; + cip->errNo = kErrRMDFailed; + } + } + } + DisposeLineListContents(&fileList); + return (batchResult); +} /* FTPRmdir */ + + + + +int +FTPSetTransferType(const FTPCIPtr cip, int type) +{ + int result; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if (cip->curTransferType != type) { + switch (type) { + case kTypeAscii: + case kTypeBinary: + case kTypeEbcdic: + break; + case 'i': + case 'b': + case 'B': + type = kTypeBinary; + break; + case 'e': + type = kTypeEbcdic; + break; + case 'a': + type = kTypeAscii; + break; + default: + /* Yeah, we don't support Tenex. Who cares? */ + Error(cip, kDontPerror, "Bad transfer type [%c].\n", type); + cip->errNo = kErrBadTransferType; + return (kErrBadTransferType); + } + result = FTPCmd(cip, "TYPE %c", type); + if (result != 2) { + result = kErrTYPEFailed; + cip->errNo = kErrTYPEFailed; + return (result); + } + cip->curTransferType = type; + } + return (kNoErr); +} /* FTPSetTransferType */ + + + + +/* If the remote host supports the SIZE command, we can find out the exact + * size of a remote file, depending on the transfer type in use. SIZE + * returns different values for ascii and binary modes! + */ +int +FTPFileSize(const FTPCIPtr cip, const char *const file, longest_int *const size, const int type) +{ + int result; + ResponsePtr rp; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if ((size == NULL) || (file == NULL)) + return (kErrBadParameter); + *size = kSizeUnknown; + + result = FTPSetTransferType(cip, type); + if (result < 0) + return (result); + + if (cip->hasSIZE == kCommandNotAvailable) { + cip->errNo = kErrSIZENotAvailable; + result = kErrSIZENotAvailable; + } else { + rp = InitResponse(); + if (rp == NULL) { + result = kErrMallocFailed; + cip->errNo = kErrMallocFailed; + Error(cip, kDontPerror, "Malloc failed.\n"); + } else { + result = RCmd(cip, rp, "SIZE %s", file); + if (result < 0) { + DoneWithResponse(cip, rp); + return (result); + } else if (result == 2) { +#if defined(HAVE_LONG_LONG) && defined(SCANF_LONG_LONG) + (void) sscanf(rp->msg.first->line, SCANF_LONG_LONG, size); +#elif defined(HAVE_LONG_LONG) && defined(HAVE_STRTOQ) + *size = (longest_int) strtoq(rp->msg.first->line, NULL, 0); +#else + (void) sscanf(rp->msg.first->line, "%ld", size); +#endif + cip->hasSIZE = kCommandAvailable; + result = kNoErr; + } else if (UNIMPLEMENTED_CMD(rp->code)) { + cip->hasSIZE = kCommandNotAvailable; + cip->errNo = kErrSIZENotAvailable; + result = kErrSIZENotAvailable; + } else { + cip->errNo = kErrSIZEFailed; + result = kErrSIZEFailed; + } + DoneWithResponse(cip, rp); + } + } + return (result); +} /* FTPFileSize */ + + + + +int +FTPMListOneFile(const FTPCIPtr cip, const char *const file, const MLstItemPtr mlip) +{ + int result; + ResponsePtr rp; + + /* We do a special check for older versions of NcFTPd which + * are based off of an incompatible previous version of IETF + * extensions. + * + * Roxen also seems to be way outdated, where MLST was on the + * data connection among other things. + * + */ + if ( + (cip->hasMLST == kCommandNotAvailable) || + ((cip->serverType == kServerTypeNcFTPd) && (cip->ietfCompatLevel < 19981201)) || + (cip->serverType == kServerTypeRoxen) + ) { + cip->errNo = kErrMLSTNotAvailable; + return (cip->errNo); + } + + rp = InitResponse(); + if (rp == NULL) { + result = cip->errNo = kErrMallocFailed; + Error(cip, kDontPerror, "Malloc failed.\n"); + } else { + result = RCmd(cip, rp, "MLST %s", file); + if ( + (result == 2) && + (rp->msg.first->line != NULL) && + (rp->msg.first->next != NULL) && + (rp->msg.first->next->line != NULL) + ) { + result = UnMlsT(rp->msg.first->next->line, mlip); + if (result < 0) { + cip->errNo = result = kErrInvalidMLSTResponse; + } + } else if (UNIMPLEMENTED_CMD(rp->code)) { + cip->hasMLST = kCommandNotAvailable; + cip->errNo = kErrMLSTNotAvailable; + result = kErrMLSTNotAvailable; + } else { + cip->errNo = kErrMLSTFailed; + result = kErrMLSTFailed; + } + DoneWithResponse(cip, rp); + } + + return (result); +} /* FTPMListOneFile */ + + + + +/* We only use STAT to see if files or directories exist. + * But since it is so rarely used in the wild, we need to + * make sure the server supports the use where we pass + * a pathname as a parameter. + */ +int +FTPFileExistsStat(const FTPCIPtr cip, const char *const file) +{ + int result; + ResponsePtr rp; + LineList fileList; + char savedCwd[512]; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if (file == NULL) + return (kErrBadParameter); + + if (cip->STATfileParamWorks == kCommandNotAvailable) { + cip->errNo = result = kErrSTATwithFileNotAvailable; + return (result); + } + + if (cip->STATfileParamWorks == kCommandAvailabilityUnknown) { + rp = InitResponse(); + if (rp == NULL) { + result = kErrMallocFailed; + cip->errNo = kErrMallocFailed; + Error(cip, kDontPerror, "Malloc failed.\n"); + return (result); + + } + + /* First, make sure that when we STAT a pathname + * that does not exist, that we get an error back. + * + * We also assume that a valid STAT response has + * at least 3 lines of response text, typically + * a "start" line, intermediate data, and then + * a trailing line. + * + * We also can see a one-line case. + */ + result = RCmd(cip, rp, "STAT %s", "NoSuchFile"); + if ((result == 2) && ((rp->msg.nLines >= 3) || (rp->msg.nLines == 1))) { + /* Hmmm.... it gave back a positive + * response. So STAT does not + * work correctly. + */ + if ( + (rp->msg.first->next != NULL) && + (rp->msg.first->next->line != NULL) && + ( + (strstr(rp->msg.first->next->line, "o such file") != NULL) || + (strstr(rp->msg.first->next->line, "ot found") != NULL) + ) + ) { + /* OK, while we didn't want a 200 + * level response, some servers, + * like wu-ftpd print an error + * message "No such file or + * directory" which we can special + * case. + */ + result = kNoErr; + } else { + cip->STATfileParamWorks = kCommandNotAvailable; + cip->errNo = result = kErrSTATwithFileNotAvailable; + DoneWithResponse(cip, rp); + return (result); + } + } + DoneWithResponse(cip, rp); + + /* We can't assume that we can simply say STAT rootdir/firstfile, + * since the remote host may not be using / as a directory + * delimiter. So we have to change to the root directory + * and then do the STAT on that file. + */ + if ( + (FTPGetCWD(cip, savedCwd, sizeof(savedCwd)) != kNoErr) || + (FTPChdir(cip, cip->startingWorkingDirectory) != kNoErr) + ) { + return (cip->errNo); + } + + /* OK, we get an error when we stat + * a non-existant file, but now we need to + * see if we get a positive reply when + * we stat a file that does exist. + * + * To do this, we list the root directory, + * which we assume has one or more items. + * If it doesn't, the user can't do anything + * anyway. Then we stat the first item + * we found to see if STAT says it exists. + */ + if ( + ((result = FTPListToMemory2(cip, "", &fileList, "", 0, (int *) 0)) < 0) || + (fileList.last == NULL) || + (fileList.last->line == NULL) + ) { + /* Hmmm... well, in any case we can't use STAT. */ + cip->STATfileParamWorks = kCommandNotAvailable; + cip->errNo = result = kErrSTATwithFileNotAvailable; + DisposeLineListContents(&fileList); + (void) FTPChdir(cip, savedCwd); + return (result); + } + + rp = InitResponse(); + if (rp == NULL) { + result = kErrMallocFailed; + cip->errNo = kErrMallocFailed; + Error(cip, kDontPerror, "Malloc failed.\n"); + DisposeLineListContents(&fileList); + (void) FTPChdir(cip, savedCwd); + return (result); + + } + + result = RCmd(cip, rp, "STAT %s", fileList.last->line); + DisposeLineListContents(&fileList); + + if ((result != 2) || (rp->msg.nLines == 2)) { + /* Hmmm.... it gave back a negative + * response. So STAT does not + * work correctly. + */ + cip->STATfileParamWorks = kCommandNotAvailable; + cip->errNo = result = kErrSTATwithFileNotAvailable; + DoneWithResponse(cip, rp); + (void) FTPChdir(cip, savedCwd); + return (result); + } else if ( + (rp->msg.first->next != NULL) && + (rp->msg.first->next->line != NULL) && + ( + (strstr(rp->msg.first->next->line, "o such file") != NULL) || + (strstr(rp->msg.first->next->line, "ot found") != NULL) + ) + ) { + /* Same special-case of the second line of STAT response. */ + cip->STATfileParamWorks = kCommandNotAvailable; + cip->errNo = result = kErrSTATwithFileNotAvailable; + DoneWithResponse(cip, rp); + (void) FTPChdir(cip, savedCwd); + return (result); + } + DoneWithResponse(cip, rp); + cip->STATfileParamWorks = kCommandAvailable; + + /* Don't forget to change back to the original directory. */ + (void) FTPChdir(cip, savedCwd); + } + + rp = InitResponse(); + if (rp == NULL) { + result = kErrMallocFailed; + cip->errNo = kErrMallocFailed; + Error(cip, kDontPerror, "Malloc failed.\n"); + return (result); + } + + result = RCmd(cip, rp, "STAT %s", file); + if (result == 2) { + result = kNoErr; + if (((rp->msg.nLines >= 3) || (rp->msg.nLines == 1))) { + if ( + (rp->msg.first->next != NULL) && + (rp->msg.first->next->line != NULL) && + ( + (strstr(rp->msg.first->next->line, "o such file") != NULL) || + (strstr(rp->msg.first->next->line, "ot found") != NULL) + ) + ) { + cip->errNo = kErrSTATFailed; + result = kErrSTATFailed; + } else { + result = kNoErr; + } + } else if (rp->msg.nLines == 2) { + cip->errNo = kErrSTATFailed; + result = kErrSTATFailed; + } else { + result = kNoErr; + } + } else { + cip->errNo = kErrSTATFailed; + result = kErrSTATFailed; + } + DoneWithResponse(cip, rp); + return (result); +} /* FTPFileExistsStat */ + + + + +/* We only use STAT to see if files or directories exist. + * But since it is so rarely used in the wild, we need to + * make sure the server supports the use where we pass + * a pathname as a parameter. + */ +int +FTPFileExistsNlst(const FTPCIPtr cip, const char *const file) +{ + int result; + LineList fileList, rootFileList; + char savedCwd[512]; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if (file == NULL) + return (kErrBadParameter); + + if (cip->NLSTfileParamWorks == kCommandNotAvailable) { + cip->errNo = result = kErrNLSTwithFileNotAvailable; + return (result); + } + + if (cip->NLSTfileParamWorks == kCommandAvailabilityUnknown) { + /* First, make sure that when we NLST a pathname + * that does not exist, that we get an error back. + * + * We also assume that a valid NLST response has + * at least 3 lines of response text, typically + * a "start" line, intermediate data, and then + * a trailing line. + * + * We also can see a one-line case. + */ + if ( + ((FTPListToMemory2(cip, "NoSuchFile", &fileList, "", 0, (int *) 0)) == kNoErr) && + (fileList.nLines >= 1) && + (strstr(fileList.last->line, "o such file") == NULL) && + (strstr(fileList.last->line, "ot found") == NULL) && + (strstr(fileList.last->line, "o Such File") == NULL) && + (strstr(fileList.last->line, "ot Found") == NULL) + + ) { + cip->NLSTfileParamWorks = kCommandNotAvailable; + cip->errNo = result = kErrNLSTwithFileNotAvailable; + DisposeLineListContents(&fileList); + return (result); + } + DisposeLineListContents(&fileList); + + /* We can't assume that we can simply say NLST rootdir/firstfile, + * since the remote host may not be using / as a directory + * delimiter. So we have to change to the root directory + * and then do the NLST on that file. + */ + if ( + (FTPGetCWD(cip, savedCwd, sizeof(savedCwd)) != kNoErr) || + (FTPChdir(cip, cip->startingWorkingDirectory) != kNoErr) + ) { + return (cip->errNo); + } + + /* OK, we get an error when we list + * a non-existant file, but now we need to + * see if we get a positive reply when + * we stat a file that does exist. + * + * To do this, we list the root directory, + * which we assume has one or more items. + * If it doesn't, the user can't do anything + * anyway. Then we do the first item + * we found to see if NLST says it exists. + */ + if ( + ((result = FTPListToMemory2(cip, "", &rootFileList, "", 0, (int *) 0)) < 0) || + (rootFileList.last == NULL) || + (rootFileList.last->line == NULL) + ) { + /* Hmmm... well, in any case we can't use NLST. */ + cip->NLSTfileParamWorks = kCommandNotAvailable; + cip->errNo = result = kErrNLSTwithFileNotAvailable; + DisposeLineListContents(&rootFileList); + (void) FTPChdir(cip, savedCwd); + return (result); + } + + if ( + ((FTPListToMemory2(cip, rootFileList.last->line, &fileList, "", 0, (int *) 0)) == kNoErr) && + (fileList.nLines >= 1) && + (strstr(fileList.last->line, "o such file") == NULL) && + (strstr(fileList.last->line, "ot found") == NULL) && + (strstr(fileList.last->line, "o Such File") == NULL) && + (strstr(fileList.last->line, "ot Found") == NULL) + + ) { + /* Good. We listed the item. */ + DisposeLineListContents(&fileList); + DisposeLineListContents(&rootFileList); + cip->NLSTfileParamWorks = kCommandAvailable; + + /* Don't forget to change back to the original directory. */ + (void) FTPChdir(cip, savedCwd); + } else { + cip->NLSTfileParamWorks = kCommandNotAvailable; + cip->errNo = result = kErrNLSTwithFileNotAvailable; + DisposeLineListContents(&fileList); + DisposeLineListContents(&rootFileList); + (void) FTPChdir(cip, savedCwd); + return (result); + } + } + + /* Check the requested item. */ + InitLineList(&fileList); + if ( + ((FTPListToMemory2(cip, file, &fileList, "", 0, (int *) 0)) == kNoErr) && + (fileList.nLines >= 1) && + (strstr(fileList.last->line, "o such file") == NULL) && + (strstr(fileList.last->line, "ot found") == NULL) && + (strstr(fileList.last->line, "o Such File") == NULL) && + (strstr(fileList.last->line, "ot Found") == NULL) + + ) { + /* The item existed. */ + result = kNoErr; + } else { + cip->errNo = kErrNLSTFailed; + result = kErrNLSTFailed; + } + + DisposeLineListContents(&fileList); + return (result); +} /* FTPFileExistsNlst*/ + + + + +/* This functions goes to a great deal of trouble to try and determine if the + * remote file specified exists. Newer servers support commands that make + * it relatively inexpensive to find the answer, but older servers do not + * provide a standard way. This means we may try a whole bunch of things, + * but the good news is that the library saves information about which things + * worked so if you do this again it uses the methods that work. + */ +int +FTPFileExists2(const FTPCIPtr cip, const char *const file, const int tryMDTM, const int trySIZE, const int tryMLST, const int trySTAT, const int tryNLST) +{ + int result; + time_t mdtm; + longest_int size; + MLstItem mlsInfo; + + if (tryMDTM != 0) { + result = FTPFileModificationTime(cip, file, &mdtm); + if (result == kNoErr) + return (kNoErr); + if (result == kErrMDTMFailed) { + cip->errNo = kErrNoSuchFileOrDirectory; + return (kErrNoSuchFileOrDirectory); + } + /* else keep going */ + } + + if (trySIZE != 0) { + result = FTPFileSize(cip, file, &size, kTypeBinary); + if (result == kNoErr) + return (kNoErr); + /* SIZE could fail if the server does + * not support it for directories. + * + * if (result == kErrSIZEFailed) + * return (kErrNoSuchFileOrDirectory); + */ + /* else keep going */ + } + + + if (tryMLST != 0) { + result = FTPMListOneFile(cip, file, &mlsInfo); + if (result == kNoErr) + return (kNoErr); + if (result == kErrMLSTFailed) { + cip->errNo = kErrNoSuchFileOrDirectory; + return (kErrNoSuchFileOrDirectory); + } + /* else keep going */ + } + + if (trySTAT != 0) { + result = FTPFileExistsStat(cip, file); + if (result == kNoErr) + return (kNoErr); + if (result == kErrSTATFailed) { + cip->errNo = kErrNoSuchFileOrDirectory; + return (kErrNoSuchFileOrDirectory); + } + /* else keep going */ + } + + if (tryNLST != 0) { + result = FTPFileExistsNlst(cip, file); + if (result == kNoErr) + return (kNoErr); + if (result == kErrNLSTFailed) { + cip->errNo = kErrNoSuchFileOrDirectory; + return (kErrNoSuchFileOrDirectory); + } + /* else keep going */ + } + + cip->errNo = kErrCantTellIfFileExists; + return (kErrCantTellIfFileExists); +} /* FTPFileExists2 */ + + + + +int +FTPFileExists(const FTPCIPtr cip, const char *const file) +{ + return (FTPFileExists2(cip, file, 1, 1, 1, 1, 1)); +} /* FTPFileExists */ + + + + + +int +FTPFileSizeAndModificationTime(const FTPCIPtr cip, const char *const file, longest_int *const size, const int type, time_t *const mdtm) +{ + MLstItem mlsInfo; + int result; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if ((mdtm == NULL) || (size == NULL) || (file == NULL)) + return (kErrBadParameter); + + *mdtm = kModTimeUnknown; + *size = kSizeUnknown; + + result = FTPSetTransferType(cip, type); + if (result < 0) + return (result); + + result = FTPMListOneFile(cip, file, &mlsInfo); + if (result < 0) { + /* Do it the regular way, where + * we do a SIZE and then a MDTM. + */ + result = FTPFileSize(cip, file, size, type); + if (result < 0) + return (result); + result = FTPFileModificationTime(cip, file, mdtm); + return (result); + } else { + *mdtm = mlsInfo.ftime; + *size = mlsInfo.fsize; + } + + return (result); +} /* FTPFileSizeAndModificationTime */ + + + + +int +FTPFileType(const FTPCIPtr cip, const char *const file, int *const ftype) +{ + int result; + MLstItem mlsInfo; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if ((file == NULL) || (file[0] == '\0')) { + cip->errNo = kErrBadParameter; + return (kErrBadParameter); + } + + if (ftype == NULL) { + cip->errNo = kErrBadParameter; + return (kErrBadParameter); + } + + *ftype = 0; + result = FTPMListOneFile(cip, file, &mlsInfo); + if (result == kNoErr) { + *ftype = mlsInfo.ftype; + return (kNoErr); + } + + /* Preserve old working directory. */ + (void) FTPGetCWD(cip, cip->buf, cip->bufSize); + + result = FTPChdir(cip, file); + if (result == kNoErr) { + *ftype = 'd'; + /* Yes it was a directory, now go back to + * where we were. + */ + (void) FTPChdir(cip, cip->buf); + + /* Note: This improperly assumes that we + * will be able to chdir back, which is + * not guaranteed. + */ + return (kNoErr); + } + + result = FTPFileExists2(cip, file, 1, 1, 0, 1, 1); + if (result != kErrNoSuchFileOrDirectory) + result = kErrFileExistsButCannotDetermineType; + + return (result); +} /* FTPFileType */ + + + + +int +FTPIsDir(const FTPCIPtr cip, const char *const dir) +{ + int result, ftype; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if ((dir == NULL) || (dir[0] == '\0')) { + cip->errNo = kErrInvalidDirParam; + return (kErrInvalidDirParam); + } + + result = FTPFileType(cip, dir, &ftype); + if ((result == kNoErr) || (result == kErrFileExistsButCannotDetermineType)) { + result = 0; + if (ftype == 'd') + result = 1; + } + return (result); +} /* FTPIsDir */ + + + + +int +FTPIsRegularFile(const FTPCIPtr cip, const char *const file) +{ + int result, ftype; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if ((file == NULL) || (file[0] == '\0')) { + cip->errNo = kErrBadParameter; + return (kErrBadParameter); + } + + result = FTPFileType(cip, file, &ftype); + if ((result == kNoErr) || (result == kErrFileExistsButCannotDetermineType)) { + result = 1; + if (ftype == 'd') + result = 0; + } + return (result); +} /* FTPIsRegularFile */ + + + + +int +FTPSymlink(const FTPCIPtr cip, const char *const lfrom, const char *const lto) +{ + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + if ((cip == NULL) || (lfrom == NULL) || (lto == NULL)) + return (kErrBadParameter); + if ((lfrom[0] == '\0') || (lto[0] == '\0')) + return (kErrBadParameter); + if (FTPCmd(cip, "SITE SYMLINK %s %s", lfrom, lto) == 2) + return (kNoErr); + return (kErrSYMLINKFailed); +} /* FTPSymlink */ + + + + +int +FTPUmask(const FTPCIPtr cip, const char *const umsk) +{ + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + if ((umsk == NULL) || (umsk[0] == '\0')) + return (kErrBadParameter); + if (FTPCmd(cip, "SITE UMASK %s", umsk) == 2) + return (kNoErr); + return (kErrUmaskFailed); +} /* FTPUmask */ + + + + +static void +GmTimeStr(char *const dst, const size_t dstsize, time_t t) +{ + char buf[64]; + struct tm *gtp; + + gtp = gmtime(&t); + if (gtp == NULL) { + dst[0] = '\0'; + } else { +#ifdef HAVE_SNPRINTF + buf[sizeof(buf) - 1] = '\0'; + (void) snprintf(buf, sizeof(buf) - 1, "%04d%02d%02d%02d%02d%02d", +#else + (void) sprintf(buf, "%04d%02d%02d%02d%02d%02d", +#endif + gtp->tm_year + 1900, + gtp->tm_mon + 1, + gtp->tm_mday, + gtp->tm_hour, + gtp->tm_min, + gtp->tm_sec + ); + (void) Strncpy(dst, buf, dstsize); + } +} /* GmTimeStr */ + + + + +int +FTPUtime(const FTPCIPtr cip, const char *const file, time_t actime, time_t modtime, time_t crtime) +{ + char mstr[64], astr[64], cstr[64]; + int result; + ResponsePtr rp; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if (cip->hasUTIME == kCommandNotAvailable) { + cip->errNo = kErrUTIMENotAvailable; + result = kErrUTIMENotAvailable; + } else { + if ((actime == (time_t) 0) || (actime == (time_t) -1)) + (void) time(&actime); + if ((modtime == (time_t) 0) || (modtime == (time_t) -1)) + (void) time(&modtime); + if ((crtime == (time_t) 0) || (crtime == (time_t) -1)) + crtime = modtime; + + (void) GmTimeStr(astr, sizeof(astr), actime); + (void) GmTimeStr(mstr, sizeof(mstr), modtime); + (void) GmTimeStr(cstr, sizeof(cstr), crtime); + + rp = InitResponse(); + if (rp == NULL) { + result = kErrMallocFailed; + cip->errNo = kErrMallocFailed; + Error(cip, kDontPerror, "Malloc failed.\n"); + } else { + result = RCmd(cip, rp, "SITE UTIME %s %s %s %s UTC", file, astr, mstr, cstr); + if (result < 0) { + DoneWithResponse(cip, rp); + return (result); + } else if (result == 2) { + cip->hasUTIME = kCommandAvailable; + result = kNoErr; + } else if (UNIMPLEMENTED_CMD(rp->code)) { + cip->hasUTIME = kCommandNotAvailable; + cip->errNo = kErrUTIMENotAvailable; + result = kErrUTIMENotAvailable; + } else { + cip->errNo = kErrUTIMEFailed; + result = kErrUTIMEFailed; + } + DoneWithResponse(cip, rp); + } + } + return (result); +} /* FTPUtime */ diff --git a/reactos/apps/utils/net/ncftp/libncftp/config.h.in b/reactos/apps/utils/net/ncftp/libncftp/config.h.in new file mode 100644 index 00000000000..33351917a5c --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/config.h.in @@ -0,0 +1,207 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +#undef CAN_USE_SYS_SELECT_H + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define to `int' if doesn't define. */ +#undef gid_t + +/* Define if your compiler supports the "long long" integral type. */ +#undef HAVE_LONG_LONG + +/* Define if you have a _res global variable used by resolve routines. */ +#undef HAVE__RES_DEFDNAME + +/* Define if you have sigsetjmp and siglongjmp. */ +#undef HAVE_SIGSETJMP + +/* Define to `int' if doesn't define. */ +#undef mode_t + +/* Define to `long' if doesn't define. */ +#undef off_t + +/* Define to `int' if doesn't define. */ +#undef pid_t + +/* Format string for the printf() family for 64 bit integers. */ +#undef PRINTF_LONG_LONG + +/* Define if printing a "long long" with "%lld" works . */ +#undef PRINTF_LONG_LONG_LLD + +/* Define if printing a "long long" with "%qd" works . */ +#undef PRINTF_LONG_LONG_QD + +/* Format string for the scanf() family for 64 bit integers. */ +#undef SCANF_LONG_LONG + +/* Define if scanning a "long long" with "%lld" works. */ +#undef SCANF_LONG_LONG_LLD + +/* Define if scanning a "long long" with "%qd" works. */ +#undef SCANF_LONG_LONG_QD + + +/* Define to the type of arg1 for select(). */ +#undef SELECT_TYPE_ARG1 + +/* Define to the type of args 2, 3 and 4 for select(). */ +#undef SELECT_TYPE_ARG234 + +/* Define to the type of arg5 for select(). */ +#undef SELECT_TYPE_ARG5 + +/* Define if the setvbuf function takes the buffering type as its second + argument and the buffer pointer as the third, as on System V + before release 3. */ +#undef SETVBUF_REVERSED + +/* Define to `unsigned' if doesn't define. */ +#undef size_t + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to the full path of the Tar program, if you have it. */ +#undef TAR + +/* Define if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Define to `int' if doesn't define. */ +#undef uid_t + +/* Result of "uname -a" */ +#undef UNAME + +/* Define if you have the fstat64 function. */ +#undef HAVE_FSTAT64 + +/* Define if you have the getcwd function. */ +#undef HAVE_GETCWD + +/* Define if you have the getdomainname function. */ +#undef HAVE_GETDOMAINNAME + +/* Define if you have the gethostname function. */ +#undef HAVE_GETHOSTNAME + +/* Define if you have the getpass function. */ +#undef HAVE_GETPASS + +/* Define if you have the getwd function. */ +#undef HAVE_GETWD + +/* Define if you have the inet_ntop function. */ +#undef HAVE_INET_NTOP + +/* Define if you have the llseek function. */ +#undef HAVE_LLSEEK + +/* Define if you have the lseek64 function. */ +#undef HAVE_LSEEK64 + +/* Define if you have the lstat64 function. */ +#undef HAVE_LSTAT64 + +/* Define if you have the mktime function. */ +#undef HAVE_MKTIME + +/* Define if you have the open64 function. */ +#undef HAVE_OPEN64 + +/* Define if you have the res_init function. */ +#undef HAVE_RES_INIT + +/* Define if you have the sigaction function. */ +#undef HAVE_SIGACTION + +/* Define if you have the snprintf function. */ +#undef HAVE_SNPRINTF + +/* Define if you have the socket function. */ +#undef HAVE_SOCKET + +/* Define if you have the stat64 function. */ +#undef HAVE_STAT64 + +/* Define if you have the strcasecmp function. */ +#undef HAVE_STRCASECMP + +/* Define if you have the strerror function. */ +#undef HAVE_STRERROR + +/* Define if you have the strstr function. */ +#undef HAVE_STRSTR + +/* Define if you have the strtoq function. */ +#undef HAVE_STRTOQ + +/* Define if you have the symlink function. */ +#undef HAVE_SYMLINK + +/* Define if you have the vsnprintf function. */ +#undef HAVE_VSNPRINTF + +/* Define if you have the waitpid function. */ +#undef HAVE_WAITPID + +/* Define if you have the header file. */ +#undef HAVE_ARPA_NAMESER_H + +/* Define if you have the header file. */ +#undef HAVE_NSERVE_H + +/* Define if you have the header file. */ +#undef HAVE_RESOLV_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the header file. */ +#undef HAVE_UTIME_H + +/* Define if you have the 44bsd library (-l44bsd). */ +#undef HAVE_LIB44BSD + +/* Define if you have the com_err library (-lcom_err). */ +#undef HAVE_LIBCOM_ERR + +/* Define if you have the crypto library (-lcrypto). */ +#undef HAVE_LIBCRYPTO + +/* Define if you have the db library (-ldb). */ +#undef HAVE_LIBDB + +/* Define if you have the gen library (-lgen). */ +#undef HAVE_LIBGEN + +/* Define if you have the gssapi_krb5 library (-lgssapi_krb5). */ +#undef HAVE_LIBGSSAPI_KRB5 + +/* Define if you have the isode library (-lisode). */ +#undef HAVE_LIBISODE + +/* Define if you have the krb5 library (-lkrb5). */ +#undef HAVE_LIBKRB5 + +/* Define if you have the nsl library (-lnsl). */ +#undef HAVE_LIBNSL + +/* Define if you have the resolv library (-lresolv). */ +#undef HAVE_LIBRESOLV + +/* Define if you have the socket library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define if you have the socks5 library (-lsocks5). */ +#undef HAVE_LIBSOCKS5 diff --git a/reactos/apps/utils/net/ncftp/libncftp/configure.in b/reactos/apps/utils/net/ncftp/libncftp/configure.in new file mode 100644 index 00000000000..778db859833 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/configure.in @@ -0,0 +1,292 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(rcmd.c) +AC_PREREQ(2.4) +AC_CONFIG_HEADER(config.h) + +nc_cv_socks5=no +no_signals=yes + +AC_ARG_ENABLE(socks5,[ --enable-socks5 try to find and use the socks5 library],nc_cv_socks5=yes,nc_cv_socks5=no) +AC_ARG_ENABLE(signals,[ --enable-signals allow use of signal handling],[no_signals=no]) + + +wi_OS_VAR + +changequote(<<, >>)dnl +MAINDIR=`pwd` +if test -f "$MAINDIR/dos2unix.sh" ; then + chmod u+rwx $MAINDIR/dos2unix.sh + for dir in . ../sio ../Strn ; do + if [ -d "$dir" ] ; then + dir=`cd "$dir" ; pwd` + find "$dir" -name '*.in' -exec "$MAINDIR/dos2unix.sh" {} \; + find "$dir" -name '*.h' -exec "$MAINDIR/dos2unix.sh" {} \; + find "$dir" -name '*.c' -exec "$MAINDIR/dos2unix.sh" {} \; + fi + done +fi +MAKE=make +STATIC="" +BDYNAMIC="# -Wl,-Bdynamic" +BSTATIC="# -Wl,-Bstatic" +LIBSET='$(LIB)' +Z31='' +Z32='' +Z33='' +Z34='' +REDWING='no' +SFLAG='-s' + +case "$host" in + redwing*) CC=cc + LDFLAGS='' + STATIC='' + Z31=' -@mv $(STGZFILE) newbin/' + Z32=' -@mv $(DTGZFILE) newbin/' + Z33=' -@mv $(MTGZFILE) newbin/' + Z34=' -@mv $(PTGZFILE) newbin/' + REDWING='yes' + ;; +esac + +case "$os" in + linux) + BDYNAMIC="-Wl,-Bdynamic" + BSTATIC="-Wl,-Bstatic" + if [ "$MAKEWORLD_SH" = "" ] ; then + LIBSET='$(LIBSO) $(LIB)' + fi + ;; + freebsd) + BDYNAMIC="-Wl,-Bdynamic" + BSTATIC="-Wl,-Bstatic" + ;; + macosx*|rhapsody) + SFLAG='-Wl,-x' + ;; +esac + +changequote([, ])dnl + +AC_SUBST(CC) +AC_SUBST(CFLAGS) +AC_SUBST(CPPFLAGS) +AC_SUBST(LDFLAGS) +AC_SUBST(STATIC) +AC_SUBST(SFLAG) +AC_SUBST(LIBS) +AC_SUBST(DEFS) +AC_SUBST(MAKE) +AC_SUBST(Z31) +AC_SUBST(Z32) +AC_SUBST(Z33) +AC_SUBST(Z34) +AC_SUBST(LIBSET) +AC_SUBST(BDYNAMIC) +AC_SUBST(BSTATIC) +AC_SUBST(MAINDIR) + +if test -f ./samples/ncftpput2probe.c ; then + PROBE="ncftpget2probe ncftpput2probe" +else + PROBE="" +fi +AC_SUBST(PROBE) + +AC_PROG_CC +wi_REQUEST_NO_Y2K_WARNINGS +wi_CFLAGS_LFS64 +wi_DEFINE_UNAME + +if test -f /usr/src/include/eos.h ; then + if test "$REDWING" = no ; then + prefix=/usr/src + fi +fi + +if test "$wi_cv_prototypes" = no ; then + AC_WARN([Your compiler is probably won't be able to compile the package.]) + AC_WARN([Get gcc, or any compiler that supports function prototypes.]) +fi + +dnl # See if we should add -I/usr/local/include -L/usr/local/lib, etc. +dnl wi_EXTRA_DIRS(yes, /usr/local /usr/ccs, -) + +dnl For the sample programs. +wi_NET_LIBS + +if test "$nc_cv_socks5" = yes ; then +# Look for the "SOCKS" library for use with Firewalls/Gateways. +savelibs="$LIBS" +AC_CHECK_LIB(db, main) +AC_CHECK_LIB(isode, main) +AC_CHECK_LIB(com_err, main) +AC_CHECK_LIB(crypto, main) +AC_CHECK_LIB(krb5, main) +AC_CHECK_LIB(gssapi_krb5, main) +AC_CHECK_LIB(socks5,SOCKSinit) + if test "$ac_cv_lib_socks5" = yes ; then + nc_cv_socks=no + else + LIBS="$savelibs" + fi +else +ac_cv_lib_socks5=no +fi + + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS(sys/time.h unistd.h utime.h nserve.h resolv.h arpa/nameser.h) +AC_TIME_WITH_SYS_TIME + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_SIZE_T +AC_TYPE_OFF_T +AC_TYPE_MODE_T +AC_TYPE_PID_T +AC_TYPE_UID_T +wi__RES_DEFDNAME +wi_USE_LONG_LONG + +dnl Checks for library functions. +if test "$SYS" != sunos ; then + # Use getwd on SunOS -- getcwd does a "popen("/bin/pwd")" -- aaaccck. + # + AC_CHECK_FUNCS(getcwd) +fi +AC_CHECK_FUNCS(getwd gethostname socket strerror strstr) +AC_CHECK_FUNCS(getpass strcasecmp getdomainname mktime symlink inet_ntop) +AC_CHECK_FUNCS(res_init snprintf vsnprintf strtoq sigaction waitpid) +AC_CHECK_FUNCS(open64 stat64 fstat64 lstat64 lseek64 llseek) +wi_FUNC_SIGSETJMP +AC_FUNC_SETVBUF_REVERSED + +wi_HEADER_SYS_SELECT_H +AC_FUNC_SELECT_ARGTYPES + +if test -f ../sio/sio.h ; then + ldir=`cd ../sio ; pwd` + LDFLAGS="$LDFLAGS -L${ldir}" + CPPFLAGS="$CPPFLAGS -I${ldir}" + LIBS="$LIBS -lsio" +fi + +if test -f ../Strn/Strn.h ; then + ldir=`cd ../Strn ; pwd` + LDFLAGS="$LDFLAGS -L${ldir}" + CPPFLAGS="$CPPFLAGS -I${ldir}" + LIBS="$LIBS -lStrn" +fi + +if test $ac_cv_func_getcwd = no && test $ac_cv_func_getwd = no ; then +AC_WARN(This system does not have either getwd or getcwd?) +AC_WARN(I find that a little hard to believe.) +AC_WARN(You may want to try -DHAVE_GETWD anyway.) +AC_WARN([ +This could also mean that your compiler isn't working]) +AC_WARN(with this configure script. Check the ./config.log) +AC_WARN(and look for anomalies.) +fi + +wi_PROG_TAR +AC_PROG_RANLIB + +if test "$LONGEST_INT" = "long long" ; then + if sed 's/^#define longest_int.*/#define longest_int long long/; +s/^#define longest_uint.*/#define longest_uint unsigned long long/' ncftp.h > temp.h ; then + mv temp.h ncftp.h + chmod a+r ncftp.h + fi +else + if sed 's/^#define longest_int.*/#define longest_int long/; +s/^#define longest_uint.*/#define longest_uint unsigned long/' ncftp.h > temp.h ; then + mv temp.h ncftp.h + chmod a+r ncftp.h + fi +fi + +CPPFLAGS="-I$MAINDIR $CPPFLAGS" + +if test "$no_signals" = no ; then + dv1='# if 0' + dv2='#if 0' +else + dv1='# if 1' + dv2='#if 1' +fi + +if sed "s!^.*/. %config1!${dv1} /* %config1!;s!^.*/. %config2!${dv2} /* %config2!" ncftp.h > temp.h ; then + mv temp.h ncftp.h + chmod a+r ncftp.h +fi + +if sed "s!^.*/. %config1!${dv1} /* %config1!;s!^.*/. %config2!${dv2} /* %config2!" syshdrs.h > temp.h ; then + mv temp.h syshdrs.h + chmod a+r syshdrs.h +fi + +changequote(<<, >>)dnl +# +# Configure sio specially, like it would do. +# +if [ -d ../sio ] ; then + if sed "s!^.*/. %config1!${dv1} /* %config1!;s!^.*/. %config2!${dv2} /* %config2!" ../sio/sio.h > temp.h ; then + mv temp.h ../sio/sio.h + chmod a+r ../sio/sio.h + fi + if sed "s!^.*/. %config1!${dv1} /* %config1!;s!^.*/. %config2!${dv2} /* %config2!" ../sio/usio.h > temp.h ; then + mv temp.h ../sio/usio.h + chmod a+r ../sio/usio.h + fi + + patterns1="" + patterns2="" + if [ "$SYS" = solaris ] ; then + patterns1='s!/. %configure%.*!#define SAccept SAcceptS!' + patterns2='s!/. %configure%.*!#define UAccept UAcceptS!' + fi + + if [ "$patterns1" != "" ] ; then + sed "$patterns1" < ../sio/sio.h > tmpfile + if [ $? -eq 0 ] ; then + mv tmpfile ../sio/sio.h + chmod 644 ../sio/sio.h + else + /bin/rm tmpfile + fi + fi + + if [ "$patterns2" != "" ] ; then + sed "$patterns2" < ../sio/usio.h > tmpfile + if [ $? -eq 0 ] ; then + mv tmpfile ../sio/usio.h + chmod 644 ../sio/usio.h + else + /bin/rm tmpfile + fi + fi +fi +changequote([, ])dnl + +if test -d bin.only ; then + binonly="bin.only/Makefile bin.only/samples/Makefile" +else + binonly="" +fi + +LIBS=`echo "$LIBS" | sed 's/^ *//;s/ *$//;s/ */ /g'` +LDFLAGS=`echo "$LDFLAGS" | sed 's/^ *//;s/ *$//;s/ */ /g'` +CPPFLAGS=`echo "$CPPFLAGS" | sed 's/^ *//;s/ *$//;s/ */ /g'` +CFLAGS=`echo "$CFLAGS" | sed 's/^ *//;s/ *$//;s/ */ /g'` +DEFS=`echo "$DEFS" | sed 's/^ *//;s/ *$//;s/ */ /g'` + +samples='' +for sample in minincftp monkey ncftpget ncftpput ncftpls simpleget ncftpsyncput misc ; do + if test -f samples/$sample/Makefile.in ; then + samples="$samples samples/$sample/Makefile" + fi +done + +AC_OUTPUT([Makefile ../Strn/Makefile ../sio/Makefile $samples $binonly]) diff --git a/reactos/apps/utils/net/ncftp/libncftp/dos2unix.sh b/reactos/apps/utils/net/ncftp/libncftp/dos2unix.sh new file mode 100644 index 00000000000..0959d5e4f2d --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/dos2unix.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +es=1 +if [ $# -eq 0 ] ; then + exec tr -d '\015\032' +elif [ ! -f "$1" ] ; then + echo "Not found: $1" 1>&2 +else + for f in "$@" ; do + if tr -d '\015\032' < "$f" > "$f.tmp" ; then + if cmp "$f" "$f.tmp" > /dev/null ; then + rm -f "$f.tmp" + else + touch -r "$f" "$f.tmp" + if mv "$f" "$f.bak" ; then + if mv "$f.tmp" "$f" ; then + rm -f "$f.bak" + es=$? + echo " converted $f" + else + rm -f "$f.tmp" + fi + else + rm -f "$f.tmp" + fi + fi + else + rm -f "$f.tmp" + fi + done +fi + +exit $es diff --git a/reactos/apps/utils/net/ncftp/libncftp/errno.c b/reactos/apps/utils/net/ncftp/libncftp/errno.c new file mode 100644 index 00000000000..2d40a9d76bf --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/errno.c @@ -0,0 +1,163 @@ +/* errno.c + * + * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft. + * All rights reserved. + * + */ + +#define _libncftp_errno_c_ 1 +#include "syshdrs.h" + +static const char *gErrList[kErrLast - kErrFirst + 2] = { + "gethostname() failed", /* -100 */ + "hostname does not include domain name", /* -101 */ + "could not set linger mode", /* -102 */ + "could not set type of service", /* -103 */ + "could not enable out-of-band data inline", /* -104 */ + "unknown host", /* -105 */ + "could not get a new stream socket", /* -106 */ + "could not duplicate a socket", /* -107 */ + "fdopen for reading failed", /* -108 */ + "fdopen for writing failed", /* -109 */ + "getsockname failed", /* -110 */ + "could not bind the data socket", /* -111 */ + "could not listen on the data socket", /* -112 */ + "passive mode failed", /* -113 */ + "server sent bogus port number", /* -114 */ + "could not connect data socket", /* -115 */ + "could not accept data socket", /* -116 */ + "could not set restart point", /* -117 */ + "could not connect to remote host", /* -118 */ + "could not connect to remote host, but can try again", /* -119 */ + "remote host refused connection", /* -120 */ + "bad transfer type", /* -121 */ + "invalid directory parameter", /* -122 */ + "malloc failed", /* -123 */ + "PWD failed", /* -124 */ + "remote chdir failed", /* -125 */ + "remote rmdir failed", /* -126 */ + "bad line list", /* -127 */ + "unimplemented option", /* -128 */ + "unimplemented function", /* -129 */ + "remote directory listing failed", /* -130 */ + "could not retrieve remote file", /* -131 */ + "could not send file to remote host", /* -132 */ + "file write error", /* -133 */ + "file read error", /* -134 */ + "socket write error", /* -135 */ + "socket read error", /* -136 */ + "could not open file", /* -137 */ + "bad magic number in FTP library structure", /* -138 */ + "bad parameter given to library", /* -139 */ + "remote mkdir failed", /* -140 */ + "remote cd .. failed", /* -141 */ + "remote chmod failed", /* -142 */ + "remote umask failed", /* -143 */ + "remote delete failed", /* -144 */ + "remote file size inquiry failed", /* -145 */ + "remote file timestamp inquiry failed", /* -146 */ + "remote transfer type change failed", /* -147 */ + "file size inquiries not understood by remote server", /* -148 */ + "file timestamp inquiries not understood by remote server", /* -149 */ + "could not rename remote file", /* -150 */ + "could not do remote wildcard expansion", /* -151 */ + "could not set keepalive option", /* -152 */ + "remote host disconnected during login", /* -153 */ + "username was not accepted for login", /* -154 */ + "username and/or password was not accepted for login", /* -155 */ + "login failed", /* -156 */ + "invalid reply from server", /* -157 */ + "remote host closed control connection", /* -158 */ + "not connected", /* -159 */ + "could not start data transfer", /* -160 */ + "data transfer failed", /* -161 */ + "PORT failed", /* -162 */ + "PASV failed", /* -163 */ + "UTIME failed", /* -164 */ + "utime requests not understood by remote server", /* -165 */ + "HELP failed", /* -166 */ + "file deletion on local host failed", /* -167 */ + "lseek failed", /* -168 */ + "data transfer aborted by local user", /* -169 */ + "SYMLINK failed", /* -170 */ + "symlink requests not understood by remote server", /* -171 */ + "no match", /* -172 */ + "server features request failed", /* -173 */ + "no valid files were specified", /* -174 */ + "file transfer buffer has not been allocated", /* -175 */ + "will not overwrite local file with older remote file", /* -176 */ + "will not overwrite remote file with older local file", /* -177 */ + "local file appears to be the same as the remote file, no transfer necessary", /* -178 */ + "could not get extended directory information (MLSD)", /* -179 */ + "could not get extended file or directory information (MLST)", /* -180 */ + "could not parse extended file or directory information", /* -181 */ + "server does not support extended file or directory information", /* -182 */ + "server does not support extended directory information", /* -183 */ + "could not get information about specified file", /* -184 */ + "server does not support file or directory information", /* -185 */ + "could not get directory information about specified file", /* -186 */ + "server does not support directory information", /* -187 */ + "no such file or directory", /* -188 */ + "server provides no way to determine file existence", /* -189 */ + "item exists, but cannot tell if it is a file or directory", /* -190 */ + "not a directory", /* -191 */ + "directory recursion limit reached", /* -192 */ + "timed out while waiting for server response", /* -193 */ + "data transfer timed out", /* -194 */ + "canceled by user", /* -195 */ + NULL, +}; + +int gLibNcFTP_Uses_Me_To_Quiet_Variable_Unused_Warnings = 0; + +const char * +FTPStrError(int e) +{ + if (e == kErrGeneric) { + return ("miscellaneous error"); + } else if (e == kNoErr) { + return ("no error"); + } else { + if (e < 0) + e = -e; + if ((e >= kErrFirst) && (e <= kErrLast)) { + return (gErrList[e - kErrFirst]); + } + } + return ("unrecognized error number"); +} /* FTPStrError */ + + + + +void +FTPPerror(const FTPCIPtr cip, const int err, const int eerr, const char *const s1, const char *const s2) +{ + if (err != kNoErr) { + if (err == eerr) { + if ((s2 == NULL) || (s2[0] == '\0')) { + if ((s1 == NULL) || (s1[0] == '\0')) { + (void) fprintf(stderr, "server said: %s\n", cip->lastFTPCmdResultStr); + } else { + (void) fprintf(stderr, "%s: server said: %s\n", s1, cip->lastFTPCmdResultStr); + } + } else if ((s1 == NULL) || (s1[0] == '\0')) { + (void) fprintf(stderr, "%s: server said: %s\n", s2, cip->lastFTPCmdResultStr); + } else { + (void) fprintf(stderr, "%s %s: server said: %s\n", s1, s2, cip->lastFTPCmdResultStr); + } + } else { + if ((s2 == NULL) || (s2[0] == '\0')) { + if ((s1 == NULL) || (s1[0] == '\0')) { + (void) fprintf(stderr, "%s.\n", FTPStrError(cip->errNo)); + } else { + (void) fprintf(stderr, "%s: %s.\n", s1, FTPStrError(cip->errNo)); + } + } else if ((s1 == NULL) || (s1[0] == '\0')) { + (void) fprintf(stderr, "%s: %s.\n", s2, FTPStrError(cip->errNo)); + } else { + (void) fprintf(stderr, "%s %s: %s.\n", s1, s2, FTPStrError(cip->errNo)); + } + } + } +} /* FTPPerror */ diff --git a/reactos/apps/utils/net/ncftp/libncftp/ftp.c b/reactos/apps/utils/net/ncftp/libncftp/ftp.c new file mode 100644 index 00000000000..ca1e4842789 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/ftp.c @@ -0,0 +1,1362 @@ +/* ftp.c + * + * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft. + * All rights reserved. + * + */ + +#define _libncftp_ftp_c_ +#include "syshdrs.h" + +char gLibNcFTPVersion[64] = kLibraryVersion; + +#ifdef NO_SIGNALS +static char gNoSignalsMarker[] = "@(#) LibNcFTP - NO_SIGNALS"; +#else + +static int gGotSig = 0; +#ifdef HAVE_SIGSETJMP +static sigjmp_buf gCancelConnectJmp; +#else +static jmp_buf gCancelConnectJmp; +#endif /* HAVE_SIGSETJMP */ + +#endif /* NO_SIGNALS */ + + +#ifndef lint +static char gCopyright[] = "@(#) LibNcFTP Copyright 1995-2000, by Mike Gleason. All rights reserved."; +#endif + +#ifdef HAVE_LIBSOCKS5 +# define SOCKS 5 +# include +#else +# ifdef HAVE_LIBSOCKS +# define accept Raccept +# define connect Rconnect +# define getsockname Rgetsockname +# define listen Rlisten +# endif +#endif + + + + +/* On entry, you should have 'host' be set to a symbolic name (like + * cse.unl.edu), or set to a numeric address (like 129.93.3.1). + * If the function fails, it will return NULL, but if the host was + * a numeric style address, you'll have the ip_address to fall back on. + */ + +static struct hostent * +GetHostEntry(char *host, struct in_addr *ip_address) +{ + struct in_addr ip; + struct hostent *hp; + + /* See if the host was given in the dotted IP format, like "36.44.0.2." + * If it was, inet_addr will convert that to a 32-bit binary value; + * it not, inet_addr will return (-1L). + */ + ip.s_addr = inet_addr(host); + if (ip.s_addr != INADDR_NONE) { + hp = NULL; + } else { + /* No IP address, so it must be a hostname, like ftp.wustl.edu. */ + hp = gethostbyname(host); + if (hp != NULL) + (void) memcpy(&ip.s_addr, hp->h_addr_list[0], (size_t) hp->h_length); + } + if (ip_address != NULL) + *ip_address = ip; + return (hp); +} /* GetHostEntry */ + + + + +/* Makes every effort to return a fully qualified domain name. */ +int +GetOurHostName(char *host, size_t siz) +{ +#ifdef HOSTNAME + /* You can hardcode in the name if this routine doesn't work + * the way you want it to. + */ + Strncpy(host, HOSTNAME, siz); + return (1); /* Success */ +#else + struct hostent *hp; + int result; + char **curAlias; + char domain[64]; + char *cp; + int rc; + + host[0] = '\0'; + result = gethostname(host, (int) siz); + if ((result < 0) || (host[0] == '\0')) { + return (-1); + } + + if (strchr(host, '.') != NULL) { + /* gethostname returned full name (like "cse.unl.edu"), instead + * of just the node name (like "cse"). + */ + return (2); /* Success */ + } + + hp = gethostbyname(host); + if (hp != NULL) { + /* Maybe the host entry has the full name. */ + cp = strchr((char *) hp->h_name, '.'); + if ((cp != NULL) && (cp[1] != '\0')) { + /* The 'name' field for the host entry had full name. */ + (void) Strncpy(host, (char *) hp->h_name, siz); + return (3); /* Success */ + } + + /* Now try the list of aliases, to see if any of those look real. */ + for (curAlias = hp->h_aliases; *curAlias != NULL; curAlias++) { + cp = strchr(*curAlias, '.'); + if ((cp != NULL) && (cp[1] != '\0')) { + (void) Strncpy(host, *curAlias, siz); + return (4); /* Success */ + } + } + } + + /* Otherwise, we just have the node name. See if we can get the + * domain name ourselves. + */ +#ifdef DOMAINNAME + (void) STRNCPY(domain, DOMAINNAME); + rc = 5; +#else + rc = -1; + domain[0] = '\0'; +# if defined(HAVE_RES_INIT) && defined(HAVE__RES_DEFDNAME) + if (domain[0] == '\0') { + (void) res_init(); + if ((_res.defdname != NULL) && (_res.defdname[0] != '\0')) { + (void) STRNCPY(domain, _res.defdname); + rc = 6; + } + } +# endif /* HAVE_RES_INIT && HAVE__RES_DEFDNAME */ + + if (domain[0] == '\0') { + FILE *fp; + char line[256]; + char *tok; + + fp = fopen("/etc/resolv.conf", "r"); + if (fp != NULL) { + (void) memset(line, 0, sizeof(line)); + while (fgets(line, sizeof(line) - 1, fp) != NULL) { + if (!isalpha((int) line[0])) + continue; /* Skip comment lines. */ + tok = strtok(line, " \t\n\r"); + if (tok == NULL) + continue; /* Impossible */ + if (strcmp(tok, "domain") == 0) { + tok = strtok(NULL, " \t\n\r"); + if (tok == NULL) + continue; /* syntax error */ + (void) STRNCPY(domain, tok); + rc = 7; + break; /* Done. */ + } + } + (void) fclose(fp); + } + } +#endif /* DOMAINNAME */ + + if (domain[0] != '\0') { + /* Supposedly, it's legal for a domain name with + * a period at the end. + */ + cp = domain + strlen(domain) - 1; + if (*cp == '.') + *cp = '\0'; + if (domain[0] != '.') + (void) Strncat(host, ".", siz); + (void) Strncat(host, domain, siz); + } + if (rc < 0) + host[0] = '\0'; + return(rc); /* Success */ +#endif /* !HOSTNAME */ +} /* GetOurHostName */ + + + +void +CloseControlConnection(const FTPCIPtr cip) +{ + /* This will close each file, if it was open. */ +#ifdef NO_SIGNALS + SClose(cip->ctrlSocketR, 3); + cip->ctrlSocketR = kClosedFileDescriptor; + cip->ctrlSocketW = kClosedFileDescriptor; + DisposeSReadlineInfo(&cip->ctrlSrl); +#else /* NO_SIGNALS */ + if (cip->ctrlTimeout > 0) + (void) alarm(cip->ctrlTimeout); + CloseFile(&cip->cin); + CloseFile(&cip->cout); + cip->ctrlSocketR = kClosedFileDescriptor; + cip->ctrlSocketW = kClosedFileDescriptor; + if (cip->ctrlTimeout > 0) + (void) alarm(0); +#endif /* NO_SIGNALS */ + cip->connected = 0; + cip->loggedIn = 0; +} /* CloseControlConnection */ + + + +static int +GetSocketAddress(const FTPCIPtr cip, int sockfd, struct sockaddr_in *saddr) +{ + int len = (int) sizeof (struct sockaddr_in); + int result = 0; + + if (getsockname(sockfd, (struct sockaddr *)saddr, &len) < 0) { + Error(cip, kDoPerror, "Could not get socket name.\n"); + cip->errNo = kErrGetSockName; + result = kErrGetSockName; + } + return (result); +} /* GetSocketAddress */ + + + + +int +SetKeepAlive(const FTPCIPtr cip, int sockfd) +{ +#ifndef SO_KEEPALIVE + cip->errNo = kErrSetKeepAlive; + return (kErrSetKeepAlive); +#else + int opt; + + opt = 1; + + if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, (int) sizeof(opt)) < 0) { + /* Error(cip, kDoPerror, "Could not set keep-alive mode.\n"); */ + cip->errNo = kErrSetKeepAlive; + return (kErrSetKeepAlive); + } + return (kNoErr); +#endif /* SO_KEEPALIVE */ +} /* SetKeepAlive */ + + + + +int +SetLinger(const FTPCIPtr cip, int sockfd, int onoff) +{ +#ifndef SO_LINGER + cip->errNo = kErrSetLinger; + return (kErrSetLinger); +#else + struct linger li; + + if (onoff != 0) { + li.l_onoff = 1; + li.l_linger = 120; /* 2 minutes, but system ignores field. */ + } else { + li.l_onoff = 0; + li.l_linger = 0; + } + /* Have the system make an effort to deliver any unsent data, + * even after we close the connection. + */ + if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (char *) &li, (int) sizeof(li)) < 0) { + /* Error(cip, kDoPerror, "Could not set linger mode.\n"); */ + cip->errNo = kErrSetLinger; + return (kErrSetLinger); + } + return (kNoErr); +#endif /* SO_LINGER */ +} /* SetLinger */ + + + + +#ifdef IP_TOS +int +SetTypeOfService(const FTPCIPtr cip, int sockfd, int tosType) +{ + /* Specify to the router what type of connection this is, so it + * can prioritize packets. + */ + if (setsockopt(sockfd, IPPROTO_IP, IP_TOS, (char *) &tosType, (int) sizeof(tosType)) < 0) { + /* Error(cip, kDoPerror, "Could not set type of service.\n"); */ + cip->errNo = kErrSetTypeOfService; + return (kErrSetTypeOfService); + } + return (kNoErr); +} /* SetTypeOfService */ +#endif /* IP_TOS */ + + + + +#ifdef SO_OOBINLINE +int +SetInlineOutOfBandData(const FTPCIPtr cip, int sockfd) +{ + int on = 1; + + if (setsockopt(sockfd, SOL_SOCKET, SO_OOBINLINE, (char *) &on, (int) sizeof(on)) < 0) { + Error(cip, kDoPerror, "Could not set out of band inline mode.\n"); + cip->errNo = kErrSetOutOfBandInline; + return (kErrSetOutOfBandInline); + } + return (kNoErr); +} /* SetInlineOutOfBandData */ +#endif /* SO_OOBINLINE */ + + + + +#ifndef NO_SIGNALS + +static void +CancelConnect(int signum) +{ + gGotSig = signum; +#ifdef HAVE_SIGSETJMP + siglongjmp(gCancelConnectJmp, 1); +#else + longjmp(gCancelConnectJmp, 1); +#endif /* HAVE_SIGSETJMP */ +} /* CancelConnect */ + +#endif /* NO_SIGNALS */ + + + +int +OpenControlConnection(const FTPCIPtr cip, char *host, unsigned int port) +{ + struct in_addr ip_address; + int err = 0; + int result; + int oerrno; + volatile int sockfd = -1; + volatile int sock2fd = -1; + ResponsePtr rp; + char **volatile curaddr; + struct hostent *hp; + char *volatile fhost; + unsigned int fport; +#ifndef NO_SIGNALS + volatile FTPSigProc osigint; + volatile FTPSigProc osigalrm; + volatile FTPCIPtr vcip; + int sj; +#endif /* NO_SIGNALS */ + const char *firstLine, *secondLine, *srvr; + + LIBNCFTP_USE_VAR(gLibNcFTPVersion); + LIBNCFTP_USE_VAR(gCopyright); +#ifdef NO_SIGNALS + LIBNCFTP_USE_VAR(gNoSignalsMarker); +#endif /* NO_SIGNALS */ + + if (cip->firewallType == kFirewallNotInUse) { + fhost = host; + fport = port; + } else { + fhost = cip->firewallHost; + fport = cip->firewallPort; + } + if (fport == 0) + fport = cip->lip->defaultPort; + + /* Since we're the client, we just have to get a socket() and + * connect() it. + */ + (void) ZERO(cip->servCtlAddr); + cip->cin = NULL; + cip->cout = NULL; + + /* Make sure we use network byte-order. */ + fport = (unsigned int) htons((unsigned short) fport); + + cip->servCtlAddr.sin_port = (unsigned short) fport; + + hp = GetHostEntry(fhost, &ip_address); + + if (hp == NULL) { + /* Okay, no Host entry, but maybe we have a numeric address + * in ip_address we can try. + */ + if (ip_address.s_addr == INADDR_NONE) { + Error(cip, kDontPerror, "%s: unknown host.\n", fhost); + cip->errNo = kErrHostUnknown; + return (kErrHostUnknown); + } + cip->servCtlAddr.sin_family = AF_INET; + cip->servCtlAddr.sin_addr.s_addr = ip_address.s_addr; + } else { + cip->servCtlAddr.sin_family = hp->h_addrtype; + /* We'll fill in the rest of the structure below. */ + } + + /* After obtaining a socket, try to connect it to a remote + * address. If we didn't get a host entry, we will only have + * one thing to try (ip_address); if we do have one, we can try + * every address in the list from the host entry. + */ + + if (hp == NULL) { + /* Since we're given a single raw address, and not a host entry, + * we can only try this one address and not any other addresses + * that could be present for a site with a host entry. + */ + + if ((sockfd = socket(cip->servCtlAddr.sin_family, SOCK_STREAM, 0)) < 0) { + Error(cip, kDoPerror, "Could not get a socket.\n"); + cip->errNo = kErrNewStreamSocket; + return (kErrNewStreamSocket); + } + + /* This doesn't do anything if you left these + * at their defaults (zero). Otherwise it + * tries to set the buffer size to the + * size specified. + */ + (void) SetSockBufSize(sockfd, cip->ctrlSocketRBufSize, cip->ctrlSocketSBufSize); + +#ifdef NO_SIGNALS + err = SConnect(sockfd, &cip->servCtlAddr, (int) cip->connTimeout); + + if (err < 0) { + oerrno = errno; + (void) SClose(sockfd, 3); + errno = oerrno; + sockfd = -1; + } +#else /* NO_SIGNALS */ + osigint = (volatile FTPSigProc) signal(SIGINT, CancelConnect); + if (cip->connTimeout > 0) { + osigalrm = (volatile FTPSigProc) signal(SIGALRM, CancelConnect); + (void) alarm(cip->connTimeout); + } + + vcip = cip; + +#ifdef HAVE_SIGSETJMP + sj = sigsetjmp(gCancelConnectJmp, 1); +#else + sj = setjmp(gCancelConnectJmp); +#endif /* HAVE_SIGSETJMP */ + + if (sj != 0) { + /* Interrupted by a signal. */ + (void) closesocket(sockfd); + (void) signal(SIGINT, (FTPSigProc) osigint); + if (vcip->connTimeout > 0) { + (void) alarm(0); + (void) signal(SIGALRM, (FTPSigProc) osigalrm); + } + if (gGotSig == SIGINT) { + result = vcip->errNo = kErrConnectMiscErr; + Error(vcip, kDontPerror, "Connection attempt canceled.\n"); + (void) kill(getpid(), SIGINT); + } else if (gGotSig == SIGALRM) { + result = vcip->errNo = kErrConnectRetryableErr; + Error(vcip, kDontPerror, "Connection attempt timed-out.\n"); + (void) kill(getpid(), SIGALRM); + } else { + result = vcip->errNo = kErrConnectMiscErr; + Error(vcip, kDontPerror, "Connection attempt failed due to an unexpected signal (%d).\n", gGotSig); + } + return (result); + } else { + err = connect(sockfd, (struct sockaddr *) &cip->servCtlAddr, + (int) sizeof (cip->servCtlAddr)); + if (cip->connTimeout > 0) { + (void) alarm(0); + (void) signal(SIGALRM, (FTPSigProc) osigalrm); + } + (void) signal(SIGINT, (FTPSigProc) osigint); + } + + if (err < 0) { + oerrno = errno; + (void) closesocket(sockfd); + errno = oerrno; + sockfd = -1; + } +#endif /* NO_SIGNALS */ + } else { + /* We can try each address in the list. We'll quit when we + * run out of addresses to try or get a successful connection. + */ + for (curaddr = hp->h_addr_list; *curaddr != NULL; curaddr++) { + if ((sockfd = socket(cip->servCtlAddr.sin_family, SOCK_STREAM, 0)) < 0) { + Error(cip, kDoPerror, "Could not get a socket.\n"); + cip->errNo = kErrNewStreamSocket; + return (kErrNewStreamSocket); + } + /* This could overwrite the address field in the structure, + * but this is okay because the structure has a junk field + * just for this purpose. + */ + (void) memcpy(&cip->servCtlAddr.sin_addr, *curaddr, (size_t) hp->h_length); + + /* This doesn't do anything if you left these + * at their defaults (zero). Otherwise it + * tries to set the buffer size to the + * size specified. + */ + (void) SetSockBufSize(sockfd, cip->ctrlSocketRBufSize, cip->ctrlSocketSBufSize); + +#ifdef NO_SIGNALS + err = SConnect(sockfd, &cip->servCtlAddr, (int) cip->connTimeout); + + if (err == 0) + break; + oerrno = errno; + (void) SClose(sockfd, 3); + errno = oerrno; + sockfd = -1; +#else /* NO_SIGNALS */ + + osigint = (volatile FTPSigProc) signal(SIGINT, CancelConnect); + if (cip->connTimeout > 0) { + osigalrm = (volatile FTPSigProc) signal(SIGALRM, CancelConnect); + (void) alarm(cip->connTimeout); + } + + vcip = cip; +#ifdef HAVE_SIGSETJMP + sj = sigsetjmp(gCancelConnectJmp, 1); +#else + sj = setjmp(gCancelConnectJmp); +#endif /* HAVE_SIGSETJMP */ + + if (sj != 0) { + /* Interrupted by a signal. */ + (void) closesocket(sockfd); + (void) signal(SIGINT, (FTPSigProc) osigint); + if (vcip->connTimeout > 0) { + (void) alarm(0); + (void) signal(SIGALRM, (FTPSigProc) osigalrm); + } + if (gGotSig == SIGINT) { + result = vcip->errNo = kErrConnectMiscErr; + Error(vcip, kDontPerror, "Connection attempt canceled.\n"); + (void) kill(getpid(), SIGINT); + } else if (gGotSig == SIGALRM) { + result = vcip->errNo = kErrConnectRetryableErr; + Error(vcip, kDontPerror, "Connection attempt timed-out.\n"); + (void) kill(getpid(), SIGALRM); + } else { + result = vcip->errNo = kErrConnectMiscErr; + Error(vcip, kDontPerror, "Connection attempt failed due to an unexpected signal (%d).\n", gGotSig); + } + return (result); + } else { + err = connect(sockfd, (struct sockaddr *) &cip->servCtlAddr, + (int) sizeof (cip->servCtlAddr)); + if (cip->connTimeout > 0) { + (void) alarm(0); + (void) signal(SIGALRM, (FTPSigProc) osigalrm); + } + (void) signal(SIGINT, (FTPSigProc) osigint); + } + + if (err == 0) + break; + oerrno = errno; + (void) closesocket(sockfd); + errno = oerrno; + sockfd = -1; +#endif /* NO_SIGNALS */ + } + } + + if (err < 0) { + /* Could not connect. Close up shop and go home. */ + + /* If possible, tell the caller if they should bother + * calling back later. + */ + switch (errno) { +#ifdef ENETDOWN + case ENETDOWN: +#elif defined(WSAENETDOWN) + case WSAENETDOWN: +#endif +#ifdef ENETUNREACH + case ENETUNREACH: +#elif defined(WSAENETUNREACH) + case WSAENETUNREACH: +#endif +#ifdef ECONNABORTED + case ECONNABORTED: +#elif defined(WSAECONNABORTED) + case WSAECONNABORTED: +#endif +#ifdef ETIMEDOUT + case ETIMEDOUT: +#elif defined(WSAETIMEDOUT) + case WSAETIMEDOUT: +#endif +#ifdef EHOSTDOWN + case EHOSTDOWN: +#elif defined(WSAEHOSTDOWN) + case WSAEHOSTDOWN: +#endif +#ifdef ECONNRESET + case ECONNRESET: +#elif defined(WSAECONNRESET) + case WSAECONNRESET: +#endif + Error(cip, kDoPerror, "Could not connect to %s -- try again later.\n", fhost); + result = cip->errNo = kErrConnectRetryableErr; + break; +#ifdef ECONNREFUSED + case ECONNREFUSED: +#elif defined(WSAECONNREFUSED) + case WSAECONNREFUSED: +#endif + Error(cip, kDoPerror, "Could not connect to %s.\n", fhost); + result = cip->errNo = kErrConnectRefused; + break; + default: + Error(cip, kDoPerror, "Could not connect to %s.\n", fhost); + result = cip->errNo = kErrConnectMiscErr; + } + goto fatal; + } + + /* Get our end of the socket address for later use. */ + if ((result = GetSocketAddress(cip, sockfd, &cip->ourCtlAddr)) < 0) + goto fatal; + +#ifdef SO_OOBINLINE + /* We want Out-of-band data to appear in the regular stream, + * since we can handle TELNET. + */ + (void) SetInlineOutOfBandData(cip, sockfd); +#endif + (void) SetKeepAlive(cip, sockfd); + (void) SetLinger(cip, sockfd, 0); /* Don't need it for ctrl. */ + +#if defined(IP_TOS) && defined(IPTOS_LOWDELAY) + /* Control connection is somewhat interactive, so quick response + * is desired. + */ + (void) SetTypeOfService(cip, sockfd, IPTOS_LOWDELAY); +#endif + +#ifdef NO_SIGNALS + cip->ctrlSocketR = sockfd; + cip->ctrlSocketW = sockfd; + cip->cout = NULL; + cip->cin = NULL; + sock2fd = kClosedFileDescriptor; + + if (InitSReadlineInfo(&cip->ctrlSrl, sockfd, cip->srlBuf, sizeof(cip->srlBuf), (int) cip->ctrlTimeout, 1) < 0) { + result = kErrFdopenW; + cip->errNo = kErrFdopenW; + Error(cip, kDoPerror, "Could not fdopen.\n"); + goto fatal; + } +#else /* NO_SIGNALS */ + if ((sock2fd = dup(sockfd)) < 0) { + result = kErrDupSocket; + cip->errNo = kErrDupSocket; + Error(cip, kDoPerror, "Could not duplicate a file descriptor.\n"); + goto fatal; + } + + /* Now setup the FILE pointers for use with the Std I/O library + * routines. + */ + if ((cip->cin = fdopen(sockfd, "r")) == NULL) { + result = kErrFdopenR; + cip->errNo = kErrFdopenR; + Error(cip, kDoPerror, "Could not fdopen.\n"); + goto fatal; + } + + if ((cip->cout = fdopen(sock2fd, "w")) == NULL) { + result = kErrFdopenW; + cip->errNo = kErrFdopenW; + Error(cip, kDoPerror, "Could not fdopen.\n"); + CloseFile(&cip->cin); + sockfd = kClosedFileDescriptor; + goto fatal; + } + + cip->ctrlSocketR = sockfd; + cip->ctrlSocketW = sockfd; + + /* We'll be reading and writing lines, so use line buffering. This + * is necessary since the stdio library will use full buffering + * for all streams not associated with the tty. + */ +#ifdef HAVE_SETLINEBUF + setlinebuf(cip->cin); + setlinebuf(cip->cout); +#else + (void) SETVBUF(cip->cin, NULL, _IOLBF, (size_t) BUFSIZ); + (void) SETVBUF(cip->cout, NULL, _IOLBF, (size_t) BUFSIZ); +#endif +#endif /* NO_SIGNALS */ + +#ifdef HAVE_INET_NTOP /* Mostly to workaround bug in IRIX 6.5's inet_ntoa */ + (void) memset(cip->ip, 0, sizeof(cip->ip)); + (void) inet_ntop(AF_INET, &cip->servCtlAddr.sin_addr, cip->ip, sizeof(cip->ip) - 1); +#else + (void) STRNCPY(cip->ip, inet_ntoa(cip->servCtlAddr.sin_addr)); +#endif + if ((hp == NULL) || (hp->h_name == NULL)) + (void) STRNCPY(cip->actualHost, fhost); + else + (void) STRNCPY(cip->actualHost, (char *) hp->h_name); + + /* Read the startup message from the server. */ + rp = InitResponse(); + if (rp == NULL) { + Error(cip, kDontPerror, "Malloc failed.\n"); + cip->errNo = kErrMallocFailed; + result = cip->errNo; + goto fatal; + } + + result = GetResponse(cip, rp); + if ((result < 0) && (rp->msg.first == NULL)) { + goto fatal; + } + if (rp->msg.first != NULL) { + cip->serverType = kServerTypeUnknown; + srvr = NULL; + firstLine = rp->msg.first->line; + secondLine = NULL; + if (rp->msg.first->next != NULL) + secondLine = rp->msg.first->next->line; + + if (strstr(firstLine, "Version wu-") != NULL) { + cip->serverType = kServerTypeWuFTPd; + srvr = "wu-ftpd"; + } else if (strstr(firstLine, "NcFTPd") != NULL) { + cip->serverType = kServerTypeNcFTPd; + srvr = "NcFTPd Server"; + } else if (STRNEQ("ProFTPD", firstLine, 7)) { + cip->serverType = kServerTypeProFTPD; + srvr = "ProFTPD"; + } else if (strstr(firstLine, "Microsoft FTP Service") != NULL) { + cip->serverType = kServerTypeMicrosoftFTP; + srvr = "Microsoft FTP Service"; + } else if (strstr(firstLine, "(NetWare ") != NULL) { + cip->serverType = kServerTypeNetWareFTP; + srvr = "NetWare FTP Service"; + } else if (STRNEQ("WFTPD", firstLine, 5)) { + cip->serverType = kServerTypeWFTPD; + srvr = "WFTPD"; + } else if (STRNEQ("Serv-U FTP", firstLine, 10)) { + cip->serverType = kServerTypeServ_U; + srvr = "Serv-U FTP-Server"; + } else if (strstr(firstLine, "VFTPD") != NULL) { + cip->serverType = kServerTypeVFTPD; + srvr = "VFTPD"; + } else if (STRNEQ("FTP-Max", firstLine, 7)) { + cip->serverType = kServerTypeFTP_Max; + srvr = "FTP-Max"; + } else if (strstr(firstLine, "Roxen") != NULL) { + cip->serverType = kServerTypeRoxen; + srvr = "Roxen"; + } else if (strstr(firstLine, "WS_FTP") != NULL) { + cip->serverType = kServerTypeWS_FTP; + srvr = "WS_FTP Server"; + } else if ((secondLine != NULL) && (strstr(secondLine, "WarFTP") != NULL)) { + cip->serverType = kServerTypeWarFTPd; + srvr = "WarFTPd"; + } + + if (srvr != NULL) + PrintF(cip, "Remote server is running %s.\n", srvr); + + /* Do the application's connect message callback, if present. */ + if ((cip->onConnectMsgProc != 0) && (rp->codeType < 4)) + (*cip->onConnectMsgProc)(cip, rp); + } + + if (rp->codeType >= 4) { + /* They probably hung up on us right away. That's too bad, + * but we can tell the caller that they can call back later + * and try again. + */ + DoneWithResponse(cip, rp); + result = kErrConnectRetryableErr; + Error(cip, kDontPerror, "Server hungup immediately after connect.\n"); + cip->errNo = kErrConnectRetryableErr; + goto fatal; + } + if (result < 0) /* Some other error occurred during connect message */ + goto fatal; + cip->connected = 1; + DoneWithResponse(cip, rp); + return (kNoErr); + +fatal: + if (sockfd > 0) + (void) closesocket(sockfd); + if (sock2fd > 0) + (void) closesocket(sock2fd); + CloseFile(&cip->cin); + CloseFile(&cip->cout); + cip->ctrlSocketR = kClosedFileDescriptor; + cip->ctrlSocketW = kClosedFileDescriptor; + return (result); +} /* OpenControlConnection */ + + + + +void +CloseDataConnection(const FTPCIPtr cip) +{ + if (cip->dataSocket != kClosedFileDescriptor) { +#ifdef NO_SIGNALS + SClose(cip->dataSocket, 3); +#else /* NO_SIGNALS */ + if (cip->xferTimeout > 0) + (void) alarm(cip->xferTimeout); + (void) closesocket(cip->dataSocket); + if (cip->xferTimeout > 0) + (void) alarm(0); +#endif /* NO_SIGNALS */ + cip->dataSocket = kClosedFileDescriptor; + } + memset(&cip->ourDataAddr, 0, sizeof(cip->ourDataAddr)); + memset(&cip->servDataAddr, 0, sizeof(cip->servDataAddr)); +} /* CloseDataConnection */ + + + + +int +SetStartOffset(const FTPCIPtr cip, longest_int restartPt) +{ + ResponsePtr rp; + int result; + + if (restartPt != (longest_int) 0) { + rp = InitResponse(); + if (rp == NULL) { + Error(cip, kDontPerror, "Malloc failed.\n"); + cip->errNo = kErrMallocFailed; + return (cip->errNo); + } + + /* Force reset to offset zero. */ + if (restartPt == (longest_int) -1) + restartPt = (longest_int) 0; +#ifdef PRINTF_LONG_LONG + result = RCmd(cip, rp, + "REST " PRINTF_LONG_LONG, + restartPt); +#else + result = RCmd(cip, rp, "REST %ld", (long) restartPt); +#endif + + if (result < 0) { + return (result); + } else if (result == 3) { + cip->hasREST = kCommandAvailable; + DoneWithResponse(cip, rp); + } else if (UNIMPLEMENTED_CMD(rp->code)) { + cip->hasREST = kCommandNotAvailable; + DoneWithResponse(cip, rp); + cip->errNo = kErrSetStartPoint; + return (kErrSetStartPoint); + } else { + DoneWithResponse(cip, rp); + cip->errNo = kErrSetStartPoint; + return (kErrSetStartPoint); + } + } + return (0); +} /* SetStartOffset */ + + + +static int +SendPort(const FTPCIPtr cip, struct sockaddr_in *saddr) +{ + char *a, *p; + int result; + ResponsePtr rp; + + rp = InitResponse(); + if (rp == NULL) { + Error(cip, kDontPerror, "Malloc failed.\n"); + cip->errNo = kErrMallocFailed; + return (cip->errNo); + } + + /* These will point to data in network byte order. */ + a = (char *) &saddr->sin_addr; + p = (char *) &saddr->sin_port; +#define UC(x) (int) (((int) x) & 0xff) + + /* Need to tell the other side which host (the address) and + * which process (port) on that host to send data to. + */ + result = RCmd(cip, rp, "PORT %d,%d,%d,%d,%d,%d", + UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); + + if (result < 0) { + return (result); + } else if (result != 2) { + /* A 500'ish response code means the PORT command failed. */ + DoneWithResponse(cip, rp); + cip->errNo = kErrPORTFailed; + return (cip->errNo); + } + DoneWithResponse(cip, rp); + return (kNoErr); +} /* SendPort */ + + + + +static int +Passive(const FTPCIPtr cip, struct sockaddr_in *saddr, int *weird) +{ + ResponsePtr rp; + int i[6], j; + unsigned char n[6]; + char *cp; + int result; + + rp = InitResponse(); + if (rp == NULL) { + Error(cip, kDontPerror, "Malloc failed.\n"); + cip->errNo = kErrMallocFailed; + return (cip->errNo); + } + + result = RCmd(cip, rp, "PASV"); + if (result < 0) + goto done; + + if (rp->codeType != 2) { + /* Didn't understand or didn't want passive port selection. */ + cip->errNo = result = kErrPASVFailed; + goto done; + } + + /* The other side returns a specification in the form of + * an internet address as the first four integers (each + * integer stands for 8-bits of the real 32-bit address), + * and two more integers for the port (16-bit port). + * + * It should give us something like: + * "Entering Passive Mode (129,93,33,1,10,187)", so look for + * digits with sscanf() starting 24 characters down the string. + */ + for (cp = rp->msg.first->line; ; cp++) { + if (*cp == '\0') { + Error(cip, kDontPerror, "Cannot parse PASV response: %s\n", rp->msg.first->line); + goto done; + } + if (isdigit((int) *cp)) + break; + } + + if (sscanf(cp, "%d,%d,%d,%d,%d,%d", + &i[0], &i[1], &i[2], &i[3], &i[4], &i[5]) != 6) { + Error(cip, kDontPerror, "Cannot parse PASV response: %s\n", rp->msg.first->line); + goto done; + } + + for (j=0, *weird = 0; j<6; j++) { + /* Some ftp servers return bogus port octets, such as + * boombox.micro.umn.edu. Let the caller know if we got a + * weird looking octet. + */ + if ((i[j] < 0) || (i[j] > 255)) + *weird = *weird + 1; + n[j] = (unsigned char) (i[j] & 0xff); + } + + (void) memcpy(&saddr->sin_addr, &n[0], (size_t) 4); + (void) memcpy(&saddr->sin_port, &n[4], (size_t) 2); + + result = kNoErr; +done: + DoneWithResponse(cip, rp); + return (result); +} /* Passive */ + + + + +static int +BindToEphemeralPortNumber(int sockfd, struct sockaddr_in *addrp, int ephemLo, int ephemHi) +{ + int i; + int result; + int rangesize; + unsigned short port; + + addrp->sin_family = AF_INET; + if (((int) ephemLo == 0) || ((int) ephemLo >= (int) ephemHi)) { + /* Do it the normal way. System will + * pick one, typically in the range + * of 1024-4999. + */ + addrp->sin_port = 0; /* Let system pick one. */ + + result = bind(sockfd, (struct sockaddr *) addrp, sizeof(struct sockaddr_in)); + } else { + rangesize = (int) ((int) ephemHi - (int) ephemLo); + result = 0; + for (i=0; i<10; i++) { + port = (unsigned short) (((int) rand() % rangesize) + (int) ephemLo); + addrp->sin_port = port; + + result = bind(sockfd, (struct sockaddr *) addrp, sizeof(struct sockaddr_in)); + if (result == 0) + break; + if ((errno != 999) + /* This next line is just fodder to + * shut the compiler up about variable + * not being used. + */ + && (gCopyright[0] != '\0')) + break; + } + } + return (result); +} /* BindToEphemeralPortNumber */ + + + + +int +OpenDataConnection(const FTPCIPtr cip, int mode) +{ + int dataSocket; + int weirdPort; + int result; + + /* Before we can transfer any data, and before we even ask the + * remote server to start transferring via RETR/NLST/etc, we have + * to setup the connection. + */ + +tryPort2: + weirdPort = 0; + result = 0; + CloseDataConnection(cip); /* In case we didn't before... */ + + dataSocket = socket(AF_INET, SOCK_STREAM, 0); + if (dataSocket < 0) { + Error(cip, kDoPerror, "Could not get a data socket.\n"); + result = kErrNewStreamSocket; + cip->errNo = kErrNewStreamSocket; + return result; + } + + /* This doesn't do anything if you left these + * at their defaults (zero). Otherwise it + * tries to set the buffer size to the + * size specified. + */ + (void) SetSockBufSize(dataSocket, cip->dataSocketRBufSize, cip->dataSocketSBufSize); + + if ((cip->hasPASV == kCommandNotAvailable) || (mode == kSendPortMode)) { +tryPort: + cip->ourDataAddr = cip->ourCtlAddr; + cip->ourDataAddr.sin_family = AF_INET; + +#ifdef HAVE_LIBSOCKS + cip->ourDataAddr.sin_port = 0; + if (Rbind(dataSocket, (struct sockaddr *) &cip->ourDataAddr, + (int) sizeof (cip->ourDataAddr), + cip->servCtlAddr.sin_addr.s_addr) < 0) +#else + if (BindToEphemeralPortNumber(dataSocket, &cip->ourDataAddr, (int) cip->ephemLo, (int) cip->ephemHi) < 0) +#endif + { + Error(cip, kDoPerror, "Could not bind the data socket"); + result = kErrBindDataSocket; + cip->errNo = kErrBindDataSocket; + goto bad; + } + + /* Need to do this so we can figure out which port the system + * gave to us. + */ + if ((result = GetSocketAddress(cip, dataSocket, &cip->ourDataAddr)) < 0) + goto bad; + + if (listen(dataSocket, 1) < 0) { + Error(cip, kDoPerror, "listen failed"); + result = kErrListenDataSocket; + cip->errNo = kErrListenDataSocket; + goto bad; + } + + if ((result = SendPort(cip, &cip->ourDataAddr)) < 0) + goto bad; + + cip->dataPortMode = kSendPortMode; + } else { + /* Passive mode. Let the other side decide where to send. */ + + cip->servDataAddr = cip->servCtlAddr; + cip->servDataAddr.sin_family = AF_INET; + cip->ourDataAddr = cip->ourCtlAddr; + cip->ourDataAddr.sin_family = AF_INET; + + if (Passive(cip, &cip->servDataAddr, &weirdPort) < 0) { + Error(cip, kDontPerror, "Passive mode refused.\n"); + cip->hasPASV = kCommandNotAvailable; + + /* We can try using regular PORT commands, which are required + * by all FTP protocol compliant programs, if you said so. + * + * We don't do this automatically, because if your host + * is running a firewall you (probably) do not want SendPort + * FTP for security reasons. + */ + if (mode == kFallBackToSendPortMode) + goto tryPort; + result = kErrPassiveModeFailed; + cip->errNo = kErrPassiveModeFailed; + goto bad; + } + +#ifdef HAVE_LIBSOCKS + cip->ourDataAddr.sin_port = 0; + if (Rbind(dataSocket, (struct sockaddr *) &cip->ourDataAddr, + (int) sizeof (cip->ourDataAddr), + cip->servCtlAddr.sin_addr.s_addr) < 0) +#else + if (BindToEphemeralPortNumber(dataSocket, &cip->ourDataAddr, (int) cip->ephemLo, (int) cip->ephemHi) < 0) +#endif + { + Error(cip, kDoPerror, "Could not bind the data socket"); + result = kErrBindDataSocket; + cip->errNo = kErrBindDataSocket; + goto bad; + } + +#ifdef NO_SIGNALS + result = SConnect(dataSocket, &cip->servDataAddr, (int) cip->connTimeout); +#else /* NO_SIGNALS */ + if (cip->connTimeout > 0) + (void) alarm(cip->connTimeout); + + result = connect(dataSocket, (struct sockaddr *) &cip->servDataAddr, (int) sizeof(cip->servDataAddr)); + if (cip->connTimeout > 0) + (void) alarm(0); +#endif /* NO_SIGNALS */ + +#ifdef NO_SIGNALS + if (result == kTimeoutErr) { + if (mode == kFallBackToSendPortMode) { + Error(cip, kDontPerror, "Data connection timed out.\n"); + Error(cip, kDontPerror, "Falling back to PORT instead of PASV mode.\n"); + (void) closesocket(dataSocket); + cip->hasPASV = kCommandNotAvailable; + goto tryPort2; + } + Error(cip, kDontPerror, "Data connection timed out.\n"); + result = kErrConnectDataSocket; + cip->errNo = kErrConnectDataSocket; + } else +#endif /* NO_SIGNALS */ + + if (result < 0) { +#ifdef ECONNREFUSED + if ((weirdPort > 0) && (errno == ECONNREFUSED)) { +#elif defined(WSAECONNREFUSED) + if ((weirdPort > 0) && (errno == WSAECONNREFUSED)) { +#endif + Error(cip, kDontPerror, "Server sent back a bogus port number.\nI will fall back to PORT instead of PASV mode.\n"); + if (mode == kFallBackToSendPortMode) { + (void) closesocket(dataSocket); + cip->hasPASV = kCommandNotAvailable; + goto tryPort2; + } + result = kErrServerSentBogusPortNumber; + cip->errNo = kErrServerSentBogusPortNumber; + goto bad; + } + if (mode == kFallBackToSendPortMode) { + Error(cip, kDoPerror, "connect failed.\n"); + Error(cip, kDontPerror, "Falling back to PORT instead of PASV mode.\n"); + (void) closesocket(dataSocket); + cip->hasPASV = kCommandNotAvailable; + goto tryPort2; + } + Error(cip, kDoPerror, "connect failed.\n"); + result = kErrConnectDataSocket; + cip->errNo = kErrConnectDataSocket; + goto bad; + } + + /* Need to do this so we can figure out which port the system + * gave to us. + */ + if ((result = GetSocketAddress(cip, dataSocket, &cip->ourDataAddr)) < 0) + goto bad; + + cip->dataPortMode = kPassiveMode; + cip->hasPASV = kCommandAvailable; + } + + (void) SetLinger(cip, dataSocket, 1); + (void) SetKeepAlive(cip, dataSocket); + +#if defined(IP_TOS) && defined(IPTOS_THROUGHPUT) + /* Data connection is a non-interactive data stream, so + * high throughput is desired, at the expense of low + * response time. + */ + (void) SetTypeOfService(cip, dataSocket, IPTOS_THROUGHPUT); +#endif + + cip->dataSocket = dataSocket; + return (0); +bad: + (void) closesocket(dataSocket); + return (result); +} /* OpenDataConnection */ + + + + +int +AcceptDataConnection(const FTPCIPtr cip) +{ + int newSocket; +#ifndef NO_SIGNALS + int len; +#endif + unsigned short remoteDataPort; + unsigned short remoteCtrlPort; + + /* If we did a PORT, we have some things to finish up. + * If we did a PASV, we're ready to go. + */ + if (cip->dataPortMode == kSendPortMode) { + /* Accept will give us back the server's data address; at the + * moment we don't do anything with it though. + */ + memset(&cip->servDataAddr, 0, sizeof(cip->servDataAddr)); + +#ifdef NO_SIGNALS + newSocket = SAccept(cip->dataSocket, &cip->servDataAddr, (int) cip->connTimeout); +#else /* NO_SIGNALS */ + len = (int) sizeof(cip->servDataAddr); + if (cip->connTimeout > 0) + (void) alarm(cip->connTimeout); + newSocket = accept(cip->dataSocket, (struct sockaddr *) &cip->servDataAddr, &len); + if (cip->connTimeout > 0) + (void) alarm(0); +#endif /* NO_SIGNALS */ + + (void) closesocket(cip->dataSocket); + if (newSocket < 0) { + Error(cip, kDoPerror, "Could not accept a data connection.\n"); + cip->dataSocket = kClosedFileDescriptor; + cip->errNo = kErrAcceptDataSocket; + return (kErrAcceptDataSocket); + } + + if (cip->require20 != 0) { + remoteDataPort = ntohs(cip->servDataAddr.sin_port); + remoteCtrlPort = ntohs(cip->servCtlAddr.sin_port); + if ((int) remoteDataPort != ((int) remoteCtrlPort - 1)) { + Error(cip, kDontPerror, "Data connection did not originate on correct port!\n"); + (void) closesocket(newSocket); + cip->dataSocket = kClosedFileDescriptor; + cip->errNo = kErrAcceptDataSocket; + return (kErrAcceptDataSocket); + } else if (memcmp(&cip->servDataAddr.sin_addr.s_addr, &cip->servCtlAddr.sin_addr.s_addr, sizeof(cip->servDataAddr.sin_addr.s_addr)) != 0) { + Error(cip, kDontPerror, "Data connection did not originate from remote server!\n"); + (void) closesocket(newSocket); + cip->dataSocket = kClosedFileDescriptor; + cip->errNo = kErrAcceptDataSocket; + return (kErrAcceptDataSocket); + } + } + + cip->dataSocket = newSocket; + } + + return (0); +} /* AcceptDataConnection */ + + + + +void +HangupOnServer(const FTPCIPtr cip) +{ + /* Since we want to close both sides of the connection for each + * socket, we can just have them closed with close() instead of + * using shutdown(). + */ + CloseControlConnection(cip); + CloseDataConnection(cip); +} /* HangupOnServer */ + + + + +void +SendTelnetInterrupt(const FTPCIPtr cip) +{ + char msg[4]; + + /* 1. User system inserts the Telnet "Interrupt Process" (IP) signal + * in the Telnet stream. + */ + + if (cip->cout != NULL) + (void) fflush(cip->cout); + + msg[0] = (char) (unsigned char) IAC; + msg[1] = (char) (unsigned char) IP; + (void) send(cip->ctrlSocketW, msg, 2, 0); + + /* 2. User system sends the Telnet "Sync" signal. */ +#if 1 + msg[0] = (char) (unsigned char) IAC; + msg[1] = (char) (unsigned char) DM; + if (send(cip->ctrlSocketW, msg, 2, MSG_OOB) != 2) + Error(cip, kDoPerror, "Could not send an urgent message.\n"); +#else + /* "Send IAC in urgent mode instead of DM because UNIX places oob mark + * after urgent byte rather than before as now is protocol," says + * the BSD ftp code. + */ + msg[0] = (char) (unsigned char) IAC; + if (send(cip->ctrlSocketW, msg, 1, MSG_OOB) != 1) + Error(cip, kDoPerror, "Could not send an urgent message.\n"); + (void) fprintf(cip->cout, "%c", DM); + (void) fflush(cip->cout); +#endif +} /* SendTelnetInterrupt */ + +/* eof FTP.c */ diff --git a/reactos/apps/utils/net/ncftp/libncftp/ftp.h b/reactos/apps/utils/net/ncftp/libncftp/ftp.h new file mode 100644 index 00000000000..f91d9503bf3 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/ftp.h @@ -0,0 +1,22 @@ +/* FTP.h + * + * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft. + * All rights reserved. + * + */ + +/* FTP.c */ +void MyInetAddr(char *, size_t, char **, int); +int GetOurHostName(char *, size_t); +void CloseControlConnection(const FTPCIPtr); +int SetKeepAlive(const FTPCIPtr, int); +int SetLinger(const FTPCIPtr, int, int); +int SetTypeOfService(const FTPCIPtr, int, int); +int SetInlineOutOfBandData(const FTPCIPtr, int); +int OpenControlConnection(const FTPCIPtr, char *, unsigned int); +void CloseDataConnection(const FTPCIPtr); +int SetStartOffset(const FTPCIPtr, longest_int); +int OpenDataConnection(const FTPCIPtr, int); +int AcceptDataConnection(const FTPCIPtr); +void HangupOnServer(const FTPCIPtr); +void SendTelnetInterrupt(const FTPCIPtr); diff --git a/reactos/apps/utils/net/ncftp/libncftp/glob.c b/reactos/apps/utils/net/ncftp/libncftp/glob.c new file mode 100644 index 00000000000..4b6f7b58f22 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/glob.c @@ -0,0 +1,1760 @@ +/* glob.c + * + * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft. + * All rights reserved. + * + */ + +#include "syshdrs.h" + +static const char *rwx[9] = { "---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx", NULL }; + + + +/* We need to use this because using NLST gives us more stuff than + * we want back sometimes. For example, say we have: + * + * /a (directory) + * /a/b (directory) + * /a/b/b1 + * /a/b/b2 + * /a/b/b3 + * /a/c (directory) + * /a/c/c1 + * /a/c/c2 + * /a/c/c3 + * /a/file + * + * If you did an "echo /a/" in a normal unix shell, you would expect + * to get back /a/b /a/c /a/file. But NLST gives back: + * + * /a/b/b1 + * /a/b/b2 + * /a/b/b3 + * /a/c/c1 + * /a/c/c2 + * /a/c/c3 + * /a/file + * + * So we use the following routine to convert into the format I expect. + */ + +static void +RemoteGlobCollapse(const char *pattern, LineListPtr fileList) +{ + LinePtr lp, nextLine; + string patPrefix; + string cur, prev; + char *endp, *cp, *dp; + const char *pp; + int wasGlobChar; + size_t plen; + + /* Copy all characters before the first glob-char. */ + dp = patPrefix; + endp = dp + sizeof(patPrefix) - 1; + wasGlobChar = 0; + for (cp = (char *) pattern; dp < endp; ) { + for (pp=kGlobChars; *pp != '\0'; pp++) { + if (*pp == *cp) { + wasGlobChar = 1; + break; + } + } + if (wasGlobChar) + break; + *dp++ = *cp++; + } + *dp = '\0'; + plen = (size_t) (dp - patPrefix); + + *prev = '\0'; + for (lp=fileList->first; lp != NULL; lp = nextLine) { + nextLine = lp->next; + if (strncmp(lp->line, patPrefix, plen) == 0) { + (void) STRNCPY(cur, lp->line + plen); + cp = strchr(cur, '/'); + if (cp == NULL) + cp = strchr(cur, '\\'); + if (cp != NULL) + *cp = '\0'; + if ((*prev != '\0') && (STREQ(cur, prev))) { + nextLine = RemoveLine(fileList, lp); + } else { + (void) STRNCPY(prev, cur); + /* We are playing with a dynamically + * allocated string, but since the + * following expression is guaranteed + * to be the same or shorter, we won't + * overwrite the bounds. + */ + (void) sprintf(lp->line, "%s%s", patPrefix, cur); + } + } + } +} /* RemoteGlobCollapse */ + + + + +#if 0 +/* May need this later. */ +static void +CheckForLS_d(FTPCIPtr cip) +{ + LineList lines; + char *cp; + + if (cip->hasNLST_d == kCommandAvailabilityUnknown) { + if (FTPListToMemory2(cip, ".", &lines, "-d ", 0, (int *) 0) == kNoErr) { + if ((lines.first != NULL) && (lines.first == lines.last)) { + /* If we have only one item in the list, see if it really was + * an error message we would recognize. + */ + cp = strchr(lines.first->line, ':'); + if ((cp != NULL) && STREQ(cp, ": No such file or directory")) { + cip->hasNLST_d = kCommandNotAvailable; + } else { + cip->hasNLST_d = kCommandAvailable; + } + } else { + cip->hasNLST_d = kCommandNotAvailable; + } + } else { + cip->hasNLST_d = kCommandNotAvailable; + } + DisposeLineListContents(&lines); + } +} /* CheckForLS_d */ +#endif + + + + +static int +LsMonthNameToNum(char *cp) +{ + int mon; /* 0..11 */ + + switch (*cp++) { + case 'A': + mon = (*cp == 'u') ? 7 : 3; + break; + case 'D': + mon = 11; + break; + case 'F': + mon = 1; + break; + default: + case 'J': + if (*cp++ == 'u') + mon = (*cp == 'l') ? 6 : 5; + else + mon = 0; + break; + case 'M': + mon = (*++cp == 'r') ? 2 : 4; + break; + case 'N': + mon = 10; + break; + case 'O': + mon = 9; + break; + case 'S': + mon = 8; + } + return (mon); +} /* LsMonthNameToNum */ + + + + +static int +UnDosLine( char *const line, + const char *const curdir, + size_t curdirlen, + char *fname, + size_t fnamesize, + int *ftype, + longest_int *fsize, + time_t *ftime) +{ + char *cp; + int hour, year; + char *filestart; + char *sizestart; + struct tm ftm; + + /* + * +0123456789012345678901234567890123456789012345678901234567890123456789 +04-27-99 10:32PM 270158 Game booklet.pdf +03-11-99 10:03PM Get A3d Banner + +We also try to parse the format from CMD.EXE, which is similar: + +03/22/2001 06:23p 62,325 cls.pdf + + * + */ + cp = line; + if ( + isdigit((int) cp[0]) + && isdigit((int) cp[1]) + && ispunct((int) cp[2]) + && isdigit((int) cp[3]) + && isdigit((int) cp[4]) + && ispunct((int) cp[5]) + && isdigit((int) cp[6]) + && isdigit((int) cp[7]) + ) { + (void) memset(&ftm, 0, sizeof(struct tm)); + ftm.tm_isdst = -1; + cp[2] = '\0'; + ftm.tm_mon = atoi(cp + 0); + if (ftm.tm_mon > 0) + ftm.tm_mon -= 1; + cp[5] = '\0'; + ftm.tm_mday = atoi(cp + 3); + if ((isdigit((int) cp[8])) && (isdigit((int) cp[9]))) { + /* Four-digit year */ + cp[10] = '\0'; + year = atoi(cp + 6); + if (year > 1900) + year -= 1900; + ftm.tm_year = year; /* years since 1900 */ + cp += 11; + } else { + /* Two-digit year */ + cp[8] = '\0'; + year = atoi(cp + 6); + if (year < 98) + year += 100; + ftm.tm_year = year; /* years since 1900 */ + cp += 9; + } + + for (;;) { + if (*cp == '\0') + return (-1); + if (isdigit(*cp)) + break; + cp++; + } + + cp[2] = '\0'; + hour = atoi(cp); + if (((cp[5] == 'P') || (cp[5] == 'p')) && (hour < 12)) + hour += 12; + else if (((cp[5] == 'A') || (cp[5] == 'a')) && (hour == 12)) + hour -= 12; + ftm.tm_hour = hour; + cp[5] = '\0'; + ftm.tm_min = atoi(cp + 3); + *ftime = mktime(&ftm); + if (*ftype == (time_t) -1) + return (-1); + + cp += 6; + *ftype = '-'; + for (;;) { + if (*cp == '\0') + return (-1); + if ((*cp == '<') && (cp[1] == 'D')) { + /* found */ + *ftype = 'd'; + cp += 5; + break; /* size field will end up being empty string */ + } else if ((*cp == '<') && (cp[1] == 'J')) { + /* found + * + * Will we ever really see this? + * IIS from Win2000sp1 sends + * for FTP, but CMD.EXE prints + * . + */ + *ftype = 'd'; + cp += 10; + break; + } else if (isdigit(*cp)) { + break; + } else { + cp++; + } + } + + sizestart = cp; + for (;;) { + if (*cp == '\0') + return (-1); +#ifdef HAVE_MEMMOVE + if (*cp == ',') { + /* Yuck -- US Locale dependency */ + memmove(cp, cp + 1, strlen(cp + 1) + 1); + } +#endif + if (!isdigit(*cp)) { + *cp++ = '\0'; + break; + } + cp++; + } + + if (fsize != NULL) { +#if defined(HAVE_LONG_LONG) && defined(SCANF_LONG_LONG) + if (*ftype == 'd') + *fsize = 0; + else + (void) sscanf(sizestart, SCANF_LONG_LONG, fsize); +#elif defined(HAVE_LONG_LONG) && defined(HAVE_STRTOQ) + if (*ftype == 'd') + *fsize = 0; + else + *fsize = (longest_int) strtoq(sizestart, NULL, 0); +#else + *fsize = (longest_int) 0; + if (*ftype != 'd') { + long fsize2 = 0L; + + (void) sscanf(sizestart, "%ld", &fsize2); + *fsize = (longest_int) fsize2; + } +#endif + } + + for (;;) { + if (*cp == '\0') + return (-1); + if (!isspace(*cp)) { + break; + } + cp++; + } + + filestart = cp; + if (curdirlen == 0) { + (void) Strncpy(fname, filestart, fnamesize); + } else { + (void) Strncpy(fname, curdir, fnamesize); + (void) Strncat(fname, filestart, fnamesize); + } + + return (0); + } + return (-1); +} /* UnDosLine */ + + + + +static int +UnLslRLine( char *const line, + const char *const curdir, + size_t curdirlen, + char *fname, + size_t fnamesize, + char *linkto, + size_t linktosize, + int *ftype, + longest_int *fsize, + time_t *ftime, + time_t now, + int thisyear, + int *plugend) +{ + char *cp; + int mon = 0, dd = 0, hr = 0, min = 0, year = 0; + char *monstart, *ddstart, *hrstart, *minstart, *yearstart; + char *linktostart, *filestart = NULL; + char *sizestart; + char *pe; + struct tm ftm; + + /* + * Look for the digit just before the space + * before the month name. + * +-rw-rw---- 1 gleason sysdev 33404 Mar 24 01:29 RCmd.o +-rw-rw-r-- 1 gleason sysdevzz 1829 Jul 7 1996 README +-rw-rw-r-- 1 gleason sysdevzz 1829 Jul 7 1996 README +-rw-rw-r-- 1 gleason sysdevzz 1829 Jul 7 1996 README +-rw-rw-r-- 1 gleason sysdevzz 1829 Jul 7 1996 README + * + *------------------------------^ + * 0123456789012345 + *------plugend--------^ + * 9876543210 + * + */ + for (cp = line; *cp != '\0'; cp++) { + if ( (isdigit((int) *cp)) + && (isspace((int) cp[1])) + && (isupper((int) cp[2])) + && (islower((int) cp[3])) + /* && (islower((int) cp[4])) */ + && (isspace((int) cp[5])) + && ( +((isdigit((int) cp[6])) && (isdigit((int) cp[7]))) +|| ((isdigit((int) cp[6])) && (isspace((int) cp[7]))) +|| ((isspace((int) cp[6])) && (isdigit((int) cp[7]))) + ) + && (isspace((int) cp[8])) + ) { + monstart = cp + 2; + ddstart = cp + 6; + if ( ((isspace((int) cp[9])) || (isdigit((int) cp[9]))) + && (isdigit((int) cp[10])) + && (isdigit((int) cp[11])) + && (isdigit((int) cp[12])) + && ((isdigit((int) cp[13])) || (isspace((int) cp[13]))) + ) { + /* "Mon DD YYYY" form */ + yearstart = cp + 9; + if (isspace((int) *yearstart)) + yearstart++; + hrstart = NULL; + minstart = NULL; + filestart = cp + 15; + cp[1] = '\0'; /* end size */ + cp[5] = '\0'; /* end mon */ + cp[8] = '\0'; /* end dd */ + cp[14] = '\0'; /* end year */ + mon = LsMonthNameToNum(monstart); + dd = atoi(ddstart); + hr = 23; + min = 59; + year = atoi(yearstart); + + pe = cp; + while (isdigit((int) *pe)) + pe--; + while (isspace((int) *pe)) + pe--; + *plugend = (int) (pe - line) + 1; + break; + } else if ( /* + * Windows NT does not 0 pad. + (isdigit((int) cp[9])) && + */ + (isdigit((int) cp[10])) + && (cp[11] == ':') + && (isdigit((int) cp[12])) + && (isdigit((int) cp[13])) + ) { + /* "Mon DD HH:MM" form */ + yearstart = NULL; + hrstart = cp + 9; + minstart = cp + 12; + filestart = cp + 15; + cp[1] = '\0'; /* end size */ + cp[5] = '\0'; /* end mon */ + cp[8] = '\0'; /* end dd */ + cp[11] = '\0'; /* end hr */ + cp[14] = '\0'; /* end min */ + mon = LsMonthNameToNum(monstart); + dd = atoi(ddstart); + hr = atoi(hrstart); + min = atoi(minstart); + year = 0; + + pe = cp; + while (isdigit((int) *pe)) + pe--; + while (isspace((int) *pe)) + pe--; + *plugend = (int) (pe - line) + 1; + break; + } + } + } + + if (*cp == '\0') + return (-1); + + linktostart = strstr(filestart, " -> "); + if (linktostart != NULL) { + *linktostart = '\0'; + linktostart += 4; + (void) Strncpy(linkto, linktostart, linktosize); + } else { + *linkto = '\0'; + } + + if (curdirlen == 0) { + (void) Strncpy(fname, filestart, fnamesize); + } else { + (void) Strncpy(fname, curdir, fnamesize); + (void) Strncat(fname, filestart, fnamesize); + } + + if (ftime != NULL) { + (void) memset(&ftm, 0, sizeof(struct tm)); + ftm.tm_mon = mon; + ftm.tm_mday = dd; + ftm.tm_hour = hr; + ftm.tm_min = min; + ftm.tm_isdst = -1; + if (year == 0) { + /* We guess the year, based on what the + * current year is. We know the file + * on the remote server is either less + * than six months old or less than + * one hour into the future. + */ + ftm.tm_year = thisyear - 1900; + *ftime = mktime(&ftm); + if (*ftime == (time_t) -1) { + /* panic */ + } else if (*ftime > (now + (15552000L + 86400L))) { + --ftm.tm_year; + *ftime = mktime(&ftm); + } else if (*ftime < (now - (15552000L + 86400L))) { + ++ftm.tm_year; + *ftime = mktime(&ftm); + } + } else { + ftm.tm_year = year - 1900; + *ftime = mktime(&ftm); + } + } + + if (fsize != NULL) { + while ((cp > line) && (isdigit((int) *cp))) + --cp; + sizestart = cp + 1; +#if defined(HAVE_LONG_LONG) && defined(SCANF_LONG_LONG) + (void) sscanf(sizestart, SCANF_LONG_LONG, fsize); +#elif defined(HAVE_LONG_LONG) && defined(HAVE_STRTOQ) + *fsize = (longest_int) strtoq(sizestart, NULL, 0); +#else + { + long fsize2 = 0L; + + (void) sscanf(sizestart, "%ld", &fsize2); + *fsize = (longest_int) fsize2; + } +#endif + } + + switch (line[0]) { + case 'd': + case 'l': + *ftype = (int) line[0]; + break; + case 'b': + case 'c': + case 's': + *ftype = (int) line[0]; + return (-1); + default: + *ftype = '-'; + } + + return (0); +} /* UnLslRLine */ + + + +int +UnLslR(FileInfoListPtr filp, LineListPtr llp, int serverType) +{ + char curdir[256]; + char line[256]; + int hadblankline = 0; + int len; + size_t curdirlen = 0; + char fname[256]; + char linkto[256]; + char *cp; + longest_int fsize; + int ftype; + time_t ftime, now; + int thisyear; + struct tm *nowtm; + int rc; + LinePtr lp; + FileInfo fi; + int linesread = 0; + int linesconverted = 0; + size_t maxFileLen = 0; + size_t maxPlugLen = 0; + size_t fileLen; + int plugend; + + (void) time(&now); + nowtm = localtime(&now); + if (nowtm == NULL) + thisyear = 1970; /* should never happen */ + else + thisyear = nowtm->tm_year + 1900; + + curdir[0] = '\0'; + + InitFileInfoList(filp); + for (lp = llp->first; lp != NULL; lp = lp->next) { + len = (int) strlen(STRNCPY(line, lp->line)); + if ((line[0] == 't') && (strncmp(line, "total", 5) == 0)) { + /* total XX line? */ + if (line[len - 1] != ':') { + hadblankline = 0; + continue; + } + /* else it was a subdir named total */ + } else { + for (cp = line; ; cp++) { + if ((*cp == '\0') || (!isspace((int) *cp))) + break; + } + if (*cp == '\0') { + /* Entire line was blank. */ + /* separator line between dirs */ + hadblankline = 1; + continue; + } + } + + if ((hadblankline != 0) && (line[len - 1] == ':')) { + /* newdir */ + hadblankline = 0; + if ((line[0] == '.') && (line[1] == '/')) { + line[len - 1] = '/'; + (void) memcpy(curdir, line + 2, (size_t) len + 1 - 2); + curdirlen = (size_t) (len - 2); + } else if ((line[0] == '.') && (line[1] == '\\')) { + line[len - 1] = '\\'; + (void) memcpy(curdir, line + 2, (size_t) len + 1 - 2); + curdirlen = (size_t) (len - 2); + } else { + line[len - 1] = '/'; + (void) memcpy(curdir, line, (size_t) len + 1); + curdirlen = (size_t) len; + } + continue; + } + + linesread++; + rc = UnLslRLine(line, curdir, curdirlen, fname, sizeof(fname), linkto, sizeof(linkto), &ftype, &fsize, &ftime, now, thisyear, &plugend); + if ((rc < 0) && (serverType == kServerTypeMicrosoftFTP)) { + rc = UnDosLine(line, curdir, curdirlen, fname, sizeof(fname), &ftype, &fsize, &ftime); + if (rc == 0) { + *linkto = '\0'; + plugend = 0; + } + } + if (rc == 0) { + linesconverted++; + fileLen = strlen(fname); + if (fileLen > maxFileLen) + maxFileLen = fileLen; + fi.relnameLen = fileLen; + fi.relname = StrDup(fname); + fi.rname = NULL; + fi.lname = NULL; + fi.rlinkto = (linkto[0] == '\0') ? NULL : StrDup(linkto); + fi.mdtm = ftime; + fi.size = (longest_int) fsize; + fi.type = ftype; + if (plugend > 0) { + fi.plug = (char *) malloc((size_t) plugend + 1); + if (fi.plug != NULL) { + (void) memcpy(fi.plug, line, (size_t) plugend); + fi.plug[plugend] = '\0'; + if ((size_t) plugend > maxPlugLen) + maxPlugLen = (size_t) plugend; + } + } else { + fi.plug = (char *) malloc(32); + if (fi.plug != NULL) { + strcpy(fi.plug, "---------- 1 ftpuser ftpusers"); + fi.plug[0] = (char) ftype; + if (30 > maxPlugLen) + maxPlugLen = (size_t) 30; + } + } + (void) AddFileInfo(filp, &fi); + } + + hadblankline = 0; + } + + filp->maxFileLen = maxFileLen; + filp->maxPlugLen = maxPlugLen; + if (linesread == 0) + return (0); + return ((linesconverted > 0) ? linesconverted : (-1)); +} /* UnLslR */ + + + + +int +UnMlsT(const char *const line0, const MLstItemPtr mlip) +{ + char *cp, *val, *fact; + int ec; + size_t len; + char line[1024]; + + memset(mlip, 0, sizeof(MLstItem)); + mlip->mode = -1; + mlip->fsize = kSizeUnknown; + mlip->ftype = '-'; + mlip->ftime = kModTimeUnknown; + + len = strlen(line0); + if (len > (sizeof(line) - 1)) + return (-1); /* Line too long, sorry. */ + /* This should be re-coded so does not need to make a + * copy of the buffer; it could be done in place. + */ + memcpy(line, line0, len + 1); + + /* Skip leading whitespace. */ + for (cp = line; *cp != '\0'; cp++) { + if (! isspace(*cp)) + break; + } + + while (*cp != '\0') { + for (fact = cp; ; cp++) { + if ((*cp == '\0') || (*cp == ' ')) { + /* protocol violation */ + return (-1); + } + if (*cp == '=') { + /* End of fact name. */ + *cp++ = '\0'; + break; + } + } + for (val = cp; ; cp++) { + if (*cp == '\0') { + /* protocol violation */ + return (-1); + } + if (*cp == ' ') { + ec = ' '; + *cp++ = '\0'; + break; + } else if (*cp == ';') { + if (cp[1] == ' ') { + ec = ' '; + *cp++ = '\0'; + *cp++ = '\0'; + } else { + ec = ';'; + *cp++ = '\0'; + } + break; + } + } + if (ISTRNEQ(fact, "OS.", 3)) + fact += 3; + if (ISTREQ(fact, "type")) { + if (ISTREQ(val, "file")) { + mlip->ftype = '-'; + } else if (ISTREQ(val, "dir")) { + mlip->ftype = 'd'; + } else if (ISTREQ(val, "cdir")) { + /* not supported: current directory */ + return (-2); + } else if (ISTREQ(val, "pdir")) { + /* not supported: parent directory */ + return (-2); + } else { + /* ? */ + return (-1); + } + } else if (ISTREQ(fact, "UNIX.mode")) { + if (val[0] == '0') + sscanf(val, "%o", &mlip->mode); + else + sscanf(val, "%i", &mlip->mode); + if (mlip->mode != (-1)) + mlip->mode &= 00777; + } else if (ISTREQ(fact, "perm")) { + STRNCPY(mlip->perm, val); + } else if (ISTREQ(fact, "size")) { +#if defined(HAVE_LONG_LONG) && defined(SCANF_LONG_LONG) + (void) sscanf(val, SCANF_LONG_LONG, &mlip->fsize); +#elif defined(HAVE_LONG_LONG) && defined(HAVE_STRTOQ) + mlip->fsize = (longest_int) strtoq(val, NULL, 0); +#else + { + long fsize2 = 0L; + + (void) sscanf(val, "%ld", &fsize2); + mlip->fsize = (longest_int) fsize2; + } +#endif + } else if (ISTREQ(fact, "modify")) { + mlip->ftime = UnMDTMDate(val); + } else if (ISTREQ(fact, "UNIX.owner")) { + STRNCPY(mlip->owner, val); + } else if (ISTREQ(fact, "UNIX.group")) { + STRNCPY(mlip->group, val); + } else if (ISTREQ(fact, "UNIX.uid")) { + mlip->uid = atoi(val); + } else if (ISTREQ(fact, "UNIX.gid")) { + mlip->gid = atoi(val); + } else if (ISTREQ(fact, "perm")) { + STRNCPY(mlip->perm, val); + } + + /* End of facts? */ + if (ec == ' ') + break; + } + + len = strlen(cp); + if (len > (sizeof(mlip->fname) - 1)) { + /* Filename too long */ + return (-1); + } + memcpy(mlip->fname, cp, len); + + /* also set linkto here if used */ + + return (0); +} /* UnMlsT */ + + + + +int +UnMlsD(FileInfoListPtr filp, LineListPtr llp) +{ + MLstItem mli; + char plug[64]; + char og[32]; + int rc; + LinePtr lp; + FileInfo fi; + int linesread = 0; + int linesconverted = 0; + int linesignored = 0; + size_t maxFileLen = 0; + size_t maxPlugLen = 0; + size_t fileLen, plugLen; + int m1, m2, m3; + const char *cm1, *cm2, *cm3; + + InitFileInfoList(filp); + for (lp = llp->first; lp != NULL; lp = lp->next) { + linesread++; + rc = UnMlsT(lp->line, &mli); + if (rc == 0) { + linesconverted++; + fileLen = strlen(mli.fname); + if (fileLen > maxFileLen) + maxFileLen = fileLen; + fi.relnameLen = fileLen; + fi.relname = StrDup(mli.fname); + fi.rname = NULL; + fi.lname = NULL; + fi.rlinkto = (mli.linkto[0] == '\0') ? NULL : StrDup(mli.linkto); + fi.mdtm = mli.ftime; + fi.size = (longest_int) mli.fsize; + fi.type = mli.ftype; + plug[0] = (char) mli.ftype; + plug[1] = '\0'; + m1 = 0; + m2 = 0; + m3 = -1; + if (mli.mode != (-1)) { + m1 = (mli.mode & 00700) >> 6; + m2 = (mli.mode & 00070) >> 3; + m3 = (mli.mode & 00007); + } + if (mli.perm[0] != '\0') { + m3 = 0; + if (fi.type == 'd') { + if (strchr(mli.perm, 'e') != NULL) { + /* execute -> execute */ + m3 |= 00001; + } + if (strchr(mli.perm, 'c') != NULL) { + /* create -> write */ + m3 |= 00002; + } + if (strchr(mli.perm, 'l') != NULL) { + /* list -> read */ + m3 |= 00004; + } + } else { + if (strchr(mli.perm, 'w') != NULL) { + /* write -> write */ + m3 |= 00002; + } + if (strchr(mli.perm, 'r') != NULL) { + /* read -> read */ + m3 |= 00004; + } + } + } + if (m3 != (-1)) { + cm1 = rwx[m1]; + cm2 = rwx[m2]; + cm3 = rwx[m3]; + sprintf(plug + 1, "%s%s%s", cm1, cm2, cm3); + } + if (mli.owner[0] != '\0') { + if (mli.group[0] != '\0') { +#ifdef HAVE_SNPRINTF + snprintf(og, sizeof(og) - 1, +#else + sprintf(og, +#endif /* HAVE_SNPRINTF */ + " %-8.8s %s", + mli.owner, mli.group + ); + STRNCAT(plug, og); + } else { + STRNCAT(plug, " "); + STRNCAT(plug, mli.owner); + } + } + fi.plug = StrDup(plug); + if (fi.plug != NULL) { + plugLen = strlen(plug); + if (plugLen > maxPlugLen) + maxPlugLen = plugLen; + } + (void) AddFileInfo(filp, &fi); + } else if (rc == (-2)) { + linesignored++; + } + } + + filp->maxFileLen = maxFileLen; + filp->maxPlugLen = maxPlugLen; + if (linesread == 0) + return (0); + linesconverted += linesignored; + return ((linesconverted > 0) ? linesconverted : (-1)); +} /* UnMlsD */ + + + +#if 0 +static void +print1(FileInfoListPtr list) +{ + FileInfoPtr fip; + int i; + + for (i = 1, fip = list->first; fip != NULL; fip = fip->next, i++) + printf("%d: %s\n", i, fip->relname == NULL ? "NULL" : fip->relname); +} + + + +static void +print2(FileInfoListPtr list) +{ + FileInfoPtr fip; + int i, n; + + n = list->nFileInfos; + for (i=0; ivec[i]; + printf("%d: %s\n", i + 1, fip->relname == NULL ? "NULL" : fip->relname); + } +} + + + + +static void +SortRecursiveFileList(FileInfoListPtr files) +{ + VectorizeFileInfoList(files); + SortFileInfoList(files, 'b', '?'); + UnvectorizeFileInfoList(files); +} /* SortRecursiveFileList */ +#endif + + + + +int +FTPRemoteRecursiveFileList1(FTPCIPtr cip, char *const rdir, FileInfoListPtr files) +{ + LineList dirContents; + FileInfoList fil; + char cwd[512]; + int result; + + if ((result = FTPGetCWD(cip, cwd, sizeof(cwd))) < 0) + return (result); + + InitFileInfoList(files); + + if (rdir == NULL) + return (-1); + + if (FTPChdir(cip, rdir) < 0) { + /* Probably not a directory. + * Just add it as a plain file + * to the list. + */ + (void) ConcatFileToFileInfoList(files, rdir); + return (kNoErr); + } + + /* Paths collected must be relative. */ + if ((result = FTPListToMemory2(cip, "", &dirContents, "-lRa", 1, (int *) 0)) < 0) { + if ((result = FTPChdir(cip, cwd)) < 0) { + return (result); + } + } + + (void) UnLslR(&fil, &dirContents, cip->serverType); + DisposeLineListContents(&dirContents); + /* Could sort it to breadth-first here. */ + /* (void) SortRecursiveFileList(&fil); */ + (void) ComputeRNames(&fil, rdir, 1, 1); + (void) ConcatFileInfoList(files, &fil); + DisposeFileInfoListContents(&fil); + + if ((result = FTPChdir(cip, cwd)) < 0) { + return (result); + } + return (kNoErr); +} /* FTPRemoteRecursiveFileList1 */ + + + + +int +FTPRemoteRecursiveFileList(FTPCIPtr cip, LineListPtr fileList, FileInfoListPtr files) +{ + LinePtr filePtr, nextFilePtr; + LineList dirContents; + FileInfoList fil; + char cwd[512]; + int result; + char *rdir; + + if ((result = FTPGetCWD(cip, cwd, sizeof(cwd))) < 0) + return (result); + + InitFileInfoList(files); + + for (filePtr = fileList->first; + filePtr != NULL; + filePtr = nextFilePtr) + { + nextFilePtr = filePtr->next; + + rdir = filePtr->line; + if (rdir == NULL) + continue; + + if (FTPChdir(cip, rdir) < 0) { + /* Probably not a directory. + * Just add it as a plain file + * to the list. + */ + (void) ConcatFileToFileInfoList(files, rdir); + continue; + } + + /* Paths collected must be relative. */ + if ((result = FTPListToMemory2(cip, "", &dirContents, "-lRa", 1, (int *) 0)) < 0) { + goto goback; + } + + (void) UnLslR(&fil, &dirContents, cip->serverType); + DisposeLineListContents(&dirContents); + (void) ComputeRNames(&fil, rdir, 1, 1); + (void) ConcatFileInfoList(files, &fil); + DisposeFileInfoListContents(&fil); + +goback: + if ((result = FTPChdir(cip, cwd)) < 0) { + return (result); + } + } + return (kNoErr); +} /* FTPRemoteRecursiveFileList */ + + + +#if defined(WIN32) || defined(_WINDOWS) + +static void +Traverse(FTPCIPtr cip, char *fullpath, struct Stat *st, char *relpath, FileInfoListPtr filp) +{ + WIN32_FIND_DATA ffd; + HANDLE searchHandle; + DWORD dwErr; + char *cp, *c2; + const char *file; + FileInfo fi; + + /* Handle directory entry first. */ + if (relpath[0] != '\0') { + fi.relname = StrDup(relpath); + fi.rname = NULL; + fi.lname = StrDup(fullpath); + fi.rlinkto = NULL; + fi.plug = NULL; + fi.mdtm = st->st_mtime; + fi.size = (longest_int) st->st_size; + fi.type = 'd'; + (void) AddFileInfo(filp, &fi); + } + + cp = fullpath + strlen(fullpath); + *cp++ = LOCAL_PATH_DELIM; + strcpy(cp, "*.*"); + + c2 = relpath + strlen(relpath); + *c2++ = LOCAL_PATH_DELIM; + *c2 = '\0'; + + memset(&ffd, 0, sizeof(ffd)); + + /* "Open" the directory. */ + searchHandle = FindFirstFile(fullpath, &ffd); + if (searchHandle == INVALID_HANDLE_VALUE) { + return; + } + + for (;;) { + + file = ffd.cFileName; + if ((*file == '.') && ((file[1] == '\0') || ((file[1] == '.') && (file[2] == '\0')))) { + /* It was "." or "..", so skip it. */ + goto next; + } + + (void) strcpy(cp, file); /* append name after slash */ + (void) strcpy(c2, file); + + if (Lstat(fullpath, st) < 0) { + Error(cip, kDoPerror, "could not stat %s.\n", fullpath); + goto next; + } + + fi.relname = StrDup(relpath + (((relpath[0] == '/') || (relpath[0] == '\\')) ? 1 : 0)); + fi.rname = NULL; + fi.lname = StrDup(fullpath); + fi.mdtm = st->st_mtime; + fi.size = (longest_int) st->st_size; + fi.rlinkto = NULL; + fi.plug = NULL; + + if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { + Traverse(cip, fullpath, st, relpath, filp); + } else { + /* file */ + fi.type = '-'; + (void) AddFileInfo(filp, &fi); + } + +next: +#if _DEBUG + memset(&ffd, 0, sizeof(ffd)); +#endif + if (!FindNextFile(searchHandle, &ffd)) { + dwErr = GetLastError(); + if (dwErr != ERROR_NO_MORE_FILES) { + FindClose(searchHandle); + return; + } + break; + } + } + FindClose(searchHandle); +} // Traverse + +#else + +static void +Traverse(FTPCIPtr cip, char *fullpath, struct Stat *st, char *relpath, FileInfoListPtr filp) +{ + char *dname; + struct dirent *dirp; + mode_t m; + DIR *dp; + char *cp; + char *c2; + FileInfo fi; + + if (relpath[0] != '\0') { + fi.relname = StrDup(relpath); + fi.rname = NULL; + fi.lname = StrDup(fullpath); + fi.rlinkto = NULL; + fi.plug = NULL; + fi.mdtm = st->st_mtime; + fi.size = (longest_int) st->st_size; + fi.type = 'd'; + (void) AddFileInfo(filp, &fi); + } + + /* Handle directory entry first. */ + cp = fullpath + strlen(fullpath); + *cp++ = '/'; + *cp = '\0'; + + c2 = relpath + strlen(relpath); + *c2++ = '/'; + *c2 = '\0'; + + if ((dp = opendir(fullpath)) == NULL) { + cp[-1] = '\0'; + c2[-1] = '\0'; + Error(cip, kDoPerror, "could not opendir %s.\n", fullpath); + return; + } + + while ((dirp = readdir(dp)) != NULL) { + dname = dirp->d_name; + if ((dname[0] == '.') && ((dname[1] == '\0') || ((dname[1] == '.') && (dname[2] == '\0')))) + continue; /* skip "." and ".." directories. */ + + (void) strcpy(cp, dirp->d_name); /* append name after slash */ + (void) strcpy(c2, dirp->d_name); + if (Lstat(fullpath, st) < 0) { + Error(cip, kDoPerror, "could not stat %s.\n", fullpath); + continue; + } + + fi.relname = StrDup(relpath + (((relpath[0] == '/') || (relpath[0] == '\\')) ? 1 : 0)); + fi.rname = NULL; + fi.lname = StrDup(fullpath); + fi.mdtm = st->st_mtime; + fi.size = (longest_int) st->st_size; + fi.rlinkto = NULL; + fi.plug = NULL; + + m = st->st_mode; + if (S_ISREG(m) != 0) { + /* file */ + fi.type = '-'; + (void) AddFileInfo(filp, &fi); + } else if (S_ISDIR(m)) { + Traverse(cip, fullpath, st, relpath, filp); +#ifdef S_ISLNK + } else if (S_ISLNK(m)) { + fi.type = 'l'; + fi.rlinkto = calloc(128, 1); + if (fi.rlinkto != NULL) { + if (readlink(fullpath, fi.rlinkto, 127) < 0) { + free(fi.rlinkto); + } else { + (void) AddFileInfo(filp, &fi); + } + } +#endif /* S_ISLNK */ + } + } + cp[-1] = '\0'; + c2[-1] = '\0'; + + (void) closedir(dp); +} /* Traverse */ + +#endif + + + + + +int +FTPLocalRecursiveFileList2(FTPCIPtr cip, LineListPtr fileList, FileInfoListPtr files, int erelative) +{ + LinePtr filePtr, nextFilePtr; +#if defined(WIN32) || defined(_WINDOWS) + char fullpath[_MAX_PATH + 1]; + char relpath[_MAX_PATH + 1]; +#else + char fullpath[512]; + char relpath[512]; +#endif + struct Stat st; + FileInfo fi; + char *cp; + + InitFileInfoList(files); + + for (filePtr = fileList->first; + filePtr != NULL; + filePtr = nextFilePtr) + { + nextFilePtr = filePtr->next; + + (void) STRNCPY(fullpath, filePtr->line); /* initialize fullpath */ + if ((erelative != 0) || (strcmp(filePtr->line, ".") == 0) || (filePtr->line[0] == '\0')) + (void) STRNCPY(relpath, ""); + else if ((cp = StrRFindLocalPathDelim(filePtr->line)) == NULL) + (void) STRNCPY(relpath, filePtr->line); + else + (void) STRNCPY(relpath, cp + 1); + if (Lstat(fullpath, &st) < 0) { + Error(cip, kDoPerror, "could not stat %s.\n", fullpath); + continue; + } + + if (S_ISDIR(st.st_mode) == 0) { + fi.relname = StrDup(relpath); + fi.rname = NULL; + fi.lname = StrDup(fullpath); + fi.mdtm = st.st_mtime; + fi.size = (longest_int) st.st_size; + fi.rlinkto = NULL; + fi.plug = NULL; + fi.type = '-'; + (void) AddFileInfo(files, &fi); + continue; /* wasn't a directory */ + } + + /* Paths collected must be relative. */ + Traverse(cip, fullpath, &st, relpath, files); + } + return (kNoErr); +} /* FTPLocalRecursiveFileList */ + + + + +int +FTPLocalRecursiveFileList(FTPCIPtr cip, LineListPtr fileList, FileInfoListPtr files) +{ + return (FTPLocalRecursiveFileList2(cip, fileList, files, 0)); +} /* FTPLocalRecursiveFileList */ + + + +int +FTPRemoteGlob(FTPCIPtr cip, LineListPtr fileList, const char *pattern, int doGlob) +{ + char *cp; + const char *lsflags; + LinePtr lp; + int result; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if (fileList == NULL) + return (kErrBadParameter); + InitLineList(fileList); + + if ((pattern == NULL) || (pattern[0] == '\0')) + return (kErrBadParameter); + + /* Note that we do attempt to use glob characters even if the remote + * host isn't UNIX. Most non-UNIX remote FTP servers look for UNIX + * style wildcards. + */ + if ((doGlob == 1) && (GLOBCHARSINSTR(pattern))) { + /* Use NLST, which lists files one per line. */ + lsflags = ""; + + /* Optimize for "NLST *" case which is same as "NLST". */ + if (strcmp(pattern, "*") == 0) { + pattern = ""; + } else if (strcmp(pattern, "**") == 0) { + /* Hack; Lets you try "NLST -a" if you're daring. */ + pattern = ""; + lsflags = "-a"; + } + + if ((result = FTPListToMemory2(cip, pattern, fileList, lsflags, 0, (int *) 0)) < 0) { + if (*lsflags == '\0') + return (result); + /* Try again, without "-a" */ + lsflags = ""; + if ((result = FTPListToMemory2(cip, pattern, fileList, lsflags, 0, (int *) 0)) < 0) { + return (result); + } + } + if (fileList->first == NULL) { + cip->errNo = kErrGlobNoMatch; + return (kErrGlobNoMatch); + } + if (fileList->first == fileList->last) { +#define glberr(a) (ISTRNEQ(cp, a, strlen(a))) + /* If we have only one item in the list, see if it really was + * an error message we would recognize. + */ + cp = strchr(fileList->first->line, ':'); + if (cp != NULL) { + if (glberr(": No such file or directory")) { + (void) RemoveLine(fileList, fileList->first); + cip->errNo = kErrGlobFailed; + return (kErrGlobFailed); + } else if (glberr(": No match")) { + cip->errNo = kErrGlobNoMatch; + return (kErrGlobNoMatch); + } + } + } + RemoteGlobCollapse(pattern, fileList); + for (lp=fileList->first; lp != NULL; lp = lp->next) + PrintF(cip, " Rglob [%s]\n", lp->line); + } else { + /* Or, if there were no globbing characters in 'pattern', then the + * pattern is really just a filename. So for this case the + * file list is really just a single file. + */ + fileList->first = fileList->last = NULL; + (void) AddLine(fileList, pattern); + } + return (kNoErr); +} /* FTPRemoteGlob */ + + + + +/* This does "tilde-expansion." Examples: + * ~/pub --> /usr/gleason/pub + * ~pdietz/junk --> /usr/pdietz/junk + */ +static void +ExpandTilde(char *pattern, size_t siz) +{ + string pat; + char *cp, *rest, *firstent; +#if defined(WIN32) || defined(_WINDOWS) +#else + struct passwd *pw; +#endif + string hdir; + + if ((pattern[0] == '~') && + (isalnum((int) pattern[1]) || IsLocalPathDelim(pattern[1]) || (pattern[1] == '\0'))) { + (void) STRNCPY(pat, pattern); + if ((cp = StrFindLocalPathDelim(pat)) != NULL) { + *cp = 0; + rest = cp + 1; /* Remember stuff after the ~/ part. */ + } else { + rest = NULL; /* Was just a ~ or ~username. */ + } + if (pat[1] == '\0') { + /* Was just a ~ or ~/rest type. */ + GetHomeDir(hdir, sizeof(hdir)); + firstent = hdir; + } else { +#if defined(WIN32) || defined(_WINDOWS) + return; +#else + /* Was just a ~username or ~username/rest type. */ + pw = getpwnam(pat + 1); + if (pw != NULL) + firstent = pw->pw_dir; + else + return; /* Bad user -- leave it alone. */ +#endif + } + + (void) Strncpy(pattern, firstent, siz); + if (rest != NULL) { + (void) Strncat(pattern, LOCAL_PATH_DELIM_STR, siz); + (void) Strncat(pattern, rest, siz); + } + } +} /* ExpandTilde */ + + + + + +#if defined(WIN32) || defined(_WINDOWS) + +static int +WinLocalGlob(FTPCIPtr cip, LineListPtr fileList, const char *const srcpat) +{ + char pattern[_MAX_PATH]; + WIN32_FIND_DATA ffd; + HANDLE searchHandle; + DWORD dwErr; + char *cp; + const char *file; + int result; + + STRNCPY(pattern, srcpat); + + /* Get rid of trailing slashes. */ + cp = pattern + strlen(pattern) - 1; + while ((cp >= pattern) && IsLocalPathDelim(*cp)) + *cp-- = '\0'; + + memset(&ffd, 0, sizeof(ffd)); + + /* "Open" the directory. */ + searchHandle = FindFirstFile(pattern, &ffd); + if (searchHandle == INVALID_HANDLE_VALUE) { + dwErr = GetLastError(); + return ((dwErr == 0) ? 0 : -1); + } + + /* Get rid of basename. */ + cp = StrRFindLocalPathDelim(pattern); + if (cp == NULL) + cp = pattern; + else + cp++; + *cp = '\0'; + + for (result = 0;;) { + file = ffd.cFileName; + if ((file[0] == '.') && ((file[1] == '\0') || ((file[1] == '.') && (file[2] == '\0')))) { + /* skip */ + } else { + Strncpy(cp, ffd.cFileName, sizeof(pattern) - (cp - pattern)); + PrintF(cip, " Lglob [%s]\n", pattern); + (void) AddLine(fileList, pattern); + } + + if (!FindNextFile(searchHandle, &ffd)) { + dwErr = GetLastError(); + if (dwErr != ERROR_NO_MORE_FILES) { + result = ((dwErr == 0) ? 0 : -1); + } + break; + } + } + + return (result); +} // WinLocalGlob + +#else + +static int +LazyUnixLocalGlob(FTPCIPtr cip, LineListPtr fileList, const char *const pattern) +{ + string cmd; + longstring gfile; + FILE *fp; + FTPSigProc sp; + + /* Do it the easy way and have the shell do the dirty + * work for us. + */ +#ifdef HAVE_SNPRINTF + (void) snprintf(cmd, sizeof(cmd) - 1, "%s -c \"%s %s %s\"", "/bin/sh", "/bin/ls", + "-d", pattern); + cmd[sizeof(cmd) - 1] = '\0'; +#else + (void) sprintf(cmd, "%s -c \"%s %s %s\"", "/bin/sh", "/bin/ls", + "-d", pattern); +#endif + + fp = (FILE *) popen(cmd, "r"); + if (fp == NULL) { + Error(cip, kDoPerror, "Could not Lglob: [%s]\n", cmd); + cip->errNo = kErrGlobFailed; + return (kErrGlobFailed); + } + sp = NcSignal(SIGPIPE, (FTPSigProc) SIG_IGN); + while (FGets(gfile, sizeof(gfile), (FILE *) fp) != NULL) { + PrintF(cip, " Lglob [%s]\n", gfile); + (void) AddLine(fileList, gfile); + } + (void) pclose(fp); + (void) NcSignal(SIGPIPE, sp); + return (kNoErr); +} /* LazyUnixLocalGlob */ + +#endif + + + + +int +FTPLocalGlob(FTPCIPtr cip, LineListPtr fileList, const char *pattern, int doGlob) +{ + string pattern2; + int result; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if (fileList == NULL) + return (kErrBadParameter); + InitLineList(fileList); + + if ((pattern == NULL) || (pattern[0] == '\0')) + return (kErrBadParameter); + + (void) STRNCPY(pattern2, pattern); /* Don't nuke the original. */ + + /* Pre-process for ~'s. */ + ExpandTilde(pattern2, sizeof(pattern2)); + InitLineList(fileList); + result = kNoErr; + + if ((doGlob == 1) && (GLOBCHARSINSTR(pattern2))) { +#if defined(WIN32) || defined(_WINDOWS) + result = WinLocalGlob(cip, fileList, pattern2); +#else + result = LazyUnixLocalGlob(cip, fileList, pattern2); +#endif + } else { + /* Or, if there were no globbing characters in 'pattern', then + * the pattern is really just a single pathname. + */ + (void) AddLine(fileList, pattern2); + } + + return (result); +} /* FTPLocalGlob */ + + + + +static int +FTPFtwL2(const FTPCIPtr cip, char *dir, char *end, size_t dirsize, FTPFtwProc proc, int maxdepth) +{ + LineList fileList; + LinePtr filePtr; + char *file, *cp; + int result; + + if (maxdepth <= 0) { + result = cip->errNo = kErrRecursionLimitReached; + return (result); + } + + result = FTPRemoteGlob(cip, &fileList, "**", kGlobYes); + if (result != kNoErr) { + if (result == kErrGlobNoMatch) + result = kNoErr; /* empty directory is okay. */ + return (result); + } + + for (filePtr = fileList.first; + filePtr != NULL; + filePtr = filePtr->next) + { + file = filePtr->line; + if (file == NULL) { + cip->errNo = kErrBadLineList; + break; + } + + if ((file[0] == '.') && ((file[1] == '\0') || ((file[1] == '.') && (file[2] == '\0')))) + continue; /* Skip . and .. */ + + result = FTPIsDir(cip, file); + if (result < 0) { + /* error */ + /* could be just a stat error, so continue */ + continue; + } else if (result == 1) { + /* directory */ + cp = Strnpcat(dir, file, dirsize); + result = (*proc)(cip, dir, kFtwDir); + if (result != kNoErr) + break; + + if ((strchr(dir, '/') == NULL) && (strrchr(dir, '\\') != NULL)) + *cp++ = '\\'; + else + *cp++ = '/'; + *cp = '\0'; + + result = FTPChdir(cip, file); + if (result == kNoErr) { + result = FTPFtwL2(cip, dir, cp, dirsize, proc, maxdepth - 1); + if (result != kNoErr) + break; + if (FTPChdir(cip, "..") < 0) { + result = kErrCannotGoToPrevDir; + cip->errNo = kErrCannotGoToPrevDir; + break; + } + } + + *end = '\0'; + if (result != 0) + break; + } else { + /* file */ + cp = Strnpcat(dir, file, dirsize); + result = (*proc)(cip, dir, kFtwFile); + *end = '\0'; + if (result != 0) + break; + } + } + DisposeLineListContents(&fileList); + + return (result); +} /* FTPFtwL2 */ + + + +int +FTPFtw(const FTPCIPtr cip, const char *const dir, FTPFtwProc proc, int maxdepth) +{ + int result, result2; + char *cp; + char savedcwd[1024]; + char curcwd[2048]; + + result = FTPIsDir(cip, dir); + if (result < 0) { + /* error */ + return result; + } else if (result == 0) { + result = cip->errNo = kErrNotADirectory; + return (result); + } + + /* Preserve old working directory. */ + (void) FTPGetCWD(cip, savedcwd, sizeof(savedcwd)); + + result = FTPChdir(cip, dir); + if (result != kNoErr) { + return (result); + } + + /* Get full working directory we just changed to. */ + result = FTPGetCWD(cip, curcwd, sizeof(curcwd) - 3); + if (result != kNoErr) { + if (FTPChdir(cip, savedcwd) != kNoErr) { + result = kErrCannotGoToPrevDir; + cip->errNo = kErrCannotGoToPrevDir; + } + return (result); + } + + result2 = (*proc)(cip, curcwd, kFtwDir); + if (result2 == kNoErr) { + cp = curcwd + strlen(curcwd); + + if ((strchr(curcwd, '/') == NULL) && (strrchr(curcwd, '\\') != NULL)) + *cp++ = '\\'; + else + *cp++ = '/'; + *cp = '\0'; + result = FTPFtwL2(cip, curcwd, cp, sizeof(curcwd), proc, maxdepth - 1); + } + + + if (FTPChdir(cip, savedcwd) != kNoErr) { + /* Could not cd back to the original user directory -- bad. */ + result = kErrCannotGoToPrevDir; + cip->errNo = kErrCannotGoToPrevDir; + return (result); + } + + if ((result2 != kNoErr) && (result == kNoErr)) + result = result2; + + return (result); +} /* FTPFtw */ + +/* eof */ diff --git a/reactos/apps/utils/net/ncftp/libncftp/io.c b/reactos/apps/utils/net/ncftp/libncftp/io.c new file mode 100644 index 00000000000..3e85bafd850 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/io.c @@ -0,0 +1,2824 @@ +/* io.c + * + * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft. + * All rights reserved. + * + */ + +#include "syshdrs.h" + +static int gGotBrokenData = 0; + +#if defined(WIN32) || defined(_WINDOWS) +# define ASCII_TRANSLATION 0 +#endif + +#ifndef ASCII_TRANSLATION +# define ASCII_TRANSLATION 1 +#endif + +#if !defined(NO_SIGNALS) && (USE_SIO || !defined(SIGALRM) || !defined(SIGPIPE) || !defined(SIGINT)) +# define NO_SIGNALS 1 +#endif + +#ifndef NO_SIGNALS + +#ifdef HAVE_SIGSETJMP +static sigjmp_buf gBrokenDataJmp; +#else +static jmp_buf gBrokenDataJmp; +#endif /* HAVE_SIGSETJMP */ +static int gCanBrokenDataJmp = 0; + +#endif /* NO_SIGNALS */ + + +#ifndef O_BINARY + /* Needed for platforms using different EOLN sequence (i.e. DOS) */ +# ifdef _O_BINARY +# define O_BINARY _O_BINARY +# else +# define O_BINARY 0 +# endif +#endif + +static int WaitForRemoteInput(const FTPCIPtr cip); +static int WaitForRemoteOutput(const FTPCIPtr cip); + + +#ifndef NO_SIGNALS + +static void +BrokenData(int signum) +{ + gGotBrokenData = signum; + if (gCanBrokenDataJmp != 0) { + gCanBrokenDataJmp = 0; +#ifdef HAVE_SIGSETJMP + siglongjmp(gBrokenDataJmp, 1); +#else + longjmp(gBrokenDataJmp, 1); +#endif /* HAVE_SIGSETJMP */ + } +} /* BrokenData */ + +#endif /* NO_SIGNALS */ + + + + +void +FTPInitIOTimer(const FTPCIPtr cip) +{ + cip->bytesTransferred = (longest_int) 0; + cip->expectedSize = kSizeUnknown; + cip->mdtm = kModTimeUnknown; + cip->rname = NULL; + cip->lname = NULL; + cip->kBytesPerSec = -1.0; + cip->percentCompleted = -1.0; + cip->sec = -1.0; + cip->secLeft = -1.0; + cip->nextProgressUpdate = 0; + cip->stalled = 0; + cip->dataTimedOut = 0; + cip->useProgressMeter = 1; + (void) gettimeofday(&cip->t0, NULL); +} /* FTPInitIOTimer */ + + + + +void +FTPStartIOTimer(const FTPCIPtr cip) +{ + (void) gettimeofday(&cip->t0, NULL); + if (cip->progress != (FTPProgressMeterProc) 0) + (*cip->progress)(cip, kPrInitMsg); +} /* FTPStartIOTimer */ + + + + +void +FTPUpdateIOTimer(const FTPCIPtr cip) +{ + double sec; + struct timeval *t0, t1; + time_t now; + + (void) time(&now); + if (now < cip->nextProgressUpdate) + return; + now += 1; + cip->nextProgressUpdate = now; + + (void) gettimeofday(&t1, NULL); + t0 = &cip->t0; + + if (t0->tv_usec > t1.tv_usec) { + t1.tv_usec += 1000000; + t1.tv_sec--; + } + sec = ((double) (t1.tv_usec - t0->tv_usec) * 0.000001) + + (t1.tv_sec - t0->tv_sec); + if (sec > 0.0) { + cip->kBytesPerSec = ((double) cip->bytesTransferred) / (1024.0 * sec); + } else { + cip->kBytesPerSec = -1.0; + } + if (cip->expectedSize == kSizeUnknown) { + cip->percentCompleted = -1.0; + cip->secLeft = -1.0; + } else if (cip->expectedSize <= 0) { + cip->percentCompleted = 100.0; + cip->secLeft = 0.0; + } else { + cip->percentCompleted = ((double) (100.0 * (cip->bytesTransferred + cip->startPoint))) / ((double) cip->expectedSize); + if (cip->percentCompleted >= 100.0) { + cip->percentCompleted = 100.0; + cip->secLeft = 0.0; + } else if (cip->percentCompleted <= 0.0) { + cip->secLeft = 999.0; + } + if (cip->kBytesPerSec > 0.0) { + cip->secLeft = ((cip->expectedSize - cip->bytesTransferred - cip->startPoint) / 1024.0) / cip->kBytesPerSec; + if (cip->secLeft < 0.0) + cip->secLeft = 0.0; + } + } + cip->sec = sec; + if ((cip->progress != (FTPProgressMeterProc) 0) && (cip->useProgressMeter != 0)) + (*cip->progress)(cip, kPrUpdateMsg); +} /* FTPUpdateIOTimer */ + + + + +void +FTPStopIOTimer(const FTPCIPtr cip) +{ + cip->nextProgressUpdate = 0; /* force last update */ + FTPUpdateIOTimer(cip); + if (cip->progress != (FTPProgressMeterProc) 0) + (*cip->progress)(cip, kPrEndMsg); +} /* FTPStopIOTimer */ + + + + +/* This isn't too useful -- it mostly serves as an example so you can write + * your own function to do what you need to do with the listing. + */ +int +FTPList(const FTPCIPtr cip, const int outfd, const int longMode, const char *const lsflag) +{ + const char *cmd; + char line[512]; + char secondaryBuf[768]; +#ifndef NO_SIGNALS + char *secBufPtr, *secBufLimit; + int nread; + volatile int result; +#else /* NO_SIGNALS */ + SReadlineInfo lsSrl; + int result; +#endif /* NO_SIGNALS */ + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + cmd = (longMode != 0) ? "LIST" : "NLST"; + if ((lsflag == NULL) || (lsflag[0] == '\0')) { + result = FTPStartDataCmd(cip, kNetReading, kTypeAscii, (longest_int) 0, "%s", cmd); + } else { + result = FTPStartDataCmd(cip, kNetReading, kTypeAscii, (longest_int) 0, "%s %s", cmd, lsflag); + } + + +#ifdef NO_SIGNALS + + if (result == 0) { + if (InitSReadlineInfo(&lsSrl, cip->dataSocket, secondaryBuf, sizeof(secondaryBuf), (int) cip->xferTimeout, 1) < 0) { + /* Not really fdopen, but close in what we're trying to do. */ + result = kErrFdopenR; + cip->errNo = kErrFdopenR; + Error(cip, kDoPerror, "Could not fdopen.\n"); + return (result); + } + + for (;;) { + result = SReadline(&lsSrl, line, sizeof(line) - 2); + if (result == kTimeoutErr) { + /* timeout */ + Error(cip, kDontPerror, "Could not directory listing data -- timed out.\n"); + cip->errNo = kErrDataTimedOut; + return (cip->errNo); + } else if (result == 0) { + /* end of listing -- done */ + cip->numListings++; + break; + } else if (result < 0) { + /* error */ + Error(cip, kDoPerror, "Could not read directory listing data"); + result = kErrLISTFailed; + cip->errNo = kErrLISTFailed; + break; + } + + (void) write(outfd, line, strlen(line)); + } + + DisposeSReadlineInfo(&lsSrl); + if (FTPEndDataCmd(cip, 1) < 0) { + result = kErrLISTFailed; + cip->errNo = kErrLISTFailed; + } + } else if (result == kErrGeneric) { + result = kErrLISTFailed; + cip->errNo = kErrLISTFailed; + } + + +#else /* NO_SIGNALS */ + + if (result == 0) { + /* This line sets the buffer pointer so that the first thing + * BufferGets will do is reset and fill the buffer using + * real I/O. + */ + secBufPtr = secondaryBuf + sizeof(secondaryBuf); + secBufLimit = (char *) 0; + + for (;;) { + if (cip->xferTimeout > 0) + (void) alarm(cip->xferTimeout); + nread = BufferGets(line, sizeof(line), cip->dataSocket, secondaryBuf, &secBufPtr, &secBufLimit, sizeof(secondaryBuf)); + if (nread <= 0) { + if (nread < 0) + break; + } else { + cip->bytesTransferred += (longest_int) nread; + (void) STRNCAT(line, "\n"); + (void) write(outfd, line, strlen(line)); + } + } + if (cip->xferTimeout > 0) + (void) alarm(0); + result = FTPEndDataCmd(cip, 1); + if (result < 0) { + result = kErrLISTFailed; + cip->errNo = kErrLISTFailed; + } + result = kNoErr; + cip->numListings++; + } else if (result == kErrGeneric) { + result = kErrLISTFailed; + cip->errNo = kErrLISTFailed; + } +#endif /* NO_SIGNALS */ + return (result); +} /* FTPList */ + + + + +static void +FTPRequestMlsOptions(const FTPCIPtr cip) +{ + int f; + char optstr[128]; + size_t optstrlen; + + if (cip->usedMLS == 0) { + /* First MLSD/MLST ? */ + cip->usedMLS = 1; + + f = cip->mlsFeatures & kPreferredMlsOpts; + optstr[0] = '\0'; + + /* TYPE */ + if ((f & kMlsOptType) != 0) { + STRNCAT(optstr, "type;"); + } + + /* SIZE */ + if ((f & kMlsOptSize) != 0) { + STRNCAT(optstr, "size;"); + } + + /* MODTIME */ + if ((f & kMlsOptModify) != 0) { + STRNCAT(optstr, "modify;"); + } + + /* MODE */ + if ((f & kMlsOptUNIXmode) != 0) { + STRNCAT(optstr, "UNIX.mode;"); + } + + /* PERM */ + if ((f & kMlsOptPerm) != 0) { + STRNCAT(optstr, "perm;"); + } + + /* OWNER */ + if ((f & kMlsOptUNIXowner) != 0) { + STRNCAT(optstr, "UNIX.owner;"); + } + + /* UID */ + if ((f & kMlsOptUNIXuid) != 0) { + STRNCAT(optstr, "UNIX.uid;"); + } + + /* GROUP */ + if ((f & kMlsOptUNIXgroup) != 0) { + STRNCAT(optstr, "UNIX.group;"); + } + + /* GID */ + if ((f & kMlsOptUNIXgid) != 0) { + STRNCAT(optstr, "UNIX.gid;"); + } + + /* UNIQUE */ + if ((f & kMlsOptUnique) != 0) { + STRNCAT(optstr, "unique;"); + } + + /* Tell the server what we prefer. */ + optstrlen = strlen(optstr); + if (optstrlen > 0) { + if (optstr[optstrlen - 1] == ';') + optstr[optstrlen - 1] = '\0'; + (void) FTPCmd(cip, "OPTS MLST %s", optstr); + } + } +} /* FTPRequestMlsOptions */ + + + + +int +FTPListToMemory2(const FTPCIPtr cip, const char *const pattern, const LineListPtr llines, const char *const lsflags, const int blankLines, int *const tryMLSD) +{ + char secondaryBuf[768]; + char line[512]; + char lsflags1[128]; + const char *command = "NLST"; + const char *scp; + char *dcp, *lim; +#ifndef NO_SIGNALS + char *secBufPtr, *secBufLimit; + volatile FTPSigProc osigpipe; + volatile FTPCIPtr vcip; + int sj; + int nread; + volatile int result; +#else /* NO_SIGNALS */ + SReadlineInfo lsSrl; + int result; +#endif /* NO_SIGNALS */ + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if ((llines == NULL) || (pattern == NULL) || (lsflags == NULL)) + return (kErrBadParameter); + + if ((tryMLSD != (int *) 0) && (*tryMLSD != 0) && (cip->hasMLSD == kCommandAvailable)) { + command = "MLSD"; + if ((lsflags[0] == '-') && (strchr(lsflags, 'd') != NULL) && (cip->hasMLST == kCommandAvailable)) + command = "MLST"; + lsflags1[0] = '\0'; + FTPRequestMlsOptions(cip); + } else { + /* Not using MLSD. */ + if (tryMLSD != (int *) 0) + *tryMLSD = 0; + if (lsflags[0] == '-') { + /* See if we should use LIST instead. */ + scp = lsflags + 1; + dcp = lsflags1; + lim = lsflags1 + sizeof(lsflags1) - 2; + for (; *scp != '\0'; scp++) { + if (*scp == 'l') { + /* do not add the 'l' */ + command = "LIST"; + } else if (dcp < lim) { + if (dcp == lsflags1) + *dcp++ = '-'; + *dcp++ = *scp; + } + } + *dcp = '\0'; + } else { + (void) STRNCPY(lsflags1, lsflags); + } + } + + InitLineList(llines); + + result = FTPStartDataCmd( + cip, + kNetReading, + kTypeAscii, + (longest_int) 0, + "%s%s%s%s%s", + command, + (lsflags1[0] == '\0') ? "" : " ", + lsflags1, + (pattern[0] == '\0') ? "" : " ", + pattern + ); + +#ifdef NO_SIGNALS + + if (result == 0) { + if (InitSReadlineInfo(&lsSrl, cip->dataSocket, secondaryBuf, sizeof(secondaryBuf), (int) cip->xferTimeout, 1) < 0) { + /* Not really fdopen, but close in what we're trying to do. */ + result = kErrFdopenR; + cip->errNo = kErrFdopenR; + Error(cip, kDoPerror, "Could not fdopen.\n"); + return (result); + } + + for (;;) { + result = SReadline(&lsSrl, line, sizeof(line) - 1); + if (result == kTimeoutErr) { + /* timeout */ + Error(cip, kDontPerror, "Could not directory listing data -- timed out.\n"); + cip->errNo = kErrDataTimedOut; + return (cip->errNo); + } else if (result == 0) { + /* end of listing -- done */ + cip->numListings++; + break; + } else if (result < 0) { + /* error */ + Error(cip, kDoPerror, "Could not read directory listing data"); + result = kErrLISTFailed; + cip->errNo = kErrLISTFailed; + break; + } + + if (line[result - 1] == '\n') + line[result - 1] = '\0'; + + if ((blankLines == 0) && (result <= 1)) + continue; + + /* Valid directory listing line of output */ + if ((line[0] == '.') && ((line[1] == '\0') || ((line[1] == '.') && ((line[2] == '\0') || (iscntrl(line[2])))))) + continue; /* Skip . and .. */ + + (void) AddLine(llines, line); + } + + DisposeSReadlineInfo(&lsSrl); + if (FTPEndDataCmd(cip, 1) < 0) { + result = kErrLISTFailed; + cip->errNo = kErrLISTFailed; + } + } else if (result == kErrGeneric) { + result = kErrLISTFailed; + cip->errNo = kErrLISTFailed; + } + + +#else /* NO_SIGNALS */ + vcip = cip; + osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenData); + + gGotBrokenData = 0; + gCanBrokenDataJmp = 0; + +#ifdef HAVE_SIGSETJMP + sj = sigsetjmp(gBrokenDataJmp, 1); +#else + sj = setjmp(gBrokenDataJmp); +#endif /* HAVE_SIGSETJMP */ + + if (sj != 0) { + (void) signal(SIGPIPE, (FTPSigProc) osigpipe); + FTPShutdownHost(vcip); + vcip->errNo = kErrRemoteHostClosedConnection; + return(vcip->errNo); + } + gCanBrokenDataJmp = 1; + + if (result == 0) { + /* This line sets the buffer pointer so that the first thing + * BufferGets will do is reset and fill the buffer using + * real I/O. + */ + secBufPtr = secondaryBuf + sizeof(secondaryBuf); + secBufLimit = (char *) 0; + memset(secondaryBuf, 0, sizeof(secondaryBuf)); + + for (;;) { + memset(line, 0, sizeof(line)); + if (cip->xferTimeout > 0) + (void) alarm(cip->xferTimeout); + nread = BufferGets(line, sizeof(line), cip->dataSocket, secondaryBuf, &secBufPtr, &secBufLimit, sizeof(secondaryBuf)); + if (nread <= 0) { + if (nread < 0) + break; + if (blankLines != 0) + (void) AddLine(llines, line); + } else { + cip->bytesTransferred += (longest_int) nread; + + if ((line[0] == '.') && ((line[1] == '\0') || ((line[1] == '.') && ((line[2] == '\0') || (iscntrl(line[2])))))) + continue; /* Skip . and .. */ + + (void) AddLine(llines, line); + } + } + if (cip->xferTimeout > 0) + (void) alarm(0); + result = FTPEndDataCmd(cip, 1); + if (result < 0) { + result = kErrLISTFailed; + cip->errNo = kErrLISTFailed; + } + result = kNoErr; + cip->numListings++; + } else if (result == kErrGeneric) { + result = kErrLISTFailed; + cip->errNo = kErrLISTFailed; + } + (void) signal(SIGPIPE, (FTPSigProc) osigpipe); +#endif /* NO_SIGNALS */ + return (result); +} /* FTPListToMemory2 */ + + + + +static void +AutomaticallyUseASCIIModeDependingOnExtension(const FTPCIPtr cip, const char *const pathName, int *const xtype) +{ + if ((*xtype == kTypeBinary) && (cip->asciiFilenameExtensions != NULL)) { + if (FilenameExtensionIndicatesASCII(pathName, cip->asciiFilenameExtensions)) { + /* Matched -- send this file in ASCII mode + * instead of binary since it's extension + * appears to be that of a text file. + */ + *xtype = kTypeAscii; + } + } +} /* AutomaticallyUseASCIIModeDependingOnExtension */ + + + + +/* The purpose of this is to provide updates for the progress meters + * during lags. Return zero if the operation timed-out. + */ +static int +WaitForRemoteOutput(const FTPCIPtr cip) +{ + fd_set ss, ss2; + struct timeval tv; + int result; + int fd; + int wsecs; + int xferTimeout; + int ocancelXfer; + + xferTimeout = cip->xferTimeout; + if (xferTimeout < 1) + return (1); + + fd = cip->dataSocket; + if (fd < 0) + return (1); + + ocancelXfer = cip->cancelXfer; + wsecs = 0; + cip->stalled = 0; + + while ((xferTimeout <= 0) || (wsecs < xferTimeout)) { + if ((cip->cancelXfer != 0) && (ocancelXfer == 0)) { + /* leave cip->stalled -- could have been stalled and then canceled. */ + return (1); + } + FD_ZERO(&ss); + FD_SET(fd, &ss); + ss2 = ss; + tv.tv_sec = 1; + tv.tv_usec = 0; + result = select(fd + 1, NULL, SELECT_TYPE_ARG234 &ss, SELECT_TYPE_ARG234 &ss2, &tv); + if (result == 1) { + /* ready */ + cip->stalled = 0; + return (1); + } else if (result < 0) { + if (errno != EINTR) { + perror("select"); + cip->stalled = 0; + return (1); + } + } else { + wsecs++; + cip->stalled = wsecs; + } + FTPUpdateIOTimer(cip); + } + +#if !defined(NO_SIGNALS) + /* Shouldn't get here -- alarm() should have + * went off by now. + */ + (void) kill(getpid(), SIGALRM); +#endif /* NO_SIGNALS */ + + cip->dataTimedOut = 1; + return (0); /* timed-out */ +} /* WaitForRemoteOutput */ + + + + +static int +FTPPutOneF( + const FTPCIPtr cip, + const char *const file, + const char *volatile dstfile, + int xtype, + const int fdtouse, + const int appendflag, + const char *volatile tmppfx, + const char *volatile tmpsfx, + const int resumeflag, + const int deleteflag, + const ConfirmResumeUploadProc resumeProc) +{ + char *buf, *cp; + const char *cmd; + const char *odstfile; + size_t bufSize; + size_t l; + int tmpResult, result; + int nread, nwrote; + volatile int fd; + char dstfile2[512]; +#if ASCII_TRANSLATION + char *src, *srclim, *dst; + int ntowrite; + char inbuf[256]; +#endif + int fstatrc, statrc; + longest_int startPoint = 0; + struct Stat st; + time_t mdtm; +#if !defined(NO_SIGNALS) + int sj; + volatile FTPSigProc osigpipe; + volatile FTPCIPtr vcip; + volatile int vfd, vfdtouse; +#endif /* NO_SIGNALS */ + volatile int vzaction; + int zaction = kConfirmResumeProcSaidBestGuess; + + if (cip->buf == NULL) { + Error(cip, kDoPerror, "Transfer buffer not allocated.\n"); + cip->errNo = kErrNoBuf; + return (cip->errNo); + } + + cip->usingTAR = 0; + if (fdtouse < 0) { + fd = Open(file, O_RDONLY|O_BINARY, 0); + if (fd < 0) { + Error(cip, kDoPerror, "Cannot open local file %s for reading.\n", file); + cip->errNo = kErrOpenFailed; + return (cip->errNo); + } + } else { + fd = fdtouse; + } + + fstatrc = Fstat(fd, &st); + if ((fstatrc == 0) && (S_ISDIR(st.st_mode))) { + if (fdtouse < 0) { + (void) close(fd); + } + Error(cip, kDontPerror, "%s is a directory.\n", (file != NULL) ? file : "that"); + cip->errNo = kErrOpenFailed; + return (cip->errNo); + } + + /* For Put, we can't recover very well if it turns out restart + * didn't work, so check beforehand. + */ + if (cip->hasREST == kCommandAvailabilityUnknown) { + (void) FTPSetTransferType(cip, kTypeBinary); + if (SetStartOffset(cip, (longest_int) 1) == kNoErr) { + /* Now revert -- we still may not end up + * doing it. + */ + SetStartOffset(cip, (longest_int) -1); + } + } + + if (fdtouse < 0) { + AutomaticallyUseASCIIModeDependingOnExtension(cip, dstfile, &xtype); + (void) FTPFileSizeAndModificationTime(cip, dstfile, &startPoint, xtype, &mdtm); + + if (appendflag == kAppendYes) { + zaction = kConfirmResumeProcSaidAppend; + } else if ( + (cip->hasREST == kCommandNotAvailable) || + (xtype != kTypeBinary) || + (fstatrc < 0) + ) { + zaction = kConfirmResumeProcSaidOverwrite; + } else if (resumeflag == kResumeYes) { + zaction = kConfirmResumeProcSaidBestGuess; + } else { + zaction = kConfirmResumeProcSaidOverwrite; + } + + statrc = -1; + if ((mdtm != kModTimeUnknown) || (startPoint != kSizeUnknown)) { + /* Then we know the file exists. We will + * ask the user what to do, if possible, below. + */ + statrc = 0; + } else if ((resumeProc != NoConfirmResumeUploadProc) && (cip->hasMDTM != kCommandAvailable) && (cip->hasSIZE != kCommandAvailable)) { + /* We already checked if the file had a filesize + * or timestamp above, but if the server indicated + * it did not support querying those directly, + * we now need to try to determine if the file + * exists in a few other ways. + */ + statrc = FTPFileExists2(cip, dstfile, 0, 0, 0, 1, 1); + } + + if ( + (resumeProc != NoConfirmResumeUploadProc) && + (statrc == 0) + ) { + zaction = (*resumeProc)(file, (longest_int) st.st_size, st.st_mtime, &dstfile, startPoint, mdtm, &startPoint); + } + + if (zaction == kConfirmResumeProcSaidCancel) { + /* User wants to cancel this file and any + * remaining in batch. + */ + cip->errNo = kErrUserCanceled; + return (cip->errNo); + } + + if (zaction == kConfirmResumeProcSaidBestGuess) { + if ((mdtm != kModTimeUnknown) && (st.st_mtime > (mdtm + 1))) { + /* Local file is newer than remote, + * overwrite the remote file instead + * of trying to resume it. + * + * Note: Add one second fudge factor + * for Windows' file timestamps being + * imprecise to one second. + */ + zaction = kConfirmResumeProcSaidOverwrite; + } else if ((longest_int) st.st_size == startPoint) { + /* Already sent file, done. */ + zaction = kConfirmResumeProcSaidSkip; + } else if ((startPoint != kSizeUnknown) && ((longest_int) st.st_size > startPoint)) { + zaction = kConfirmResumeProcSaidResume; + } else { + zaction = kConfirmResumeProcSaidOverwrite; + } + } + + if (zaction == kConfirmResumeProcSaidSkip) { + /* Nothing done, but not an error. */ + if (fdtouse < 0) { + (void) close(fd); + } + if (deleteflag == kDeleteYes) { + if (unlink(file) < 0) { + cip->errNo = kErrLocalDeleteFailed; + return (cip->errNo); + } + } + return (kNoErr); + } else if (zaction == kConfirmResumeProcSaidResume) { + /* Resume; proc set the startPoint. */ + if ((longest_int) st.st_size == startPoint) { + /* Already sent file, done. */ + if (fdtouse < 0) { + (void) close(fd); + } + + if (deleteflag == kDeleteYes) { + if (unlink(file) < 0) { + cip->errNo = kErrLocalDeleteFailed; + return (cip->errNo); + } + } + return (kNoErr); + } else if (Lseek(fd, (off_t) startPoint, SEEK_SET) != (off_t) -1) { + cip->startPoint = startPoint; + } + } else if (zaction == kConfirmResumeProcSaidAppend) { + /* append: leave startPoint at zero, we will append everything. */ + cip->startPoint = startPoint = 0; + } else /* if (zaction == kConfirmResumeProcSaidOverwrite) */ { + /* overwrite: leave startPoint at zero */ + cip->startPoint = startPoint = 0; + } + } + + if ((cip->numUploads == 0) && (cip->dataSocketSBufSize > 0)) { + /* If dataSocketSBufSize is non-zero, it means you + * want to explicitly try to set the size of the + * socket's I/O buffer. + * + * If it is zero, it means you want to just use the + * TCP stack's default value, which is typically + * between 8 and 64 kB. + * + * If you try to set the buffer larger than 64 kB, + * the TCP stack should try to use RFC 1323 to + * negotiate "TCP Large Windows" which may yield + * significant performance gains. + */ + if (cip->hasSTORBUFSIZE == kCommandAvailable) + (void) FTPCmd(cip, "SITE STORBUFSIZE %lu", (unsigned long) cip->dataSocketSBufSize); + else if (cip->hasSBUFSIZ == kCommandAvailable) + (void) FTPCmd(cip, "SITE SBUFSIZ %lu", (unsigned long) cip->dataSocketSBufSize); + else if (cip->hasSBUFSZ == kCommandAvailable) + (void) FTPCmd(cip, "SITE SBUFSZ %lu", (unsigned long) cip->dataSocketSBufSize); + /* At least one server implemenation has RBUFSZ but not + * SBUFSZ and instead uses RBUFSZ for both. + */ + else if ((cip->hasSBUFSZ != kCommandAvailable) && (cip->hasRBUFSZ == kCommandAvailable)) + (void) FTPCmd(cip, "SITE RBUFSZ %lu", (unsigned long) cip->dataSocketSBufSize); + else if (cip->hasBUFSIZE == kCommandAvailable) + (void) FTPCmd(cip, "SITE BUFSIZE %lu", (unsigned long) cip->dataSocketSBufSize); + } + +#ifdef NO_SIGNALS + vzaction = zaction; +#else /* NO_SIGNALS */ + vcip = cip; + vfdtouse = fdtouse; + vfd = fd; + vzaction = zaction; + osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenData); + + gGotBrokenData = 0; + gCanBrokenDataJmp = 0; + +#ifdef HAVE_SIGSETJMP + sj = sigsetjmp(gBrokenDataJmp, 1); +#else + sj = setjmp(gBrokenDataJmp); +#endif /* HAVE_SIGSETJMP */ + + if (sj != 0) { + (void) signal(SIGPIPE, (FTPSigProc) osigpipe); + if (vfdtouse < 0) { + (void) close(vfd); + } + FTPShutdownHost(vcip); + vcip->errNo = kErrRemoteHostClosedConnection; + return(vcip->errNo); + } + gCanBrokenDataJmp = 1; +#endif /* NO_SIGNALS */ + + if (vzaction == kConfirmResumeProcSaidAppend) { + cmd = "APPE"; + tmppfx = ""; /* Can't use that here. */ + tmpsfx = ""; + } else { + cmd = "STOR"; + if (tmppfx == NULL) + tmppfx = ""; + if (tmpsfx == NULL) + tmpsfx = ""; + } + + odstfile = dstfile; + if ((tmppfx[0] != '\0') || (tmpsfx[0] != '\0')) { + cp = strrchr(dstfile, '/'); + if (cp == NULL) + cp = strrchr(dstfile, '\\'); + if (cp == NULL) { + (void) STRNCPY(dstfile2, tmppfx); + (void) STRNCAT(dstfile2, dstfile); + (void) STRNCAT(dstfile2, tmpsfx); + } else { + cp++; + l = (size_t) (cp - dstfile); + (void) STRNCPY(dstfile2, dstfile); + dstfile2[l] = '\0'; /* Nuke stuff after / */ + (void) STRNCAT(dstfile2, tmppfx); + (void) STRNCAT(dstfile2, cp); + (void) STRNCAT(dstfile2, tmpsfx); + } + dstfile = dstfile2; + } + + tmpResult = FTPStartDataCmd( + cip, + kNetWriting, + xtype, + startPoint, + "%s %s", + cmd, + dstfile + ); + + if (tmpResult < 0) { + cip->errNo = tmpResult; + if (fdtouse < 0) { + (void) close(fd); + } +#if !defined(NO_SIGNALS) + (void) signal(SIGPIPE, (FTPSigProc) osigpipe); +#endif /* NO_SIGNALS */ + return (cip->errNo); + } + + if ((startPoint != 0) && (cip->startPoint == 0)) { + /* Remote could not or would not set the start offset + * to what we wanted. + * + * So now we have to undo our seek. + */ + if (Lseek(fd, (off_t) 0, SEEK_SET) != (off_t) 0) { + cip->errNo = kErrLseekFailed; + if (fdtouse < 0) { + (void) close(fd); + } +#if !defined(NO_SIGNALS) + (void) signal(SIGPIPE, (FTPSigProc) osigpipe); +#endif /* NO_SIGNALS */ + return (cip->errNo); + } + startPoint = 0; + } + + result = kNoErr; + buf = cip->buf; + bufSize = cip->bufSize; + + FTPInitIOTimer(cip); + if ((fstatrc == 0) && (S_ISREG(st.st_mode) != 0)) { + cip->expectedSize = (longest_int) st.st_size; + cip->mdtm = st.st_mtime; + } + cip->lname = file; /* could be NULL */ + cip->rname = odstfile; + if (fdtouse >= 0) + cip->useProgressMeter = 0; + FTPStartIOTimer(cip); + + /* Note: On Windows, we don't have to do anything special + * for ASCII mode, since Net ASCII's end-of-line sequence + * corresponds to the same thing used for DOS/Windows. + */ + +#if ASCII_TRANSLATION + if (xtype == kTypeAscii) { + /* ascii */ + for (;;) { +#if !defined(NO_SIGNALS) + gCanBrokenDataJmp = 0; +#endif /* NO_SIGNALS */ + nread = read(fd, inbuf, sizeof(inbuf)); + if (nread < 0) { + if (errno == EINTR) { + continue; + } else { + result = kErrReadFailed; + cip->errNo = kErrReadFailed; + Error(cip, kDoPerror, "Local read failed.\n"); + } + break; + } else if (nread == 0) { + break; + } + cip->bytesTransferred += (longest_int) nread; + +#if !defined(NO_SIGNALS) + gCanBrokenDataJmp = 1; +#endif /* NO_SIGNALS */ + src = inbuf; + srclim = src + nread; + dst = cip->buf; /* must be 2x sizeof inbuf or more. */ + while (src < srclim) { + if (*src == '\n') + *dst++ = '\r'; + *dst++ = *src++; + } + ntowrite = (size_t) (dst - cip->buf); + cp = cip->buf; + +#if !defined(NO_SIGNALS) + if (cip->xferTimeout > 0) + (void) alarm(cip->xferTimeout); +#endif /* NO_SIGNALS */ + do { + if (! WaitForRemoteOutput(cip)) { /* could set cancelXfer */ + cip->errNo = result = kErrDataTimedOut; + Error(cip, kDontPerror, "Remote write timed out.\n"); + goto brk; + } + if (cip->cancelXfer > 0) { + FTPAbortDataTransfer(cip); + result = cip->errNo = kErrDataTransferAborted; + goto brk; + } + +#ifdef NO_SIGNALS + nwrote = SWrite(cip->dataSocket, cp, (size_t) ntowrite, (int) cip->xferTimeout, kNoFirstSelect); + if (nwrote < 0) { + if (nwrote == kTimeoutErr) { + cip->errNo = result = kErrDataTimedOut; + Error(cip, kDontPerror, "Remote write timed out.\n"); + } else if ((gGotBrokenData != 0) || (errno == EPIPE)) { + cip->errNo = result = kErrSocketWriteFailed; + errno = EPIPE; + Error(cip, kDoPerror, "Lost data connection to remote host.\n"); + } else if (errno == EINTR) { + continue; + } else { + cip->errNo = result = kErrSocketWriteFailed; + Error(cip, kDoPerror, "Remote write failed.\n"); + } + (void) shutdown(cip->dataSocket, 2); + goto brk; + } +#else /* NO_SIGNALS */ + nwrote = write(cip->dataSocket, cp, ntowrite); + if (nwrote < 0) { + if ((gGotBrokenData != 0) || (errno == EPIPE)) { + cip->errNo = result = kErrSocketWriteFailed; + errno = EPIPE; + Error(cip, kDoPerror, "Lost data connection to remote host.\n"); + } else if (errno == EINTR) { + continue; + } else { + cip->errNo = result = kErrSocketWriteFailed; + Error(cip, kDoPerror, "Remote write failed.\n"); + } + (void) shutdown(cip->dataSocket, 2); + goto brk; + } +#endif /* NO_SIGNALS */ + cp += nwrote; + ntowrite -= nwrote; + } while (ntowrite > 0); + FTPUpdateIOTimer(cip); + } + } else +#endif /* ASCII_TRANSLATION */ + { + /* binary */ + for (;;) { +#if !defined(NO_SIGNALS) + gCanBrokenDataJmp = 0; +#endif /* NO_SIGNALS */ + cp = buf; + nread = read(fd, cp, bufSize); + if (nread < 0) { + if (errno == EINTR) { + continue; + } else { + result = kErrReadFailed; + cip->errNo = kErrReadFailed; + Error(cip, kDoPerror, "Local read failed.\n"); + } + break; + } else if (nread == 0) { + break; + } + cip->bytesTransferred += (longest_int) nread; + +#if !defined(NO_SIGNALS) + gCanBrokenDataJmp = 1; + if (cip->xferTimeout > 0) + (void) alarm(cip->xferTimeout); +#endif /* NO_SIGNALS */ + do { + if (! WaitForRemoteOutput(cip)) { /* could set cancelXfer */ + cip->errNo = result = kErrDataTimedOut; + Error(cip, kDontPerror, "Remote write timed out.\n"); + goto brk; + } + if (cip->cancelXfer > 0) { + FTPAbortDataTransfer(cip); + result = cip->errNo = kErrDataTransferAborted; + goto brk; + } + +#ifdef NO_SIGNALS + nwrote = SWrite(cip->dataSocket, cp, (size_t) nread, (int) cip->xferTimeout, kNoFirstSelect); + if (nwrote < 0) { + if (nwrote == kTimeoutErr) { + cip->errNo = result = kErrDataTimedOut; + Error(cip, kDontPerror, "Remote write timed out.\n"); + } else if ((gGotBrokenData != 0) || (errno == EPIPE)) { + cip->errNo = result = kErrSocketWriteFailed; + errno = EPIPE; + Error(cip, kDoPerror, "Lost data connection to remote host.\n"); + } else if (errno == EINTR) { + continue; + } else { + cip->errNo = result = kErrSocketWriteFailed; + Error(cip, kDoPerror, "Remote write failed.\n"); + } + (void) shutdown(cip->dataSocket, 2); + cip->dataSocket = -1; + goto brk; + } +#else /* NO_SIGNALS */ + nwrote = write(cip->dataSocket, cp, nread); + if (nwrote < 0) { + if ((gGotBrokenData != 0) || (errno == EPIPE)) { + cip->errNo = result = kErrSocketWriteFailed; + errno = EPIPE; + Error(cip, kDoPerror, "Lost data connection to remote host.\n"); + } else if (errno == EINTR) { + continue; + } else { + cip->errNo = result = kErrSocketWriteFailed; + Error(cip, kDoPerror, "Remote write failed.\n"); + } + (void) shutdown(cip->dataSocket, 2); + cip->dataSocket = -1; + goto brk; + } +#endif /* NO_SIGNALS */ + cp += nwrote; + nread -= nwrote; + } while (nread > 0); + FTPUpdateIOTimer(cip); + } + } +brk: + + if (fdtouse < 0) { + (void) Fstat(fd, &st); + } + + if (fdtouse < 0) { + if (shutdown(fd, 1) == 0) { + /* This looks very bizarre, since + * we will be checking the socket + * for readability here! + * + * The reason for this is that we + * want to be able to timeout a + * small put. So, we close the + * write end of the socket first, + * which tells the server we're + * done writing. We then wait + * for the server to close down + * the whole socket, which tells + * us that the file was completed. + */ + (void) WaitForRemoteInput(cip); /* Close could block. */ + } + } + +#if !defined(NO_SIGNALS) + gCanBrokenDataJmp = 0; + if (cip->xferTimeout > 0) + (void) alarm(0); +#endif /* NO_SIGNALS */ + tmpResult = FTPEndDataCmd(cip, 1); + if ((tmpResult < 0) && (result == kNoErr)) { + cip->errNo = result = kErrSTORFailed; + } + FTPStopIOTimer(cip); + + if (fdtouse < 0) { + /* If they gave us a descriptor (fdtouse >= 0), + * leave it open, otherwise we opened it, so + * we need to dispose of it. + */ + (void) close(fd); + fd = -1; + } + + if (result == kNoErr) { + /* The store succeeded; If we were + * uploading to a temporary file, + * move the new file to the new name. + */ + cip->numUploads++; + + if ((tmppfx[0] != '\0') || (tmpsfx[0] != '\0')) { + if ((result = FTPRename(cip, dstfile, odstfile)) < 0) { + /* May fail if file was already there, + * so delete the old one so we can move + * over it. + */ + if (FTPDelete(cip, odstfile, kRecursiveNo, kGlobNo) == kNoErr) { + result = FTPRename(cip, dstfile, odstfile); + if (result < 0) { + Error(cip, kDontPerror, "Could not rename %s to %s: %s.\n", dstfile, odstfile, FTPStrError(cip->errNo)); + } + } else { + Error(cip, kDontPerror, "Could not delete old %s, so could not rename %s to that: %s\n", odstfile, dstfile, FTPStrError(cip->errNo)); + } + } + } + + if (FTPUtime(cip, odstfile, st.st_atime, st.st_mtime, st.st_ctime) != kNoErr) { + if (cip->errNo != kErrUTIMENotAvailable) + Error(cip, kDontPerror, "Could not preserve times for %s: %s.\n", odstfile, FTPStrError(cip->errNo)); + } + + if (deleteflag == kDeleteYes) { + if (unlink(file) < 0) { + result = cip->errNo = kErrLocalDeleteFailed; + } + } + } + +#if !defined(NO_SIGNALS) + (void) signal(SIGPIPE, (FTPSigProc) osigpipe); +#endif /* NO_SIGNALS */ + return (result); +} /* FTPPutOneF */ + + + + +int +FTPPutOneFile3( + const FTPCIPtr cip, + const char *const file, + const char *const dstfile, + const int xtype, + const int fdtouse, + const int appendflag, + const char *const tmppfx, + const char *const tmpsfx, + const int resumeflag, + const int deleteflag, + const ConfirmResumeUploadProc resumeProc, + int UNUSED(reserved)) +{ + int result; + + LIBNCFTP_USE_VAR(reserved); + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if ((dstfile == NULL) || (dstfile[0] == '\0')) + return (kErrBadParameter); + if (fdtouse < 0) { + if ((file == NULL) || (file[0] == '\0')) + return (kErrBadParameter); + } + result = FTPPutOneF(cip, file, dstfile, xtype, fdtouse, appendflag, tmppfx, tmpsfx, resumeflag, deleteflag, resumeProc); + return (result); +} /* FTPPutOneFile3 */ + + + + +int +FTPPutFiles3( + const FTPCIPtr cip, + const char *const pattern, + const char *const dstdir1, + const int recurse, + const int doGlob, + const int xtype, + int appendflag, + const char *const tmppfx, + const char *const tmpsfx, + const int resumeflag, + const int deleteflag, + const ConfirmResumeUploadProc resumeProc, + int UNUSED(reserved)) +{ + LineList globList; + FileInfoList files; + FileInfoPtr filePtr; + int batchResult; + int result; + const char *dstdir; + char dstdir2[512]; + + LIBNCFTP_USE_VAR(reserved); + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if (dstdir1 == NULL) { + dstdir = NULL; + } else { + dstdir = STRNCPY(dstdir2, dstdir1); + StrRemoveTrailingLocalPathDelim(dstdir2); + } + + (void) FTPLocalGlob(cip, &globList, pattern, doGlob); + if (recurse == kRecursiveYes) { + appendflag = kAppendNo; + (void) FTPLocalRecursiveFileList(cip, &globList, &files); + if (files.first == NULL) { + cip->errNo = kErrNoValidFilesSpecified; + return (kErrNoValidFilesSpecified); + } + (void) ComputeRNames(&files, dstdir, 0, 1); + } else { + (void) LineListToFileInfoList(&globList, &files); + (void) ComputeLNames(&files, NULL, NULL, 1); + (void) ComputeRNames(&files, dstdir, 0, 0); + } + DisposeLineListContents(&globList); + +#if 0 + for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) { + PrintF(cip, " R=%s, L=%s, 2=%s, size=%d, mdtm=%u, type=%c\n", + filePtr->rname, + filePtr->lname, + filePtr->rlinkto ? filePtr->rlinkto : "", + filePtr->size, + (unsigned int) filePtr->mdtm, + filePtr->type + ); + } +#endif + + batchResult = kNoErr; + for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) { + if (cip->connected == 0) { + if (batchResult == kNoErr) + batchResult = kErrRemoteHostClosedConnection; + break; + } + if (filePtr->type == 'd') { + /* mkdir */ + StrRemoveTrailingLocalPathDelim(filePtr->rname); + result = FTPMkdir(cip, filePtr->rname, kRecursiveNo); + if (result != kNoErr) + batchResult = result; +#ifdef HAVE_SYMLINK + } else if (filePtr->type == 'l') { + /* symlink */ + /* no RFC way to create the link, though. */ + if ((filePtr->rlinkto != NULL) && (filePtr->rlinkto[0] != '\0')) + (void) FTPSymlink(cip, filePtr->rname, filePtr->rlinkto); +#endif + } else if (recurse != kRecursiveYes) { + result = FTPPutOneF(cip, filePtr->lname, filePtr->rname, xtype, -1, appendflag, tmppfx, tmpsfx, resumeflag, deleteflag, resumeProc); + if (files.nFileInfos == 1) { + if (result != kNoErr) + batchResult = result; + } else { + if ((result != kNoErr) && (result != kErrLocalFileNewer) && (result != kErrRemoteFileNewer) && (result != kErrLocalSameAsRemote)) + batchResult = result; + } + if (result == kErrUserCanceled) + cip->cancelXfer = 1; + if (cip->cancelXfer > 0) + break; + } else { + result = FTPPutOneF(cip, filePtr->lname, filePtr->rname, xtype, -1, appendflag, tmppfx, tmpsfx, resumeflag, deleteflag, resumeProc); + if (files.nFileInfos == 1) { + if (result != kNoErr) + batchResult = result; + } else { + if ((result != kNoErr) && (result != kErrLocalFileNewer) && (result != kErrRemoteFileNewer) && (result != kErrLocalSameAsRemote)) + batchResult = result; + } + if (result == kErrUserCanceled) + cip->cancelXfer = 1; + if (cip->cancelXfer > 0) + break; + } + } + DisposeFileInfoListContents(&files); + if (batchResult < 0) + cip->errNo = batchResult; + return (batchResult); +} /* FTPPutFiles3 */ + + + + +/* The purpose of this is to provide updates for the progress meters + * during lags. Return zero if the operation timed-out. + */ +static int +WaitForRemoteInput(const FTPCIPtr cip) +{ + fd_set ss, ss2; + struct timeval tv; + int result; + int fd; + int wsecs; + int xferTimeout; + int ocancelXfer; + + xferTimeout = cip->xferTimeout; + if (xferTimeout < 1) + return (1); + + fd = cip->dataSocket; + if (fd < 0) + return (1); + + ocancelXfer = cip->cancelXfer; + wsecs = 0; + cip->stalled = 0; + + while ((xferTimeout <= 0) || (wsecs < xferTimeout)) { + if ((cip->cancelXfer != 0) && (ocancelXfer == 0)) { + /* leave cip->stalled -- could have been stalled and then canceled. */ + return (1); + } + FD_ZERO(&ss); + FD_SET(fd, &ss); + ss2 = ss; + tv.tv_sec = 1; + tv.tv_usec = 0; + result = select(fd + 1, SELECT_TYPE_ARG234 &ss, NULL, SELECT_TYPE_ARG234 &ss2, &tv); + if (result == 1) { + /* ready */ + cip->stalled = 0; + return (1); + } else if (result < 0) { + if (result != EINTR) { + perror("select"); + cip->stalled = 0; + return (1); + } + } else { + wsecs++; + cip->stalled = wsecs; + } + FTPUpdateIOTimer(cip); + } + +#if !defined(NO_SIGNALS) + /* Shouldn't get here -- alarm() should have + * went off by now. + */ + (void) kill(getpid(), SIGALRM); +#endif /* NO_SIGNALS */ + + cip->dataTimedOut = 1; + return (0); /* timed-out */ +} /* WaitForRemoteInput */ + + + + +/* Nice for UNIX, but not necessary otherwise. */ +#ifdef TAR + +static int +OpenTar(const FTPCIPtr cip, const char *const dstdir, int *const pid) +{ + int pipe1[2]; + int pid1; + int i; + char *argv[8]; + + *pid = -1; + + if (access(TAR, X_OK) < 0) { + /* Path to TAR is invalid. */ + return (-1); + } + + if (pipe(pipe1) < 0) { + Error(cip, kDoPerror, "pipe to Tar failed"); + return (-1); + } + + pid1 = (int) fork(); + if (pid1 < 0) { + (void) close(pipe1[0]); + (void) close(pipe1[1]); + return (-1); + } else if (pid1 == 0) { + /* Child */ + if ((dstdir != NULL) && (dstdir[0] != '\0') && (chdir(dstdir) < 0)) { + Error(cip, kDoPerror, "tar chdir to %s failed", dstdir); + exit(1); + } + (void) close(pipe1[1]); /* close write end */ + (void) dup2(pipe1[0], 0); /* use read end on stdin */ + (void) close(pipe1[0]); + + for (i=3; i<256; i++) + (void) close(i); + + argv[0] = (char *) "tar"; + argv[1] = (char *) "xpf"; + argv[2] = (char *) "-"; + argv[3] = NULL; + + (void) execv(TAR, argv); + exit(1); + } + + /* Parent */ + *pid = pid1; + + (void) close(pipe1[0]); /* close read end */ + return (pipe1[1]); /* use write end */ +} /* OpenTar */ + + + + +static int +FTPGetOneTarF(const FTPCIPtr cip, const char *file, const char *const dstdir) +{ + char *buf; + size_t bufSize; + int tmpResult; + volatile int result; + int nread, nwrote; + volatile int fd; + volatile int vfd; + const char *volatile vfile; +#ifndef NO_SIGNALS + int sj; + volatile FTPSigProc osigpipe; + volatile FTPCIPtr vcip; +#endif + int pid, status; + char savedCwd[512]; + char *volatile basecp; + + result = kNoErr; + cip->usingTAR = 0; + + if ((file[0] == '\0') || ((file[0] == '/') && (file[1] == '\0'))) { + /* It was "/" + * We can't do that, because "get /.tar" + * or "get .tar" does not work. + */ + result = kErrOpenFailed; + cip->errNo = kErrOpenFailed; + return (result); + } + + if (FTPCmd(cip, "MDTM %s.tar", file) == 2) { + /* Better not use this method since there is + * no way to tell if the server would use the + * existing .tar or do a new one on the fly. + */ + result = kErrOpenFailed; + cip->errNo = kErrOpenFailed; + return (result); + } + + basecp = strrchr(file, '/'); + if (basecp != NULL) + basecp = strrchr(file, '\\'); + if (basecp != NULL) { + /* Need to cd to the parent directory and get it + * from there. + */ + if (FTPGetCWD(cip, savedCwd, sizeof(savedCwd)) != 0) { + result = kErrOpenFailed; + cip->errNo = kErrOpenFailed; + return (result); + } + result = FTPChdir(cip, file); + if (result != kNoErr) { + return (result); + } + result = FTPChdir(cip, ".."); + if (result != kNoErr) { + (void) FTPChdir(cip, savedCwd); + return (result); + } + file = basecp + 1; + } + + fd = OpenTar(cip, dstdir, &pid); + if (fd < 0) { + result = kErrOpenFailed; + cip->errNo = kErrOpenFailed; + if (basecp != NULL) + (void) FTPChdir(cip, savedCwd); + return (result); + } + + vfd = fd; + vfile = file; + +#ifndef NO_SIGNALS + vcip = cip; + osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenData); + + gGotBrokenData = 0; + gCanBrokenDataJmp = 0; + +#ifdef HAVE_SIGSETJMP + sj = sigsetjmp(gBrokenDataJmp, 1); +#else + sj = setjmp(gBrokenDataJmp); +#endif /* HAVE_SIGSETJMP */ + + if (sj != 0) { + (void) signal(SIGPIPE, (FTPSigProc) osigpipe); + FTPShutdownHost(vcip); + + (void) signal(SIGPIPE, SIG_IGN); + (void) close(vfd); + for (;;) { +#ifdef HAVE_WAITPID + if ((waitpid(pid, &status, 0) < 0) && (errno != EINTR)) + break; +#else + if ((wait(&status) < 0) && (errno != EINTR)) + break; +#endif + if (WIFEXITED(status) || WIFSIGNALED(status)) + break; /* done */ + } + if (basecp != NULL) + (void) FTPChdir(cip, savedCwd); + vcip->errNo = kErrRemoteHostClosedConnection; + return(vcip->errNo); + } + gCanBrokenDataJmp = 1; + +#endif /* NO_SIGNALS */ + + tmpResult = FTPStartDataCmd(cip, kNetReading, kTypeBinary, (longest_int) 0, "RETR %s.tar", vfile); + + if (tmpResult < 0) { + result = tmpResult; + if (result == kErrGeneric) + result = kErrRETRFailed; + cip->errNo = result; + +#ifndef NO_SIGNALS + (void) signal(SIGPIPE, SIG_IGN); +#endif + (void) close(vfd); + for (;;) { +#ifdef HAVE_WAITPID + if ((waitpid(pid, &status, 0) < 0) && (errno != EINTR)) + break; +#else + if ((wait(&status) < 0) && (errno != EINTR)) + break; +#endif + if (WIFEXITED(status) || WIFSIGNALED(status)) + break; /* done */ + } + +#ifndef NO_SIGNALS + (void) signal(SIGPIPE, (FTPSigProc) osigpipe); +#endif + if (basecp != NULL) + (void) FTPChdir(cip, savedCwd); + return (result); + } + + cip->usingTAR = 1; + buf = cip->buf; + bufSize = cip->bufSize; + + FTPInitIOTimer(cip); + cip->lname = vfile; /* could be NULL */ + cip->rname = vfile; + FTPStartIOTimer(cip); + + /* Binary */ + for (;;) { + if (! WaitForRemoteInput(cip)) { /* could set cancelXfer */ + cip->errNo = result = kErrDataTimedOut; + Error(cip, kDontPerror, "Remote read timed out.\n"); + break; + } + if (cip->cancelXfer > 0) { + FTPAbortDataTransfer(cip); + result = cip->errNo = kErrDataTransferAborted; + break; + } +#if !defined(NO_SIGNALS) + gCanBrokenDataJmp = 1; + if (cip->xferTimeout > 0) + (void) alarm(cip->xferTimeout); +#endif /* NO_SIGNALS */ +#ifdef NO_SIGNALS + nread = SRead(cip->dataSocket, buf, bufSize, (int) cip->xferTimeout, kFullBufferNotRequired|kNoFirstSelect); + if (nread == kTimeoutErr) { + cip->errNo = result = kErrDataTimedOut; + Error(cip, kDontPerror, "Remote read timed out.\n"); + break; + } else if (nread < 0) { + if (errno == EINTR) + continue; + Error(cip, kDoPerror, "Remote read failed.\n"); + result = kErrSocketReadFailed; + cip->errNo = kErrSocketReadFailed; + break; + } else if (nread == 0) { + break; + } +#else + nread = read(cip->dataSocket, buf, bufSize); + if (nread < 0) { + if (errno == EINTR) + continue; + Error(cip, kDoPerror, "Remote read failed.\n"); + result = kErrSocketReadFailed; + cip->errNo = kErrSocketReadFailed; + break; + } else if (nread == 0) { + break; + } + gCanBrokenDataJmp = 0; +#endif + + nwrote = write(fd, buf, nread); + if (nwrote != nread) { + if ((gGotBrokenData != 0) || (errno == EPIPE)) { + result = kErrWriteFailed; + cip->errNo = kErrWriteFailed; + errno = EPIPE; + } else { + Error(cip, kDoPerror, "Local write failed.\n"); + result = kErrWriteFailed; + cip->errNo = kErrWriteFailed; + } + break; + } + cip->bytesTransferred += (longest_int) nread; + FTPUpdateIOTimer(cip); + } + +#if !defined(NO_SIGNALS) + if (cip->xferTimeout > 0) + (void) alarm(0); + gCanBrokenDataJmp = 0; +#endif /* NO_SIGNALS */ + + (void) close(fd); + for (;;) { +#ifdef HAVE_WAITPID + if ((waitpid(pid, &status, 0) < 0) && (errno != EINTR)) + break; +#else + if ((wait(&status) < 0) && (errno != EINTR)) + break; +#endif + if (WIFEXITED(status) || WIFSIGNALED(status)) + break; /* done */ + } + + tmpResult = FTPEndDataCmd(cip, 1); + if ((tmpResult < 0) && (result == 0)) { + result = kErrRETRFailed; + cip->errNo = kErrRETRFailed; + } + FTPStopIOTimer(cip); +#if !defined(NO_SIGNALS) + (void) signal(SIGPIPE, (FTPSigProc) osigpipe); +#endif + + if ((result == 0) && (cip->bytesTransferred == 0)) { + result = kErrOpenFailed; + cip->errNo = kErrOpenFailed; + } + if (basecp != NULL) + (void) FTPChdir(cip, savedCwd); + return (result); +} /* FTPGetOneTarF */ + +#endif /* TAR */ + + + + + +static int +FTPGetOneF( + const FTPCIPtr cip, + const char *const file, + const char *dstfile, + int xtype, + const int fdtouse, + longest_int expectedSize, + time_t mdtm, + const int resumeflag, + const int appendflag, + const int deleteflag, + const ConfirmResumeDownloadProc resumeProc) +{ + char *buf; + size_t bufSize; + int tmpResult; + volatile int result; + int nread, nwrote; + volatile int fd; +#if ASCII_TRANSLATION + char *src, *srclim; + char *dst, *dstlim; + char outbuf[512]; +#endif + volatile longest_int startPoint = 0; + struct utimbuf ut; + struct Stat st; +#if !defined(NO_SIGNALS) + volatile FTPSigProc osigpipe; + volatile FTPCIPtr vcip; + volatile int vfd, vfdtouse; + int sj; +#endif /* NO_SIGNALS */ + volatile int created = 0; + int zaction = kConfirmResumeProcSaidBestGuess; + int statrc; + int noMdtmCheck; + time_t now; + + if (cip->buf == NULL) { + Error(cip, kDoPerror, "Transfer buffer not allocated.\n"); + cip->errNo = kErrNoBuf; + return (cip->errNo); + } + + result = kNoErr; + cip->usingTAR = 0; + + if (fdtouse < 0) { + /* Only ask for extended information + * if we have the name of the file + * and we didn't already have the + * info. + * + * Always ask for the modification time, + * because even if it was passed in it + * may not be accurate. This is often + * the case when it came from an ls + * listing, in which the local time + * zone could be a factor. + * + */ + + AutomaticallyUseASCIIModeDependingOnExtension(cip, file, &xtype); + if (expectedSize == kSizeUnknown) { + (void) FTPFileSizeAndModificationTime(cip, file, &expectedSize, xtype, &mdtm); + } else { + (void) FTPFileModificationTime(cip, file, &mdtm); + } + + /* For Get, we can't recover very well if it turns out restart + * didn't work, so check beforehand. + */ + if ((resumeflag == kResumeYes) || (resumeProc != NoConfirmResumeDownloadProc)) { + if (cip->hasREST == kCommandAvailabilityUnknown) { + (void) FTPSetTransferType(cip, kTypeBinary); + if (SetStartOffset(cip, (longest_int) 1) == kNoErr) { + /* Now revert -- we still may not end up + * doing it. + */ + SetStartOffset(cip, (longest_int) -1); + } + } + } + + if (appendflag == kAppendYes) { + zaction = kConfirmResumeProcSaidAppend; + } else if (cip->hasREST == kCommandNotAvailable) { + zaction = kConfirmResumeProcSaidOverwrite; + } else if (resumeflag == kResumeYes) { + zaction = kConfirmResumeProcSaidBestGuess; + } else { + zaction = kConfirmResumeProcSaidOverwrite; + } + + statrc = Stat(dstfile, &st); + if (statrc == 0) { + if (resumeProc != NULL) { + zaction = (*resumeProc)( + &dstfile, + (longest_int) st.st_size, + st.st_mtime, + file, + expectedSize, + mdtm, + &startPoint + ); + } + + if (zaction == kConfirmResumeProcSaidBestGuess) { + if (expectedSize != kSizeUnknown) { + /* We know the size of the remote file, + * and we have a local file too. + * + * Try and decide if we need to get + * the entire file, or just part of it. + */ + + startPoint = (longest_int) st.st_size; + zaction = kConfirmResumeProcSaidResume; + + /* If the local file exists and has a recent + * modification time (< 12 hours) and + * the remote file's modtime is not recent, + * then heuristically conclude that the + * local modtime should not be trusted + * (i.e. user killed the process before + * the local modtime could be preserved). + */ + noMdtmCheck = 0; + if (mdtm != kModTimeUnknown) { + time(&now); + if ((st.st_mtime > now) || (((now - st.st_mtime) < 46200) && ((now - mdtm) >= 46200))) + noMdtmCheck = 1; + } + + if ((mdtm == kModTimeUnknown) || (noMdtmCheck != 0)) { + /* Can't use the timestamps as an aid. */ + if (startPoint == expectedSize) { + /* Don't go to all the trouble of downloading nothing. */ + cip->errNo = kErrLocalSameAsRemote; + if (deleteflag == kDeleteYes) + (void) FTPDelete(cip, file, kRecursiveNo, kGlobNo); + return (cip->errNo); + } else if (startPoint > expectedSize) { + /* Panic; odds are the file we have + * was a different file altogether, + * since it is larger than the + * remote copy. Re-do it all. + */ + zaction = kConfirmResumeProcSaidOverwrite; + } /* else resume at startPoint */ + } else if ((mdtm == st.st_mtime) || (mdtm == (st.st_mtime - 1)) || (mdtm == (st.st_mtime + 1))) { + /* File has the same time. + * Note: Windows' file timestamps can be off by one second! + */ + if (startPoint == expectedSize) { + /* Don't go to all the trouble of downloading nothing. */ + cip->errNo = kErrLocalSameAsRemote; + if (deleteflag == kDeleteYes) + (void) FTPDelete(cip, file, kRecursiveNo, kGlobNo); + return (cip->errNo); + } else if (startPoint > expectedSize) { + /* Panic; odds are the file we have + * was a different file altogether, + * since it is larger than the + * remote copy. Re-do it all. + */ + zaction = kConfirmResumeProcSaidOverwrite; + } else { + /* We have a file by the same time, + * but smaller start point. Leave + * the startpoint as is since it + * is most likely valid. + */ + } + } else if (mdtm < st.st_mtime) { + /* Remote file is older than + * local file. Don't overwrite + * our file. + */ + cip->errNo = kErrLocalFileNewer; + return (cip->errNo); + } else /* if (mdtm > st.st_mtime) */ { + /* File has a newer timestamp + * altogether, assume the remote + * file is an entirely new file + * and replace ours with it. + */ + zaction = kConfirmResumeProcSaidOverwrite; + } + } else { + zaction = kConfirmResumeProcSaidOverwrite; + } + } + } else { + zaction = kConfirmResumeProcSaidOverwrite; + } + + if (zaction == kConfirmResumeProcSaidCancel) { + /* User wants to cancel this file and any + * remaining in batch. + */ + cip->errNo = kErrUserCanceled; + return (cip->errNo); + } else if (zaction == kConfirmResumeProcSaidSkip) { + /* Nothing done, but not an error. */ + if (deleteflag == kDeleteYes) + (void) FTPDelete(cip, file, kRecursiveNo, kGlobNo); + return (kNoErr); + } else if (zaction == kConfirmResumeProcSaidResume) { + /* Resume; proc set the startPoint. */ + if (startPoint == expectedSize) { + /* Don't go to all the trouble of downloading nothing. */ + /* Nothing done, but not an error. */ + if (deleteflag == kDeleteYes) + (void) FTPDelete(cip, file, kRecursiveNo, kGlobNo); + return (kNoErr); + } else if (startPoint > expectedSize) { + /* Cannot set start point past end of remote file */ + cip->errNo = result = kErrSetStartPoint; + return (result); + } + fd = Open(dstfile, O_WRONLY|O_APPEND|O_BINARY, 00666); + } else if (zaction == kConfirmResumeProcSaidAppend) { + /* leave startPoint at zero, we will append everything. */ + startPoint = (longest_int) 0; + fd = Open(dstfile, O_WRONLY|O_CREAT|O_APPEND|O_BINARY, 00666); + } else /* if (zaction == kConfirmResumeProcSaidOverwrite) */ { + created = 1; + startPoint = (longest_int) 0; + fd = Open(dstfile, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 00666); + } + + if (fd < 0) { + Error(cip, kDoPerror, "Cannot open local file %s for writing.\n", dstfile); + result = kErrOpenFailed; + cip->errNo = kErrOpenFailed; + return (result); + } + + if ((expectedSize == (longest_int) 0) && (startPoint <= (longest_int) 0) && (zaction != kConfirmResumeProcSaidOverwrite)) { + /* Don't go to all the trouble of downloading nothing. */ +#if defined(WIN32) || defined(_WINDOWS) + /* Note: Windows doesn't allow zero-size files. */ + (void) write(fd, "\r\n", 2); +#endif + (void) close(fd); + if (mdtm != kModTimeUnknown) { + cip->mdtm = mdtm; + (void) time(&ut.actime); + ut.modtime = mdtm; + (void) utime(dstfile, &ut); + } + if (deleteflag == kDeleteYes) + (void) FTPDelete(cip, file, kRecursiveNo, kGlobNo); + return (kNoErr); + } + } else { + fd = fdtouse; + } + + if ((cip->numDownloads == 0) && (cip->dataSocketRBufSize > 0)) { + /* If dataSocketSBufSize is non-zero, it means you + * want to explicitly try to set the size of the + * socket's I/O buffer. + * + * If it is zero, it means you want to just use the + * TCP stack's default value, which is typically + * between 8 and 64 kB. + * + * If you try to set the buffer larger than 64 kB, + * the TCP stack should try to use RFC 1323 to + * negotiate "TCP Large Windows" which may yield + * significant performance gains. + */ + if (cip->hasRETRBUFSIZE == kCommandAvailable) + (void) FTPCmd(cip, "SITE RETRBUFSIZE %lu", (unsigned long) cip->dataSocketRBufSize); + else if (cip->hasRBUFSIZ == kCommandAvailable) + (void) FTPCmd(cip, "SITE RBUFSIZ %lu", (unsigned long) cip->dataSocketRBufSize); + else if (cip->hasRBUFSZ == kCommandAvailable) + (void) FTPCmd(cip, "SITE RBUFSZ %lu", (unsigned long) cip->dataSocketRBufSize); + else if (cip->hasBUFSIZE == kCommandAvailable) + (void) FTPCmd(cip, "SITE BUFSIZE %lu", (unsigned long) cip->dataSocketSBufSize); + } + +#ifdef NO_SIGNALS +#else /* NO_SIGNALS */ + vcip = cip; + vfdtouse = fdtouse; + vfd = fd; + osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenData); + + gGotBrokenData = 0; + gCanBrokenDataJmp = 0; + +#ifdef HAVE_SIGSETJMP + sj = sigsetjmp(gBrokenDataJmp, 1); +#else + sj = setjmp(gBrokenDataJmp); +#endif /* HAVE_SIGSETJMP */ + + if (sj != 0) { + (void) signal(SIGPIPE, (FTPSigProc) osigpipe); + if (vfdtouse < 0) { + (void) close(vfd); + } + FTPShutdownHost(vcip); + vcip->errNo = kErrRemoteHostClosedConnection; + return(vcip->errNo); + } + gCanBrokenDataJmp = 1; +#endif /* NO_SIGNALS */ + + tmpResult = FTPStartDataCmd(cip, kNetReading, xtype, startPoint, "RETR %s", file); + + if (tmpResult < 0) { + result = tmpResult; + if (result == kErrGeneric) + result = kErrRETRFailed; + cip->errNo = result; + if (fdtouse < 0) { + (void) close(fd); + if ((created != 0) && (appendflag == kAppendNo) && (cip->startPoint == 0)) + (void) unlink(dstfile); + } +#if !defined(NO_SIGNALS) + (void) signal(SIGPIPE, (FTPSigProc) osigpipe); +#endif /* NO_SIGNALS */ + return (result); + } + + if ((startPoint != 0) && (cip->startPoint == 0)) { + /* Remote could not or would not set the start offset + * to what we wanted. + * + * So now we have to undo our seek. + */ + if (Lseek(fd, (off_t) 0, SEEK_SET) != (off_t) 0) { + cip->errNo = kErrLseekFailed; + if (fdtouse < 0) { + (void) close(fd); + } +#if !defined(NO_SIGNALS) + (void) signal(SIGPIPE, (FTPSigProc) osigpipe); +#endif /* NO_SIGNALS */ + return (cip->errNo); + } + startPoint = 0; + } + + buf = cip->buf; + bufSize = cip->bufSize; + + FTPInitIOTimer(cip); + cip->mdtm = mdtm; + (void) time(&ut.actime); + ut.modtime = mdtm; + cip->expectedSize = expectedSize; + cip->lname = dstfile; /* could be NULL */ + cip->rname = file; + if (fdtouse >= 0) + cip->useProgressMeter = 0; + FTPStartIOTimer(cip); + +#if ASCII_TRANSLATION + if (xtype == kTypeAscii) { + /* Ascii */ + for (;;) { + if (! WaitForRemoteInput(cip)) { /* could set cancelXfer */ + cip->errNo = result = kErrDataTimedOut; + Error(cip, kDontPerror, "Remote read timed out.\n"); + break; + } + if (cip->cancelXfer > 0) { + FTPAbortDataTransfer(cip); + result = cip->errNo = kErrDataTransferAborted; + break; + } +#ifdef TESTING_ABOR + if (cip->bytesTransferred > 0) { + cip->cancelXfer = 1; + FTPAbortDataTransfer(cip); + result = cip->errNo = kErrDataTransferAborted; + break; + } +#endif /* TESTING_ABOR */ +#ifdef NO_SIGNALS + nread = SRead(cip->dataSocket, buf, bufSize, (int) cip->xferTimeout, kFullBufferNotRequired|kNoFirstSelect); + if (nread == kTimeoutErr) { + cip->errNo = result = kErrDataTimedOut; + Error(cip, kDontPerror, "Remote read timed out.\n"); + break; + } else if (nread < 0) { + if ((gGotBrokenData != 0) || (errno == EPIPE)) { + result = cip->errNo = kErrSocketReadFailed; + errno = EPIPE; + Error(cip, kDoPerror, "Lost data connection to remote host.\n"); + } else if (errno == EINTR) { + continue; + } else { + Error(cip, kDoPerror, "Remote read failed.\n"); + result = kErrSocketReadFailed; + cip->errNo = kErrSocketReadFailed; + } + break; + } else if (nread == 0) { + break; + } +#else + gCanBrokenDataJmp = 1; + if (cip->xferTimeout > 0) + (void) alarm(cip->xferTimeout); + nread = read(cip->dataSocket, buf, bufSize); + if (nread < 0) { + if ((gGotBrokenData != 0) || (errno == EPIPE)) { + result = cip->errNo = kErrSocketReadFailed; + errno = EPIPE; + Error(cip, kDoPerror, "Lost data connection to remote host.\n"); + (void) shutdown(cip->dataSocket, 2); + } else if (errno == EINTR) { + continue; + } else { + result = cip->errNo = kErrSocketReadFailed; + Error(cip, kDoPerror, "Remote read failed.\n"); + (void) shutdown(cip->dataSocket, 2); + } + break; + } else if (nread == 0) { + break; + } + + gCanBrokenDataJmp = 0; +#endif /* NO_SIGNALS */ + + src = buf; + srclim = src + nread; + dst = outbuf; + dstlim = dst + sizeof(outbuf); + while (src < srclim) { + if (*src == '\r') { + src++; + continue; + } + if (dst >= dstlim) { + nwrote = write(fd, outbuf, (size_t) (dst - outbuf)); + if (nwrote == (int) (dst - outbuf)) { + /* Success. */ + dst = outbuf; + } else if ((gGotBrokenData != 0) || (errno == EPIPE)) { + result = kErrWriteFailed; + cip->errNo = kErrWriteFailed; + errno = EPIPE; + (void) shutdown(cip->dataSocket, 2); + goto brk; + } else { + Error(cip, kDoPerror, "Local write failed.\n"); + result = kErrWriteFailed; + cip->errNo = kErrWriteFailed; + (void) shutdown(cip->dataSocket, 2); + goto brk; + } + } + *dst++ = *src++; + } + if (dst > outbuf) { + nwrote = write(fd, outbuf, (size_t) (dst - outbuf)); + if (nwrote != (int) (dst - outbuf)) { + if ((gGotBrokenData != 0) || (errno == EPIPE)) { + result = kErrWriteFailed; + cip->errNo = kErrWriteFailed; + errno = EPIPE; + (void) shutdown(cip->dataSocket, 2); + goto brk; + } else { + Error(cip, kDoPerror, "Local write failed.\n"); + result = kErrWriteFailed; + cip->errNo = kErrWriteFailed; + (void) shutdown(cip->dataSocket, 2); + goto brk; + } + } + } + + if (mdtm != kModTimeUnknown) { + (void) utime(dstfile, &ut); + } + cip->bytesTransferred += (longest_int) nread; + FTPUpdateIOTimer(cip); + } + } else +#endif /* ASCII_TRANSLATION */ + { + /* Binary */ + for (;;) { + if (! WaitForRemoteInput(cip)) { /* could set cancelXfer */ + cip->errNo = result = kErrDataTimedOut; + Error(cip, kDontPerror, "Remote read timed out.\n"); + break; + } + if (cip->cancelXfer > 0) { + FTPAbortDataTransfer(cip); + result = cip->errNo = kErrDataTransferAborted; + break; + } +#ifdef TESTING_ABOR + if (cip->bytesTransferred > 0) { + cip->cancelXfer = 1; + FTPAbortDataTransfer(cip); + result = cip->errNo = kErrDataTransferAborted; + break; + } +#endif /* TESTING_ABOR */ +#ifdef NO_SIGNALS + nread = SRead(cip->dataSocket, buf, bufSize, (int) cip->xferTimeout, kFullBufferNotRequired|kNoFirstSelect); + if (nread == kTimeoutErr) { + cip->errNo = result = kErrDataTimedOut; + Error(cip, kDontPerror, "Remote read timed out.\n"); + break; + } else if (nread < 0) { + if ((gGotBrokenData != 0) || (errno == EPIPE)) { + result = cip->errNo = kErrSocketReadFailed; + errno = EPIPE; + Error(cip, kDoPerror, "Lost data connection to remote host.\n"); + } else if (errno == EINTR) { + continue; + } else { + Error(cip, kDoPerror, "Remote read failed.\n"); + result = kErrSocketReadFailed; + cip->errNo = kErrSocketReadFailed; + } + break; + } else if (nread == 0) { + break; + } +#else + gCanBrokenDataJmp = 1; + if (cip->xferTimeout > 0) + (void) alarm(cip->xferTimeout); + nread = read(cip->dataSocket, buf, bufSize); + if (nread < 0) { + if ((gGotBrokenData != 0) || (errno == EPIPE)) { + result = cip->errNo = kErrSocketReadFailed; + errno = EPIPE; + Error(cip, kDoPerror, "Lost data connection to remote host.\n"); + } else if (errno == EINTR) { + continue; + } else { + result = cip->errNo = kErrSocketReadFailed; + Error(cip, kDoPerror, "Remote read failed.\n"); + } + (void) shutdown(cip->dataSocket, 2); + break; + } else if (nread == 0) { + break; + } + gCanBrokenDataJmp = 0; +#endif /* NO_SIGNALS */ + + nwrote = write(fd, buf, nread); + if (nwrote != nread) { + if ((gGotBrokenData != 0) || (errno == EPIPE)) { + result = kErrWriteFailed; + cip->errNo = kErrWriteFailed; + errno = EPIPE; + } else { + Error(cip, kDoPerror, "Local write failed.\n"); + result = kErrWriteFailed; + cip->errNo = kErrWriteFailed; + } + (void) shutdown(cip->dataSocket, 2); + break; + } + + /* Ugggh... do this after each write operation + * so it minimizes the chance of a user killing + * the process before we reset the timestamps. + */ + if (mdtm != kModTimeUnknown) { + (void) utime(dstfile, &ut); + } + cip->bytesTransferred += (longest_int) nread; + FTPUpdateIOTimer(cip); + } + } + +#if ASCII_TRANSLATION +brk: +#endif + +#if !defined(NO_SIGNALS) + if (cip->xferTimeout > 0) + (void) alarm(0); + gCanBrokenDataJmp = 0; +#endif /* NO_SIGNALS */ + + if (fdtouse < 0) { + /* If they gave us a descriptor (fdtouse >= 0), + * leave it open, otherwise we opened it, so + * we need to close it. + */ + (void) close(fd); + fd = -1; + } + + tmpResult = FTPEndDataCmd(cip, 1); + if ((tmpResult < 0) && (result == 0)) { + result = kErrRETRFailed; + cip->errNo = kErrRETRFailed; + } + FTPStopIOTimer(cip); +#if !defined(NO_SIGNALS) + (void) signal(SIGPIPE, (FTPSigProc) osigpipe); +#endif /* NO_SIGNALS */ + + if ((mdtm != kModTimeUnknown) && (cip->bytesTransferred > 0)) { + (void) utime(dstfile, &ut); + } + + if (result == kNoErr) { + cip->numDownloads++; + + if (deleteflag == kDeleteYes) { + result = FTPDelete(cip, file, kRecursiveNo, kGlobNo); + } + } + + return (result); +} /* FTPGetOneF */ + + + + +int +FTPGetOneFile3( + const FTPCIPtr cip, + const char *const file, + const char *const dstfile, + const int xtype, + const int fdtouse, + const int resumeflag, + const int appendflag, + const int deleteflag, + const ConfirmResumeDownloadProc resumeProc, + int UNUSED(reserved)) +{ + int result; + + LIBNCFTP_USE_VAR(reserved); + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if ((file == NULL) || (file[0] == '\0')) + return (kErrBadParameter); + if (fdtouse < 0) { + if ((dstfile == NULL) || (dstfile[0] == '\0')) + return (kErrBadParameter); + } + + result = FTPGetOneF(cip, file, dstfile, xtype, fdtouse, kSizeUnknown, kModTimeUnknown, resumeflag, appendflag, deleteflag, resumeProc); + return (result); +} /* FTPGetOneFile3 */ + + + + +int +FTPGetFiles3( + const FTPCIPtr cip, + const char *pattern1, + const char *const dstdir1, + const int recurse, + int doGlob, + const int xtype, + const int resumeflag, + int appendflag, + const int deleteflag, + const int tarflag, + const ConfirmResumeDownloadProc resumeProc, + int UNUSED(reserved)) +{ + LineList globList; + LinePtr itemPtr; + FileInfoList files; + FileInfoPtr filePtr; + int batchResult; + int result; + char *ldir; + char *cp; + const char *dstdir; + const char *pattern; + char *pattern2, *dstdir2; + char c; + int recurse1; + int errRc; + + LIBNCFTP_USE_VAR(reserved); + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + if (pattern1 == NULL) + return (kErrBadParameter); + + dstdir2 = NULL; + pattern2 = NULL; + + if (dstdir1 == NULL) { + dstdir = NULL; + } else { + dstdir2 = StrDup(dstdir1); + if (dstdir2 == NULL) { + errRc = kErrMallocFailed; + goto return_err; + } + StrRemoveTrailingLocalPathDelim(dstdir2); + dstdir = dstdir2; + } + + pattern2 = StrDup(pattern1); + if (pattern2 == NULL) { + errRc = kErrMallocFailed; + goto return_err; + } + StrRemoveTrailingSlashes(pattern2); + pattern = pattern2; + + if (pattern[0] == '\0') { + if (recurse == kRecursiveNo) { + errRc = kErrBadParameter; + goto return_err; + } + pattern = "."; + doGlob = kGlobNo; + } else if (strcmp(pattern, ".") == 0) { + if (recurse == kRecursiveNo) { + errRc = kErrBadParameter; + goto return_err; + } + doGlob = kGlobNo; + } + if (recurse == kRecursiveYes) + appendflag = kAppendNo; + + batchResult = FTPRemoteGlob(cip, &globList, pattern, doGlob); + if (batchResult != kNoErr) { + errRc = batchResult; + goto return_err; + } + + cip->cancelXfer = 0; /* should already be zero */ + + for (itemPtr = globList.first; itemPtr != NULL; itemPtr = itemPtr->next) { + if ((recurse == kRecursiveYes) && (FTPIsDir(cip, itemPtr->line) > 0)) { +#ifdef TAR + if ((tarflag == kTarYes) && (xtype == kTypeBinary) && (appendflag == kAppendNo) && (deleteflag == kDeleteNo) && (FTPGetOneTarF(cip, itemPtr->line, dstdir) == kNoErr)) { + /* Great! */ + continue; + } +#endif /* TAR */ + (void) FTPRemoteRecursiveFileList1(cip, itemPtr->line, &files); + (void) ComputeLNames(&files, itemPtr->line, dstdir, 1); + recurse1 = recurse; + } else { + recurse1 = kRecursiveNo; + (void) LineToFileInfoList(itemPtr, &files); + (void) ComputeRNames(&files, ".", 0, 1); + (void) ComputeLNames(&files, NULL, dstdir, 0); + } + if (cip->cancelXfer > 0) { + DisposeFileInfoListContents(&files); + break; + } + +#if 0 + for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) { + PrintF(cip, " R=%s, L=%s, 2=%s, size=%d, mdtm=%u, type=%c\n", + filePtr->rname, + filePtr->lname, + filePtr->rlinkto ? filePtr->rlinkto : "", + filePtr->size, + (unsigned int) filePtr->mdtm, + filePtr->type + ); + } +#endif + + + for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) { + if (cip->connected == 0) { + if (batchResult == kNoErr) + batchResult = kErrRemoteHostClosedConnection; + break; + } + if (filePtr->type == 'd') { +#if defined(WIN32) || defined(_WINDOWS) + (void) MkDirs(filePtr->lname, 00777); +#else + (void) mkdir(filePtr->lname, 00777); +#endif + } else if (filePtr->type == 'l') { + /* skip it -- we do that next pass. */ + } else if (recurse1 != kRecursiveYes) { + result = FTPGetOneF(cip, filePtr->rname, filePtr->lname, xtype, -1, filePtr->size, filePtr->mdtm, resumeflag, appendflag, deleteflag, resumeProc); + if (files.nFileInfos == 1) { + if (result != kNoErr) + batchResult = result; + } else { + if ((result != kNoErr) && (result != kErrLocalFileNewer) && (result != kErrRemoteFileNewer) && (result != kErrLocalSameAsRemote)) + batchResult = result; + } + if (result == kErrUserCanceled) + cip->cancelXfer = 1; + if (cip->cancelXfer > 0) + break; + } else { + ldir = filePtr->lname; + cp = StrRFindLocalPathDelim(ldir); + if (cp != NULL) { + while (cp > ldir) { + if (! IsLocalPathDelim(*cp)) { + ++cp; + break; + } + --cp; + } + if (cp > ldir) { + c = *cp; + *cp = '\0'; + if (MkDirs(ldir, 00777) < 0) { + Error(cip, kDoPerror, "Could not create local directory \"%s\"\n", ldir); + batchResult = kErrGeneric; + *cp = c; + continue; + } + *cp = c; + } + } + result = FTPGetOneF(cip, filePtr->rname, filePtr->lname, xtype, -1, filePtr->size, filePtr->mdtm, resumeflag, appendflag, deleteflag, resumeProc); + + if (files.nFileInfos == 1) { + if (result != kNoErr) + batchResult = result; + } else { + if ((result != kNoErr) && (result != kErrLocalFileNewer) && (result != kErrRemoteFileNewer) && (result != kErrLocalSameAsRemote)) + batchResult = result; + } + if (result == kErrUserCanceled) + cip->cancelXfer = 1; + if (cip->cancelXfer > 0) + break; + } + } + if (cip->cancelXfer > 0) { + DisposeFileInfoListContents(&files); + break; + } + +#ifdef HAVE_SYMLINK + for (filePtr = files.first; filePtr != NULL; filePtr = filePtr->next) { + if (filePtr->type == 'l') { + (void) unlink(filePtr->lname); + if (symlink(filePtr->rlinkto, filePtr->lname) < 0) { + Error(cip, kDoPerror, "Could not symlink %s to %s\n", filePtr->rlinkto, filePtr->lname); + /* Note: not worth setting batchResult */ + } + } + } +#endif /* HAVE_SYMLINK */ + + + DisposeFileInfoListContents(&files); + } + + DisposeLineListContents(&globList); + if (batchResult < 0) + cip->errNo = batchResult; + errRc = batchResult; + +return_err: + if (dstdir2 != NULL) + free(dstdir2); + if (pattern2 != NULL) + free(pattern2); + return (errRc); +} /* FTPGetFiles3 */ + + + + +/*------------------------- wrappers for old routines ----------------------*/ + +int +FTPGetOneFile(const FTPCIPtr cip, const char *const file, const char *const dstfile) +{ + return (FTPGetOneFile3(cip, file, dstfile, kTypeBinary, -1, kResumeNo, kAppendNo, kDeleteNo, (ConfirmResumeDownloadProc) 0, 0)); +} /* FTPGetOneFile */ + + + + +int +FTPGetOneFile2(const FTPCIPtr cip, const char *const file, const char *const dstfile, const int xtype, const int fdtouse, const int resumeflag, const int appendflag) +{ + return (FTPGetOneFile3(cip, file, dstfile, xtype, fdtouse, resumeflag, appendflag, kDeleteNo, (ConfirmResumeDownloadProc) 0, 0)); +} /* FTPGetOneFile2 */ + + + + +int +FTPGetFiles(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob) +{ + return (FTPGetFiles3(cip, pattern, dstdir, recurse, doGlob, kTypeBinary, kResumeNo, kAppendNo, kDeleteNo, kTarYes, (ConfirmResumeDownloadProc) 0, 0)); +} /* FTPGetFiles */ + + + + +int +FTPGetFiles2(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob, const int xtype, const int resumeflag, const int appendflag) +{ + return (FTPGetFiles3(cip, pattern, dstdir, recurse, doGlob, xtype, resumeflag, appendflag, kDeleteNo, kTarYes, (ConfirmResumeDownloadProc) 0, 0)); +} /* FTPGetFiles2 */ + + + + +int +FTPGetOneFileAscii(const FTPCIPtr cip, const char *const file, const char *const dstfile) +{ + return (FTPGetOneFile3(cip, file, dstfile, kTypeAscii, -1, kResumeNo, kAppendNo, kDeleteNo, (ConfirmResumeDownloadProc) 0, 0)); +} /* FTPGetOneFileAscii */ + + + + +int +FTPGetFilesAscii(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob) +{ + return (FTPGetFiles3(cip, pattern, dstdir, recurse, doGlob, kTypeAscii, kResumeNo, kAppendNo, kDeleteNo, kTarNo, (ConfirmResumeDownloadProc) 0, 0)); +} /* FTPGetFilesAscii */ + + + + +int +FTPPutOneFile(const FTPCIPtr cip, const char *const file, const char *const dstfile) +{ + return (FTPPutOneFile3(cip, file, dstfile, kTypeBinary, -1, 0, NULL, NULL, kResumeNo, kDeleteNo, NoConfirmResumeUploadProc, 0)); +} /* FTPPutOneFile */ + + + + +int +FTPPutOneFile2(const FTPCIPtr cip, const char *const file, const char *const dstfile, const int xtype, const int fdtouse, const int appendflag, const char *const tmppfx, const char *const tmpsfx) +{ + return (FTPPutOneFile3(cip, file, dstfile, xtype, fdtouse, appendflag, tmppfx, tmpsfx, kResumeNo, kDeleteNo, NoConfirmResumeUploadProc, 0)); +} /* FTPPutOneFile2 */ + + + + +int +FTPPutFiles(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob) +{ + return (FTPPutFiles3(cip, pattern, dstdir, recurse, doGlob, kTypeBinary, 0, NULL, NULL, kResumeNo, kDeleteNo, NoConfirmResumeUploadProc, 0)); +} /* FTPPutFiles */ + + + + +int +FTPPutFiles2(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob, const int xtype, const int appendflag, const char *const tmppfx, const char *const tmpsfx) +{ + return (FTPPutFiles3(cip, pattern, dstdir, recurse, doGlob, xtype, appendflag, tmppfx, tmpsfx, kResumeNo, kDeleteNo, NoConfirmResumeUploadProc, 0)); +} /* FTPPutFiles2 */ + + + + +int +FTPPutOneFileAscii(const FTPCIPtr cip, const char *const file, const char *const dstfile) +{ + return (FTPPutOneFile3(cip, file, dstfile, kTypeAscii, -1, 0, NULL, NULL, kResumeNo, kDeleteNo, NoConfirmResumeUploadProc, 0)); +} /* FTPPutOneFileAscii */ + + + + +int +FTPPutFilesAscii(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob) +{ + return (FTPPutFiles3(cip, pattern, dstdir, recurse, doGlob, kTypeAscii, 0, NULL, NULL, kResumeNo, kDeleteNo, NoConfirmResumeUploadProc, 0)); +} /* FTPPutFilesAscii */ + + + +int +FTPListToMemory(const FTPCIPtr cip, const char *const pattern, const LineListPtr llines, const char *const lsflags) +{ + return (FTPListToMemory2(cip, pattern, llines, lsflags, 1, (int *) 0)); +} /* FTPListToMemory */ + +/* eof IO.c */ diff --git a/reactos/apps/utils/net/ncftp/libncftp/libncftp.dsp b/reactos/apps/utils/net/ncftp/libncftp/libncftp.dsp new file mode 100644 index 00000000000..0b2bcf18fb9 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/libncftp.dsp @@ -0,0 +1,160 @@ +# Microsoft Developer Studio Project File - Name="libncftp" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=libncftp - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "libncftp.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "libncftp.mak" CFG="libncftp - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libncftp - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "libncftp - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libncftp - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W4 /GX /O2 /Ob1 /I "..\Strn" /I "..\sio" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "libncftp - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\Strn" /I "..\sio" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "libncftp - Win32 Release" +# Name "libncftp - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\cmds.c +# End Source File +# Begin Source File + +SOURCE=.\errno.c +# End Source File +# Begin Source File + +SOURCE=.\ftp.c +# End Source File +# Begin Source File + +SOURCE=.\glob.c +# End Source File +# Begin Source File + +SOURCE=.\io.c +# End Source File +# Begin Source File + +SOURCE=.\linelist.c +# End Source File +# Begin Source File + +SOURCE=.\mksrczip.bat +# End Source File +# Begin Source File + +SOURCE=.\open.c +# End Source File +# Begin Source File + +SOURCE=.\rcmd.c +# End Source File +# Begin Source File + +SOURCE=.\util.c +# End Source File +# Begin Source File + +SOURCE=.\util2.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\ftp.h +# End Source File +# Begin Source File + +SOURCE=.\ncftp.h +# End Source File +# Begin Source File + +SOURCE=.\ncftp_errno.h +# End Source File +# Begin Source File + +SOURCE=.\syshdrs.h +# End Source File +# Begin Source File + +SOURCE=.\util.h +# End Source File +# Begin Source File + +SOURCE=.\wincfg.h +# End Source File +# End Group +# End Target +# End Project diff --git a/reactos/apps/utils/net/ncftp/libncftp/libncftp.dsw b/reactos/apps/utils/net/ncftp/libncftp/libncftp.dsw new file mode 100644 index 00000000000..d02da5713cb --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/libncftp.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "libncftp"=.\libncftp.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/reactos/apps/utils/net/ncftp/libncftp/linelist.c b/reactos/apps/utils/net/ncftp/libncftp/linelist.c new file mode 100644 index 00000000000..e1528af01e8 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/linelist.c @@ -0,0 +1,783 @@ +/* linelist.c + * + * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft. + * All rights reserved. + * + */ + +#include "syshdrs.h" + +/* Dynamically make a copy of a string. */ +char * +StrDup(const char *buf) +{ + char *cp; + size_t len; + + if (buf == NULL) + return (NULL); + + len = strlen(buf) + 1; + cp = (char *) malloc(len); + if (cp != NULL) + (void) memcpy(cp, buf, len); + return (cp); +} /* StrDup */ + + + +/* Disposes each node of a LineList. Does a few extra things + * so the disposed memory won't be very useful after it is freed. + */ +void +DisposeLineListContents(LineListPtr list) +{ + LinePtr lp, lp2; + + for (lp = list->first; lp != NULL; ) { + lp2 = lp; + lp = lp->next; + if (lp2->line != NULL) { + lp2->line[0] = '\0'; + free(lp2->line); + } + free(lp2); + } + /* Same as InitLineList. */ + (void) memset(list, 0, sizeof(LineList)); +} /* DisposeLineListContents */ + + + + +void +InitLineList(LineListPtr list) +{ + (void) memset(list, 0, sizeof(LineList)); +} /* InitLineList */ + + + + +LinePtr +RemoveLine(LineListPtr list, LinePtr killMe) +{ + LinePtr nextLine, prevLine; + + nextLine = killMe->next; + prevLine = killMe->prev; + if (killMe->line != NULL) { + killMe->line[0] = '\0'; /* Make it useless just in case. */ + free(killMe->line); + } + + if (list->first == killMe) + list->first = nextLine; + if (list->last == killMe) + list->last = prevLine; + + if (nextLine != NULL) + nextLine->prev = prevLine; + if (prevLine != NULL) + prevLine->next = nextLine; + + free(killMe); + list->nLines--; + return (nextLine); +} /* RemoveLine */ + + + + +/* Adds a string to the LineList specified. */ +LinePtr +AddLine(LineListPtr list, const char *buf1) +{ + LinePtr lp; + char *buf; + + lp = (LinePtr) malloc(sizeof(Line)); + if (lp != NULL) { + buf = StrDup(buf1); + if (buf == NULL) { + free(lp); + lp = NULL; + } else { + lp->line = buf; + lp->next = NULL; + if (list->first == NULL) { + list->first = list->last = lp; + lp->prev = NULL; + list->nLines = 1; + } else { + lp->prev = list->last; + list->last->next = lp; + list->last = lp; + list->nLines++; + } + } + } + return lp; +} /* AddLine */ + + + + +int +CopyLineList(LineListPtr dst, LineListPtr src) +{ + LinePtr lp, lp2; + + InitLineList(dst); + for (lp = src->first; lp != NULL; ) { + lp2 = lp; + lp = lp->next; + if (lp2->line != NULL) { + if (AddLine(dst, lp2->line) == NULL) { + DisposeLineListContents(dst); + return (-1); + } + } + } + return (0); +} /* CopyLineList */ + + + + +/* Disposes each node of a FileInfoList. Does a few extra things + * so the disposed memory won't be very useful after it is freed. + */ +void +DisposeFileInfoListContents(FileInfoListPtr list) +{ + FileInfoPtr lp, lp2; + + for (lp = list->first; lp != NULL; ) { + lp2 = lp; + lp = lp->next; + if (lp2->relname != NULL) { + lp2->relname[0] = '\0'; + free(lp2->relname); + } + if (lp2->lname != NULL) { + lp2->lname[0] = '\0'; + free(lp2->lname); + } + if (lp2->rname != NULL) { + lp2->rname[0] = '\0'; + free(lp2->rname); + } + if (lp2->rlinkto != NULL) { + lp2->rlinkto[0] = '\0'; + free(lp2->rlinkto); + } + if (lp2->plug != NULL) { + lp2->plug[0] = '\0'; + free(lp2->plug); + } + free(lp2); + } + + if (list->vec != NULL) + free(list->vec); + + /* Same as InitFileInfoList. */ + (void) memset(list, 0, sizeof(FileInfoList)); +} /* DisposeFileInfoListContents */ + + + + +void +InitFileInfoList(FileInfoListPtr list) +{ + (void) memset(list, 0, sizeof(FileInfoList)); +} /* InitFileInfoList */ + + + + +static int +TimeCmp(const void *a, const void *b) +{ + FileInfoPtr *fipa, *fipb; + + fipa = (FileInfoPtr *) a; + fipb = (FileInfoPtr *) b; + if ((**fipb).mdtm == (**fipa).mdtm) + return (0); + else if ((**fipb).mdtm < (**fipa).mdtm) + return (-1); + return (1); +} /* TimeCmp */ + + + + +static int +ReverseTimeCmp(const void *a, const void *b) +{ + FileInfoPtr *fipa, *fipb; + + fipa = (FileInfoPtr *) a; + fipb = (FileInfoPtr *) b; + if ((**fipa).mdtm == (**fipb).mdtm) + return (0); + else if ((**fipa).mdtm < (**fipb).mdtm) + return (-1); + return (1); +} /* ReverseTimeCmp */ + + + + +static int +SizeCmp(const void *a, const void *b) +{ + FileInfoPtr *fipa, *fipb; + + fipa = (FileInfoPtr *) a; + fipb = (FileInfoPtr *) b; + if ((**fipb).size == (**fipa).size) + return (0); + else if ((**fipb).size < (**fipa).size) + return (-1); + return (1); +} /* SizeCmp */ + + + + +static int +ReverseSizeCmp(const void *a, const void *b) +{ + FileInfoPtr *fipa, *fipb; + + fipa = (FileInfoPtr *) a; + fipb = (FileInfoPtr *) b; + if ((**fipa).size == (**fipb).size) + return (0); + else if ((**fipa).size < (**fipb).size) + return (-1); + return (1); +} /* ReverseSizeCmp */ + + + + +static int +ReverseNameCmp(const void *a, const void *b) +{ + FileInfoPtr *fipa, *fipb; + + fipa = (FileInfoPtr *) a; + fipb = (FileInfoPtr *) b; +#ifdef HAVE_SETLOCALE + return (strcoll((**fipb).relname, (**fipa).relname)); +#else + return (strcmp((**fipb).relname, (**fipa).relname)); +#endif +} /* ReverseNameCmp */ + + + + +static int +NameCmp(const void *a, const void *b) +{ + FileInfoPtr *fipa, *fipb; + + fipa = (FileInfoPtr *) a; + fipb = (FileInfoPtr *) b; +#ifdef HAVE_SETLOCALE + return (strcoll((**fipa).relname, (**fipb).relname)); +#else + return (strcmp((**fipa).relname, (**fipb).relname)); +#endif +} /* NameCmp */ + + + + +static int +BreadthFirstCmp(const void *a, const void *b) +{ + FileInfoPtr *fipa, *fipb; + char *cp, *cpa, *cpb; + int depth, deptha, depthb; + int c; + + fipa = (FileInfoPtr *) a; + fipb = (FileInfoPtr *) b; + + cpa = (**fipa).relname; + cpb = (**fipb).relname; + + for (cp = cpa, depth = 0;;) { + c = *cp++; + if (c == '\0') + break; + if ((c == '/') || (c == '\\')) { + depth++; + } + } + deptha = depth; + + for (cp = cpb, depth = 0;;) { + c = *cp++; + if (c == '\0') + break; + if ((c == '/') || (c == '\\')) { + depth++; + } + } + depthb = depth; + + if (deptha < depthb) + return (-1); + else if (deptha > depthb) + return (1); + +#ifdef HAVE_SETLOCALE + return (strcoll(cpa, cpb)); +#else + return (strcmp(cpa, cpb)); +#endif +} /* BreadthFirstCmp */ + + + + +void +SortFileInfoList(FileInfoListPtr list, int sortKey, int sortOrder) +{ + FileInfoVec fiv; + FileInfoPtr fip; + int i, j, n, n2; + + fiv = list->vec; + if (fiv == NULL) + return; + + if (list->sortKey == sortKey) { + if (list->sortOrder == sortOrder) + return; /* Already sorted they you want. */ + + /* Reverse the sort. */ + n = list->nFileInfos; + if (n > 1) { + n2 = n / 2; + for (i=0; isortOrder = sortOrder; + } else if ((sortKey == 'n') && (sortOrder == 'a')) { + qsort(fiv, (size_t) list->nFileInfos, sizeof(FileInfoPtr), + NameCmp); + list->sortKey = sortKey; + list->sortOrder = sortOrder; + } else if ((sortKey == 'n') && (sortOrder == 'd')) { + qsort(fiv, (size_t) list->nFileInfos, sizeof(FileInfoPtr), + ReverseNameCmp); + list->sortKey = sortKey; + list->sortOrder = sortOrder; + } else if ((sortKey == 't') && (sortOrder == 'a')) { + qsort(fiv, (size_t) list->nFileInfos, sizeof(FileInfoPtr), + TimeCmp); + list->sortKey = sortKey; + list->sortOrder = sortOrder; + } else if ((sortKey == 't') && (sortOrder == 'd')) { + qsort(fiv, (size_t) list->nFileInfos, sizeof(FileInfoPtr), + ReverseTimeCmp); + list->sortKey = sortKey; + list->sortOrder = sortOrder; + } else if ((sortKey == 's') && (sortOrder == 'a')) { + qsort(fiv, (size_t) list->nFileInfos, sizeof(FileInfoPtr), + SizeCmp); + list->sortKey = sortKey; + list->sortOrder = sortOrder; + } else if ((sortKey == 's') && (sortOrder == 'd')) { + qsort(fiv, (size_t) list->nFileInfos, sizeof(FileInfoPtr), + ReverseSizeCmp); + list->sortKey = sortKey; + list->sortOrder = sortOrder; + } else if (sortKey == 'b') { + /* This is different from the rest. */ + list->sortKey = sortKey; + list->sortOrder = sortOrder; + qsort(fiv, (size_t) list->nFileInfos, sizeof(FileInfoPtr), + BreadthFirstCmp); + } +} /* SortFileInfoList */ + + + + +void +VectorizeFileInfoList(FileInfoListPtr list) +{ + FileInfoVec fiv; + FileInfoPtr fip; + int i; + + fiv = (FileInfoVec) calloc((size_t) (list->nFileInfos + 1), sizeof(FileInfoPtr)); + if (fiv != (FileInfoVec) 0) { + for (i = 0, fip = list->first; fip != NULL; fip = fip->next, i++) + fiv[i] = fip; + list->vec = fiv; + } +} /* VectorizeFileInfoList */ + + + + +void +UnvectorizeFileInfoList(FileInfoListPtr list) +{ + FileInfoVec fiv; + FileInfoPtr fip; + int i, n; + + fiv = list->vec; + if (fiv != (FileInfoVec) 0) { + list->first = fiv[0]; + n = list->nFileInfos; + if (n > 0) { + list->last = fiv[n - 1]; + fip = fiv[0]; + fip->prev = NULL; + fip->next = fiv[1]; + for (i = 1; i < n; i++) { + fip = fiv[i]; + fip->prev = fiv[i - 1]; + fip->next = fiv[i + 1]; + } + } + free(fiv); + list->vec = (FileInfoVec) 0; + } +} /* UnvectorizeFileInfoList */ + + + + +void +InitFileInfo(FileInfoPtr fip) +{ + (void) memset(fip, 0, sizeof(FileInfo)); + fip->type = '-'; + fip->size = kSizeUnknown; + fip->mdtm = kModTimeUnknown; +} /* InitFileInfoList */ + + + + +FileInfoPtr +RemoveFileInfo(FileInfoListPtr list, FileInfoPtr killMe) +{ + FileInfoPtr nextFileInfo, prevFileInfo; + + nextFileInfo = killMe->next; + prevFileInfo = killMe->prev; + if (killMe->lname != NULL) { + killMe->lname[0] = '\0'; /* Make it useless just in case. */ + free(killMe->lname); + } + if (killMe->relname != NULL) { + killMe->relname[0] = '\0'; + free(killMe->relname); + } + if (killMe->rname != NULL) { + killMe->rname[0] = '\0'; + free(killMe->rname); + } + if (killMe->rlinkto != NULL) { + killMe->rlinkto[0] = '\0'; + free(killMe->rlinkto); + } + if (killMe->plug != NULL) { + killMe->plug[0] = '\0'; + free(killMe->plug); + } + + if (list->first == killMe) + list->first = nextFileInfo; + if (list->last == killMe) + list->last = prevFileInfo; + + if (nextFileInfo != NULL) + nextFileInfo->prev = prevFileInfo; + if (prevFileInfo != NULL) + prevFileInfo->next = nextFileInfo; + + free(killMe); + list->nFileInfos--; + return (nextFileInfo); +} /* RemoveFileInfo */ + + + + +/* Adds a string to the FileInfoList specified. */ +FileInfoPtr +AddFileInfo(FileInfoListPtr list, FileInfoPtr src) +{ + FileInfoPtr lp; + + lp = (FileInfoPtr) malloc(sizeof(FileInfo)); + if (lp != NULL) { + (void) memcpy(lp, src, sizeof(FileInfo)); + lp->next = NULL; + if (list->first == NULL) { + list->first = list->last = lp; + lp->prev = NULL; + list->nFileInfos = 1; + } else { + lp->prev = list->last; + list->last->next = lp; + list->last = lp; + list->nFileInfos++; + } + } + return lp; +} /* AddFileInfo */ + + + + +int +ConcatFileInfoList(FileInfoListPtr dst, FileInfoListPtr src) +{ + FileInfoPtr lp, lp2; + FileInfo newfi; + + for (lp = src->first; lp != NULL; lp = lp2) { + lp2 = lp->next; + newfi = *lp; + newfi.relname = StrDup(lp->relname); + newfi.lname = StrDup(lp->lname); + newfi.rname = StrDup(lp->rname); + newfi.rlinkto = StrDup(lp->rlinkto); + newfi.plug = StrDup(lp->plug); + if (AddFileInfo(dst, &newfi) == NULL) + return (-1); + } + return (0); +} /* ConcatFileInfoList */ + + + + +int +ComputeRNames(FileInfoListPtr dst, const char *dstdir, int pflag, int nochop) +{ + FileInfoPtr lp, lp2; + char *buf; + char *cp; + + if (dstdir == NULL) + dstdir = "."; + + for (lp = dst->first; lp != NULL; lp = lp2) { + lp2 = lp->next; + + buf = NULL; + if (nochop != 0) { + if ((dstdir[0] != '\0') && (strcmp(dstdir, "."))) { + if (Dynscat(&buf, dstdir, "/", lp->relname, 0) == NULL) + goto memerr; + + if (pflag != 0) { + /* Init lname to parent dir name of remote dir */ + cp = strrchr(dstdir, '/'); + if (cp == NULL) + cp = strrchr(dstdir, '\\'); + if (cp != NULL) { + if (Dynscat(&lp->lname, cp + 1, 0) == NULL) + goto memerr; + TVFSPathToLocalPath(lp->lname); + } + } + } else { + if (Dynscat(&buf, lp->relname, 0) == NULL) + goto memerr; + } + } else { + if ((dstdir[0] != '\0') && (strcmp(dstdir, "."))) { + cp = strrchr(lp->relname, '/'); + if (cp == NULL) + cp = strrchr(lp->relname, '\\'); + if (cp != NULL) { + cp++; + } else { + cp = lp->relname; + } + if (Dynscat(&buf, dstdir, "/", cp, 0) == NULL) + goto memerr; + + if (pflag != 0) { + /* Init lname to parent dir name of remote dir */ + cp = strrchr(dstdir, '/'); + if (cp == NULL) + cp = strrchr(dstdir, '\\'); + if (cp != NULL) { + if (Dynscat(&lp->lname, cp + 1, 0) == NULL) + goto memerr; + TVFSPathToLocalPath(lp->lname); + } + } + } else { + cp = strrchr(lp->relname, '/'); + if (cp == NULL) + cp = strrchr(lp->relname, '\\'); + if (cp != NULL) { + cp++; + } else { + cp = lp->relname; + } + if (Dynscat(&buf, cp, 0) == NULL) + goto memerr; + } + } + lp->rname = buf; + if (lp->rname == NULL) { +memerr: + return (-1); + } + LocalPathToTVFSPath(lp->rname); + } + return (0); +} /* ComputeRNames */ + + + + +int +ComputeLNames(FileInfoListPtr dst, const char *srcdir, const char *dstdir, int nochop) +{ + FileInfoPtr lp, lp2; + char *buf; + char *cp; + + if (srcdir != NULL) { + cp = strrchr(srcdir, '/'); + if (cp == NULL) + cp = strrchr(srcdir, '\\'); + if (cp != NULL) + srcdir = cp + 1; + } + if (dstdir == NULL) + dstdir = "."; + + for (lp = dst->first; lp != NULL; lp = lp2) { + lp2 = lp->next; + + buf = NULL; + if (nochop != 0) { + if ((dstdir[0] != '\0') && (strcmp(dstdir, "."))) { + if (Dynscat(&buf, dstdir, "/", 0) == NULL) + goto memerr; + } + if (lp->lname != NULL) { + if (Dynscat(&buf, lp->lname, "/", 0) == NULL) + goto memerr; + } else if (srcdir != NULL) { + if (Dynscat(&buf, srcdir, "/", 0) == NULL) + goto memerr; + } + if (Dynscat(&buf, lp->relname, 0) == NULL) + goto memerr; + } else { + if ((dstdir[0] != '\0') && (strcmp(dstdir, "."))) { + cp = strrchr(lp->relname, '/'); + if (cp == NULL) + cp = strrchr(lp->relname, '\\'); + if (cp == NULL) { + cp = lp->relname; + } else { + cp++; + } + if (Dynscat(&buf, dstdir, "/", cp, 0) == NULL) + goto memerr; + } else { + cp = strrchr(lp->relname, '/'); + if (cp == NULL) + cp = strrchr(lp->relname, '\\'); + if (cp == NULL) { + cp = lp->relname; + } else { + cp++; + } + if (Dynscat(&buf, cp, 0) == NULL) + goto memerr; + } + } + if (buf == NULL) { +memerr: + return (-1); + } + if (lp->lname != NULL) { + free(lp->lname); + lp->lname = NULL; + } + lp->lname = buf; + TVFSPathToLocalPath(lp->lname); + } + return (0); +} /* ComputeLNames */ + + + + +int +ConcatFileToFileInfoList(FileInfoListPtr dst, char *rfile) +{ + FileInfo newfi; + + InitFileInfo(&newfi); /* Use defaults. */ + newfi.relname = StrDup(rfile); + newfi.rname = NULL; + newfi.lname = NULL; + + if (AddFileInfo(dst, &newfi) == NULL) + return (-1); + return (0); +} /* ConcatFileToFileInfoList */ + + + + +int +LineListToFileInfoList(LineListPtr src, FileInfoListPtr dst) +{ + LinePtr lp, lp2; + + InitFileInfoList(dst); + for (lp = src->first; lp != NULL; lp = lp2) { + lp2 = lp->next; + if (ConcatFileToFileInfoList(dst, lp->line) < 0) + return (-1); + } + return (0); +} /* LineListToFileList */ + + + + +int +LineToFileInfoList(LinePtr lp, FileInfoListPtr dst) +{ + InitFileInfoList(dst); + if (ConcatFileToFileInfoList(dst, lp->line) < 0) + return (-1); + return (0); +} /* LineToFileInfoList */ + +/* eof */ diff --git a/reactos/apps/utils/net/ncftp/libncftp/mksrctar.sh b/reactos/apps/utils/net/ncftp/libncftp/mksrctar.sh new file mode 100644 index 00000000000..4d3f36db151 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/mksrctar.sh @@ -0,0 +1,97 @@ +#!/bin/sh + +if [ -f rcmd.c ] ; then + cd .. +fi +wd=`pwd` +for f in libncftp sio Strn doc ; do + if [ ! -f "$f" ] && [ ! -d "$f" ] ; then + echo "Missing directory $f ?" 1>&2 + exit 1 + fi +done + +( cd libncftp ; make clean ) + +TMPDIR=/tmp +if [ "$#" -lt 2 ] ; then + TARDIR="libncftp" + STGZFILE="$TARDIR.tar.gz" +else + TARDIR="$1" + STGZFILE="$2" +fi + +rm -rf $TMPDIR/TAR +mkdir -p -m755 $TMPDIR/TAR/$TARDIR 2>/dev/null + +chmod 755 configure sh/* install-sh 2>/dev/null + +find . -depth -follow -type f | sed ' +/sio\/configure$/d +/Strn\/configure$/d +/\.o$/d +/\.so$/d +/\.a$/d +/\.lib$/d +/\.ncb$/d +/\.pdb$/d +/\.idb$/d +/\.pch$/d +/\.ilk$/d +/\.res$/d +/\.aps$/d +/\.opt$/d +/\.plg$/d +/\.obj$/d +/\.exe$/d +/\.zip$/d +/\.gz$/d +/\.tgz$/d +/\.tar$/d +/\.swp$/d +/\.orig$/d +/\.rej$/d +/\/Makefile\.bin$/p +/\.bin$/d +/\/bin/d +/\/core$/d +/\/^[Rr]elease$/d +/\/^[Dd]ebug$/d +/\/sio\/.*\//d +/shit/d +/\/upload/d +/\/config\.h\.in$/p +/\/config\./d +/\/Makefile$/d +/\/OLD/d +/\/old/d' | cut -c3- | tee "$wd/doc/manifest.txt" | cpio -Lpdm $TMPDIR/TAR/$TARDIR + +( cd "$TMPDIR/TAR/$TARDIR" ; ln -s doc/README.txt README ) + +x=`tar --help 2>&1 | sed -n 's/.*owner=NAME.*/owner=NAME/g;/owner=NAME/p'` +case "$x" in + *owner=NAME*) + TARFLAGS="-c --owner=bin --group=bin --verbose -f" + TAR=tar + ;; + *) + TARFLAGS="cvf" + TAR=tar + x2=`gtar --help 2>&1 | sed -n 's/.*owner=NAME.*/owner=NAME/g;/owner=NAME/p'` + case "$x2" in + *owner=NAME*) + TARFLAGS="-c --owner=bin --group=bin --verbose -f" + TAR=gtar + ;; + esac + ;; +esac + +( cd $TMPDIR/TAR ; $TAR $TARFLAGS - $TARDIR | gzip -c > $STGZFILE ) +cp $TMPDIR/TAR/$STGZFILE . +chmod 644 $STGZFILE +rm -rf $TMPDIR/TAR +ls -l $STGZFILE 2>/dev/null +mv $TGZFILE newbin/ 2>/dev/null +exit 0 diff --git a/reactos/apps/utils/net/ncftp/libncftp/mksrczip.bat b/reactos/apps/utils/net/ncftp/libncftp/mksrczip.bat new file mode 100644 index 00000000000..2d73d39d6c0 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/mksrczip.bat @@ -0,0 +1,19 @@ +@echo off + +IF NOT EXIST ncftp.h GOTO ERR: + +cd .. +erase \temp\libncftp.zip >NUL +pkzip25.exe -add -204 -dir=current -excl=*.lib -excl=*.exe -excl=*.zip -excl=*.gz -excl=*.tar -excl=*.o -excl=*.obj -excl=*.pch -excl=*.ilk -excl=*.ncb -excl=*.opt -excl=*.pdb -excl=*.idb -excl=*.plg -excl=config.* -excl=*.so -excl=*.a -excl=Makefile -excl=core \temp\libncftp.zip libncftp\*.* +pkzip25.exe -add -204 -dir=current -excl=*.lib -excl=*.exe -excl=*.zip -excl=*.gz -excl=*.tar -excl=*.o -excl=*.obj -excl=*.pch -excl=*.ilk -excl=*.ncb -excl=*.opt -excl=*.pdb -excl=*.idb -excl=*.plg -excl=config.* -excl=*.so -excl=*.a -excl=Makefile -excl=core \temp\libncftp.zip sio\*.* +pkzip25.exe -add -204 -dir=current -excl=*.lib -excl=*.exe -excl=*.zip -excl=*.gz -excl=*.tar -excl=*.o -excl=*.obj -excl=*.pch -excl=*.ilk -excl=*.ncb -excl=*.opt -excl=*.pdb -excl=*.idb -excl=*.plg -excl=config.* -excl=*.so -excl=*.a -excl=Makefile -excl=core \temp\libncftp.zip Strn\*.* + +cd libncftp +dir \temp\libncftp.zip + +GOTO DONE: + +:ERR +echo Please cd to the source directory and then run this script. + +:DONE \ No newline at end of file diff --git a/reactos/apps/utils/net/ncftp/libncftp/ncftp.h b/reactos/apps/utils/net/ncftp/libncftp/ncftp.h new file mode 100644 index 00000000000..aa15802db2c --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/ncftp.h @@ -0,0 +1,691 @@ +/* ncftp.h + * + * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft. + * All rights reserved. + * + */ + +#ifndef _ncftp_h_ +#define _ncftp_h_ 1 + +#define kLibraryVersion "@(#) LibNcFTP 3.0.6 (April 14, 2001)" + +#if defined(WIN32) || defined(_WINDOWS) +# define longest_int LONGLONG +# define longest_uint ULONGLONG +# ifndef HAVE_LONG_LONG +# define HAVE_LONG_LONG 1 +# endif +# ifndef SCANF_LONG_LONG +# define SCANF_LONG_LONG "%I64d" +# endif +# ifndef PRINTF_LONG_LONG +# define PRINTF_LONG_LONG "%I64d" +# endif +# ifndef PRINTF_LONG_LONG_I64D +# define PRINTF_LONG_LONG_I64D 1 +# endif +# ifndef SCANF_LONG_LONG_I64D +# define SCANF_LONG_LONG_I64D 1 +# endif +# ifndef USE_SIO +# define USE_SIO 1 +# endif +# ifndef NO_SIGNALS +# define NO_SIGNALS 1 +# endif +#else +# include +# include +# if !defined(__ultrix) || !defined(XTI) +# include +# endif +# include +# if 1 /* %config1% -- set by configure script -- do not modify */ +# ifndef USE_SIO +# define USE_SIO 1 +# endif +# ifndef NO_SIGNALS +# define NO_SIGNALS 1 +# endif +# else +# ifndef USE_SIO +# define USE_SIO 0 +# endif + /* #undef NO_SIGNALS */ +# endif +#endif + +#include "ncftp_errno.h" + +/* This is used to verify validty of the data passed in. + * It also specifies the minimum version that is binary-compatibile with + * this version. (So this may not necessarily be kLibraryVersion.) + */ +#define kLibraryMagic "LibNcFTP 3.0.6" + +#ifndef longest_int +#define longest_int long long +#define longest_uint unsigned long long +#endif + +#ifndef forever +# define forever for ( ; ; ) +#endif + +typedef void (*FTPSigProc)(int); + +typedef struct Line *LinePtr; +typedef struct Line { + LinePtr prev, next; + char *line; +} Line; + +typedef struct LineList { + LinePtr first, last; + int nLines; +} LineList, *LineListPtr; + +typedef struct Response { + LineList msg; + int codeType; + int code; + int printMode; + int eofOkay; + int hadEof; +} Response, *ResponsePtr; + +#if USE_SIO && !defined(_SReadlineInfo_) +#define _SReadlineInfo_ 1 +typedef struct SReadlineInfo { + char *buf; /* Pointer to beginning of buffer. */ + char *bufPtr; /* Pointer to current position in buffer. */ + char *bufLim; /* Pointer to end of buffer. */ + size_t bufSize; /* Current size of buffer block. */ + size_t bufSizeMax; /* Maximum size available for buffer. */ + int malloc; /* If non-zero, malloc() was used for buf. */ + int fd; /* File descriptor to use for I/O. */ + int timeoutLen; /* Timeout to use, in seconds. */ + int requireEOLN; /* When buffer is full, continue reading and discarding until \n? */ +} SReadlineInfo; +#endif + +typedef struct FTPLibraryInfo { + char magic[16]; /* Don't modify this field. */ + int init; /* Don't modify this field. */ + int socksInit; /* Don't modify this field. */ + unsigned int defaultPort; /* Don't modify this field. */ + char ourHostName[64]; /* Don't modify this field. */ + int hresult; /* Don't modify this field. */ + int htried; /* Don't modify this field. */ + char defaultAnonPassword[80]; /* You may set this after init. */ +} FTPLibraryInfo, *FTPLIPtr; + +typedef struct FTPConnectionInfo *FTPCIPtr; +typedef void (*FTPProgressMeterProc)(const FTPCIPtr, int); +typedef void (*FTPLogProc)(const FTPCIPtr, char *); +typedef void (*FTPConnectMessageProc)(const FTPCIPtr, ResponsePtr); +typedef void (*FTPLoginMessageProc)(const FTPCIPtr, ResponsePtr); +typedef void (*FTPRedialStatusProc)(const FTPCIPtr, int, int); +typedef void (*FTPPrintResponseProc)(const FTPCIPtr, ResponsePtr); +typedef int (*FTPFtwProc)(const FTPCIPtr cip, const char *fn, int flag); +typedef void (*FTPGetPassphraseProc)(const FTPCIPtr, LineListPtr pwPrompt, char *pass, size_t dsize); + +typedef struct FTPConnectionInfo { + char magic[16]; /* Don't modify this field. */ + char host[64]; /* REQUIRED input parameter. */ + char user[64]; /* OPTIONAL input parameter. */ + char pass[64]; /* OPTIONAL input parameter. */ + char acct[64]; /* OPTIONAL input parameter. */ + unsigned int port; /* OPTIONAL input parameter. */ + unsigned int xferTimeout; /* OPTIONAL input parameter. */ + unsigned int connTimeout; /* OPTIONAL input parameter. */ + unsigned int ctrlTimeout; /* OPTIONAL input parameter. */ + unsigned int abortTimeout; /* OPTIONAL input parameter. */ + FILE *debugLog; /* OPTIONAL input parameter. */ + FILE *errLog; /* OPTIONAL input parameter. */ + FTPLogProc debugLogProc; /* OPTIONAL input parameter. */ + FTPLogProc errLogProc; /* OPTIONAL input parameter. */ + FTPLIPtr lip; /* Do not modify this field. */ + int maxDials; /* OPTIONAL input parameter. */ + int redialDelay; /* OPTIONAL input parameter. */ + int dataPortMode; /* OPTIONAL input parameter. */ + char actualHost[64]; /* Do not modify this field. */ + char ip[32]; /* Do not modify this field. */ + int connected; /* Do not modify this field. */ + int loggedIn; /* Do not modify this field. */ + int curTransferType; /* Do not modify this field. */ + char *startingWorkingDirectory; /* Use, but do not modify. */ + longest_int startPoint; /* Do not modify this field. */ + int hasPASV; /* Do not modify this field. */ + int hasSIZE; /* Do not modify this field. */ + int hasMDTM; /* Do not modify this field. */ + int hasREST; /* Do not modify this field. */ + int hasNLST_d; /* Do not modify this field. */ + int hasUTIME; /* Do not modify this field. */ + int hasFEAT; /* Do not modify this field. */ + int hasMLSD; /* Do not modify this field. */ + int hasMLST; /* Do not modify this field. */ + int usedMLS; /* Do not modify this field. */ + int hasCLNT; /* Do not modify this field. */ + int hasRETRBUFSIZE; /* Do not modify this field. */ + int hasRBUFSIZ; /* Do not modify this field. */ + int hasRBUFSZ; /* Do not modify this field. */ + int hasSTORBUFSIZE; /* Do not modify this field. */ + int hasSBUFSIZ; /* Do not modify this field. */ + int hasSBUFSZ; /* Do not modify this field. */ + int hasBUFSIZE; /* Do not modify this field. */ + int mlsFeatures; /* Do not modify this field. */ + int STATfileParamWorks; /* Do not modify this field. */ + int NLSTfileParamWorks; /* Do not modify this field. */ + struct sockaddr_in servCtlAddr; /* Do not modify this field. */ + struct sockaddr_in servDataAddr; /* Do not modify this field. */ + struct sockaddr_in ourCtlAddr; /* Do not modify this field. */ + struct sockaddr_in ourDataAddr; /* Do not modify this field. */ + int netMode; /* Do not use or modify. */ + char *buf; /* Do not modify this field. */ + size_t bufSize; /* Do not modify this field. */ + FILE *cin; /* Do not use or modify. */ + FILE *cout; /* Do not use or modify. */ + int ctrlSocketR; /* You may use but not modify/close. */ + int ctrlSocketW; /* You may use but not modify/close. */ + int dataSocket; /* You may use but not modify/close. */ + int errNo; /* You may modify this if you want. */ + unsigned short ephemLo; /* You may modify this if you want. */ + unsigned short ephemHi; /* You may modify this if you want. */ + int cancelXfer; /* You may modify this. */ + longest_int bytesTransferred; /* Do not modify this field. */ + FTPProgressMeterProc progress; /* You may modify this if you want. */ + int useProgressMeter; /* Used internally. */ + int leavePass; /* You may modify this. */ + double sec; /* Do not modify this field. */ + double secLeft; /* Do not modify this field. */ + double kBytesPerSec; /* Do not modify this field. */ + double percentCompleted; /* Do not modify this field. */ + longest_int expectedSize; /* Do not modify this field. */ + time_t mdtm; /* Do not modify this field. */ + time_t nextProgressUpdate; /* Do not modify this field. */ + const char *rname; /* Do not modify this field. */ + const char *lname; /* Do not modify this field. */ + struct timeval t0; /* Do not modify this field. */ + int stalled; /* Do not modify this field. */ + int dataTimedOut; /* Do not modify this field. */ + int eofOkay; /* Do not use or modify. */ + char lastFTPCmdResultStr[128]; /* You may modify this if you want. */ + LineList lastFTPCmdResultLL; /* Use, but do not modify. */ + int lastFTPCmdResultNum; /* You may modify this if you want. */ + char firewallHost[64]; /* You may modify this. */ + char firewallUser[64]; /* You may modify this. */ + char firewallPass[64]; /* You may modify this. */ + unsigned int firewallPort; /* You may modify this. */ + int firewallType; /* You may modify this. */ + int require20; /* You may modify this. */ + int usingTAR; /* Use, but do not modify. */ + FTPConnectMessageProc onConnectMsgProc; /* You may modify this. */ + FTPRedialStatusProc redialStatusProc; /* You may modify this. */ + FTPPrintResponseProc printResponseProc; /* You may modify this. */ + FTPLoginMessageProc onLoginMsgProc; /* You may modify this. */ + size_t ctrlSocketRBufSize; /* You may modify this. */ + size_t ctrlSocketSBufSize; /* You may modify this. */ + size_t dataSocketRBufSize; /* You may modify this. */ + size_t dataSocketSBufSize; /* You may modify this. */ + int serverType; /* Do not use or modify. */ + int ietfCompatLevel; /* Do not use or modify. */ + int numDownloads; /* Do not use or modify. */ + int numUploads; /* Do not use or modify. */ + int numListings; /* Do not use or modify. */ + int doNotGetStartingWorkingDirectory; /* You may modify this. */ +#if USE_SIO + char srlBuf[768]; + SReadlineInfo ctrlSrl; /* Do not use or modify. */ +#endif + FTPGetPassphraseProc passphraseProc; /* You may modify this. */ + int iUser; /* Scratch integer field you can use. */ + void *pUser; /* Scratch pointer field you can use. */ + longest_int llUser; /* Scratch long long field you can use. */ + const char *asciiFilenameExtensions; /* You may assign this. */ + int reserved[32]; /* Do not use or modify. */ +} FTPConnectionInfo; + +typedef struct FileInfo *FileInfoPtr, **FileInfoVec; +typedef struct FileInfo { + FileInfoPtr prev, next; + char *relname; + char *rname; + char *rlinkto; + char *lname; + char *plug; /* permissions, links, user, group */ + int type; + time_t mdtm; + longest_int size; + size_t relnameLen; +} FileInfo; + +typedef struct FileInfoList { + FileInfoPtr first, last; + FileInfoVec vec; + size_t maxFileLen; + size_t maxPlugLen; + int nFileInfos; + int sortKey; + int sortOrder; +} FileInfoList, *FileInfoListPtr; + +/* Used with UnMlsT() */ +typedef struct MLstItem{ + char fname[512]; + char linkto[512]; + int ftype; + longest_int fsize; + time_t ftime; + int mode; /* "UNIX.mode" fact */ + int uid; /* "UNIX.uid" fact */ + int gid; /* "UNIX.gid" fact */ + char perm[16]; /* "perm" fact */ + char owner[16]; /* "UNIX.owner" fact */ + char group[16]; /* "UNIX.group" fact */ +} MLstItem, *MLstItemPtr; + +/* Messages we pass to the current progress meter function. */ +#define kPrInitMsg 1 +#define kPrUpdateMsg 2 +#define kPrEndMsg 3 + +/* Parameter for OpenDataConnection() */ +#define kSendPortMode 0 +#define kPassiveMode 1 +#define kFallBackToSendPortMode 2 + +/* Parameter for AcceptDataConnection() */ +#define kAcceptForWriting 00100 +#define kAcceptForReading 00101 +#define kNetWriting kAcceptForWriting +#define kNetReading kAcceptForReading + +/* Value for printMode field of Response structure. + * Generally, don't worry about this. + */ +#define kResponseNoPrint 00001 +#define kResponseNoSave 00002 +#define kResponseNoProc 00002 + +#define kDefaultFTPPort 21 + +#define kDefaultFTPBufSize 32768 + +#ifdef USE_SIO +/* This version of the library can handle timeouts without + * a user-installed signal handler. + */ +#define kDefaultXferTimeout 600 +#define kDefaultConnTimeout 30 +#define kDefaultCtrlTimeout 135 +#define kDefaultAbortTimeout 10 +#else +/* The library doesn't use timeouts by default because it would + * break apps that don't have a SIGALRM handler. + */ +#define kDefaultXferTimeout (0) /* No timeout. */ +#define kDefaultConnTimeout (0) /* No timeout. */ +#define kDefaultCtrlTimeout (0) /* No timeout. */ +#define kDefaultAbortTimeout 10 +#endif + + +/* Suggested timeout values, in seconds, if you use timeouts. */ +#define kSuggestedDefaultXferTimeout (0) /* No timeout on data blocks. */ +#define kSuggestedDefaultConnTimeout 30 +#define kSuggestedDefaultCtrlTimeout 135 /* 2*MSL, + slop */ +#define kSuggestedAbortTimeout 10 + +#define kDefaultMaxDials 3 +#define kDefaultRedialDelay 20 /* seconds */ + +#define kDefaultDataPortMode kSendPortMode + +#define kRedialStatusDialing 0 +#define kRedialStatusSleeping 1 + +#ifndef INADDR_NONE +# define INADDR_NONE (0xffffffff) /* should have it. */ +#endif + +#define kTypeAscii 'A' +#define kTypeBinary 'I' +#define kTypeEbcdic 'E' + +#define kGlobChars "[*?" +#define GLOBCHARSINSTR(a) (strpbrk(a, kGlobChars) != NULL) + +#define kGlobYes 1 +#define kGlobNo 0 +#define kRecursiveYes 1 +#define kRecursiveNo 0 +#define kAppendYes 1 +#define kAppendNo 0 +#define kResumeYes 1 +#define kResumeNo 0 +#define kDeleteYes 1 +#define kDeleteNo 0 +#define kTarYes 1 +#define kTarNo 0 + +#define UNIMPLEMENTED_CMD(a) ((a == 500) || (a == 502) || (a == 504)) + +/* Possible values returned by GetDateAndTime. */ +#define kSizeUnknown ((longest_int) (-1)) +#define kModTimeUnknown ((time_t) (-1)) + +#define kCommandAvailabilityUnknown (-1) +#define kCommandAvailable 1 +#define kCommandNotAvailable 0 + +/* Values returned by FTPDecodeURL. */ +#define kNotURL (-1) +#define kMalformedURL (-2) + +/* Values for the firewall/proxy open. */ +#define kFirewallNotInUse 0 +#define kFirewallUserAtSite 1 +#define kFirewallLoginThenUserAtSite 2 +#define kFirewallSiteSite 3 +#define kFirewallOpenSite 4 +#define kFirewallUserAtUserPassAtPass 5 +#define kFirewallFwuAtSiteFwpUserPass 6 +#define kFirewallUserAtSiteFwuPassFwp 7 +#define kFirewallLastType kFirewallUserAtSiteFwuPassFwp + +/* For MLSD, MLST, and STAT. */ +#define kPreferredMlsOpts (kMlsOptType | kMlsOptSize | kMlsOptModify | kMlsOptUNIXmode | kMlsOptUNIXowner | kMlsOptUNIXgroup | kMlsOptUNIXuid | kMlsOptUNIXgid | kMlsOptPerm) + +#define kMlsOptType 00001 +#define kMlsOptSize 00002 +#define kMlsOptModify 00004 +#define kMlsOptUNIXmode 00010 +#define kMlsOptUNIXowner 00020 +#define kMlsOptUNIXgroup 00040 +#define kMlsOptPerm 00100 +#define kMlsOptUNIXuid 00200 +#define kMlsOptUNIXgid 00400 +#define kMlsOptUnique 01000 + +/* For FTPFtw(). */ +#define kFtwFile 0 +#define kFtwDir 1 + +/* For FTPChdir3(). */ +#define kChdirOnly 00000 +#define kChdirAndMkdir 00001 +#define kChdirAndGetCWD 00002 +#define kChdirOneSubdirAtATime 00004 + +/* Return codes for custom ConfirmResumeDownloadProcs. */ +#define kConfirmResumeProcNotUsed 0 +#define kConfirmResumeProcSaidSkip 1 +#define kConfirmResumeProcSaidResume 2 +#define kConfirmResumeProcSaidOverwrite 3 +#define kConfirmResumeProcSaidAppend 4 +#define kConfirmResumeProcSaidBestGuess 5 +#define kConfirmResumeProcSaidCancel 6 + +typedef int (*ConfirmResumeDownloadProc)( + const char *volatile *localpath, + volatile longest_int localsize, + volatile time_t localmtime, + const char *volatile remotepath, + volatile longest_int remotesize, + volatile time_t remotetime, + volatile longest_int *volatile startPoint +); + +typedef int (*ConfirmResumeUploadProc)( + const char *volatile localpath, + volatile longest_int localsize, + volatile time_t localmtime, + const char *volatile *remotepath, + volatile longest_int remotesize, + volatile time_t remotetime, + volatile longest_int *volatile startPoint +); + +#define NoConfirmResumeDownloadProc ((ConfirmResumeDownloadProc) 0) +#define NoConfirmResumeUploadProc ((ConfirmResumeUploadProc) 0) +#define NoGetPassphraseProc ((FTPGetPassphraseProc) 0) + +/* Types of FTP server software. + * + * We try to recognize a few of these, for information + * only, and occasional uses to determine some additional + * or broken functionality. + */ +#define kServerTypeUnknown 0 +#define kServerTypeWuFTPd 1 +#define kServerTypeNcFTPd 2 +#define kServerTypeProFTPD 3 +#define kServerTypeMicrosoftFTP 4 +#define kServerTypeWarFTPd 5 +#define kServerTypeServ_U 6 +#define kServerTypeWFTPD 7 +#define kServerTypeVFTPD 8 +#define kServerTypeFTP_Max 9 +#define kServerTypeRoxen 10 +#define kServerTypeNetWareFTP 11 +#define kServerTypeWS_FTP 12 + + +#if !defined(WIN32) && !defined(_WINDOWS) && !defined(closesocket) +# define closesocket close +#endif + +#if !defined(WIN32) && !defined(_WINDOWS) && !defined(ioctlsocket) +# define ioctlsocket ioctl +#endif + +#if defined(WIN32) || defined(_WINDOWS) +# define LOCAL_PATH_DELIM '\\' +# define LOCAL_PATH_DELIM_STR "\\" +# define LOCAL_PATH_ALTDELIM '/' +# define IsLocalPathDelim(c) ((c == LOCAL_PATH_DELIM) || (c == LOCAL_PATH_ALTDELIM)) +# define UNC_PATH_PREFIX "\\\\" +# define IsUNCPrefixed(s) (IsLocalPathDelim(s[0]) && IsLocalPathDelim(s[1])) +#else +# define LOCAL_PATH_DELIM '/' +# define LOCAL_PATH_DELIM_STR "/" +# define StrFindLocalPathDelim(a) strchr(a, LOCAL_PATH_DELIM) +# define StrRFindLocalPathDelim(a) strrchr(a, LOCAL_PATH_DELIM) +# define StrRemoveTrailingLocalPathDelim StrRemoveTrailingSlashes +# define IsLocalPathDelim(c) (c == LOCAL_PATH_DELIM) +# define TVFSPathToLocalPath(s) +# define LocalPathToTVFSPath(s) +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#ifndef _libncftp_ftp_c_ +extern char gLibNcFTPVersion[64]; +#endif + +#ifndef _libncftp_errno_c_ +extern int gLibNcFTP_Uses_Me_To_Quiet_Variable_Unused_Warnings; +#endif + +#if (defined(__GNUC__)) && (__GNUC__ >= 2) +# ifndef UNUSED +# define UNUSED(a) a __attribute__ ((unused)) +# endif +# define LIBNCFTP_USE_VAR(a) +#else +# define LIBNCFTP_USE_VAR(a) gLibNcFTP_Uses_Me_To_Quiet_Variable_Unused_Warnings = (a == 0) +# ifndef UNUSED +# define UNUSED(a) a +# endif +#endif + +/* Public routines */ +void FTPAbortDataTransfer(const FTPCIPtr cip); +int FTPChdir(const FTPCIPtr cip, const char *const cdCwd); +int FTPChdirAndGetCWD(const FTPCIPtr cip, const char *const cdCwd, char *const newCwd, const size_t newCwdSize); +int FTPChdir3(FTPCIPtr cip, const char *const cdCwd, char *const newCwd, const size_t newCwdSize, int flags); +int FTPChmod(const FTPCIPtr cip, const char *const pattern, const char *const mode, const int doGlob); +int FTPCloseHost(const FTPCIPtr cip); +int FTPCmd(const FTPCIPtr cip, const char *const cmdspec, ...) +#if (defined(__GNUC__)) && (__GNUC__ >= 2) +__attribute__ ((format (printf, 2, 3))) +#endif +; +int FTPDecodeURL(const FTPCIPtr cip, char *const url, LineListPtr cdlist, char *const fn, const size_t fnsize, int *const xtype, int *const wantnlst); +int FTPDelete(const FTPCIPtr cip, const char *const pattern, const int recurse, const int doGlob); +int FTPFileExists(const FTPCIPtr cip, const char *const file); +int FTPFileModificationTime(const FTPCIPtr cip, const char *const file, time_t *const mdtm); +int FTPFileSize(const FTPCIPtr cip, const char *const file, longest_int *const size, const int type); +int FTPFileSizeAndModificationTime(const FTPCIPtr cip, const char *const file, longest_int *const size, const int type, time_t *const mdtm); +int FTPFileType(const FTPCIPtr cip, const char *const file, int *const ftype); +int FTPGetCWD(const FTPCIPtr cip, char *const newCwd, const size_t newCwdSize); +int FTPGetFiles3(const FTPCIPtr cip, const char *pattern, const char *const dstdir, const int recurse, int doGlob, const int xtype, const int resumeflag, int appendflag, const int deleteflag, const int tarflag, const ConfirmResumeDownloadProc resumeProc, int reserved); +int FTPGetOneFile3(const FTPCIPtr cip, const char *const file, const char *const dstfile, const int xtype, const int fdtouse, const int resumeflag, const int appendflag, const int deleteflag, const ConfirmResumeDownloadProc resumeProc, int reserved); +int FTPInitConnectionInfo(const FTPLIPtr lip, const FTPCIPtr cip, size_t bufsize); +int FTPInitLibrary(const FTPLIPtr lip); +int FTPIsDir(const FTPCIPtr cip, const char *const dir); +int FTPIsRegularFile(const FTPCIPtr cip, const char *const file); +int FTPList(const FTPCIPtr cip, const int outfd, const int longMode, const char *const lsflag); +int FTPListToMemory(const FTPCIPtr cip, const char *const pattern, const LineListPtr llines, const char *const lsflags); +int FTPLocalGlob(FTPCIPtr cip, LineListPtr fileList, const char *pattern, int doGlob); +int FTPLoginHost(const FTPCIPtr cip); +int FTPMkdir(const FTPCIPtr cip, const char *const newDir, const int recurse); +int FTPMkdir2(const FTPCIPtr cip, const char *const newDir, const int recurse, const char *const curDir); +int FTPOpenHost(const FTPCIPtr cip); +int FTPOpenHostNoLogin(const FTPCIPtr cip); +void FTPPerror(const FTPCIPtr cip, const int err, const int eerr, const char *const s1, const char *const s2); +int FTPPutOneFile3(const FTPCIPtr cip, const char *const file, const char *const dstfile, const int xtype, const int fdtouse, const int appendflag, const char *const tmppfx, const char *const tmpsfx, const int resumeflag, const int deleteflag, const ConfirmResumeUploadProc resumeProc, int reserved); +int FTPPutFiles3(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob, const int xtype, int appendflag, const char *const tmppfx, const char *const tmpsfx, const int resumeflag, const int deleteflag, const ConfirmResumeUploadProc resumeProc, int reserved); +int FTPRemoteGlob(FTPCIPtr cip, LineListPtr fileList, const char *pattern, int doGlob); +int FTPRename(const FTPCIPtr cip, const char *const oldname, const char *const newname); +int FTPRmdir(const FTPCIPtr cip, const char *const pattern, const int recurse, const int doGlob); +void FTPShutdownHost(const FTPCIPtr cip); +const char *FTPStrError(int e); +int FTPSymlink(const FTPCIPtr cip, const char *const lfrom, const char *const lto); +int FTPUmask(const FTPCIPtr cip, const char *const umsk); +int FTPUtime(const FTPCIPtr cip, const char *const file, time_t actime, time_t modtime, time_t crtime); + +/* LineList routines */ +int CopyLineList(LineListPtr, LineListPtr); +void DisposeLineListContents(LineListPtr); +void InitLineList(LineListPtr); +LinePtr RemoveLine(LineListPtr, LinePtr); +LinePtr AddLine(LineListPtr, const char *); + +/* Other routines that might be useful. */ +char *StrDup(const char *); +char *FGets(char *, size_t, FILE *); +void GetHomeDir(char *, size_t); +void GetUsrName(char *, size_t); +void Scramble(unsigned char *dst, size_t dsize, unsigned char *src, char *key); +time_t UnMDTMDate(char *); +int MkDirs(const char *const, int mode1); +char *GetPass(const char *const prompt); +int FilenameExtensionIndicatesASCII(const char *const pathName, const char *const extnList); +void StrRemoveTrailingSlashes(char *dst); +#if defined(WIN32) || defined(_WINDOWS) +char *StrFindLocalPathDelim(const char *src); +char *StrRFindLocalPathDelim(const char *src); +void StrRemoveTrailingLocalPathDelim(char *dst); +void TVFSPathToLocalPath(char *dst); +void LocalPathToTVFSPath(char *dst); +int gettimeofday(struct timeval *const tp, void *junk); +void WinSleep(unsigned int seconds); +#endif + +#ifdef HAVE_SIGACTION +void (*NcSignal(int signum, void (*handler)(int)))(int); +#elif !defined(NcSignal) +# define NcSignal signal +#endif + +/* Obselete routines. */ +int FTPGetOneFile(const FTPCIPtr cip, const char *const file, const char *const dstfile); +int FTPGetOneFile2(const FTPCIPtr cip, const char *const file, const char *const dstfile, const int xtype, const int fdtouse, const int resumeflag, const int appendflag); +int FTPGetFiles(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob); +int FTPGetFiles2(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob, const int xtype, const int resumeflag, const int appendflag); +int FTPGetOneFileAscii(const FTPCIPtr cip, const char *const file, const char *const dstfile); +int FTPGetFilesAscii(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob); +int FTPPutOneFile(const FTPCIPtr cip, const char *const file, const char *const dstfile); +int FTPPutOneFile2(const FTPCIPtr cip, const char *const file, const char *const dstfile, const int xtype, const int fdtouse, const int appendflag, const char *const tmppfx, const char *const tmpsfx); +int FTPPutFiles(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob); +int FTPPutFiles2(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob, const int xtype, const int appendflag, const char *const tmppfx, const char *const tmpsfx); +int FTPPutOneFileAscii(const FTPCIPtr cip, const char *const file, const char *const dstfile); +int FTPPutFilesAscii(const FTPCIPtr cip, const char *const pattern, const char *const dstdir, const int recurse, const int doGlob); + +/* Private routines, or stuff for testing */ +char *FTPGetLocalCWD(char *buf, size_t size); +int FTPQueryFeatures(const FTPCIPtr); +int FTPMListOneFile(const FTPCIPtr cip, const char *const file, const MLstItemPtr mlip); +void FTPInitializeOurHostName(const FTPLIPtr); +void FTPInitializeAnonPassword(const FTPLIPtr); +int FTPListToMemory2(const FTPCIPtr cip, const char *const pattern, const LineListPtr llines, const char *const lsflags, const int blanklines, int *const tryMLSD); +void FTPInitIOTimer(const FTPCIPtr); +int FTPStartDataCmd(const FTPCIPtr, int, int, longest_int, const char *,...) +#if (defined(__GNUC__)) && (__GNUC__ >= 2) +__attribute__ ((format (printf, 5, 6))) +#endif +; +void FTPStartIOTimer(const FTPCIPtr); +void FTPStopIOTimer(const FTPCIPtr); +void FTPUpdateIOTimer(const FTPCIPtr); +int FTPSetTransferType(const FTPCIPtr, int); +int FTPEndDataCmd(const FTPCIPtr, int); +int FTPRemoteHelp(const FTPCIPtr, const char *const, const LineListPtr); +int FTPCmdNoResponse(const FTPCIPtr, const char *const cmdspec,...) +#if (defined(__GNUC__)) && (__GNUC__ >= 2) +__attribute__ ((format (printf, 2, 3))) +#endif +; +int WaitResponse(const FTPCIPtr, unsigned int); +int FTPLocalRecursiveFileList(FTPCIPtr, LineListPtr, FileInfoListPtr); +int FTPLocalRecursiveFileList2(FTPCIPtr cip, LineListPtr fileList, FileInfoListPtr files, int erelative); +int FTPRemoteRecursiveFileList(FTPCIPtr, LineListPtr, FileInfoListPtr); +int FTPRemoteRecursiveFileList1(FTPCIPtr, char *const, FileInfoListPtr); +int FTPRebuildConnectionInfo(const FTPLIPtr lip, const FTPCIPtr cip); +int FTPFileExistsStat(const FTPCIPtr cip, const char *const file); +int FTPFileExistsNlst(const FTPCIPtr cip, const char *const file); +int FTPFileExists2(const FTPCIPtr cip, const char *const file, const int tryMDTM, const int trySIZE, const int tryMLST, const int trySTAT, const int tryNLST); +int FTPFtw(const FTPCIPtr cip, const char *const dir, FTPFtwProc proc, int maxdepth); +int BufferGets(char *, size_t, int, char *, char **, char **, size_t); +void DisposeFileInfoListContents(FileInfoListPtr); +void InitFileInfoList(FileInfoListPtr); +void InitFileInfo(FileInfoPtr); +FileInfoPtr RemoveFileInfo(FileInfoListPtr, FileInfoPtr); +FileInfoPtr AddFileInfo(FileInfoListPtr, FileInfoPtr); +void SortFileInfoList(FileInfoListPtr, int, int); +void VectorizeFileInfoList(FileInfoListPtr); +void UnvectorizeFileInfoList(FileInfoListPtr); +int ComputeRNames(FileInfoListPtr, const char *, int, int); +int ComputeLNames(FileInfoListPtr, const char *, const char *, int); +int ConcatFileInfoList(FileInfoListPtr, FileInfoListPtr); +int ConcatFileToFileInfoList(FileInfoListPtr, char *); +int LineListToFileInfoList(LineListPtr, FileInfoListPtr); +int LineToFileInfoList(LinePtr, FileInfoListPtr); +void URLCopyToken(char *, size_t, const char *, size_t); +int UnMlsT(const char *const, const MLstItemPtr); +int UnMlsD(FileInfoListPtr, LineListPtr); +int UnLslR(FileInfoListPtr, LineListPtr, int); +void TraceResponse(const FTPCIPtr, ResponsePtr); +void PrintResponse(const FTPCIPtr, LineListPtr); +void DoneWithResponse(const FTPCIPtr, ResponsePtr); +ResponsePtr InitResponse(void); +void ReInitResponse(const FTPCIPtr, ResponsePtr); +int GetTelnetString(const FTPCIPtr, char *, size_t, FILE *, FILE *); +int GetResponse(const FTPCIPtr, ResponsePtr); +int RCmd(const FTPCIPtr, ResponsePtr, const char *, ...) +#if (defined(__GNUC__)) && (__GNUC__ >= 2) +__attribute__ ((format (printf, 3, 4))) +#endif +; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _ncftp_h_ */ diff --git a/reactos/apps/utils/net/ncftp/libncftp/ncftp_errno.h b/reactos/apps/utils/net/ncftp/libncftp/ncftp_errno.h new file mode 100644 index 00000000000..21ab09d1111 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/ncftp_errno.h @@ -0,0 +1,113 @@ +/* ncftp_errno.h + * + * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft. + * All rights reserved. + * + */ + +#ifndef kNoErr +# define kNoErr 0 +#endif + +#ifndef kErrGeneric +# define kErrGeneric (-1) +#endif + +#define kErrFirst (100) +#define kErrGetHostNameFailed (-100) +#define kErrHostWithoutDomain (-101) +#define kErrSetLinger (-102) +#define kErrSetTypeOfService (-103) +#define kErrSetOutOfBandInline (-104) +#define kErrHostUnknown (-105) +#define kErrNewStreamSocket (-106) +#define kErrDupSocket (-107) +#define kErrFdopenR (-108) +#define kErrFdopenW (-109) +#define kErrGetSockName (-110) +#define kErrBindDataSocket (-111) +#define kErrListenDataSocket (-112) +#define kErrPassiveModeFailed (-113) +#define kErrServerSentBogusPortNumber (-114) +#define kErrConnectDataSocket (-115) +#define kErrAcceptDataSocket (-116) +#define kErrSetStartPoint (-117) +#define kErrConnectMiscErr (-118) +#define kErrConnectRetryableErr (-119) +#define kErrConnectRefused (-120) +#define kErrBadTransferType (-121) +#define kErrInvalidDirParam (-122) +#define kErrMallocFailed (-123) +#define kErrPWDFailed (-124) +#define kErrCWDFailed (-125) +#define kErrRMDFailed (-126) +#define kErrBadLineList (-127) +#define kErrUnimplementedOption (-128) +#define kErrUnimplementedFunction (-129) +#define kErrLISTFailed (-130) +#define kErrRETRFailed (-131) +#define kErrSTORFailed (-132) +#define kErrWriteFailed (-133) +#define kErrReadFailed (-134) +#define kErrSocketWriteFailed (-135) +#define kErrSocketReadFailed (-136) +#define kErrOpenFailed (-137) +#define kErrBadMagic (-138) +#define kErrBadParameter (-139) +#define kErrMKDFailed (-140) +#define kErrCannotGoToPrevDir (-141) +#define kErrChmodFailed (-142) +#define kErrUmaskFailed (-143) +#define kErrDELEFailed (-144) +#define kErrSIZEFailed (-145) +#define kErrMDTMFailed (-146) +#define kErrTYPEFailed (-147) +#define kErrSIZENotAvailable (-148) +#define kErrMDTMNotAvailable (-149) +#define kErrRenameFailed (-150) +#define kErrGlobFailed (-151) +#define kErrSetKeepAlive (-152) +#define kErrHostDisconnectedDuringLogin (-153) +#define kErrBadRemoteUser (-154) +#define kErrBadRemoteUserOrPassword (-155) +#define kErrLoginFailed (-156) +#define kErrInvalidReplyFromServer (-157) +#define kErrRemoteHostClosedConnection (-158) +#define kErrNotConnected (-159) +#define kErrCouldNotStartDataTransfer (-160) +#define kErrDataTransferFailed (-161) +#define kErrPORTFailed (-162) +#define kErrPASVFailed (-163) +#define kErrUTIMEFailed (-164) +#define kErrUTIMENotAvailable (-165) +#define kErrHELPFailed (-166) +#define kErrLocalDeleteFailed (-167) +#define kErrLseekFailed (-168) +#define kErrDataTransferAborted (-169) +#define kErrSYMLINKFailed (-170) +#define kErrSYMLINKNotAvailable (-171) +#define kErrGlobNoMatch (-172) +#define kErrFEATNotAvailable (-173) +#define kErrNoValidFilesSpecified (-174) +#define kErrNoBuf (-175) +#define kErrLocalFileNewer (-176) +#define kErrRemoteFileNewer (-177) +#define kErrLocalSameAsRemote (-178) +#define kErrMLSDFailed (-179) +#define kErrMLSTFailed (-180) +#define kErrInvalidMLSTResponse (-181) +#define kErrMLSTNotAvailable (-182) +#define kErrMLSDNotAvailable (-183) +#define kErrSTATFailed (-184) +#define kErrSTATwithFileNotAvailable (-185) +#define kErrNLSTFailed (-186) +#define kErrNLSTwithFileNotAvailable (-187) +#define kErrNoSuchFileOrDirectory (-188) +#define kErrCantTellIfFileExists (-189) +#define kErrFileExistsButCannotDetermineType (-190) +#define kErrNotADirectory (-191) +#define kErrRecursionLimitReached (-192) +#define kErrControlTimedOut (-193) +#define kErrDataTimedOut (-194) +#define kErrUserCanceled (-195) +#define kErrLast (195) diff --git a/reactos/apps/utils/net/ncftp/libncftp/open.c b/reactos/apps/utils/net/ncftp/libncftp/open.c new file mode 100644 index 00000000000..29ba1e5f076 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/open.c @@ -0,0 +1,1137 @@ +/* open.c + * + * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft. + * All rights reserved. + * + */ + +#include "syshdrs.h" + +static void +FTPDeallocateHost(const FTPCIPtr cip) +{ + /* Requires the cip->bufSize field set, + * and the cip->buf set if the + * buffer is allocated. + */ + if (cip->buf != NULL) { + (void) memset(cip->buf, 0, cip->bufSize); + free(cip->buf); + cip->buf = NULL; + } + + if (cip->startingWorkingDirectory != NULL) { + free(cip->startingWorkingDirectory); + cip->startingWorkingDirectory = NULL; + } + +#if USE_SIO + DisposeSReadlineInfo(&cip->ctrlSrl); +#endif + DisposeLineListContents(&cip->lastFTPCmdResultLL); +} /* FTPDeallocateHost */ + + + + + +static int +FTPAllocateHost(const FTPCIPtr cip) +{ + char *buf; + + /* Requires the cip->bufSize field set, + * and the cip->buf cleared if the + * buffer is not allocated. + */ + if (cip->buf == NULL) { + buf = (char *) calloc((size_t) 1, cip->bufSize); + if (buf == NULL) { + Error(cip, kDontPerror, "Malloc failed.\n"); + cip->errNo = kErrMallocFailed; + return (kErrMallocFailed); + } + cip->buf = buf; + } + return (kNoErr); +} /* FTPAllocateHost */ + + + + +void +FTPInitializeOurHostName(const FTPLIPtr lip) +{ + if (lip == NULL) + return; + if (strcmp(lip->magic, kLibraryMagic)) + return; + + if (lip->htried == 0) { + (void) memset(lip->ourHostName, 0, sizeof(lip->ourHostName)); + lip->hresult = GetOurHostName(lip->ourHostName, sizeof(lip->ourHostName)); + } + lip->htried++; +} /* FTPInitializeOurHostName */ + + + + +void +FTPInitializeAnonPassword(const FTPLIPtr lip) +{ + if (lip == NULL) + return; + if (strcmp(lip->magic, kLibraryMagic)) + return; + + FTPInitializeOurHostName(lip); + + if (lip->defaultAnonPassword[0] == '\0') { +#ifdef SPAM_PROBLEM_HAS_BEEN_SOLVED_FOREVER + GetUsrName(lip->defaultAnonPassword, sizeof(lip->defaultAnonPassword)); + (void) STRNCAT(lip->defaultAnonPassword, "@"); + + /* Default to the "user@" notation + * supported by NcFTPd and wu-ftpd. + */ + if (lip->htried > 0) + (void) STRNCAT(lip->defaultAnonPassword, lip->ourHostName); +#else + (void) STRNCPY(lip->defaultAnonPassword, "NcFTP@"); +#endif + } +} /* FTPInitializeAnonPassword */ + + + + +int +FTPLoginHost(const FTPCIPtr cip) +{ + ResponsePtr rp; + int result = kErrLoginFailed; + int anonLogin; + int sentpass = 0; + int fwloggedin; + int firstTime; + char cwd[512]; + + if (cip == NULL) + return (kErrBadParameter); + if ((cip->firewallType < kFirewallNotInUse) || (cip->firewallType > kFirewallLastType)) + return (kErrBadParameter); + + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + anonLogin = 0; + if (cip->user[0] == '\0') + (void) STRNCPY(cip->user, "anonymous"); + if ((strcmp(cip->user, "anonymous") == 0) || (strcmp(cip->user, "ftp") == 0)) { + anonLogin = 1; + /* Try to get the email address if you didn't specify + * a password when the user is anonymous. + */ + if (cip->pass[0] == '\0') { + FTPInitializeAnonPassword(cip->lip); + (void) STRNCPY(cip->pass, cip->lip->defaultAnonPassword); + } + } + + rp = InitResponse(); + if (rp == NULL) { + result = kErrMallocFailed; + cip->errNo = kErrMallocFailed; + goto done2; + } + + for (firstTime = 1, fwloggedin = 0; ; ) { + /* Here's a mini finite-automaton for the login process. + * + * Originally, the FTP protocol was designed to be entirely + * implementable from a FA. It could be done, but I don't think + * it's something an interactive process could be the most + * effective with. + */ + + if (firstTime != 0) { + rp->code = 220; + firstTime = 0; + } else if (result < 0) { + goto done; + } + + switch (rp->code) { + case 220: /* Welcome, ready for new user. */ + if ((cip->firewallType == kFirewallNotInUse) || (fwloggedin != 0)) { + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "USER %s", cip->user); + } else if (cip->firewallType == kFirewallUserAtSite) { + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "USER %s@%s", cip->user, cip->host); + } else if (cip->firewallType == kFirewallUserAtUserPassAtPass) { + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "USER %s@%s@%s", cip->user, cip->firewallUser, cip->host); + } else if (cip->firewallType == kFirewallUserAtSiteFwuPassFwp) { + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "USER %s@%s %s", cip->user, cip->host, cip->firewallUser); + } else if (cip->firewallType == kFirewallFwuAtSiteFwpUserPass) { + /* only reached when !fwloggedin */ + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "USER %s@%s", cip->firewallUser, cip->host); + } else if (cip->firewallType > kFirewallNotInUse) { + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "USER %s", cip->firewallUser); + } else { + goto unknown; + } + break; + + case 230: /* 230 User logged in, proceed. */ + case 231: /* User name accepted. */ + case 202: /* Command not implemented, superfluous at this site. */ + if ((cip->firewallType == kFirewallNotInUse) || (fwloggedin != 0)) + goto okay; + + /* Now logged in to the firewall. */ + fwloggedin++; + + if (cip->firewallType == kFirewallLoginThenUserAtSite) { + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "USER %s@%s", cip->user, cip->host); + } else if (cip->firewallType == kFirewallUserAtUserPassAtPass) { + goto okay; + } else if (cip->firewallType == kFirewallOpenSite) { + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "OPEN %s", cip->host); + } else if (cip->firewallType == kFirewallSiteSite) { + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "SITE %s", cip->host); + } else if (cip->firewallType == kFirewallFwuAtSiteFwpUserPass) { + /* only reached when !fwloggedin */ + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "USER %s", cip->user); + } else /* kFirewallUserAtSite */ { + goto okay; + } + break; + + case 421: /* 421 Service not available, closing control connection. */ + result = kErrHostDisconnectedDuringLogin; + goto done; + + case 331: /* 331 User name okay, need password. */ + if ((cip->firewallType == kFirewallNotInUse) || (fwloggedin != 0)) { + if ((cip->pass[0] == '\0') && (cip->passphraseProc != NoGetPassphraseProc)) + (*cip->passphraseProc)(cip, &rp->msg, cip->pass, sizeof(cip->pass)); + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "PASS %s", cip->pass); + } else if (cip->firewallType == kFirewallUserAtSite) { + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "PASS %s", cip->pass); + } else if (cip->firewallType == kFirewallUserAtUserPassAtPass) { + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "PASS %s@%s", cip->pass, cip->firewallPass); + } else if (cip->firewallType == kFirewallUserAtSiteFwuPassFwp) { + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "PASS %s", cip->pass); + } else if (cip->firewallType == kFirewallFwuAtSiteFwpUserPass) { + /* only reached when !fwloggedin */ + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "PASS %s", cip->firewallPass); + } else if (cip->firewallType > kFirewallNotInUse) { + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "PASS %s", cip->firewallPass); + } else { + goto unknown; + } + sentpass++; + break; + + case 332: /* 332 Need account for login. */ + case 532: /* 532 Need account for storing files. */ + if ((cip->firewallType == kFirewallNotInUse) || (fwloggedin != 0)) { + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "ACCT %s", cip->acct); + } else if (cip->firewallType == kFirewallUserAtSiteFwuPassFwp) { + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "ACCT %s", cip->firewallPass); + } else { + /* ACCT not supported on firewall. */ + goto unknown; + } + break; + + case 530: /* Not logged in. */ + result = (sentpass != 0) ? kErrBadRemoteUserOrPassword : kErrBadRemoteUser; + goto done; + + case 501: /* Syntax error in parameters or arguments. */ + case 503: /* Bad sequence of commands. */ + case 550: /* Can't set guest privileges. */ + goto done; + + default: + unknown: + if (rp->msg.first == NULL) { + Error(cip, kDontPerror, "Lost connection during login.\n"); + } else { + Error(cip, kDontPerror, "Unexpected response: %s\n", + rp->msg.first->line + ); + } + goto done; + } + } + +okay: + /* Do the application's connect message callback, if present. */ + if (cip->onLoginMsgProc != 0) + (*cip->onLoginMsgProc)(cip, rp); + DoneWithResponse(cip, rp); + result = 0; + cip->loggedIn = 1; + + /* Make a note of what our root directory is. + * This is often different from "/" when not + * logged in anonymously. + */ + if (cip->startingWorkingDirectory != NULL) { + free(cip->startingWorkingDirectory); + cip->startingWorkingDirectory = NULL; + } + if ((cip->doNotGetStartingWorkingDirectory == 0) && + (FTPGetCWD(cip, cwd, sizeof(cwd)) == kNoErr)) + { + cip->startingWorkingDirectory = StrDup(cwd); + } + + /* When a new site is opened, ASCII mode is assumed (by protocol). */ + cip->curTransferType = 'A'; + PrintF(cip, "Logged in to %s as %s.\n", cip->host, cip->user); + + /* Don't leave cleartext password in memory. */ + if ((anonLogin == 0) && (cip->leavePass == 0)) + (void) memset(cip->pass, '*', strlen(cip->pass)); + + if (result < 0) + cip->errNo = result; + return result; + +done: + DoneWithResponse(cip, rp); + +done2: + /* Don't leave cleartext password in memory. */ + if ((anonLogin == 0) && (cip->leavePass == 0)) + (void) memset(cip->pass, '*', strlen(cip->pass)); + if (result < 0) + cip->errNo = result; + return result; +} /* FTPLoginHost */ + + + + +static void +FTPExamineMlstFeatures(const FTPCIPtr cip, const char *features) +{ + char buf[256], *feat; + int flags; + + flags = 0; + STRNCPY(buf, features); + feat = strtok(buf, ";*"); + while (feat != NULL) { + if (ISTRNEQ(feat, "OS.", 3)) + feat += 3; + if (ISTREQ(feat, "type")) { + flags |= kMlsOptType; + } else if (ISTREQ(feat, "size")) { + flags |= kMlsOptSize; + } else if (ISTREQ(feat, "modify")) { + flags |= kMlsOptModify; + } else if (ISTREQ(feat, "UNIX.mode")) { + flags |= kMlsOptUNIXmode; + } else if (ISTREQ(feat, "UNIX.owner")) { + flags |= kMlsOptUNIXowner; + } else if (ISTREQ(feat, "UNIX.group")) { + flags |= kMlsOptUNIXgroup; + } else if (ISTREQ(feat, "perm")) { + flags |= kMlsOptPerm; + } else if (ISTREQ(feat, "UNIX.uid")) { + flags |= kMlsOptUNIXuid; + } else if (ISTREQ(feat, "UNIX.gid")) { + flags |= kMlsOptUNIXgid; + } else if (ISTREQ(feat, "UNIX.gid")) { + flags |= kMlsOptUnique; + } + feat = strtok(NULL, ";*"); + } + + cip->mlsFeatures = flags; +} /* FTPExamineMlstFeatures */ + + + + +int +FTPQueryFeatures(const FTPCIPtr cip) +{ + ResponsePtr rp; + int result; + LinePtr lp; + char *cp, *p; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if (cip->serverType == kServerTypeNetWareFTP) { + /* NetWare 5.00 server freaks out when + * you give it a command it doesn't + * recognize, so cheat here and return. + */ + cip->hasPASV = kCommandAvailable; + cip->hasSIZE = kCommandNotAvailable; + cip->hasMDTM = kCommandNotAvailable; + cip->hasREST = kCommandNotAvailable; + cip->NLSTfileParamWorks = kCommandAvailable; + cip->hasUTIME = kCommandNotAvailable; + cip->hasCLNT = kCommandNotAvailable; + cip->hasMLST = kCommandNotAvailable; + cip->hasMLSD = kCommandNotAvailable; + return (kNoErr); + } + + rp = InitResponse(); + if (rp == NULL) { + cip->errNo = kErrMallocFailed; + result = cip->errNo; + } else { + rp->printMode = (kResponseNoPrint|kResponseNoSave); + result = RCmd(cip, rp, "FEAT"); + if (result < kNoErr) { + DoneWithResponse(cip, rp); + return (result); + } else if (result != 2) { + /* We cheat here and pre-populate some + * fields when the server is wu-ftpd. + * This server is very common and we + * know it has always had these. + */ + if (cip->serverType == kServerTypeWuFTPd) { + cip->hasPASV = kCommandAvailable; + cip->hasSIZE = kCommandAvailable; + cip->hasMDTM = kCommandAvailable; + cip->hasREST = kCommandAvailable; + cip->NLSTfileParamWorks = kCommandAvailable; + } else if (cip->serverType == kServerTypeNcFTPd) { + cip->hasPASV = kCommandAvailable; + cip->hasSIZE = kCommandAvailable; + cip->hasMDTM = kCommandAvailable; + cip->hasREST = kCommandAvailable; + cip->NLSTfileParamWorks = kCommandAvailable; + } + + /* Newer commands are only shown in FEAT, + * so we don't have to do the "try it, + * then save that it didn't work" thing. + */ + cip->hasMLST = kCommandNotAvailable; + cip->hasMLSD = kCommandNotAvailable; + } else { + cip->hasFEAT = kCommandAvailable; + + for (lp = rp->msg.first; lp != NULL; lp = lp->next) { + /* If first character was not a space it is + * either: + * + * (a) The header line in the response; + * (b) The trailer line in the response; + * (c) A protocol violation. + */ + cp = lp->line; + if (*cp++ != ' ') + continue; + if (ISTRNCMP(cp, "PASV", 4) == 0) { + cip->hasPASV = kCommandAvailable; + } else if (ISTRNCMP(cp, "SIZE", 4) == 0) { + cip->hasSIZE = kCommandAvailable; + } else if (ISTRNCMP(cp, "MDTM", 4) == 0) { + cip->hasMDTM = kCommandAvailable; + } else if (ISTRNCMP(cp, "REST", 4) == 0) { + cip->hasREST = kCommandAvailable; + } else if (ISTRNCMP(cp, "UTIME", 5) == 0) { + cip->hasUTIME = kCommandAvailable; + } else if (ISTRNCMP(cp, "MLST", 4) == 0) { + cip->hasMLST = kCommandAvailable; + cip->hasMLSD = kCommandAvailable; + FTPExamineMlstFeatures(cip, cp + 5); + } else if (ISTRNCMP(cp, "CLNT", 4) == 0) { + cip->hasCLNT = kCommandAvailable; + } else if (ISTRNCMP(cp, "Compliance Level: ", 18) == 0) { + /* Probably only NcFTPd will ever implement this. + * But we use it internally to differentiate + * between different NcFTPd implementations of + * IETF extensions. + */ + cip->ietfCompatLevel = atoi(cp + 18); + } + } + } + + ReInitResponse(cip, rp); + result = RCmd(cip, rp, "HELP SITE"); + if (result == 2) { + for (lp = rp->msg.first; lp != NULL; lp = lp->next) { + cp = lp->line; + if (strstr(cp, "RETRBUFSIZE") != NULL) + cip->hasRETRBUFSIZE = kCommandAvailable; + if (strstr(cp, "RBUFSZ") != NULL) + cip->hasRBUFSZ = kCommandAvailable; + /* See if RBUFSIZ matches (but not STORBUFSIZE) */ + if ( + ((p = strstr(cp, "RBUFSIZ")) != NULL) && + ( + (p == cp) || + ((p > cp) && (!isupper(p[-1]))) + ) + ) + cip->hasRBUFSIZ = kCommandAvailable; + if (strstr(cp, "STORBUFSIZE") != NULL) + cip->hasSTORBUFSIZE = kCommandAvailable; + if (strstr(cp, "SBUFSIZ") != NULL) + cip->hasSBUFSIZ = kCommandAvailable; + if (strstr(cp, "SBUFSZ") != NULL) + cip->hasSBUFSZ = kCommandAvailable; + if (strstr(cp, "BUFSIZE") != NULL) + cip->hasBUFSIZE = kCommandAvailable; + } + } + DoneWithResponse(cip, rp); + } + + return (kNoErr); +} /* FTPQueryFeatures */ + + + +int +FTPCloseHost(const FTPCIPtr cip) +{ + ResponsePtr rp; + int result; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + /* Data connection shouldn't be open normally. */ + if (cip->dataSocket != kClosedFileDescriptor) + FTPAbortDataTransfer(cip); + + result = kNoErr; + if (cip->connected != 0) { + rp = InitResponse(); + if (rp == NULL) { + cip->errNo = kErrMallocFailed; + result = cip->errNo; + } else { + rp->eofOkay = 1; /* We are expecting EOF after this cmd. */ + cip->eofOkay = 1; + (void) RCmd(cip, rp, "QUIT"); + DoneWithResponse(cip, rp); + } + } + + CloseControlConnection(cip); + + /* Dispose dynamic data structures, so you won't leak + * if you OpenHost with this again. + */ + FTPDeallocateHost(cip); + return (result); +} /* FTPCloseHost */ + + + + +void +FTPShutdownHost(const FTPCIPtr cip) +{ +#ifdef SIGPIPE + FTPSigProc osigpipe; +#endif + + if (cip == NULL) + return; + if (strcmp(cip->magic, kLibraryMagic)) + return; + +#ifdef SIGPIPE + osigpipe = signal(SIGPIPE, (FTPSigProc) SIG_IGN); +#endif + + /* Linger could cause close to block, so unset it. */ + if (cip->dataSocket != kClosedFileDescriptor) + (void) SetLinger(cip, cip->dataSocket, 0); + CloseDataConnection(cip); /* Shouldn't be open normally. */ + + /* Linger should already be turned off for this. */ + CloseControlConnection(cip); + + FTPDeallocateHost(cip); + +#ifdef SIGPIPE + (void) signal(SIGPIPE, (FTPSigProc) osigpipe); +#endif +} /* FTPShutdownHost */ + + + + +void +URLCopyToken(char *dst, size_t dsize, const char *src, size_t howmuch) +{ + char *dlim; + const char *slim; + unsigned int hc; + int c; + char h[4]; + + dlim = dst + dsize - 1; /* leave room for \0 */ + slim = src + howmuch; + while (src < slim) { + c = *src++; + if (c == '\0') + break; + if (c == '%') { + /* hex representation */ + if (src < slim + 2) { + h[0] = *src++; + h[1] = *src++; + h[2] = '\0'; + hc = 0xeeff; + if ((sscanf(h, "%x", &hc) >= 0) && (hc != 0xeeff)) { + if (dst < dlim) { + *(unsigned char *)dst = (unsigned char) hc; + dst++; + } + } + } else { + break; + } + } else { + *dst++ = (char) c; + } + } + *dst = '\0'; +} /* URLCopyToken */ + + + + +int +FTPDecodeURL( + const FTPCIPtr cip, /* area pointed to may be modified */ + char *const url, /* always modified */ + LineListPtr cdlist, /* always modified */ + char *const fn, /* always modified */ + const size_t fnsize, + int *const xtype, /* optional; may be modified */ + int *const wantnlst /* optional; always modified */ +) +{ + char *cp; + char *hstart, *hend; + char *h2start; + char *at1; + char portstr[32]; + int port; + int sc; + char *lastslash; + char *parsestr; + char *tok; + char subdir[128]; + char *semi; + + InitLineList(cdlist); + *fn = '\0'; + if (wantnlst != NULL) + *wantnlst = 0; + if (xtype != NULL) + *xtype = kTypeBinary; + + cp = NULL; /* shut up warnings */ +#ifdef HAVE_STRCASECMP + if (strncasecmp(url, " */ + *cp = '\0'; + cp = url + 11; + } else if (strncasecmp(url, "ftp://", 6) == 0) { + cp = url + 6; + } else { + return (-1); /* not a RFC 1738 URL */ + } +#else /* HAVE_STRCASECMP */ + if (strncmp(url, " */ + *cp = '\0'; + cp = url + 11; + } else if (strncmp(url, "ftp://", 6) == 0) { + cp = url + 6; + } else { + return (-1); /* not a RFC 1738 URL */ + } +#endif /* HAVE_STRCASECMP */ + + /* //:@:/ */ + + at1 = NULL; + for (hstart = cp; ; cp++) { + if (*cp == '@') { + if (at1 == NULL) + at1 = cp; + else + return (kMalformedURL); + } else if ((*cp == '\0') || (*cp == '/')) { + hend = cp; + break; + } + } + + sc = *hend; + *hend = '\0'; + if (at1 == NULL) { + /* no user or password */ + h2start = hstart; + } else { + *at1 = '\0'; + cp = strchr(hstart, ':'); + if (cp == NULL) { + /* whole thing is the user name then */ + URLCopyToken(cip->user, sizeof(cip->user), hstart, (size_t) (at1 - hstart)); + } else if (strchr(cp + 1, ':') != NULL) { + /* Too many colons */ + return (kMalformedURL); + } else { + URLCopyToken(cip->user, sizeof(cip->user), hstart, (size_t) (cp - hstart)); + URLCopyToken(cip->pass, sizeof(cip->pass), cp + 1, (size_t) (at1 - (cp + 1))); + } + *at1 = '@'; + h2start = at1 + 1; + } + + cp = strchr(h2start, ':'); + if (cp == NULL) { + /* whole thing is the host then */ + URLCopyToken(cip->host, sizeof(cip->host), h2start, (size_t) (hend - h2start)); + } else if (strchr(cp + 1, ':') != NULL) { + /* Too many colons */ + return (kMalformedURL); + } else { + URLCopyToken(cip->host, sizeof(cip->host), h2start, (size_t) (cp - h2start)); + URLCopyToken(portstr, sizeof(portstr), cp + 1, (size_t) (hend - (cp + 1))); + port = atoi(portstr); + if (port > 0) + cip->port = port; + } + + *hend = (char) sc; + if ((*hend == '\0') || ((*hend == '/') && (hend[1] == '\0'))) { + /* no path, okay */ + return (0); + } + + lastslash = strrchr(hend, '/'); + if (lastslash == NULL) { + /* no path, okay */ + return (0); + } + *lastslash = '\0'; + + if ((semi = strchr(lastslash + 1, ';')) != NULL) { + *semi++ = '\0'; +#ifdef HAVE_STRCASECMP + if (strcasecmp(semi, "type=i") == 0) { + if (xtype != NULL) + *xtype = kTypeBinary; + } else if (strcasecmp(semi, "type=a") == 0) { + if (xtype != NULL) + *xtype = kTypeAscii; + } else if (strcasecmp(semi, "type=b") == 0) { + if (xtype != NULL) + *xtype = kTypeBinary; + } else if (strcasecmp(semi, "type=d") == 0) { + if (wantnlst != NULL) { + *wantnlst = 1; + if (xtype != NULL) + *xtype = kTypeAscii; + } else { + /* You didn't want these. */ + return (kMalformedURL); + } + } +#else /* HAVE_STRCASECMP */ + if (strcmp(semi, "type=i") == 0) { + if (xtype != NULL) + *xtype = kTypeBinary; + } else if (strcmp(semi, "type=a") == 0) { + if (xtype != NULL) + *xtype = kTypeAscii; + } else if (strcmp(semi, "type=b") == 0) { + if (xtype != NULL) + *xtype = kTypeBinary; + } else if (strcmp(semi, "type=d") == 0) { + if (wantnlst != NULL) { + *wantnlst = 1; + if (xtype != NULL) + *xtype = kTypeAscii; + } else { + /* You didn't want these. */ + return (kMalformedURL); + } + } +#endif /* HAVE_STRCASECMP */ + } + URLCopyToken(fn, fnsize, lastslash + 1, strlen(lastslash + 1)); + for (parsestr = hend; (tok = strtok(parsestr, "/")) != NULL; parsestr = NULL) { + URLCopyToken(subdir, sizeof(subdir), tok, strlen(tok)); + (void) AddLine(cdlist, subdir); + } + *lastslash = '/'; + return (kNoErr); +} /* FTPDecodeURL */ + + + + +int +FTPOpenHost(const FTPCIPtr cip) +{ + int result; + time_t t0, t1; + int elapsed; + int dials; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if (cip->host[0] == '\0') { + cip->errNo = kErrBadParameter; + return (kErrBadParameter); + } + + for ( result = kErrConnectMiscErr, dials = 0; + cip->maxDials < 0 || dials < cip->maxDials; + dials++) + { + /* Allocate (or if the host was closed, reallocate) + * the transfer data buffer. + */ + result = FTPAllocateHost(cip); + if (result < 0) + return (result); + + if (dials > 0) + PrintF(cip, "Retry Number: %d\n", dials); + if (cip->redialStatusProc != 0) + (*cip->redialStatusProc)(cip, kRedialStatusDialing, dials); + (void) time(&t0); + result = OpenControlConnection(cip, cip->host, cip->port); + (void) time(&t1); + if (result == kNoErr) { + /* We were hooked up successfully. */ + PrintF(cip, "Connected to %s.\n", cip->host); + + result = FTPLoginHost(cip); + if (result == kNoErr) { + (void) FTPQueryFeatures(cip); + break; + } + + /* Close and try again. */ + (void) FTPCloseHost(cip); + + /* Originally we also stopped retyring if + * we got kErrBadRemoteUser and non-anonymous, + * but some FTP servers apparently do their + * max user check after the username is sent. + */ + if (result == kErrBadRemoteUserOrPassword /* || (result == kErrBadRemoteUser) */) { + if (strcmp(cip->user, "anonymous") != 0) { + /* Non-anonymous login was denied, and + * retrying is not going to help. + */ + break; + } + } + } else if ((result != kErrConnectRetryableErr) && (result != kErrConnectRefused) && (result != kErrRemoteHostClosedConnection)) { + /* Irrecoverable error, so don't bother redialing. + * The error message should have already been printed + * from OpenControlConnection(). + */ + PrintF(cip, "Cannot recover from miscellaneous open error %d.\n", result); + return result; + } + + /* Retryable error, wait and then redial. */ + if (cip->redialDelay > 0) { + /* But don't sleep if this is the last loop. */ + if ((cip->maxDials < 0) || (dials < (cip->maxDials - 1))) { + elapsed = (int) (t1 - t0); + if (elapsed < cip->redialDelay) { + PrintF(cip, "Sleeping %u seconds.\n", + (unsigned) cip->redialDelay - elapsed); + if (cip->redialStatusProc != 0) + (*cip->redialStatusProc)(cip, kRedialStatusSleeping, cip->redialDelay - elapsed); + (void) sleep((unsigned) cip->redialDelay - elapsed); + } + } + } + } + return (result); +} /* FTPOpenHost */ + + + + +int +FTPOpenHostNoLogin(const FTPCIPtr cip) +{ + int result; + time_t t0, t1; + int elapsed; + int dials; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + if (cip->host[0] == '\0') { + cip->errNo = kErrBadParameter; + return (kErrBadParameter); + } + + for ( result = kErrConnectMiscErr, dials = 0; + cip->maxDials < 0 || dials < cip->maxDials; + dials++) + { + + /* Allocate (or if the host was closed, reallocate) + * the transfer data buffer. + */ + result = FTPAllocateHost(cip); + if (result < 0) + return (result); + + if (dials > 0) + PrintF(cip, "Retry Number: %d\n", dials); + if (cip->redialStatusProc != 0) + (*cip->redialStatusProc)(cip, kRedialStatusDialing, dials); + (void) time(&t0); + result = OpenControlConnection(cip, cip->host, cip->port); + (void) time(&t1); + if (result == kNoErr) { + /* We were hooked up successfully. */ + PrintF(cip, "Connected to %s.\n", cip->host); + + /* Not logging in... */ + if (result == kNoErr) + break; + } else if ((result != kErrConnectRetryableErr) && (result != kErrConnectRefused) && (result != kErrRemoteHostClosedConnection)) { + /* Irrecoverable error, so don't bother redialing. + * The error message should have already been printed + * from OpenControlConnection(). + */ + PrintF(cip, "Cannot recover from miscellaneous open error %d.\n", result); + return result; + } + + /* Retryable error, wait and then redial. */ + if (cip->redialDelay > 0) { + /* But don't sleep if this is the last loop. */ + if ((cip->maxDials < 0) || (dials < (cip->maxDials - 1))) { + elapsed = (int) (t1 - t0); + if (elapsed < cip->redialDelay) { + PrintF(cip, "Sleeping %u seconds.\n", + (unsigned) cip->redialDelay - elapsed); + if (cip->redialStatusProc != 0) + (*cip->redialStatusProc)(cip, kRedialStatusSleeping, cip->redialDelay - elapsed); + (void) sleep((unsigned) cip->redialDelay - elapsed); + } + } + } + } + return (result); +} /* FTPOpenHostNoLogin */ + + + + +int +FTPInitConnectionInfo(const FTPLIPtr lip, const FTPCIPtr cip, size_t bufSize) +{ + size_t siz; + + if ((lip == NULL) || (cip == NULL) || (bufSize == 0)) + return (kErrBadParameter); + + siz = sizeof(FTPConnectionInfo); + (void) memset(cip, 0, siz); + + if (strcmp(lip->magic, kLibraryMagic)) + return (kErrBadMagic); + + cip->buf = NULL; /* denote that it needs to be allocated. */ + cip->bufSize = bufSize; + cip->port = lip->defaultPort; + cip->firewallPort = lip->defaultPort; + cip->maxDials = kDefaultMaxDials; + cip->redialDelay = kDefaultRedialDelay; + cip->xferTimeout = kDefaultXferTimeout; + cip->connTimeout = kDefaultConnTimeout; + cip->ctrlTimeout = kDefaultCtrlTimeout; + cip->abortTimeout = kDefaultAbortTimeout; + cip->ctrlSocketR = kClosedFileDescriptor; + cip->ctrlSocketW = kClosedFileDescriptor; + cip->dataPortMode = kSendPortMode; + cip->dataSocket = kClosedFileDescriptor; + cip->lip = lip; + cip->hasPASV = kCommandAvailabilityUnknown; + cip->hasSIZE = kCommandAvailabilityUnknown; + cip->hasMDTM = kCommandAvailabilityUnknown; + cip->hasREST = kCommandAvailabilityUnknown; + cip->hasNLST_d = kCommandAvailabilityUnknown; + cip->hasUTIME = kCommandAvailabilityUnknown; + cip->hasFEAT = kCommandAvailabilityUnknown; + cip->hasMLSD = kCommandAvailabilityUnknown; + cip->hasMLST = kCommandAvailabilityUnknown; + cip->hasCLNT = kCommandAvailabilityUnknown; + cip->hasRETRBUFSIZE = kCommandAvailabilityUnknown; + cip->hasRBUFSIZ = kCommandAvailabilityUnknown; + cip->hasRBUFSZ = kCommandAvailabilityUnknown; + cip->hasSTORBUFSIZE = kCommandAvailabilityUnknown; + cip->hasSBUFSIZ = kCommandAvailabilityUnknown; + cip->hasSBUFSZ = kCommandAvailabilityUnknown; + cip->STATfileParamWorks = kCommandAvailabilityUnknown; + cip->NLSTfileParamWorks = kCommandAvailabilityUnknown; + cip->firewallType = kFirewallNotInUse; + cip->startingWorkingDirectory = NULL; + (void) STRNCPY(cip->magic, kLibraryMagic); + (void) STRNCPY(cip->user, "anonymous"); + return (kNoErr); +} /* FTPInitConnectionInfo */ + + + + +int +FTPRebuildConnectionInfo(const FTPLIPtr lip, const FTPCIPtr cip) +{ + char *buf; + + cip->lip = lip; + cip->debugLog = NULL; + cip->errLog = NULL; + cip->debugLogProc = NULL; + cip->errLogProc = NULL; + cip->buf = NULL; + cip->cin = NULL; + cip->cout = NULL; + cip->errNo = 0; + cip->progress = NULL; + cip->rname = NULL; + cip->lname = NULL; + cip->onConnectMsgProc = NULL; + cip->redialStatusProc = NULL; + cip->printResponseProc = NULL; + cip->onLoginMsgProc = NULL; + cip->passphraseProc = NULL; + cip->startingWorkingDirectory = NULL; + cip->asciiFilenameExtensions = NULL; + + (void) memset(&cip->lastFTPCmdResultLL, 0, sizeof(LineList)); + + /* Allocate a new buffer. */ + buf = (char *) calloc((size_t) 1, cip->bufSize); + if (buf == NULL) { + cip->errNo = kErrMallocFailed; + return (kErrMallocFailed); + } + cip->buf = buf; + + /* Reattach the FILE pointers for use with the Std I/O library + * routines. + */ + if ((cip->cin = fdopen(cip->ctrlSocketR, "r")) == NULL) { + cip->errNo = kErrFdopenR; + cip->ctrlSocketR = kClosedFileDescriptor; + cip->ctrlSocketW = kClosedFileDescriptor; + return (kErrFdopenR); + } + + if ((cip->cout = fdopen(cip->ctrlSocketW, "w")) == NULL) { + CloseFile(&cip->cin); + cip->errNo = kErrFdopenW; + cip->ctrlSocketR = kClosedFileDescriptor; + cip->ctrlSocketW = kClosedFileDescriptor; + return (kErrFdopenW); + } + +#if USE_SIO + if (InitSReadlineInfo(&cip->ctrlSrl, cip->ctrlSocketR, cip->srlBuf, sizeof(cip->srlBuf), (int) cip->ctrlTimeout, 1) < 0) { + cip->errNo = kErrFdopenW; + CloseFile(&cip->cin); + cip->errNo = kErrFdopenW; + cip->ctrlSocketR = kClosedFileDescriptor; + cip->ctrlSocketW = kClosedFileDescriptor; + return (kErrFdopenW); + } +#endif + return (kNoErr); +} /* FTPRebuildConnectionInfo */ + + + + +int +FTPInitLibrary(const FTPLIPtr lip) +{ + struct servent *ftp; + + if (lip == NULL) + return (kErrBadParameter); + + (void) memset(lip, 0, sizeof(FTPLibraryInfo)); + if ((ftp = getservbyname("ftp", "tcp")) == NULL) + lip->defaultPort = (unsigned int) kDefaultFTPPort; + else + lip->defaultPort = (unsigned int) ntohs(ftp->s_port); + + lip->init = 1; + (void) STRNCPY(lip->magic, kLibraryMagic); + + /* We'll initialize the defaultAnonPassword field + * later when we try the first anon ftp connection. + */ + +#ifdef HAVE_LIBSOCKS + SOCKSinit("libncftp"); + lip->socksInit = 1; +#endif + return (kNoErr); +} /* FTPInitLibrary */ + +/* Open.c */ diff --git a/reactos/apps/utils/net/ncftp/libncftp/rcmd.c b/reactos/apps/utils/net/ncftp/libncftp/rcmd.c new file mode 100644 index 00000000000..15fd487abd8 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/rcmd.c @@ -0,0 +1,1038 @@ +/* rcmd.c + * + * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft. + * All rights reserved. + * + */ + +#include "syshdrs.h" + +#if !defined(NO_SIGNALS) && (USE_SIO || !defined(SIGALRM) || !defined(SIGPIPE) || !defined(SIGINT)) +# define NO_SIGNALS 1 +#endif + +#ifndef NO_SIGNALS + +#ifdef HAVE_SIGSETJMP +static sigjmp_buf gBrokenCtrlJmp; +#else +static jmp_buf gBrokenCtrlJmp; +#endif /* HAVE_SIGSETJMP */ + +static void +BrokenCtrl(int UNUSED(signumIgnored)) +{ + LIBNCFTP_USE_VAR(signumIgnored); /* Shut up gcc */ +#ifdef HAVE_SIGSETJMP + siglongjmp(gBrokenCtrlJmp, 1); +#else + longjmp(gBrokenCtrlJmp, 1); +#endif /* HAVE_SIGSETJMP */ +} /* BrokenCtrl */ + +#endif /* NO_SIGNALS */ + + +/* A 'Response' parameter block is simply zeroed to be considered init'ed. */ +ResponsePtr +InitResponse(void) +{ + ResponsePtr rp; + + rp = (ResponsePtr) calloc(SZ(1), sizeof(Response)); + if (rp != NULL) + InitLineList(&rp->msg); + return (rp); +} /* InitResponse */ + + + + +/* If we don't print it to the screen, we may want to save it to our + * trace log. + */ +void +TraceResponse(const FTPCIPtr cip, ResponsePtr rp) +{ + LinePtr lp; + + if (rp != NULL) { + lp = rp->msg.first; + if (lp != NULL) { + PrintF(cip, "%3d: %s\n", rp->code, lp->line); + for (lp = lp->next; lp != NULL; lp = lp->next) + PrintF(cip, " %s\n", lp->line); + } + } +} /* TraceResponse */ + + + + + +void +PrintResponse(const FTPCIPtr cip, LineListPtr llp) +{ + LinePtr lp; + + if (llp != NULL) { + for (lp = llp->first; lp != NULL; lp = lp->next) + PrintF(cip, "%s\n", lp->line); + } +} /* PrintResponse */ + + + + + +static void +SaveLastResponse(const FTPCIPtr cip, ResponsePtr rp) +{ + if (rp == NULL) { + cip->lastFTPCmdResultStr[0] = '\0'; + cip->lastFTPCmdResultNum = -1; + DisposeLineListContents(&cip->lastFTPCmdResultLL); + } else if ((rp->msg.first == NULL) || (rp->msg.first->line == NULL)) { + cip->lastFTPCmdResultStr[0] = '\0'; + cip->lastFTPCmdResultNum = rp->code; + DisposeLineListContents(&cip->lastFTPCmdResultLL); + } else { + (void) STRNCPY(cip->lastFTPCmdResultStr, rp->msg.first->line); + cip->lastFTPCmdResultNum = rp->code; + + /* Dispose previous command's line list. */ + DisposeLineListContents(&cip->lastFTPCmdResultLL); + + /* Save this command's line list. */ + cip->lastFTPCmdResultLL = rp->msg; + } +} /* SaveLastResponse */ + + + +void +DoneWithResponse(const FTPCIPtr cip, ResponsePtr rp) +{ + /* Dispose space taken up by the Response, and clear it out + * again. For some reason, I like to return memory to zeroed + * when not in use. + */ + if (rp != NULL) { + TraceResponse(cip, rp); + if (cip->printResponseProc != 0) { + if ((rp->printMode & kResponseNoProc) == 0) + (*cip->printResponseProc)(cip, rp); + } + if ((rp->printMode & kResponseNoSave) == 0) + SaveLastResponse(cip, rp); + else + DisposeLineListContents(&rp->msg); + (void) memset(rp, 0, sizeof(Response)); + free(rp); + } +} /* DoneWithResponse */ + + + + +/* This takes an existing Response and recycles it, by clearing out + * the current contents. + */ +void +ReInitResponse(const FTPCIPtr cip, ResponsePtr rp) +{ + if (rp != NULL) { + TraceResponse(cip, rp); + if (cip->printResponseProc != 0) { + if ((rp->printMode & kResponseNoProc) == 0) + (*cip->printResponseProc)(cip, rp); + } + if ((rp->printMode & kResponseNoSave) == 0) + SaveLastResponse(cip, rp); + else + DisposeLineListContents(&rp->msg); + (void) memset(rp, 0, sizeof(Response)); + } +} /* ReInitResponse */ + + + + +#ifndef NO_SIGNALS + +/* Since the control stream is defined by the Telnet protocol (RFC 854), + * we follow Telnet rules when reading the control stream. We use this + * routine when we want to read a response from the host. + */ +int +GetTelnetString(const FTPCIPtr cip, char *str, size_t siz, FILE *cin, FILE *cout) +{ + int c; + size_t n; + int eofError; + char *cp; + + cp = str; + --siz; /* We'll need room for the \0. */ + + if ((cin == NULL) || (cout == NULL)) { + eofError = -1; + goto done; + } + + for (n = (size_t)0, eofError = 0; ; ) { + c = fgetc(cin); +checkChar: + if (c == EOF) { +eof: + eofError = -1; + break; + } else if (c == '\r') { + /* A telnet string can have a CR by itself. But to denote that, + * the protocol uses \r\0; an end of line is denoted \r\n. + */ + c = fgetc(cin); + if (c == '\n') { + /* Had \r\n, so done. */ + goto done; + } else if (c == EOF) { + goto eof; + } else if (c == '\0') { + c = '\r'; + goto addChar; + } else { + /* Telnet protocol violation! */ + goto checkChar; + } + } else if (c == '\n') { + /* Really shouldn't get here. If we do, the other side + * violated the TELNET protocol, since eoln's are CR/LF, + * and not just LF. + */ + PrintF(cip, "TELNET protocol violation: raw LF.\n"); + goto done; + } else if (c == IAC) { + /* Since the control connection uses the TELNET protocol, + * we have to handle some of its commands ourselves. + * IAC is the protocol's escape character, meaning that + * the next character after the IAC (Interpret as Command) + * character is a telnet command. But, if there just + * happened to be a character in the text stream with the + * same numerical value of IAC, 255, the sender denotes + * that by having an IAC followed by another IAC. + */ + + /* Get the telnet command. */ + c = fgetc(cin); + + switch (c) { + case WILL: + case WONT: + /* Get the option code. */ + c = fgetc(cin); + + /* Tell the other side that we don't want + * to do what they're offering to do. + */ + (void) fprintf(cout, "%c%c%c",IAC,DONT,c); + (void) fflush(cout); + break; + case DO: + case DONT: + /* Get the option code. */ + c = fgetc(cin); + + /* The other side said they are DOing (or not) + * something, which would happen if our side + * asked them to. Since we didn't do that, + * ask them to not do this option. + */ + (void) fprintf(cout, "%c%c%c",IAC,WONT,c); + (void) fflush(cout); + break; + + case EOF: + goto eof; + + default: + /* Just add this character, since it was most likely + * just an escaped IAC character. + */ + goto addChar; + } + } else { +addChar: + /* If the buffer supplied has room, add this character to it. */ + if (n < siz) { + *cp++ = c; + ++n; + } + } + } + +done: + *cp = '\0'; + return (eofError); +} /* GetTelnetString */ + +#endif /* NO_SIGNALS */ + + + +/* Returns 0 if a response was read, or (-1) if an error occurs. + * This reads the entire response text into a LineList, which is kept + * in the 'Response' structure. + */ +int +GetResponse(const FTPCIPtr cip, ResponsePtr rp) +{ + longstring str; + int eofError; + str16 code; + char *cp; + int continuation; + volatile FTPCIPtr vcip; +#ifdef NO_SIGNALS + int result; +#else /* NO_SIGNALS */ + volatile FTPSigProc osigpipe; + int sj; +#endif /* NO_SIGNALS */ + + /* RFC 959 states that a reply may span multiple lines. A single + * line message would have the 3-digit code then the msg. + * A multi-line message would have the code and the first + * line of the msg, then additional lines, until the last line, + * which has the code and last line of the msg. + * + * For example: + * 123-First line + * Second line + * 234 A line beginning with numbers + * 123 The last line + */ + +#ifdef NO_SIGNALS + vcip = cip; +#else /* NO_SIGNALS */ + osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenCtrl); + vcip = cip; + +#ifdef HAVE_SIGSETJMP + sj = sigsetjmp(gBrokenCtrlJmp, 1); +#else + sj = setjmp(gBrokenCtrlJmp); +#endif /* HAVE_SIGSETJMP */ + + if (sj != 0) { + (void) signal(SIGPIPE, (FTPSigProc) osigpipe); + FTPShutdownHost(vcip); + vcip->errNo = kErrRemoteHostClosedConnection; + return(vcip->errNo); + } +#endif /* NO_SIGNALS */ + +#ifdef NO_SIGNALS + cp = str; + eofError = 0; + if (cip->dataTimedOut > 0) { + /* Give up immediately unless the server had already + * sent a message. Odds are since the data is timed + * out, so is the control. + */ + if (SWaitUntilReadyForReading(cip->ctrlSocketR, 0) == 0) { + /* timeout */ + Error(cip, kDontPerror, "Could not read reply from control connection -- timed out.\n"); + FTPShutdownHost(vcip); + cip->errNo = kErrControlTimedOut; + return (cip->errNo); + } + } + result = SReadline(&cip->ctrlSrl, str, sizeof(str) - 1); + if (result == kTimeoutErr) { + /* timeout */ + Error(cip, kDontPerror, "Could not read reply from control connection -- timed out.\n"); + FTPShutdownHost(vcip); + cip->errNo = kErrControlTimedOut; + return (cip->errNo); + } else if (result == 0) { + /* eof */ + eofError = 1; + rp->hadEof = 1; + if (rp->eofOkay == 0) + Error(cip, kDontPerror, "Remote host has closed the connection.\n"); + FTPShutdownHost(vcip); + cip->errNo = kErrRemoteHostClosedConnection; + return (cip->errNo); + } else if (result < 0) { + /* error */ + Error(cip, kDoPerror, "Could not read reply from control connection"); + FTPShutdownHost(vcip); + cip->errNo = kErrInvalidReplyFromServer; + return (cip->errNo); + } + + if (str[result - 1] == '\n') + str[result - 1] = '\0'; + +#else /* NO_SIGNALS */ + /* Get the first line of the response. */ + eofError = GetTelnetString(cip, str, sizeof(str), cip->cin, cip->cout); + + cp = str; + if (*cp == '\0') { + if (eofError < 0) { + /* No bytes read for reply, and EOF detected. */ + rp->hadEof = 1; + if (rp->eofOkay == 0) + Error(cip, kDontPerror, "Remote host has closed the connection.\n"); + FTPShutdownHost(vcip); + cip->errNo = kErrRemoteHostClosedConnection; + (void) signal(SIGPIPE, osigpipe); + return(cip->errNo); + } + } +#endif /* NO_SIGNALS */ + + if (!isdigit((int) *cp)) { + Error(cip, kDontPerror, "Invalid reply: \"%s\"\n", cp); + cip->errNo = kErrInvalidReplyFromServer; +#ifndef NO_SIGNALS + (void) signal(SIGPIPE, osigpipe); +#endif + return (cip->errNo); + } + + rp->codeType = *cp - '0'; + cp += 3; + continuation = (*cp == '-'); + *cp++ = '\0'; + (void) STRNCPY(code, str); + rp->code = atoi(code); + (void) AddLine(&rp->msg, cp); + if (eofError < 0) { + /* Read reply, but EOF was there also. */ + rp->hadEof = 1; + } + + while (continuation) { + +#ifdef NO_SIGNALS + result = SReadline(&cip->ctrlSrl, str, sizeof(str) - 1); + if (result == kTimeoutErr) { + /* timeout */ + Error(cip, kDontPerror, "Could not read reply from control connection -- timed out.\n"); + FTPShutdownHost(vcip); + cip->errNo = kErrControlTimedOut; + return (cip->errNo); + } else if (result == 0) { + /* eof */ + eofError = 1; + rp->hadEof = 1; + if (rp->eofOkay == 0) + Error(cip, kDontPerror, "Remote host has closed the connection.\n"); + FTPShutdownHost(vcip); + cip->errNo = kErrRemoteHostClosedConnection; + return (cip->errNo); + } else if (result < 0) { + /* error */ + Error(cip, kDoPerror, "Could not read reply from control connection"); + FTPShutdownHost(vcip); + cip->errNo = kErrInvalidReplyFromServer; + return (cip->errNo); + } + + if (str[result - 1] == '\n') + str[result - 1] = '\0'; +#else /* NO_SIGNALS */ + eofError = GetTelnetString(cip, str, sizeof(str), cip->cin, cip->cout); + if (eofError < 0) { + /* Read reply, but EOF was there also. */ + rp->hadEof = 1; + continuation = 0; + } +#endif /* NO_SIGNALS */ + cp = str; + if (strncmp(code, cp, SZ(3)) == 0) { + cp += 3; + if (*cp == ' ') + continuation = 0; + ++cp; + } + (void) AddLine(&rp->msg, cp); + } + + if (rp->code == 421) { + /* + * 421 Service not available, closing control connection. + * This may be a reply to any command if the service knows it + * must shut down. + */ + if (rp->eofOkay == 0) + Error(cip, kDontPerror, "Remote host has closed the connection.\n"); + FTPShutdownHost(vcip); + cip->errNo = kErrRemoteHostClosedConnection; +#ifndef NO_SIGNALS + (void) signal(SIGPIPE, osigpipe); +#endif + return(cip->errNo); + } + +#ifndef NO_SIGNALS + (void) signal(SIGPIPE, osigpipe); +#endif + return (kNoErr); +} /* GetResponse */ + + + + +/* This creates the complete command text to send, and writes it + * on the stream. + */ +#ifdef NO_SIGNALS + +static int +SendCommand(const FTPCIPtr cip, const char *cmdspec, va_list ap) +{ + longstring command; + int result; + + if (cip->ctrlSocketW != kClosedFileDescriptor) { +#ifdef HAVE_VSNPRINTF + (void) vsnprintf(command, sizeof(command) - 1, cmdspec, ap); + command[sizeof(command) - 1] = '\0'; +#else + (void) vsprintf(command, cmdspec, ap); +#endif + if ((strncmp(command, "PASS", SZ(4)) != 0) || ((strcmp(cip->user, "anonymous") == 0) && (cip->firewallType == kFirewallNotInUse))) + PrintF(cip, "Cmd: %s\n", command); + else + PrintF(cip, "Cmd: %s\n", "PASS xxxxxxxx"); + (void) STRNCAT(command, "\r\n"); /* Use TELNET end-of-line. */ + cip->lastFTPCmdResultStr[0] = '\0'; + cip->lastFTPCmdResultNum = -1; + + result = SWrite(cip->ctrlSocketW, command, strlen(command), (int) cip->ctrlTimeout, 0); + + if (result < 0) { + cip->errNo = kErrSocketWriteFailed; + Error(cip, kDoPerror, "Could not write to control stream.\n"); + return (cip->errNo); + } + return (kNoErr); + } + return (kErrNotConnected); +} /* SendCommand */ + +#else /* NO_SIGNALS */ + +static int +SendCommand(const FTPCIPtr cip, const char *cmdspec, va_list ap) +{ + longstring command; + int result; + volatile FTPCIPtr vcip; + volatile FTPSigProc osigpipe; + int sj; + + if (cip->cout != NULL) { +#ifdef HAVE_VSNPRINTF + (void) vsnprintf(command, sizeof(command) - 1, cmdspec, ap); + command[sizeof(command) - 1] = '\0'; +#else + (void) vsprintf(command, cmdspec, ap); +#endif + if ((strncmp(command, "PASS", SZ(4)) != 0) || ((strcmp(cip->user, "anonymous") == 0) && (cip->firewallType == kFirewallNotInUse))) + PrintF(cip, "Cmd: %s\n", command); + else + PrintF(cip, "Cmd: %s\n", "PASS xxxxxxxx"); + (void) STRNCAT(command, "\r\n"); /* Use TELNET end-of-line. */ + cip->lastFTPCmdResultStr[0] = '\0'; + cip->lastFTPCmdResultNum = -1; + + osigpipe = (volatile FTPSigProc) signal(SIGPIPE, BrokenCtrl); + vcip = cip; + +#ifdef HAVE_SIGSETJMP + sj = sigsetjmp(gBrokenCtrlJmp, 1); +#else + sj = setjmp(gBrokenCtrlJmp); +#endif /* HAVE_SIGSETJMP */ + + if (sj != 0) { + (void) signal(SIGPIPE, (FTPSigProc) osigpipe); + FTPShutdownHost(vcip); + if (vcip->eofOkay == 0) { + Error(cip, kDontPerror, "Remote host has closed the connection.\n"); + vcip->errNo = kErrRemoteHostClosedConnection; + return(vcip->errNo); + } + return (kNoErr); + } + + result = fputs(command, cip->cout); + if (result < 0) { + (void) signal(SIGPIPE, osigpipe); + cip->errNo = kErrSocketWriteFailed; + Error(cip, kDoPerror, "Could not write to control stream.\n"); + return (cip->errNo); + } + result = fflush(cip->cout); + if (result < 0) { + (void) signal(SIGPIPE, osigpipe); + cip->errNo = kErrSocketWriteFailed; + Error(cip, kDoPerror, "Could not write to control stream.\n"); + return (cip->errNo); + } + (void) signal(SIGPIPE, osigpipe); + return (kNoErr); + } + return (kErrNotConnected); +} /* SendCommand */ +#endif /* NO_SIGNALS */ + + + +/* For "simple" (i.e. not data transfer) commands, this routine is used + * to send the command and receive one response. It returns the codeType + * field of the 'Response' as the result, or a negative number upon error. + */ +/*VARARGS*/ +int +FTPCmd(const FTPCIPtr cip, const char *const cmdspec, ...) +{ + va_list ap; + int result; + ResponsePtr rp; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + rp = InitResponse(); + if (rp == NULL) { + result = kErrMallocFailed; + cip->errNo = kErrMallocFailed; + Error(cip, kDontPerror, "Malloc failed.\n"); + return (cip->errNo); + } + + va_start(ap, cmdspec); +#ifndef NO_SIGNALS + if (cip->ctrlTimeout > 0) + (void) alarm(cip->ctrlTimeout); +#endif /* NO_SIGNALS */ + result = SendCommand(cip, cmdspec, ap); + va_end(ap); + if (result < 0) { +#ifndef NO_SIGNALS + if (cip->ctrlTimeout > 0) + (void) alarm(0); +#endif /* NO_SIGNALS */ + return (result); + } + + /* Get the response to the command we sent. */ + result = GetResponse(cip, rp); +#ifndef NO_SIGNALS + if (cip->ctrlTimeout > 0) + (void) alarm(0); +#endif /* NO_SIGNALS */ + + if (result == kNoErr) + result = rp->codeType; + DoneWithResponse(cip, rp); + return (result); +} /* FTPCmd */ + + + + +/* This is for debugging the library -- don't use. */ +/*VARARGS*/ +int +FTPCmdNoResponse(const FTPCIPtr cip, const char *const cmdspec, ...) +{ + va_list ap; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + va_start(ap, cmdspec); +#ifndef NO_SIGNALS + if (cip->ctrlTimeout > 0) + (void) alarm(cip->ctrlTimeout); +#endif /* NO_SIGNALS */ + (void) SendCommand(cip, cmdspec, ap); +#ifndef NO_SIGNALS + if (cip->ctrlTimeout > 0) + (void) alarm(0); +#endif /* NO_SIGNALS */ + va_end(ap); + + return (kNoErr); +} /* FTPCmdNoResponse */ + + + + +int +WaitResponse(const FTPCIPtr cip, unsigned int sec) +{ + int result; + fd_set ss; + struct timeval tv; + int fd; + +#ifdef NO_SIGNALS + fd = cip->ctrlSocketR; +#else /* NO_SIGNALS */ + if (cip->cin == NULL) + return (-1); + fd = fileno(cip->cin); +#endif /* NO_SIGNALS */ + if (fd < 0) + return (-1); + FD_ZERO(&ss); + FD_SET(fd, &ss); + tv.tv_sec = (unsigned long) sec; + tv.tv_usec = 0; + result = select(fd + 1, SELECT_TYPE_ARG234 &ss, NULL, NULL, &tv); + return (result); +} /* WaitResponse */ + + + + +/* For "simple" (i.e. not data transfer) commands, this routine is used + * to send the command and receive one response. It returns the codeType + * field of the 'Response' as the result, or a negative number upon error. + */ + +/*VARARGS*/ +int +RCmd(const FTPCIPtr cip, ResponsePtr rp, const char *cmdspec, ...) +{ + va_list ap; + int result; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + va_start(ap, cmdspec); +#ifndef NO_SIGNALS + if (cip->ctrlTimeout > 0) + (void) alarm(cip->ctrlTimeout); +#endif /* NO_SIGNALS */ + result = SendCommand(cip, cmdspec, ap); + va_end(ap); + if (result < 0) { +#ifndef NO_SIGNALS + if (cip->ctrlTimeout > 0) + (void) alarm(0); +#endif /* NO_SIGNALS */ + return (result); + } + + /* Get the response to the command we sent. */ + result = GetResponse(cip, rp); +#ifndef NO_SIGNALS + if (cip->ctrlTimeout > 0) + (void) alarm(0); +#endif /* NO_SIGNALS */ + + if (result == kNoErr) + result = rp->codeType; + return (result); +} /* RCmd */ + + + +/* Returns -1 if an error occurred, or 0 if not. + * This differs from RCmd, which returns the code class of a response. + */ + +/*VARARGS*/ +int +FTPStartDataCmd(const FTPCIPtr cip, int netMode, int type, longest_int startPoint, const char *cmdspec, ...) +{ + va_list ap; + int result; + int respCode; + ResponsePtr rp; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + result = FTPSetTransferType(cip, type); + if (result < 0) + return (result); + + /* Re-set the cancellation flag. */ + cip->cancelXfer = 0; + + /* To transfer data, we do these things in order as specifed by + * the RFC. + * + * First, we tell the other side to set up a data line. This + * is done below by calling OpenDataConnection(), which sets up + * the socket. When we do that, the other side detects a connection + * attempt, so it knows we're there. Then tell the other side + * (by using listen()) that we're willing to receive a connection + * going to our side. + */ + + if ((result = OpenDataConnection(cip, cip->dataPortMode)) < 0) + goto done; + + /* If asked, attempt to start at a later position in the remote file. */ + if (startPoint != (longest_int) 0) { + if ((startPoint == kSizeUnknown) || ((result = SetStartOffset(cip, startPoint)) != 0)) + startPoint = (longest_int) 0; + } + cip->startPoint = startPoint; + + /* Now we tell the server what we want to do. This sends the + * the type of transfer we want (RETR, STOR, LIST, etc) and the + * parameters for that (files to send, directories to list, etc). + */ + va_start(ap, cmdspec); +#ifndef NO_SIGNALS + if (cip->ctrlTimeout > 0) + (void) alarm(cip->ctrlTimeout); +#endif /* NO_SIGNALS */ + result = SendCommand(cip, cmdspec, ap); + va_end(ap); + if (result < 0) { +#ifndef NO_SIGNALS + if (cip->ctrlTimeout > 0) + (void) alarm(0); +#endif /* NO_SIGNALS */ + goto done; + } + + /* Get the response to the transfer command we sent, to see if + * they can accomodate the request. If everything went okay, + * we will get a preliminary response saying that the transfer + * initiation was successful and that the data is there for + * reading (for retrieves; for sends, they will be waiting for + * us to send them something). + */ + rp = InitResponse(); + if (rp == NULL) { + Error(cip, kDontPerror, "Malloc failed.\n"); + cip->errNo = kErrMallocFailed; + result = cip->errNo; + goto done; + } + result = GetResponse(cip, rp); +#ifndef NO_SIGNALS + if (cip->ctrlTimeout > 0) + (void) alarm(0); +#endif /* NO_SIGNALS */ + + if (result < 0) + goto done; + respCode = rp->codeType; + DoneWithResponse(cip, rp); + + if (respCode > 2) { + cip->errNo = kErrCouldNotStartDataTransfer; + result = cip->errNo; + goto done; + } + + /* Now we accept the data connection that the other side is offering + * to us. Then we can do the actual I/O on the data we want. + */ + cip->netMode = netMode; + if ((result = AcceptDataConnection(cip)) < 0) + goto done; + return (kNoErr); + +done: + (void) FTPEndDataCmd(cip, 0); + return (result); +} /* FTPStartDataCmd */ + + + + +void +FTPAbortDataTransfer(const FTPCIPtr cip) +{ + ResponsePtr rp; + int result; + + if (cip->dataSocket != kClosedFileDescriptor) { + PrintF(cip, "Starting abort sequence.\n"); + SendTelnetInterrupt(cip); /* Probably could get by w/o doing this. */ + + result = FTPCmdNoResponse(cip, "ABOR"); + if (result != kNoErr) { + /* Linger could cause close to block, so unset it. */ + (void) SetLinger(cip, cip->dataSocket, 0); + CloseDataConnection(cip); + PrintF(cip, "Could not send abort command.\n"); + return; + } + + if (cip->abortTimeout > 0) { + result = WaitResponse(cip, (unsigned int) cip->abortTimeout); + if (result <= 0) { + /* Error or no response received to ABOR in time. */ + (void) SetLinger(cip, cip->dataSocket, 0); + CloseDataConnection(cip); + PrintF(cip, "No response received to abort request.\n"); + return; + } + } + + rp = InitResponse(); + if (rp == NULL) { + Error(cip, kDontPerror, "Malloc failed.\n"); + cip->errNo = kErrMallocFailed; + result = cip->errNo; + return; + } + + result = GetResponse(cip, rp); + if (result < 0) { + /* Shouldn't happen, and doesn't matter if it does. */ + (void) SetLinger(cip, cip->dataSocket, 0); + CloseDataConnection(cip); + PrintF(cip, "Invalid response to abort request.\n"); + DoneWithResponse(cip, rp); + return; + } + DoneWithResponse(cip, rp); + + /* A response to the abort request has been received. + * Now the only thing left to do is close the data + * connection, making sure to turn off linger mode + * since we don't care about straggling data bits. + */ + (void) SetLinger(cip, cip->dataSocket, 0); + CloseDataConnection(cip); /* Must close (by protocol). */ + PrintF(cip, "End abort.\n"); + } +} /* FTPAbortDataTransfer */ + + + + +int +FTPEndDataCmd(const FTPCIPtr cip, int didXfer) +{ + int result; + int respCode; + ResponsePtr rp; + + if (cip == NULL) + return (kErrBadParameter); + if (strcmp(cip->magic, kLibraryMagic)) + return (kErrBadMagic); + + CloseDataConnection(cip); + result = kNoErr; + if (didXfer) { + /* Get the response to the data transferred. Most likely a message + * saying that the transfer completed succesfully. However, if + * we tried to abort the transfer using ABOR, we will have a response + * to that command instead. + */ + rp = InitResponse(); + if (rp == NULL) { + Error(cip, kDontPerror, "Malloc failed.\n"); + cip->errNo = kErrMallocFailed; + result = cip->errNo; + return (result); + } + result = GetResponse(cip, rp); + if (result < 0) + return (result); + respCode = rp->codeType; + DoneWithResponse(cip, rp); + if (respCode != 2) { + cip->errNo = kErrDataTransferFailed; + result = cip->errNo; + } else { + result = kNoErr; + } + } + return (result); +} /* FTPEndDataCmd */ + + + + +int +BufferGets(char *buf, size_t bufsize, int inStream, char *secondaryBuf, char **secBufPtr, char **secBufLimit, size_t secBufSize) +{ + int err; + char *src; + char *dst; + char *dstlim; + int len; + int nr; + int haveEof = 0; + + err = 0; + dst = buf; + dstlim = dst + bufsize - 1; /* Leave room for NUL. */ + src = (*secBufPtr); + for ( ; dst < dstlim; ) { + if (src >= (*secBufLimit)) { + /* Fill the buffer. */ + +/* Don't need to poll it here. The routines that use BufferGets don't + * need any special processing during timeouts (i.e. progress reports), + * so go ahead and just let it block until there is data to read. + */ + nr = (int) read(inStream, secondaryBuf, secBufSize); + if (nr == 0) { + /* EOF. */ + haveEof = 1; + goto done; + } else if (nr < 0) { + /* Error. */ + err = -1; + goto done; + } + (*secBufPtr) = secondaryBuf; + (*secBufLimit) = secondaryBuf + nr; + src = (*secBufPtr); + if (nr < (int) secBufSize) + src[nr] = '\0'; + } + if (*src == '\r') { + ++src; + } else { + if (*src == '\n') { + /* *dst++ = *src++; */ ++src; + goto done; + } + *dst++ = *src++; + } + } + +done: + (*secBufPtr) = src; + *dst = '\0'; + len = (int) (dst - buf); + if (err < 0) + return (err); + if ((len == 0) && (haveEof == 1)) + return (-1); + return (len); /* May be zero, if a blank line. */ +} /* BufferGets */ + +/* eof */ diff --git a/reactos/apps/utils/net/ncftp/libncftp/syshdrs.h b/reactos/apps/utils/net/ncftp/libncftp/syshdrs.h new file mode 100644 index 00000000000..7a123cb99ad --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/syshdrs.h @@ -0,0 +1,237 @@ +/* syshdrs.h + * + * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft. + * All rights reserved. + * + */ + +#if defined(HAVE_CONFIG_H) +# include +#endif + +#if defined(WIN32) || defined(_WINDOWS) +# include "wincfg.h" +# include /* Includes */ +//# include +# ifdef HAVE_UNISTD_H +# include +# endif +# include +# include +# include +# ifdef HAVE_STRINGS_H +# include +# endif +# include +# include +# include +# include +# include +# include +# include +# include +# include +# define strcasecmp stricmp +# define strncasecmp strnicmp +# define sleep WinSleep +# ifndef S_ISREG +# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) +# define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) +# endif +# ifndef open +# define open _open +# define write _write +# define read _read +# define close _close +# define lseek _lseek +# define stat _stat +# define lstat _stat +# define fstat _fstat +# define dup _dup +# define utime _utime +# define utimbuf _utimbuf +# endif +# ifndef unlink +# define unlink remove +# endif +# define NO_SIGNALS 1 +# define USE_SIO 1 +#else /* UNIX */ + +#if defined(AIX) || defined(_AIX) +# define _ALL_SOURCE 1 +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include +#include +#include +#if !defined(HAVE_GETCWD) && defined(HAVE_GETWD) +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_STRINGS_H +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_NET_ERRNO_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#endif +#ifdef HAVE_NSERVE_H +# include +#endif +#ifdef HAVE_RESOLV_H +# include +#endif +#ifdef CAN_USE_SYS_SELECT_H +# include +#endif + +#ifdef HAVE_GETCWD +# ifndef HAVE_UNISTD_H + extern char *getcwd(); +# endif +#else +# ifdef HAVE_GETWD +# include +# ifndef MAXPATHLEN +# define MAXPATHLEN 1024 +# endif + extern char *getwd(char *); +# endif +#endif + +#endif /* UNIX */ + + +#if defined(HAVE_LONG_LONG) && defined(HAVE_OPEN64) +# define Open open64 +#else +# define Open open +#endif + +#if defined(HAVE_LONG_LONG) && defined(HAVE_STAT64) && defined(HAVE_STRUCT_STAT64) +# define Stat stat64 +# ifdef HAVE_FSTAT64 +# define Fstat fstat64 +# else +# define Fstat fstat +# endif +# ifdef HAVE_LSTAT64 +# define Lstat lstat64 +# else +# define Lstat lstat +# endif +#else +# define Stat stat +# define Fstat fstat +# define Lstat lstat +#endif + +#if defined(HAVE_LONG_LONG) && defined(HAVE_LSEEK64) +# define Lseek(a,b,c) lseek64(a, (longest_int) b, c) +#elif defined(HAVE_LONG_LONG) && defined(HAVE_LLSEEK) +# if 1 +# if defined(LINUX) && (LINUX <= 23000) +# define Lseek(a,b,c) lseek(a, (off_t) b, c) +# else +# define Lseek(a,b,c) llseek(a, (longest_int) b, c) +# endif +# else +# define Lseek(a,b,c) lseek(a, (off_t) b, c) +# endif +#else +# define Lseek(a,b,c) lseek(a, (off_t) b, c) +#endif + + +#ifndef IAC + +/* + * Definitions for the TELNET protocol. + */ +#define IAC 255 /* interpret as command: */ +#define DONT 254 /* you are not to use option */ +#define DO 253 /* please, you use option */ +#define WONT 252 /* I won't use option */ +#define WILL 251 /* I will use option */ +#define SB 250 /* interpret as subnegotiation */ +#define GA 249 /* you may reverse the line */ +#define EL 248 /* erase the current line */ +#define EC 247 /* erase the current character */ +#define AYT 246 /* are you there */ +#define AO 245 /* abort output--but let prog finish */ +#define IP 244 /* interrupt process--permanently */ +#define BREAK 243 /* break */ +#define DM 242 /* data mark--for connect. cleaning */ +#define NOP 241 /* nop */ +#define SE 240 /* end sub negotiation */ +#define EOR 239 /* end of record (transparent mode) */ +#define ABORT 238 /* Abort process */ +#define SUSP 237 /* Suspend process */ +#define xEOF 236 /* End of file: EOF is already used... */ + +#define SYNCH 242 /* for telfunc calls */ +#endif + +#ifdef HAVE_UTIME_H +# include +#else + struct utimbuf { time_t actime, modtime; }; +#endif + + +#ifdef HAVE_LIBSOCKS5 +# define SOCKS 5 +# include +#endif + +#if 1 /* %config2% -- set by configure script -- do not modify */ +# ifndef USE_SIO +# define USE_SIO 1 +# endif +# ifndef NO_SIGNALS +# define NO_SIGNALS 1 +# endif +#else +# ifndef USE_SIO +# define USE_SIO 0 +# endif + /* #undef NO_SIGNALS */ +#endif + +#if USE_SIO +# include "sio\sio.h" /* Library header. */ +#endif + +#include "Strn\Strn.h" /* Library header. */ +#include "ncftp.h" /* Library header. */ + +#include "util.h" +#include "ftp.h" + +/* eof */ diff --git a/reactos/apps/utils/net/ncftp/libncftp/util.c b/reactos/apps/utils/net/ncftp/libncftp/util.c new file mode 100644 index 00000000000..c2e5155d902 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/util.c @@ -0,0 +1,1048 @@ +/* util.c + * + * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft. + * All rights reserved. + * + */ + +#include "syshdrs.h" + +#if defined(WIN32) || defined(_WINDOWS) +#include +extern void GetSpecialDir(char *dst, size_t size, int whichDir); +#endif + + +static void * +Realloc(void *ptr, size_t siz) +{ + if (ptr == NULL) + return (void *) malloc(siz); + return ((void *) realloc(ptr, siz)); +} /* Realloc */ + + +/* Use getcwd/getwd to get the full path of the current local + * working directory. + */ +char * +FTPGetLocalCWD(char *buf, size_t size) +{ +#ifdef HAVE_GETCWD + static char *cwdBuf = NULL; + static size_t cwdBufSize = 0; + + if (cwdBufSize == 0) { + cwdBufSize = (size_t) 128; + cwdBuf = (char *) malloc(cwdBufSize); + } + + for (errno = 0; ; ) { + if (cwdBuf == NULL) { + return NULL; + } + + if (getcwd(cwdBuf, cwdBufSize) != NULL) + break; + if (errno != ERANGE) { + (void) Strncpy(buf, ".", size); + return NULL; + } + cwdBufSize *= 2; + cwdBuf = (char *) Realloc(cwdBuf, cwdBufSize); + } + + return (Strncpy(buf, cwdBuf, size)); +#else +#ifdef HAVE_GETWD + static char *cwdBuf = NULL; + char *dp; + + /* Due to the way getwd is usually implemented, it's + * important to have a buffer large enough to hold the + * whole thing. getwd usually starts at the end of the + * buffer, and works backwards, returning you a pointer + * to the beginning of it when it finishes. + */ + if (size < MAXPATHLEN) { + /* Buffer not big enough, so use a temporary one, + * and then copy the first 'size' bytes of the + * temporary buffer to your 'buf.' + */ + if (cwdBuf == NULL) { + cwdBuf = (char *) malloc((size_t) MAXPATHLEN); + if (cwdBuf == NULL) { + return NULL; + } + } + dp = cwdBuf; + } else { + /* Buffer is big enough already. */ + dp = buf; + } + *dp = '\0'; + if (getwd(dp) == NULL) { + /* getwd() should write the reason why in the buffer then, + * according to the man pages. + */ + (void) Strncpy(buf, ".", size); + return (NULL); + } + return (Strncpy(buf, dp, size)); + +#elif defined(WIN32) || defined(_WINDOWS) + if (GetCurrentDirectory((DWORD) size - 1, buf) < 1) + return NULL; + buf[size - 1] = '\0'; + return buf; +#else + /* Not a solution, but does anybody not have either of + * getcwd or getwd? + */ + --Error--; +#endif +#endif +} /* GetCWD */ + + + +/* Read a line, and axe the end-of-line. */ +char * +FGets(char *str, size_t size, FILE *fp) +{ + char *cp, *nlptr; + + cp = fgets(str, ((int) size) - 1, fp); + if (cp != NULL) { + cp[((int) size) - 1] = '\0'; /* ensure terminator */ + nlptr = cp + strlen(cp) - 1; + if (*nlptr == '\n') + *nlptr = '\0'; + } else { + memset(str, 0, size); + } + return cp; +} /* FGets */ + + + + +#if defined(WIN32) || defined(_WINDOWS) + +int gettimeofday(struct timeval *const tp, void *junk) +{ + SYSTEMTIME systemTime; + + GetSystemTime(&systemTime); + + /* Create an arbitrary second counter; + * Note that this particular one creates + * a problem at the end of the month. + */ + tp->tv_sec = + systemTime.wSecond + + systemTime.wMinute * 60 + + systemTime.wHour * 3600 + + systemTime.wDay * 86400; + + tp->tv_usec = systemTime.wMilliseconds * 1000; + + return 0; +} /* gettimeofday */ + +#endif + + + + +#if defined(WIN32) || defined(_WINDOWS) +#else +/* This looks up the user's password entry, trying to look by the username. + * We have a couple of extra hacks in place to increase the probability + * that we can get the username. + */ +struct passwd * +GetPwByName(void) +{ + char *cp; + struct passwd *pw; + + cp = getlogin(); + if (cp == NULL) { + cp = (char *) getenv("LOGNAME"); + if (cp == NULL) + cp = (char *) getenv("USER"); + } + pw = NULL; + if (cp != NULL) + pw = getpwnam(cp); + return (pw); +} /* GetPwByName */ +#endif + + + +char * +GetPass(const char *const prompt) +{ +#ifdef HAVE_GETPASS + return getpass(prompt); +#elif defined(_CONSOLE) && (defined(WIN32) || defined(_WINDOWS)) + static char pwbuf[128]; + char *dst, *dlim; + int c; + + (void) memset(pwbuf, 0, sizeof(pwbuf)); + if (! _isatty(_fileno(stdout))) + return (pwbuf); + (void) fputs(prompt, stdout); + (void) fflush(stdout); + + for (dst = pwbuf, dlim = dst + sizeof(pwbuf) - 1;;) { + c = _getch(); + if ((c == 0) || (c == 0xe0)) { + /* The key is a function or arrow key; read and discard. */ + (void) _getch(); + } + if ((c == '\r') || (c == '\n')) + break; + if (dst < dlim) + *dst++ = c; + } + *dst = '\0'; + + (void) fflush(stdout); + (void) fflush(stdin); + return (pwbuf); +#else + static char pwbuf[128]; + + (void) memset(pwbuf, 0, sizeof(pwbuf)); +#if defined(WIN32) || defined(_WINDOWS) + if (! _isatty(_fileno(stdout))) +#else + if (! isatty(1)) +#endif + return (pwbuf); + (void) fputs(prompt, stdout); + (void) fflush(stdout); + (void) FGets(pwbuf, sizeof(pwbuf), stdin); + (void) fflush(stdout); + (void) fflush(stdin); + return (pwbuf); +#endif +} /* GetPass */ + + + + +void +GetHomeDir(char *dst, size_t size) +{ +#if defined(WIN32) || defined(_WINDOWS) + const char *homedrive, *homepath; + + homedrive = getenv("HOMEDRIVE"); + homepath = getenv("HOMEPATH"); + if ((homedrive != NULL) && (homepath != NULL)) { + (void) Strncpy(dst, homedrive, size); + (void) Strncat(dst, homepath, size); + return; + } + +// GetSpecialDir(dst, size, CSIDL_PERSONAL /* "My Documents" */); +// if (dst[0] != '\0') +// return; +// +// dst[0] = '\0'; +// if (GetWindowsDirectory(dst, size - 1) < 1) +// (void) Strncpy(dst, ".", size); +// else if (dst[1] == ':') { +// dst[2] = '\\'; +// dst[3] = '\0'; +// } +#else + const char *cp; + struct passwd *pw; + + pw = NULL; +#if defined(USE_GETPWUID) + /* Try to use getpwuid(), but if we have to, fall back to getpwnam(). */ + if ((pw = getpwuid(getuid())) == NULL) + pw = GetPwByName(); /* Oh well, try getpwnam() then. */ +#else + /* Try to use getpwnam(), but if we have to, fall back to getpwuid(). */ + if ((pw = GetPwByName()) == NULL) + pw = getpwuid(getuid()); /* Try getpwnam() then. */ +#endif + if (pw != NULL) + cp = pw->pw_dir; + else if ((cp = (const char *) getenv("LOGNAME")) == NULL) + cp = "."; + (void) Strncpy(dst, cp, size); +#endif +} /* GetHomeDir */ + + + + +void +GetUsrName(char *dst, size_t size) +{ +#if defined(WIN32) || defined(_WINDOWS) + DWORD size1; + + size1 = size - 1; + if (! GetUserName(dst, &size1)) + (void) strncpy(dst, "unknown", size); + dst[size - 1] = '\0'; +#else + const char *cp; + struct passwd *pw; + + pw = NULL; +#ifdef USE_GETPWUID + /* Try to use getpwuid(), but if we have to, fall back to getpwnam(). */ + if ((pw = getpwuid(getuid())) == NULL) + pw = GetPwByName(); /* Oh well, try getpwnam() then. */ +#else + /* Try to use getpwnam(), but if we have to, fall back to getpwuid(). */ + if ((pw = GetPwByName()) == NULL) + pw = getpwuid(getuid()); /* Try getpwnam() then. */ +#endif + if (pw != NULL) + cp = pw->pw_name; + else if ((cp = (const char *) getenv("LOGNAME")) == NULL) + cp = "UNKNOWN"; + (void) Strncpy(dst, cp, size); +#endif +} /* GetUserName */ + + + + + +/* Closes the file supplied, if it isn't a std stream. */ +void +CloseFile(FILE **f) +{ + if (*f != NULL) { + if ((*f != stdout) && (*f != stdin) && (*f != stderr)) + (void) fclose(*f); + *f = NULL; + } +} /* CloseFile */ + + + +/*VARARGS*/ +void +PrintF(const FTPCIPtr cip, const char *const fmt, ...) +{ + va_list ap; + char buf[256]; + + va_start(ap, fmt); + if (cip->debugLog != NULL) { + (void) vfprintf(cip->debugLog, fmt, ap); + (void) fflush(cip->debugLog); + } + if (cip->debugLogProc != NULL) { +#ifdef HAVE_VSNPRINTF + (void) vsnprintf(buf, sizeof(buf) - 1, fmt, ap); + buf[sizeof(buf) - 1] = '\0'; +#else + (void) vsprintf(buf, fmt, ap); +#endif + (*cip->debugLogProc)(cip, buf); + } + va_end(ap); +} /* PrintF */ + + + + + +/*VARARGS*/ +void +Error(const FTPCIPtr cip, const int pError, const char *const fmt, ...) +{ + va_list ap; + int errnum; + size_t len; + char buf[256]; + int endsinperiod; + int endsinnewline; +#ifndef HAVE_STRERROR + char errnostr[16]; +#endif + + errnum = errno; + va_start(ap, fmt); +#ifdef HAVE_VSNPRINTF + vsnprintf(buf, sizeof(buf) - 1, fmt, ap); + buf[sizeof(buf) - 1] = '\0'; +#else + (void) vsprintf(buf, fmt, ap); +#endif + va_end(ap); + + if (pError != 0) { + len = strlen(buf); + endsinperiod = 0; + endsinnewline = 0; + if (len > 2) { + if (buf[len - 1] == '\n') { + endsinnewline = 1; + buf[len - 1] = '\0'; + if (buf[len - 2] == '.') { + endsinperiod = 1; + buf[len - 2] = '\0'; + } + } else if (buf[len - 1] == '.') { + endsinperiod = 1; + buf[len - 1] = '\0'; + } + } +#ifdef HAVE_STRERROR + (void) STRNCAT(buf, ": "); + (void) STRNCAT(buf, strerror(errnum)); +#else +# ifdef HAVE_SNPRINTF + sprintf(errnostr, sizeof(errnostr) - 1, " (errno = %d)", errnum); + errnostr[sizeof(errnostr) - 1] = '\0'; +# else + sprintf(errnostr, " (errno = %d)", errnum); +# endif + STRNCAT(buf, errnostr); +#endif + if (endsinperiod != 0) + (void) STRNCAT(buf, "."); + if (endsinnewline != 0) + (void) STRNCAT(buf, "\n"); + } + + if (cip->errLog != NULL) { + (void) fprintf(cip->errLog, "%s", buf); + (void) fflush(cip->errLog); + } + if ((cip->debugLog != NULL) && (cip->debugLog != cip->errLog)) { + if ((cip->errLog != stderr) || (cip->debugLog != stdout)) { + (void) fprintf(cip->debugLog, "%s", buf); + (void) fflush(cip->debugLog); + } + } + if (cip->errLogProc != NULL) { + (*cip->errLogProc)(cip, buf); + } + if ((cip->debugLogProc != NULL) && (cip->debugLogProc != cip->errLogProc)) { + (*cip->debugLogProc)(cip, buf); + } +} /* Error */ + + + + +/* Cheezy, but somewhat portable way to get GMT offset. */ +#ifdef HAVE_MKTIME +static +time_t GetUTCOffset(int mon, int mday) +{ + struct tm local_tm, utc_tm, *utc_tmptr; + time_t local_t, utc_t, utcOffset; + + ZERO(local_tm); + ZERO(utc_tm); + utcOffset = 0; + + local_tm.tm_year = 94; /* Doesn't really matter. */ + local_tm.tm_mon = mon; + local_tm.tm_mday = mday; + local_tm.tm_hour = 12; + local_tm.tm_isdst = -1; + local_t = mktime(&local_tm); + + if (local_t != (time_t) -1) { + utc_tmptr = gmtime(&local_t); + utc_tm.tm_year = utc_tmptr->tm_year; + utc_tm.tm_mon = utc_tmptr->tm_mon; + utc_tm.tm_mday = utc_tmptr->tm_mday; + utc_tm.tm_hour = utc_tmptr->tm_hour; + utc_tm.tm_isdst = -1; + utc_t = mktime(&utc_tm); + + if (utc_t != (time_t) -1) + utcOffset = (local_t - utc_t); + } + return (utcOffset); +} /* GetUTCOffset */ +#endif /* HAVE_MKTIME */ + + + +/* Converts a MDTM date, like "19930602204445" + * format to a time_t. + */ +time_t UnMDTMDate(char *dstr) +{ +#ifndef HAVE_MKTIME + return (kModTimeUnknown); +#else + struct tm ut, *t; + time_t mt, now; + time_t result = kModTimeUnknown; + + if (strncmp(dstr, "19100", 5) == 0) { + /* Server Y2K bug! */ + return (result); + } + + (void) time(&now); + t = localtime(&now); + + /* Copy the whole structure of the 'tm' pointed to by t, so it will + * also set all fields we don't specify explicitly to be the same as + * they were in t. That way we copy non-standard fields such as + * tm_gmtoff, if it exists or not. + */ + ut = *t; + + /* The time we get back from the server is (should be) in UTC. */ + if (sscanf(dstr, "%04d%02d%02d%02d%02d%02d", + &ut.tm_year, + &ut.tm_mon, + &ut.tm_mday, + &ut.tm_hour, + &ut.tm_min, + &ut.tm_sec) == 6) + { + --ut.tm_mon; + ut.tm_year -= 1900; + mt = mktime(&ut); + if (mt != (time_t) -1) { + mt += GetUTCOffset(ut.tm_mon, ut.tm_mday); + result = (time_t) mt; + } + } + return result; +#endif /* HAVE_MKTIME */ +} /* UnMDTMDate */ + + + +int +GetSockBufSize(int sockfd, size_t *rsize, size_t *ssize) +{ +#ifdef SO_SNDBUF + int rc = -1; + int opt; + int optsize; + + if (ssize != NULL) { + opt = 0; + optsize = sizeof(opt); + rc = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *) &opt, &optsize); + if (rc == 0) + *ssize = (size_t) opt; + else + *ssize = 0; + } + if (rsize != NULL) { + opt = 0; + optsize = sizeof(opt); + rc = getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char *) &opt, &optsize); + if (rc == 0) + *rsize = (size_t) opt; + else + *rsize = 0; + } + return (rc); +#else + if (ssize != NULL) + *ssize = 0; + if (rsize != NULL) + *rsize = 0; + return (-1); +#endif +} /* GetSockBufSize */ + + + +int +SetSockBufSize(int sockfd, size_t rsize, size_t ssize) +{ +#ifdef SO_SNDBUF + int rc = -1; + int opt; + int optsize; + +#ifdef TCP_RFC1323 + /* This is an AIX-specific socket option to do RFC1323 large windows */ + if (ssize > 0 || rsize > 0) { + opt = 1; + optsize = sizeof(opt); + rc = setsockopt(sockfd, IPPROTO_TCP, TCP_RFC1323, &opt, optsize); + } +#endif + + if (ssize > 0) { + opt = (int) ssize; + optsize = sizeof(opt); + rc = setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *) &opt, optsize); + } + if (rsize > 0) { + opt = (int) rsize; + optsize = sizeof(opt); + rc = setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char *) &opt, optsize); + } + return (rc); +#else + return (-1); +#endif +} /* SetSockBufSize */ + + + +void +Scramble(unsigned char *dst, size_t dsize, unsigned char *src, char *key) +{ + int i; + unsigned int ch; + unsigned char *k2; + size_t keyLen; + + keyLen = strlen(key); + k2 = (unsigned char *) key; + for (i=0; i < (int) dsize - 1; i++) { + ch = src[i]; + if (ch == 0) + break; + dst[i] = (unsigned char) (ch ^ (int) (k2[i % (int) keyLen])); + } + dst[i] = '\0'; +} /* Scramble */ + + + + + +#if defined(WIN32) || defined(_WINDOWS) +void WinSleep(unsigned int seconds) +{ + DWORD now, deadline; + DWORD milliseconds = seconds * 1000; + + if (milliseconds > 0) { + now = GetTickCount(); + deadline = now + milliseconds; + if (now < deadline) { + /* Typical case */ + do { + milliseconds = deadline - now; + Sleep(milliseconds); + now = GetTickCount(); + } while (now < deadline); + } else { + /* Overflow case */ + deadline = now - 1; + milliseconds -= (0xFFFFFFFF - now); + do { + Sleep(0xFFFFFFFF - now); + now = GetTickCount(); + } while (now > deadline); + /* Counter has now wrapped around */ + deadline = now + milliseconds; + do { + milliseconds = deadline - now; + Sleep(milliseconds); + now = GetTickCount(); + } while (now < deadline); + } + } +} /* WinSleep */ + + + + +char * +StrFindLocalPathDelim(const char *src) /* TODO: optimize */ +{ + const char *first; + int c; + + first = NULL; + for (;;) { + c = *src++; + if (c == '\0') + break; + if (IsLocalPathDelim(c)) { + first = src - 1; + break; + } + } + + return ((char *) first); +} /* StrFindLocalPathDelim */ + + + +char * +StrRFindLocalPathDelim(const char *src) /* TODO: optimize */ +{ + const char *last; + int c; + + last = NULL; + for (;;) { + c = *src++; + if (c == '\0') + break; + if (IsLocalPathDelim(c)) + last = src - 1; + } + + return ((char *) last); +} /* StrRFindLocalPathDelim */ + + + + +void +StrRemoveTrailingLocalPathDelim(char *dst) +{ + char *cp; + + cp = StrRFindLocalPathDelim(dst); + if ((cp == NULL) || (cp[1] != '\0')) + return; + + /* Note: Do not destroy a path of "/" */ + while ((cp > dst) && (IsLocalPathDelim(*cp))) + *cp-- = '\0'; +} /* StrRemoveTrailingLocalPathDelim */ + + + +void +TVFSPathToLocalPath(char *dst) +{ + int c; + + /* Note: Technically we don't need to do this, + * since Win32 accepts a / as equivalent to a \ + * in a pathname. + */ + if (dst != NULL) { + for (;;) { + c = *dst++; + if (c == '\0') + break; + if (c == '/') + dst[-1] = LOCAL_PATH_DELIM; + } + } +} /* TVFSPathToLocalPath */ + + +void +LocalPathToTVFSPath(char *dst) +{ + int c; + + if (dst != NULL) { + for (;;) { + c = *dst++; + if (c == '\0') + break; + if (c == LOCAL_PATH_DELIM) + dst[-1] = '/'; + } + } +} /* LocalPathToTVFSPath */ +#endif /* WINDOWS */ + + + + +void +StrRemoveTrailingSlashes(char *dst) +{ + char *cp; + + cp = strrchr(dst, '/'); + if ((cp == NULL) || (cp[1] != '\0')) + return; + + /* Note: Do not destroy a path of "/" */ + while ((cp > dst) && (*cp == '/')) + *cp-- = '\0'; +} /* StrRemoveTrailingSlashes */ + + + + +int +MkDirs(const char *const newdir, int mode1) +{ + char s[512]; + int rc; + char *cp, *sl; +#if defined(WIN32) || defined(_WINDOWS) + struct _stat st; + char *share; +#else + struct Stat st; + mode_t mode = (mode_t) mode1; +#endif + +#if defined(WIN32) || defined(_WINDOWS) + if ((isalpha(newdir[0])) && (newdir[1] == ':')) { + if (! IsLocalPathDelim(newdir[2])) { + /* Special case "c:blah", and errout. + * "c:\blah" must be used or _access GPFs. + */ + errno = EINVAL; + return (-1); + } else if (newdir[3] == '\0') { + /* Special case root directory, which cannot be made. */ + return (0); + } + } else if (IsUNCPrefixed(newdir)) { + share = StrFindLocalPathDelim(newdir + 2); + if ((share == NULL) || (StrFindLocalPathDelim(share + 1) == NULL)) + return (-1); + } + + if (_access(newdir, 00) == 0) { + if (_stat(newdir, &st) < 0) + return (-1); + if (! S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + return (-1); + } + return 0; + } +#else + if (access(newdir, F_OK) == 0) { + if (Stat(newdir, &st) < 0) + return (-1); + if (! S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + return (-1); + } + return 0; + } +#endif + + (void) strncpy(s, newdir, sizeof(s)); + if (s[sizeof(s) - 1] != '\0') { +#ifdef ENAMETOOLONG + errno = ENAMETOOLONG; +#else + errno = EINVAL; + return (-1); +#endif + } + + cp = StrRFindLocalPathDelim(s); + if (cp == NULL) { +#if defined(WIN32) || defined(_WINDOWS) + if (! CreateDirectory(newdir, (LPSECURITY_ATTRIBUTES) 0)) + return (-1); + return (0); +#else + rc = mkdir(newdir, mode); + return (rc); +#endif + } else if (cp[1] == '\0') { + /* Remove trailing slashes from path. */ + --cp; + while (cp > s) { + if (! IsLocalPathDelim(*cp)) + break; + --cp; + } + cp[1] = '\0'; + cp = StrRFindLocalPathDelim(s); + if (cp == NULL) { +#if defined(WIN32) || defined(_WINDOWS) + if (! CreateDirectory(s, (LPSECURITY_ATTRIBUTES) 0)) + return (-1); +#else + rc = mkdir(s, mode); + return (rc); +#endif + } + } + + /* Find the deepest directory in this + * path that already exists. When + * we do, we want to have the 's' + * string as it was originally, but + * with 'cp' pointing to the first + * slash in the path that starts the + * part that does not exist. + */ + sl = NULL; + for (;;) { + *cp = '\0'; +#if defined(WIN32) || defined(_WINDOWS) + rc = _access(s, 00); +#else + rc = access(s, F_OK); +#endif + if (sl != NULL) + *sl = LOCAL_PATH_DELIM; + if (rc == 0) { + *cp = LOCAL_PATH_DELIM; + break; + } + sl = cp; + cp = StrRFindLocalPathDelim(s); + if (cp == NULL) { + /* We do not have any more + * slashes, so none of the + * new directory's components + * existed before, so we will + * have to make everything + * starting at the first node. + */ + if (sl != NULL) + *sl = LOCAL_PATH_DELIM; + + /* We refer to cp + 1 below, + * so this is why we can + * set "cp" to point to the + * byte before the array starts. + */ + cp = s - 1; + break; + } + } + + for (;;) { + /* Extend the path we have to + * include the next component + * to make. + */ + sl = StrFindLocalPathDelim(cp + 1); + if (sl == s) { + /* If the next slash is pointing + * to the start of the string, then + * the path is an absolute path and + * we don't need to make the root node, + * and besides the next mkdir would + * try an empty string. + */ + ++cp; + sl = StrFindLocalPathDelim(cp + 1); + } + if (sl != NULL) { + *sl = '\0'; + } +#if defined(WIN32) || defined(_WINDOWS) + if (! CreateDirectory(s, (LPSECURITY_ATTRIBUTES) 0)) + return (-1); +#else + rc = mkdir(s, mode); + if (rc < 0) + return rc; +#endif + if (sl == NULL) + break; + *sl = LOCAL_PATH_DELIM; + cp = sl; + } + return (0); +} /* MkDirs */ + + + + +int +FilenameExtensionIndicatesASCII(const char *const pathName, const char *const extnList) +{ + const char *extn; + char *cp; + int c; + char extnPattern[16]; + + extn = pathName + strlen(pathName) - 1; + forever { + if (extn <= pathName) + return (0); /* End of pathname, no extension. */ + c = (int) *--extn; + if (IsLocalPathDelim(c)) + return (0); /* End of filename, no extension. */ + if (c == '.') { + extn += 1; + break; + } + } + if (strlen(extn) > (sizeof(extnPattern) - 2 - 1 - 1)) { + return (0); + } +#ifdef HAVE_SNPRINTF + snprintf(extnPattern, sizeof(extnPattern), +#else + sprintf(extnPattern, +#endif + "|.%s|", + extn + ); + + cp = extnPattern; + forever { + c = *cp; + if (c == '\0') + break; + if (isupper(c)) { + c = tolower(c); + *cp++ = (char) c; + } else { + cp++; + } + } + + /* Extension list is specially formatted, like this: + * + * |ext1|ext2|ext3|...|extN| + * + * I.e, each filename extension is delimited with + * a pipe, and we always begin and end the string + * with a pipe. + */ + if (strstr(extnList, extnPattern) != NULL) { + return (1); + } + return (0); +} /* FilenameExtensionIndicatesASCII */ + + + + + +#ifdef HAVE_SIGACTION +void (*NcSignal(int signum, void (*handler)(int)))(int) +{ + struct sigaction sa, osa; + + (void) sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = handler; + if (signum == SIGALRM) { +#ifdef SA_INTERRUPT + sa.sa_flags |= SA_INTERRUPT; +#endif + } else { +#ifdef SA_RESTART + sa.sa_flags |= SA_RESTART; +#endif + } + if (sigaction(signum, &sa, &osa) < 0) + return ((FTPSigProc) SIG_ERR); + return (osa.sa_handler); +} +#endif /* HAVE_SIGACTION */ + +/* eof */ diff --git a/reactos/apps/utils/net/ncftp/libncftp/util.h b/reactos/apps/utils/net/ncftp/libncftp/util.h new file mode 100644 index 00000000000..061a6ecef0a --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/util.h @@ -0,0 +1,108 @@ +/* Util.h + * + * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft. + * All rights reserved. + * + */ + +#ifndef _util_h_ +#define _util_h_ 1 + +typedef char string[160], str16[16], str32[32], str64[64]; +typedef char longstring[512]; +typedef char pathname[512]; + +#ifndef PTRZERO +# define PTRZERO(p,siz) (void) memset(p, 0, (size_t) (siz)) +#endif + +#define ZERO(a) PTRZERO(&(a), sizeof(a)) +#define STREQ(a,b) (strcmp(a,b) == 0) +#define STRNEQ(a,b,s) (strncmp(a,b,(size_t)(s)) == 0) + +#ifndef ISTRCMP +# ifdef HAVE_STRCASECMP +# define ISTRCMP strcasecmp +# define ISTRNCMP strncasecmp +# else +# define ISTRCMP strcmp +# define ISTRNCMP strncmp +# endif +#endif + +#define ISTREQ(a,b) (ISTRCMP(a,b) == 0) +#define ISTRNEQ(a,b,s) (ISTRNCMP(a,b,(size_t)(s)) == 0) + +typedef int (*cmp_t)(const void *, const void *); +#define QSORT(base,n,s,cmp) \ + qsort(base, (size_t)(n), (size_t)(s), (cmp_t)(cmp)) + +#define BSEARCH(key,base,n,s,cmp) \ + bsearch(key, base, (size_t)(n), (size_t)(s), (cmp_t)(cmp)) + +/* For Error(): */ +#define kDoPerror 1 +#define kDontPerror 0 + +#define kClosedFileDescriptor (-1) + +#define SZ(a) ((size_t) (a)) + +#ifndef F_OK +# define F_OK 0 +#endif + +#ifdef HAVE_REMOVE +# define UNLINK remove +#else +# define UNLINK unlink +#endif + +#ifndef SEEK_SET +# define SEEK_SET 0 +# define SEEK_CUR 1 +# define SEEK_END 2 +#endif /* SEEK_SET */ + +#ifdef SETVBUF_REVERSED +# define SETVBUF(a,b,c,d) setvbuf(a,c,b,d) +#else +# define SETVBUF setvbuf +#endif + + +/* Util.c */ +char *FGets(char *, size_t, FILE *); +struct passwd *GetPwByName(void); +void GetHomeDir(char *, size_t); +void GetUsrName(char *, size_t); +void CloseFile(FILE **); +void PrintF(const FTPCIPtr cip, const char *const fmt, ...) +#if (defined(__GNUC__)) && (__GNUC__ >= 2) +__attribute__ ((format (printf, 2, 3))) +#endif +; +void Error(const FTPCIPtr cip, const int pError, const char *const fmt, ...) +#if (defined(__GNUC__)) && (__GNUC__ >= 2) +__attribute__ ((format (printf, 3, 4))) +#endif +; +int GetSockBufSize(int sockfd, size_t *rsize, size_t *ssize); +int SetSockBufSize(int sockfd, size_t rsize, size_t ssize); +time_t UnMDTMDate(char *); +void Scramble(unsigned char *dst, size_t dsize, unsigned char *src, char *key); +#if defined(WIN32) || defined(_WINDOWS) +char *StrFindLocalPathDelim(const char *src); +char *StrRFindLocalPathDelim(const char *src); +void TVFSPathToLocalPath(char *dst); +void LocalPathToTVFSPath(char *dst); +int gettimeofday(struct timeval *const tp, void *junk); +#endif + +#ifdef HAVE_SIGACTION +void (*NcSignal(int signum, void (*handler)(int)))(int); +#elif !defined(NcSignal) +# define NcSignal signal +#endif + +#endif /* _util_h_ */ diff --git a/reactos/apps/utils/net/ncftp/libncftp/util2.cpp b/reactos/apps/utils/net/ncftp/libncftp/util2.cpp new file mode 100644 index 00000000000..6fb0147c206 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/util2.cpp @@ -0,0 +1,34 @@ +#include "syshdrs.h" + +#if defined(WIN32) || defined(_WINDOWS) + +extern "C" void +GetSpecialDir(char *dst, size_t size, int whichDir) +{ + LPITEMIDLIST idl; + LPMALLOC shl; + char path[MAX_PATH + 1]; + HRESULT hResult; + + memset(dst, 0, size); + hResult = SHGetMalloc(&shl); + if (SUCCEEDED(hResult)) { + hResult = SHGetSpecialFolderLocation( + NULL, + CSIDL_PERSONAL, + &idl + ); + + if (SUCCEEDED(hResult)) { + if(SHGetPathFromIDList(idl, path)) { + (void) strncpy(dst, path, size - 1); + dst[size - 1] = '\0'; + } + shl->Free(idl); + } + shl->Release(); + } +} // GetSpecialDir + + +#endif diff --git a/reactos/apps/utils/net/ncftp/libncftp/wincfg.h b/reactos/apps/utils/net/ncftp/libncftp/wincfg.h new file mode 100644 index 00000000000..c6afc4ddfcb --- /dev/null +++ b/reactos/apps/utils/net/ncftp/libncftp/wincfg.h @@ -0,0 +1,33 @@ +#define SELECT_TYPE_ARG1 int + +/* Define to the type of args 2, 3 and 4 for select(). */ +#define SELECT_TYPE_ARG234 (fd_set *) + +/* Define to the type of arg5 for select(). */ +#define SELECT_TYPE_ARG5 (struct timeval *) + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you have the gethostname function. */ +#define HAVE_GETHOSTNAME 1 + +/* Define if you have the mktime function. */ +#define HAVE_MKTIME 1 + +/* Define if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* #define HAVE_STRCASECMP 1 */ + +/* Define if you have the strstr function. */ +#define HAVE_STRSTR 1 + +/* Define if you have the header file. */ +/* #define HAVE_UNISTD_H 1 */ + +#define HAVE_LONG_LONG 1 +#define SCANF_LONG_LONG "%I64d" +#define PRINTF_LONG_LONG "%I64d" +#define PRINTF_LONG_LONG_I64D 1 +#define SCANF_LONG_LONG_I64D 1 diff --git a/reactos/apps/utils/net/ncftp/makefile b/reactos/apps/utils/net/ncftp/makefile new file mode 100644 index 00000000000..004068708f0 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/makefile @@ -0,0 +1,105 @@ +# +# ncftp 3.0.3 for reactos ported from MS-Vc++ +# sedwards 12-20-01 + +PATH_TO_TOP = ../../.. + +TARGET_TYPE = program + +TARGET_APPTYPE = console + +TARGET_NAME = ftp + +TARGET_SDKLIBS = kernel32.a ws2_32.a + +TARGET_CFLAGS = -Dncftp + +TARGET_CLEAN = \ +sio/*.o Strn/*.o libncftp/*.o ncftp/*.o + +OBJECTS_SIO = \ +sio\PRead.o \ +sio\PWrite.o \ +sio\SAcceptA.o \ +sio\SAcceptS.o \ +sio\SBind.o \ +sio\SClose.o \ +sio\SConnect.o \ +sio\SConnectByName.o \ +sio\SNew.o \ +sio\SRead.o \ +sio\SReadline.o \ +sio\SRecv.o \ +sio\SRecvfrom.o \ +sio\SRecvmsg.o \ +sio\SSelect.o \ +sio\SSend.o \ +sio\SSendto.o \ +sio\SSendtoByName.o \ +sio\SWrite.o \ +sio\SocketUtil.o \ +sio\StrAddr.o \ +sio\UAcceptA.o \ +sio\UAcceptS.o \ +sio\UBind.o \ +sio\UConnect.o \ +sio\UConnectByName.o \ +sio\UNew.o \ +sio\URecvfrom.o \ +sio\USendto.o \ +sio\USendtoByName.o \ +sio\SError.o \ +sio\main.o \ +sio\SWait.o + +OBJECTS_STRN = \ +Strn\Dynscat.o \ +Strn\Strncpy.o \ +Strn\Strncat.o \ +Strn\Strntok.o \ +Strn\Strnpcpy.o \ +Strn\Strnpcat.o \ +Strn\strtokc.o \ +Strn\version.o + +OBJECTS_LIBNCFTP = \ +libncftp\open.o \ +libncftp\cmds.o \ +libncftp\util.o \ +libncftp\rcmd.o \ +libncftp\ftp.o \ +libncftp\io.o \ +libncftp\errno.o \ +libncftp\linelist.o \ +libncftp\glob.o + +OBJECTS_NCFTP = \ +ncftp\cmds.o \ +ncftp\cmdlist.o \ +ncftp\getopt.o \ +ncftp\ls.o \ +ncftp\main.o \ +ncftp\version.o \ +ncftp\shell.o \ +ncftp\util.o \ +ncftp\readln.o \ +ncftp\progress.o \ +ncftp\bookmark.o \ +ncftp\pref.o \ +ncftp\preffw.o \ +ncftp\trace.o \ +ncftp\spool.o \ +ncftp\log.o \ +ncftp\getline.o + +TARGET_OBJECTS = \ + $(OBJECTS_SIO) \ + $(OBJECTS_STRN) \ + $(OBJECTS_LIBNCFTP) \ + $(OBJECTS_NCFTP) + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk + +# EOF \ No newline at end of file diff --git a/reactos/apps/utils/net/ncftp/ncftp/Makefile.in b/reactos/apps/utils/net/ncftp/ncftp/Makefile.in new file mode 100644 index 00000000000..2a603c27f68 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/ncftp/Makefile.in @@ -0,0 +1,89 @@ +#----------------------------------------------------------------------------- +# +# NcFTP makefile for the platform @OS@, on the host @host@. +# +#----------------------------------------------------------------------------- + +CC=@CC@ +CFLAGS=@CFLAGS@ +#CC=gcc +#CFLAGS=-O2 -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wshadow -Wbad-function-cast -Wwrite-strings -Wconversion +VPATH=@srcdir@ +CPPFLAGS=@CPPFLAGS@ -I. -I../libncftp -I../Strn -I../sio +prefix=@prefix@ +exec_prefix=@exec_prefix@ +BINDIR=@bindir@ + +LIBS=@LIBS@ +STRIP=strip +LDFLAGS=-L../libncftp -L../Strn -L../sio @LDFLAGS@ + +# Any -D definitions: +BETA=# -DBETA=20 +DEFS=-Dncftp $(BETA) -DBINDIR=\"$(BINDIR)\" @DEFS@ + +OBJS=cmds.@OBJEXT@ cmdlist.@OBJEXT@ getopt.@OBJEXT@ ls.@OBJEXT@ main.@OBJEXT@ version.@OBJEXT@ shell.@OBJEXT@ util.@OBJEXT@ readln.@OBJEXT@ progress.@OBJEXT@ bookmark.@OBJEXT@ pref.@OBJEXT@ preffw.@OBJEXT@ trace.@OBJEXT@ spool.@OBJEXT@ log.@OBJEXT@ getline.@OBJEXT@ + +DPROGS=../bin/ncftp@EXEEXT@ + +all: $(DPROGS) + -@echo 'Done making NcFTP.' + +../bin/ncftp@EXEEXT@: $(OBJS) ../libncftp/libncftp.a +@Z30@ + $(CC) $(CFLAGS) $(DEFS) $(CPPFLAGS) $(OBJS) -o ../bin/ncftp@EXEEXT@ $(LDFLAGS) -lncftp -lStrn -lsio $(LIBS) + -@$(STRIP) ../bin/ncftp@EXEEXT@ + +clean: + /bin/rm -f $(DPROGS) $(OBJS) + +SHELL=/bin/sh +.SUFFIXES: .c .@OBJEXT@ + +.c.@OBJEXT@: + $(CC) $(CFLAGS) $(DEFS) $(CPPFLAGS) $< -c + +PACKAGE=Makefile.in bookmark.c bookmark.h cmdlist.c \ + cmds.c cmds.h getopt.c getopt.h \ + ls.c ls.h main.c main.h \ + pref.c pref.h progress.c progress.h \ + readln.c readln.h shell.c shell.h \ + spool.c spool.h syshdrs.h trace.c \ + trace.h util.c util.h version.c \ + preffw.c log.c log.h getline.c \ + getline.h + +TMPDIR=/tmp +TARDIR=ncftp + +tarcp: + -@mkdir -p $(TMPDIR)/TAR/$(TARDIR) + -@chmod ga+r $(PACKAGE) + -@chmod 755 $(TMPDIR)/TAR/$(TARDIR) + cp -pr $(PACKAGE) $(TMPDIR)/TAR/$(TARDIR) + +### Dependencies ############################################################# + +version.@OBJEXT@: version.c + $(CC) $(CFLAGS) -DOS=\"@OS@\" $< -c + +bookmark.@OBJEXT@: bookmark.c syshdrs.h bookmark.h util.h ../libncftp/ncftp.h ../libncftp/ncftp_errno.h +cmdlist.@OBJEXT@: cmdlist.c syshdrs.h shell.h bookmark.h cmds.h ../libncftp/ncftp.h ../libncftp/ncftp_errno.h +cmds.@OBJEXT@: cmds.c syshdrs.h shell.h util.h ls.h bookmark.h cmds.h main.h \ + trace.h pref.h spool.h getopt.h ../libncftp/ncftp.h ../libncftp/ncftp_errno.h +getopt.@OBJEXT@: getopt.c getopt.h +ls.@OBJEXT@: ls.c syshdrs.h util.h ls.h trace.h ../libncftp/ncftp.h ../libncftp/ncftp_errno.h +main.@OBJEXT@: main.c syshdrs.h ls.h bookmark.h cmds.h main.h shell.h \ + getopt.h progress.h pref.h readln.h trace.h spool.h util.h ../libncftp/ncftp.h ../libncftp/ncftp_errno.h +pref.@OBJEXT@: pref.c syshdrs.h pref.h util.h ../libncftp/ncftp.h ../libncftp/ncftp_errno.h +preffw.@OBJEXT@: preffw.c syshdrs.h pref.h util.h ../libncftp/ncftp.h ../libncftp/ncftp_errno.h +progress.@OBJEXT@: progress.c syshdrs.h util.h progress.h ../libncftp/ncftp.h ../libncftp/ncftp_errno.h +readln.@OBJEXT@: readln.c syshdrs.h shell.h util.h bookmark.h cmds.h ls.h \ + readln.h getline.h ../libncftp/ncftp.h ../libncftp/ncftp_errno.h +shell.@OBJEXT@: shell.c syshdrs.h shell.h util.h bookmark.h cmds.h readln.h \ + trace.h main.h ../libncftp/ncftp.h ../libncftp/ncftp_errno.h +spool.@OBJEXT@: spool.c syshdrs.h ../libncftp/ncftp.h ../libncftp/ncftp_errno.h +trace.@OBJEXT@: trace.c syshdrs.h trace.h util.h ../libncftp/ncftp.h ../libncftp/ncftp_errno.h +util.@OBJEXT@: util.c syshdrs.h shell.h trace.h util.h ../libncftp/ncftp.h ../libncftp/ncftp_errno.h +log.@OBJEXT@: log.c syshdrs.h log.h util.h ../libncftp/ncftp.h ../libncftp/ncftp_errno.h +getline.@OBJEXT@: getline.c syshdrs.h getline.h diff --git a/reactos/apps/utils/net/ncftp/ncftp/bookmark.c b/reactos/apps/utils/net/ncftp/ncftp/bookmark.c new file mode 100644 index 00000000000..4050f96a90f --- /dev/null +++ b/reactos/apps/utils/net/ncftp/ncftp/bookmark.c @@ -0,0 +1,845 @@ +/* bookmark.c + * + * Copyright (c) 1992-2001 by Mike Gleason. + * All rights reserved. + * + */ + +#include "syshdrs.h" + +#include "bookmark.h" +#include "util.h" + +/* + * The ~/.ncftp/bookmarks file contains a list of sites + * the user wants to remember. + * + * Unlike previous versions of the program, we now open/close + * the file every time we need it; That way we can have + * multiple ncftp processes changing the file. There is still + * a possibility that two different processes could be modifying + * the file at the same time. + */ + +Bookmark gBm; +int gLoadedBm = 0; +int gBookmarkMatchMode = 0; +int gNumBookmarks = 0; +BookmarkPtr gBookmarkTable = NULL; + +extern char gOurDirectoryPath[]; + +/* Converts a pre-loaded Bookmark structure into a RFC 1738 + * Uniform Resource Locator. + */ +void +BookmarkToURL(BookmarkPtr bmp, char *url, size_t urlsize) +{ + char pbuf[32]; + + /* //:@:/ */ + /* Note that if an absolute path is given, + * you need to escape the first entry, i.e. /pub -> %2Fpub + */ + (void) Strncpy(url, "ftp://", urlsize); + if (bmp->user[0] != '\0') { + (void) Strncat(url, bmp->user, urlsize); + if (bmp->pass[0] != '\0') { + (void) Strncat(url, ":", urlsize); + (void) Strncat(url, "PASSWORD", urlsize); + } + (void) Strncat(url, "@", urlsize); + } + (void) Strncat(url, bmp->name, urlsize); + if (bmp->port != 21) { + (void) sprintf(pbuf, ":%u", (unsigned int) bmp->port); + (void) Strncat(url, pbuf, urlsize); + } + if (bmp->dir[0] == '/') { + /* Absolute URL path, must escape first slash. */ + (void) Strncat(url, "/%2F", urlsize); + (void) Strncat(url, bmp->dir + 1, urlsize); + (void) Strncat(url, "/", urlsize); + } else if (bmp->dir[0] != '\0') { + (void) Strncat(url, "/", urlsize); + (void) Strncat(url, bmp->dir, urlsize); + (void) Strncat(url, "/", urlsize); + } +} /* BookmarkToURL */ + + + + +void +SetBookmarkDefaults(BookmarkPtr bmp) +{ + (void) memset(bmp, 0, sizeof(Bookmark)); + + bmp->xferType = 'I'; + bmp->xferMode = 'S'; /* Use FTP protocol default as ours too. */ + bmp->hasSIZE = kCommandAvailabilityUnknown; + bmp->hasMDTM = kCommandAvailabilityUnknown; + bmp->hasUTIME = kCommandAvailabilityUnknown; + bmp->hasPASV = kCommandAvailabilityUnknown; + bmp->isUnix = 1; + bmp->lastCall = (time_t) 0; + bmp->deleted = 0; +} /* SetBookmarkDefaults */ + + + + +/* Used when converting hex strings to integral types. */ +static int +HexCharToNibble(int c) +{ + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return (c - '0'); + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + return (c - 'a' + 10); + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + return (c - 'A' + 10); + + } + return (-1); /* Error. */ +} /* HexCharToNibble */ + + + + + +/* Fills in a Bookmark structure based off of a line from the NcFTP + * "bookmarks" file. + */ +int +ParseHostLine(char *line, BookmarkPtr bmp) +{ + char token[128]; + char pass[128]; + char *s, *d; + char *tokenend; + long L; + int i; + int result; + int n, n1, n2; + + SetBookmarkDefaults(bmp); + s = line; + tokenend = token + sizeof(token) - 1; + result = -1; + for (i=1; ; i++) { + if (*s == '\0') + break; + /* Some tokens may need to have a comma in them. Since this is a + * field delimiter, these fields use \, to represent a comma, and + * \\ for a backslash. This chunk gets the next token, paying + * attention to the escaped stuff. + */ + for (d = token; *s != '\0'; ) { + if ((*s == '\\') && (s[1] != '\0')) { + if (d < tokenend) + *d++ = s[1]; + s += 2; + } else if (*s == ',') { + ++s; + break; + } else if ((*s == '$') && (s[1] != '\0') && (s[2] != '\0')) { + n1 = HexCharToNibble(s[1]); + n2 = HexCharToNibble(s[2]); + if ((n1 >= 0) && (n2 >= 0)) { + n = (n1 << 4) | n2; + if (d < tokenend) + *(unsigned char *)d++ = (unsigned int) n; + } + s += 3; + } else { + if (d < tokenend) + *d++ = *s; + ++s; + } + } + *d = '\0'; + switch(i) { + case 1: (void) STRNCPY(bmp->bookmarkName, token); break; + case 2: (void) STRNCPY(bmp->name, token); break; + case 3: (void) STRNCPY(bmp->user, token); break; + case 4: (void) STRNCPY(bmp->pass, token); break; + case 5: (void) STRNCPY(bmp->acct, token); break; + case 6: (void) STRNCPY(bmp->dir, token); + result = 0; /* Good enough to have these fields. */ + break; + case 7: + if (token[0] != '\0') + bmp->xferType = (int) token[0]; + break; + case 8: + /* Most of the time, we won't have a port. */ + if (token[0] == '\0') + bmp->port = (unsigned int) kDefaultFTPPort; + else + bmp->port = (unsigned int) atoi(token); + break; + case 9: + (void) sscanf(token, "%lx", &L); + bmp->lastCall = (time_t) L; + break; + case 10: bmp->hasSIZE = atoi(token); break; + case 11: bmp->hasMDTM = atoi(token); break; + case 12: bmp->hasPASV = atoi(token); break; + case 13: bmp->isUnix = atoi(token); + result = 3; /* Version 3 had all fields to here. */ + break; + case 14: (void) STRNCPY(bmp->lastIP, token); break; + case 15: (void) STRNCPY(bmp->comment, token); break; + case 16: + case 17: + case 18: + case 19: + break; + case 20: bmp->xferMode = token[0]; + result = 7; /* Version 7 has all fields to here. */ + break; + case 21: bmp->hasUTIME = atoi(token); + break; + case 22: (void) STRNCPY(bmp->ldir, token); + result = 8; /* Version 8 has all fields to here. */ + break; + default: + result = 99; /* Version >8 ? */ + goto done; + } + } +done: + + /* Decode password, if it was base-64 encoded. */ + if (strncmp(bmp->pass, kPasswordMagic, kPasswordMagicLen) == 0) { + FromBase64(pass, bmp->pass + kPasswordMagicLen, strlen(bmp->pass + kPasswordMagicLen), 1); + (void) STRNCPY(bmp->pass, pass); + } + return (result); +} /* ParseHostLine */ + + + + +void +CloseBookmarkFile(FILE *fp) +{ + if (fp != NULL) + (void) fclose(fp); +} /* CloseBookmarkFile */ + + + + + +int +GetNextBookmark(FILE *fp, Bookmark *bmp) +{ + char line[512]; + + while (FGets(line, sizeof(line), fp) != NULL) { + if (ParseHostLine(line, bmp) >= 0) + return (0); + } + return (-1); +} /* GetNextBookmark */ + + + + +/* Opens a NcFTP 2.x or 3.x style bookmarks file, and sets the file pointer + * so that it is ready to read the first data line. + */ +FILE * +OpenBookmarkFile(int *numBookmarks0) +{ + char pathName[256], path2[256]; + char line[256]; + FILE *fp; + int version; + int numBookmarks; + Bookmark junkbm; + + if (gOurDirectoryPath[0] == '\0') + return NULL; /* Don't create in root directory. */ + (void) OurDirectoryPath(pathName, sizeof(pathName), kBookmarkFileName); + fp = fopen(pathName, FOPEN_READ_TEXT); + if (fp == NULL) { + /* See if it exists under the old name. */ + (void) OurDirectoryPath(path2, sizeof(path2), kOldBookmarkFileName); + if (rename(path2, pathName) == 0) { + /* Rename succeeded, now open it. */ + fp = fopen(pathName, FOPEN_READ_TEXT); + if (fp == NULL) + return NULL; + } + return NULL; /* Okay to not have one yet. */ + } + + (void) chmod(pathName, 00600); + if (FGets(line, sizeof(line), fp) == NULL) { + (void) fprintf(stderr, "%s: invalid format.\n", pathName); + (void) fclose(fp); + return NULL; + } + + /* Sample line we're looking for: + * "NcFTP bookmark-file version: 8" + */ + version = -1; + (void) sscanf(line, "%*s %*s %*s %d", &version); + if (version < kBookmarkMinVersion) { + if (version < 0) { + (void) fprintf(stderr, "%s: invalid format, or bad version.\n", pathName); + (void) fclose(fp); + return NULL; + } + (void) STRNCPY(path2, pathName); + (void) sprintf(line, ".v%d", version); + (void) STRNCAT(path2, line); + (void) rename(pathName, path2); + (void) fprintf(stderr, "%s: old version.\n", pathName); + (void) fclose(fp); + return NULL; + } + + /* Sample line we're looking for: + * "Number of entries: 28" or "# # # 1" + */ + numBookmarks = -1; + + /* At the moment, we can't trust the number stored in the + * file. It's there for future use. + */ + if (FGets(line, sizeof(line), fp) == NULL) { + (void) fprintf(stderr, "%s: invalid format.\n", pathName); + (void) fclose(fp); + return NULL; + } + + if (numBookmarks0 == (int *) 0) { + /* If the caller doesn't care how many bookmarks are *really* + * in the file, then we can return now. + */ + return(fp); + } + + /* Otherwise, we have to read through the whole file because + * unfortunately the header line can't be trusted. + */ + for (numBookmarks = 0; ; numBookmarks++) { + if (GetNextBookmark(fp, &junkbm) < 0) + break; + } + + /* Now we have to re-open and re-position the file. + * We don't use rewind() because it doesn't always work. + * This introduces a race condition, but the bookmark + * functionality wasn't designed to be air-tight. + */ + CloseBookmarkFile(fp); + fp = fopen(pathName, FOPEN_READ_TEXT); + if (fp == NULL) + return (NULL); + if (FGets(line, sizeof(line), fp) == NULL) { + (void) fprintf(stderr, "%s: invalid format.\n", pathName); + (void) fclose(fp); + return NULL; + } + + if (FGets(line, sizeof(line), fp) == NULL) { + (void) fprintf(stderr, "%s: invalid format.\n", pathName); + (void) fclose(fp); + return NULL; + } + + /* NOW we're done. */ + *numBookmarks0 = numBookmarks; + return (fp); +} /* OpenBookmarkFile */ + + + + +/* Looks for a saved bookmark by the abbreviation given. */ +int +GetBookmark(const char *const bmabbr, Bookmark *bmp) +{ + FILE *fp; + char line[512]; + Bookmark byHostName; + Bookmark byHostAbbr; + Bookmark byBmAbbr; + size_t byBmNameFlag = 0; + size_t byBmAbbrFlag = 0; + size_t byHostNameFlag = 0; + size_t byHostAbbrFlag = 0; + int result = -1; + int exactMatch = 0; + size_t bmabbrLen; + char *cp; + + fp = OpenBookmarkFile(NULL); + if (fp == NULL) + return (-1); + + bmabbrLen = strlen(bmabbr); + while (FGets(line, sizeof(line), fp) != NULL) { + if (ParseHostLine(line, bmp) < 0) + continue; + if (ISTREQ(bmp->bookmarkName, bmabbr)) { + /* Exact match, done. */ + byBmNameFlag = bmabbrLen; + exactMatch = 1; + break; + } else if (ISTRNEQ(bmp->bookmarkName, bmabbr, bmabbrLen)) { + /* Remember this one, it matched an abbreviated + * bookmark name. + */ + byBmAbbr = *bmp; + byBmAbbrFlag = bmabbrLen; + } else if (ISTREQ(bmp->name, bmabbr)) { + /* Remember this one, it matched a full + * host name. + */ + byHostName = *bmp; + byHostNameFlag = bmabbrLen; + } else if ((cp = strchr(bmp->name, '.')) != NULL) { + /* See if it matched part of the hostname. */ + if (ISTRNEQ(bmp->name, "ftp", 3)) { + cp = cp + 1; + } else if (ISTRNEQ(bmp->name, "www", 3)) { + cp = cp + 1; + } else { + cp = bmp->name; + } + if (ISTRNEQ(cp, bmabbr, bmabbrLen)) { + /* Remember this one, it matched a full + * host name. + */ + byHostAbbr = *bmp; + byHostAbbrFlag = bmabbrLen; + } + } + } + + if (gBookmarkMatchMode == 0) { + /* Only use a bookmark when the exact + * bookmark name was used. + */ + if (exactMatch != 0) { + result = 0; + } + } else { + /* Pick the best match, if any. */ + if (byBmNameFlag != 0) { + /* *bmp is already set. */ + result = 0; + } else if (byBmAbbrFlag != 0) { + result = 0; + *bmp = byBmAbbr; + } else if (byHostNameFlag != 0) { + result = 0; + *bmp = byHostName; + } else if (byHostAbbrFlag != 0) { + result = 0; + *bmp = byHostAbbr; + } + } + + if (result != 0) + memset(bmp, 0, sizeof(Bookmark)); + + CloseBookmarkFile(fp); + return (result); +} /* GetBookmark */ + + + + +static int +BookmarkSortProc(const void *a, const void *b) +{ + return (ISTRCMP((*(Bookmark *)a).bookmarkName, (*(Bookmark *)b).bookmarkName)); +} /* BookmarkSortProc */ + + + +static int +BookmarkSearchProc(const void *key, const void *b) +{ + return (ISTRCMP((char *) key, (*(Bookmark *)b).bookmarkName)); +} /* BookmarkSearchProc */ + + + +BookmarkPtr +SearchBookmarkTable(const char *key) +{ + return ((BookmarkPtr) bsearch(key, gBookmarkTable, (size_t) gNumBookmarks, sizeof(Bookmark), BookmarkSearchProc)); +} /* SearchBookmarkTable */ + + + + +void +SortBookmarks(void) +{ + if ((gBookmarkTable == NULL) || (gNumBookmarks < 2)) + return; + + /* Sorting involves swapping entire Bookmark structures. + * Normally the proper thing to do is to use an array + * of pointers to Bookmarks and sort them, but even + * these days a large bookmark list can be sorted in + * the blink of an eye. + */ + qsort(gBookmarkTable, (size_t) gNumBookmarks, sizeof(Bookmark), BookmarkSortProc); +} /* SortBookmarks */ + + + +int +LoadBookmarkTable(void) +{ + int i, nb; + FILE *infp; + + infp = OpenBookmarkFile(&nb); + if (infp == NULL) { + nb = 0; + } + if ((nb != gNumBookmarks) && (gBookmarkTable != NULL)) { + /* Re-loading the table from disk. */ + gBookmarkTable = (Bookmark *) realloc(gBookmarkTable, (size_t) (nb + 1) * sizeof(Bookmark)); + memset(gBookmarkTable, 0, (nb + 1) * sizeof(Bookmark)); + } else { + gBookmarkTable = calloc((size_t) (nb + 1), (size_t) sizeof(Bookmark)); + } + + if (gBookmarkTable == NULL) { + CloseBookmarkFile(infp); + return (-1); + } + + for (i=0; ibookmarkName) < 0) return (-1) ;/*1*/ + if (fprintf(outfp, ",%s", BmEscapeTok(tok, sizeof(tok), bmp->name)) < 0) return (-1) ;/*2*/ + if (fprintf(outfp, ",%s", BmEscapeTok(tok, sizeof(tok), bmp->user)) < 0) return (-1) ;/*3*/ + if ((bmp->pass[0] != '\0') && (savePassword == 1)) { + (void) memcpy(pass, kPasswordMagic, kPasswordMagicLen); + ToBase64(pass + kPasswordMagicLen, bmp->pass, strlen(bmp->pass), 1); + if (fprintf(outfp, ",%s", pass) < 0) return (-1) ;/*4*/ + } else { + if (fprintf(outfp, ",%s", "") < 0) return (-1) ;/*4*/ + } + if (fprintf(outfp, ",%s", BmEscapeTok(tok, sizeof(tok), bmp->acct)) < 0) return (-1) ;/*5*/ + if (fprintf(outfp, ",%s", BmEscapeTok(tok, sizeof(tok), bmp->dir)) < 0) return (-1) ;/*6*/ + if (fprintf(outfp, ",%c", bmp->xferType) < 0) return (-1) ;/*7*/ + if (fprintf(outfp, ",%u", (unsigned int) bmp->port) < 0) return (-1) ;/*8*/ + if (fprintf(outfp, ",%lu", (unsigned long) bmp->lastCall) < 0) return (-1) ;/*9*/ + if (fprintf(outfp, ",%d", bmp->hasSIZE) < 0) return (-1) ;/*10*/ + if (fprintf(outfp, ",%d", bmp->hasMDTM) < 0) return (-1) ;/*11*/ + if (fprintf(outfp, ",%d", bmp->hasPASV) < 0) return (-1) ;/*12*/ + if (fprintf(outfp, ",%d", bmp->isUnix) < 0) return (-1) ;/*13*/ + if (fprintf(outfp, ",%s", bmp->lastIP) < 0) return (-1) ;/*14*/ + if (fprintf(outfp, ",%s", BmEscapeTok(tok, sizeof(tok), bmp->comment)) < 0) return (-1) ;/*15*/ + if (fprintf(outfp, ",%s", "") < 0) return (-1) ;/*16*/ + if (fprintf(outfp, ",%s", "") < 0) return (-1) ;/*17*/ + if (fprintf(outfp, ",%s", "") < 0) return (-1) ;/*18*/ + if (fprintf(outfp, ",%s", "") < 0) return (-1) ;/*19*/ + if (fprintf(outfp, ",%c", bmp->xferMode) < 0) return (-1) ;/*20*/ + if (fprintf(outfp, ",%d", bmp->hasUTIME) < 0) return (-1) ;/*21*/ + if (fprintf(outfp, ",%s", BmEscapeTok(tok, sizeof(tok), bmp->ldir)) < 0) return (-1) ;/*22*/ + if (fprintf(outfp, "\n") < 0) return (-1) ; + if (fflush(outfp) < 0) return (-1); + return (0); +} /* WriteBmLine */ + + + +static int +SwapBookmarkFiles(void) +{ + char pidStr[32]; + char pathName[256], path2[256]; + + (void) OurDirectoryPath(path2, sizeof(path2), kBookmarkFileName); + (void) OurDirectoryPath(pathName, sizeof(pathName), kTmpBookmarkFileName); + (void) sprintf(pidStr, "-%u.txt", (unsigned int) getpid()); + (void) STRNCAT(pathName, pidStr); + + (void) remove(path2); + if (rename(pathName, path2) < 0) { + return (-1); + } + return (0); +} /* SwapBookmarkFiles */ + + + + + + +/* Saves a Bookmark structure into the bookmarks file. */ +FILE * +OpenTmpBookmarkFile(int nb) +{ + FILE *outfp; + char pidStr[32]; + char pathName[256], path2[256]; + + if (gOurDirectoryPath[0] == '\0') + return (NULL); /* Don't create in root directory. */ + + (void) OurDirectoryPath(path2, sizeof(path2), kBookmarkFileName); + (void) OurDirectoryPath(pathName, sizeof(pathName), kTmpBookmarkFileName); + (void) sprintf(pidStr, "-%u.txt", (unsigned int) getpid()); + (void) STRNCAT(pathName, pidStr); + + outfp = fopen(pathName, FOPEN_WRITE_TEXT); + if (outfp == NULL) { + (void) fprintf(stderr, "Could not save bookmark.\n"); + perror(pathName); + return (NULL); + } + (void) chmod(pathName, 00600); + if (nb > 0) { + if (fprintf(outfp, "NcFTP bookmark-file version: %d\nNumber of bookmarks: %d\n", kBookmarkVersion, nb) < 0) { + (void) fprintf(stderr, "Could not save bookmark.\n"); + perror(pathName); + (void) fclose(outfp); + return (NULL); + } + } else { + if (fprintf(outfp, "NcFTP bookmark-file version: %d\nNumber of bookmarks: ??\n", kBookmarkVersion) < 0) { + (void) fprintf(stderr, "Could not save bookmark.\n"); + perror(pathName); + (void) fclose(outfp); + return (NULL); + } + } + + return (outfp); +} /* OpenTmpBookmarkFile */ + + + + +int +SaveBookmarkTable(void) +{ + int i; + FILE *outfp; + int nb; + + if ((gNumBookmarks < 1) || (gBookmarkTable == NULL)) + return (0); /* Nothing to save. */ + + /* Get a count of live bookmarks. */ + for (i=0, nb=0; ibookmarkName); + (void) STRNCAT(bmAbbr, ","); + len = strlen(bmAbbr); + + /* This may fail the first time we ever save a bookmark. */ + infp = OpenBookmarkFile(NULL); + if (infp != NULL) { + while (FGets(line, sizeof(line), infp) != NULL) { + if (strncmp(line, bmAbbr, len) == 0) { + /* Replace previous entry. */ + if (WriteBmLine(bmp, outfp, savePassword) < 0) { + (void) fprintf(stderr, "Could not save bookmark.\n"); + perror("reason"); + (void) fclose(outfp); + } + replaced = 1; + } else { + if (fprintf(outfp, "%s\n", line) < 0) { + (void) fprintf(stderr, "Could not save bookmark.\n"); + perror("reason"); + (void) fclose(outfp); + return (-1); + } + } + } + CloseBookmarkFile(infp); + } + + if (replaced == 0) { + /* Add it as a new bookmark. */ + if (WriteBmLine(bmp, outfp, savePassword) < 0) { + (void) fprintf(stderr, "Could not save bookmark.\n"); + perror("reason"); + (void) fclose(outfp); + return (-1); + } + } + + if (fclose(outfp) < 0) { + (void) fprintf(stderr, "Could not save bookmark.\n"); + perror("reason"); + return (-1); + } + + if (SwapBookmarkFiles() < 0) { + (void) fprintf(stderr, "Could not rename bookmark file.\n"); + perror("reason"); + return (-1); + } + return (0); +} /* PutBookmark */ + + + + +/* Tries to generate a bookmark abbreviation based off of the hostname. */ +void +DefaultBookmarkName(char *dst, size_t siz, char *src) +{ + char str[128]; + const char *token; + const char *cp; + + (void) STRNCPY(str, src); + + /* Pick the first "significant" part of the hostname. Usually + * this is the first word in the name, but if it's something like + * ftp.unl.edu, we would want to choose "unl" and not "ftp." + */ + token = str; + if ((token = strtok(str, ".")) == NULL) + token = str; + else if ((ISTRNEQ(token, "ftp", 3)) || (ISTRNEQ(token, "www", 3))) { + if ((token = strtok(NULL, ".")) == NULL) + token = ""; + } + for (cp = token; ; cp++) { + if (*cp == '\0') { + /* Token was all digits, like an IP address perhaps. */ + token = ""; + } + if (!isdigit((int) *cp)) + break; + } + (void) Strncpy(dst, token, siz); +} /* DefaultBookmarkName */ diff --git a/reactos/apps/utils/net/ncftp/ncftp/bookmark.h b/reactos/apps/utils/net/ncftp/ncftp/bookmark.h new file mode 100644 index 00000000000..4a4ae0e6949 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/ncftp/bookmark.h @@ -0,0 +1,59 @@ +/* bookmark.h + * + * Copyright (c) 1992-2001 by Mike Gleason. + * All rights reserved. + * + */ + +typedef struct Bookmark *BookmarkPtr; +typedef struct Bookmark { + char bookmarkName[16]; + char name[64]; + char user[64]; + char pass[64]; + char acct[64]; + char dir[160]; + char ldir[160]; + int xferType; + unsigned int port; + time_t lastCall; + int hasSIZE; + int hasMDTM; + int hasPASV; + int isUnix; + char lastIP[32]; + char comment[128]; + int xferMode; + int hasUTIME; + + int deleted; +} Bookmark; + +#define kBookmarkVersion 8 +#define kBookmarkMinVersion 3 +#if defined(WIN32) || defined(_WINDOWS) +# define kBookmarkFileName "bookmarks.txt" +#else +# define kBookmarkFileName "bookmarks" +#endif +#define kTmpBookmarkFileName "bookmarks-tmp" +#define kOldBookmarkFileName "hosts" +#define kBookmarkBupFileName "bookmarks.old" + +#define BMTINDEX(p) ((int) ((char *) p - (char *) gBookmarkTable) / (int) sizeof(Bookmark)) + +/* bookmark.c */ +void BookmarkToURL(BookmarkPtr, char *, size_t); +void SetBookmarkDefaults(BookmarkPtr); +int ParseHostLine(char *, BookmarkPtr); +void CloseBookmarkFile(FILE *); +FILE *OpenBookmarkFile(int *); +FILE *OpenTmpBookmarkFile(int); +int SaveBookmarkTable(void); +int GetNextBookmark(FILE *, Bookmark *); +int GetBookmark(const char *const, Bookmark *); +int PutBookmark(Bookmark *, int); +int LoadBookmarkTable(void); +BookmarkPtr SearchBookmarkTable(const char *); +void SortBookmarks(void); +void DefaultBookmarkName(char *, size_t, char *); diff --git a/reactos/apps/utils/net/ncftp/ncftp/cmdlist.c b/reactos/apps/utils/net/ncftp/ncftp/cmdlist.c new file mode 100644 index 00000000000..baa811cd9c7 --- /dev/null +++ b/reactos/apps/utils/net/ncftp/ncftp/cmdlist.c @@ -0,0 +1,527 @@ +/* cmdlist.c + * + * Copyright (c) 1992-2001 by Mike Gleason. + * All rights reserved. + * + */ + +#include "syshdrs.h" +#include "shell.h" +#include "bookmark.h" +#include "cmds.h" + +/* These will be sorted lexiographically when the program is run, but + * they should already be listed that way. + */ +Command gCommands[] = { +#if defined(WIN32) || defined(_WINDOWS) +#else + { "!", + ShellCmd, + "[arguments]", + "Runs a subshell", + kCmdHidden, + kNoMin, kNoMax, + }, +#endif + { "?", + HelpCmd, + "[optional commands]", + "shows commands, or detailed help on specified commands", + kCmdHidden, + kNoMin, kNoMax, + }, + { "ascii", + TypeCmd, + "", + "sets the file transfer type to ASCII text", + kCmdMustBeConnected, + 0, 0, + }, + { "bgget", + SpoolGetCmd, +"[-flags] file1 [file2...]\n\ +Flags:\n\ + -R : Recursive. Useful for fetching whole directories.\n\ + -z : Get the remote file X, and name it to Y.\n\ + -@