freebsd-dev/lib/libftp/utils/uftp.c
1995-05-30 05:51:47 +00:00

825 lines
12 KiB
C

/* 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;
int 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);
}
}