summaryrefslogtreecommitdiffstats
path: root/lib/libftp/utils
diff options
context:
space:
mode:
authorjkh <jkh@FreeBSD.org>1995-04-25 15:05:11 +0000
committerjkh <jkh@FreeBSD.org>1995-04-25 15:05:11 +0000
commit02ace706173509b7d8549494277ff682b7cefb8a (patch)
tree437a6d909f192743fe7d26def0fdfae947754209 /lib/libftp/utils
downloadFreeBSD-src-02ace706173509b7d8549494277ff682b7cefb8a.zip
FreeBSD-src-02ace706173509b7d8549494277ff682b7cefb8a.tar.gz
A programmatic interface to ftp. I need this for several other
components of the system. The license is poorly worded, though I have an (email only) release from the author for unlimited FreeBSD use. I will try to get something more concrete, though the author's remote location makes this difficult. Submitted by: Oleg Orel <orel@oea.ihep.su>
Diffstat (limited to 'lib/libftp/utils')
-rw-r--r--lib/libftp/utils/Makefile34
-rw-r--r--lib/libftp/utils/cdefs.h122
-rw-r--r--lib/libftp/utils/ftptry.c633
-rw-r--r--lib/libftp/utils/glob.c850
-rw-r--r--lib/libftp/utils/glob.h89
-rw-r--r--lib/libftp/utils/mirror.c92
-rw-r--r--lib/libftp/utils/readline.c961
-rw-r--r--lib/libftp/utils/uftp.c824
-rw-r--r--lib/libftp/utils/uftp.h83
-rw-r--r--lib/libftp/utils/uftp.man452
-rw-r--r--lib/libftp/utils/uftpcmd.c1202
11 files changed, 5342 insertions, 0 deletions
diff --git a/lib/libftp/utils/Makefile b/lib/libftp/utils/Makefile
new file mode 100644
index 0000000..783451b
--- /dev/null
+++ b/lib/libftp/utils/Makefile
@@ -0,0 +1,34 @@
+#
+# A rather bogus Makefile, but one intended to be used by hand anyway..
+#
+
+CFLAGS = -I${.CURDIR} -I${.CURDIR}/.. -DREADLINE
+LDADD+= -L${.CURDIR}
+DPADD+= libetc.a
+
+.if exists(${.CURDIR}/../obj)
+LDADD+= -L${.CURDIR}/../obj
+DPADD+= ${.CURDIR}/../obj/libftp.a
+.else
+LDADD+= -L${.CURDIR}/..
+DPADD+= ${.CURDIR}/../libftp.a
+.endif
+
+all: ftptry mirror uftp
+
+ftptry: ftptry.o
+ $(CC) $(CFLAGS) -o ftptry ftptry.o -lftp
+
+uftp: uftp.o uftpcmd.o libetc.a
+ $(CC) $(CFLAGS) -o uftp uftp.o uftpcmd.o -lftp -letc
+
+mirror: mirror.o
+ $(CC) $(CFLAGS) -o mirror mirror.o -lftp
+
+clean:
+ rm -f ftptry mirror uftp *~ *.o *.a
+
+LIBOBJS= readline.o glob.o
+libetc.a: $(LIBOBJS)
+ ar qc libetc.a $(LIBOBJS)
+ ranlib libetc.a
diff --git a/lib/libftp/utils/cdefs.h b/lib/libftp/utils/cdefs.h
new file mode 100644
index 0000000..c104b9e
--- /dev/null
+++ b/lib/libftp/utils/cdefs.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Berkeley Software Design, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)cdefs.h 8.7 (Berkeley) 1/21/94
+ */
+
+#ifndef _CDEFS_H_
+#define _CDEFS_H_
+
+#if defined(__cplusplus)
+#define __BEGIN_DECLS extern "C" {
+#define __END_DECLS };
+#else
+#define __BEGIN_DECLS
+#define __END_DECLS
+#endif
+
+/*
+ * The __CONCAT macro is used to concatenate parts of symbol names, e.g.
+ * with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces oldfoo.
+ * The __CONCAT macro is a bit tricky -- make sure you don't put spaces
+ * in between its arguments. __CONCAT can also concatenate double-quoted
+ * strings produced by the __STRING macro, but this only works with ANSI C.
+ */
+#if defined(__STDC__) || defined(__cplusplus)
+#define __P(protos) protos /* full-blown ANSI C */
+#define __CONCAT(x,y) x ## y
+#define __STRING(x) #x
+
+#define __const const /* define reserved names to standard */
+#define __signed signed
+#define __volatile volatile
+#if defined(__cplusplus)
+#define __inline inline /* convert to C++ keyword */
+#else
+#ifndef __GNUC__
+#define __inline /* delete GCC keyword */
+#endif /* !__GNUC__ */
+#endif /* !__cplusplus */
+
+#else /* !(__STDC__ || __cplusplus) */
+#define __P(protos) () /* traditional C preprocessor */
+#define __CONCAT(x,y) x/**/y
+#define __STRING(x) "x"
+
+#ifndef __GNUC__
+#define __const /* delete pseudo-ANSI C keywords */
+#define __inline
+#define __signed
+#define __volatile
+/*
+ * In non-ANSI C environments, new programs will want ANSI-only C keywords
+ * deleted from the program and old programs will want them left alone.
+ * When using a compiler other than gcc, programs using the ANSI C keywords
+ * const, inline etc. as normal identifiers should define -DNO_ANSI_KEYWORDS.
+ * When using "gcc -traditional", we assume that this is the intent; if
+ * __GNUC__ is defined but __STDC__ is not, we leave the new keywords alone.
+ */
+#ifndef NO_ANSI_KEYWORDS
+#define const /* delete ANSI C keywords */
+#define inline
+#define signed
+#define volatile
+#endif
+#endif /* !__GNUC__ */
+#endif /* !(__STDC__ || __cplusplus) */
+
+/*
+ * GCC1 and some versions of GCC2 declare dead (non-returning) and
+ * pure (no side effects) functions using "volatile" and "const";
+ * unfortunately, these then cause warnings under "-ansi -pedantic".
+ * GCC2 uses a new, peculiar __attribute__((attrs)) style. All of
+ * these work for GNU C++ (modulo a slight glitch in the C++ grammar
+ * in the distribution version of 2.5.5).
+ */
+#if !defined(__GNUC__) || __GNUC__ < 2 || __GNUC_MINOR__ < 5
+#define __attribute__(x) /* delete __attribute__ if non-gcc or gcc1 */
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+#define __dead __volatile
+#define __pure __const
+#endif
+#endif
+
+/* Delete pseudo-keywords wherever they are not available or needed. */
+#ifndef __dead
+#define __dead
+#define __pure
+#endif
+
+#endif /* !_CDEFS_H_ */
diff --git a/lib/libftp/utils/ftptry.c b/lib/libftp/utils/ftptry.c
new file mode 100644
index 0000000..623d0da
--- /dev/null
+++ b/lib/libftp/utils/ftptry.c
@@ -0,0 +1,633 @@
+/*
+Library for ftpd clients.(libftp)
+ Copyright by Oleg Orel
+ All rights reserved.
+
+This library is desined for free, non-commercial software creation.
+It is changeable and can be improved. The author would greatly appreciate
+any advises, new components and patches of the existing programs.
+Commercial usage is also possible with participation of it's author.
+
+
+
+*/
+
+char intro[]="\
+ Ftptry - try transfer via FTP.\n\
+ Copyright by Oleg Orel is Reserved.\n\
+\n\
+This program is writen using \"libftp\".The main orientation for this\n\
+program is FTPing via bad-working network. Many network links are\n\
+down-up switched and networks are broaken, so the problem of\n\
+transfering large files exists. The main method, used by this\n\
+software is repetition until successfull transfer. There are some\n\
+keys for setting repetition and timeout intervals, modes of transfer\n\
+(binary and ascii), types of transfer (get,put,directory). All options\n\
+will be described in usage, if the program is started without them.\n\
+\n\
+ The libftp you may transfer from host lpuds.oea.ihep.su via ftp-anonymous.\n\
+ All question are sent to author via e-mail (orel@oea.ihep.su)\n\
+ ";
+
+#include <FtpLibrary.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <string.h>
+
+#ifdef __GNUC__
+#define INLINE inline
+#else
+#define inline
+#endif
+
+#define FTPTRY "FTPTRY" /* The name of enviroment
+ variable with default options*/
+#define log(x) FtpLog("ftptry",x)
+#define DEBUG(x) (debug?log(x):0)
+#define USERNAME (getenv("USER")==NULL?getenv("LOGNAME"):getenv("USER"))
+#define DEFAULT_TIMEOUT 600
+
+
+enum __type__ {ascii=1,binary};
+enum __mode__ {get=1,put,dir,multiget};
+enum __logmode__ {lm_tty,lm_file,lm_mail};
+enum __rcode__ {OK_, BREAK_, CANCEL_};
+
+char *gethost();
+char *date();
+int my_abort();
+int my_IO();
+int my_debug();
+void done(),leave(),sighup();
+
+char
+ *machine ="localhost",
+ *user="anonymous",
+ *password,
+ *localfile=NULL,
+ *progname="ftptry";
+
+jmp_buf stack,trap;
+int counter=0;
+String tmp;
+FTP *ftp;
+int type=ascii;
+int sleeptime=600;
+int debug=false;
+int mode=get;
+int logmode=lm_tty;
+char *logfile=NULL;
+FILE *LIST=NULL;
+extern int errno;
+extern char *optarg;
+extern int optind, opterr;
+String PASSWORD;
+
+
+/* Setup enviroment */
+
+main(int argc,char **argv)
+{
+ FILE *out,*in;
+ int i;
+
+ if (setjmp(trap)!=0)
+ exit(1);
+
+ signal(SIGHUP,sighup);
+ signal(SIGTRAP,done);
+ signal(SIGINT,done);
+ signal(SIGQUIT,done);
+
+ sprintf(password=PASSWORD,"%s@%s",
+ USERNAME,
+ gethost());
+
+ progname=argv[0];
+
+ FtpDebug(&FtpInit);
+ FtpSetErrorHandler(&FtpInit,my_abort);
+ FtpSetIOHandler(&FtpInit,my_IO);
+ FtpSetFlag(&FtpInit,FTP_REST);
+ FtpSetTimeout(&FtpInit,DEFAULT_TIMEOUT);
+
+ setoptions();
+ optind=1;
+ options(argc,argv);
+ if ( argc<2 ) usage();
+
+ switch(logmode)
+ {
+
+ case lm_file:
+
+ if (fork()) quit("Deattaching.....");
+ close(0);close(1);close(2);
+
+ if (logfile==NULL)
+ {
+ sprintf(tmp,"/tmp/ftptry-%s.XXXXXX",USERNAME);
+ mktemp(tmp);
+ }
+ else
+ strcpy(tmp,logfile);
+
+ open(tmp,O_TRUNC|O_CREAT|O_WRONLY,0600);
+ dup(0);
+ dup(0);
+ break;
+
+ case lm_mail:
+
+
+
+ if (fork()) quit("Deattaching.....");
+
+ close(0);close(1);close(2);
+ if (popen("/usr/lib/sendmail -t","w")==NULL)
+ perror("sendmail"),
+ quit("");
+
+ dup(0);
+ dup(0);
+
+ printf("From: %s@%s\n",USERNAME,gethost());
+ printf("To: %s@%s\n",USERNAME,gethost());
+ printf("Subject: ftptry session log\n\n");
+
+ fflush(stdout);
+
+ break;
+ }
+
+
+ signal(SIGHUP,sighup);
+ if (isatty(fileno(stdout))) FtpSetHashHandler(&FtpInit,FtpHash);
+ loop(argc,argv,optind);
+ exit(0);
+}
+
+
+
+INLINE noargs(int argc, char **argv, int optind)
+{
+ int i;
+
+ for (i=optind;i<argc;i++)
+ if (argv[i]!=NULL) return 0;
+ return 1;
+}
+
+
+
+/* Main loop */
+
+loop(int argc, char **argv, int optind /* First args as filename */ )
+{
+ int i,rcode;
+ String tmp;
+ String machine;
+ String filename;
+ String localfilename;
+ char *p1;
+
+ for(i=optind;;(i==argc-1)?i=optind,
+ sprintf(tmp,"Sleeping %d secs",sleeptime),log(tmp),sleep(sleeptime):
+ i++)
+ {
+ if (noargs(argc,argv,optind))
+ quit("Nothing doing");
+
+ if (strchr(argv[i],':')==NULL)
+ {
+ if (find_archie(argv[i],machine,filename,localfilename)==0)
+ argv[i]=NULL;
+ }
+ else
+ {
+ sscanf(argv[i],"%[^:]:%s",machine,filename);
+ if ((p1=strrchr(filename,'/'))!=NULL)
+ strcpy(localfilename,p1+1);
+ else
+ strcpy(localfilename,filename);
+ }
+ if (localfile == NULL ) localfile=localfilename;
+ if ((rcode=transfer(machine, filename, localfile))==OK_)
+ DEBUG("Transfer complete"),
+ exit(0);
+ if (rcode==CANCEL_ && strchr(argv[i],':')!=NULL)
+ argv[i]=NULL;
+ }
+}
+
+transfer(char *machine, char *file, char *localfile)
+{
+ int r;
+ String tmp;
+
+ if ((r=setjmp(stack))!=0)
+ return r;
+
+ sprintf(tmp,"Start transfer, machine is %s, remote file is %s, local file is %s",
+ machine, file, localfile);
+ DEBUG(tmp);
+
+ FtpLogin(&ftp,machine,user,password,NULL);
+
+ if (type==binary)
+ FtpBinary(ftp);
+
+ switch (mode)
+ {
+
+ case get:
+
+ FtpRetr(ftp,"RETR %s",file,localfile);
+ break;
+
+ case put:
+
+ FtpStor(ftp,"STOR %s",localfile,file);
+ break;
+
+ case dir:
+
+ FtpRetr(ftp,"LIST %s",file,localfile);
+ break;
+
+ case multiget:
+ domultiget(file);
+ break;
+
+ }
+
+ FtpBye(ftp);
+
+ DEBUG("Transfer complete");
+ return OK_;
+}
+
+
+void leave(int code)
+{
+ FtpQuickBye(ftp);
+ DEBUG("Leaving transfering");
+ longjmp(stack,code);
+}
+
+void sighup()
+{
+ leave(BREAK_);
+}
+
+
+quit(char *s)
+{
+ log(s);
+ longjmp(trap,1);
+}
+
+
+my_IO(FTP *ftp, int n, char *s )
+{
+
+ DEBUG(s);
+ leave(BREAK_);
+}
+
+my_abort(FTP *ftp, int n, char *s )
+{
+
+ log(s);
+ /* No access or not found, exclude network or host unreachable */;
+ if (abs(n) == 550 && FtpBadReply550(s))
+ leave(CANCEL_);
+ leave(BREAK_);
+}
+
+
+domultiget(char *file)
+{
+ String list,localname,tmp_name;
+ char *p1;
+
+ sprintf(list,"/tmp/ftptry-%s-multiget.XXXXXX",USERNAME);
+ mktemp(list);
+
+ FtpRetr(ftp,"NLST %s",file,list);
+
+ if ((LIST=fopen(list,"r"))==NULL) quit((char *)sys_errlist[errno]);
+
+ while ( fgets (tmp, sizeof tmp, LIST) != NULL )
+ {
+ tmp[strlen(tmp)-1]=0;
+ if ((p1=strrchr(tmp,'/'))!=NULL)
+ strcpy(localname,p1+1);
+ else
+ strcpy(localname,tmp);
+
+ DEBUG(localname);
+ FtpGet(ftp,tmp,localname);
+ }
+
+ fclose(LIST);
+ LIST=NULL;
+ return;
+}
+
+usage()
+{
+ fprintf(stderr,"\
+Usage: %s [optins] [host:file]\n\
+ (default host \"localhost\",\n\
+ default file \"README\" or \".\" in directory mode)\n\
+\n\
+Valid options:\n\
+\n\
+ -u user default anonymous\n\
+ -p password default %s\n\
+ -P inquire password from your terminal\n\
+ -l local_file use only if remote and local file differ\n\
+ -c direct output to stdout(like cat)\n\
+ -r reverse mode, i.e. send file to remote host\n\
+ -d directory mode, remote file is patern or \"ls\" options\n\
+ default output is stdout.\n\
+ -G multiget mode, file is patern for \"ls\" command\n\
+ again at next try.\n\
+ -b binary transfer mode\n\
+ -s seconds Retry interval, default 10 minutes\n\
+ -t seconds Timeout, default 10 minutes\n\
+ -D Turn on debugging mode\n\
+ -B Run in background and direct output to\n\
+ /tmp/ftptry-%s.XXXXXX\n\
+ -o file Run in background and direct output\n\
+ to file\n\
+ -m Send output to orel via e-mail\n\
+ -I Print short introduction\n\
+\n\
+Example:\n\
+ %s -Dbs 300 garbo.uwasa.fi:ls-lR.Z\n\
+ Retrive file ls-lR.Z from garbo.uwasa.fi in binary mode\n\
+ trying to reestablish connection every 5 minutes\n\
+ on failure. Print debugging information.\n\
+\n\
+ You can set default options to %s enviroment variable\n\
+",progname,password,USERNAME,progname,FTPTRY);
+ exit(-1);
+}
+
+
+char *gethost()
+{
+ static String tmp;
+ String tmp2;
+
+ gethostname(tmp2,sizeof tmp2);
+
+ strcpy(tmp,FtpGetHost(tmp2)->h_name);
+ return tmp;
+}
+
+
+void done(sig)
+{
+ String x;
+
+ signal(sig,done);
+ sprintf(x,"interputed by signal %d",sig);
+ log(x);
+ longjmp(trap,1);
+}
+
+
+options(int argc,char **argv)
+{
+ char c;
+
+ while((c=getopt(argc,argv,"GOIBDru:p:Pdbs:o:l:t:cm"))!=EOF)
+ {
+ switch(c)
+ {
+
+ case 'G':
+ mode=multiget;
+ break;
+
+ case 'c':
+
+ if (localfile==NULL) localfile="*STDOUT*";
+ break;
+
+ case 'I':
+ fprintf(stderr,intro);
+ exit(0);
+
+ case 'r':
+
+ mode=put;
+ break;
+
+ case 'd':
+
+ mode=dir;
+ if (localfile==NULL) localfile="*STDOUT*";
+ break;
+
+ case 't':
+
+ FtpSetTimeout(&FtpInit,atoi(optarg));
+ break;
+
+ case 'l':
+
+ localfile=optarg;
+ break;
+
+ case 'D':
+
+ debug=true;
+ break;
+
+ case 'u':
+
+ user=optarg;
+ break;
+
+ case 'p':
+
+ password=optarg;
+ break;
+
+ case 'P':
+
+ password=(char *)getpass("Password:");
+ break;
+
+ case 'b':
+
+ type=binary;
+ break;
+
+ case 's':
+
+ sleeptime=atoi(optarg);
+ break;
+
+ case 'o':
+
+ logmode=lm_file;
+ logfile=optarg;
+ break;
+
+ case 'm':
+
+ logmode=lm_mail;
+ break;
+
+ case 'B':
+
+ logmode=lm_file;
+ logfile=NULL;
+ break;
+
+ default:
+
+ usage();
+
+ }
+ }
+}
+
+
+setoptions()
+{
+ String x;
+ char *p,*sp;
+ int argc;
+ char *argv[100];
+
+
+
+
+ if ((p=(char *)getenv(FTPTRY))!=NULL && *p!=0)
+ strcpy(x,p);
+ else
+ return;
+
+
+
+ for (argv[0]="",p=x,sp=x,argc=1; *p!=0 ; p++)
+ {
+ if (*p==' ')
+ {
+ *p=0;
+ argv[argc++] = sp;
+ sp = p+1;
+ }
+ }
+
+ argv[argc++]=sp;
+
+ options(argc,argv);
+}
+
+
+INLINE unsigned long maxsize(String *result, int hops)
+{
+ unsigned long maxsiz=0,cursiz=0;
+ int i;
+
+ for (i=0;i<hops;i++)
+ {
+ sscanf(result[i],"%*[^ ] %u %*s",&cursiz);
+ if (cursiz>maxsiz)maxsiz=cursiz;
+ }
+ return maxsiz;
+}
+
+
+find_archie(char *what,char *machine, char *filename, char *localfilename)
+{
+
+#define MAXHOPS 15
+
+ static String result[MAXHOPS];
+ static int last=0;
+ static int size=0;
+ static int first=0;
+ int rnd;
+ static int init=0;
+ static String oldwhat={'\0'};
+ char *p1;
+ int i;
+
+ if (!init || strcmp(oldwhat,what)!=0 || last==0)
+ {
+ String cmd;
+ FILE *archie;
+
+ for (i=0;i<MAXHOPS;i++) result[i][0]=0;
+ sprintf(cmd,"archie -l -m %d %s",MAXHOPS,what);
+ DEBUG(cmd);
+
+ if ((archie = popen(cmd,"r"))==NULL)
+ quit("Archie can't execute");
+
+ for(i=0;i<MAXHOPS;i++)
+ {
+ if (fgets(result[i],sizeof (result[i]), archie)==NULL)
+ break;
+ result[i][strlen(result[i])-1]=0;
+ DEBUG(result[i]);
+ }
+
+
+ last=i;
+
+ if ( last==0 )
+ {
+ DEBUG("archie not found need file");
+ return(0);
+ }
+
+
+ init=1;
+ first=0;
+ strcpy(oldwhat,what);
+ size=maxsize(result,MAXHOPS);
+ }
+
+ if (first >= last-1) first=0;
+ for ( i=first; i<last; i++)
+ if ( atoi ( strchr(result[i],' ') + 1 ) == size)
+ {
+ first=i+1;
+ break;
+ }
+
+ DEBUG("Archie select is ... (see next line)");
+ DEBUG(result[i]);
+
+ if (sscanf ( result[i] , "%*[^ ] %*[^ ] %[^ ] %s", machine, filename )!=2)
+ {
+ DEBUG("Bad archie output format");
+ last=0;
+ return(0);
+ }
+
+
+ if ( (p1=strrchr(filename,'/'))!= NULL)
+ strcpy(localfilename,p1+1);
+ else
+ strcpy(localfilename,filename);
+
+ return(1);
+}
+
+
+
+
+
+
diff --git a/lib/libftp/utils/glob.c b/lib/libftp/utils/glob.c
new file mode 100644
index 0000000..d80b146
--- /dev/null
+++ b/lib/libftp/utils/glob.c
@@ -0,0 +1,850 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * glob(3) -- a superset of the one defined in POSIX 1003.2.
+ *
+ * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
+ *
+ * Optional extra services, controlled by flags not defined by POSIX:
+ *
+ * GLOB_QUOTE:
+ * Escaping convention: \ inhibits any special meaning the following
+ * character might have (except \ at end of string is retained).
+ * GLOB_MAGCHAR:
+ * Set in gl_flags if pattern contained a globbing character.
+ * GLOB_NOMAGIC:
+ * Same as GLOB_NOCHECK, but it will only append pattern if it did
+ * not contain any magic characters. [Used in csh style globbing]
+ * GLOB_ALTDIRFUNC:
+ * Use alternately specified directory access functions.
+ * GLOB_TILDE:
+ * expand ~user/foo to the /home/dir/of/user/foo
+ * GLOB_BRACE:
+ * expand {1,2}{a,b} to 1a 1b 2a 2b
+ * gl_matchc:
+ * Number of matches in the current invocation of glob.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <glob.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define DOLLAR '$'
+#define DOT '.'
+#define EOS '\0'
+#define LBRACKET '['
+#define NOT '!'
+#define QUESTION '?'
+#define QUOTE '\\'
+#define RANGE '-'
+#define RBRACKET ']'
+#define SEP '/'
+#define STAR '*'
+#define TILDE '~'
+#define UNDERSCORE '_'
+#define LBRACE '{'
+#define RBRACE '}'
+#define SLASH '/'
+#define COMMA ','
+
+#ifndef DEBUG
+
+#define M_QUOTE 0x8000
+#define M_PROTECT 0x4000
+#define M_MASK 0xffff
+#define M_ASCII 0x00ff
+
+typedef u_short Char;
+
+#else
+
+#define M_QUOTE 0x80
+#define M_PROTECT 0x40
+#define M_MASK 0xff
+#define M_ASCII 0x7f
+
+typedef char Char;
+
+#endif
+
+
+#define CHAR(c) ((Char)((c)&M_ASCII))
+#define META(c) ((Char)((c)|M_QUOTE))
+#define M_ALL META('*')
+#define M_END META(']')
+#define M_NOT META('!')
+#define M_ONE META('?')
+#define M_RNG META('-')
+#define M_SET META('[')
+#define ismeta(c) (((c)&M_QUOTE) != 0)
+
+
+static int compare __P((const void *, const void *));
+static void g_Ctoc __P((const Char *, char *));
+static int g_lstat __P((Char *, struct stat *, glob_t *));
+static DIR *g_opendir __P((Char *, glob_t *));
+static Char *g_strchr __P((Char *, int));
+#ifdef notdef
+static Char *g_strcat __P((Char *, const Char *));
+#endif
+static int g_stat __P((Char *, struct stat *, glob_t *));
+static int glob0 __P((const Char *, glob_t *));
+static int glob1 __P((Char *, glob_t *));
+static int glob2 __P((Char *, Char *, Char *, glob_t *));
+static int glob3 __P((Char *, Char *, Char *, Char *, glob_t *));
+static int globextend __P((const Char *, glob_t *));
+static const Char * globtilde __P((const Char *, Char *, glob_t *));
+static int globexp1 __P((const Char *, glob_t *));
+static int globexp2 __P((const Char *, const Char *, glob_t *, int *));
+static int match __P((Char *, Char *, Char *));
+#ifdef DEBUG
+static void qprintf __P((const char *, Char *));
+#endif
+
+int
+glob(pattern, flags, errfunc, pglob)
+ const char *pattern;
+ int flags, (*errfunc) __P((const char *, int));
+ glob_t *pglob;
+{
+ const u_char *patnext;
+ int c;
+ Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];
+
+ patnext = (u_char *) pattern;
+ if (!(flags & GLOB_APPEND)) {
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = NULL;
+ if (!(flags & GLOB_DOOFFS))
+ pglob->gl_offs = 0;
+ }
+ pglob->gl_flags = flags & ~GLOB_MAGCHAR;
+ pglob->gl_errfunc = errfunc;
+ pglob->gl_matchc = 0;
+
+ bufnext = patbuf;
+ bufend = bufnext + MAXPATHLEN;
+ if (flags & GLOB_QUOTE) {
+ /* Protect the quoted characters. */
+ while (bufnext < bufend && (c = *patnext++) != EOS)
+ if (c == QUOTE) {
+ if ((c = *patnext++) == EOS) {
+ c = QUOTE;
+ --patnext;
+ }
+ *bufnext++ = c | M_PROTECT;
+ }
+ else
+ *bufnext++ = c;
+ }
+ else
+ while (bufnext < bufend && (c = *patnext++) != EOS)
+ *bufnext++ = c;
+ *bufnext = EOS;
+
+ if (flags & GLOB_BRACE)
+ return globexp1(patbuf, pglob);
+ else
+ return glob0(patbuf, pglob);
+}
+
+/*
+ * Expand recursively a glob {} pattern. When there is no more expansion
+ * invoke the standard globbing routine to glob the rest of the magic
+ * characters
+ */
+static int globexp1(pattern, pglob)
+ const Char *pattern;
+ glob_t *pglob;
+{
+ const Char* ptr = pattern;
+ int rv;
+
+ /* Protect a single {}, for find(1), like csh */
+ if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
+ return glob0(pattern, pglob);
+
+ while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
+ if (!globexp2(ptr, pattern, pglob, &rv))
+ return rv;
+
+ return glob0(pattern, pglob);
+}
+
+
+/*
+ * Recursive brace globbing helper. Tries to expand a single brace.
+ * If it succeeds then it invokes globexp1 with the new pattern.
+ * If it fails then it tries to glob the rest of the pattern and returns.
+ */
+static int globexp2(ptr, pattern, pglob, rv)
+ const Char *ptr, *pattern;
+ glob_t *pglob;
+ int *rv;
+{
+ int i;
+ Char *lm, *ls;
+ const Char *pe, *pm, *pl;
+ Char patbuf[MAXPATHLEN + 1];
+
+ /* copy part up to the brace */
+ for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
+ continue;
+ ls = lm;
+
+ /* Find the balanced brace */
+ for (i = 0, pe = ++ptr; *pe; pe++)
+ if (*pe == LBRACKET) {
+ /* Ignore everything between [] */
+ for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
+ continue;
+ if (*pe == EOS) {
+ /*
+ * We could not find a matching RBRACKET.
+ * Ignore and just look for RBRACE
+ */
+ pe = pm;
+ }
+ }
+ else if (*pe == LBRACE)
+ i++;
+ else if (*pe == RBRACE) {
+ if (i == 0)
+ break;
+ i--;
+ }
+
+ /* Non matching braces; just glob the pattern */
+ if (i != 0 || *pe == EOS) {
+ *rv = glob0(patbuf, pglob);
+ return 0;
+ }
+
+ for (i = 0, pl = pm = ptr; pm <= pe; pm++)
+ switch (*pm) {
+ case LBRACKET:
+ /* Ignore everything between [] */
+ for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
+ continue;
+ if (*pm == EOS) {
+ /*
+ * We could not find a matching RBRACKET.
+ * Ignore and just look for RBRACE
+ */
+ pm = pl;
+ }
+ break;
+
+ case LBRACE:
+ i++;
+ break;
+
+ case RBRACE:
+ if (i) {
+ i--;
+ break;
+ }
+ /* FALLTHROUGH */
+ case COMMA:
+ if (i && *pm == COMMA)
+ break;
+ else {
+ /* Append the current string */
+ for (lm = ls; (pl < pm); *lm++ = *pl++)
+ continue;
+ /*
+ * Append the rest of the pattern after the
+ * closing brace
+ */
+ for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
+ continue;
+
+ /* Expand the current pattern */
+#ifdef DEBUG
+ qprintf("globexp2:", patbuf);
+#endif
+ *rv = globexp1(patbuf, pglob);
+
+ /* move after the comma, to the next string */
+ pl = pm + 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ *rv = 0;
+ return 0;
+}
+
+
+
+/*
+ * expand tilde from the passwd file.
+ */
+static const Char *
+globtilde(pattern, patbuf, pglob)
+ const Char *pattern;
+ Char *patbuf;
+ glob_t *pglob;
+{
+ struct passwd *pwd;
+ char *h;
+ const Char *p;
+ Char *b;
+
+ if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
+ return pattern;
+
+ /* Copy up to the end of the string or / */
+ for (p = pattern + 1, h = (char *) patbuf; *p && *p != SLASH;
+ *h++ = *p++)
+ continue;
+
+ *h = EOS;
+
+ if (((char *) patbuf)[0] == EOS) {
+ /*
+ * handle a plain ~ or ~/ by expanding $HOME
+ * first and then trying the password file
+ */
+ if ((h = getenv("HOME")) == NULL) {
+ if ((pwd = getpwuid(getuid())) == NULL)
+ return pattern;
+ else
+ h = pwd->pw_dir;
+ }
+ }
+ else {
+ /*
+ * Expand a ~user
+ */
+ if ((pwd = getpwnam((char*) patbuf)) == NULL)
+ return pattern;
+ else
+ h = pwd->pw_dir;
+ }
+
+ /* Copy the home directory */
+ for (b = patbuf; *h; *b++ = *h++)
+ continue;
+
+ /* Append the rest of the pattern */
+ while ((*b++ = *p++) != EOS)
+ continue;
+
+ return patbuf;
+}
+
+
+/*
+ * The main glob() routine: compiles the pattern (optionally processing
+ * quotes), calls glob1() to do the real pattern matching, and finally
+ * sorts the list (unless unsorted operation is requested). Returns 0
+ * if things went well, nonzero if errors occurred. It is not an error
+ * to find no matches.
+ */
+static int
+glob0(pattern, pglob)
+ const Char *pattern;
+ glob_t *pglob;
+{
+ const Char *qpatnext;
+ int c, err, oldpathc;
+ Char *bufnext, patbuf[MAXPATHLEN+1];
+
+ qpatnext = globtilde(pattern, patbuf, pglob);
+ oldpathc = pglob->gl_pathc;
+ bufnext = patbuf;
+
+ /* We don't need to check for buffer overflow any more. */
+ while ((c = *qpatnext++) != EOS) {
+ switch (c) {
+ case LBRACKET:
+ c = *qpatnext;
+ if (c == NOT)
+ ++qpatnext;
+ if (*qpatnext == EOS ||
+ g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
+ *bufnext++ = LBRACKET;
+ if (c == NOT)
+ --qpatnext;
+ break;
+ }
+ *bufnext++ = M_SET;
+ if (c == NOT)
+ *bufnext++ = M_NOT;
+ c = *qpatnext++;
+ do {
+ *bufnext++ = CHAR(c);
+ if (*qpatnext == RANGE &&
+ (c = qpatnext[1]) != RBRACKET) {
+ *bufnext++ = M_RNG;
+ *bufnext++ = CHAR(c);
+ qpatnext += 2;
+ }
+ } while ((c = *qpatnext++) != RBRACKET);
+ pglob->gl_flags |= GLOB_MAGCHAR;
+ *bufnext++ = M_END;
+ break;
+ case QUESTION:
+ pglob->gl_flags |= GLOB_MAGCHAR;
+ *bufnext++ = M_ONE;
+ break;
+ case STAR:
+ pglob->gl_flags |= GLOB_MAGCHAR;
+ /* collapse adjacent stars to one,
+ * to avoid exponential behavior
+ */
+ if (bufnext == patbuf || bufnext[-1] != M_ALL)
+ *bufnext++ = M_ALL;
+ break;
+ default:
+ *bufnext++ = CHAR(c);
+ break;
+ }
+ }
+ *bufnext = EOS;
+#ifdef DEBUG
+ qprintf("glob0:", patbuf);
+#endif
+
+ if ((err = glob1(patbuf, pglob)) != 0)
+ return(err);
+
+ /*
+ * If there was no match we are going to append the pattern
+ * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
+ * and the pattern did not contain any magic characters
+ * GLOB_NOMAGIC is there just for compatibility with csh.
+ */
+ if (pglob->gl_pathc == oldpathc &&
+ ((pglob->gl_flags & GLOB_NOCHECK) ||
+ ((pglob->gl_flags & GLOB_NOMAGIC) &&
+ !(pglob->gl_flags & GLOB_MAGCHAR))))
+ return(globextend(pattern, pglob));
+ else if (!(pglob->gl_flags & GLOB_NOSORT))
+ qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
+ pglob->gl_pathc - oldpathc, sizeof(char *), compare);
+ return(0);
+}
+
+static int
+compare(p, q)
+ const void *p, *q;
+{
+ return(strcmp(*(char **)p, *(char **)q));
+}
+
+static int
+glob1(pattern, pglob)
+ Char *pattern;
+ glob_t *pglob;
+{
+ Char pathbuf[MAXPATHLEN+1];
+
+ /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
+ if (*pattern == EOS)
+ return(0);
+ return(glob2(pathbuf, pathbuf, pattern, pglob));
+}
+
+/*
+ * The functions glob2 and glob3 are mutually recursive; there is one level
+ * of recursion for each segment in the pattern that contains one or more
+ * meta characters.
+ */
+static int
+glob2(pathbuf, pathend, pattern, pglob)
+ Char *pathbuf, *pathend, *pattern;
+ glob_t *pglob;
+{
+ struct stat sb;
+ Char *p, *q;
+ int anymeta;
+
+ /*
+ * Loop over pattern segments until end of pattern or until
+ * segment with meta character found.
+ */
+ for (anymeta = 0;;) {
+ if (*pattern == EOS) { /* End of pattern? */
+ *pathend = EOS;
+ if (g_lstat(pathbuf, &sb, pglob))
+ return(0);
+
+ if (((pglob->gl_flags & GLOB_MARK) &&
+ pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
+#ifdef S_ISLNK
+ || (S_ISLNK(sb.st_mode) &&
+#else
+ || ( (sb.st_mode&S_IFLNK) &&
+#endif
+ (g_stat(pathbuf, &sb, pglob) == 0) &&
+ S_ISDIR(sb.st_mode)))) {
+ *pathend++ = SEP;
+ *pathend = EOS;
+ }
+ ++pglob->gl_matchc;
+ return(globextend(pathbuf, pglob));
+ }
+
+ /* Find end of next segment, copy tentatively to pathend. */
+ q = pathend;
+ p = pattern;
+ while (*p != EOS && *p != SEP) {
+ if (ismeta(*p))
+ anymeta = 1;
+ *q++ = *p++;
+ }
+
+ if (!anymeta) { /* No expansion, do next segment. */
+ pathend = q;
+ pattern = p;
+ while (*pattern == SEP)
+ *pathend++ = *pattern++;
+ } else /* Need expansion, recurse. */
+ return(glob3(pathbuf, pathend, pattern, p, pglob));
+ }
+ /* NOTREACHED */
+}
+
+static int
+glob3(pathbuf, pathend, pattern, restpattern, pglob)
+ Char *pathbuf, *pathend, *pattern, *restpattern;
+ glob_t *pglob;
+{
+ register struct dirent *dp;
+ DIR *dirp;
+ int err;
+ char buf[MAXPATHLEN];
+
+ /*
+ * The readdirfunc declaration can't be prototyped, because it is
+ * assigned, below, to two functions which are prototyped in glob.h
+ * and dirent.h as taking pointers to differently typed opaque
+ * structures.
+ */
+ struct dirent *(*readdirfunc)();
+
+ *pathend = EOS;
+ errno = 0;
+
+ if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
+ /* TODO: don't call for ENOENT or ENOTDIR? */
+ if (pglob->gl_errfunc) {
+ g_Ctoc(pathbuf, buf);
+ if (pglob->gl_errfunc(buf, errno) ||
+ pglob->gl_flags & GLOB_ERR)
+ return (GLOB_ABEND);
+ }
+ return(0);
+ }
+
+ err = 0;
+
+ /* Search directory for matching names. */
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ readdirfunc = pglob->gl_readdir;
+ else
+ readdirfunc = readdir;
+ while ((dp = (*readdirfunc)(dirp))) {
+ register u_char *sc;
+ register Char *dc;
+
+ /* Initial DOT must be matched literally. */
+ if (dp->d_name[0] == DOT && *pattern != DOT)
+ continue;
+ for (sc = (u_char *) dp->d_name, dc = pathend;
+ (*dc++ = *sc++) != EOS;)
+ continue;
+ if (!match(pathend, pattern, restpattern)) {
+ *pathend = EOS;
+ continue;
+ }
+ err = glob2(pathbuf, --dc, restpattern, pglob);
+ if (err)
+ break;
+ }
+
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ (*pglob->gl_closedir)(dirp);
+ else
+ closedir(dirp);
+ return(err);
+}
+
+
+/*
+ * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
+ * add the new item, and update gl_pathc.
+ *
+ * This assumes the BSD realloc, which only copies the block when its size
+ * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
+ * behavior.
+ *
+ * Return 0 if new item added, error code if memory couldn't be allocated.
+ *
+ * Invariant of the glob_t structure:
+ * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
+ * gl_pathv points to (gl_offs + gl_pathc + 1) items.
+ */
+static int
+globextend(path, pglob)
+ const Char *path;
+ glob_t *pglob;
+{
+ register char **pathv;
+ register int i;
+ u_int newsize;
+ char *copy;
+ const Char *p;
+
+ newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
+ pathv = pglob->gl_pathv ?
+ realloc((char *)pglob->gl_pathv, newsize) :
+ malloc(newsize);
+ if (pathv == NULL)
+ return(GLOB_NOSPACE);
+
+ if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
+ /* first time around -- clear initial gl_offs items */
+ pathv += pglob->gl_offs;
+ for (i = pglob->gl_offs; --i >= 0; )
+ *--pathv = NULL;
+ }
+ pglob->gl_pathv = pathv;
+
+ for (p = path; *p++;)
+ continue;
+ if ((copy = malloc(p - path)) != NULL) {
+ g_Ctoc(path, copy);
+ pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
+ }
+ pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+ return(copy == NULL ? GLOB_NOSPACE : 0);
+}
+
+
+/*
+ * pattern matching function for filenames. Each occurrence of the *
+ * pattern causes a recursion level.
+ */
+static int
+match(name, pat, patend)
+ register Char *name, *pat, *patend;
+{
+ int ok, negate_range;
+ Char c, k;
+
+ while (pat < patend) {
+ c = *pat++;
+ switch (c & M_MASK) {
+ case M_ALL:
+ if (pat == patend)
+ return(1);
+ do
+ if (match(name, pat, patend))
+ return(1);
+ while (*name++ != EOS);
+ return(0);
+ case M_ONE:
+ if (*name++ == EOS)
+ return(0);
+ break;
+ case M_SET:
+ ok = 0;
+ if ((k = *name++) == EOS)
+ return(0);
+ if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
+ ++pat;
+ while (((c = *pat++) & M_MASK) != M_END)
+ if ((*pat & M_MASK) == M_RNG) {
+ if (c <= k && k <= pat[1])
+ ok = 1;
+ pat += 2;
+ } else if (c == k)
+ ok = 1;
+ if (ok == negate_range)
+ return(0);
+ break;
+ default:
+ if (*name++ != c)
+ return(0);
+ break;
+ }
+ }
+ return(*name == EOS);
+}
+
+/* Free allocated data belonging to a glob_t structure. */
+void
+globfree(pglob)
+ glob_t *pglob;
+{
+ register int i;
+ register char **pp;
+
+ if (pglob->gl_pathv != NULL) {
+ pp = pglob->gl_pathv + pglob->gl_offs;
+ for (i = pglob->gl_pathc; i--; ++pp)
+ if (*pp)
+ free(*pp);
+ free(pglob->gl_pathv);
+ }
+}
+
+static DIR *
+g_opendir(str, pglob)
+ register Char *str;
+ glob_t *pglob;
+{
+ char buf[MAXPATHLEN];
+
+ if (!*str)
+ strcpy(buf, ".");
+ else
+ g_Ctoc(str, buf);
+
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ return((*pglob->gl_opendir)(buf));
+
+ return(opendir(buf));
+}
+
+static int
+g_lstat(fn, sb, pglob)
+ register Char *fn;
+ struct stat *sb;
+ glob_t *pglob;
+{
+ char buf[MAXPATHLEN];
+
+ g_Ctoc(fn, buf);
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ return((*pglob->gl_lstat)(buf, sb));
+ return(lstat(buf, sb));
+}
+
+static int
+g_stat(fn, sb, pglob)
+ register Char *fn;
+ struct stat *sb;
+ glob_t *pglob;
+{
+ char buf[MAXPATHLEN];
+
+ g_Ctoc(fn, buf);
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ return((*pglob->gl_stat)(buf, sb));
+ return(stat(buf, sb));
+}
+
+static Char *
+g_strchr(str, ch)
+ Char *str;
+ int ch;
+{
+ do {
+ if (*str == ch)
+ return (str);
+ } while (*str++);
+ return (NULL);
+}
+
+#ifdef notdef
+static Char *
+g_strcat(dst, src)
+ Char *dst;
+ const Char* src;
+{
+ Char *sdst = dst;
+
+ while (*dst++)
+ continue;
+ --dst;
+ while((*dst++ = *src++) != EOS)
+ continue;
+
+ return (sdst);
+}
+#endif
+
+static void
+g_Ctoc(str, buf)
+ register const Char *str;
+ char *buf;
+{
+ register char *dc;
+
+ for (dc = buf; (*dc++ = *str++) != EOS;)
+ continue;
+}
+
+#ifdef DEBUG
+static void
+qprintf(str, s)
+ const char *str;
+ register Char *s;
+{
+ register Char *p;
+
+ (void)printf("%s:\n", str);
+ for (p = s; *p; p++)
+ (void)printf("%c", CHAR(*p));
+ (void)printf("\n");
+ for (p = s; *p; p++)
+ (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
+ (void)printf("\n");
+ for (p = s; *p; p++)
+ (void)printf("%c", ismeta(*p) ? '_' : ' ');
+ (void)printf("\n");
+}
+#endif
diff --git a/lib/libftp/utils/glob.h b/lib/libftp/utils/glob.h
new file mode 100644
index 0000000..bffb28c
--- /dev/null
+++ b/lib/libftp/utils/glob.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)glob.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _GLOB_H_
+#define _GLOB_H_
+
+
+#include <cdefs.h>
+
+struct stat;
+typedef struct {
+ int gl_pathc; /* Count of total paths so far. */
+ int gl_matchc; /* Count of paths matching pattern. */
+ int gl_offs; /* Reserved at beginning of gl_pathv. */
+ int gl_flags; /* Copy of flags parameter to glob. */
+ char **gl_pathv; /* List of paths matching pattern. */
+ /* Copy of errfunc parameter to glob. */
+ int (*gl_errfunc) __P((const char *, int));
+
+ /*
+ * Alternate filesystem access methods for glob; replacement
+ * versions of closedir(3), readdir(3), opendir(3), stat(2)
+ * and lstat(2).
+ */
+ void (*gl_closedir) __P((void *));
+ struct dirent *(*gl_readdir) __P((void *));
+ void *(*gl_opendir) __P((const char *));
+ int (*gl_lstat) __P((const char *, struct stat *));
+ int (*gl_stat) __P((const char *, struct stat *));
+} glob_t;
+
+#define GLOB_APPEND 0x0001 /* Append to output from previous call. */
+#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */
+#define GLOB_ERR 0x0004 /* Return on error. */
+#define GLOB_MARK 0x0008 /* Append / to matching directories. */
+#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */
+#define GLOB_NOSORT 0x0020 /* Don't sort. */
+
+#define GLOB_ALTDIRFUNC 0x0040 /* Use alternately specified directory funcs. */
+#define GLOB_BRACE 0x0080 /* Expand braces ala csh. */
+#define GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */
+#define GLOB_NOMAGIC 0x0200 /* GLOB_NOCHECK without magic chars (csh). */
+#define GLOB_QUOTE 0x0400 /* Quote special chars with \. */
+#define GLOB_TILDE 0x0800 /* Expand tilde names from the passwd file. */
+
+#define GLOB_NOSPACE (-1) /* Malloc call failed. */
+#define GLOB_ABEND (-2) /* Unignored error. */
+
+__BEGIN_DECLS
+int glob __P((const char *, int, int (*)(const char *, int), glob_t *));
+void globfree __P((glob_t *));
+__END_DECLS
+
+#endif /* !_GLOB_H_ */
diff --git a/lib/libftp/utils/mirror.c b/lib/libftp/utils/mirror.c
new file mode 100644
index 0000000..babd840
--- /dev/null
+++ b/lib/libftp/utils/mirror.c
@@ -0,0 +1,92 @@
+
+/* Mirror directrory structure to another host */
+
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <sys/stat.h>
+#include <syslog.h>
+#include <FtpLibrary.h>
+
+/* Usage: mirror <local_dir> <host> <user> <passwd> <remote_dir> */
+FTP *ftp;
+
+main(int a,char **b)
+{
+
+#define LOCAL_DIR b[1]
+#define HOST b[2]
+#define USER b[3]
+#define PASSWD b[4]
+#define REMOTE_DIR b[5]
+
+ if ( a < 5 )
+ quit("Usage: mirror <local_dir> <host> <user> <passwd> <remote_dir>");
+
+
+ FtplibDebug(yes);
+ FtpLogin(&ftp,HOST,USER,PASSWD,NULL);
+ FtpChdir(ftp,REMOTE_DIR);
+ FtpBinary(ftp);
+ doit(LOCAL_DIR);
+ exit(0);
+}
+
+doit(char *dirname)
+{
+ DIR *dp;
+ struct direct *de;
+ char n[256],fn[256];
+ struct stat st;
+
+
+ if ( (dp=opendir(dirname)) == NULL )
+ {
+ log(dirname);
+ return;
+ }
+
+ while ( (de = readdir(dp)) != NULL )
+ {
+ if ( de -> d_name[0] == '.' )
+ continue;
+
+ sprintf(fn,"%s/%s",dirname,de->d_name);
+
+ if ( stat(fn,&st) != 0 ) {
+ log(fn);
+ continue;
+ }
+
+ if ( S_ISDIR (st.st_mode) )
+ {
+ FtpCommand(ftp,"MKD %s",fn,0,EOF); /* Ignore errors (0,EOF) */
+ doit(fn);
+ continue;
+ }
+
+ if ( st.st_size != FtpSize(ftp,fn))
+
+ FtpPut(ftp,fn,fn);
+ }
+
+ closedir(dp);
+
+}
+
+
+
+quit(char *s)
+{
+ log(s);
+ exit(1);
+}
+
+log(char *s)
+{
+ perror(s);
+}
+
+
+
diff --git a/lib/libftp/utils/readline.c b/lib/libftp/utils/readline.c
new file mode 100644
index 0000000..34612ba
--- /dev/null
+++ b/lib/libftp/utils/readline.c
@@ -0,0 +1,961 @@
+#ifndef lint
+static char *RCSid = "$Id: readline.c%v 3.50.1.9 1993/08/05 05:38:59 woo Exp $";
+#endif
+
+
+/* GNUPLOT - readline.c */
+/*
+ * Copyright (C) 1986 - 1993 Thomas Williams, Colin Kelley
+ *
+ * Permission to use, copy, and distribute this software and its
+ * documentation for any purpose with or without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.
+ *
+ * Permission to modify the software is granted, but not the right to
+ * distribute the modified code. Modifications are to be distributed
+ * as patches to released version.
+ *
+ * This software is provided "as is" without express or implied warranty.
+ *
+ *
+ * AUTHORS
+ *
+ * Original Software:
+ * Tom Tkacik
+ *
+ * Msdos port and some enhancements:
+ * Gershon Elber and many others.
+ *
+ * There is a mailing list for gnuplot users. Note, however, that the
+ * newsgroup
+ * comp.graphics.gnuplot
+ * is identical to the mailing list (they
+ * both carry the same set of messages). We prefer that you read the
+ * messages through that newsgroup, to subscribing to the mailing list.
+ * (If you can read that newsgroup, and are already on the mailing list,
+ * please send a message info-gnuplot-request@dartmouth.edu, asking to be
+ * removed from the mailing list.)
+ *
+ * The address for mailing to list members is
+ * info-gnuplot@dartmouth.edu
+ * and for mailing administrative requests is
+ * info-gnuplot-request@dartmouth.edu
+ * The mailing list for bug reports is
+ * bug-gnuplot@dartmouth.edu
+ * The list of those interested in beta-test versions is
+ * info-gnuplot-beta@dartmouth.edu
+ */
+
+#ifdef READLINE
+#ifdef ATARI
+#include "plot.h"
+#endif
+#ifdef _WINDOWS
+#define _Windows
+#endif
+
+/* a small portable version of GNU's readline */
+/* this is not the BASH or GNU EMACS version of READLINE due to Copyleft
+ restrictions */
+/* do not need any terminal capabilities except backspace, */
+/* and space overwrites a character */
+
+/* NANO-EMACS line editing facility */
+/* printable characters print as themselves (insert not overwrite) */
+/* ^A moves to the beginning of the line */
+/* ^B moves back a single character */
+/* ^E moves to the end of the line */
+/* ^F moves forward a single character */
+/* ^K kills from current position to the end of line */
+/* ^P moves back through history */
+/* ^N moves forward through history */
+/* ^H and DEL delete the previous character */
+/* ^D deletes the current character, or EOF if line is empty */
+/* ^L/^R redraw line in case it gets trashed */
+/* ^U kills the entire line */
+/* ^W kills last word */
+/* LF and CR return the entire line regardless of the cursor postition */
+/* EOF with an empty line returns (char *)NULL */
+
+/* all other characters are ignored */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+
+#if !defined(MSDOS) && !defined(ATARI) && !defined(_Windows) && !defined(DOS386)
+
+/*
+ * Set up structures using the proper include file
+ */
+#if defined(_IBMR2) || defined(alliant)
+#define SGTTY
+#endif
+
+/* submitted by Francois.Dagorn@cicb.fr */
+#ifdef SGTTY
+#include <sgtty.h>
+static struct sgttyb orig_termio, rl_termio;
+/* define terminal control characters */
+static struct tchars s_tchars;
+#define VERASE 0
+#define VEOF 1
+#define VKILL 2
+#ifdef TIOCGLTC /* available only with the 'new' line discipline */
+static struct ltchars s_ltchars;
+#define VWERASE 3
+#define VREPRINT 4
+#define VSUSP 5
+#endif /* TIOCGLTC */
+#define NCCS 6
+
+#else /* SGTTY */
+
+/* SIGTSTP defines job control */
+/* if there is job control then we need termios.h instead of termio.h */
+/* (Are there any systems with job control that use termio.h? I hope not.) */
+#ifdef SIGTSTP
+#define TERMIOS
+#include <termios.h>
+/* Added by Robert Eckardt, RobertE@beta.TP2.Ruhr-Uni-Bochum.de */
+#ifdef ISC22
+#ifndef ONOCR /* taken from sys/termio.h */
+#define ONOCR 0000020 /* true at least for ISC 2.2 */
+#endif
+#ifndef IUCLC
+#define IUCLC 0001000
+#endif
+#endif /* ISC22 */
+
+static struct termios orig_termio, rl_termio;
+#else
+#include <termio.h>
+static struct termio orig_termio, rl_termio;
+/* termio defines NCC instead of NCCS */
+#define NCCS NCC
+#endif /* SIGTSTP */
+#endif /* SGTTY */
+
+/* ULTRIX defines VRPRNT instead of VREPRINT */
+#ifdef VRPRNT
+#define VREPRINT VRPRNT
+#endif
+
+/* define characters to use with our input character handler */
+static char term_chars[NCCS];
+
+static int term_set = 0; /* =1 if rl_termio set */
+
+#define special_getc() ansi_getc()
+static char ansi_getc();
+
+#else /* !MSDOS && !ATARI && !_Windows */
+
+#ifdef _Windows
+#include <windows.h>
+#include "win/wtext.h"
+#include "win/wgnuplib.h"
+extern TW textwin;
+#define TEXTUSER 0xf1
+#define TEXTGNUPLOT 0xf0
+#define special_getc() msdos_getch()
+static char msdos_getch();
+#endif
+
+#if defined(MSDOS) || defined(DOS386)
+/* MSDOS specific stuff */
+#ifdef DJGPP
+#include <pc.h>
+#endif
+#ifdef __EMX__
+#include <conio.h>
+#endif
+#define special_getc() msdos_getch()
+static char msdos_getch();
+#endif /* MSDOS */
+
+#ifdef ATARI
+#include <stdlib.h>
+#ifdef __PUREC__
+#include <tos.h>
+#else
+#include <osbind.h>
+#endif
+#define special_getc() tos_getch()
+static char tos_getch();
+#endif
+
+#endif /* !MSDOS && !ATARI && !_Windows */
+
+#if !defined(ATARI)
+/* is it <string.h> or <strings.h>? just declare what we need */
+extern int strlen();
+extern char *strcpy();
+#endif
+#define alloc malloc
+extern char *alloc(); /* we'll use the safe malloc from misc.c */
+
+#define MAXBUF 1024
+#define BACKSPACE 0x08 /* ^H */
+#define SPACE ' '
+
+struct hist {
+ char *line;
+ struct hist *prev;
+ struct hist *next;
+};
+
+static struct hist *history = NULL; /* no history yet */
+static struct hist *cur_entry = NULL;
+
+static char cur_line[MAXBUF]; /* current contents of the line */
+static int cur_pos = 0; /* current position of the cursor */
+static int max_pos = 0; /* maximum character position */
+
+
+void add_history();
+static void fix_line();
+static void redraw_line();
+static void clear_line();
+static void clear_eoline();
+static void copy_line();
+static void set_termio();
+void reset_termio();
+
+/* user_putc and user_puts should be used in the place of
+ * fputc(ch,stderr) and fputs(str,stderr) for all output
+ * of user typed characters. This allows MS-Windows to
+ * display user input in a different color. */
+int
+user_putc(ch)
+int ch;
+{
+ int rv;
+#ifdef _Windows
+ TextAttr(&textwin,TEXTUSER);
+#endif
+ rv = fputc(ch, stderr);
+#ifdef _Windows
+ TextAttr(&textwin,TEXTGNUPLOT);
+#endif
+ return rv;
+}
+
+int
+user_puts(str)
+char *str;
+{
+ int rv;
+#ifdef _Windows
+ TextAttr(&textwin,TEXTUSER);
+#endif
+ rv = fputs(str, stderr);
+#ifdef _Windows
+ TextAttr(&textwin,TEXTGNUPLOT);
+#endif
+ return rv;
+}
+
+/* This function provides a centralized non-destructive backspace capability */
+/* M. Castro */
+
+backspace()
+{
+ user_putc(BACKSPACE);
+}
+
+char *
+readline(prompt)
+char *prompt;
+{
+
+ unsigned char cur_char;
+ char *new_line;
+ /* unsigned char *new_line; */
+
+ /* set the termio so we can do our own input processing */
+ set_termio();
+
+ /* print the prompt */
+ fputs(prompt, stderr);
+ cur_line[0] = '\0';
+ cur_pos = 0;
+ max_pos = 0;
+ cur_entry = NULL;
+
+ /* get characters */
+ for(;;) {
+ cur_char = special_getc();
+#ifdef OS2
+ /* for emx: remap scan codes for cursor keys */
+ if( cur_char == 0 ) {
+ cur_char = getc(stdin);
+ switch( cur_char){
+ case 75: /* left, map to ^B */
+ cur_char=2;
+ break ;
+ case 77: /* right, map to ^F */
+ cur_char=6;
+ break ;
+ case 115: /* ctrl left */
+ case 71: /* home, map to ^A */
+ cur_char=1;
+ break ;
+ case 116: /* ctrl right */
+ case 79: /* end, map to ^E */
+ cur_char=5;
+ break ;
+ case 72: /* up, map to ^P */
+ cur_char=16;
+ break ;
+ case 80: /* down, map to ^N */
+ cur_char=14;
+ break ;
+ case 83: /* delete, map to ^D */
+ cur_char=4;
+ break ;
+ default: /* ignore */
+ cur_char=0;
+ continue ;
+ }
+ }
+#endif /*OS2*/
+ if((isprint(cur_char)
+#if defined(ATARI) || defined(_Windows) || defined(MSDOS) || defined(DOS386)
+ /* this should be used for all 8bit ASCII machines, I guess */
+ || ((unsigned char)cur_char > 0x7f)
+#endif
+ )&& max_pos<MAXBUF-1) {
+ int i;
+ for(i=max_pos; i>cur_pos; i--) {
+ cur_line[i] = cur_line[i-1];
+ }
+ user_putc(cur_char);
+ cur_line[cur_pos] = cur_char;
+ cur_pos += 1;
+ max_pos += 1;
+ if (cur_pos < max_pos)
+ fix_line();
+ cur_line[max_pos] = '\0';
+
+ /* else interpret unix terminal driver characters */
+#ifdef VERASE
+ } else if(cur_char == term_chars[VERASE] ){ /* DEL? */
+ if(cur_pos > 0) {
+ int i;
+ cur_pos -= 1;
+ backspace();
+ for(i=cur_pos; i<max_pos; i++)
+ cur_line[i] = cur_line[i+1];
+ max_pos -= 1;
+ fix_line();
+ }
+#endif /* VERASE */
+#ifdef VEOF
+ } else if(cur_char == term_chars[VEOF] ){ /* ^D? */
+ if(max_pos == 0) {
+ reset_termio();
+ return((char *)NULL);
+ }
+ if((cur_pos < max_pos)&&(cur_char == 004)) { /* ^D */
+ int i;
+ for(i=cur_pos; i<max_pos; i++)
+ cur_line[i] = cur_line[i+1];
+ max_pos -= 1;
+ fix_line();
+ }
+#endif /* VEOF */
+#ifdef VKILL
+ } else if(cur_char == term_chars[VKILL] ){ /* ^U? */
+ clear_line(prompt);
+#endif /* VKILL */
+#ifdef VWERASE
+ } else if(cur_char == term_chars[VWERASE] ){ /* ^W? */
+ while((cur_pos > 0) &&
+ (cur_line[cur_pos-1] == SPACE)) {
+ cur_pos -= 1;
+ backspace();
+ }
+ while((cur_pos > 0) &&
+ (cur_line[cur_pos-1] != SPACE)) {
+ cur_pos -= 1;
+ backspace();
+ }
+ clear_eoline();
+ max_pos = cur_pos;
+#endif /* VWERASE */
+#ifdef VREPRINT
+ } else if(cur_char == term_chars[VREPRINT] ){ /* ^R? */
+ putc('\n',stderr); /* go to a fresh line */
+ redraw_line(prompt);
+#endif /* VREPRINT */
+#ifdef VSUSP
+ } else if(cur_char == term_chars[VSUSP]) {
+ reset_termio();
+ kill(0, SIGTSTP);
+
+ /* process stops here */
+
+ set_termio();
+ /* print the prompt */
+ redraw_line(prompt);
+#endif /* VSUSP */
+ } else {
+ /* do normal editing commands */
+ /* some of these are also done above */
+ int i;
+ switch(cur_char) {
+ case EOF:
+ reset_termio();
+ return((char *)NULL);
+ case 001: /* ^A */
+ while(cur_pos > 0) {
+ cur_pos -= 1;
+ backspace();
+ }
+ break;
+ case 002: /* ^B */
+ if(cur_pos > 0) {
+ cur_pos -= 1;
+ backspace();
+ }
+ break;
+ case 005: /* ^E */
+ while(cur_pos < max_pos) {
+ user_putc(cur_line[cur_pos]);
+ cur_pos += 1;
+ }
+ break;
+ case 006: /* ^F */
+ if(cur_pos < max_pos) {
+ user_putc(cur_line[cur_pos]);
+ cur_pos += 1;
+ }
+ break;
+ case 013: /* ^K */
+ clear_eoline();
+ max_pos = cur_pos;
+ break;
+ case 020: /* ^P */
+ if(history != NULL) {
+ if(cur_entry == NULL) {
+ cur_entry = history;
+ clear_line(prompt);
+ copy_line(cur_entry->line);
+ } else if(cur_entry->prev != NULL) {
+ cur_entry = cur_entry->prev;
+ clear_line(prompt);
+ copy_line(cur_entry->line);
+ }
+ }
+ break;
+ case 016: /* ^N */
+ if(cur_entry != NULL) {
+ cur_entry = cur_entry->next;
+ clear_line(prompt);
+ if(cur_entry != NULL)
+ copy_line(cur_entry->line);
+ else
+ cur_pos = max_pos = 0;
+ }
+ break;
+ case 014: /* ^L */
+ case 022: /* ^R */
+ putc('\n',stderr); /* go to a fresh line */
+ redraw_line(prompt);
+ break;
+ case 0177: /* DEL */
+ case 010: /* ^H */
+ if(cur_pos > 0) {
+ cur_pos -= 1;
+ backspace();
+ for(i=cur_pos; i<max_pos; i++)
+ cur_line[i] = cur_line[i+1];
+ max_pos -= 1;
+ fix_line();
+ }
+ break;
+ case 004: /* ^D */
+ if(max_pos == 0) {
+ reset_termio();
+ return((char *)NULL);
+ }
+ if(cur_pos < max_pos) {
+ for(i=cur_pos; i<max_pos; i++)
+ cur_line[i] = cur_line[i+1];
+ max_pos -= 1;
+ fix_line();
+ }
+ break;
+ case 025: /* ^U */
+ clear_line(prompt);
+ break;
+ case 027: /* ^W */
+ while((cur_pos > 0) &&
+ (cur_line[cur_pos-1] == SPACE)) {
+ cur_pos -= 1;
+ backspace();
+ }
+ while((cur_pos > 0) &&
+ (cur_line[cur_pos-1] != SPACE)) {
+ cur_pos -= 1;
+ backspace();
+ }
+ clear_eoline();
+ max_pos = cur_pos;
+ break;
+ case '\n': /* ^J */
+ case '\r': /* ^M */
+ cur_line[max_pos+1] = '\0';
+ putc('\n', stderr);
+ new_line = (char *)alloc((unsigned long) (strlen(cur_line)+1), "history");
+ strcpy(new_line,cur_line);
+ reset_termio();
+ return(new_line);
+ default:
+ break;
+ }
+ }
+ }
+}
+
+/* fix up the line from cur_pos to max_pos */
+/* do not need any terminal capabilities except backspace, */
+/* and space overwrites a character */
+static void
+fix_line()
+{
+ int i;
+
+ /* write tail of string */
+ for(i=cur_pos; i<max_pos; i++)
+ user_putc(cur_line[i]);
+
+ /* write a space at the end of the line in case we deleted one */
+ user_putc(SPACE);
+
+ /* backup to original position */
+ for(i=max_pos+1; i>cur_pos; i--)
+ backspace();
+
+}
+
+/* redraw the entire line, putting the cursor where it belongs */
+static void
+redraw_line(prompt)
+char *prompt;
+{
+ int i;
+
+ fputs(prompt, stderr);
+ user_puts(cur_line);
+
+ /* put the cursor where it belongs */
+ for(i=max_pos; i>cur_pos; i--)
+ backspace();
+}
+
+/* clear cur_line and the screen line */
+static void
+clear_line(prompt)
+char *prompt;
+{
+ int i;
+ for(i=0; i<max_pos; i++)
+ cur_line[i] = '\0';
+
+ for(i=cur_pos; i>0; i--)
+ backspace();
+
+ for(i=0; i<max_pos; i++)
+ putc(SPACE, stderr);
+
+ putc('\r', stderr);
+ fputs(prompt, stderr);
+
+ cur_pos = 0;
+ max_pos = 0;
+}
+
+/* clear to end of line and the screen end of line */
+static void
+clear_eoline(prompt)
+char *prompt;
+{
+ int i;
+ for(i=cur_pos; i<max_pos; i++)
+ cur_line[i] = '\0';
+
+ for(i=cur_pos; i<max_pos; i++)
+ putc(SPACE, stderr);
+ for(i=cur_pos; i<max_pos; i++)
+ backspace();
+}
+
+/* copy line to cur_line, draw it and set cur_pos and max_pos */
+static void
+copy_line(line)
+char *line;
+{
+ strcpy(cur_line, line);
+ user_puts(cur_line);
+ cur_pos = max_pos = strlen(cur_line);
+}
+
+/* add line to the history */
+void
+add_history(line)
+char *line;
+{
+ struct hist *entry;
+ entry = (struct hist *)alloc((unsigned long)sizeof(struct hist),"history");
+ entry->line = alloc((unsigned long)(strlen(line)+1),"history");
+ strcpy(entry->line, line);
+
+ entry->prev = history;
+ entry->next = NULL;
+ if(history != NULL) {
+ history->next = entry;
+ }
+ history = entry;
+}
+
+
+/* Convert ANSI arrow keys to control characters */
+static char
+ansi_getc()
+{
+ char c = getc(stdin);
+ if (c == 033) {
+ c = getc(stdin); /* check for CSI */
+ if (c == '[') {
+ c = getc(stdin); /* get command character */
+ switch (c) {
+ case 'D': /* left arrow key */
+ c = 002;
+ break;
+ case 'C': /* right arrow key */
+ c = 006;
+ break;
+ case 'A': /* up arrow key */
+ c = 020;
+ break;
+ case 'B': /* down arrow key */
+ c = 016;
+ break;
+ }
+ }
+ }
+ return c;
+}
+
+#if defined(MSDOS) || defined(_Windows) || defined(DOS386)
+
+/* Convert Arrow keystrokes to Control characters: */
+static char
+msdos_getch()
+{
+#ifdef DJGPP
+ char c;
+ int ch = getkey();
+ c = (ch & 0xff00) ? 0 : ch & 0xff;
+#else
+ char c = getch();
+#endif
+
+ if (c == 0) {
+#ifdef DJGPP
+ c = ch & 0xff;
+#else
+ c = getch(); /* Get the extended code. */
+#endif
+ switch (c) {
+ case 75: /* Left Arrow. */
+ c = 002;
+ break;
+ case 77: /* Right Arrow. */
+ c = 006;
+ break;
+ case 72: /* Up Arrow. */
+ c = 020;
+ break;
+ case 80: /* Down Arrow. */
+ c = 016;
+ break;
+ case 115: /* Ctl Left Arrow. */
+ case 71: /* Home */
+ c = 001;
+ break;
+ case 116: /* Ctl Right Arrow. */
+ case 79: /* End */
+ c = 005;
+ break;
+ case 83: /* Delete */
+ c = 004;
+ break;
+ default:
+ c = 0;
+ break;
+ }
+ }
+ else if (c == 033) { /* ESC */
+ c = 025;
+ }
+
+
+ return c;
+}
+
+#endif /* MSDOS */
+
+#ifdef ATARI
+
+/* Convert Arrow keystrokes to Control characters: TOS version */
+
+/* the volatile could be necessary to keep gcc from reordering
+ the two Super calls
+*/
+#define CONTERM ((/*volatile*/ char *)0x484L)
+
+static void
+remove_conterm()
+{
+ void *ssp=(void*)Super(0L);
+ *CONTERM &= ~0x8;
+ Super(ssp);
+}
+
+static char
+tos_getch()
+{
+ long rawkey;
+ char c;
+ int scan_code;
+ void *ssp;
+ static int init = 1;
+ static int in_help = 0;
+
+ if (in_help) {
+ switch(in_help) {
+ case 1:
+ case 5: in_help++; return 'e';
+ case 2:
+ case 6: in_help++; return 'l';
+ case 3:
+ case 7: in_help++; return 'p';
+ case 4: in_help = 0; return 0x0d;
+ case 8: in_help = 0; return ' ';
+ }
+ }
+
+ if (init) {
+ ssp = (void*)Super(0L);
+ if( !(*CONTERM & 0x8) ) {
+ *CONTERM |= 0x8;
+ } else {
+ init=0;
+ }
+ (void)Super(ssp);
+ if( init ) {
+ atexit(remove_conterm);
+ init = 0;
+ }
+ }
+
+ (void)Cursconf(1, 0); /* cursor on */
+ rawkey = Cnecin();
+ c = (char)rawkey;
+ scan_code= ((int)(rawkey>>16)) & 0xff; /* get the scancode */
+ if( rawkey&0x07000000 ) scan_code |= 0x80; /* shift or control */
+
+ switch (scan_code) {
+ case 0x62: /* HELP */
+ if (max_pos==0) {
+ in_help = 1;
+ return 'h';
+ } else {
+ return 0;
+ }
+ case 0xe2: /* shift HELP */
+ if (max_pos==0) {
+ in_help = 5;
+ return 'h';
+ } else {
+ return 0;
+ }
+ case 0x48: /* Up Arrow */
+ return 0x10; /* ^P */
+ case 0x50: /* Down Arrow */
+ return 0x0e; /* ^N */
+ case 0x4b: /* Left Arrow */
+ return 0x02; /* ^B */
+ case 0x4d: /* Right Arrow */
+ return 0x06; /* ^F */
+ case 0xcb: /* Shift Left Arrow */
+ case 0xf3: /* Ctrl Left Arrow (TOS-bug ?) */
+ case 0x47: /* Home */
+ return 0x01; /* ^A */
+ case 0xcd: /* Shift Right Arrow */
+ case 0xf4: /* Ctrl Right Arrow (TOS-bug ?) */
+ case 0xc7: /* Shift Home */
+ case 0xf7: /* Crtl Home */
+ return 0x05; /* ^E */
+ case 0x61: /* Undo - redraw line */
+ return 0x0c; /* ^L */
+ default:
+ if (c == 0x1b) return 0x15; /* ESC becomes ^U */
+ if (c == 0x7f) return 0x04; /* Del becomes ^D */
+ break;
+ }
+
+ return c;
+}
+
+#endif /* ATARI */
+
+ /* set termio so we can do our own input processing */
+static void
+set_termio()
+{
+#if !defined(MSDOS) && !defined(ATARI) && !defined(_Windows) && !defined(DOS386)
+/* set termio so we can do our own input processing */
+/* and save the old terminal modes so we can reset them later */
+ if(term_set == 0) {
+ /*
+ * Get terminal modes.
+ */
+#ifdef SGTTY
+ ioctl(0, TIOCGETP, &orig_termio);
+#else /* SGTTY */
+#ifdef TERMIOS
+#ifdef TCGETS
+ ioctl(0, TCGETS, &orig_termio);
+#else
+ tcgetattr(0, &orig_termio);
+#endif /* TCGETS */
+#else
+ ioctl(0, TCGETA, &orig_termio);
+#endif /* TERMIOS */
+#endif /* SGTTY */
+
+ /*
+ * Save terminal modes
+ */
+ rl_termio = orig_termio;
+
+ /*
+ * Set the modes to the way we want them
+ * and save our input special characters
+ */
+#ifdef SGTTY
+ rl_termio.sg_flags |= CBREAK;
+ rl_termio.sg_flags &= ~(ECHO|XTABS);
+ ioctl(0, TIOCSETN, &rl_termio);
+
+ ioctl(0, TIOCGETC, &s_tchars);
+ term_chars[VERASE] = orig_termio.sg_erase;
+ term_chars[VEOF] = s_tchars.t_eofc;
+ term_chars[VKILL] = orig_termio.sg_kill;
+#ifdef TIOCGLTC
+ ioctl(0, TIOCGLTC, &s_ltchars);
+ term_chars[VWERASE] = s_ltchars.t_werasc;
+ term_chars[VREPRINT] = s_ltchars.t_rprntc;
+ term_chars[VSUSP] = s_ltchars.t_suspc;
+
+ /* disable suspending process on ^Z */
+ s_ltchars.t_suspc = 0;
+ ioctl(0, TIOCSLTC, &s_ltchars);
+#endif /* TIOCGLTC */
+#else /* SGTTY */
+#ifdef IUCLC
+ rl_termio.c_iflag &= ~(BRKINT|PARMRK|INPCK|IUCLC|IXON|IXOFF);
+#else
+ rl_termio.c_iflag &= ~(BRKINT|PARMRK|INPCK|IXON|IXOFF);
+#endif
+ rl_termio.c_iflag |= (IGNBRK|IGNPAR);
+
+ /* rl_termio.c_oflag &= ~(ONOCR); Costas Sphocleous Irvine,CA */
+
+ rl_termio.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL|NOFLSH);
+#ifdef OS2
+ /* for emx: remove default terminal processing */
+ rl_termio.c_lflag &= ~(IDEFAULT);
+#endif /* OS2 */
+ rl_termio.c_lflag |= (ISIG);
+ rl_termio.c_cc[VMIN] = 1;
+ rl_termio.c_cc[VTIME] = 0;
+
+#ifndef VWERASE
+#define VWERASE 3
+#endif
+ term_chars[VERASE] = orig_termio.c_cc[VERASE];
+ term_chars[VEOF] = orig_termio.c_cc[VEOF];
+ term_chars[VKILL] = orig_termio.c_cc[VKILL];
+#ifdef TERMIOS
+ term_chars[VWERASE] = orig_termio.c_cc[VWERASE];
+#ifdef VREPRINT
+ term_chars[VREPRINT] = orig_termio.c_cc[VREPRINT];
+#else
+#ifdef VRPRNT
+ term_chars[VRPRNT] = orig_termio.c_cc[VRPRNT];
+#endif
+#endif
+ term_chars[VSUSP] = orig_termio.c_cc[VSUSP];
+
+ /* disable suspending process on ^Z */
+ rl_termio.c_cc[VSUSP] = 0;
+#endif /* TERMIOS */
+#endif /* SGTTY */
+
+ /*
+ * Set the new terminal modes.
+ */
+#ifdef SGTTY
+ ioctl(0, TIOCSLTC, &s_ltchars);
+#else
+#ifdef TERMIOS
+#ifdef TCSETSW
+ ioctl(0, TCSETSW, &rl_termio);
+#else
+ tcsetattr(0, TCSADRAIN, &rl_termio);
+#endif /* TCSETSW */
+#else
+ ioctl(0, TCSETAW, &rl_termio);
+#endif /* TERMIOS */
+#endif /* SGTTY */
+ term_set = 1;
+ }
+#endif /* !MSDOS && !ATARI && !defined(_Windows) */
+}
+
+void
+reset_termio()
+{
+#if !defined(MSDOS) && !defined(ATARI) && !defined(_Windows) && !defined(DOS386)
+/* reset saved terminal modes */
+ if(term_set == 1) {
+#ifdef SGTTY
+ ioctl(0, TIOCSETN, &orig_termio);
+#ifdef TIOCGLTC
+ /* enable suspending process on ^Z */
+ s_ltchars.t_suspc = term_chars[VSUSP];
+ ioctl(0, TIOCSLTC, &s_ltchars);
+#endif /* TIOCGLTC */
+#else /* SGTTY */
+#ifdef TERMIOS
+#ifdef TCSETSW
+ ioctl(0, TCSETSW, &orig_termio);
+#else
+ tcsetattr(0, TCSADRAIN, &orig_termio);
+#endif /* TCSETSW */
+#else
+ ioctl(0, TCSETAW, &orig_termio);
+#endif /* TERMIOS */
+#endif /* SGTTY */
+ term_set = 0;
+ }
+#endif /* !MSDOS && !ATARI && !_Windows */
+}
+#endif /* READLINE */
diff --git a/lib/libftp/utils/uftp.c b/lib/libftp/utils/uftp.c
new file mode 100644
index 0000000..49037ad0
--- /dev/null
+++ b/lib/libftp/utils/uftp.c
@@ -0,0 +1,824 @@
+/* File Transfer Protocol Toolkit based on libftp */
+
+#include "uftp.h"
+#include <varargs.h>
+
+
+FTP *ftp[NFRAMES];
+LINKINFO iftp[NFRAMES];
+int frame=0;
+
+
+int status;
+jmp_buf start;
+int lastcmd=0;
+int glassmode=0;
+int trymode=1;
+int restmode=1;
+int hashmode=0;
+int sleeptime=30;
+time_t noopinterval=0;
+time_t nooptimeout=1;
+time_t prevtime=0;
+
+String cmd;
+String prompt="%T %u@%H:%d> ";
+String defaultuser;
+
+ALIAS *firstalias=NULL;
+
+/* if main have any arguments, interprets each it as command with args */
+
+
+main(int argc, char **argv)
+
+{
+ register int i;
+ register char *p1;
+ FILE *fp;
+ String tmp;
+
+ if (setjmp(start)!=0)
+ goto main_loop;
+
+ setsignals();
+
+
+
+ FtpSetErrorHandler(&FtpInit,my_error);
+ FtpSetIOHandler(&FtpInit,my_error);
+
+ strcpy(defaultuser,getpwuid(getuid())->pw_name);
+
+
+ memset(ftp,0,sizeof(FTP*)*NFRAMES);
+ memset(iftp,0,sizeof(LINKINFO)*NFRAMES);
+
+
+
+ batch(SYSTEMRC);
+
+ if (access(getrcname(),F_OK))
+ {
+ FILE *out=fdopen(open(getrcname(),O_WRONLY|O_CREAT|O_TRUNC,0700),"w");
+
+ printf("Create default rc-file \"%s\"\n",getrcname());
+
+ if (out==NULL)
+ perror(getrcname());
+
+ else
+ {
+
+ fprintf(out,"set timeout 120\nset hash\nset debug\nset bin\n");
+ fprintf(out,"set prompt \"%%T %%u@%%h:%%d\\> \"\n");
+ fprintf(out,"alias a alias\na ed ! emacs\nalias tn ! telnet\n");
+
+ fclose(out);
+ }
+ }
+
+
+ batch(getrcname());
+ batch(getaliasrcname());
+
+
+ for (i=1, tmp[0]=0; i< argc; i++)
+ {
+ strcat(tmp,argv[i]);
+ if (i+1!=argc) strcat(tmp," ");
+ }
+
+ if (tmp[0]!=0)
+ {
+ String new;
+
+/*
+ if (!strcmp(defaultuser,"ftp") || !strcmp(defaultuser,"anonymous"))
+ strcpy(new,"ftp ");
+ else
+*/
+ strcpy(new,"open ");
+
+ if (ifalias(tmp))
+ execute (tmp);
+ else
+ strcat(new,tmp),
+ execute(new);
+ }
+
+
+main_loop:
+
+ setsignals();
+
+ while (1)
+ {
+
+ setjmp(start);
+ if (lastcmd) exit(0);
+
+
+ if (isatty(fileno(stdin)))
+ p1=readline(getprompt());
+ else
+ p1=gets(cmd);
+
+ if (p1==NULL)
+ {
+ putchar('\n');
+ exit(0);
+ }
+
+ strcpy(cmd,p1);
+
+ if (cmd[0]) add_history(cmd);
+ execute(cmd);
+ }
+}
+
+INLINE char *findspace(char *str)
+{
+ while ( !isspace(*str) && *str != '\0' ) str++;
+ return str;
+}
+
+
+
+char *word(char *str, int n)
+{
+ String new;
+ register char *p1, *p2;
+ register int i;
+
+ strcpy(new,str);
+
+ p1=new;
+
+ while (isspace(*p1)) p1++;
+
+ if (n>1 )
+ for (i=0;i<n-1;i++) /* Skip n-1 words */
+ {
+ if ((*p1=='"')||(*p1=='\''))
+ {
+ p1=strchr(p1+1,*p1);
+ if (p1==NULL) return "";
+ p1++;
+ while ( isspace(*p1) ) p1++;
+ continue;
+ }
+ p1=findspace(p1);
+ if ( *p1=='\0' ) return "";
+ p1++;
+ while ( isspace(*p1) ) p1++;
+ }
+
+ if ((*p1=='"')|(*p1=='\''))
+ {
+ p2=strchr(p1+1,*p1);
+ if (p2==NULL) return p1+1;
+ *p2=0;
+ return p1+1;
+ }
+
+ if ((p2=findspace(p1)) != NULL )
+ {
+ *p2=0;
+ return p1;
+ }
+ return "";
+}
+
+
+/* Exacute few command separated by ';' . The character ' must use for mark complex
+ works*/
+
+execute (char *cmd)
+{
+ String w1,w2,w3,w4,w5,w6;
+ String newcmd;
+ char *p;
+
+ if (!*cmd || *cmd=='#' ) return;
+
+ for ( p=newcmd ; *cmd; cmd++)
+ {
+ if ( *cmd == '\'' )
+ {
+ *p++=*cmd++;
+ while ( *cmd != '\'' && *cmd != 0 ) *p++=*cmd++;
+ if ( *cmd == 0 )
+ return puts("Unbalanced \', please corrected!\n");
+ *p++=*cmd;
+ continue;
+ }
+
+ if ( *cmd == ';' )
+ {
+ *p=0;
+ execute(newcmd);
+ p=newcmd;
+ continue;
+ }
+ *p++=*cmd;
+ }
+
+
+ *p=0;
+ cmd=newcmd;
+
+ if ( *cmd=='\\' )
+ cmd++;
+ else
+ {
+ String new;
+ strcpy(new,"\\");
+ strcat(new,expandalias(cmd));
+ return execute(new);
+ }
+
+ if ( *cmd == '!' )
+ {
+ int pid,_pid;
+ union wait status;
+
+ if (!(pid=fork()))
+ {
+ execlp((getenv("SHELL")==NULL)?"/bin/sh":(char *)getenv("SHELL"),
+ "shell","-c",cmd+1,NULL);
+ }
+
+ while(1)
+ {
+ _pid=wait(&status);
+ if (_pid==pid)
+ return;
+ }
+ }
+
+
+ redir(cmd);
+
+ if (cmd[strlen(cmd)-1]=='&')
+ {
+ String tmp;
+
+ cmd[strlen(cmd)-1]=0;
+
+ strcpy(tmp,"bg ");
+ strcat(tmp,cmd);
+
+ strcpy(cmd,tmp);
+ }
+
+ strcpy(w1,word(cmd,1));
+ strcpy(w2,word(cmd,2));
+ strcpy(w3,word(cmd,3));
+ strcpy(w4,word(cmd,4));
+ strcpy(w5,word(cmd,5));
+ strcpy(w6,word(cmd,6));
+
+ return executev(w1,w2,w3,w4,w5,w6);
+}
+
+executev(ARGS)
+{
+ CMDS *xcmd=&cmds[0];
+ String tmp;
+
+ if (isdigit(*w1))
+ return
+ atoi(w1)<NFRAMES?frame=atoi(w1):0,
+ executev(w2,w3,w4,w5,w6,"");
+
+ while ( xcmd -> cmd != NULL )
+ {
+ if ( !strcmp(xcmd->cmd,w1) && (xcmd -> func != NULL) )
+ {
+ int status;
+
+ if ( xcmd -> need && LINK == NULL)
+ return puts("Need connection to server");
+ iftp[frame].lock=1; unsetsignals();
+ status = (*xcmd->func)(w1,w2,w3,w4,w5,w6);
+ iftp[frame].lock=0; setsignals();
+ redirback();
+ return status;
+ }
+ xcmd++;
+ }
+
+
+ if (LINK!=NULL && glassmode)
+ return FtpCommand(LINK,cmd,"",0,EOF);
+
+ printf("%s: unknown command\n",w1);
+ fflush(stdout);
+ return -1;
+}
+
+
+void intr(int sig)
+{
+ printf("Interupted by signal %d\n",sig);
+ if (LINK!=NULL) FtpSetHashHandler(LINK,NULL);
+ setsignals();
+ reset_termio(); /* From readline */
+ prevtime = time((time_t *)0);
+ longjmp(start,1);
+}
+
+newframe(int connecteble)
+{
+ register int i;
+
+ if (connecteble)
+ for (i=0; i<NFRAMES; i++) if (ftp[i]!=NULL) return frame=i;
+ for (i=0; i<NFRAMES; i++) if (ftp[i]==NULL) return frame=i;
+ return -1;
+}
+
+STATUS my_error(FTP *ftp, int code, char *msg)
+{
+
+ if (code==LQUIT||(ftp==NULL)) log(msg);
+ else
+ FtpLog(ftp->title,msg);
+
+ if ( abs(code) == 530 && (strstr(msg,"anonymous")!=NULL))
+ {
+ Ftp_reopen();
+ longjmp(start,1);
+ }
+ longjmp(start,1);
+}
+
+char *getrcname()
+{
+ static String rcpath;
+ struct passwd *pwd=getpwuid(getuid());
+
+ sprintf(rcpath,"%s/.uftprc",pwd->pw_dir);
+ return rcpath;
+}
+
+char *getaliasrcname()
+{
+ static String rcpath;
+ struct passwd *pwd=getpwuid(getuid());
+
+ sprintf(rcpath,"%s/.uftp_aliases",pwd->pw_dir);
+ return rcpath;
+}
+
+char *makestr(va_alist)
+ va_dcl
+{
+ char *p1;
+ va_list args;
+ String new={0};
+
+ va_start(args);
+
+ while(1)
+ {
+ p1=va_arg(args,char *);
+ if (p1==NULL) break;
+ if (*p1!=0)
+ {
+ if (new[0]!=0) strcat(new," ");
+ strcat(new,p1);
+ }
+ }
+ va_end(args);
+ return new;
+}
+
+
+#define ADD(str,chr) (*str++=chr,*str=0)
+
+INLINE ADDSTR(char **str, char *str1)
+{
+ while (*str1) *(*str)++=*str1++;
+}
+
+char *expandalias(char *str)
+{
+ ALIAS *a=firstalias;
+ String new={0},w1={0};
+ char *p,*p1=new,*args;
+ int dollar=0;
+
+ strcpy(w1,word(str,1));
+
+ if ( (p=strchr(str,' '))!=NULL )
+ args=p+1;
+ else
+ args="";
+
+ while (a)
+ {
+ if (!strcmp(a->name,w1))
+ break;
+ a=a->next;
+ }
+
+ if (!a)
+ return str;
+
+ for ( p=a->str; *p; p++)
+ {
+ if ( *p != '$' )
+ {
+ ADD(p1,*p);
+ continue;
+ }
+
+ dollar=1;
+ p++;
+
+ if (isdigit(*p))
+ {
+ ADDSTR(&p1,word(str,(*p)-'0'+1));
+ continue;
+ }
+
+ switch (*p)
+ {
+
+ case '\0':
+ case '$': ADD(p1,'$');continue;
+ case '*': ADDSTR(&p1,args);continue;
+ default: ADD(p1,'$');ADD(p1,*p);continue;
+ }
+ }
+
+ if (!dollar)
+ {
+ ADD(p1,' ');
+ ADDSTR(&p1,args);
+ }
+
+ *p=0;
+
+ return new;
+}
+
+ifalias(char *cmd)
+{
+ String what;
+ ALIAS *a=firstalias;
+
+
+ strcpy(what,word(cmd,1));
+
+ while ( a!=NULL)
+ {
+ if (!strcmp(a->name,what))
+ return 1;
+ a=a->next;
+ }
+ return 0;
+}
+
+
+
+char *getprompt()
+{
+
+ static String _prompt;
+ String tmp;
+ char *s;
+
+ _prompt[0]=0;
+
+ for(s=prompt;*s;s++)
+ switch (*s)
+ {
+ case '%':
+ switch (*++s)
+ {
+
+ case 'H':
+ strcat(_prompt,iftp[frame].host);
+ break;
+
+ case 'h':
+ strcpy(tmp,iftp[frame].host);
+ if (strchr(tmp,'.')!=NULL) *(char *)strchr(tmp,'.')=0;
+ strcat(_prompt,tmp);
+ break;
+
+ case 'M':
+ gethostname(tmp, sizeof tmp);
+ strcat(_prompt,gethostbyname(tmp)->h_name);
+ break;
+
+ case 'm':
+ gethostname(tmp, sizeof tmp);
+ strcpy(tmp,gethostbyname(tmp)->h_name);
+ if (strchr(tmp,'.')!=NULL) *(char *)strchr(tmp,'.')=0;
+ strcat(_prompt,tmp);
+ break;
+
+ case 'u':
+ strcat(_prompt,iftp[frame].user);
+ break;
+
+ case 'd':
+ strcat(_prompt,iftp[frame].pwd);
+ break;
+
+ case 'D':
+ strcat(_prompt,(char *)getcwd(tmp,sizeof(tmp)));
+ break;
+
+ case 'f':
+ sprintf(tmp,"%d",frame);
+ strcat(_prompt,tmp);
+ break;
+
+ case 'p':
+ sprintf(tmp,"%d",(LINK==NULL)?0:LINK->port);
+ strcat(_prompt,tmp);
+ break;
+
+ case 't':
+
+ sprintf(tmp,"%d",(LINK==NULL)?0:LINK->timeout.tv_sec);
+ strcat(_prompt,tmp);
+ break;
+
+
+ case 'T':
+
+ {
+ time_t t=time((time_t *)0);
+ struct tm *lt=localtime(&t);
+ sprintf(tmp,"%02d:%02d:%02d",lt->tm_hour,
+ lt->tm_min,lt->tm_sec);
+ strcat(_prompt,tmp);
+ }
+ break;
+
+ case 'P':
+
+ sprintf(tmp,"%d",getpid());
+ strcat(_prompt,tmp);
+ break;
+
+ default:
+ sprintf(tmp,"%%%c",*s);
+ strcat(_prompt,tmp);
+ break;
+ }
+ break;
+
+ case '^':
+
+ ++s;
+ if (isalpha(*s))
+ {
+ sprintf(tmp,"%c",toupper(*s)-'A'+1);
+ strcat(_prompt,tmp);
+ }
+ break;
+
+ default:
+
+ sprintf(tmp,"%c",*s);
+ strcat(_prompt,tmp);
+ break;
+ }
+ return _prompt;
+}
+
+
+void noop()
+{
+ int i;
+ time_t curtime,save;
+ STATUS (*func1)(),(*func2)(),(*func3)();
+
+
+ if (noopinterval==0) return;
+
+ curtime = time((time_t *)0);
+
+ signal(SIGALRM,noop);
+
+ if (prevtime==0)
+ {
+ prevtime=curtime;
+ alarm(noopinterval);
+ return;
+ }
+
+ if (curtime-prevtime < noopinterval)
+ {
+ alarm(prevtime+noopinterval-curtime);
+ return;
+ }
+
+ printf("Waiting...");fflush(stdout);
+
+ for (i=0;i<NFRAMES;i++)
+ {
+ if ( ftp[i]==NULL || FTPCMD(ftp[i]) == NULL || iftp[i].lock )
+ continue;
+
+ func1=ftp[i]->debug; ftp[i]->debug=NULL;
+ func2=ftp[i]->error; ftp[i]->error=NULL;
+ func3=ftp[i]->IO; ftp[i]->IO=NULL;
+ save = ftp[i]->timeout.tv_sec;
+ ftp[i]->timeout.tv_sec = nooptimeout;
+
+ FtpCommand(ftp[i],"NOOP","",0,EOF);
+
+ ftp[i]->timeout.tv_sec = save;
+ ftp[i]->debug=func1;
+ ftp[i]->error=func1;
+ ftp[i]->IO=func1;
+
+ }
+
+ alarm(noopinterval);
+ prevtime=curtime;
+
+ for (i=0;i<10;i++) putchar(8),putchar(' '),putchar(8);
+ fflush(stdout);
+}
+
+
+setsignals()
+{
+ signal(SIGINT,intr);
+ signal(SIGQUIT,intr);
+ noop();
+}
+
+unsetsignals()
+{
+ signal(SIGALRM,SIG_IGN);
+ alarm(0);
+}
+
+
+int myhash(FTP *ftp,unsigned int chars)
+{
+
+ if (hashmode)
+ {
+ if (chars==0) return ftp -> counter=0;
+ ftp -> counter += chars;
+ fprintf(stdout,"%10u bytes transfered\r",ftp -> counter);
+ fflush(stdout);
+ }
+
+ if (!lastcmd)
+ {
+ noop();
+ alarm(0);
+ }
+}
+
+
+
+char *makefilename(char *f1, char *f2)
+{
+ char *p;
+
+ if (*f2!=0)
+ return f2;
+
+ if ( (p=strrchr(f1,'/'))!=NULL)
+ return p+1;
+ return f1;
+}
+
+redir(char *cmdline)
+{
+ char *p=cmdline;
+ String result;
+ char *r=result;
+
+ for ( ; *p ; p++ , r++ )
+ {
+ if ( *p == '\\' )
+ {
+ *r = * ++ p ;
+ continue;
+ }
+
+ if ( *p == '>' || *p == '<' )
+ {
+ String filename;
+ char *q=filename;
+ char c=*p;
+
+ for (p++;isspace(*p)&&*p!=0;p++);
+ if (*p=='"')
+ {
+ for (p++; *p!='"' && *p!=0 ; p++,q++) *q=*p;
+ if (*p!='"') p++;
+ }
+ else
+ for (; !isspace(*p) && *p!=0 ; p++,q++) *q=*p;
+
+ *q=0;
+
+ if ( c == '>' )
+ output(filename);
+ else
+ input(filename);
+ }
+ *r=*p;
+ }
+ *r=0;
+ strcpy(cmdline,result);
+}
+
+int itty=-1,otty=-1;
+FILE *is=NULL,*os=NULL;
+
+
+input(char *filename)
+{
+
+ if ((is=Ftpfopen(filename,"r"))==NULL)
+ {
+ perror(filename);
+ return;
+ }
+
+ fflush(stdin);
+ itty=dup(0);
+ close(0);
+ dup2(fileno(is),0);
+
+}
+
+output(char *filename)
+{
+
+ if ((os=Ftpfopen(filename,"w"))==NULL)
+ {
+ perror(filename);
+ return;
+ }
+
+ fflush(stdout);
+ otty=dup(1);
+ close(1);
+ dup2(fileno(os),1);
+}
+
+redirback()
+{
+
+ if (itty!=-1)
+ {
+ fflush(stdin);
+ close(0);
+ Ftpfclose(is);
+ dup2(itty,0);
+ is=NULL;
+ itty=-1;
+ }
+
+ if (otty!=-1)
+ {
+ fflush(stdout);
+ close(1);
+ Ftpfclose(os);
+ dup2(otty,1);
+ os=NULL;
+ otty=-1;
+ }
+}
+
+
+batch(char *filename)
+{
+ FILE *fp;
+ String tmp;
+
+ if ((fp=fopen(filename,"r"))!=NULL)
+ {
+
+ while ( fgets(tmp, sizeof tmp, fp) != NULL)
+ {
+ tmp[strlen(tmp)-1]=0;
+ execute(tmp);
+ if (tmp[0]) add_history(tmp);
+ }
+ fclose(fp);
+ }
+}
+
+
+
+
+
+
diff --git a/lib/libftp/utils/uftp.h b/lib/libftp/utils/uftp.h
new file mode 100644
index 0000000..3e7b3fe
--- /dev/null
+++ b/lib/libftp/utils/uftp.h
@@ -0,0 +1,83 @@
+#include <FtpLibrary.h>
+#include <strings.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/file.h>
+#include <arpa/telnet.h>
+#include <pwd.h>
+#include <errno.h>
+#include <glob.h>
+
+
+#define SYSTEMRC "/usr/share/etc/uftprc"
+#define LINK ftp[frame]
+#define NFRAMES 10
+#define TIME(proc) settimer(), status = proc , showtimer(), status
+#define ARGS char *w1,char *w2,char *w3,char *w4,char *w5,char *w6
+#define log(x) FtpLog("uftp",x)
+
+typedef struct
+{
+ String host;
+ String user;
+ String pass;
+ String pwd;
+ int lock;
+} LINKINFO;
+
+typedef struct
+{
+ char *cmd;
+ int (*func)();
+ int need;
+ char *help;
+} CMDS;
+
+typedef struct _alias
+{
+ String name,str;
+ struct _alias *next;
+} ALIAS;
+
+extern ALIAS *firstalias;
+extern FTP *ftp[NFRAMES];
+extern LINKINFO iftp[NFRAMES];
+extern int frame;
+extern int lastcmd;
+extern int glassmode;
+extern int trymode;
+extern int hashmode;
+extern int restmode;
+extern int sleeptime;
+extern time_t noopinterval,nooptimeout;
+extern CMDS cmds[];
+extern int status;
+extern String prompt;
+extern String defaultuser;
+extern jmp_buf start;
+
+char *word(char *,int);
+char *readline(char *);
+char *getpass(char *);
+char *getrcname();
+char *getaliasrcname();
+char *makestr();
+char *expandalias(char *str);
+char *getprompt();
+char *makefilename(char *,char *);
+
+void intr(int);
+void noop();
+int myhash(FTP *,unsigned int);
+STATUS my_error(FTP *, int, char *);
+
+
+
+
+
+
+
+
+
diff --git a/lib/libftp/utils/uftp.man b/lib/libftp/utils/uftp.man
new file mode 100644
index 0000000..9cf95d3
--- /dev/null
+++ b/lib/libftp/utils/uftp.man
@@ -0,0 +1,452 @@
+.TH \fBuftp\fR 1
+.SH Name
+uftp \- universal file transfer program
+.SH Syntax
+\fBuftp\fR
+.PP
+\fBuftp alias_name [args_for_alias]\fR
+.PP
+\fBuftp hostname\fR
+
+.SH Description
+
+
+The uftp is user interactive and non-interactive program to the ARPANET File Transfer Protocol (RFC959).
+The uftp allows user to transfer files, group of files in foreground and background modes. uftp runs on the client host.
+
+
+.SH Basic features
+
+
+
+Auto retrying of connection to remote node until it is succeeded.
+.PP
+Automatic reconnection with continue to transfer if the connection was broken.
+.PP
+Several sessions (frames) at once. Dynamically switching between them.
+.PP
+Setup commands, which are executed after "open" and "cd" commands. (aliases autologin & autocd )
+.PP
+Cleaning timeout on the remote server.
+.PP
+The user can setup any system parameters, like timeouts, reconnect delays, default port number,
+automatic binary mode, automatic "hash" mode and interval to clean timeouts on FTP server.
+.PP
+User can setup the prompt with the descriptions of local and remote directories, full or short site name,
+time, frame number,
+remote user's name, port number, timeout, process identification.
+.PP
+Several commands in one line.
+.PP
+Aliases with arguments, which may contain few commands separated by ';'.
+.PP
+Redirection input/output irrespective of context or/and command.
+.PP
+The local files are libftp-files, which split on local files, pipes and ftp-files. This particular file specification
+can be used in any context, including for file names of redirection input/output streams.
+.PP
+Any command may be executed in background mode, though the current frame is not droped out and user can continue
+his work.
+.PP
+Creation of alias described the current frame, and save all exist aliases to personal
+automatic startup file, which is differ from startup file. This file user can make himself.
+
+
+.SH Environment description
+
+
+
+Command line mode supports all edit key bindings. (uftp using readline library).
+Before each command user can see the prompt with description of current frame.
+If debug mode is enabled user see the protocol between uftp and ftp-daemon (ftpd).
+
+
+
+.SH Commands
+
+
+.IP \fBconnect\fR 10
+[host-name]
+
+Connect to remote site.
+
+.IP \fBopen\fR 10
+[host-name] [user-name] [password] [directory]
+
+Makes connection to remote site, sent login, password and change directory.
+If the "try" option is set an attempt to connect will be forced until success.
+
+.IP \fBftp\fR 10
+[hostname] [directory]
+
+Anonymous connection to ftp-site.
+
+.IP \fBreopen\fR 10
+
+Reopen broken frame.
+
+.IP \fBclose\fR 10
+
+Close the current connection.
+
+.IP \fBquit\fR 10
+
+Quit from uftp (You can press Contol-D)
+
+.IP \fBlist\fR 10
+
+Description list of all frames.
+
+.IP \fBuser\fR 10
+[user-name] [password]
+
+Send user's name to site, automatically require password if needed.
+
+.IP \fBpass\fR 10
+[password]
+
+Specify user's password.
+
+.IP \fBbin\fR 10
+
+Set binary transfer mode.
+
+.IP \fBascii\fR 10
+
+Set ASCII transfer mode.
+
+.IP \fBcd\fR 10
+directory_name
+
+Change the current directory on remote site.
+
+.IP \fBacd\fR 10
+[directory_name]
+
+Archie searching by specified pattern with subsequent connection to desired point.
+Maximum number of possible points is 20.
+Afterwards user can select any point. If user don't specify "directory_name",
+last search buffer is displayed for selection, if this buffer is not empty.
+
+.IP \fBlcd\fR 10
+directory_name
+
+Local change directory. User can use metacharacters.
+
+.IP \fBabort\fR 10
+
+Abort execute of last procedure with server.
+
+Warning: this procedure sometimes is not correctly working.
+
+.IP \fBmkdir\fR 10
+directory_name
+
+Create new directory on the server.
+
+.IP \fBrm\fR 10
+filename_or_pattern
+
+Remove specified file(s) on the server.
+
+.IP \fBmv\fR 10
+old_filename new_filename
+
+Move file on the server.
+
+.IP \fBdir\fR 10
+[keys] [filename_spec] ....
+
+Make long list of specified file(s) with date, size, etc...
+
+.IP \fBls\fR 10
+[keys] [filename_spec] ....
+
+Make short list of specified file(s).
+
+.IP \fBget\fR 10
+remote_filename [local_filename_or_directory]
+
+Receive the file from the server to local file system (only one file!).
+If option "rest" is turn on then transfer starts from the end of local file.
+
+.IP \fBmget\fR 10
+[remote_filename] [local_directory]
+
+Receive many files from the server to local file system.
+
+.IP \fBreget\fR 10
+remote_filename [local_filename_or_directory].
+
+The same as get, but the option "rest" is ignored.
+
+.IP \fBaget\fR 10
+[pattern_for_archie]
+
+Getting the file, which need to find via archie service. See also "acd" description.
+
+.IP \fBbget\fR 10
+[libftp_file] [local_file]
+
+Get file specified as libftp-file. See libftp file specification. Operation
+proceedes until success.
+
+.IP \fBput\fR 10
+local_filename [remote_filename]
+
+Put one file to server.
+
+.IP \fBmput\fR 10
+local_filename(s)
+
+Put specified file(s) to server.
+
+.IP \fBreput\fR 10
+The same as put, but the option "rest" is ignored.
+
+.IP \fBbput\fR 10
+[[local_file] libftp_file]
+
+Put file specified as libftp-file. See libftp file specification. Operation
+proceedes until success.
+
+.IP \fBcopy\fR 10
+[frame/]filename [frame/]filename
+
+Copy one file from first frame to second. If the frame number is not specified
+then use current frame number. Transfer operation executes via libftp cache.
+
+
+.IP \fBccopy\fR 10
+[frame/]filename [frame/]filename
+
+Copy one file from first frame to second. If the frame number is not specified
+then used current frame number. Transfer operation executes via leased line
+between two servers cache.
+
+
+.IP \fBcat\fR 10
+filename
+
+Display context of specified file on screen.
+
+.IP \fBpage\fR 10
+
+The same as cat, but with using of pager. Name of pager specified in environment variable
+PAGER or "more" by default.
+
+.IP \fBbg\fR 10
+any_command
+
+any_command &
+
+Run any command in background mode. Default output is redirected to
+/tmp/uftp-<user_name>.XXXXXX file.
+
+.IP \fBarchie\fR 10
+[pattern]
+
+Archie search. In case if argument are omitted, reprint last search.
+
+.IP \fBdup\fR 10
+
+Create new frame as current.
+
+.IP \fBquote\fR 10
+
+Send raw command to server. If option "glassmode" is set then all non-recognized
+commands send to server as raw also.
+
+.IP \fBhelp\fR 10
+[command]
+
+Print brief help or help for specified command.
+
+.IP \fBalias\fR 10
+alias_name alias_string
+
+Makes new alias, if the alias string uftp contains string like $1, $2, $* then
+it will be replaced by argument to alias. If this sequences in alias is not found, then
+all existing alias's arguments will append to end of alias call string. User can insert to alias
+string like \\\> \\\< for future redirect input/output. Quotes ' and " can be used
+also.
+
+.IP \fBunalias\fR 10
+alias_name
+
+Remove specified alias.
+
+.IP \fBmkalias\fR 10
+alias_name
+
+Makes new alias, which user can use in future for login to this point again.
+See also "savealias"
+
+.IP \fBsavealias\fR 10
+
+Save all aliases in startup file.
+
+
+.SH Libftp file specification
+
+All local files interpret as libftp's files. Libftp responds to three types of files such
+ as local file, ftp files and program
+pipes. All files can be described as next syntax:
+
+ |string - interprets string as shell command, which must be \
+ executed with appropriate input/output for file. It depends where
+ this file is specified.
+
+ hostname:filename - interprets as file, which must be taken
+ using ftp protocol with anonymous access
+
+ user@hostname:filename - interprets as file accesses via ftp
+ with password yourname@your_host.your_domain
+
+ user/pass@hostname:filename - also ftp file.
+
+ *STDIN*, *STDOUT*, *STDERR* or char '-' - opened streams.
+
+ anything - local file name.
+
+.SH String syntax
+
+The strings starting from char '!' interpret as shell command.
+The strings or aliases containing one or few char ';' will be executed as a chain commands.
+The chains of characters between " or ' interpret as one set without syntax resolving.
+In any command string user can redirect input or/and output
+using char > and < . For the complex file name it must quoted by ' or ".
+
+Examples:
+
+ dir >filename
+
+ cat filename >'|mail -s "my files" fiend@hostname.domain'
+
+ dir -R etc bin >"|gzip >result.gz"
+
+ cat filename > user/password@hostname:/dir/filename.ext
+
+ put - < "|finger @hostname" newfile.finger
+
+
+.SH Options (command set)
+
+.IP \fBset\fR
+
+
+Show all current settings.
+
+.IP \fBset\fR
+frame <frame_number>
+
+Switch to another frame. You can also switch by insert on frame number to the
+begin of command line.
+
+.IP \fBset\fR
+timeout <seconds>
+
+Set timeout for send/receive operations.
+
+.IP \fBset\fR
+noop <secs>
+
+Set interval for send NOOP command to each connected server for cleaning
+timeouts.
+
+.IP \fBset\fR
+nooptimeout <seconds>
+
+Set timeout for NOOP operation.
+
+.IP \fBset\fR
+sleep <secs>
+
+Set pause interval between transfer attempts.
+
+.IP \fBset\fR
+debug <y|n>
+
+Enable or disable protocol debug output
+
+.IP \fBset\fR
+try <y|n>
+
+Enable or disable retrys after lost peer.
+
+.IP \fBset\fR
+hash <y|n>
+
+Enable or disable trace for the transfer operations.
+
+.IP \fBset\fR
+restore <y|n>
+
+Enable or disable default transfer starting from end of file.
+
+.IP \fBset\fR
+bin <y|n>
+
+Automatic binary mode.
+
+.IP \fBset\fR
+glass <y|n>
+
+This command only to debug the protocol. After glassmode it is enable
+to send raw to server of all unresponded commands.
+
+.IP \fBset\fR
+prompt <prompt_string>
+
+Set the prompt. Prompt is a string, which may contain %<char>
+or ^<char> combitanions with the next embodies:
+
+ %H, %h - full and short remote host names
+ %M, %m - full and short local host names
+ %u - remote user's name
+ %d - remote current directory
+ %D - local current directory
+ %f - number of current frame
+ %p - the ftp's port number
+ %t - timeout
+ %T - current time
+ %P - uftp process id
+ %% - character %
+ ^<char>- control character
+ %^ - character ^
+
+
+.IP \fBset\fR
+port <number>
+
+Set default FTP's port for next sessions.
+
+.IP \fBset\fR
+user <user_name>
+
+Set default user's name.
+
+.SH Startup file
+
+User can modify his startup file created automatically. This file may
+contain some uftp's commands separated by new-line. The name of this file is ~/.uftprc.
+The file ~/.uftp_aliases is created automatically by uftp's command "savealias",
+so it is not needed to edit handly.
+
+.SH Author of uftp and libftp
+
+ Oleg Orel
+
+ Department of Electronics and automatisation.
+
+ Institute for High Energy Physics
+
+ Protvino, Russia
+
+ E-mail: orel@oea.ihep.su, orel@dxcern.cern.ch
+
+
+
+.SH See also
+
+ \fBncftp\fR (1), \fBftp\fR (1), \fBftpd\fR (8)
diff --git a/lib/libftp/utils/uftpcmd.c b/lib/libftp/utils/uftpcmd.c
new file mode 100644
index 0000000..959de40
--- /dev/null
+++ b/lib/libftp/utils/uftpcmd.c
@@ -0,0 +1,1202 @@
+#include "uftp.h"
+
+String tmp;
+
+jmp_buf connectstack;
+
+
+
+Ftp_connect_hook(FTP *ftp,int code, char *msg)
+{
+ FtpLog(ftp->title,msg);
+ longjmp(connectstack,1);
+
+}
+
+
+Ftp_connect(ARGS)
+{
+ STATUS (*func1)(),(*func2)();
+
+ if (*w2==0) w2=readline("Host:");
+
+ if (FtpGetHost(w2)==NULL && FtpInit.IO != NULL)
+ {
+ char *msg;
+ extern int h_errno;
+
+ switch(h_errno)
+ {
+ case HOST_NOT_FOUND: msg = "Host unknown"; break;
+ case TRY_AGAIN: msg = "Hostname lookup failure";break;
+ default: msg = "gethostbyname failure";
+ }
+ return (*FtpInit.IO)(LINK,QUIT,msg);
+ }
+
+ newframe(0);
+
+ func1 = FtpInit.error;
+ func2 = FtpInit.IO;
+
+ if (trymode)
+ {
+ FtpSetErrorHandler(&FtpInit,Ftp_connect_hook);
+ FtpSetIOHandler(&FtpInit,Ftp_connect_hook);
+ setjmp(connectstack);
+ }
+
+ FtpConnect(&LINK,w2);
+ strcpy(iftp[frame].host,FtpGetHost(w2)->h_name);
+
+ FtpSetErrorHandler(LINK,func1);
+ FtpSetErrorHandler(&FtpInit,func1);
+ FtpSetIOHandler(LINK,func2);
+ FtpSetIOHandler(&FtpInit,func2);
+
+ return;
+}
+
+Ftp_user(ARGS)
+{
+
+ if (*w2==0)
+ {
+ sprintf(tmp,"login (default %s):",defaultuser);
+ w2=readline(tmp);
+ if (*w2==0)
+ w2=defaultuser;
+ }
+ strcpy(iftp[frame].user,w2);
+ strcpy(iftp[frame].pass,w3);
+ if (FtpUser(LINK,w2)==331) Ftp_pass("",w3,"","","","");
+}
+
+Ftp_pass(ARGS)
+{
+ if (*w2==0)
+ {
+ String pass;
+ String host;
+
+ gethostname(host, sizeof host);
+ strcpy(host,FtpGetHost(host)->h_name);
+ sprintf(pass,"%s@%s",getpwuid(getuid())->pw_name,host);
+ sprintf(tmp,"Password (default %s):",pass);
+ w2=getpass(tmp);
+ if (*w2==0) w2=pass;
+ }
+
+ strcpy(iftp[frame].pass,w2);
+ FtpPassword(LINK,w2);
+ strcpy(iftp[frame].pwd,FtpPwd(LINK));
+}
+
+Ftp_open(ARGS)
+{
+ register char *p1;
+ STATUS (*err)();
+
+ Ftp_connect("",w2,"","","","");
+ Ftp_user("",w3,w4,"","","" );
+ if (ifalias("autologin")) execute("autologin");
+ if (*w5)
+ Ftp_cd("cd",w5,"","","","");
+}
+
+Ftp_reopen(ARGS)
+{
+ String host,user,pass,pwd;
+
+ strcpy(host,iftp[frame].host);
+ strcpy(user,iftp[frame].user);
+ strcpy(pass,iftp[frame].pass);
+ strcpy(pwd,iftp[frame].pwd);
+
+ Ftp_close("","","","","","");
+ Ftp_open("",host,user,pass,pwd,"");
+}
+
+Ftp_ftp(ARGS)
+{
+ String pass;
+ String host;
+
+ gethostname(host, sizeof host);
+ strcpy(host,FtpGetHost(host)->h_name);
+ sprintf(pass,"%s@%s",getpwuid(getuid())->pw_name,host);
+
+ Ftp_open("",w2,"anonymous",pass,w3,"");
+ return;
+}
+
+Ftp_quit(ARGS)
+{
+ exit(0);
+}
+
+Ftp_mput_handler()
+{
+ log("File(s) or directory not found");
+ longjmp(start,1);
+}
+
+
+Ftp_lcd(ARGS)
+{
+ glob_t gl;
+
+ bzero(&gl,sizeof gl);
+
+ glob(w2,GLOB_BRACE|GLOB_TILDE|GLOB_QUOTE,
+ Ftp_mput_handler, &gl);
+
+
+ if (gl.gl_matchc<1 || chdir(*gl.gl_pathv))
+ perror(w2);
+
+ printf("Local directory is \"%s\"\n",getwd(tmp));
+}
+
+Ftp_dir(ARGS)
+{
+ char *cmd1;
+ String cmd;
+ char mode=LINK->mode;
+
+ if ( !strcmp(w1,"dir") )
+ cmd1="LIST";
+ else
+ cmd1="NLST";
+
+ strcpy(cmd,makestr(cmd1,w2,w3,w4,w5,w6,NULL));
+
+ if ( LINK->mode != 'A' ) FtpAscii(LINK);
+ FtpRetr(LINK,cmd,"","-");
+ if ( LINK->mode != mode ) FtpType(LINK,mode);
+
+}
+
+Ftp_close(ARGS)
+{
+ register int i;
+
+ if (isdigit(*w2))
+ {
+ i=atoi(w2);
+ }
+ else
+ {
+ i=frame;
+ }
+
+ FtpQuickBye(ftp[i]);
+
+ iftp[i].host[0]=0;
+ iftp[i].pwd[0]=0;
+ ftp[i]=NULL;
+ newframe(1);
+}
+
+
+INLINE SetLogicalVar(char arg, int * var, char *msg)
+{
+ switch(arg)
+ {
+
+ case 'y':
+
+ *var=1;
+ break;
+
+ case 'n':
+
+ *var=0;
+ break;
+
+ default:
+
+ (*var)?(*var=0):(*var=1);
+ break;
+ }
+ return printf("%s %s\n",msg,(*var)?"enable":"disable");
+}
+
+
+Ftp_set(ARGS)
+{
+ if (!strcmp("frame",w2))
+ return atoi(w3)<NFRAMES?frame=atoi(w3):0;
+
+ if (!strcmp("timeout",w2))
+ {
+ FtpSetTimeout(&FtpInit,atoi(w3));
+ if (LINK!=0)
+ FtpSetTimeout(LINK,atoi(w3));
+ return;
+ }
+
+ if (!strcmp("sleep",w2))
+ {
+ sleeptime=atoi(w3);
+ return;
+ }
+
+ if (!strcmp("debug",w2))
+ {
+ if ( *w3=='y' || *w3==0)
+ {
+ if (LINK!=NULL) FtpSetDebugHandler(LINK,FtpDebugDebug);
+ FtpSetDebugHandler(&FtpInit,FtpDebugDebug);
+ return puts("Debuging on for current and next session");
+ }
+ if ( *w3 == 'n')
+ {
+ if (LINK!=NULL) FtpSetDebugHandler(LINK,NULL);
+ FtpSetDebugHandler(&FtpInit,NULL);
+ return puts("Debuging off for current and next session");
+ }
+ }
+
+ if (!strcmp("bin",w2))
+ {
+ if ( *w3=='y' || *w3==0)
+ {
+ FtpInit.mode='I';
+ return puts("Binary mode enable");
+ }
+ if ( *w3 == 'n')
+ {
+ FtpInit.mode='A';
+ return puts("Binary mode disable");
+ }
+ }
+
+ if (!strcmp("try",w2))
+ return SetLogicalVar(*w3,&trymode,"Try mode");
+ if (!strcmp("hash",w2))
+ return SetLogicalVar(*w3,&hashmode,"Hash mode");
+ if (!strcmp("glass",w2))
+ return SetLogicalVar(*w3,&glassmode,"Glass mode");
+ if (!strcmp("rest",w2)||!strcmp(w2,"restore"))
+ return SetLogicalVar(*w3,&restmode,"Restore mode");
+
+ if (!strcmp("prompt",w2))
+ {
+ strcpy(prompt,w3);
+ return;
+ }
+
+ if (!strcmp("port",w2))
+ {
+ if ( isdigit(*w3))
+ return FtpSetPort(&FtpInit,atoi(w3));
+ puts("Port must be number");
+ fflush(stdout);
+ return;
+ }
+
+ if (!strcmp("noopinterval",w2)||!strcmp("noop",w2))
+ {
+ if ( isdigit(*w3))
+ return noopinterval=(time_t)atoi(w3);
+ puts("Time must be number");
+ fflush(stdout);
+ return;
+ }
+
+ if (!strcmp("nooptimeout",w2))
+ {
+ if ( isdigit(*w3))
+ return nooptimeout=(time_t)atoi(w3);
+ puts("Time must be number");
+ fflush(stdout);
+ return;
+ }
+
+
+
+ if (!strcmp("user",w2)||!strcmp("login",w2))
+ {
+ strcpy(defaultuser,w3);
+ return;
+ }
+
+ if (!strcmp("",w2))
+ {
+
+ printf("frime %d\n",frame);
+ printf("timeout %d secs\n",FtpInit.timeout.tv_sec);
+ printf("sleep time %d secs\n",sleeptime);
+ printf("debug %s\n",(FtpInit.debug!=NULL)?"enable":"disable");
+ printf("glass mode %s\n",glassmode?"enable":"disable");
+ printf("try mode %s\n",trymode?"enable":"disable");
+ printf("hash mode %s\n",hashmode?"enable":"disable");
+ printf("restore mode %s\n",restmode?"enable":"disable");
+ printf("automatic binary mode %s\n",(FtpInit.mode=='I')?"enable":"disable");
+ printf("prompt \"%s\"\n",prompt);
+ printf("port %d\n",FtpInit.port);
+ printf("noop interval %d\n",noopinterval);
+ printf("noop timeout %d\n",nooptimeout);
+ printf("Default login name \"%s\"\n",defaultuser);
+ fflush(stdout);
+ return;
+ }
+ return puts("arg 2 unknown");
+
+}
+
+jmp_buf getstack;
+
+Ftp_get_hook(FTP *con,int code, char *msg)
+{
+
+ if ( abs(code)==550 && FtpBadReply550(msg) )
+ {
+ FtpLog(con->title,msg);
+ log("Transfer cancel");
+ longjmp(getstack,2);
+ }
+
+ if ( code == LQUIT )
+ {
+ log(msg);
+ log("Transfer leave after I/O error with local file");
+ longjmp(getstack,2);
+ }
+
+
+
+ FtpLog(con->title,msg);
+ FtpQuickBye(LINK);
+ LINK=NULL;
+
+ log("sleeping......");
+ sleep(sleeptime);
+ log("try again...");
+
+ longjmp(getstack,1);
+
+}
+
+void Ftp_get_intr(int sig)
+{
+ signal(SIGINT,intr);
+ log("Transfer interupt");
+ Ftp_abort();
+ longjmp(getstack,3);
+}
+
+Ftp_get(ARGS)
+{
+ FTP OldInit;
+ int back=0;
+ int code;
+ int status=0;
+
+ OldInit=FtpInit;
+
+ if (strstr(w1,"put")!=NULL) back=1;
+
+
+ if (restmode || ((*w1=='r')&&(*(w1+1)=='e')) )
+ FtpSetFlag(LINK,FTP_REST);
+ else
+ FtpClearFlag(LINK,FTP_REST);
+
+
+
+ if (trymode)
+ {
+ FtpSetErrorHandler(LINK,Ftp_get_hook);
+ FtpSetIOHandler(LINK,Ftp_get_hook);
+ FtpInit=*LINK;
+ FTPCMD(&FtpInit)=FTPCMD(&OldInit);
+ FTPDATA(&FtpInit)=FTPDATA(&OldInit);
+ }
+
+ signal(SIGINT,Ftp_get_intr);
+ FtpSetHashHandler(LINK,NULL);
+
+
+ if ((status=setjmp(getstack))==2||status==3)
+ goto done;
+
+ if ((LINK==NULL)||(LINK->sock==FtpInit.sock))
+ {
+ FtpLogin(&LINK,iftp[frame].host,iftp[frame].user,
+ iftp[frame].pass,NULL);
+ FtpChdir(LINK,iftp[frame].pwd);
+ }
+
+ if (hashmode && isatty(fileno(stdout)))
+ FtpSetHashHandler(LINK,myhash);
+ else
+ FtpSetHashHandler(LINK,NULL);
+
+ myhash(LINK,0);
+
+ if (!back)
+ FtpGet(LINK,w2,makefilename(w2,w3));
+ else
+ FtpPut(LINK,w2,makefilename(w2,w3));
+
+
+ log("Transfer compliete");
+
+
+done:
+
+
+ FtpSetHashHandler(LINK,NULL);
+ FtpSetErrorHandler(LINK,my_error);
+ FtpSetIOHandler(LINK,my_error);
+ FtpClearFlag(LINK,FTP_REST);
+ FtpInit=OldInit;
+}
+
+Ftp_mget(ARGS)
+{
+ FILE *list;
+ char mode=LINK->mode;
+
+ sprintf(tmp,"/tmp/uftplist-%s.XXXXXX",getpwuid(getuid())->pw_name);
+ mktemp(tmp);
+
+ if ( LINK->mode != 'A' ) FtpAscii(LINK);
+
+ if (*w2==0)
+ FtpRetr(LINK,"NLST","",tmp);
+ else
+ FtpRetr(LINK,"NLST %s",w2,tmp);
+
+ if ( LINK->mode != mode ) FtpType(LINK,mode);
+
+ if ((list=fopen(tmp,"r"))==NULL)
+ return FtpLog(tmp,sys_errlist[errno]);
+
+ while ( fgets(tmp,sizeof tmp,list)!=NULL)
+ {
+ tmp[strlen(tmp)-1]=0;
+ Ftp_get("get",tmp,w3,"","","");
+ }
+
+ fclose(list);
+}
+
+Ftp_mput(ARGS)
+{
+ glob_t gl;
+
+ glob(w2,GLOB_BRACE|GLOB_TILDE|GLOB_QUOTE,
+ Ftp_mput_handler, &gl);
+
+ while(gl.gl_matchc--)
+ {
+ Ftp_get("put",*gl.gl_pathv,"","","","");
+ gl.gl_pathv++;
+ }
+}
+
+
+Ftp_bget(ARGS)
+{
+
+ String fn,lfn;
+ char *p;
+
+ newframe(0);
+
+ if (!FtpFullSyntax(w2,iftp[frame].host,iftp[frame].user,
+ iftp[frame].pass,fn))
+ return puts("Filename syntax error");
+
+ strcpy(iftp[frame].pwd,"/");
+
+ if ((p=strrchr(fn,'/'))!=NULL)
+ strcpy(lfn,p+1);
+ else
+ strcpy(lfn,fn);
+
+ FtpQuickBye(LINK);
+ LINK=FtpCreateObject();
+ LINK->sock=NULL;
+
+ Ftp_get("get",fn,(*w3==0)?lfn:w3,"","","");
+}
+
+Ftp_bput(ARGS)
+{
+
+ String fn,lfn;
+ char *p;
+
+ if (!FtpFullSyntax((*w3==0)?w2:w3,iftp[frame].host,iftp[frame].user,
+ iftp[frame].pass,fn))
+ return puts("Filename syntax error");
+
+ strcpy(iftp[frame].pwd,"/");
+
+ if ((p=strrchr(fn,'/'))!=NULL)
+ strcpy(lfn,p+1);
+ else
+ strcpy(lfn,fn);
+
+ FtpQuickBye(LINK);
+ LINK=FtpCreateObject();
+ LINK->sock=NULL;
+
+ Ftp_get("put",(*w3==0)?lfn:w2,fn,"","","");
+}
+
+Ftp_copy(ARGS)
+{
+ char *p;
+ int in,out;
+
+ if ( !*w2 || !*w3 ) return puts("Must pass two args");
+
+ if ((p=strchr(w2,'!'))!=NULL)
+ {
+ *p=0;
+ in=atoi(w2);
+ w2=p+1;
+ }
+ else
+ in=frame;
+
+ if ((p=strchr(w3,'!'))!=NULL)
+ {
+ *p=0;
+ out=atoi(w3);
+ w3=p+1;
+ }
+ else
+ in=frame;
+
+ if (in==out) return puts("Files must been from different frames");
+
+ FtpCopy(ftp[in],ftp[out],w2,w3);
+}
+
+Ftp_ccopy(ARGS)
+{
+ char *p;
+ int in,out;
+
+ if ( !*w2 || !*w3 ) return puts("Must pass two args");
+
+ if ((p=strchr(w2,'!'))!=NULL)
+ {
+ *p=0;
+ in=atoi(w2);
+ w2=p+1;
+ }
+ else
+ in=frame;
+
+ if ((p=strchr(w3,'!'))!=NULL)
+ {
+ *p=0;
+ out=atoi(w3);
+ w3=p+1;
+ }
+ else
+ in=frame;
+
+ if (in==out) return puts("Files must been from different frames");
+
+ FtpPassiveTransfer(ftp[in],ftp[out],w2,w3);
+}
+
+Ftp_bin(ARGS)
+{
+ FtpBinary(LINK);
+}
+
+Ftp_ascii(ARGS)
+{
+ FtpAscii(LINK);
+}
+
+Ftp_cd(ARGS)
+{
+ FtpChdir(LINK,w2);
+ strcpy(iftp[frame].pwd,FtpPwd(LINK));
+ if (ifalias("autocd")) execute("autocd");
+}
+
+
+Ftp_dup(ARGS)
+{
+ LINKINFO oldinfo;
+ FTP oldftp;
+
+ oldinfo=iftp[frame];
+ oldftp=*LINK;
+
+ newframe(0);
+ puts("Make alternative connection...");
+ Ftp_open("",oldinfo.host,oldinfo.user,oldinfo.pass,"","");
+ if (strcmp(oldinfo.pwd,iftp[frame].pwd))
+ Ftp_cd("",oldinfo.pwd,"","","","");
+ if (LINK->mode!=oldftp.mode)
+ FtpType(LINK,oldftp.mode);
+ LINK -> timeout = oldftp.timeout;
+ LINK -> flags = oldftp.flags;
+ FtpSetDebugHandler(LINK,oldftp.debug);
+ FtpSetErrorHandler(LINK,oldftp.error);
+ FtpSetIOHandler(LINK,oldftp.IO);
+ FtpSetHashHandler(LINK,oldftp.hash);
+}
+
+
+
+Ftp_bg(ARGS)
+{
+ if (fork())
+ {
+
+ log("Backgrounding...");
+ return;
+ }
+ else
+ {
+ int i=frame;
+
+ lastcmd=1;
+
+ /* Ignoring keypad */
+
+ alarm (0);
+ signal(SIGALRM,SIG_IGN);
+ signal(SIGURG,SIG_IGN);
+ signal(SIGPIPE,SIG_IGN);
+ signal(SIGTSTP,SIG_IGN);
+ signal(SIGINT,SIG_IGN);
+ signal(SIGQUIT,SIG_IGN);
+ signal(SIGCHLD,SIG_IGN);
+ signal(SIGIO,SIG_IGN);
+
+ /* Droping output */
+
+
+ sprintf(tmp,"/tmp/uftp-%s.XXXXXX",getpwuid(getuid())->pw_name);
+ mktemp(tmp);
+ close(0);close(1);close(2);
+ open(tmp,O_RDWR|O_TRUNC|O_CREAT,0600);
+ dup(0);dup(0);
+
+ if (LINK!=NULL)
+ {
+ Ftp_dup("","","","","","");
+ free(ftp[i]);
+ ftp[i]=NULL;
+ }
+
+ return executev(w2,w3,w4,w5,w6,"");
+ }
+}
+
+
+Ftp_list()
+{
+ register int i;
+
+#define _FMT "%-5s %-15s %-10s %-25s %-7s %-4s\n"
+#define FMT "%-5d %-15s %-10s %-25s %-7d %-4d\n"
+
+ printf(_FMT,"Frame","Host name","User's name","Working directory","Timeout","Port");
+
+ for ( i = 0 ; i < NFRAMES ; i++ )
+ if (ftp[i]!=NULL)
+ printf(FMT,i,iftp[i].host,iftp[i].user,iftp[i].pwd,
+ ftp[i]->timeout.tv_sec,ftp[i]->port);
+ fflush(stdout);
+ return;
+}
+
+Ftp_abort(ARGS)
+{
+ time_t save;
+
+ if (LINK!=NULL)
+ {
+ save = LINK ->timeout.tv_sec;
+ LINK->timeout.tv_sec = nooptimeout;
+ FtpAbort(LINK);
+ LINK->timeout.tv_sec = save;
+ }
+}
+
+Ftp_type(ARGS)
+{
+ FtpGet(LINK,w2,"*STDOUT*");
+}
+
+
+Ftp_page(ARGS)
+{
+ register char *pager;
+ String out={'|',0};
+
+ if ((pager=(char *)getenv("PAGER"))==NULL)
+ pager="more";
+
+ strcat(out,pager);
+ FtpGet(LINK,w2,out);
+}
+
+
+Ftp_mkdir(ARGS)
+{
+ FtpMkdir(LINK,w2);
+}
+
+Ftp_rm(ARGS)
+{
+ FILE *list;
+
+ sprintf(tmp,"/tmp/uftplist-%s.XXXXXX",getpwuid(getuid())->pw_name);
+ mktemp(tmp);
+
+ if (*w2==0)
+ {
+ log("Filename specification must present");
+ return;
+ }
+
+ FtpRetr(LINK,"NLST %s",w2,tmp);
+
+ if ((list=fopen(tmp,"r"))==NULL)
+ return FtpLog(tmp,sys_errlist[errno]);
+
+ while ( fgets(tmp,sizeof tmp,list)!=NULL)
+ {
+ tmp[strlen(tmp)-1]=0;
+ FtpCommand(LINK,"DELE %s",tmp,0,EOF);
+ }
+
+ fclose(list);
+}
+
+
+
+
+Ftp_move(ARGS)
+{
+ FtpMove(LINK,w2,w3);
+}
+
+Ftp_help(ARGS)
+{
+ register int i,ii;
+
+ if ( !*w2 )
+ {
+ puts("Warrning!!!! \nPlease read general information using command \"help etc\"\n\n");
+
+ for ( i = 0 ;1; i++)
+ {
+ for ( ii = 0 ; ii < 5 ; ii++)
+ {
+ if (cmds[ii+i*5].cmd==NULL) return putchar('\n');
+ printf("%-16s",cmds[ii+i*5].cmd);
+ }
+ putchar ('\n');
+ }
+ }
+
+
+ for ( i = 0 ; 1; i++)
+ {
+
+ if (cmds[i].cmd==NULL) return puts("Command not found");
+ if (!strcmp(cmds[i].cmd,w2))
+ break;
+ }
+
+ puts(cmds[i].help);
+
+}
+
+Ftp_quote(ARGS)
+{
+ String new;
+
+ new[0]=0;
+
+ if (*w2!=0) strcpy(new,w2);
+ if (*w3!=0) strcat(new," "),strcat(new,w3);
+ if (*w4!=0) strcat(new," "),strcat(new,w4);
+ if (*w5!=0) strcat(new," "),strcat(new,w5);
+ if (*w6!=0) strcat(new," "),strcat(new,w6);
+
+ FtpCommand(LINK,new,"",0,EOF);
+}
+
+Ftp_alias(ARGS)
+{
+ ALIAS *a=firstalias;
+
+
+ if ( *w2==0 )
+ {
+ while (a!=NULL)
+ {
+ printf("%s=%s\n",a->name,a->str);
+ a=a->next;
+ }
+ return;
+ }
+
+
+ while (1)
+ {
+
+ if ( a == NULL )
+ {
+ firstalias = a = (ALIAS *) malloc(sizeof(ALIAS));
+ memset(a,0,sizeof(ALIAS));
+ a -> next = NULL;
+ break;
+ }
+
+ if (!strcmp(a->name,w2))
+ break;
+
+ if ( a->next == NULL)
+ {
+ a -> next = (ALIAS *) malloc(sizeof(ALIAS));
+ a = a->next;
+ memset(a,0,sizeof(ALIAS));
+ a -> next = NULL;
+ break;
+ }
+ a=a->next;
+ }
+
+ strcpy(a -> name,w2);
+ strcpy(a -> str,makestr(w3,w4,w5,w6,NULL));
+}
+
+Ftp_mkalias(ARGS)
+{
+ String new;
+
+ if (!*w2) return puts("Arg must present\n");
+
+ sprintf(new,"open \"%s\" \"%s\" \"%s\" \"%s\"",
+ iftp[frame].host,iftp[frame].user,
+ iftp[frame].pass,iftp[frame].pwd);
+
+ Ftp_alias("alias",w2,new,"","","");
+}
+
+Ftp_unalias(ARGS)
+{
+ ALIAS *cur,*prev;
+
+ cur=prev=firstalias;
+
+ while ( cur != NULL )
+ {
+ if (!strcmp(cur->name,w2))
+ {
+ if ( cur == firstalias )
+ {
+ firstalias = cur->next;
+ free(cur);
+ return;
+ }
+ prev -> next = cur -> next;
+ free(cur);
+ }
+ prev=cur;
+ cur=cur->next;
+ }
+}
+
+
+Ftp_save(ARGS)
+{
+ ALIAS *a=firstalias;
+ String fn;
+ FILE *out;
+
+ if ((out=fopen (getaliasrcname(),"w"))==NULL)
+ {
+ perror(getaliasrcname());
+ return;
+ }
+
+ while (a!=NULL)
+ {
+ fprintf(out,"alias %s '%s'\n",a->name,a->str);
+ a=a->next;
+ }
+ fclose(out);
+ chmod ( getaliasrcname(), 0600);
+ puts("Aliases saved");
+}
+
+#define ARCHIE_MAX_TARGETS 20
+
+Ftp_acd(ARGS)
+{
+ static int targets=0;
+ static String what={0};
+ static ARCHIE result[ARCHIE_MAX_TARGETS];
+
+ int i, selected_target;
+ String tmp;
+ char *p;
+
+
+ if ( (what[0] == 0 || strcmp(w2,what) != 0) && *w2!=0 )
+ {
+ if ((targets=FtpArchie(w2,result,ARCHIE_MAX_TARGETS))<1)
+ return puts("Archie failure or target not found");
+ strcpy(what,w2);
+ }
+
+ for (i=0;i<targets;i++)
+ printf("%2d %s:%s\n",i,result[i].host,result[i].file);
+
+ if (strcmp(w1,"archie")==0)
+ return;
+
+
+ p = readline("Your selection? ");
+ if (p==NULL) return;
+
+ selected_target = atoi(p);
+
+ if ( result[selected_target].file[strlen(result[selected_target].file)-1]
+ == '/' )
+ {
+ Ftp_ftp("ftp",result[selected_target].host,result[selected_target].file,
+ "","","");
+ return;
+ }
+ else
+ {
+ sprintf(tmp,"%s:%s",
+ result[selected_target].host,result[selected_target].file);
+ Ftp_bget("bget",tmp,"","","","");
+ }
+}
+
+
+CMDS cmds[]={
+
+ "connect", Ftp_connect, 0,
+ "connect <hostname> - make new ftp connection",
+
+ "open", Ftp_open, 0,
+ "open <hostname> <user> <pass> <directory> - login to server",
+
+ "reopen", Ftp_reopen, 1,
+ "Open again connection with existing frame information",
+
+ "ftp", Ftp_ftp, 0,
+ "ftp <hostname> - anonymously login to server",
+
+ "close", Ftp_close, 1,
+ "Close connection",
+
+ "quit", Ftp_quit, 0,
+ "Exit from uftp",
+
+ "set", Ftp_set, 0,
+"Set variables: (Without args print current settings)\n\
+ frame <number> - select another session(frame)\n\
+ timeout <secs> - Set network timeout\n\
+ nooptimeout <secs>- Set network timeout with clearing timeout\n\
+ noop <secs> - Set time interval for sending NOOP operator\n\
+ to server for erased delay\n\
+ sleep <secs> - Set pause beetween transfer attempt\n\
+ debug <y|n> - Set debuging ftp's protocol (Default no)\n\
+ try <y|n> - Set retransfer mode with broken network (Default yes)\n\
+ hash <y|n> - Set hashing transfer (Default no)\n\
+ restore <y|n> - Set retransfer mode (reget/reput) (Default yes!!!!)\n\
+ bin <y|n> - Set automatic turn on binary mode (Default no) \n\
+ glass <y|n> - Set glass mode (bad commands interprets as commands for FTPD)\n\
+ prompt <string> - Set prompt (See help prompt)\n\
+ port <number> - Set ftpd's port for next sessions\n\
+ user <name> - Set default user name (default you name)",
+
+ "prompt", NULL, 0,
+ "\
+prompt is a string, which may be contains %<char>
+or ^<char> combitanion, which have next interprets:
+
+%H, %h - full and short remote host names
+%M, %m - full and short local host names
+%u - remote user's name
+%d - remote current directory
+%D - local current directory
+%f - number of current frame
+%p - the ftp's port number
+%t - timeout
+%T - current time
+%P - uftp process id
+%% - character %
+^<char>- control character
+%^ - character ^
+",
+
+ "list", Ftp_list, 0,
+"List session's information",
+
+ "user", Ftp_user, 1,
+"user <user> - send user's name",
+
+ "pass", Ftp_pass, 1,
+"pass <pass> - send user's password",
+
+ "bin", Ftp_bin, 1,
+"Set binary mode for current frame",
+
+ "ascii", Ftp_ascii, 1,
+"Set ASCII mode for current frame",
+
+ "cd", Ftp_cd, 1,
+"cd <directory> - change current remote directory ",
+
+ "acd", Ftp_acd, 0,
+"acd <file_or_directory> - search pointed directory using archie, and setup connection to it",
+
+ "lcd", Ftp_lcd, 0,
+"Change local directory",
+
+ "abort", Ftp_abort, 1,
+"abort last operation",
+
+ "mkdir", Ftp_mkdir, 1,
+"mkdir <dirname> - create new directory",
+
+ "rm", Ftp_rm, 1,
+"rm <filename_spec> - remove file(s)",
+
+ "mv", Ftp_move, 1,
+"mv <old> <new> - rename file",
+
+ "dir", Ftp_dir, 1,
+"dir <argslist> ... - print list of files",
+
+ "ls", Ftp_dir, 1,
+"ls <arglist> ... - print short list of files",
+
+ "get", Ftp_get, 1,
+"get <remote_file> [<local_file>] - receive file from server",
+
+ "mget", Ftp_mget, 1,
+"mget <remote_file(s)> [<local_directory>] - receive file(s) from server",
+
+ "reget", Ftp_get, 1,
+"reget <remote_file> <local_file> - receive file restarting at end of local file",
+
+ "aget", Ftp_acd, 0,
+"aget <file> - search pointed file using archie, and retrive it",
+
+ "put", Ftp_get, 1,
+"put <local_file> [<remote_file>] - send server to file",
+
+ "mput", Ftp_mput, 1,
+"mput <local_file(s)> - send file(s) from server",
+
+ "reput", Ftp_get, 1,
+"reput <local_file> [<remote_file>] - send file restarting at end of remote file",
+
+ "bget", Ftp_bget, 0,
+"bget <libftp_file> [<localfile>] - full session procedure (See \"help etc\")",
+
+ "bput", Ftp_bput, 0,
+"bput [<localfile>] <libftp_file> - full session procedure (See \"help etc\")",
+
+ "copy", Ftp_copy, 1,
+"copy [<frame>!]file [<frame>!]file - copy file via client cache",
+
+ "ccopy", Ftp_ccopy, 1,
+"ccopy [<frame>!]file [<frame>!]file - copy file directly beetween servers",
+
+ "cat", Ftp_type, 1,
+"cat <file> - print body of remote file to screen",
+
+ "page", Ftp_page, 1,
+"page <file> - print body of remote file to screen via pager",
+
+ "bg", Ftp_bg, 0,
+"bg <any_command> - run command(s) backgroundly (output redirect to file),\n\
+You can also add &-char to back of line without \"bg\"",
+
+ "archie", Ftp_acd, 0,
+"Find file using archie service and display to screen",
+
+ "dup", Ftp_dup, 1,
+"Make new analogous frame",
+
+ "quote", Ftp_quote, 1,
+"quote <some_string> - send command directly to server",
+
+ "help", Ftp_help, 0,
+"help <command> - print list of commands or command description",
+
+ "alias", Ftp_alias, 0,
+"\
+alias aliasname <list> .... - make new alias, use $X for taking \n\
+ X's argument from command string, and $* for taking\n\
+ all arguments. If $<anything> on alias not present,\n\
+ the arguments appending to end of command string",
+
+ "unalias", Ftp_unalias, 0,
+"unalias <aliasname> - remove alias",
+
+ "mkalias", Ftp_mkalias, 0,
+"make alias for create this frame, use savealias for saving it to file",
+
+ "savealias", Ftp_save, 0,
+ "Save aliases to file",
+
+ "etc", NULL, 0,
+ "\
+1. In any command you may use constructions <file and >file for\n\
+ redirect input output.\n\
+\n\
+2. All local files files interprets as libftp file(s), \n\
+ this support next specification:\n\
+\n\
+ |string - interprets string as shell command, which must be\n\
+ execute and input or output take from/to it.\n\
+ \n\
+ hostname:filename - interprets as file, witch must be take \n\
+ using ftp protocol with anonymously access\n\
+ \n\
+ user@hostname:filename - interprets as file accesses via ftp\n\
+ with password yourname@your_host.your_domain\n\
+\n\
+ user/pass@hostname:filename - also ftp file.\n\
+\n\
+ *STDIN*, *STDOUT*, *STDERR* - opened streams.\n\
+\n\
+ anything - local file name.\n\
+\n\
+3. Command started with '!' passed to shell.\n
+\n\
+4. If string beetween two \" or \', its interprets as one word.\n\
+\n\
+5. Any string may be devide to few commands using ';'.",
+
+
+
+ NULL
+
+};
+
+
+
+
+
+
+
OpenPOWER on IntegriCloud