summaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--lib/libftp/FtpAbort.c47
-rw-r--r--lib/libftp/FtpArchie.c63
-rw-r--r--lib/libftp/FtpBye.c50
-rw-r--r--lib/libftp/FtpClose.c26
-rw-r--r--lib/libftp/FtpCommand.c60
-rw-r--r--lib/libftp/FtpConnect.c71
-rw-r--r--lib/libftp/FtpCopy.c50
-rw-r--r--lib/libftp/FtpData.c90
-rw-r--r--lib/libftp/FtpDebug.c90
-rw-r--r--lib/libftp/FtpFilenameChecker.c43
-rw-r--r--lib/libftp/FtpFull.c142
-rw-r--r--lib/libftp/FtpGetHost.c44
-rw-r--r--lib/libftp/FtpGood.c54
-rw-r--r--lib/libftp/FtpIO.c172
-rw-r--r--lib/libftp/FtpInit.c40
-rw-r--r--lib/libftp/FtpLibrary.h264
-rw-r--r--lib/libftp/FtpLogin.c34
-rw-r--r--lib/libftp/FtpMessage.c130
-rw-r--r--lib/libftp/FtpMove.c25
-rw-r--r--lib/libftp/FtpNumber.c22
-rw-r--r--lib/libftp/FtpOpenDir.c27
-rw-r--r--lib/libftp/FtpPasv.c97
-rw-r--r--lib/libftp/FtpPort.c32
-rw-r--r--lib/libftp/FtpPwd.c33
-rw-r--r--lib/libftp/FtpRetr.c82
-rw-r--r--lib/libftp/FtpSize.c35
-rw-r--r--lib/libftp/FtpStor.c57
-rw-r--r--lib/libftp/FtpSyscalls.c34
-rw-r--r--lib/libftp/FtpType.c26
-rw-r--r--lib/libftp/Ftpfopen.c98
-rw-r--r--lib/libftp/Makefile9
-rw-r--r--lib/libftp/doc/Makefile2
-rw-r--r--lib/libftp/doc/example.c51
-rw-r--r--lib/libftp/doc/example.tex59
-rw-r--r--lib/libftp/doc/libftp.tex571
-rw-r--r--lib/libftp/doc/rus.tex521
-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
47 files changed, 8593 insertions, 0 deletions
diff --git a/lib/libftp/FtpAbort.c b/lib/libftp/FtpAbort.c
new file mode 100644
index 0000000..50b32e6
--- /dev/null
+++ b/lib/libftp/FtpAbort.c
@@ -0,0 +1,47 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+
+FtpAbort(FTP *ftp)
+{
+ fd_set fds;
+ char msgc=IAC;
+ String msg;
+
+ FD_ZERO(&fds);
+ FD_SET(fileno(FTPCMD(ftp)),&fds);
+
+ FtpPutc(ftp, FTPCMD(ftp), IAC);
+ FtpPutc(ftp, FTPCMD(ftp), IP);
+
+ if ( send ( fileno(FTPCMD(ftp)), &msgc , 1 ,MSG_OOB) != 1 )
+ return EXIT(ftp,QUIT);
+
+ FtpPutc(ftp, FTPCMD(ftp), DM);
+
+ FtpSendMessage(ftp,"ABOR");
+
+ while (select ( getdtablesize(), &fds, 0,0, &(ftp->timeout) )>0)
+ {
+ register int i;
+
+ FtpGetMessage(ftp,msg);
+ if (FtpGood(FtpNumber(msg),225,226,EOF)) break;
+ }
+}
+
+
+
diff --git a/lib/libftp/FtpArchie.c b/lib/libftp/FtpArchie.c
new file mode 100644
index 0000000..7f039be
--- /dev/null
+++ b/lib/libftp/FtpArchie.c
@@ -0,0 +1,63 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+#define C2I(n) ((int)((n)-'0'))
+
+int FtpArchie ( char *what, ARCHIE *result, int len)
+{
+ FILE *archie;
+ String cmd,tmp;
+ int i;
+
+ bzero(result,sizeof(result[0])*len);
+
+ sprintf(cmd,"archie -l -m %d %s",len,what);
+
+ if ((archie = popen(cmd,"r"))==NULL)
+ return 0;
+
+ for(i=0;i<len;i++)
+ {
+ char *p, *pp;
+
+ if (fgets(tmp,sizeof (tmp), archie)==NULL)
+ break;
+
+
+ result[i].createtime.tm_year = C2I (tmp[2 ])*10 - 70 + C2I(tmp[3]);
+ result[i].createtime.tm_mday = C2I (tmp[4 ])*10 + C2I(tmp[5]);
+ result[i].createtime.tm_hour = C2I (tmp[6 ])*10 + C2I(tmp[7]);
+ result[i].createtime.tm_min = C2I (tmp[8 ])*10 + C2I(tmp[9]);
+ result[i].createtime.tm_sec = C2I (tmp[10])*10 + C2I(tmp[11]);
+
+ for(p=tmp; *p!=' '; p++);
+ for(; *p==' '; p++);
+
+ result[i].size = atoi(p);
+
+ for(; *p!=' '; p++);
+ for(; *p==' '; p++);
+
+ for (pp=result[i].host;*p!=' ';p++,pp++) *pp=*p;
+ *pp=0;
+ for(; *p==' '; p++);
+ for (pp=result[i].file;*p!='\n';p++,pp++) *pp=*p;
+ *pp=0;
+
+ }
+
+ return i;
+}
diff --git a/lib/libftp/FtpBye.c b/lib/libftp/FtpBye.c
new file mode 100644
index 0000000..de300d5
--- /dev/null
+++ b/lib/libftp/FtpBye.c
@@ -0,0 +1,50 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+#include <signal.h>
+
+STATUS FtpBye(FTP *ftp)
+{
+ String S1;
+ int i;
+
+ FtpAssert(ftp,FtpCommand(ftp,"QUIT",221,EOF));
+
+ fclose(FTPCMD(ftp));
+ free(ftp);
+ return 0;
+}
+
+STATUS FtpQuickBye(FTP *ftp)
+{
+
+
+ if (ftp == NULL) return;
+
+ if (FTPDATA(ftp)!=NULL)
+ {
+ shutdown(fileno(FTPDATA(ftp)),2);
+ fclose(FTPDATA(ftp));
+ }
+
+ if (FTPCMD(ftp)!=NULL)
+ {
+ shutdown(fileno(FTPCMD(ftp)),2);
+ fclose(FTPCMD(ftp));
+ }
+
+ free(ftp);
+}
+
diff --git a/lib/libftp/FtpClose.c b/lib/libftp/FtpClose.c
new file mode 100644
index 0000000..26dbc51
--- /dev/null
+++ b/lib/libftp/FtpClose.c
@@ -0,0 +1,26 @@
+/* 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.
+*/
+
+#include "FtpLibrary.h"
+
+STATUS FtpClose(FTP *ftp)
+{
+ int i;
+ String S1;
+
+ fflush(FTPDATA(ftp));
+ shutdown(fileno(FTPDATA(ftp)),2);
+ fclose(FTPDATA(ftp));
+
+ FtpAssert(ftp,i=FtpGetMessage(ftp,S1));
+ if ( i != 226 )
+ return EXIT(ftp,-i);
+ return EXIT(ftp,i);
+}
diff --git a/lib/libftp/FtpCommand.c b/lib/libftp/FtpCommand.c
new file mode 100644
index 0000000..06421ba
--- /dev/null
+++ b/lib/libftp/FtpCommand.c
@@ -0,0 +1,60 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+STATUS FtpCommand(va_alist)
+ va_dcl
+{
+ FTP *con;
+ char *command, *param;
+ int Answer[MAX_ANSWERS];
+ va_list args;
+ String S1;
+ int i,counter=0;
+
+ va_start(args);
+
+ con = va_arg(args,FTP *);
+ command = va_arg(args,char *);
+ param = va_arg(args, char *);
+
+ while ( 1 )
+ {
+ if (counter == MAX_ANSWERS)
+ return EXIT(con,QUIT);
+ Answer[counter] = va_arg(args,int);
+ if (Answer[counter] == EOF ) break;
+ counter++;
+ }
+
+ va_end(args);
+
+
+ sprintf(S1,command,param);
+
+ if ( FtpSendMessage(con,S1) == QUIT )
+ return EXIT(con,QUIT);
+
+ if ( (i=FtpGetMessage(con,S1)) == QUIT )
+ return EXIT(con,QUIT);
+
+ if ( ! FtpGood1 ( i , Answer ))
+ return EXIT(con,-i);
+
+ return EXIT(con,i);
+}
+
+
+
diff --git a/lib/libftp/FtpConnect.c b/lib/libftp/FtpConnect.c
new file mode 100644
index 0000000..6869e60
--- /dev/null
+++ b/lib/libftp/FtpConnect.c
@@ -0,0 +1,71 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+STATUS FtpConnect(FTP **con,char * hostname)
+{
+ struct sockaddr_in unit;
+ register struct hostent *host;
+ register int new_socket;
+ String S1;
+ STATUS x;
+
+ *con = FtpCreateObject();
+
+ if ((host=FtpGetHost(hostname))==NULL)
+ return EXIT((*con),QUIT);
+
+ strcpy((*con) -> title,host -> h_name); /* Default title for FtpLog */
+
+ unit.sin_family = host -> h_addrtype; /* AF_INET */
+
+ bcopy(host-> h_addr_list[0],(char *)&unit.sin_addr,host->h_length);
+ if ( ( new_socket = socket ( unit.sin_family , SOCK_STREAM , 0)) < 0)
+ return EXIT((*con),QUIT);
+
+ unit.sin_port = htons((*con)->port);
+
+ while ( connect ( new_socket , (struct sockaddr *)&unit , sizeof unit ) < 0 )
+ {
+ host -> h_addr_list ++;
+ if (host -> h_addr_list[0]==NULL) {
+ close(new_socket);
+ return EXIT((*con),QUIT);
+ }
+ bcopy(host -> h_addr_list[0],(char *)&unit,host->h_length);
+ close(new_socket);
+ if ( ( new_socket = socket ( unit.sin_family , SOCK_STREAM , 0)) < 0)
+ {
+ close(new_socket);
+ return EXIT((*con),QUIT);
+ }
+ }
+
+ FTPCMD(*con) = fdopen(new_socket,"r+");
+
+ if ( (x=FtpGetMessage(*con,S1)) == QUIT )
+ return EXIT((*con),QUIT);
+ if ( ! FtpGood(x,120,220,EOF))
+ {
+ close(new_socket);
+ return EXIT((*con),-x);
+ }
+ if ( (*con)->mode != 'A' ) FtpType(*con,(*con)->mode);
+
+ return EXIT((*con),x);
+}
+
+
+
diff --git a/lib/libftp/FtpCopy.c b/lib/libftp/FtpCopy.c
new file mode 100644
index 0000000..d09fd36
--- /dev/null
+++ b/lib/libftp/FtpCopy.c
@@ -0,0 +1,50 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+STATUS FtpCopy (FTP * ftp1 , FTP * ftp2 ,char *in , char * out)
+{
+ int size;
+ char buffer[FTPBUFSIZ];
+
+ if (!*out) out=in;
+
+ if ( FtpTestFlag(ftp1,FTP_REST) && FtpTestFlag(ftp2,FTP_REST)
+ && (size=FtpSize(ftp1,in))>0
+ && FtpCommand(ftp1,"REST 0",0,0,EOF)==350 && FtpCommand(ftp2,"REST 0",0,0,EOF)==350 )
+ ftp1->seek=ftp2->seek=size;
+ else
+ ftp1->seek=ftp2->seek=0;
+
+ FtpAssert(ftp1,FtpData(ftp1,"RETR %s",in,"r"));
+ FtpAssert(ftp2,FtpData(ftp2,"STOR %s",out,"w"));
+
+ while ((size=FtpReadBlock(ftp1,buffer,FTPBUFSIZ))>0)
+ {
+ if (FtpWriteBlock(ftp2,buffer,size)!=size)
+ return EXIT(ftp2,QUIT);
+ }
+
+ FtpAssert(ftp1,FtpClose(ftp1));
+ FtpAssert(ftp2,FtpClose(ftp2));
+ return 0;
+}
+
+
+
+
+
+
+
diff --git a/lib/libftp/FtpData.c b/lib/libftp/FtpData.c
new file mode 100644
index 0000000..e0c768e
--- /dev/null
+++ b/lib/libftp/FtpData.c
@@ -0,0 +1,90 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+STATUS FtpData(FTP * con,char * command , char * file ,char * mode)
+{
+ struct sockaddr_in data,from;
+ register struct hostent *host;
+ String hostname,cmd;
+ int NewSocket,Accepted_Socket,len=sizeof(data),one=1,fromlen=sizeof(from),i;
+ char *a,*b;
+
+ FREE(data);
+ FREE(from);
+
+ if ( gethostname( hostname , sizeof hostname ) == -1 )
+ return EXIT(con,QUIT);
+
+ if ((host=(struct hostent *)gethostbyname(hostname))==0)
+ return EXIT(con,QUIT);
+
+ data.sin_family = host -> h_addrtype;
+
+ bcopy(host-> h_addr_list[0],(char *)&data.sin_addr,host->h_length);
+
+ if ((NewSocket = socket ( AF_INET , SOCK_STREAM , 0 ))<0)
+ return EXIT(con,QUIT);
+
+ if ( setsockopt ( NewSocket , SOL_SOCKET , SO_REUSEADDR ,
+ (char *)&one , sizeof(one) ) < 0 )
+ {
+ close(NewSocket);
+ return EXIT ( con,QUIT );
+ }
+
+ data.sin_port = 0 ;
+
+ if ( bind ( NewSocket , (struct sockaddr *)&data , sizeof data ) < 0 )
+ return EXIT(con,QUIT);
+
+ if ( getsockname ( NewSocket , &data , &len ) < 0 )
+ return EXIT(con,QUIT);
+
+ if ( listen ( NewSocket , 1 ) < 0 )
+ return EXIT(con,QUIT);
+
+ a = ( char * ) & data.sin_addr;
+ b = ( char * ) & data.sin_port;
+
+ FtpAssert(con,FtpPort(con,CUT(a[0]),CUT(a[1]),CUT(a[2]),
+ CUT(a[3]),CUT(b[0]),CUT(b[1])));
+
+ if ( con -> seek != 0)
+ {
+ if ((i = FtpCommand ( con, "REST %d" , con -> seek , 0, EOF)) != 350 )
+ return -i;
+ }
+
+ FtpAssert(con, FtpCommand ( con , command , file ,
+ 200, 120 , 150 , 125 , 250 , EOF ));
+
+ if (( Accepted_Socket = accept (NewSocket , &from , &fromlen )) < 0)
+ {
+ close(NewSocket);
+ return EXIT(con,QUIT);
+ }
+
+ close(NewSocket);
+
+ FTPDATA(con) = fdopen(Accepted_Socket, "r+");
+
+ return i;
+}
+
+
+
+
+
diff --git a/lib/libftp/FtpDebug.c b/lib/libftp/FtpDebug.c
new file mode 100644
index 0000000..c7fa811
--- /dev/null
+++ b/lib/libftp/FtpDebug.c
@@ -0,0 +1,90 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+void FtpDebug(FTP *ftp)
+{
+ STATUS FtpDebugDebug(),
+ FtpDebugError(),
+ FtpDebugIO();
+
+ FtpSetDebugHandler(ftp,FtpDebugDebug);
+ FtpSetErrorHandler(ftp,FtpDebugError);
+ FtpSetIOHandler(ftp,FtpDebugIO);
+}
+
+STATUS FtpDebugDebug(FTP *ftp,int n, char * Message)
+{
+ String tmp;
+
+
+ strcpy(tmp,Message);
+
+ if (strncmp(tmp,"PASS ",5)==0)
+ {
+ char *p=tmp+5;
+ while ( *p != '\0') *p++='*';
+ };
+
+ FtpLog(ftp->title,tmp);
+ return 1;
+}
+
+STATUS FtpDebugError(FTP *ftp,int n, char * Message)
+{
+
+ FtpLog("FtpDebugError","");
+ FtpLog(ftp->title,Message);
+ if ( ! FtpTestFlag(ftp,FTP_NOEXIT))
+ exit(1);
+}
+
+STATUS FtpDebugIO(FTP *ftp,int n, char * Message)
+{
+ FtpLog("FtpDebugIO","");
+ FtpLog(ftp->title,Message);
+ if ( ! FtpTestFlag(ftp,FTP_NOEXIT))
+ exit(1);
+}
+
+STATUS FtpLog(char *name,char *str)
+{
+ time_t t=time((time_t *)0);
+ struct tm *lt=localtime(&t);
+ fprintf(stderr,"%02d:%02d:%02d %s %s\n",lt->tm_hour,
+ lt->tm_min,lt->tm_sec,name,str);
+ fflush(stderr);
+}
+
+FtpHash(FTP *ftp, unsigned long chars)
+{
+
+ if (chars==0) return ftp->counter=0;
+ ftp->counter+=chars;
+ fprintf(stdout,"%10u bytes transfered\r",ftp->counter);
+ fflush(stdout);
+ return ftp->counter;
+}
+
+
+STATUS FtpBadReply550(char *s)
+{
+ if(
+ (strstr(s,"unreachable")!=NULL) ||
+ (strstr(s,"Broken pipe")!=NULL)
+ )
+ return 0;
+ return 1;
+}
diff --git a/lib/libftp/FtpFilenameChecker.c b/lib/libftp/FtpFilenameChecker.c
new file mode 100644
index 0000000..47483d4
--- /dev/null
+++ b/lib/libftp/FtpFilenameChecker.c
@@ -0,0 +1,43 @@
+/* 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.
+*/
+
+#include "FtpLibrary.h"
+
+static char * simplename(char *s)
+{
+ char *p;
+
+ if ( (p=(char *)strrchr(s,'/')) == NULL )
+ return s;
+ return p+1;
+}
+
+
+
+
+STATUS FtpFilenameChecker(char ** in, char ** out)
+{
+ struct stat st;
+
+ if ( (stat(*out,&st) == 0) && S_ISDIR(st.st_mode))
+ {
+ char * sfn = simplename(*in);
+ char * new = (char *) malloc ( strlen(*out)+ strlen(sfn) + 2 );
+
+ strcpy(new,*out);
+ strcat(new,"/");
+ strcat(new,sfn);
+ *out=new;
+ return;
+ };
+
+}
+
+
diff --git a/lib/libftp/FtpFull.c b/lib/libftp/FtpFull.c
new file mode 100644
index 0000000..aefaa2d
--- /dev/null
+++ b/lib/libftp/FtpFull.c
@@ -0,0 +1,142 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+#include <pwd.h>
+
+static FTP *ftp_table[256];
+static STATUS syntax();
+
+FILE * FtpFullOpen(char * file , char * mode )
+{
+ FTP *ftp;
+ FILE *tmp;
+ String Host,User,Passwd,RemoteFile;
+ STATUS i;
+
+ if ( ! FtpFullSyntax (file,Host,User,Passwd,RemoteFile))
+ {
+ tmp=fopen(file,mode);
+ if (tmp==NULL) return tmp;
+ ftp_table[(int)fileno(tmp)] = NULL;
+ return tmp;
+ }
+ if ( FtpError(i=FtpLogin(&ftp,Host,User,Passwd,NULL)))
+ return NULL;
+
+ if (mode[1]=='b') FtpBinary(ftp);
+
+ switch(mode[0])
+ {
+ case 'r':
+ if (FtpError(FtpOpenRead(ftp,RemoteFile)))
+ return NULL;
+ ftp_table[fileno(FTPDATA(ftp))] = ftp;
+ return FTPDATA(ftp);
+ case 'w':
+ if (FtpError(FtpOpenWrite(ftp,RemoteFile)))
+ return NULL;
+ ftp_table[fileno(FTPDATA(ftp))] = ftp;
+ return FTPDATA(ftp);
+ case 'a':
+ if (FtpError(FtpOpenAppend(ftp,RemoteFile)))
+ return NULL;
+ ftp_table[fileno(FTPDATA(ftp))] = ftp;
+ return FTPDATA(ftp);
+ }
+ /* Error Mode */
+ return NULL;
+}
+
+STATUS FtpFullClose(FILE *f)
+{
+ FTP *ftp=ftp_table[(int)fileno(f)];
+ if (ftp == NULL)
+ return fclose(f);
+ FtpClose(ftp);
+ return FtpQuickBye(ftp);
+}
+
+
+/* Format of ftp's file [user[/passord]@]hostname:filename_with_path */
+
+STATUS FtpFullSyntax ( String source ,
+ String host ,
+ String user ,
+ String passwd ,
+ String file)
+
+{
+ char *in,*out;
+ String tmp;
+
+ host[0] = user[0] = passwd[0] = file[0] = '\0';
+
+ for ( in=source, out = user;
+ *in !='\0' && *in != '/' && *in!='@' && *in!=':' ;
+ *out++ = *in++);
+ *out = '\0';
+
+ if ( *in == '\0' ) return 0;
+
+ if ( *in == ':' )
+ {
+ strcpy(host,user);
+ strcpy(user,"anonymous");
+ gethostname(tmp, sizeof tmp);
+ sprintf(passwd,"%s@%s",
+ getpwuid(getuid())->pw_name,gethostbyname(tmp)->h_name);
+ goto file;
+ }
+
+ if ( *in == '/' )
+ {
+ for ( in++, out = passwd;
+ *in !='\0' && *in!='@' ;
+ *out++ = *in++);
+ *out = '\0';
+ if ( *in == '\0' ) return 0;
+ }
+ else
+ {
+ gethostname(tmp, sizeof tmp);
+ sprintf(passwd,"%s@%s",
+ getpwuid(getuid())->pw_name,gethostbyname(tmp)->h_name);
+ }
+
+
+ for ( in++, out = host;
+ *in !='\0' && *in!=':' ;
+ *out++ = *in++);
+ *out = '\0';
+
+ if ( *in == '\0' ) return 0;
+
+file:
+
+ for ( in++, out = file;
+ *in !='\0';
+ *out++ = *in++);
+ *out = '\0';
+
+ return 1;
+}
+
+
+
+
+
+
+
+
diff --git a/lib/libftp/FtpGetHost.c b/lib/libftp/FtpGetHost.c
new file mode 100644
index 0000000..e0c2305
--- /dev/null
+++ b/lib/libftp/FtpGetHost.c
@@ -0,0 +1,44 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+
+
+struct hostent *FtpGetHost(char *host)
+{
+
+ static struct in_addr addr;
+ static struct hostent _host;
+ static char *point[2];
+ static char *alias[1];
+
+ bzero(&_host,sizeof _host);
+ if ( (addr.s_addr=inet_addr(host)) != -1 )
+ {
+ _host.h_addr_list = point;
+ _host.h_addr_list[0] = (char *) &addr;
+ _host.h_addr_list[1] = (char *) 0;
+ alias[0]=NULL;
+ _host.h_aliases=alias;
+ _host.h_name=host;
+ _host.h_length=sizeof(unsigned long);
+ _host.h_addrtype=AF_INET;
+ return &_host;
+ }
+
+ return gethostbyname(host);
+}
+
+
diff --git a/lib/libftp/FtpGood.c b/lib/libftp/FtpGood.c
new file mode 100644
index 0000000..332232a
--- /dev/null
+++ b/lib/libftp/FtpGood.c
@@ -0,0 +1,54 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+STATUS FtpGood(va_alist)
+ va_dcl
+{
+ va_list args;
+ int Number;
+ int Answer[MAX_ANSWERS];
+ int counter=0;
+
+ va_start(args);
+
+ Number = va_arg(args,int);
+
+ while ( 1 )
+ {
+ if (counter == MAX_ANSWERS)
+ return 0;
+ Answer[counter] = va_arg(args,int);
+ if (Answer[counter] == EOF ) break;
+ counter++;
+ }
+
+ va_end(args);
+
+ return FtpGood1(Number,Answer);
+}
+
+
+STATUS FtpGood1(int Number , int *Answer)
+{
+ while (1)
+ {
+ if ( *Answer == Number) return 1;
+ if ( *Answer == 0) return 1;
+ if ( *Answer == EOF ) return 0;
+ Answer++;
+ }
+}
+
diff --git a/lib/libftp/FtpIO.c b/lib/libftp/FtpIO.c
new file mode 100644
index 0000000..3686981
--- /dev/null
+++ b/lib/libftp/FtpIO.c
@@ -0,0 +1,172 @@
+/* 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 exist
+ing programs.
+Commercial usage is also possible with participation of it's author.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+int FtpRead(FTP *con)
+{
+ int c;
+
+ if ( con -> mode == 'I' )
+ return FtpGetc(con,FTPDATA(con));
+
+ if ( con->ch != EOF )
+ {
+ c=con->ch;
+ con->ch=EOF;
+ return c;
+ }
+
+ c=FtpGetc(con,FTPDATA(con));
+
+ if ( c == Ctrl('M') )
+ {
+ c = FtpGetc(con,FTPDATA(con));
+
+ if ( c == Ctrl('J') )
+ return '\n';
+ con->ch = c;
+ return Ctrl('M');
+ }
+ return c;
+}
+
+int FtpWrite(FTP *ftp,char c)
+{
+
+ if ( ftp -> mode == 'I' || c != '\n' )
+ return FtpPutc(ftp,FTPDATA(ftp),c);
+
+ FtpPutc(ftp,FTPDATA(ftp),Ctrl('M'));
+ return FtpPutc(ftp,FTPDATA(ftp),Ctrl('J'));
+}
+
+
+int FtpGetc(FTP *ftp,FILE *fp)
+{
+ fd_set fds;
+ char c;
+
+ FD_ZERO(&fds);
+ FD_SET(fileno(fp),&fds);
+
+ if (select(getdtablesize(), &fds, 0, 0, &(ftp->timeout))<1)
+ return EXIT(ftp,QUIT);
+
+ if (read(fileno(fp),&c,1)<1)
+ return EOF;
+
+ if (ftp->hash!=NULL) (*ftp->hash)(ftp,1);
+
+ return (int)c;
+}
+
+
+STATUS FtpPutc(FTP *ftp,FILE *fp,char c)
+{
+ fd_set fds;
+
+ FD_ZERO(&fds);
+ FD_SET(fileno(fp),&fds);
+
+ if (select(getdtablesize(), 0, &fds, 0, &(ftp->timeout))<1)
+ return EXIT(ftp,QUIT);
+
+ if (write(fileno(fp),&c,1)!=1)
+ return EXIT(ftp,QUIT);
+
+ if (ftp->hash!=NULL) (*ftp->hash)(ftp,1);
+}
+
+
+STATUS FtpReadBlock(FTP *ftp, char *buffer, int size)
+{
+ fd_set fds;
+ register int rsize,status;
+
+ FD_ZERO(&fds);
+ FD_SET(fileno(FTPDATA(ftp)),&fds);
+
+ if (select(getdtablesize(), &fds,0, 0, &(ftp->timeout))<1)
+ return EXIT(ftp,QUIT);
+
+
+ if ((rsize=read(fileno(FTPDATA(ftp)),buffer,size))<0)
+ return EXIT(ftp,QUIT);
+
+ if (ftp->hash!=NULL && rsize!=0) (*ftp->hash)(ftp,rsize);
+
+ if (ftp->mode == 'A')
+ {
+ char buffer2[size];
+ register int i,ii;
+
+ for (i=0,ii=0;i<rsize;i++,ii++)
+ if (buffer[i]==Ctrl('M')&&buffer[i+1]==Ctrl('J'))
+ buffer2[ii]='\n',i++;
+ else
+ buffer2[ii]=buffer[i];
+
+ rsize=ii;
+ bcopy(buffer2,buffer,rsize);
+ }
+ return rsize;
+}
+
+
+STATUS FtpWriteBlock(FTP *ftp, char *buffer, int size)
+{
+ fd_set fds;
+ register int wsize;
+ char buffer2[size*2];
+
+ FD_ZERO(&fds);
+ FD_SET(fileno(FTPDATA(ftp)),&fds);
+
+ if (select(getdtablesize(), 0, &fds, 0, &(ftp->timeout))<1)
+ return EXIT(ftp,QUIT);
+
+
+ if (ftp->mode=='A')
+ {
+ register int i,ii;
+
+ for(i=0,ii=0;i<size;i++,ii++)
+ if (buffer[i]=='\n')
+ buffer2[ii++]=Ctrl('M'),buffer2[ii]=Ctrl('J');
+ else
+ buffer2[ii]=buffer[i];
+ buffer=buffer2;
+ size=ii;
+ }
+
+ if ((wsize=write(fileno(FTPDATA(ftp)),buffer,size))!=size)
+ return EXIT(ftp,QUIT);
+
+ if ( ftp->hash!=NULL && wsize!=0 ) (*ftp->hash)(ftp,wsize);
+
+ return wsize;
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/libftp/FtpInit.c b/lib/libftp/FtpInit.c
new file mode 100644
index 0000000..eee7cea
--- /dev/null
+++ b/lib/libftp/FtpInit.c
@@ -0,0 +1,40 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+FTP FtpInit = {
+ NULL, /*sock*/
+ NULL, /*data*/
+ 'A', /*mode*/
+ 0, /*errno*/
+ 0, /*ch*/
+ NULL,NULL,NULL, NULL, /*funcs*/
+ 0, /*seek*/
+ 0, /*flags*/
+ {120,0}, /*timeout 2 min*/
+ 21, /*Port*/
+ 0, /*Counter*/
+};
+
+FTP *FtpCreateObject()
+{
+ FTP *new = (FTP *) malloc (sizeof(FTP));
+
+ bcopy(&FtpInit,new,sizeof(FTP));
+
+ return new;
+}
+
+
diff --git a/lib/libftp/FtpLibrary.h b/lib/libftp/FtpLibrary.h
new file mode 100644
index 0000000..02aa662
--- /dev/null
+++ b/lib/libftp/FtpLibrary.h
@@ -0,0 +1,264 @@
+/*
+ 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.
+
+
+*/
+
+
+#ifndef __FTPLIBRARY_H
+#define __FTPLIBRARY_H
+
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <arpa/ftp.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <varargs.h>
+#include <arpa/telnet.h>
+#include <sys/stat.h>
+
+
+#ifndef __FreeBSD__
+extern char *sys_errlist[];
+extern int errno;
+#else
+#include <errno.h>
+#endif
+
+
+ /* Standard Macros & Definitions */
+
+
+
+#define EXIT(con,e) \
+ ( con -> errno = e, \
+ ((e==QUIT||e==LQUIT)&&(con->IO != NULL))?(*(con->IO))(con,e,sys_errlist[errno]):0,\
+ ((con->error != NULL) && (e < 0) )?(*(con->error))(con,e,FtpMessage(e)):0,\
+ e)
+
+
+#define MAX_ANSWERS 10 /* Number of known goodest answers for reqest */
+#define NFDS 64
+#define FTPBUFSIZ BUFSIZ
+#define LQUIT (-6)
+#define QUIT (-5) /* Few time ago QUIT character been
+ equivalence to zero, changed for clear
+ conflicts with reading functions */
+#define Ctrl(x) ((x) - '@')
+#define FREE(x) memset ( &(x) , '\0' , sizeof (x) )
+#define CUT(x) ((x)&0xff)
+#define FtpError(x) ((x)<0)
+#define FtpAssert(ftp,x) if (FtpError(x)) return EXIT((ftp),(ftp)->errno);
+
+typedef int STATUS;
+typedef char String[256];
+
+#ifdef __GNUC__
+#define INLINE inline
+#else
+#define INLINE
+#endif
+
+
+
+ /* Common Information Structure */
+
+typedef struct/* All structure initialize from edited struct FtpInit */
+{
+ FILE *sock; /* Command stream to server */
+
+#define FTPDATA(x) ((x)->data)
+#define FTPCMD(x) ((x)->sock)
+
+
+ FILE *data; /* Data stream to server */
+ char mode; /* Binary, Ascii, ......... */
+ int errno; /* Last error code */
+ int ch; /* Help character for ascii streams */
+
+ STATUS (*error)();
+ STATUS (*debug)();
+ STATUS (*IO)();
+ STATUS (*hash)(); /* Call with reading/writing next "int" characters
+ from stream */
+ int seek; /*
+ Warning! If server not supported REST-command,
+ then seek variable automaticaly turn to zero
+ */
+ int flags; /* FTP_REST,
+ FTP_NOEXIT */
+ struct timeval timeout;
+ /* How long must be waiting next character
+ from server */
+ int port;
+ String title; /* Using for FtpLog, FtpConnect lets hostname */
+ unsigned long counter;
+ /* Using by FtpHash */
+} FTP;
+
+typedef struct
+{
+ struct tm createtime;
+ unsigned long size;
+ String host;
+ String file;
+} ARCHIE;
+
+
+enum {FTP_REST=1,FTP_NOEXIT=2};
+enum {no,yes};
+enum {off,on};
+enum {false,true};
+
+extern FTP FtpInit;
+
+/* Options defines */
+
+#define FtpSetFlag(ftp,flag) ((ftp)->flags|=(flag))
+#define FtpClearFlag(ftp,flag) ((ftp)->flags &= (~(flag)) )
+#define FtpTestFlag(ftp,flag) ((ftp)->flags&(flag)==flag)
+#define FtpSetTimeout(ftp,tim) \
+ ((ftp)->timeout.tv_sec=tim,(ftp)->timeout.tv_usec=0)
+#define FtpSetPort(ftp,prt) ((ftp)->port=(prt))
+
+/* Connect & disconnect */
+
+STATUS FtpConnect(FTP **con,char *hostname);
+#define FtpUser(ftp,user) FtpCommand(ftp,"USER %s",user,230,331,332,EOF)
+#define FtpPassword(ftp,pas) FtpCommand(ftp,"PASS %s",pas,230,332,EOF)
+#define FtpAccount(ftp,acc) FtpCommand(ftp,"ACCT %s",acc,230,EOF)
+STATUS FtpLogin(FTP **con,char *host ,char *user,char *pass,char *acct);
+STATUS FtpBye (FTP * con);
+STATUS FtpQuickBye (FTP * con);
+STATUS FtpAbort(FTP *ftp);
+
+/* Set type of transfer */
+
+STATUS FtpType(FTP *ftp,char type);
+#define FtpAscii(ftp) FtpType(ftp,'A')
+#define FtpBinary(ftp) FtpType(ftp,'I')
+
+
+/* Send/Receive and handling Procedure(s) */
+
+STATUS FtpCopy(FTP *ftp1, FTP *ftp2, char *in, char *out);
+STATUS FtpPassiveTransfer(FTP *ftp1, FTP *ftp2, char *in, char *out);
+
+STATUS FtpRetr(FTP *con, char *command,char *inp,char *out);
+#define FtpGet(ftp,in,out) FtpRetr(ftp,"RETR %s",in,out)
+#define FtpDirectory(ftp,pat,out) FtpRetr(ftp,"LIST %s",pat,out)
+#define FtpDir(ftp,out) FtpRetr(ftp,"LIST","",out)
+
+STATUS FtpStor(FTP *con ,char*command ,char *inp,char *out);
+#define FtpPut(ftp,in,out) FtpStor(ftp,"STOR %s",in,out)
+
+STATUS FtpData( FTP * con , char * command , char * param , char *mode);
+STATUS FtpPort ( FTP *con ,int ,int ,int ,int ,int ,int );
+#define FtpOpenRead(ftp,file) FtpData(ftp,"RETR %s",file,"r")
+#define FtpOpenWrite(ftp,file) FtpData(ftp,"STOR %s",file,"w")
+#define FtpOpenAppend(ftp,file) FtpData(ftp,"APPE %s",file,"r")
+STATUS FtpOpenDir( FTP * con , char * files );
+STATUS FtpClose ( FTP *);
+
+/* Command for hand transfer */
+
+STATUS FtpRead ( FTP * con);
+STATUS FtpWrite ( FTP * con , char c);
+int FtpGetc ( FTP * ftp, FILE *fp );
+STATUS FtpPutc (FTP *ftp, FILE *fp, char c);
+
+/* Manipulation commands for remote server */
+
+STATUS FtpCommand ();
+#define FtpChdir(ftp,dir) FtpCommand(ftp,"CWD %s",dir,200,250,EOF)
+#define FtpMkdir(ftp,dir) FtpCommand(ftp,"MKD %s",dir,200,257,EOF)
+#define FtpRm(ftp,dir) FtpCommand(ftp,"DELE %s",dir,200,250,EOF)
+char *FtpPwd(FTP *con);
+int FtpSize(FTP *con,char *filename);
+STATUS FtpMove ( FTP *con,char * old,char *new);
+
+/* Procedures for dialog with remote server */
+
+STATUS FtpInitMessageList();
+STATUS FtpSendMessage( FTP * con , char * Message );
+int FtpGetMessage( FTP * con , char * Message);
+char *FtpMessage(int Number);
+int FtpNumber ( char * Message );
+
+
+/* Debug */
+
+#define FtpSetErrorHandler(con,f) (con)->error = f
+#define FtpSetDebugHandler(con,f) (con)->debug = f
+#define FtpSetIOHandler(con,f) (con)->IO =f
+#define FtpSetHashHandler(con,f) (con)->hash =f
+#define FtplibDebug(t) FtpDebug(&FtpInit)
+
+STATUS FtpDebugDebug ( FTP *con, int errno, char * Message);
+STATUS FtpDebugError ( FTP *con, int errno, char * Message);
+STATUS FtpDebugIO ( FTP *con, int errno, char * Message);
+STATUS FtpLog(char *progtitle, char *msg);
+STATUS FtpHash ( FTP *con, unsigned long number_of_bytes );
+void FtpDebug ( FTP * con );
+STATUS FtpBadReply550 (char *message);
+
+
+/* Other Procedures */
+
+FTP *FtpCreateObject();
+FILE *FtpFullOpen(char * file,char * mode );
+STATUS FtpFullSyntax(String,String,String,String,String);
+FILE *Ftpfopen(char *filename,char *mode);
+STATUS Ftpfclose(FILE *);
+STATUS FtpFullClose(FILE *);
+STATUS FtpGood ();
+STATUS FtpGood1 (int, int *);
+struct hostent *FtpGetHost(char *host);
+STATUS FtpFilenameChecher(char *input, char *output);
+STATUS FtpLink(FTP *,FTP *);
+int FtpArchie(char *what, ARCHIE *, int number);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/* Additional definitions */
+
+#ifdef _AIX
+int accept (int, struct sockaddr_in*, int*);
+char *bcopy (char*, char*, size_t);
+int bind (int, const void*, int);
+int connect (int, struct sockaddr_in*, int);
+int gethostname (char*, size_t);
+int getsockname (int, struct sockaddr_in*, int*);
+int getpeername (int, struct sockaddr_in*, int*);
+int getsockopt (int, int, int, void*, int*);
+int listen(int, int);
+int setsockopt (int, int, int, void*, int);
+int socket (int, int, int);
+void free (void*);
+void *malloc (size_t);
+#endif
+
+
+
+
+#endif /* __FTPLIBRARYH_ */
+
+
+
diff --git a/lib/libftp/FtpLogin.c b/lib/libftp/FtpLogin.c
new file mode 100644
index 0000000..27e43ae
--- /dev/null
+++ b/lib/libftp/FtpLogin.c
@@ -0,0 +1,34 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+STATUS FtpLogin ( FTP ** con, char * host , char * user ,
+ char * password , char * account)
+{
+
+ FtpAssert((*con),FtpConnect(con,host));
+ FtpAssert((*con),FtpUser((*con),user));
+ if (((*con)->errno)==230 )
+ return ((*con)->errno);
+ if (((*con)->errno)==332)
+ {
+ if ( account == NULL )
+ return EXIT(((*con)),(*con)->errno);
+ FtpAssert((*con),FtpAccount( (*con) , account ));
+ if ( ((*con)->errno)==230 )
+ return (*con)->errno;
+ }
+ return FtpPassword((*con),password);
+}
diff --git a/lib/libftp/FtpMessage.c b/lib/libftp/FtpMessage.c
new file mode 100644
index 0000000..dd02261
--- /dev/null
+++ b/lib/libftp/FtpMessage.c
@@ -0,0 +1,130 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+
+static char * FtpMessageList[1000];
+
+INLINE static char *___gets(char *s, int maxchars, FTP *ftp)
+{
+ char *p=s;
+ int c;
+
+ while (1)
+ {
+ if ((c = FtpGetc(ftp,FTPCMD(ftp))) == EOF)
+ return NULL;
+
+ if ( c == '\n' && *(p-1) == '\r' )
+ {
+ p--;
+ *p='\0';
+ return s;
+ }
+
+ if ( (p-s) > maxchars ) return NULL;
+
+ *p++=(char)c;
+ }
+}
+
+
+
+
+int FtpGetMessage(FTP *con , char * Message )
+{
+ int i=0,n;
+ char tmp[1024];
+
+ while(1)
+ {
+ if (___gets(tmp,sizeof tmp,con)==NULL)
+ return EXIT(con,QUIT);
+ if (isdigit(tmp[0]) &&
+ isdigit(tmp[1]) &&
+ isdigit(tmp[2]) &&
+ tmp[3]!='-') break;
+ if ( con -> debug != NULL )
+ (*con->debug)(con,0,tmp);
+ }
+
+ strcpy(Message,tmp);
+ FtpInitMessageList();
+ FtpMessageList[n=FtpNumber(Message)] =
+ ( char * ) malloc ( strlen(Message) + 1);
+ strcpy(FtpMessageList[n] , Message );
+ if ( con -> debug != NULL )
+ (*con->debug)(con,n,Message);
+
+ return n;
+}
+
+STATUS FtpSendMessage(FTP *ftp,char * Message )
+{
+ char *msg=Message;
+
+ while (*Message)
+ FtpAssert(ftp,FtpPutc(ftp,FTPCMD(ftp),*Message++));
+
+ FtpAssert(ftp,FtpPutc(ftp,FTPCMD(ftp),'\015'));
+ FtpAssert(ftp,FtpPutc(ftp,FTPCMD(ftp),'\012'));
+
+ if ( ftp -> debug != NULL )
+ (*ftp->debug)(ftp,0,msg);
+ return 1;
+}
+
+char *FtpMessage(int number)
+{
+ extern int sys_nerr,errno;
+#ifndef __FreeBSD__
+ extern char *sys_errlist[];
+#endif
+
+ FtpInitMessageList();
+ if ( number == 0 )
+ return sys_errlist[errno];
+ return (FtpMessageList[abs(number)]==NULL)?
+ "":FtpMessageList[abs(number)];
+}
+
+
+STATUS FtpInitMessageList()
+{
+ int i;
+ static u = 0;
+
+ if ( u )
+ return 1;
+
+ u = 1;
+
+ for (i=0;i<1000;i++)
+ FtpMessageList[i]=NULL;
+
+ return 1;
+}
+
+int FtpNumber(char *Message)
+{
+ return (Message[0] - '0') * 100 +
+ (Message[1] - '0') * 10 +
+ (Message[2] - '0') ;
+}
+
+
+
+
+
diff --git a/lib/libftp/FtpMove.c b/lib/libftp/FtpMove.c
new file mode 100644
index 0000000..31d6c25
--- /dev/null
+++ b/lib/libftp/FtpMove.c
@@ -0,0 +1,25 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+STATUS FtpMove(FTP *con,char * oldname , char * newname )
+{
+ STATUS i;
+
+ if ((i=FtpCommand(con,"RNFR %s",oldname,200,350,EOF)) > 1 )
+ return FtpCommand(con,"RNTO %s",newname,200,250,EOF);
+ else
+ return i;
+}
diff --git a/lib/libftp/FtpNumber.c b/lib/libftp/FtpNumber.c
new file mode 100644
index 0000000..56411f8
--- /dev/null
+++ b/lib/libftp/FtpNumber.c
@@ -0,0 +1,22 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+int FtpNumber(char *Message)
+{
+ return (Message[0] - '0') * 100 +
+ (Message[1] - '0') * 10 +
+ (Message[2] - '0') ;
+}
diff --git a/lib/libftp/FtpOpenDir.c b/lib/libftp/FtpOpenDir.c
new file mode 100644
index 0000000..2d3e56e
--- /dev/null
+++ b/lib/libftp/FtpOpenDir.c
@@ -0,0 +1,27 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+STATUS FtpOpenDir(FTP * con,char * file)
+{
+ String command;
+
+ if ( file == NULL || *file == '\0' )
+ strcpy(command,"NLST");
+ else
+ sprintf(command,"NLST %s",file);
+
+ return FtpCommand(con,command,"",120,150,200,EOF);
+}
diff --git a/lib/libftp/FtpPasv.c b/lib/libftp/FtpPasv.c
new file mode 100644
index 0000000..88b000d
--- /dev/null
+++ b/lib/libftp/FtpPasv.c
@@ -0,0 +1,97 @@
+/* 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 exist
+ing programs.
+Commercial usage is also possible with participation of it's author.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+
+char * FtpPasv (FTP *ftp)
+{
+ char *msg;
+ String PORT;
+ char *p=PORT;
+
+ if FtpError(FtpCommand(ftp,"PASV","",227,EOF))
+ return "";
+
+ msg = FtpMessage (227);
+
+ msg+=3;
+
+ while (!isdigit(*msg++));
+ msg--;
+
+ while (isdigit(*msg)||*msg==',') *p++=*msg++;
+ *p=0;
+
+ return PORT;
+}
+
+
+STATUS FtpLink(FTP *ftp1, FTP *ftp2)
+{
+
+ String PORT;
+
+ strcpy(PORT,FtpPasv(ftp1));
+
+ FtpCommand(ftp2,"PORT %s",PORT,200,EOF);
+}
+
+STATUS FtpPassiveTransfer(FTP *ftp1, FTP *ftp2, char *f1, char *f2)
+{
+ String tmp;
+ fd_set fds;
+
+ FtpAssert(ftp1,FtpLink(ftp1,ftp2));
+
+
+ if (!*f2) f2=f1;
+
+ FtpAssert(ftp2,FtpCommand(ftp2,"STOR %s",f2, 200, 120 , 150 , 125 , 250 , EOF ));
+ FtpAssert(ftp1,FtpCommand(ftp1,"RETR %s",f1, 200, 120 , 150 , 125 , 250 , EOF ));
+
+ FD_ZERO(&fds);
+
+ FD_SET(fileno(FTPCMD(ftp1)),&fds);
+ FD_SET(fileno(FTPCMD(ftp2)),&fds);
+
+ if (select(getdtablesize(),&fds,0,0,0)<0)
+ {
+ if (ftp1->error!=NULL)
+ return (*(ftp1->error))(ftp1,QUIT,sys_errlist[errno]);
+ if (ftp2->error!=NULL)
+ return (*(ftp2->error))(ftp1,QUIT,sys_errlist[errno]);
+ return QUIT;
+ }
+
+ if (FD_ISSET(fileno(FTPCMD(ftp1)),&fds))
+ {
+ FtpGetMessage(ftp1,tmp);
+ FtpLog(ftp1->title,tmp);
+ FtpGetMessage(ftp2,tmp);
+ FtpLog(ftp2->title,tmp);
+ }
+ else
+ {
+ FtpGetMessage(ftp2,tmp);
+ FtpLog(ftp2->title,tmp);
+ FtpGetMessage(ftp1,tmp);
+ FtpLog(ftp1->title,tmp);
+ }
+}
+
+
+
+
+
diff --git a/lib/libftp/FtpPort.c b/lib/libftp/FtpPort.c
new file mode 100644
index 0000000..c6b0ca2
--- /dev/null
+++ b/lib/libftp/FtpPort.c
@@ -0,0 +1,32 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+STATUS FtpPort(FTP *con,int a,int b,int c,int d,int e,int f)
+{
+ String cmd;
+ int i;
+
+ sprintf(cmd,"PORT %d,%d,%d,%d,%d,%d",a,b,c,d,e,f);
+ if ( FtpSendMessage(con,cmd) == QUIT)
+ return QUIT;
+ if ( (i=FtpGetMessage(con,cmd)) == QUIT)
+ return QUIT;
+
+ if ( ! FtpGood ( i , 200 , EOF ))
+ return EXIT(con,-i);
+
+ return EXIT(con,i);
+}
diff --git a/lib/libftp/FtpPwd.c b/lib/libftp/FtpPwd.c
new file mode 100644
index 0000000..fb74841
--- /dev/null
+++ b/lib/libftp/FtpPwd.c
@@ -0,0 +1,33 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+char * FtpPwd(FTP * con)
+{
+ String tmp,tmp1;
+ int i;
+
+ if ( FtpSendMessage(con,"PWD") == QUIT )
+ return (char *) EXIT(con,QUIT);
+ if ( (i=FtpGetMessage(con,tmp)) == QUIT )
+ return (char *) EXIT(con,QUIT);
+
+ if ( i != 257 )
+ return (char *) EXIT(con,-i);
+
+ sscanf(tmp,"%*[^\"]%*c%[^\"]%*s",tmp1);
+ con -> errno = i;
+ return tmp1;
+}
diff --git a/lib/libftp/FtpRetr.c b/lib/libftp/FtpRetr.c
new file mode 100644
index 0000000..889621f
--- /dev/null
+++ b/lib/libftp/FtpRetr.c
@@ -0,0 +1,82 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+STATUS FtpRetr (FTP * con , char * command ,
+ char *in , char * out)
+{
+ FILE *o;
+ int c;
+ struct stat st;
+ char buffer[FTPBUFSIZ],buffer2[FTPBUFSIZ];
+ register int size;
+
+ FtpFilenameChecker(&in,&out);
+
+ if ( FtpTestFlag(con,FTP_REST) && stat(out,&st)==0)
+ {
+ con -> seek = st.st_size;
+ if ((o=Ftpfopen(out,"a+"))==NULL)
+ return EXIT(con,LQUIT);
+ }
+ else
+ {
+ con -> seek = 0;
+ if ((o=Ftpfopen(out,"w+"))==NULL)
+ return EXIT(con,LQUIT);
+ }
+
+
+ if ( FtpError(FtpData(con,command,in,"r")))
+ {
+
+ if (con->seek==0) return EXIT(con,con->errno);
+
+ con -> seek = 0;
+ fclose(o);
+
+ if ( FtpError(FtpData(con,command,in,"r")) )
+ {
+ return EXIT(con,con->errno);
+ }
+
+ if ((o=Ftpfopen(out,"w+"))==NULL)
+ return EXIT(con,LQUIT);
+ }
+
+
+ fseek(o,con->seek,0);
+
+ while((size=FtpReadBlock(con,buffer,FTPBUFSIZ))>0)
+ {
+ if (write(fileno(o),buffer,size)!=size)
+ return EXIT(con,LQUIT);
+ }
+
+ Ftpfclose(o);
+ return FtpClose(con);
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/libftp/FtpSize.c b/lib/libftp/FtpSize.c
new file mode 100644
index 0000000..040e16b
--- /dev/null
+++ b/lib/libftp/FtpSize.c
@@ -0,0 +1,35 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+int FtpSize(FTP * con, char *filename)
+{
+ String tmp;
+ int i,size;
+
+ strcpy(tmp,"SIZE ");
+ strcat(tmp,filename);
+
+ if ( FtpSendMessage(con,tmp) == QUIT )
+ return EXIT(con,QUIT);
+ if ( (i=FtpGetMessage(con,tmp)) == QUIT )
+ return EXIT(con,QUIT);
+
+ if ( i != 213 )
+ return con -> errno = (-i);
+
+ sscanf(tmp,"%*d %d",&size);
+ return size;
+}
diff --git a/lib/libftp/FtpStor.c b/lib/libftp/FtpStor.c
new file mode 100644
index 0000000..2fe218c
--- /dev/null
+++ b/lib/libftp/FtpStor.c
@@ -0,0 +1,57 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+STATUS FtpStor (FTP * con , char * command ,
+ char *in , char * out)
+{
+ FILE *i;
+ char buffer[FTPBUFSIZ];
+ int size;
+
+ con->seek=0;
+
+ if ( (i=Ftpfopen(in,"rb")) == NULL )
+ return EXIT(con,LQUIT);
+
+ if ( FtpTestFlag(con,FTP_REST) &&
+ (con->seek=FtpSize(con,out))<0 )
+ con->seek=0;
+
+
+ if ( FtpError(FtpData(con,command,out,"w")))
+ {
+ if (con->seek==0) return EXIT(con,con->errno);
+
+ con -> seek =0;
+ if ( FtpError(FtpData(con,command,out,"w")) )
+ return EXIT(con,con->errno);
+ }
+
+ if (con->seek) fseek(i,con->seek,0);
+
+ while ( (size=read ( fileno(i) , buffer, FTPBUFSIZ ))>0)
+ FtpWriteBlock(con,buffer,size);
+
+ Ftpfclose(i);
+ return FtpClose(con);
+}
+
+
+
+
+
+
+
diff --git a/lib/libftp/FtpSyscalls.c b/lib/libftp/FtpSyscalls.c
new file mode 100644
index 0000000..d1c74e6
--- /dev/null
+++ b/lib/libftp/FtpSyscalls.c
@@ -0,0 +1,34 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+#include <errno.h>
+
+#define DEF(syscal,name) name(a,b,c,d,e,f,g,h) \
+{\
+ register int status;\
+ while (((status=syscal(a,b,c,d,e,f,g,h))==-1) && (errno==EINTR));\
+ return status;\
+}
+
+DEF(open,nointr_open)
+DEF(close,nointr_close)
+DEF(select,nointr_select)
+DEF(read,nointr_read)
+DEF(write,nointr_write)
+DEF(dup,nointr_dup)
+DEF(wait,nointr_wait)
+DEF(connect,nointr_connect)
+DEF(listen,nointr_listen)
+DEF(accept,nointr_accept)
diff --git a/lib/libftp/FtpType.c b/lib/libftp/FtpType.c
new file mode 100644
index 0000000..6c32016
--- /dev/null
+++ b/lib/libftp/FtpType.c
@@ -0,0 +1,26 @@
+/*
+ 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.
+
+
+
+*/
+
+#include "FtpLibrary.h"
+
+STATUS FtpType(FTP *ftp, char type)
+{
+ STATUS p;
+
+ if ((p=FtpCommand(ftp,"TYPE %c",type,200,EOF))>0)
+ ftp->mode=(int)type;
+ return p;
+}
+
+
diff --git a/lib/libftp/Ftpfopen.c b/lib/libftp/Ftpfopen.c
new file mode 100644
index 0000000..b7b96d5
--- /dev/null
+++ b/lib/libftp/Ftpfopen.c
@@ -0,0 +1,98 @@
+/*
+ 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.
+
+
+
+*/
+
+#include <FtpLibrary.h>
+
+#define NFSD 256
+
+static int fds_types[NFDS];
+static int init=0;
+
+enum {T_EMPTY=0,T_FILE,T_STREAM,T_PIPE,T_FULL};
+
+FILE *Ftpfopen(char *filename,char *mode)
+{
+ FILE *fp;
+
+ if (!init)
+ {
+ bzero(fds_types,NFDS*sizeof(fds_types[0]));
+ init=1;
+ }
+
+ if (!strcmp(filename,"*STDIN*") || (!strcmp(filename,"-") && (mode[0]=='r')) )
+ {
+ fds_types[fileno(stdin)]=T_STREAM;
+ return stdin;
+ }
+
+ if (!strcmp(filename,"*STDOUT*") || (!strcmp(filename,"-") && (mode[0]=='w')))
+ {
+ fds_types[fileno(stdout)]=T_STREAM;
+ return stdout;
+ }
+
+ if (strcmp(filename,"*STDERR*")==0)
+ {
+ fds_types[fileno(stderr)]=T_STREAM;
+ return stderr;
+ }
+
+
+
+ if (*filename=='|')
+ {
+ fp=popen(filename+1,mode);
+ if (fp==NULL) return fp;
+ fds_types[fileno(fp)]=T_PIPE;
+ return fp;
+ }
+
+ fp=FtpFullOpen(filename,mode);
+ if (fp==NULL) return fp;
+ fds_types[fileno(fp)]=T_FILE;
+ return fp;
+
+}
+
+int Ftpfclose(FILE *fp)
+{
+
+ if (!init)
+ {
+ bzero(fds_types,NFDS*sizeof(fds_types[0]));
+ init=1;
+ }
+
+ switch (fds_types[fileno(fp)])
+ {
+
+ case T_FILE:
+
+ return FtpFullClose(fp);
+
+ case T_STREAM:
+
+ return fflush(fp);
+
+ case T_PIPE:
+
+ return pclose(fp);
+
+ default:
+
+ return -1;
+ }
+
+}
diff --git a/lib/libftp/Makefile b/lib/libftp/Makefile
new file mode 100644
index 0000000..d75e47a
--- /dev/null
+++ b/lib/libftp/Makefile
@@ -0,0 +1,9 @@
+LIB= ftp
+CFLAGS+= -I${.CURDIR}
+
+SRCS= FtpAbort.c FtpArchie.c FtpBye.c FtpClose.c FtpCommand.c FtpConnect.c \
+ FtpCopy.c FtpData.c FtpDebug.c FtpFilenameChecker.c FtpFull.c \
+ FtpMove.c FtpOpenDir.c FtpPasv.c FtpPort.c FtpPwd.c FtpRetr.c \
+ FtpSize.c FtpStor.c FtpType.c Ftpfopen.c
+
+.include <bsd.lib.mk>
diff --git a/lib/libftp/doc/Makefile b/lib/libftp/doc/Makefile
new file mode 100644
index 0000000..82fe3e0
--- /dev/null
+++ b/lib/libftp/doc/Makefile
@@ -0,0 +1,2 @@
+all clean cleandist install:
+ @echo -n
diff --git a/lib/libftp/doc/example.c b/lib/libftp/doc/example.c
new file mode 100644
index 0000000..7f09287
--- /dev/null
+++ b/lib/libftp/doc/example.c
@@ -0,0 +1,51 @@
+
+/* Include standard libftp's header */
+
+#include <FtpLibrary.h>
+
+
+
+main(int argc, char *argv[])
+{
+
+ FILE *input,*output;
+ int c;
+
+
+ if (argc<3)
+ exit(fprintf(stderr,"Usage: %s input-file output-file\n",argv[0]));
+
+ FtplibDebug(yes);
+
+ if ((input=Ftpfopen(argv[1],"r"))==NULL)
+ {
+ perror(argv[1]);
+ exit(1);
+ }
+
+ if ((output=Ftpfopen(argv[2],"w"))==NULL)
+ {
+ perror(argv[2]);
+ exit(1);
+ }
+
+ while ( (c=getc(input)) != EOF && (putc(c,output)!=EOF) );
+
+ if (ferror(input))
+ {
+ perror(argv[1]);
+ exit(1);
+ }
+
+ if (ferror(output))
+ {
+ perror(argv[1]);
+ exit(1);
+ }
+
+ Ftpfclose(input);
+ Ftpfclose(output);
+
+ exit(0);
+
+}
diff --git a/lib/libftp/doc/example.tex b/lib/libftp/doc/example.tex
new file mode 100644
index 0000000..47c4a9d
--- /dev/null
+++ b/lib/libftp/doc/example.tex
@@ -0,0 +1,59 @@
+%%
+%% Creator: ansic2latex (from <stdin>)
+%% Date: Tue Dec 27 16:14:26 1994
+%%
+\expandafter\ifx\csname indentation\endcsname\relax
+\newlength{\indentation}\fi
+\setlength{\indentation}{0.5em}
+\begin{flushleft}
+\mbox{}\\
+{\em /$\ast$\hspace*{1\indentation}Include\hspace*{1\indentation}standard\hspace*{1\indentation}libftp's\hspace*{1\indentation}header\hspace*{1\indentation}$\ast$/}\mbox{}\\
+\mbox{}\\
+{\tt\#include} $<${\tt FtpLibrary.h}$>$ \mbox{}\\
+\mbox{}\\
+\mbox{}\\
+main({\bf int\/} argc, {\bf char\/} $\ast$argv[])\mbox{}\\
+\{\mbox{}\\
+\mbox{}\\
+\hspace*{2\indentation}FILE $\ast$input,$\ast$output;\mbox{}\\
+\hspace*{2\indentation}{\bf int\/} c;\mbox{}\\
+\hspace*{2\indentation}\mbox{}\\
+\mbox{}\\
+\hspace*{2\indentation}{\bf if\/} (argc$<$3)\mbox{}\\
+\hspace*{4\indentation}exit(fprintf(stderr,{\tt "Usage: \%s input-file output-file$\backslash$n"},argv[0]));\mbox{}\\
+\mbox{}\\
+\hspace*{2\indentation}FtplibDebug(yes);\mbox{}\\
+\hspace*{2\indentation}\mbox{}\\
+\hspace*{2\indentation}{\bf if\/} ((input=Ftpfopen(argv[1],{\tt "r"}))==NULL)\mbox{}\\
+\hspace*{4\indentation}\{\mbox{}\\
+\hspace*{6\indentation}perror(argv[1]);\mbox{}\\
+\hspace*{6\indentation}exit(1);\mbox{}\\
+\hspace*{4\indentation}\}\mbox{}\\
+\hspace*{2\indentation}\mbox{}\\
+\hspace*{2\indentation}{\bf if\/} ((output=Ftpfopen(argv[2],{\tt "w"}))==NULL)\mbox{}\\
+\hspace*{4\indentation}\{\mbox{}\\
+\hspace*{6\indentation}perror(argv[2]);\mbox{}\\
+\hspace*{6\indentation}exit(1);\mbox{}\\
+\hspace*{4\indentation}\}\mbox{}\\
+\hspace*{2\indentation}\mbox{}\\
+\hspace*{2\indentation}{\bf while\/} ( (c=getc(input)) $\neq$ EOF \&\& (putc(c,output)$\neq$EOF) );\mbox{}\\
+\mbox{}\\
+\hspace*{2\indentation}{\bf if\/} (ferror(input))\mbox{}\\
+\hspace*{4\indentation}\{\mbox{}\\
+\hspace*{6\indentation}perror(argv[1]);\mbox{}\\
+\hspace*{6\indentation}exit(1);\mbox{}\\
+\hspace*{4\indentation}\}\mbox{}\\
+\hspace*{2\indentation}\mbox{}\\
+\hspace*{2\indentation}{\bf if\/} (ferror(output))\mbox{}\\
+\hspace*{4\indentation}\{\mbox{}\\
+\hspace*{6\indentation}perror(argv[1]);\mbox{}\\
+\hspace*{6\indentation}exit(1);\mbox{}\\
+\hspace*{4\indentation}\}\mbox{}\\
+\mbox{}\\
+\hspace*{2\indentation}Ftpfclose(input);\mbox{}\\
+\hspace*{2\indentation}Ftpfclose(output);\mbox{}\\
+\mbox{}\\
+\hspace*{2\indentation}exit(0);\mbox{}\\
+\hspace*{2\indentation}\mbox{}\\
+\}\mbox{}\\
+\end{flushleft}
diff --git a/lib/libftp/doc/libftp.tex b/lib/libftp/doc/libftp.tex
new file mode 100644
index 0000000..f7d14e8
--- /dev/null
+++ b/lib/libftp/doc/libftp.tex
@@ -0,0 +1,571 @@
+\documentstyle[cxx,fancyheadings,twoside,epsf,indentfirst]{article}
+% Vertical sizes
+%\vsize=20cm
+%\voffset=-2.3cm
+%\topmargin=0cm
+%\headheight=0.9cm
+%\footskip=1cm
+%\footheight=0.9cm
+%\textheight=16cm
+%\headrulewidth 0.01cm
+%\footrulewidth 0.0cm
+% 0 sizes
+%\hsize=30cm
+%\hoffset=-4.3cm
+%\hoffset=-2.3cm
+%\textwidth=13cm
+% Modes
+% \special{landscape}
+\pagestyle{empty}
+\pagestyle{fancyplain}
+\newcommand{\tit}[1]{#1}
+\rhead[\fancyplain{}{\tit{\leftmark}}]{\fancyplain{}{\tit{\rightmark}}}
+\lhead[\fancyplain{}{\tit{\rightmark}}]{\fancyplain{}{\tit{\leftmark}}}
+\chead{\hfill}
+\lfoot[\fancyplain{}{\tit{\thepage}}]{\fancyplain{}{\hfill}}
+\rfoot[\fancyplain{}{\hfill}]{\fancyplain{}{\tit{\thepage}}}
+\cfoot{\hfill}
+\renewcommand{\sectionmark}[1]{\markboth{#1}{\ }}
+\renewcommand{\subsectionmark}[1]{\markright{\ }}
+\newcommand{\look}[1]{(Chapter~\ref{#1}, page~\pageref{#1})}
+\newcommand{\toindex}[1]{\underline{\bf#1}\index{#1}}
+\newcommand{\add}[1]{\symbol{64}}
+\newcommand{\ps}[1]{\symbol{37}s}
+\newcommand{\twcol}[4]{
+\noindent\parbox[t]{#1\textwidth}{#3} \hfill \parbox[t]{#2\textwidth}{#4\hfill}\\
+}
+\newcommand{\tc}[2]{\twcol{0.49}{0.49}{#1}{#2}}
+\newcommand{\tcc}[2]{\twcol{0.49}{0.49}{\toindex{#1}}{#2}}
+\newcommand{\ttt}[2]{\bigskip
+
+{\bf#1}
+
+#2}
+\newcommand{\ts}[1]{{\underline{\bf#1}}}
+\newcommand{\dl}[2]{\parbox[t]{0.4\textwidth}{#1\hfill}\hfill
+ \parbox[t]{0.4\textwidth}{#2\hfill}}
+\makeindex
+\begin{document}
+\title{\bf\it{LIBFTP User's guide}}
+\author{Oleg Orel}
+\date{\today}
+\newpage
+\maketitle
+
+\section*{License}
+
+This library is designed 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.
+
+\section*{Introduction}
+
+The basic orientation of this library is making user's programs which transport
+files via TCP/IP network. It contains set of functions,
+starting from primitive, such as opening FTP connection to the server,
+and finishing by high-level functions, such as functions which retrieve files
+ via network, making and closing channels to the server. All functions have
+prototypes in common header file named \toindex{FtpLibrary.h},
+which must be
+available in standard headers directory
+\footnote{for example ``/usr/include''}.
+Those prototypes almost fully
+describe orientation and arguments of all functions,
+but common ideology and library components should be mentioned.
+
+This library is a client and uses standard FTPD from the other side.
+
+There are problems of errors processing in many operating systems including input/output errors.
+The mutual mechanism of value returning of all functions is used in this library.
+(EXIT macros, defined in file FtpLibrary.h). This mechanism allows,
+ after the definition of the error processing functions, write programs,
+considering the conditions to be ideal.
+Data transfer functions have possibility to preset data stream
+expectation timeout.
+When the set time expires, previously set function will be called.
+
+\section{Variables and definitions}
+
+\subsection{Some definitions in libftp's header file (FtpLibrary.h)}
+
+\ttt{\toindex{EXIT}}{Main macro for return value from library's functions with
+calling handlers if it's need}
+
+\ttt{\toindex{MAX\_ANSWERS}}{Number of possible answers from FTPD for one request}
+
+\ttt{\toindex{NFDS}}{Maximum numbers of one-time opened files in your system, if this
+value higher than need isn't important. }
+
+\ttt{\toindex{FTPBUFSIZE}}{Size of block for transmit data via network. By default equivalence \toindex{BUSIZ}}
+
+\ttt{\toindex{LQUIT}}{Error status of local functions. If you give this status from libftp's function you must use perror for expand diagnostic.}
+
+\ttt{\toindex{QUIT}}{Error status of network operation. Use perror.}
+
+\ttt{\toindex{Ctrl}(char)}{Return control character code}
+
+\ttt{\toindex{FREE}(data)}{Full data by zero}
+
+\ttt{\toindex{FtpError}(libftp's call)}{Special macro for diagnostic bad conditions}
+
+\ttt{\toindex{FtpAssert}(libftp's call}{Special macro for automatically return from
+this function if status is bad}
+
+\subsection{Libftp's file specification}
+
+All files wich must be interprets as local interprets 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:
+
+\ttt{$\mid$string}{interprets string as shell command, which must be
+ executed with appropriate input/output for file. It depends where
+ this file is specified.}
+
+\ttt{hostname:filename}{interprets as file, which must be taken
+ using ftp protocol with anonymous access}
+
+\ttt{user@hostname:filename\\
+user/pass@hostname:filename
+}{interprets as file accesses via ftp
+ with password yourname@your\_host.your\_domain}
+
+
+\ttt{*STDIN*, *STDOUT*, *STDERR* or char '-'}{opened standard streams}
+
+\ttt{anything else}{local file}
+
+
+
+
+\subsection{The FTP data structure}
+
+\subsubsection{The members of FTP structure}
+
+\tc{FILE *\toindex{sock}\footnote{You can use macro FTPCMD(ftp) for extract
+this members, using this macro for making your program more compatibility
+with next versions of this library}}
+{--- command channel to the server;}
+
+\tc{FILE *\toindex{data}\footnote{You can use macro FTPDATA(ftp) for extract
+this members, using this macro for making your program more compatibility
+with next versions of this library}}
+{--- pointer to data structure, which describes data channel to the server;}
+
+\tc{int \toindex{errno}}{ --- last returned value. When value is lower than 1, an error occurred;}
+
+\tc{char \toindex{mode}}{--- type of transfer (valid values: 'A' 'I' ....);}
+
+\tc{int \toindex{ch}}{--- help variable. Is used to convert ASCII files, user of library for cleaning your problems must forget about this member;}
+
+\tc{STATUS (*\toindex{error})()}{--- pointer to an error handler. It is called
+ when status from the server is bad;}
+\tc{STATUS (*\toindex{debug})()}{--- pointer to a debug handler. Is called from
+ functions of sending/receiving messages to/from server;}
+
+\tc{STATUS (*\toindex{IO})()}{--- pointer to Input/Output error handler. Is called when channel to server is broken.}
+
+\tc{STATUS (*\toindex{hash})()}{--- pointer to function, which must compute
+summary traffic. This function can take one argument which describe
+ how many bytes
+now received of sended to/from server. If the argument is equivalence
+to zero, then counter must be reset to zero. But of course user can use
+this handler for another properties of herself program, for example for
+perriodicaly called anything else for checking other conditions, because
+the transfer procedure can take large time from user's program.}
+
+\tc{int \toindex{seek}}{--- the first byte in file for transfer. This option
+can use for retransfer file again after connection is broken}
+
+\tc{int \toindex{flags}}{--- the option list for transfer procedures such as:
+\\
+\begin{itemize}
+\item[FTP\_REST] Turn on retransfer file using method of compare size of files
+in both sides.
+\item[FTP\_NOEXIT] Don't exit from standard error and IO handlers
+\end{itemize}}
+
+\tc{struct timeval \toindex{timeout}}{--- Timeout for send/receive procedures}
+
+\tc{int \toindex{port}}{--- Port for making command connection}
+
+\tc{String \toindex{title}}{--- Connection identification}
+
+\tc{unsigned long \toindex{counter}}{--- counter of already transferred bytes}
+
+\subsubsection{Initialization of FTP structure}
+
+This library have two special objects: procedure FtpCreateObject and external
+static structure FtpInit. The procedure FtpCreateObject called from
+FtpConnect. The structure FtpInit can be modified by hand or by using special
+macros such as \toindex{FtpSetFlag}, \toindex{FtpClearFlag}, \toindex{FtpSetPort}, \toindex{FtpSetTimeout}, \toindex{FtpSetErrorHandler}, \toindex{FtpSetDebugHandler}, \toindex{FtpSetIOHandler}, \\
+\toindex{FtpSetHashHandler}.
+
+\subsection{The \toindex{ARCHIE} data structure}
+
+The \ts{ARCHIE} data structure using only with function FtpArchie for extract
+result of works one. This structure have four members such as:
+
+\tc{struct tm \toindex{createtime}}{Time of file creation.}
+
+\tc{unsigned long \toindex{size}}{size of file.}
+
+\tc{String \toindex{host}}{Host which file is located}
+
+\tc{String \toindex{file}}{Full path in pointed host of this file}
+
+
+\section{Library's routines}
+
+\subsection{Connection/Disconnection with server}
+
+\ttt{STATUS \toindex{FtpConnect}(FTP~**, char~*hostname
+\footnote{The name of the host may be symbolic (for example \ts{dxcern.cern.ch}) or numeric (for example \ts{128.141.201.96})}
+)}
+{
+ Makes channel to the server, at the ``hostname'' machine.
+ Creates FTP data structure and returns pointer to it. If the procedure \toindex{FtplibDebug}(1)
+was previously called, \ts{FtpConnect} calls automatically \ts{FtpDebug} for the \ts{debug mode} to be turned on.
+ \look{debug}.
+}
+\ttt{STATUS \toindex{FtpUser}(FTP~*, char~*user)}
+{
+ Sends the name of the user to the server. The connection must be done before it.
+}
+
+\ttt{STATUS \toindex{FtpPassword}(FTP~*, char~*password)}
+{
+ Sends \ts{password} to the server. The function \ts{FtpUser} must be called before it.
+}
+
+\ttt{STATUS \toindex{FtpAccount}(FTP~*, char~*account)}
+{
+ Sends a name of the account to the server. The name of the account is not standard
+ attribute for many systems, so this function is used very seldom.
+ The function \ts{FtpPassword} must be called before it.
+}
+
+\ttt{
+STATUS \toindex{FtpLogin}(FTP~**, char~*hostname, char~*user, char~*password, char~*account)}
+{
+ Executes functions \ts{FtpConnect}, \ts{FtpUser}, \ts{FtpPassword},
+ \ts{FtpAccount} (if necessary) consistently. If the name of the account is absent,
+ replaces it with the \ts{NULL} value.
+}
+
+\ttt{STATUS \toindex{FtpBye}(FTP~*)}
+{ Finishes work with the server and closes all channels.
+\footnote{You can see from the description of connect/disconnect functions, that you can create
+more than one connection to servers simultaneously.}
+}
+
+\ttt{STATUS \toindex{FtpQuickBye}(FTP~*)}
+{ Fast close data and command connection to server without delays for waiting
+server's confirmation and destroying the FTP object.
+}
+
+\ttt{STATUS \toindex{FtpAbort}(FTP~*)}
+{ Abort last command passed to server}
+
+
+\subsection{The debugging} \label{debug}
+
+There is a possibility to predefine few functions,
+such as:~\footnote{If the \ts{NULL} value is transferred as a parameter \ts{``function''} to the functions, described below,
+the handling will be turned off.}
+
+\ttt{\toindex{FtpSetDebugHandler}(FTP *,function)}
+{ Predefines function of protocol debugging.
+ After the function is predefined, it is called with every
+ sending/receiving messages from the server.
+ The function, defined as a debug handler must do returns to the calling
+functions (\ts{FtpSendMessage}/\ts{FtpGetMessage}), but can also abort the program.
+
+}
+
+\ttt{\toindex{FtpSetErrorHandler}(FTP *,function)}
+{
+ Predefines error handler. If the server's answer means, that the operation is not finished
+ correctly, this function will be called.
+ The result code is negative, if an error is occurs.
+}
+\ttt{\toindex{FtpSetIOHandler}(FTP *,function)}
+{
+ Predefines handler of Input/Output processing. This function is called, when a connection to the
+ server is broken. For example, when the network or the remote host is down. This handler also is
+ called after the \toindex{timeout} of one character waiting expires.
+}
+
+\ttt{\toindex{FtpDebug}(FTP *)}
+{
+Turns on all standard debugging functions.
+
+\tc{\toindex{FtpDebugError}}{--- prints a string, taken from the server, and aborts the program;}
+\tc{\toindex{FtpDebugDebug}}{--- prints a string, taken from the server;}
+\tc{\toindex{FtpDebugIO}}{--- prints string \ts{strerror(errno)} and aborts the program.}
+}
+
+\ttt{\toindex{FtpSetHashHandler}(FTP *,function)}
+{
+ Predefines handler of function which must compute traffic size. This
+function have only one argument which describe number of transferred bytes.
+If this argument is zero counter must be reset to zero.
+}
+
+
+All function for debugging have three arguments:\\
+1. Pointer to FTP data structure;\\
+2. Last returned value from the server. When errors occur, the value is less than 1;\\
+3. Diagnostic string.(char *)
+
+\ttt{\toindex{FtplibDebug}(yes|no)}
+{ Turns on/off autostart debug mode, when connection is established.
+}
+
+\ttt{\toindex{FtpLog}(char *name\_of\_log, char *message)}
+{ Print message to user's screen in libftp's standard format,
+ name\_of\_log must be your program name (if this function called
+from standard handlers then this string is title from FTP structure) and
+message with diagnostic string from anywhere.}
+
+
+\subsection{Data transfer procedures}
+
+\ttt{STATUS \toindex{FtpRetr}(FTP~*, char~*command, char~*inp, char~*out)}
+{
+ This is basically and single procedure in the library with transfer
+ file from the server. One check many option with customizing its style
+ of working. This options basically is members of FTP structure such
+ as timeout, all handlers, mode, seek. If in continue of working this
+ function happen timeout or network broked then this function
+ automatically called I/O handler which can restart this function
+ again or broken procedure. If handler is not set then FtpRetr return
+ status QUIT or LQUIT as signal of type of error (LQUIT is specify
+ error happen with local filesystem). \\
+ {\bf Warring!} All receive function described bellow working by
+ called this procedure and described rules is right for them.
+}
+
+\ttt{\toindex{FtpGet}(FTP~*, char~*in, char~*out)}
+{
+ Calls \ts{FtpRetr} with adaptation arguments to transfer file
+}
+
+\ttt{\toindex{FtpDirectory}(FTP~*, char~*pat\footnote{This is the first argument for \ts{``ls''} command}, char~*out)}
+{
+ Transfers files listing from the server, described by \ts{pat}, to the local file \ts{out}.
+}
+
+\ttt{\toindex{FtpDir}(FTP~*, char~*out)}
+{
+ Transfers files listing of the current directory from the server to the local file \ts{out}.
+}
+
+\ttt{\toindex{FtpStor}(FTP~*, char~*command, char~*inp, char*~out)}
+{
+ Store file to the server. Works like FtpRetr.
+}
+
+\ttt{\toindex{FtpPut}(FTP~*, char~*in, char~*out)}
+{
+ Calls \ts{FtpStor} adaptation arguments to transfer file
+}
+
+\ttt{\toindex{FtpCopy}(FTP~*ftp\_from, FTP~*ftp\_to, char~*in, char~*out)}
+{
+ Transfer file between two server without connection to client's host
+}
+
+\ttt{\toindex{FtpPassiveTransfer}(FTP~*ftp\_from, FTP~*ftp\_to, char~*in, char~*out)}
+{
+ Transfer file between two server via client's cache.
+}
+
+\subsection{Server's files read/write procedures}
+
+This library contains special functions for remote files reading and
+writing, without precopying them to local files. The functions,
+which are described below, do it. After the data channel
+to a remote file is created, it becomes possible to read and write
+ characters using standard Input/Output functions
+or using special functions \ts{FtpRead}/\ts{FtpWrite} and/or
+\ts{FtpGetc}/\ts{FtpPutc}, which reorganize stream for standard text file,
+under condition that the \ts{ASCII} mode is set.
+\footnote{Of course, such functions as \ts{seek}, \ts{ioctl}, ....
+can not be used.}
+
+\ttt{\toindex{FtpData}(FTP~*, char~*command, char~*param, char~*mode)}
+{ Makes data transfer channel, with presending command composed from \ts{command} and \ts{param}.
+The mode must be \ts{``r''} or \ts{``w''}}
+
+\ttt{\toindex{FtpOpenRead}(FTP~*,char~*filename)}
+{ Opens file named \ts{filename} for reading on server}
+
+\ttt{\toindex{FtpOpenWrite}(FTP~*,char~*filename)}
+{ Creats and opens file named \ts{filename} for writing on server}
+
+\ttt{\toindex{FtpOpenAppend}(FTP~*,char~*filename)}
+{ Creats and opens file named \ts{filename} for appending on server}
+
+\ttt{\toindex{FtpOpenDir}(FTP~*, char~*files)}
+{
+ Creats channel for directory list reading, described by argument \ts{files}.
+}
+
+\ttt{STATUS \toindex{FtpRead}(FTP~*)}{
+Reads character from data stream. If \ts{ASCII} mode is set\footnote{By default} converts new line markers.
+When the end of file is detected or channel is broken, returns \toindex{EOF}}
+
+\ttt{\toindex{FtpWrite}(FTP~*, char~c)}{
+Writes single character to stream, if \ts{ASCII} mode is set converts new line markers.
+When channel is broken, returns \toindex{EOF}}
+
+\ttt{int \toindex{FtpGetc}(FTP~*,FILE~*fp)}{
+Reads character from data stream specified by fp. Using macros FTPDATA and FTPCMD you can specify stream need for reading. \footnote{Functions FtpGetc and FtpPutc ignories data stream mode, works as binary always}
+}
+
+\ttt{STATUS \toindex{FtpPutc}(FTP~*,FILE~*fp, char c)}{
+Writes character to data stream specified by fp. Using macros FTPDATA and
+FTPCMD you can specify stream need for reading. \footnote{Functions
+FtpGetc and FtpPutc ignores data stream mode, works as binary always}
+}
+
+
+\ttt{\toindex{FtpClose}(FTP~*)}
+{Closes opened channel to server}
+
+\subsection{Other commands for server}
+
+\ttt{\toindex{FtpCommand}(FTP~*, char~*command, char~*param, int~ok1, ok2, ok3, ..., okN, EOF)}
+{ Sends a command, composed from \ts{command} and \ts{param} using \ts{sprintf} function.
+Reads an answer from the server.
+When return code from the server is not included to \ts{ok-list}(\ts{ok1},\ts{ok2}...) the sign of code
+will be inverted.}
+
+
+\ttt{\toindex{FtpType}(FTP~*,char~mode)}
+{Sets transfer mode, such as \ts{'A'},\ts{'I'},\ts{'S'},etc...}
+
+\ttt{\toindex{FtpBinary}(FTP~*)}
+{Sets binary mode}
+
+\ttt{\toindex{FtpAscii}(FTP~*)}
+{Sets \ts{ASCII} mode}
+
+
+\ttt{\toindex{FtpMkdir}(FTP~*,char *dirname)}
+{Makes directory on server}
+
+\ttt{\toindex{FtpChdir}(FTP~*,char *dirname)}
+{Changes working directory on server}
+
+\ttt{\toindex{FtpRm}(FTP~*,char *filename)}
+{Removes file on server}
+
+\ttt{char~*\toindex{FtpPwd}(FTP~*)}
+{Returns the name of working directory on server}
+
+\ttt{int \toindex{FtpSize}(FTP~*,char *filename)}
+{Returned size (in bytes) of description's file.}
+
+\ttt{\toindex{FtpMove}(FTP~*,char *oldfilename, char *newfilename)}
+{Renames file from \ts{oldfilename} to \ts{newfilename}}
+
+\ttt{\toindex{FtpPort}(FTP~*, int~a, int~b, int~c, int~d, int~e, int~f)
+\footnote{Recommended in non-trivial situations}
+}
+{ A command for the server for making a new data channel. \ts{a.b.c.d} is an IP address of a client(i.e. your IP address),
+\ts{e*256+f} is a port number}
+
+
+\ttt{struct hostent *\toindex{FtpGetHost}(char *hostname)
+\footnote{Extension of standard function ``gethostbyname''}
+}
+{Returned pointer to structure \ts{hostent} creating using string
+\ts{hostname}, which contains name of the computer or its IP
+address~\footnote{For example''dxunk8.oea.ihep.su'' or ``192.102.229.71''}
+}
+
+
+\subsection{Functions for sending/receiving control messages to/from server}
+
+\ttt{\toindex{FtpSendMessage}(FTP~*, char~*message)}
+{Sends a message to the server}
+
+\ttt{int \toindex{FtpGetMessage}(FTP~*)}
+{Receives a message from the server.}
+
+\ttt{\toindex{FtpMessage}(int Number)}
+{Gets a message by code.}
+
+\ttt{\toindex{FtpNumber}(char *Message)}
+{Extract message's number from string.}
+
+\subsection{High-level functions}
+
+\ttt{FILE *\toindex{FtpFullOpen}(char *filename,char *mode)}
+{
+Parses string \ts{filename}, which must contain a string in format or \\
+\ts{host/user/password:filename} or \ts{filename},
+what corresponds to remote or local file. The second argument is the type of opening, divided into two characters:
+first --- the mode of opening \ts{``r''}, \ts{``w''} or \ts{``a''}, second is the transfer type , if contains character \ts{``b''},
+ then the mode is binary.
+}
+
+\ttt{STATUS \toindex{FtpFullSyntax}(String source,String host,String user,String password,String file)}
+{Make out string ``source'' for next four parameters.}
+
+\ttt{FILE *\toindex{Ftpfopen}(char *file, char *mode)}
+{
+ Open file specified in libftp's file specification. Works like
+ \ts{fopen}. See description of libftp's file specification in the
+ top of paper.
+}
+
+\ttt{STATUS \toindex{Ftpfclose}(FILE *fp)}
+{
+ Close file which opened using Ftpfopen. Works like fclose.
+}
+
+\ttt{STATUS \toindex{FtpArchie}(char *what, ARCHIE *result, int number)}{
+Find \ts{number} entrys in archie's database enrolls described by \ts{what}
+argument. \ts{result} must be pointer to array of ARCHIE's structures number
+of which must be equivalence or higher than \ts{number}. This call return
+number of entrys which found in database. If FtpArchie return value lower
+than zero then pointed target not found or archie isn't works}
+
+
+\section{Example of using libftp}
+
+Next example demonstrate very simple using library calls only Ftpfopen
+and Ftpfclose functions which discriminate libftp's file specification:
+
+\input example
+
+For tests works this program you can try run one as:
+
+\bigskip
+
+\% example username/password@hostname:filename myfile.out
+
+\% example myfile.input username/password@hostname:filename.out
+
+
+\newpage
+\input libftp.ind
+\newpage
+\tableofcontents
+\end{document}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/libftp/doc/rus.tex b/lib/libftp/doc/rus.tex
new file mode 100644
index 0000000..2361c11
--- /dev/null
+++ b/lib/libftp/doc/rus.tex
@@ -0,0 +1,521 @@
+\documentstyle[russian,fancyheadings,twoside,epsf,indentfirst]{article}
+% Vertical sizes
+%\vsize=20cm
+%\voffset=-2.3cm
+%\topmargin=0cm
+%\headheight=0.9cm
+%\footskip=1cm
+%\footheight=0.9cm
+%\textheight=16cm
+%\headrulewidth 0.01cm
+%\footrulewidth 0.0cm
+% horisontal sizes
+%\hsize=30cm
+%\hoffset=-4.3cm
+%\hoffset=-2.3cm
+%\textwidth=13cm
+% Modes
+% \special{landscape}
+\pagestyle{empty}
+\pagestyle{fancyplain}
+\newcommand{\tit}[1]{#1}
+\rhead[\fancyplain{}{\tit{\leftmark}}]{\fancyplain{}{\tit{\rightmark}}}
+\lhead[\fancyplain{}{\tit{\rightmark}}]{\fancyplain{}{\tit{\leftmark}}}
+\chead{\hfill}
+\lfoot[\fancyplain{}{\tit{\thepage}}]{\fancyplain{}{\hfill}}
+\rfoot[\fancyplain{}{\hfill}]{\fancyplain{}{\tit{\thepage}}}
+\cfoot{\hfill}
+\renewcommand{\sectionmark}[1]{\markboth{#1}{\ }}
+\renewcommand{\subsectionmark}[1]{\markright{\ }}
+\newcommand{\look}[1]{(çÌÁ×Á~\ref{#1}, ÓÔÒ.~\pageref{#1})}
+\newcommand{\toindex}[1]{\underline{\bf#1}\index{#1}}
+\newcommand{\add}[1]{\symbol{64}}
+\newcommand{\ps}[1]{\symbol{37}s}
+\newcommand{\twcol}[4]{
+\noindent\parbox[t]{#1\textwidth}{#3} \hfill \parbox[t]{#2\textwidth}{#4\hfill}\\
+}
+\newcommand{\tc}[2]{\twcol{0.49}{0.49}{#1}{#2}}
+\newcommand{\tcc}[2]{\twcol{0.49}{0.49}{\toindex{#1}}{#2}}
+\newcommand{\ttt}[2]{\bigskip
+
+{\bf#1}
+
+#2}
+\newcommand{\ts}[1]{{\bf#1}}
+\newcommand{\dl}[2]{\parbox[t]{0.4\textwidth}{#1\hfill}\hfill
+ \parbox[t]{0.4\textwidth}{#2\hfill}}
+\makeindex
+\begin{document}
+\title{\bf\it òõëï÷ïäóô÷ï ðïìøúï÷áôåìñ âéâìéïôåëé "LIBFTP"}
+\author{ïÌÅÇ ïÒÅÌ}
+\date{\today}
+\newpage
+\maketitle
+
+\section*{ìÉÃÅÎÚÉÑ}
+
+ðÒÏÄÕËÔ ÐÒÅÄÎÁÚÎÁÞÅÎ ÄÌÑ ÎÁÐÉÓÁÎÉÑ Ó×ÏÂÏÄÎÏÇÏ ÎÅËÏÍÍÅÒÞÅÓËÏÇÏ ÐÒÏÇÒÁÍÍÎÏÇÏ
+ÏÂÅÓÐÅÞÅÎÉÑ. ïÎ ÍÏÖÅÔ ÉÓÐÒÁ×ÌÑÔØÓÑ É ÄÏÐÉÓÙ×ÁÔØÓÑ.
+á×ÔÏÒ ÂÕÄÅÔ ÂÌÁÇÏÄÁÒÅÎ ÚÁ ÐÏÌÕÞÅÎÉÅ ÓÏ×ÅÔÏ×, ÎÏ×ÙÈ ËÏÍÐÏÎÅÎÔ É ÐÒÁ×ÏË
+ÓÕÝÅÓÔ×ÕÀÝÉÈ ÐÏÄÐÒÏÇÒÁÍÍ.
+
+ëÏÍÍÅÒÞÅÓËÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÜÔÏÊ ÂÉÂÌÉÏÔÅËÉ ×ÏÚÍÏÖÎÏ Ó ÐÒÉ×ÌÅÞÅÎÉÅÍ
+Å\"Å Á×ÔÏÒÁ.
+
+\section*{ðÒÉÞÉÎÙ ÓÏÚÄÁÎÉÑ É ÉÓÔÏÒÉÑ ÒÁÚ×ÉÔÉÑ}
+
+äÌÑ ÌÀÄÅÊ, ËÏÔÏÒÙÅ ÈÏÔÑ ÂÙ ÏÄÉÎ ÒÁÚ ÐÉÓÁÌÉ ÐÒÏÇÒÁÍÍÕ Ó ÉÓÐÏÌØÚÏ×ÁÎÉÅÍ
+ÓÉÓÔÅÍÎÙÈ ×ÙÚÏ×Ï× ÔÉÐÁ socket, connect, bind.... ÎÅ ÓÅËÒÅÔ, ÞÔÏ ÐÏÞÔÉ ×ÓÅÇÄÁ
+ÐÏÓÌÅÄÏ×ÁÔÅÌØÎÏÓÔØ ×ÙÚÏ×Ï× ÆÕÎËÃÉÊ ÄÌÑ ÓÏÚÄÁÎÉÑ ÓÏÅÄÉÎÅÎÉÑ ÐÏ ÐÒÏÔÏËÏÌÕ TCP ÏÄÎÁ É ÔÁ ÖÅ. ïÔÓÀÄÁ ×ÏÚÎÉËÁÅÔ ÒÅÚÏÎÎÙÊ
+×ÏÐÒÏÓ ``á ÐÏÞÅÍÕ ÓÏÂÓÔ×ÅÎÎÏ ÎÅ ÉÍÅÔØ ÂÉÂÌÉÏÔÅËÉ ÂÏÌÅÅ ×ÙÓÏËÏÇÏ
+ÕÒÏ×ÎÑ, ÄÌÑ ÕÐÒÏÝÅÎÉÑ ÐÒÏÃÅÓÓÁ ÐÒÏÇÒÁÍÍÉÒÏ×ÁÎÉÑ?''.
+üÔÏ ÐÏÓÌÕÖÉÌÏ ÐÒÉÞÉÎÏÊ ÓÏÚÄÁÎÉÑ \ts{libftp}.
+
+ðÏÓÌÅ ÒÅÁÌÉÚÁÃÉÉ ``ÎÉÖÎÅÊ'' ÞÁÓÔÉ ÂÉÂÌÉÏÔÅËÉ, ÂÙÌÉ ÓÏÚÄÁÎÙ
+ÆÕÎËÃÉÉ ÂÏÌÅÅ ×ÙÓÏËÏÇÏ ÕÒÏ×ÎÑ, ÔÁËÉÅ ËÁË
+ÐÅÒÅÄÁÞÁ ÃÅÌÏÇÏ ÆÁÊÌÁ ÉÌÉ ÞÔÅÎÉÅ ÓÐÉÓËÁ ÆÁÊÌÏ×. ðÒÉ ÎÁÐÉÓÁÎÉÉ
+ÜÔÉÈ ÐÒÏÃÅÄÕÒ ×ÏÚÎÉËÌÁ ÎÅÏÂÈÏÄÉÍÏÓÔØ ÕÄÏÂÎÏÊ ÏÔÌÁÄËÉ ÓÂÏÊÎÙÈ ÓÌÕÞÁÅ×,
+ÄÌÑ ÏÓ×ÏÂÏÖÄÅÎÉÑ ÐÒÏÇÒÁÍÍÙ ÏÔ ÂÅÓËÏÎÅÞÎÏÇÏ ÞÉÓÌÁ ÕÓÌÏ×ÉÊ
+(ÏÂÒÁÂÏÔËÁ ×ÏÚ×ÒÁÝÁÅÍÏÇÏ
+ÂÉÂÌÉÏÔÅÞÎÙÍÉ ÆÕÎËÃÉÑÍÉ ÓÔÁÔÕÓÁ).
+äÌÑ ÜÔÏÇÏ ÂÙÌ ÓÏÚÄÁÎ ÍÁËÒÏÓ \ts{EXIT}, ËÏÔÏÒÙÊ ÐÒÉ ×ÏÚ×ÒÁÔÅ ÆÕÎËÃÉÑÍÉ ÓÔÁÔÕÓÁ,
+ÐÒÏ×ÅÒÑÅÔ ÅÇÏ, É × ÓÌÕÞÁÅ ÎÅÏÂÈÏÄÉÍÏÓÔÉ ×ÙÚÙ×ÁÅÔ ÚÁÒÁÎÅÅ ÕÓÔÁÎÏ×ÌÅÎÎÙÅ
+ÆÕÎËÃÉÉ.
+
+ðÒÉ ÐÅÒÅÄÁÞÉ ÆÁÊÌÏ× ÐÏ ÓÅÔÉ, ËÏÔÏÒÁÑ × ÏÓÎÏ×ÎÏÍ ÓÏÓÔÏÉÔ ÉÚ dialup-slip'Ï×
+(ÔÉÐÉÞÎÁÑ ÓÉÔÕÁÃÉÑ ÄÌÑ exUSSR)
+ÞÁÓÔÏ ×ÏÚÎÉËÁÀÔ ÓÉÔÕÁÃÉÉ ``ÐÏÌÏÍËÉ ÓÅÔÉ'' É ÆÁÊÌ ÂÏÌØÛÏÇÏ ÒÁÚÍÅÒÁ ÐÅÒÅÄÁÔØ
+ÓÔÁÎÏ×ÉÔÓÑ ÐÒÁËÔÉÞÅÓËÉ ÎÅ×ÏÚÍÏÖÎÏ\footnote{ëÏÎÅÞÎÏ ÍÏÖÎÏ ÐÅÒÉÏÄÉÞÅÓËÉ
+ÚÁÐÕÓËÁÔØ ftp, É ÇÏ×ÏÒÉÔØ × ÎÅÍ ``reget filename''}, ÜÔÏ ÐÏÓÌÕÖÉÌÏ ÐÒÉÞÉÎÏÊ
+ÎÁÐÉÓÁÎÉÑ ÐÒÏÇÒÁÍÍÙ \toindex{ftptry}\footnote{ðÒÏÇÒÁÍÍÁ \ts{ftptry} ÂÕÄÅÔ ÏÐÉÓÁÎÁ ÎÉÖÅ} Ó ÉÓÐÏÌØÚÏ×ÁÎÉÅÍ ÂÉÂÌÉÏÔÅËÉ libftp.
+äÌÑ Å\"Å ÒÅÁÌÉÚÁÃÉÉ × ÂÉÂÌÉÏÔÅËÕ ÂÙÌÉ ÄÏÂÁ×ÌÅÎÙ ÆÕÎËÃÉÉ
+\toindex{FtpRestorTimeout} É \toindex{FtpReretrTimeout},
+ËÏÔÏÒÙÅ × ÏÔÌÉÞÉÉ ÏÔ ÆÕÎËÃÉÊ \ts{FtpStorTimeout} É \ts{FtpRetrTimeout}
+ÎÅ ÐÅÒÅÄÁÀÔ Á ÄÏËÁÞÉ×ÁÀÔ ÆÁÊÌÙ.
+
+\section*{îÅÄÏÓÔÁÔËÉ - ÄÌÑ ÉÓÐÒÁ×ÌÅÎÉÑ × ÓÌÅÄÕÀÝÉÈ ×ÅÒÓÉÑÈ}
+
+\begin{itemize}
+
+\item ÷ ÐÒÏÃÅÄÕÒÁÈ ÞÔÅÎÉÑ ÐÏÔÏËÁ ÉÚ socket'Ï× ÉÓÐÏÌØÚÕÅÔÓÑ ÍÅÈÁÎÉÚÍÙ
+setjmp-longjmp, alarm+SIGALRM, SIGIO, ËÏÔÏÒÙÅ ÂÕÄÕÔ ÚÁÍÅÎÅÎÙ ÎÁ select.
+üÔÏÔ ÎÅÄÏÓÔÁÔÏË (ÉÓÐÏÌØÚÏ×ÁÎÉÅ SIGALRM) ÐÒÏÑ×ÌÑÅÔÓÑ ÐÒÉ ÒÁÂÏÔÅ Ó X11
+\footnote{ÔÁÍ ÔÏÖÅ ÉÓÐÏÌØÚÕÅÔÓÑ alarm}
+
+\item ðÅÒÅÍÅÎÎÁÑ FtpDataStart\footnote{ó ËÁËÏÇÏ ÂÁÊÔÁ ÐÅÒÅÄÁ×ÁÔØ ÆÁÊÌÙ} ÎÅ ÐÒÉÎÁÄÌÅÖÉÔ ÓÔÒÕËÔÕÒÅ FTP, Á Ñ×ÌÑÅÔÓÑ ÏÂÛÅÊ ÄÌÑ ×ÓÅÈ.
+
+\item ïÔÓÕÔÓÔ×ÉÅ ÒÁÂÏÔÙ Ó \toindex{site-specific} ftpd ËÏÍÁÎÄÁÍÉ
+\end{itemize}
+
+\section*{éÄÅÉ ÄÌÑ ÄÁÌØÎÅÊÛÉÈ ÒÅÁÌÉÚÁÃÉÉ}
+
+\begin{itemize}
+
+\item òÁÚÒÁÂÏÔËÁ ÐÒÏÇÒÁÍÍÙ ÄÕÂÌÉÒÏ×ÁÎÉÑ ÄÅÒÅ×Á
+ÄÉÒÅËÔÏÒÉÊ ÏÄÎÏÊ ÍÁÛÉÎÙ ÎÁ ÄÒÕÇÕÀ. \footnote{òÁÚÒÁÂÏÔËÁ ÉÄÅÔ × ÄÁÎÎÙÊ ÍÏÍÅÎÔ}
+
+\item òÁÚÒÁÂÏÔËÁ ÉÎÔÅÒÆÅÊÓÁ × ÏËÒÕÖÅÎÉÉ X-window's ÄÌÑ ÍÁÎÉÐÕÌÑÃÉÉ
+ÆÁÊÌÁÍÉ ÎÁÈÏÄÑÝÉÈÓÑ ÎÁ ÒÁÚÎÙÈ ÍÁÛÉÎÁÈ Ó ×ÏÚÍÏÖÎÏÓÔØÀ ÎÅÉÎÔÅÒÁËÔÉ×ÎÏÊ ÐÅÒÅÄÁÞÉ
+(ÄÌÑ ÍÅÄÌÅÎÎÙÈ ÓÅÔÅÊ)
+
+\item óÏÚÄÁÎÉÅ ÍÕÌØÔÉÐÌÅËÓÉÒÕÀÝÅÇÏ ÁÐÐÁÒÁÔÁ ÄÌÑ ÏÄÎÏ×ÒÅÍÅÎÎÏÊ
+ÏÂÒÁÂÏÔËÉ ÎÅÓËÏÌØËÉÈ ÐÏÔÏËÏ× ÄÁÎÎÙÈ.
+
+\item óÏÚÄÁÎÉÅ ÏÂßÅËÔÁ FTP ÄÌÑ C++
+
+\end{itemize}
+
+\section*{÷×ÅÄÅÎÉÅ}
+
+âÉÂÌÉÏÔÅËÁ ``libftp'' ÐÒÅÄÎÁÚÎÁÞÅÎÁ ÄÌÑ ÎÁÐÉÓÁÎÉÑ ÐÒÉËÌÁÄÎÙÈ ÐÒÏÇÒÁÍÍ × ËÏÔÏÒÙÈ
+ÓÕÝÅÓÔ×ÕÅÔ ÎÅÏÂÈÏÄÉÍÏÓÔØ ÐÅÒÅÄÁ×ÁÔØ ÆÁÊÌÙ ÐÏ ÓÅÔÉ TCP/IP. OÎÁ
+Ñ×ÌÑÅÔÓÑ ÎÁÂÏÒÏÍ ÆÕÎËÃÉÊ ÎÁÞÉÎÁÑ ÏÔ ÐÒÉÍÉÔÉ×ÎÙÈ ÆÕÎËÃÉÊ, ÔÁËÉÈ ËÁË ÏÔËÒÙÔÉÅ ÓÏÅÄÉÎÅÎÉÑ ÐÏ ÐÒÏÔÏËÏÌÕ FTP ÎÁ ÕÄÁÌÅÎÎÕÀ ÍÁÛÉÎÕ, ÄÏ ÆÕÎËÃÉÊ ×ÙÓÏËÏÇÏ ÕÒÏ×ÎÑ, ËÏÔÏÒÙÅ ÐÅÒÅÄÁÀÔ
+ÆÁÊÌÙ ÓÁÍÉ ÐÒÏÉÚ×ÏÄÑ ÓÏÅÄÉÎÅÎÉÅ/ÒÁÚßÅÄÉÎÅÎÉÅ Ó ÓÅÒ×ÅÒÏÍ.
+÷ÓÅ ÆÕÎËÃÉÉ ÉÍÅÀÔ ÐÒÏÔÏÔÉÐÙ × ÆÁÊÌÅ \toindex{FtpLibrary.h},
+ËÏÔÏÒÙÊ ÄÏÌÖÅÎ ÂÙÔØ ÐÏÍÅÝÅÎ
+× ËÁÔÁÌÏÇ ÓÔÁÎÄÁÒÔÎÙÈ ÚÁÇÏÌÏ×ËÏ×\footnote{îÁÐÒÉÍÅÒ /usr/include}.
+üÔÉ ÐÒÏÔÏÔÉÐÙ ÐÒÁËÔÉÞÅÓËÉ ÐÏÌÎÏÓÔØÀ ÏÐÉÓÙ×ÁÀÔ
+ÎÁÚÎÁÞÅÎÉÅ ÆÕÎËÃÉÊ É ÉÈ ÁÒÇÕÍÅÎÔÙ, ÎÏ ÔÅÍ ÎÅ ÍÅÎÅÅ ÎÅÏÂÈÏÄÉÍÏ ÓËÁÚÁÔØ ÏÂ ÏÂÝÅÊ ÉÄÅÏÌÏÇÉÉ
+ÐÏÓÔÒÏÅÎÉÑ ÂÉÂÌÉÏÔÅËÉ É ÅÅ ËÏÍÐÏÎÅÎÔ.
+
+÷ÓÑ ÂÉÂÌÉÏÔÅËÁ, Ñ×ÌÑÑÓØ ËÌÉÅÎÔÏÍ, ÉÓÐÏÌØÚÕÅÔ
+Ó ÐÒÏÔÉ×ÏÐÏÌÏÖÎÏÊ ÓÔÏÒÏÎÙ ÓÏÅÄÉÎÅÎÉÑ ÓÔÁÎÄÁÒÔÎÙÊ \toindex{FTPD}
+\footnote{äÌÑ ÒÁÂÏÔÙ ÆÕÎËÃÉÊ FtpRertrTimeout, FtpRestorTimeout ÎÅÏÂÈÏÄÉÍÏ
+ÞÔÏÂÙ ÓÅÒ×ÅÒ ÏÔÒÁÂÁÔÙ×ÁÌ ËÏÍÁÎÄÕ REST}.
+
+÷Ï ÍÎÏÇÉÈ ÏÐÅÒÁÃÉÏÎÎÙÈ ÓÉÓÔÅÍÁÈ ÓÕÝÅÓÔ×ÕÅÔ ÐÒÏÂÌÅÍÁ ÏÂÒÁÂÏÔËÉ
+ÒÁÚÎÏÇÏ ÒÏÄÁ ÏÛÉÂÏË, × ÔÏÍ ÞÉÓÌÅ ÏÛÉÂÏË
+××ÏÄÁ/×Ù×ÏÄÁ, × ÄÁÎÎÏÍ ÉÎÓÔÒÕÍÅÎÔÁÒÉÉ ÉÓÐÏÌØÚÏ×ÁÎ ÅÄÉÎÙÊ ÍÅÈÁÎÉÚÍ ×ÏÚ×ÒÁÔÁ
+ÒÅÚÕÌØÔÁÔÁ ÒÁÂÏÔÙ ÌÀÂÏÊ ÆÕÎËÃÉÉ (ÍÁËÒÏËÏÍÁÎÄÁ \ts{EXIT}, ÏÐÒÅÄÅÌÅÎÎÁÑ × \ts{FtpLibrary.h})
+ËÏÔÏÒÙÊ ÐÏÚ×ÏÌÑÅÔ
+ÐÒÅÄ×ÁÒÉÔÅÌØÎÏ ÕÓÔÁÎÏ×É× Ó×ÏÉ ÉÌÉ ÓÔÁÎÄÁÒÔÎÙÅ ÆÕÎËÃÉÉ ÏÂÒÁÂÏÔËÉ
+ÏÛÉÂÏË É ÆÕÎËÃÉÉ
+ÏÔÌÁÄËÉ, ÐÉÓÁÔØ ÓÍÙÓÌÏ×ÕÀ ÞÁÓÔØ ÐÒÏÇÒÁÍÍÙ, ÄÕÍÁÑ ÔÏÌØËÏ Ï ÅÅ ÍÅÔÏÄÅ ÒÁÂÏÔÙ
+× ÉÄÅÁÌØÎÙÈ ÕÓÌÏ×ÉÑÈ. ÷ ÆÕÎËÃÉÑÈ ÐÅÒÅÄÁÞÉ ÄÁÎÎÙÈ × ÏÂÅ ÓÔÏÒÏÎÙ ÓÕÝÅÓÔ×ÕÅÔ
+×ÏÚÍÏÖÎÏÓÔØ ÕÓÔÁÎÏ×ÉÔØ ÍÁËÓÉÍÁÌØÎÏÅ ×ÒÅÍÑ ÏÖÉÄÁÎÉÑ ÐÏÔÏËÁ ÄÁÎÎÙÈ, ÐÏ ÉÓÔÅÞÅÎÉÉ ËÏÔÏÒÏÇÏ, ×ÏÚÍÏÖÎÏ ×ÙÚ×ÁÔØ ÏÐÒÅÄÅÌÅÎÎÕÀ ÐÒÏÃÅÄÕÒÕ.
+
+
+ðÒÉ ÒÁÂÏÔÅ Ó ÂÉÂÌÉÏÔÅËÏÊ, ÐÅÒ×ÏÊ ×ÓÅÇÄÁ ×ÙÚÙ×ÁÅÔÓÑ ÐÒÏÃÅÄÕÒÁ
+ÓÏÅÄÉÎÅÎÉÑ Ó ÓÅÒ×ÅÒÏÍ\footnote{úÁ ÉÓËÌÀÞÅÎÉÅÍ FtplibDebug} (\ts{FtpLogin} ÉÌÉ \ts{FtpConnect})
+ËÏÔÏÒÁÑ ×ÏÚ×ÒÁÝÁÅÔ ÕËÁÚÁÔÅÌØ ÎÁ ×ÎÏ×Ø ÓÏÚÄÁÎÎÕÀ ÓÔÒÕËÔÕÒÕ ÄÁÎÎÙÈ (ÔÉÐÁ \ts{FTP})
+Ï ÓÏÅÄÉÎÅÎÉÉ Ó ÓÅÒ×ÅÒÏÍ.
+
+
+
+
+\section{óÔÒÕËÔÕÒÁ ÄÁÎÎÙÈ FTP}
+
+
+\tc{int \toindex{sock}}{--- ÄÅÓËÒÉÐÔÏÒ ËÁÎÁÌÁ ÐÅÒÅÄÁÞÉ ËÏÍÁÎÄ ÎÁ ÓÅÒ×ÅÒ;}
+\tc{FILE *\toindex{data}}{--- ÏÐÉÓÁÎÉÅ ËÁÎÁÌÁ ÄÌÑ ÐÅÒÅÄÁÞÉ ÄÁÎÎÙÈ ÎÁ ÓÅÒ×ÅÒ;}
+\tc{int \toindex{errno}}{ --- ÚÎÁÞÅÎÉÅ ÐÏÓÌÅÄÎÅÇÏ ×ÏÚ×ÒÁÝÅÎÎÏÇÏ ÂÉÂÌÉÏÔÅËÏÊ ÚÎÁÞÅÎÉÑ.
+ ÷ ÓÌÕÞÁÅ ÅÓÌÉ ÏÎÏ ÏÔÒÉÃÁÔÅÌØÎÏ ÉÌÉ ÒÁ×ÎÏ ÎÕÌÀ,
+ ÔÏ ÐÒÏÉÚÏÛÌÁ ÏÛÉÂËÁ;}
+\tc{char \toindex{mode}}{--- ÔÉÐ ÐÅÒÅÄÁÞÉ ÄÁÎÎÙÈ;}
+\tc{int ch}{--- ×ÓÐÏÍÏÇÁÔÅÌØÎÁÑ ÐÅÒÅÍÅÎÎÁÑ ÉÓÐÏÌØÚÕÅÍÁÑ ÄÌÑ ÐÒÅÏÂÒÁÚÏ×ÁÎÉÑ
+ ÐÏÔÏËÁ × ÒÅÖÉÍÅ ÐÅÒÅÄÁÞÉ ÔÅËÓÔÏ×ÙÈ ÆÁÊÌÏ×;}
+\tc{STATUS (*func)()}{--- ÁÄÒÅÓ ÆÕÎËÃÉÉ, ËÏÔÏÒÁÑ ×ÙÚÙ×ÁÅÔÓÑ × ÓÌÕÞÁÅ ËÏÇÄÁ ÏÔ ÓÅÒ×ÅÒÁ
+ ÐÏÌÕÞÅÎ ÏÔ×ÅÔ Ï ÏÛÉÂËÅ;}
+\tc{STATUS (*debug)()}{--- ÁÄÒÅÓ ÆÕÎËÃÉÉ, ËÏÔÏÒÁÑ ×ÙÚÙ×ÁÅÔÓÑ ÄÌÑ ÏÔÌÁÄËÉ ÐÒÏÔÏËÏÌÁ;}
+\tc{STATUS (*IO)()}{--- ÆÕÎËÃÉÑ ×ÙÚÙ×ÁÅÍÁÑ × ÓÌÕÞÁÅ ÐÏÔÅÒÉ Ó×ÑÚÉ Ó ÓÅÒ×ÅÒÏÍ, ÉÌÉ
+ ÐÏ ÉÓÔÅÞÅÎÉÀ ÍÁËÓÉÍÁÌØÎÏÇÏ ×ÒÅÍÅÎÉ ÎÁ ÐÒÉÅÍ/ÐÅÒÅÄÁÞÕ ÏÄÎÏÇÏ
+ ÓÉÍ×ÏÌÁ.}
+
+
+\section{ ðÒÏÃÅÄÕÒÙ ÓÏÅÄÉÎÅÎÉÑ/ÒÁÚßÅÄÉÎÅÎÉÑ Ó ÓÅÒ×ÅÒÏÍ}
+
+\ttt{STATUS \toindex{FtpConnect}(FTP~**, char~*hostname
+\footnote{éÍÑ ÍÁÛÉÎÙ ÍÏÖÅÔ ÂÙÔØ ËÁË ÓÉÍ×ÏÌØÎÏÅ ÔÁË É ÃÉÆÒÏ×ÏÅ, ÎÁÐÒÉÍÅÒ
+\ts{dxcern.cern.ch} ÉÌÉ \ts{128.141.201.96}}
+)}
+{
+ óÏÚÄÁÅÔ ËÁÎÁÌ ÓÏÅÄÉÎÅÎÉÑ Ó ÓÅÒ×ÅÒÏÍ, ÎÁÈÏÄÑÝÉÍÓÑ ÎÁ ÍÁÛÉÎÅ hostname,
+ É ÓÏÚÄÁÅÔ ÓÔÒÕËÔÕÒÕ FTP, ×ÏÚ×ÒÁÝÁÑ ÎÁ ÎÅÅ ÕËÁÚÁÔÅÌØ. åÓÌÉ ÐÒÅÄ×ÁÒÉÔÅÌØÎÏ
+ ÂÙÌÁ ×ÙÐÏÌÎÅÎÁ ÐÒÏÃÅÄÕÒÁ \toindex{FtplibDebug}(1),
+ ÔÏ ÄÏ ÓÏÅÄÉÎÅÎÉÑ Ó ÓÅÒ×ÅÒÏÍ ×ËÌÀÞÁÅÔ ÓÔÁÎÄÁÒÔÎÙÅ
+ ÐÏÄÐÒÏÇÒÁÍÍÙ ÏÂÒÁÂÏÔËÉ ÏÛÉÂÏË \toindex{FtpDebugDebug}, \toindex{FtpDebugError},
+ \toindex{FtpDebugIO} \look{debug}.
+}
+\ttt{STATUS \toindex{FtpUser}(FTP~*, char~*user)}
+{
+ ðÏÓÙÌÁÅÔ ÓÅÒ×ÅÒÕ ÉÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ. òÁÎÅÅ ÄÏÌÖÎÏ ÂÙÌÏ ÂÙÔØ ÐÒÏÉÚ×ÅÄÅÎÏ ÓÏÅÄÉÎÅÎÉÅ
+}
+
+\ttt{STATUS \toindex{FtpPassword}(FTP~*, char~*password)}
+{
+ ðÏÓÙÌÁÅÔ ÓÅÒ×ÅÒÕ ÐÁÒÏÌØ. òÁÎÅÅ ÄÏÌÖÎÁ ÂÙÌÁ ÂÙÔØ ×ÙÐÏÌÎÅÎÁ ÐÒÏÃÅÄÕÒÁ \ts{FtpUser}
+}\ttt{STATUS \toindex{FtpAccount}(FTP~*, char~*acct)}
+{
+ ðÏÓÙÌÁÅÔ ÓÅÒ×ÅÒÕ ÉÍÑ account'a üÔÁ ÆÕÎËÃÉÑ ÓÄÅÌÁÎÁ ÄÌÑ ÐÏÌÎÏÇÏ ÓÏÏÔ×ÅÔÓÔ×ÉÑ
+ ÂÉÂÌÉÏÔÅËÉ ÐÒÏÔÏËÏÌÕ \ts{FTP}, ÎÏ Ô.Ë. ÍÁÌÏ ÔÁËÉÈ ÏÐÅÒÁÃÉÏÎÎÙÈ ÓÉÓÔÅÍ × ËÏÔÏÒÙÈ ÎÅÏÂÈÏÄÉÍ ÜÔÏÔ
+ ÁÔÒÉÂÕÔ ÐÏÌØÚÏ×ÁÔÅÌÑ ÔÏ ÆÕÎËÃÉÑ \ts{FtpAccount} × ÏÂÝÅÍ ÔÏ ÎÅ ÎÕÖÎÁ.
+ ðÒÅÄ×ÁÒÉÔÅÌØÎÏ ÄÏÌÖÎÁ ÂÙÌÁ ÂÙÔØ ×ÙÐÏÌÎÅÎÁ ÐÒÏÃÅÄÕÒÁ
+ \ts{FtpUser}.
+}
+
+\ttt{
+STATUS \toindex{FtpLogin}(FTP~**, char~*hostname, char~*user, char~*password, char~*account)}
+{
+ ðÏÓÌÅÄÏ×ÁÔÅÌØÎÏ ×ÙÐÏÌÎÑÅÔ ÐÒÏÃÅÄÕÒÙ \ts{FtpConnect}, \ts{FtpUser}, \ts{FtpPassword}, \ts{FtpAccount}
+(ÅÓÌÉ ÐÁÒÁÍÅÔÒ account ÒÁ×ÅÎ NULL, ÔÏ ÐÒÏÃÅÄÕÒÁ FtpAccount ÎÅ ×ÙÚÙ×ÁÅÔÓÑ)}
+
+\ttt{STATUS \toindex{FtpBye}(FTP~*)}
+{ úÁ×ÅÒÛÁÅÔ ÓÅÁÎÓ ÒÁÂÏÔÙ Ó ÓÅÒ×ÅÒÏÍ \footnote{ëÁË ×ÉÄÎÏ ÉÚ ÏÐÉÓÁÎÉÑ ÐÒÏÃÅÄÕÒ ÓÏÅÄÉÎÅÎÉÑ/ÒÁÚßÅÄÉÎÅÎÉÑ ÉÚ ÏÄÎÏÊ ÐÒÏÇÒÁÍÍÙ ÍÏÖÎÏ ÏÄÎÏ×ÒÅÍÅÎÎÏ ÓÏÅÄÉÎÑÔÓÑ Ó ÎÅÓËÏÌØËÉÍÉ ÓÅÒ×ÅÒÁÍÉ} }
+
+
+
+
+\section{ðÒÏÃÅÄÕÒÙ ÏÔÌÁÄËÉ ÐÒÏÇÒÁÍÍÙ} \label{debug}
+
+óÕÝÅÓÔ×ÕÅÔ ×ÏÚÍÏÖÎÏÓÔØ ÐÒÅÄ×ÁÒÉÔÅÌØÎÏ ÏÐÒÅÄÅÌÉÔØ ÔÒÉ
+ÐÒÏÃÅÄÕÒÙ:~\footnote{åÓÌÉ × ÌÀÂÕÀ ÉÚ ÆÕÎËÃÉÊ, ÏÐÉÓÁÎÎÙÈ ÎÉÖÅ, ×ÍÅÓÔÏ ÐÁÒÁÍÅÔÒÁ function ÐÅÒÅÄÁÔØ ÚÎÁÞÅÎÉÅ \ts{NULL}, ÔÏ ÜÔÏ ÂÕÄÅÔ ÏÚÎÁÞÁÔØ
+ÏÔËÌÀÞÅÎÉÅ ÏÔÌÁÄËÉ. ðÒÉ ÏÔËÌÀÞÅÎÎÏÊ ÏÔÌÁÄËÅ ÒÅÚÕÌØÔÁÔ ÒÁÂÏÔÙ ÍÏÖÎÏ
+ÏÐÒÅÄÅÌÉÔØ ÉÌÉ ÖÅ ÐÏ ×ÏÚ×ÒÁÝÁÅÍÏÍÕ ÆÕÎËÃÉÅÊ ÚÎÁÞÅÎÉÀ (åÓÌÉ ÏÎÁ ÔÉÐÁ \toindex{STATUS}) ÉÌÉ
+ÐÏ ÐÅÒÅÍÅÎÎÏÊ errno × ÓÔÒÕËÔÕÒÅ \ts{FTP}}
+
+\ttt{\toindex{FtpSetDebugHandler}(FTP *,function)}
+{ õÓÔÁÎÁ×ÌÉ×ÁÅÔ ÐÒÏÃÅÄÕÒÕ ÏÔÌÁÄËÉ ÐÒÏÔÏËÏÌÁ Ó ÕÄÁÌÅÎÎÙÍ ÓÅÒ×ÅÒÏÍ.
+ åÓÌÉ ÅÅ ÏÐÒÅÄÅÌÉÔØ, ÔÏ ÏÎÁ ×ÓÅÇÄÁ ÂÕÄÅÔ ×ÙÚÙ×ÁÅÔÓÑ ÉÚ ÓÔÁÎÄÁÒÔÎÏÊ ÆÕÎËÃÉÉ
+ ÐÒÉÅÍÁ/ÐÅÒÅÄÁÞÉ ÓÏÏÂÝÅÎÉÑ Ó/ÎÁ ÓÅÒ×ÅÒÁ. äÏÌÖÎÁ ÄÅÌÁÔØ ×ÏÚ×ÒÁÔ, ÎÏ × ÐÒÉÎÃÉÐÅ
+ ÉÍÅÅÔ ÐÏÌÎÏÅ ÐÒÁ×Ï ÐÒÅÒÙ×ÁÔØ ×ÙÐÏÌÎÅÎÉÅ ÐÒÏÇÒÁÍÍÙ × ÓÌÕÞÁÅ ÎÅÏÂÈÏÄÉÍÏÓÔÉ.
+}
+
+\ttt{\toindex{FtpSetErrorHandler}(FTP *,function)}
+{
+ ïÐÒÅÄÅÌÑÅÔ ÆÕÎËÃÉÀ ÏÂÒÁÂÏÔËÉ ÏÛÉÂÏË.
+ ðÏÓÌÅ ÅÅ ÏÐÒÅÄÅÌÅÎÉÑ, × ÓÌÕÞÁÅ ×ÏÚ×ÒÁÝÅÎÉÑ ÓÅÒ×ÅÒÏÍ
+ ÎÅÕÄÏ×ÌÅÔ×ÏÒÉÔÅÌØÎÏÇÏ ÏÔ×ÅÔÁ, ÂÕÄÅÔ ×ÙÚÙ×ÁÔØÓÑ ÕËÁÚÁÎÎÁÑ ÆÕÎËÃÉÑ.
+ ðÒÉ ÜÔÏÍ ÚÎÁË Õ ËÏÄÁ ÏÛÉÂËÉ ÍÅÎÑÅÔÓÑ ÎÁ '-', É Ô.Ï. ÒÅÚÕÌØÔÁÔ
+ ÓÔÁÎÏ×ÉÔÓÑ ÍÅÎØÛÅ ÎÕÌÑ.
+}
+\ttt{\toindex{FtpSetIOHandler}(FTP *,function)}
+{
+ ïÐÒÅÄÅÌÅÎÉÅ ÆÕÎËÃÉÉ ÏÂÒÁÂÏÔËÉ ÏÛÉÂÏË ××ÏÄÁ/×Ù×ÏÄÁ.
+ ðÒÉ ÐÅÒÅÄÁÞÅ ÄÁÎÎÙÈ ÉÌÉ ËÏÍÁÎÄ ÎÁ ÓÅÒ×ÅÒ, ÍÏÖÅÔ ×ÏÚÎÉËÎÕÔØ ÓÉÔÕÁÃÉÑ ËÏÇÄÁ
+ Ó×ÑÚØ Ó ÓÅÒ×ÅÒÏÍ ÂÕÄÅÔ ÐÏÔÅÒÑÎÁ (ÓÀÄÁ ×ÈÏÄÑÔ ÐÒÁËÔÉÞÅÓËÉ ×ÓÅ ÓÂÏÉ ÓÅÔÉ
+ É ÓÂÏÉ ÐÒÉ ÒÁÂÏÔÅ ÓÅÒ×ÅÒÁ ÎÁ ÕÄÁÌÅÎÎÏÊ ÍÁÛÉÎÅ) ÐÒÉ ÜÔÏÍ ÂÕÄÅÔ ×ÙÚ×ÁÎÁ
+ ÕËÁÚÁÎÎÁÑ ÆÕÎËÃÉÑ. ïÎÁ ×ÙÚÙ×ÁÅÔÓÑ ÔÁË ÖÅ ÐÏ ÉÓÔÅÞÅÎÉÀ
+ ÍÁËÓÉÍÁÌØÎÏÇÏ ×ÒÅÍÅÎÉ ÐÒÉ ÏÖÉÄÁÎÉÉ ÏÞÅÒÅÄÎÏÇÏ ÓÉÍ×ÏÌÁ Ó ÓÅÒ×ÅÒÁ ×Ï ×ÒÅÍÑ
+ ÐÅÒÅÄÁÞÉ ÄÁÎÎÙÈ. (\toindex{timeout})
+}
+
+\ttt{\toindex{FtpDebug}(FTP *)}
+{
+ðÏÄËÌÀÞÅÎÉÅ ÓÔÁÎÄÁÒÔÎÙÈ ÆÕÎËÃÉÊ ÏÔÌÁÄËÉ ÐÒÏÔÏËÏÌÁ ÔÁËÉÈ ËÁË
+\tc{\toindex{FtpDebugError}}{--- ÐÅÞÁÔÁÅÔ ÓÔÒÏËÕ ×ÏÚ×ÒÁÝÅÎÎÕÀ ÓÅÒ×ÅÒÏÍ É ÐÒÅÒÙ×ÁÅÔ ÐÒÏÇÒÁÍÍÕ;}
+\tc{\toindex{FtpDebugDebug}}{--- ÐÅÞÁÔÁÅÔ ÓÔÒÏËÕ ×ÏÚ×ÒÁÝÅÎÎÕÀ ÓÅÒ×ÅÒÏÍ;}
+\tc{\toindex{FtpDebugIO}}{--- ÐÅÞÁÔÁÅÔ ÓÔÒÏËÕ \ts{strerror(errno)} É ÐÒÅÒÙ×ÁÅÔ ÐÒÏÇÒÁÍÍÕ.}
+}
+
+÷Ï ×ÓÅ ÐÒÏÃÅÄÕÒÙ ÐÅÒÅÄÁÀÔÓÑ ÔÒÉ ÁÒÇÕÍÅÎÔÁ:\\
+1. óÔÒÕËÔÕÒÁ \ts{FTP};\\
+2. úÎÁÞÅÎÉÅ ×ÏÚ×ÒÁÝÅÎÎÏÅ ÆÕÎËÃÉÅÊ, ÅÓÌÉ ÏÎÏ ÍÅÎØÛÅ ÅÄÉÎÉÃÙ ÔÏ ÐÒÏÉÚÏÛÌÁ ÏÛÉÂËÁ;\\
+3. óÉÍ×ÏÌØÎÏÅ ÓÏÏÂÝÅÎÉÅ Ï ÏÛÉÂËÅ (char *).
+
+\ttt{\toindex{FtplibDebug}(\ts{on} or \ts{off})}
+{ ÷ËÌÀÞÁÅÔ/×ÙËÌÀÞÁÅÔ Á×ÔÏÍÁÔÉÞÅÓËÏÅ ×ËÌÀÞÅÎÉÅ ×ÓÅÈ ×ÉÄÏ× ÏÔÌÁÄËÉ ÐÒÉ
+ ×ÙÐÏÌÎÅÎÉÉ ÆÕÎËÃÉÉ \ts{FtpConnect(FtpLogin)}}
+\section{ðÒÏÃÅÄÕÒÙ ÐÅÒÅÄÁÞÉ ÄÁÎÎÙÈ Ó ÓÅÒ×ÅÒÁ}
+
+\ttt{STATUS \toindex{FtpRetrTimeout}(FTP~*, char~*command, char~*inp, char~*out
+\footnote{åÓÌÉ ÉÍÑ ÌÏËÁÌØÎÏÇÏ ÆÁÊÌÁ \ts{out} ÓÏ×ÐÁÄÅÔ ÓÏ ÓÔÒÏËÁÍÉ \ts{*STDIN*}, \ts{*STDOUT*}, \ts{*STDERR*} ÔÏ
+×ÍÅÓÔÏ ÏÔËÒÙÔÉÑ ÎÏ×ÏÇÏ ÆÁÊÌÁ ÐÒÏÉÚÏÊÄÅÔ ÄÕÂÌÉÒÏ×ÁÎÉÅ ÐÏÔÏËÁ ÓÏÏÔ×ÅÔÓÔ×ÅÎÎÏ Ó ËÁÎÁÌÁÍÉ
+\ts{stdin}, \ts{stdout}, \ts{stderr} (ïÂÒÁÂÏÔËÕ ÄÁÎÎÏÊ ÓÐÅÃÉÆÉËÁÃÉÉ ÆÁÊÌÏ×
+ÐÒÏÉÚ×ÏÄÉÔ ÆÕÎËÃÉÑ \toindex{Ftpfopen}, ËÏÔÏÒÁÑ ÐÒÉ ÎÅÏÂÈÏÄÉÍÏÓÔÉ ÍÏÖÅÔ ÂÙÔØ ×ÙÚ×ÁÎÁ ÓÁÍÏÓÔÏÑÔÅÌØÎÏ, Ó ÔÁËÉÍÉ ÖÅ ÁÒÇÕÍÅÎÔÁÍÉ, ËÁË ÓÉÓÔÅÍÎÁÑ ÆÕÎËÃÉÑ fopen)},
+ long~time)}
+{
+ ðÏÓÙÌÁÅÔ ËÏÍÁÎÄÕ \ts{command} ÎÁ ÓÅÒ×ÅÒ, ÐÒÉÞÅÍ ÅÓÌÉ × ËÏÍÁÎÄÅ
+ ×ÓÔÒÅÔÉÔÓÑ ÐÏÄÓÔÒÏËÁ \ps, ÔÏ ÎÁ ÅÅ ÍÅÓÔÏ ÂÕÄÅÔ ÐÏÄÓÔÁ×ÌÅÎÁ ÓÔÒÏËÁ \ts{inp}.
+ óÏÚÄÁÅÔ ËÁÎÁÌ ÄÌÑ ÐÅÒÅÄÁÞÉ ÄÁÎÎÙÈ, É ÔÏ ÞÔÏ ÂÕÄÅÔ ÐÅÒÅÄÁÎÏ
+ ÓÅÒ×ÅÒÏÍ × ÜÔÏÔ ËÁÎÁÌ ÂÕÄÅÔ ÓËÏÐÉÒÏ×ÁÎÏ × ÌÏËÁÌØÎÙÊ ÆÁÊÌ \ts{out}.
+ åÓÌÉ × ÔÅÞÅÎÉÉ ×ÒÅÍÅÎÉ \ts{time}(× ÓÅËÕÎÄÁÈ)
+ Ó ÓÅÒ×ÅÒÁ ÎÅ ÐÒÉÄÅÔ ÎÅ ÏÄÎÏÇÏ ÓÉÍ×ÏÌÁ, ÔÏ
+ ÆÕÎËÃÉÑ ×ÏÚ×ÒÁÔÉÔ ÓÔÁÔÕÓ ËÏÔÏÒÙÊ ÂÕÄÅÔ ÏÚÎÁÞÁÔØ ÏÛÉÂËÕ ××ÏÄÁ/×Ù×ÏÄÁ.
+ ÷ ÓÌÕÞÁÅ ËÏÇÄÁ \toindex{timeout}=0,
+ ÍÁËÓÉÍÁÌØÎÏÅ ×ÒÅÍÑ ÏÖÉÄÁÎÉÑ ÎÁ ÕÒÏ×ÎÅ ÂÉÂÌÉÏÔÅËÉ ÒÁ×ÎÏ
+ ÂÅÓËÏÎÅÞÎÏÓÔÉ, × ÜÔÏÍ ÓÌÕÞÁÅ ÏÛÉÂËÁ ××ÏÄÁ/×Ù×ÏÄÁ ÍÏÖÅÔ ×ÏÚÎÉËÎÕÔØ
+ ÐÏ ÉÓÔÅÞÅÎÉÀ timeout'a × ÑÄÒÅ TCP/IP (ÉÌÉ ÓÉÓÔÅÍÙ). ôÁËÉÍ ÏÂÒÁÚÏÍ, ÅÓÌÉ \ts{timeout} ×
+ ÐÁÒÁÍÅÔÒÅ time ÂÏÌØÛÅ ÞÅÍ timeout × ÑÄÒÅ TCP/IP, ÏÎ ÎÉËÏÇÄÁ
+ ÎÅ ÐÒÅÒ×ÅÔ ÐÅÒÅÄÁÞÕ ÄÁÎÎÙÈ. \footnote{\ts{Timeout} × ÑÄÒÁÈ ÒÁÚÎÙÈ TCP/IP(ÓÉÓÔÅÍÁÈ) ÒÁÚÎÙÊ}
+}
+
+\ttt{STATUS \toindex{FtpReretrTimeout}(FTP~*, char~*command, char~*inp, char~*out, long~time)}
+{
+ ðÒÏÉÚ×ÏÄÉÔ Ôo ÖÅ ÓaÍÏÅ ÄÅÊÓÔ×ÉÅ ÞÔÏ É ÆÕÎËÃÉÑ \ts{FtpRetrTimeout}, ÚÁ
+ÉÓËÌÀÞÅÎÉÅ ÔÏÇÏ, ÞÔÏ ÐÅÒÅÄ ÐÅÒÅÄÁÞÅÊ ÐÒÏ×ÅÒÑÅÔÓÑ ÆÁÊÌ \ts{out}, É × ÓÌÕÞÁÅ
+ÅÇÏ ÓÕÝÅÓÔ×Ï×ÁÎÉÑ ÐÅÒÅÄÁÞÁ Ó ÓÅÒ×ÅÒÁ ÎÁÞÉÎÁÅÔÓÑ Ó ÂÁÊÔÁ Ó ÎÏÍÅÒÏÍ \ts{<ÒÁÚÍÅÒ ÆÁÊÌÁ out>}+1.}
+\ttt{\toindex{FtpRetr}(FTP~*, char~*command, char~*inp, char~*out)}
+{
+ ÷ÙÚÙ×ÁÅÔ ÔÏ ÖÅ ÄÅÊÓÔ×ÉÅ ÞÔÏ É FtpRetrTimeout, ÎÏ Ó ×ÙËÌÀÞÅÎÎÙÍ timeout'ÏÍ.
+}
+
+\ttt{\toindex{FtpGetTimeout}(FTP~*, char~*inp, char~*out, long~time)}
+{
+ ðÅÒÅÄÁÅÔ Ó ÓÅÒ×ÅÒÁ ÆÁÊÌ \ts{inp} × ÌÏËÁÌØÎÙÊ ÆÁÊÌ \ts{out}, ÐÒÉ ÜÔÏÍ ÕÓÔÁÎÁ×ÌÉ×ÁÅÔÓÑ
+ \ts{timeout=time}.
+}
+
+\ttt{\toindex{FtpGet}(FTP~*, char~*in, char~*out)}
+{
+ ÷ÙÚÙ×ÁÅÔ ÆÕÎËÃÉÀ \ts{FtpGetTimeout} Ó ×ÙËÌÀÞÅÎÎÙÍ ÍÁËÓÉÍÁÌØÎÙÍ ×ÒÅÍÅÎÅÍ
+ÏÖÉÄÁÎÉÑ ÄÁÎÎÙÈ}
+
+\ttt{\toindex{FtpDirectory}(FTP~*, char~*pat\footnote{üÔÏ ÐÅÒ×ÙÊ ÁÒÇÕÍÅÎÔ ÄÌÑ ËÏÍÁÎÄÙ ls(dir)}, char~*out)}
+{
+ ðÅÒÅÄÁÅÔ ÓÏÄÅÒÖÉÍÏÅ ÄÉÒÅËÔÏÒÉÉ, ÏÐÉÓÁÎÎÏÇÏ ÐÁÒÁÍÅÔÒÏÍ \ts{pat}, Ó ÓÅÒ×ÅÒÁ × ÆÁÊÌ \ts{out}.
+}
+\ttt{\toindex{FtpDir}(FTP~*, char~*out)}
+{
+ ðÅÒÅÄÁÅÔ ÓÏÄÅÒÖÉÍÏÅ ÔÅËÕÝÅÊ ÄÉÒÅËÔÏÒÉÉ Ó ÓÅÒ×ÅÒÁ × ÆÁÊÌ \ts{out}.
+}
+
+\section{ðÒÏÃÅÄÕÒÙ ÐÅÒÅÄÁÞÉ ÄÁÎÎÙÈ ÎÁ ÓÅÒ×ÅÒ}
+
+\ttt{\toindex{FtpStorTimeout}(FTP~*, char~*command, char~*inp, char~*out, long~time)}
+{
+ ðÅÒÅÄÁÅÔ ÓÏÄÅÒÖÉÍÏÅ ÌÏËÁÌØÎÏÇÏ ÆÁÊÌÁ \ts{inp} ÎÁ ÓÅÒ×ÅÒ, ÐÒÅÄ×ÁÒÉÔÅÌØÎÏ ÐÏÓÌÁ×
+ÅÍÕ ËÏÍÁÎÄÕ, ÓÏÓÔÁ×ÌÅÎÎÕÀ ÉÚ \ts{command} É \ts{out}. ðÁÒÁÍÅÔÒ \ts{time}, ÚÁÄÁÅÔ ÍÁËÓÉÍÁÌØÎÏÅ
+×ÒÅÍÑ ÎÁ ÏÔÐÒÁ×ËÕ ÏÄÎÏÇÏ ÓÉÍ×ÏÌÁ.
+}
+
+\ttt{STATUS \toindex{FtpRestorTimeout}(FTP~*, char~*command, char~*inp, char~*out, long~time)}
+{
+ ðÒÏÉÚ×ÏÄÉÔ Ôo ÖÅ ÓaÍÏÅ ÄÅÊÓÔ×ÉÅ ÞÔÏ É ÆÕÎËÃÉÑ \ts{FtpStorTimeout}, ÚÁ
+ÉÓËÌÀÞÅÎÉÅ ÔÏÇÏ, ÞÔÏ ÐÅÒÅÄ ÐÅÒÅÄÁÞÅÊ ÐÒÏ×ÅÒÑÅÔÓÑ ÆÁÊÌ \ts{out} ÎÁ ÓÅÒ×ÅÒÅ,
+É, × ÓÌÕÞÁÅ ÅÇÏ ÓÕÝÅÓÔ×Ï×ÁÎÉÑ, ÐÅÒÅÄÁÞÁ ÎÁ ÓÅÒ×ÅÒ ÎÁÞÉÎÁÅÔÓÑ Ó ÂÁÊÔÁ Ó ÎÏÍÅÒÏÍ \ts{<ÒÁÚÍÅÒ ÆÁÊÌÁ out>}+1.}
+
+\ttt{\toindex{FtpStor}(FTP~*, char~*command, char~*inp, char*~out)}
+{
+ ÷ÙÚÙ×ÁÅÔ ÚÁÐÕÓË ÐÒÏÃÅÄÕÒÙ \ts{FtpStorTimeout} Ó ÐÁÒÁÍÅÔÒÏÍ \ts{time=0}.
+}
+
+\ttt{\toindex{FtpPutTimeout}(FTP~*, char~*in, char~*out, long~time)}
+{ ðÅÒÅÄÁÅÔ ÌÏËÁÌØÎÙÊ ÆÁÊÌ \ts{in} ÎÁ ÓÅÒ×ÅÒ × ÆÁÊÌ Ó ÉÍÅÎÅÍ \ts{out}, ÐÒÉ ÜÔÏÍ \ts{timeout=time}}
+
+\ttt{\toindex{FtpPut}(FTP~*, char~*in, char~*out)}
+{
+ ÷ÙÚÙ×ÁÅÔ ÐÒÏÃÅÄÕÒÕ \ts{FtpPutTimeout} Ó ÐÁÒÁÍÅÔÒÏÍ \ts{time=0}}
+
+
+\section{ðÒÏÃÅÄÕÒÙ ÞÔÅÎÉÑ/ÚÁÐÉÓÉ × ÆÁÊÌ ÎÁ ÓÅÒ×ÅÒÅ}
+
+äÌÑ ÔÏÇÏ, ÞÔÏÂÙ ÐÒÏÉÚ×ÏÄÉÔØ ××ÏÄ/×Ù×ÏÄ ÉÚ/× ÆÁÊÌÙ ËÏÔÏÒÙÅ ÎÁÈÏÄÑÔÓÑ ÎÁ ÓÅÒ×ÅÒÅ,
+ÐÒÉÞÅÍ ÎÅ ËÏÐÉÒÕÑ ÉÈ ÐÒÅÄ×ÁÒÉÔÅÌØÎÏ × ÌÏËÁÌØÎÙÊ ÆÁÊÌ, Á ÒÁÂÏÔÁÑ ÎÅÐÏÓÒÅÄÓÔ×ÅÎÎÏ Ó ÏÒÉÇÉÎÁÌÏÍ,
+ÓÕÝÅÓÔ×ÕÅÔ ×ÏÚÍÏÖÎÏÓÔØ ÏÔËÒÙÔØ ÆÁÊÌ ÎÁ ÓÅÒ×ÅÒÅ ÎÁ ÞÔÅÎÉÅ/ÚÁÐÉÓØ/ÄÏÚÁÐÉÓØ É
+ÚÁÔÅÍ Ó ÐÏÍÏÝØÀ ÏÂÙÞÎÙÈ ÐÒÏÃÅÄÕÒ ××ÏÄÁ/×Ù×ÏÄÁ ÉÌÉ ÖÅ ÐÒÉ ÐÏÍÏÝÉ ÐÒÏÃÅÄÕÒ
+\ts{FtpRead} É \ts{FtpWrite}, ËÏÔÏÒÙÅ × ÏÔÌÉÞÉÉ ÏÔ ÐÅÒ×ÙÈ ÐÒÅÏÂÒÁÚÕÀÔ ÔÅËÓÔÏ×ÙÅ ÆÁÊÌÙ,
+ÐÒÏÉÚ×ÏÄÉÔØ ÎÅÏÂÈÏÄÉÍÙÅ ÏÐÅÒÁÃÉÉ.
+\footnote{åÓÔÅÓÔ×ÅÎÎÏ, ÔÁËÉÅ ÆÕÎËÃÉÉ ËÁË \ts{seek}, \ts{ioctl}, ...
+ ÄÌÑ ÜÔÉÈ ÆÁÊÌÏ× ÎÅÄÏÐÕÓÔÉÍÙ.}
+
+
+\ttt{\toindex{FtpData}(FTP~*, char~*command, char~*param, char~*mode)}
+{ óÏÚÄÁÅÔ ËÁÎÁÌ ÄÌÑ ÐÅÒÅÄÁÞÉ ÄÁÎÎÙÈ ÐÒÅÄ×ÁÒÉÔÅÌØÎÏ ÐÏÓÌÁ× ÓÅÒ×ÅÒÕ ËÏÍÁÎÄÕ ËÏÔÏÒÁÑ
+ÓÏÓÔÁ×ÌÑÅÔÓÑ ÉÚ ÐÁÒÁÍÅÔÒÏ× \ts{command} É \ts{param}. ðÁÒÁÍÅÔÒ \ts{mode} ÕËÁÚÙ×ÁÅÔ ÍÏÖÅÔ ÂÙÔØ
+ÉÌÉ ``r'' ÉÌÉ ``w''}
+
+\ttt{\toindex{FtpOpenRead}(FTP~*,char~*filename)}
+{ ïÔËÒÙ×ÁÅÔ ÄÌÑ ÞÔÅÎÉÑ ÆÁÊÌ Ó ÉÍÅÎÅÍ \ts{filename} ÎÁ ÓÅÒ×ÅÒÅ }
+
+\ttt{\toindex{FtpOpenWrite}(FTP~*,char~*filename)}
+{ ïÔËÒÙ×ÁÅÔ ÄÌÑ ÚÁÐÉÓÉ ÆÁÊÌ Ó ÉÍÅÎÅÍ \ts{filename} ÎÁ ÓÅÒ×ÅÒÅ }
+
+\ttt{\toindex{FtpOpenAppend}(FTP~*,char~*filename)}
+{ ïÔËÒÙ×ÁÅÔ ÄÌÑ ÄÏÚÁÐÉÓÉ ÆÁÊÌ Ó ÉÍÅÎÅÍ \ts{filename} ÎÁ ÓÅÒ×ÅÒÅ }
+
+\ttt{\toindex{FtpOpenDir}(FTP~*, char~*files)}
+{
+ óÏÚÄÁÅÔ ËÁÎÁÌ ÄÌÑ ÞÔÅÎÉÑ ÕÄÁÌÅÎÎÏÇÏ ÌÉÓÔÉÎÇÁ ÄÉÒÅËÔÏÒÉÉ, ÐÁÒÁÍÅÔÒ files ÐÅÒÅÄÁÅÔÓÑ
+ËÏÍÁÎÄÅ \ts{ls} ÎÁ ÓÅÒ×ÅÒÅ × ËÁÞÅÓÔ×Å 1-ÇÏ ÐÁÒÁÍÅÔÒÁ
+}
+
+\ttt{int \toindex{FtpRead}(FTP~*)}{þÉÔÁÅÔ ÓÉÍ×ÏÌ ÉÚ ÐÏÔÏËÁ ÄÁÎÎÙÈ, ÅÓÌÉ ÂÙÌÁ ÕÓÔÁÎÏ×ÌÅÎÁ
+ ÔÅËÓÔÏ×ÁÑ ÍÏÄÁ ÐÅÒÅÄÁÞÉ \footnote{õÓÔÁÎÏ×ÌÅÎÁ ÐÏ ÕÍÏÌÞÁÎÉÀ.}, ÐÒÅÏÂÒÁÚÕÅÔ ÐÅÒÅÈÏÄÙ ÎÁ ÎÏ×ÕÀ ÓÔÒÏËÕ. ðÒÉ ÏÂÎÁÒÕÖÅÎÉÉ
+ËÏÎÃÁ ÐÏÔÏËÁ ×ÏÚ×ÒÁÝÁÅÔ \toindex{EOF}}
+
+\ttt{\toindex{FtpGetString}(FTP~*, char~*str)}
+{ þÔÅÎÉÅ ÏÄÎÏÊ ÓÔÒÏËÉ ÉÚ ÐÏÔÏËÁ ÄÁÎÎÙÈ ÐÒÉ ÐÏÍÏÝÉ ÆÕÎËÃÉÉ \ts{FtpRead}.}
+
+\ttt{\toindex{FtpWrite}(FTP~*, char~c)}{ðÉÛÅÔ ÓÉÍ×ÏÌ × ÐÏÔÏË ÄÁÎÎÙÈ, ÅÓÌÉ ÂÙÌÁ ÕÓÔÁÎÏ×ÌÅÎÁ
+ ÔÅËÓÔÏ×ÁÑ ÍÏÄÁ ÐÅÒÅÄÁÞÉ, ÐÒÅÏÂÒÁÚÕÅÔ ÐÅÒÅÈÏÄÙ ÎÁ ÎÏ×ÕÀ ÓÔÒÏËÕ. ðÒÉ ÏÂÎÁÒÕÖÅÎÉÉ
+ÏÛÉÂËÉ ××ÏÄÁ/×Ù×ÏÄÁ ×ÏÚ×ÒÁÝÁÅÔ \toindex{EOF}}
+
+\ttt{\toindex{FtpClose}(FTP~*)}
+{úÁËÒÙ×ÁÅÔ ÒÁÎÅÅ ÏÔËÒÙÔÙÊ ÐÏÔÏË ÄÁÎÎÙÈ.}
+
+\section{ëÏÍÁÎÄÙ ÄÌÑ ÓÅÒ×ÅÒÁ É ×ÓÐÏÍÏÇÁÔÅÌØÎÙÅ ÆÕÎËÃÉÉ}
+
+\ttt{\toindex{FtpCommand}(FTP~*, char~*command, char~*param, int~ok1, ok2, ok3, ..., okN, EOF)}
+{ ðÏÓÙÌÁÅÔ ËÏÍÁÎÄÕ, ÓÏÓÔÁ×ÌÅÎÎÕÀ ÉÚ ÐÁÒÁÍÅÔÒÏ× \ts{command} É \ts{param}, É ÓÞÉÔÙ×ÁÅÔ
+ÏÔ×ÅÔ ÓÅÒ×ÅÒÁ, ÅÓÌÉ ËÏÄ ÏÔ×ÅÔÁ ÎÅ ÓÏ×ÐÁÄÁÅÔ ÎÅ Ó ÏÄÎÉÍ ÚÎÁÞÅÎÉÅÍ \ts{ok}, ÔÏ
+ÚÎÁË ËÏÄÁ ÏÔ×ÅÔÁ ÍÅÎÑÅÔÓÑ ÎÁ '-'. ÷ ÓÌÕÞÁÅ ÅÓÌÉ ÕÓÔÁÎÏ×ÌÅÎ handler ÏÂÒÁÂÏÔËÉ
+ÏÛÉÂÏË ×ÙÚÙ×ÁÅÔ ÅÇÏ.
+}
+
+\ttt{\toindex{FtpType}(FTP~*,char~*mode)}
+{õÓÔÁÎÁ×ÌÉ×ÁÅÔ ÍÏÄÕ ÐÅÒÅÄÁÞÉ ÆÁÊÌÏ×, mode ÍÏÖÅÔ ÂÙÔØ ``A'', ``I'', ``S'',....}
+
+\ttt{\toindex{FtpBinary}(FTP~*)}
+{õÓÔÁÎÁ×ÌÉ×ÁÅÔ Ä×ÏÉÞÎÕÀ ÍÏÄÕ ÐÅÒÅÄÁÞÉ ÆÁÊÌÏ×}
+
+\ttt{\toindex{FtpAscii}(FTP~*)}
+{õÓÔÁÎÁ×ÌÉ×ÁÅÔ ÔÅËÓÔÏ×ÕÀ ÍÏÄÕ ÐÅÒÅÄÁÞÉ ÆÁÊÌÏ×}
+
+
+\ttt{\toindex{FtpMkdir}(FTP~*,char *dirname)}
+{óÏÚÄÁÅÔ ÄÉÒÅËÔÏÒÉÀ ÎÁ ÓÅÒ×ÅÒÅ}
+
+\ttt{\toindex{FtpChdir}(FTP~*,char *dirname)}
+{íÅÎÑÅÔ ÁËÔÉ×ÎÕÀ ÄÉÒÅËÔÏÒÉÀ ÎÁ ÓÅÒ×ÅÒÅ}
+
+\ttt{\toindex{FtpRm}(FTP~*,char *filename)}
+{õÄÁÌÑÅÔ ÆÁÊÌ ÎÁ ÓÅÒ×ÅÒÅ}
+
+\ttt{char~*\toindex{FtpPwd}(FTP~*)}
+{÷ÏÚ×ÒÁÝÁÅÔ ÁËÔÉ×ÎÕÀ ÄÉÒÅËÔÏÒÉÀ ÎÁ ÓÅÒ×ÅÒÅ}
+
+\ttt{int \toindex{FtpSize}(FTP~*,char *filename)}
+{÷ÏÚ×ÒÁÝÁÅÔ ÒÁÚÍÅÒ ÆÁÊÌÁ × ÂÁÊÔÁÈ, ÅÓÌÉ ÆÁÊÌ Ó ÕËÁÚÁÎÎÙÍ ÉÍÅÎÅÍ ÏÔÓÕÔÓÔ×ÕÅÔ,
+ÔÏ ×ÏÚ×ÒÁÝÁÅÔÓÑ ÓÔÁÔÕÓ ÏÛÉÂËÉ, Ô.Å. ÚÎÁÞÅÎÉÅ ÍÅÎØÛÅ ÎÕÌÑ}
+
+\ttt{\toindex{FtpMove}(FTP~*,char *oldfilename, char *newfilename)}
+{ðÅÒÅÉÍÅÎÏ×Ù×ÁÅÔ ÎÁ ÓÅÒ×ÅÒÅ ÆÁÊÌ \ts{oldfilename} × ÆÁÊÌ \ts{newfilename}}
+
+\ttt{\toindex{FtpPort}(FTP~*, int~a, int~b, int~c, int~d, int~e, int~f)}
+{ëÏÍÁÎÄÁ ÓÅÒ×ÅÒÕ ÓÏÚÄÁÔØ ËÁÎÁÌ ÄÌÑ ÐÅÒÅÄÁÞÉ ÄÁÎÎÙÈ. ðÒÉÞÅÍ \ts{a.b.c.d} ÜÔÏ IP ÁÄÒÅÓ
+ËÌÉÅÎÔÁ Á \ts{e*256+f} ÎÏÍÅÒ ÐÏÒÔÁ.}
+
+\ttt{struct hostent *\toindex{FtpGetHost}(char *hostname)}
+{÷ÏÚ×ÒÁÝÁÅÔ ÕËÁÚÁÔÅÌØ ÎÁ ÓÔÒÕËÔÕÒÕ ÔÉÐÁ hostent.
+ áÒÇÕÍÅÎÔ -- ÜÔÏ ÓÔÒÏËÁ ÓÏÄÅÒÖÁÝÁÑ ÉÌÉ ÉÍÑ ÍÁÛÉÎÙ,
+ÉÌÉ ÅÅ IP ÁÄÒÅÓ × ÓÔÒÏÞÎÏÍ ×ÉÄÅ\footnote{îÁÐÒÉÍÅÒ: ``dxunk8.oea.ihep.su'' ÉÌÉ
+``192.102.229.71''}.}
+
+\section{ðÏÄÐÒÏÇÒÁÍÍÙ ÐÅÒÅÄÁÞÉ ÓÏÏÂÝÅÎÉÊ ×/ÉÚ ÓÅÒ×ÅÒÁ}
+
+\ttt{\toindex{FtpSendMessage}(FTP~*, char~*message)}
+{ðÏÓÙÌÁÅÔ ÓÏÏÂÝÅÎÉÅ ÓÅÒ×ÅÒÕ}
+
+\ttt{int \toindex{FtpGetMessage}(FTP~*)}
+{ðÒÉÎÉÍÁÅÔ ÓÏÏÂÝÅÎÉÅ ÏÔ ÓÅÒ×ÅÒÁ É ×ÏÚ×ÒÁÝÁÅÔ ÅÇÏ ËÏÄ}
+
+\ttt{\toindex{FtpMessage}(int Number)}
+{÷ÏÚ×ÒÁÝÁÅÔ ÐÏ ËÏÄÕ ÓÏÏÂÝÅÎÉÑ ÅÇÏ ÓÏÄÅÒÖÉÍÏÅ}
+
+\section{æÕÎËÃÉÉ ÐÏÌÎÏÇÏ ÓÅÁÎÓÁ ÒÁÂÏÔÙ}
+
+\ttt{FILE *\toindex{FtpFullOpen}(char *filename,char *mode)}
+{ òÁÚÂÉÒÁÅÔ ÓÔÒÏËÕ filename, ËÏÔÏÒÁÑ ÄÏÌÖÎÁ ÂÙÔØ ÔÉÐÁ
+\\ \ts{host/user/password:filename} ÉÌÉ ÖÅ ÔÉÐÁ \ts{filename}, × ÚÁ×ÉÓÉÍÏÓÔÉ ÏÔ ÜÔÏÇÏ
+ÏÔËÒÙ×ÁÅÔÓÑ ÆÁÊÌ ÉÌÉ ÎÁ ÓÅÒ×ÅÒÅ \ts{host} ÉÌÉ ÌÏËÁÌØÎÙÊ ÆÁÊÌ. ðÁÒÁÍÅÔÒ mode ÄÏÌÖÅÎ
+ÓÏÄÅÒÖÁÔØ ÏÄÉÎ ÉÌÉ Ä×Á ÓÉÍ×ÏÌÁ. ðÅÒ×ÙÊ ÚÁÄÁÅÔ ÔÉÐ ÏÔËÒÙÔÉÑ ÆÁÊÌÁ ``r'',``w'' ÉÌÉ
+``a''. ÷ÔÏÒÏÊ ÓÉÍ×ÏÌ ÍÏÖÅÔ ÓÏÄÅÒÖÁÔØ ÓÉÍ×ÏÌ ``b'' ÞÔÏ ÂÕÄÅÔ ÚÁÄÁ×ÁÔØ Ä×ÏÉÞÎÕÀ ÍÏÄÕ ÐÅÒÅÄÁÞÉ}
+\ttt{\toindex{FtpFullClose}(FILE *f)}
+{úÁËÒÙÔÉÅ ÆÁÊÌÁ}
+
+
+\section{ïÐÉÓÁÎÉÅ ÐÒÉÍÅÒÏ× É ÐÒÉËÌÁÄÎÙÈ ÐÒÏÇÒÁÍÍ}
+
+\subsection{ðÒÏÇÒÁÍÍÁ get}\index{get}
+
+ëÏÐÉÒÏ×ÁÎÉÅ ÆÁÊÌÁ Ó ÓÅÒ×ÅÒÁ × ÌÏËÁÌØÎÙÊ ÆÁÊÌ Ó ÔÁËÉÍ ÖÅ ÉÍÅÎÅÍ Ó ÉÓÐÏÌØÚÏ×ÁÎÉÅÍ ÆÕÎËÃÉÊ ÐÏÌÎÏÇÏ ÓÅÁÎÓÁ.
+
+
+\subsection{ðÒÏÇÒÁÍÍÁ fcp}\index{fcp}
+
+ðÒÏÇÒÁÍÍÁ fcp ÄÅÍÏÎÓÔÒÉÒÕÅÔ ÐÒÏÓÔÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÆÕÎËÃÉÊ ÐÏÌÎÏÇÏ ÓÅÁÎÓÁ ÒÁÂÏÔÙ
+(FtpFullOpen É FtpFullClose). éÍÑ ÆÁÊÌÁ ÐÅÒÅÄÁ×ÁÅÍÏÇÏ × ËÁÞÅÓÔ×Å
+ÐÁÒÁÍÅÔÒÁ, ÍÏÖÅÔ ÏÐÉÓÙ×ÁÔØ É ÌÏËÁÌØÎÙÊ É ÕÄÁÌÅÎÎÙÊ ÆÁÊÌ. üÔÏ ÐÏÚ×ÏÌÑÅÔ
+ÐÒÏÉÚ×ÏÄÉÔØ ÐÅÒÅÄÁÞÕ ËÁË Ó ÓÅÒ×ÅÒÁ × ÌÏËÁÌØÎÙÊ ÆÁÊÌ, ÔÁË É ÎÁÏÂÏÒÏÔ,
+ Á ÔÁËÖÅ Ó ÓÅÒ×ÅÒÁ ÎÁ ÓÅÒ×ÅÒ.
+
+\subsection{ðÒÏÇÒÁÍÍÁ ftptry}\index{ftptry}
+
+ðÒÅÄÎÁÚÎÁÞÅÎÁ ÄÌÑ ÐÅÒÅÄÁÞÉ ÆÁÊÌÏ× ÂÏÌØÛÏÇÏ ÒÁÚÍÅÒÁ ÐÏ ÓÅÔÑÍ ËÏÔÏÒÙÅ
+ÏÞÅÎØ ÞÁÓÔÏ ``ÌÏÍÁÀÔÓÑ''. üÔÏ ÐÒÅÖÄÅ ×ÓÅÇÏ ÏÔÎÏÓÉÔÓÑ Ë ÓÅÔÑÍ ÐÏÓÔÒÏÅÎÎÙÈ
+ÎÁ dialup-ÌÉÎÉÑÈ.
+
+\ts{ftptry} × ÏÓÎÏ×ÎÏÍ ÐÒÅÄÎÁÚÎÁÞÅÎ ÄÌÑ ÎÅÉÔÅÒÁËÔÉ×ÎÏÊ
+ÐÅÒÅÄÁÞÉ ÄÁÎÎÙÈ, ÐÏÜÔÏÍÕ ÎÅÏÂÈÏÄÉÍÁÑ ÉÎÆÏÒÍÁÃÉÑ ÄÌÑ ×ÙÐÏÌÎÅÎÉÑ ÐÅÒÅÄÁÞÉ ÚÁÄÁeÔÓÑ × ×ÉÄÅ ÏÐÃÉÊ ÐÒÉ ÚÁÐÕÓËÅ ÐÒÏÇÒÁÍÍÙ.
+
+ðÒÉ ÚÁÐÕÓËÅ \ts{ftptry} ÂÅÚ ËÌÀÞÅÊ, ÎÁ ÜËÒÁÎ ×Ù×ÏÄÉÔÓÑ ÓÐÉÓÏË ×ÓÅÈ ÄÏÐÕÓÔÉÍÙÈ
+ÏÐÃÉÊ É ÏÄÉÎ ÐÒÉÍÅÒ ÚÁÐÕÓËÁ, ÐÏÜÔÏÍÕ × ÄÁÎÎÏÍ ÒÕËÏ×ÏÄÓÔ×Å ËÌÀÞÉ
+É ÉÈ ÎÁÚÎÁÞÅÎÉÑ ÏÐÉÓÙ×ÁÔØ ÎÅ ÉÍÅÅÔ ÓÍÙÓÌÁ.
+îÅÏÂÈÏÄÉÍÏ ÔÏÌØËÏ ÓËÁÚÁÔØ Ï ÔÏÍ, ÞÔÏ
+ÔÁË ËÁË ÎÅËÏÔÏÒÙÅ ÏÐÃÉÉ ÎÅÏÂÈÏÄÉÍÏ ÓÔÁ×ÉÔØ ÐÒÁËÔÉÞÅÓËÉ ×ÓÅÇÄÁ,
+ÔÏ ÍÏÖÎÏ ÐÒÅÄ×ÁÒÉÔÅÌØÎÏ
+ÕÓÔÁÎÏ×ÉÔØ ÐÅÒÅÍÅÎÎÕÀ ÏËÒÕÖÅÎÉÑ ``FTPTRY''\index{FTPTRY enviroment}
+ÐÏ ÁÎÁÌÏÇÉÉ Ó ÔÅÍ ËÁË ÜÔÏ ÄÅÌÁÅÔÓÑ
+× ÐÒÏÇÒÁÍÍÅ ``less''
+\footnote{îÁÐÒÉÍÅÒ: \% setenv FTPTRY ``-DBb -u anonymous -s 60 -t 15''},
+É ÐÉÓÁÔØ × ËÏÍÁÎÄÎÏÊ ÓÔÒÏËÅ ÔÏÌØËÏ ÔÅ ÏÐÃÉÉ ËÏÔÏÒÙÅ ÒÅÄËÏ
+ÉÓÐÏÌØÚÕÀÔÓÑ ÉÌÉ ÎÅ ÐÉÓÁÔØ ÉÈ ×ÏÏÂÝÅ.
+
+
+\newpage
+\input rus.ind
+\newpage
+\tableofcontents
+\end{document}
+
+
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