/* Make the necessary includes and set up the variables. */
// written in 2005 8 27 summer by chenjinlai
// ftp client in linux
//usage :
// connect : ftp.out 10.10.10.10 21
// download file: get filename
// upload file : put filename
// download directory: d filename
// upload directory : u filename
// list : list
// list : dir
// quit : quit
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <malloc.h>
#define BUFFER 1024
#define TRY 1000
enum COMMAND {LIST = 1,UNKNOW,QUIT,GET,PUT,CWD,D,PRINT,U};
struct ftp_client {
int protocol; // sock for protocol communication
int data; // sock for data communication
struct sockaddr_in address_protocol;
struct sockaddr_in address_data;
char buf[BUFFER];
char path[BUFFER];
int n;
int len;
char *stack[BUFFER]; //for store directory name
int position ;
int tell ; // for position in list_ftp in directory process it should be set to 0
char name[BUFFER][128]; // name length of file is 128
char file[BUFFER];
};
enum COMMAND getcmd(struct ftp_client *p);
int getline(char *buf);
int getport(char *buf);
int atoi(char *);
void exit(int);
int pasv( struct ftp_client *p);
int list( struct ftp_client *p);
int get( struct ftp_client *p);
int cwd( struct ftp_client *p);
int get_d(struct ftp_client *p); // download dirctory
int print_list( struct ftp_client *p); // print file name in a list file
int get_file ( struct ftp_client *p);
int analyse ( struct ftp_client *p);
int print_local_list( struct ftp_client *p); // print file name in a list file
int get_local_file ( struct ftp_client *p);
int get_local_d(struct ftp_client *p); // download dirctory
int mkd(struct ftp_client *p);
int put( struct ftp_client *p);
int system(char *);
int analyse_local ( struct ftp_client *p);
int analyse ( struct ftp_client *p) //got all the name of file and directory in list_ftp
{
int i;
int j;
int k;
char ch;
char temp[BUFFER];
FILE *f;
f = fopen("list_ftp","r");
if ( f== NULL) // file deleted no more name
{
perror("can't open list_ftp");
return 1;
}
p->tell = 0; // reset
while(!feof(f))
{
ch = fgetc(f);
if ( ch == EOF )
break;
if ( ch == 'd' )
{
p->file[p->tell] = 1;
}
else
p->file[p->tell] = 0;
fscanf(f,"%s",p->buf);
for(i=1;i<8;i++)
{
fscanf(f,"%s",p->buf);
}
memset(p->name[p->tell],0,1);
j=0;
ch = fgetc(f);
while( ( ch = fgetc(f) ) != '\n')
p->name[p->tell][j++]=ch;
p->name[p->tell][j-1]='\0';
if(p->name[p->tell][0] == '.')
continue;
if( p->file[p->tell] == 1 ) // is a directory
{
strcpy(temp,p->path);
for( k=0; temp[k];k++);
temp[k] = '/';
strcpy(temp+k+1,p->name[p->tell]);
//mkdir(temp,0777) ; // create the directory
}
p->tell++;
}
fclose(f);
return 1;
}
int analyse_local ( struct ftp_client *p)
{
int i;
int j;
int k;
char ch;
char temp[BUFFER];
char recover[BUFFER];
FILE *f;
f = fopen("list_ftp","r");
if ( f== NULL) // file deleted no more name
{
perror("can't open list_ftp");
return 1;
}
p->tell = 0; // reset
while(!feof(f))
{
ch = fgetc(f);
if ( ch == EOF )
break;
if ( ch == 'd' )
{
p->file[p->tell] = 1;
}
else if ( ch == 't' ) // "total %d "
{
fscanf(f,"%s",p->buf);
fscanf(f,"%s",p->buf);
while( ( ch = fgetc(f) ) != '\n');
continue;
}
else
p->file[p->tell] = 0;
fscanf(f,"%s",p->buf);
for(i=1;i<8;i++)
{
fscanf(f,"%s",p->buf);
}
memset(p->name[p->tell],0,1);
j=0;
ch = fgetc(f);
while( ( ch = fgetc(f) ) != '\n')
p->name[p->tell][j++]=ch;
p->name[p->tell][j]='\0';
if(p->name[p->tell][0] == '.')
continue;
if( p->file[p->tell] == 1 ) // is a directory
{
strcpy(temp,p->path);
for( k=0; temp[k];k++);
temp[k] = '/';
strcpy(temp+k+1,p->name[p->tell]);
strcpy(recover,p->path);
strcpy(p->path,temp);
//mkd(p) ; // create the directory
strcpy(p->path,recover);
}
p->tell++;
}
printf("p name tell = %s",p->name[p->tell]);fflush(stdout);
printf("p path = %s",p->path);fflush(stdout);
fclose(f);
return 1;
}
int get_file ( struct ftp_client *p) // download all the file in this level and push directory to stack
{
int n;
int i;
char recover[BUFFER];
strcpy(recover,p->path);
n=0;
while(p->path[n++]); // n is current path length
analyse(p); // name is store in p->buf
while(p->tell >0)
{
if ( p->file[p->tell-1] == 0 ) // == file why don't tell the file name ? file name is store in p->buf al
{
p->path[n-1] = '/';
strcpy(p->path+n,p->name[p->tell-1]);
pasv(p);
get(p);
strcpy(p->path, recover);
}
else if (p->file[p->tell-1] == 1 ) // == directory
{
i =0;
while(p->name[p->tell-1][i++]); // i is subdirectory length
p->stack[p->position] = (char *)malloc(n+i);
strcpy(p->stack[p->position],p->path);
p->stack[p->position][n-1]='/';
strcpy(p->stack[p->position]+n,p->name[p->tell-1]);
p->position ++;
}
p->tell--; // one file in current directory is processed
}
return 1;
}
int get_local_file ( struct ftp_client *p) // upload all the file in this level and push directory to stack
{
int n;
int i;
char recover[BUFFER];
strcpy(recover,p->path);
n=0;
while(p->path[n++]); // n is current path length
analyse_local(p); // name is store in p->buf
printf("\nafter analyse %s",p->name[p->tell-1]);fflush(stdout);
while(p->tell >0)
{
if ( p->file[p->tell-1] == 0 ) // == file why don't tell the file name ? file name is store in p->buf al
{
p->path[n-1] = '/';
strcpy(p->path+n,p->name[p->tell-1]);
pasv(p);
//printf("in get_local_file p->path = %s!",p->path);
put(p);
strcpy(p->path, recover);
}
else if (p->file[p->tell-1] == 1 ) // == directory
{
i =0;
while(p->name[p->tell-1][i++]); // i is subdirectory length
p->stack[p->position] = (char *)malloc(n+i);
strcpy(p->stack[p->position],p->path);
p->stack[p->position][n-1]='/';
strcpy(p->stack[p->position]+n,p->name[p->tell-1]);
p->position ++;
}
p->tell--; // one file in current directory is processed
}
return 1;
}
int get_d(struct ftp_client *p) //download directory
{
int i;
int n;
char recover[BUFFER];
mkdir(p->path,0777);
cwd( p);
pasv( p);
print_list( p);
/////////////////////////////////////////////////////////////////////////////////////
n = 1;
i=0;
while(p->path[i]) // relocation position to original position
{
if(p->path[i] == '/')
n++;
i++;
}
strcpy(recover,p->path);
while( n--)
{
strcpy(p->path, "..");
cwd(p);
}
strcpy(p->path,recover);
/////////////////////////////////////////////////////////////////////////////////////
get_file( p ); // receive file and add directory to stack position++
while( p->position > 0)
{
strcpy( p->path , p->stack[p->position-1] ); // enter to the directory of stack
free ( p->stack[p->position-1] );
p->position--;
get_d(p);
}
if (p->position > BUFFER-1)
{
perror("eror BUFFER OVERFLOW");
exit(1);
}
return 1;
}
int mkd(struct ftp_client *p) // make directory in server
{
int n;
strcpy(p->buf,"mkd ./");
strcpy(p->buf+6, p->path);
n = 0;
while(p->buf[n++]); // the command in protocol pipe should be "%s\r\n"
p->buf[n-1] = '\r';
p->buf[n] = '\n';
p->buf[n+1] = '\0';
printf("buf = in mkd %s!",p->buf);
//exit(1);
send(p->protocol, p->buf, n+1, 0);
n = recv(p->protocol, p->buf, BUFFER,0); // 250 from server
p->buf[n] = '\0';
printf("from protocol in mkd:\n%s", p->buf);
return 1;
}
int get_local_d(struct ftp_client *p) //upload directory
{
int n;
mkd(p);
strcpy(p->buf,"ls ./");
strcpy(p->buf+5, p->path);
n = 0;
while(p->buf[n++]); // the command in protocol pipe should be "%s\r\n"
printf("%d n = ",n);
strcpy(p->buf+n-1," > list_ftp -al");
printf("list print %s!",p->buf);fflush(stdout);
system(p->buf);
get_local_file( p ); // send file and add directory to stack position++
while( p->position > 0)
{
strcpy( p->path , p->stack[p->position-1] ); // enter to the directory of stack
free ( p->stack[p->position-1] );
p->position--;
get_local_d(p);
}
if (p->position > BUFFER-1)
{
perror("eror BUFFER OVERFLOW");
exit(1);
}
return 1;
}
int cwd( struct ftp_client *p) //change directory in ftp server
{
int n;
//printf("buf = %s,path = %s!\n",p->buf,p->path);
strcpy(p->buf,"cwd ./");
strcpy(p->buf+6, p->path);
n = 0;
while(p->buf[n++]); // the command in protocol pipe should be "%s\r\n"
p->buf[n-1] = '\r';
p->buf[n] = '\n';
p->buf[n+1] = '\0';
send(p->protocol, p->buf, n+1, 0);
n = recv(p->protocol, p->buf, BUFFER,0); // 250 from server
p->buf[n] = '\0';
printf("from protocol :\n%s", p->buf);
return 1;
}
int get( struct ftp_client *p) //download file
{
int n = 0;
//int k = 0;
FILE *f;
int count;
strcpy(p->buf,"retr ./");
strcpy(p->buf+7, p->path);
n = p->path[9];
n = 0;
while(p->buf[n++]); // the command in protocol pipe should be "%s\r\n"
p->buf[n-1] = '\r';
p->buf[n] = '\n';
p->buf[n+1] = '\0';
send(p->protocol, p->buf, n+1, 0);
//printf("buf = %s,path = %s",p->buf,p->path);
//fflush(stdout);
n = recv(p->protocol, p->buf, BUFFER,0); // 150 from server
p->buf[n] = '\0';
printf("from protocol :\n%s", p->buf);
n = 0;
while(p->path[n])
n++;
f = fopen(p->path,"w");
if(!f) {
perror("error, cannt creat file\n");
return 0;
}
count = 0;
printf("data transfer \n"); fflush(stdout);
do
{
n = recv(p->data, p->buf, BUFFER,0);
count += n;
printf("%d byte transfer process \r",count);
fwrite(p->buf,sizeof(char),n,f);
}
while(n>0);
n = recv(p->protocol, p->buf, BUFFER,0); // 226 from server
p->buf[n] = '\0';
printf("from protocol :\n%s", p->buf);
printf("transfer file %s, date %d byte\n",p->path,count);
fclose(f);
return 1;
}
int put( struct ftp_client *p) // upload file
{
int n = 0;
int count;
FILE *f;
strcpy(p->buf,"STOR //");
strcpy(p->buf+7, p->path);
n = 0;
while(p->buf[n++]); // the command in protocol pipe should be "%s\r\n"
p->buf[n-1] = '\r';
p->buf[n] = '\n';
p->buf[n+1] = '\0';
send(p->protocol, p->buf, n+1, 0);
n = recv(p->protocol, p->buf, BUFFER,0); // 150 from server
p->buf[n] = '\0';
printf("from protocol :\n%s", p->buf);
if (p->buf[0]== '5') // 550 error
return 1;
//read(p->protocol, p->buf, BUFFER); // 226 from server
//printf("from protocol :\n%s", p->buf);
n = 0;
while(p->path[n])
n++;
f = fopen(p->path,"r");
printf("open file path = %s",p->path);fflush(stdout);
if(!f) {
perror("error, cannt open file\n");
return 0;
}
count = 0;
do
{
n = fread(p->buf, sizeof(char), BUFFER, f);
count +=n;
if (n < BUFFER)
{
p->buf[n] = '\0';
write(p->data, p->buf, n);
close(p->data); //close socket indicate fransfer ended
printf("transfer file %s,data transfer is %d byte\n",p->path,count);
break;
}
printf("%d byte transfer process \r",count);
write(p->data, p->buf, n);
}
while(n>0);
n = recv(p->protocol, p->buf, BUFFER,0); // 226 from server
p->buf[n] = '\0';
printf("from protocol :\n%s", p->buf);
fclose(f);
close(p->data);
return 1;
}
int list( struct ftp_client *p)
{
int n;
send(p->protocol, "list\r\n", 6, 0);
n = recv(p->protocol, p->buf, BUFFER,0); // 150 from server
p->buf[n] = '\0';
printf("from fd :\n%s", p->buf);
printf("from data :\n");
do
{
n = recv(p->data, p->buf, BUFFER,0);
p->buf[n] = '\0';
printf("%s", p->buf);
}
while(n>0);
n = recv(p->protocol, p->buf, BUFFER,0); // 226 from server
p->buf[n] = '\0';
printf("from fd :\n%s", p->buf);
close(p->data);
return 1;
}
int print_list( struct ftp_client *p)
{
int n;
FILE *f;
int result;
send(p->protocol, "pasv\r\n", 6, 0);
n = recv(p->protocol, p->buf, BUFFER,0);
p->data = socket(AF_INET, SOCK_STREAM, 0);
n = getport(p->buf);
p->address_data.sin_port = htons(n);
result = connect(p->data, (struct sockaddr *)&p->address_data, p->len); // Now connect our socket to the server's socket.
if(result == -1) {
perror("error, check your ftp ip and port is correct\n");
exit(1);
}
send(p->protocol, "list\r\n", 6, 0);
n = recv(p->protocol, p->buf, BUFFER,0); // 150 from server
f = fopen("list_ftp","w+");
if(!f) {
perror("error, cannt open file list_ftp.txt \n");
return 0;
}
do
{
n = recv(p->data, p->buf, BUFFER,0);
fwrite(p->buf,sizeof(char),n,f);
}
while(n>0);
n = recv(p->protocol, p->buf, BUFFER,0); // 226 from server
close(p->data);
fclose(f);
return 1;
}
int pasv( struct ftp_client *p)
{
int n;
int result;
printf("pasv start \n");fflush(stdout);
int i = 0;
while(1)
{
i++;
if (i > TRY)
{
printf("error pasv mode failed\n");
return 0;
}
send(p->protocol, "pasv\r\n", 6, 0);
n = recv(p->protocol, p->buf, BUFFER,0);
p->buf[++n] = '\0';
//printf("receive = %s\n%d byte\n", p->buf,n);fflush(stdout);
if(p->buf[0] == '5' ) // 550 deny
{
//sleep(1);
printf("%c%c%c\n",p->buf[0],p->buf[1],p->buf[2]);
continue;
}
if(p->buf[0] == '2' ) // 227 success
{
printf("receive = %s\n%d byte\n", p->buf,n);fflush(stdout);
break;
}
}
p->data = socket(AF_INET, SOCK_STREAM, 0);
n = getport(p->buf);
printf("data port is %d\n",n);
p->address_data.sin_port = htons(n);
printf("data pipe connect started \n");
result = connect(p->data, (struct sockaddr *)&p->address_data, p->len); // Now connect our socket to the server's socket.
if(result == -1) {
perror("error, check your ftp ip and port is correct\n");
exit(1);
}
return 1;
}
int getline(char *buf) // get a line of user input
{
int n = 0;
char ch;
while( (ch = getchar()) != '\n')
{
buf[n++] = ch;
}
buf[n++]='\r';
buf[n++]='\n';
buf[n++]='\0';
return n;
}
int getport(char *buf) // get connect port
{
char ch = 0;
int n = 0;
int p1,p2;
while( (ch = buf[n] ) != '(')
{
n++;
}
//printf("getport format :\n%s",buf+n);
sscanf(buf+n+1,"%d,%d,%d,%d,%d,%d",&n,&n,&n,&n,&p1,&p2);
//printf("p1,p2 = %d %d \n",p1,p2);
p1 = (p1<<8) +p2;
//printf("%d",p1);
return p1;
}
enum COMMAND getcmd(struct ftp_client *p) // get user command
{
int n = 0;
int k = 0;
int mode = 0;
enum COMMAND command;
//printf("buf = %s,path = %s",p->buf,p->path);
//fflush(stdout);
while(p->buf[n])
{
p->buf[n] = tolower(p->buf[n]); // change to lower type
n++;
}
p->buf[n-2] = '\0';
k = 0;
while(p->buf[k])
{
if ( p->buf[k] == ' ') // k is the first ' ' for case of "get path "
{
p->buf[k] = '\0';
mode = 1;
break;
}
k++;
}
if (!strcmp(p->buf,"list") || !strcmp(p->buf,"dir"))
command = LIST;
else if (!strcmp(p->buf,"quit"))
command = QUIT;
else if (!strcmp(p->buf,"get"))
{
command = GET;
if (mode == 1)
{
strcpy(p->path, p->buf+k+1);
}
}
else if (!strcmp(p->buf,"cd"))
{
command = CWD;
if (mode == 1)
{
strcpy(p->path, p->buf+k+1);
}
}
else if (!strcmp(p->buf,"d"))
{
command = D;
//printf("dfdf \n");
if (mode == 1)
{
strcpy(p->path, p->buf+k+1);
}
}
else if (!strcmp(p->buf,"u"))
{
command = U ;
//printf("dfdf \n");
if (mode == 1)
{
strcpy(p->path, p->buf+k+1);
}
}
else if (!strcmp(p->buf,"put"))
{
command = PUT;
if (mode == 1)
{
strcpy(p->path, p->buf+k+1);
}
}
else if (!strcmp(p->buf,"print"))
command = PRINT;
else
command = UNKNOW;
return command;
}
int main(int argc, char *argv[])
{
int result;
struct ftp_client c;
int n;
enum COMMAND command;
c.position = 0; // important no directory in stack to be download
c.protocol = socket(AF_INET, SOCK_STREAM, 0); // Name the socket, as agreed with the server
c.address_protocol.sin_family = AF_INET;
c.address_data.sin_family = AF_INET;
if (argc != 3)
{
printf("usage : a.out 10.10.10.10 21");
exit(1);
}
c.address_protocol.sin_addr.s_addr = inet_addr(argv[1]);
c.address_data.sin_addr.s_addr = inet_addr(argv[1]);
c.address_protocol.sin_port = htons(atoi(argv[2]));
c.len = sizeof(c.address_protocol);
printf("connect started \n"); // Now connect our socket to the server's socket.
result = connect(c.protocol, (struct sockaddr *)&c.address_protocol, c.len);
if(result == -1) {
perror("error, check your ftp ip and port is correct\n");
exit(1);
}
// We can now read/write via socket
printf("connect succesful\n");
//memset(c.buf,0,1);
//n = read(c.protocol, c.buf, BUFFER-1); // welcome information from ftp server
//printf("%s", c.buf
/////////////////////////////////////////////////////////////////
int user_len;
int pass_len;
char user[BUFFER];
char pass[BUFFER];
printf("input user name: \n"); //process user name
strcpy(user,"USER ");
user_len = getline(user+5);
printf("input user passcode: \n"); //process user code
strcpy(pass,"PASS ");
pass_len = getline(pass+5);
printf("user = %s,%d\n",user,user_len);
printf("pass = %s,%d\n",pass,pass_len);
recv(c.protocol,c.buf,BUFFER,0);
printf("receive = %s", c.buf);
if(c.buf[0]=='2' && c.buf[1]=='2' && c.buf[2] == '0')
{
send(c.protocol,user,user_len+4,0) ;
}
while(1)
{
read(c.protocol,c.buf,BUFFER);
printf("receive = %s", c.buf);fflush(stdout);
if(c.buf[0]=='2' && c.buf[1]=='3' && c.buf[2] == '0')
break;
send(c.protocol,pass,pass_len+4,0);
sleep(1);
}
memset(c.buf,0,1);
send(c.protocol, "type i\r\n", 8, 0); //data type ascII
n = recv(c.protocol, c.buf, BUFFER,0);
c.buf[n] = '\0';
printf("set type = %s", c.buf);
int k = 6;
send(c.protocol, "syst\r\n", k, 0);
n = recv(c.protocol, c.buf, BUFFER,0);
c.buf[n] = '\0';
printf("syst = %s",c.buf);
while(1)
{
static int flag = 0;
if (flag) break;
printf("please input command:\n");
n = getline(c.buf);
command = getcmd( &c);
printf("command id is %d \ncommand is %s\n",command,c.buf);
switch(command)
{
case LIST:
if ( pasv( &c) ==1 )
list( &c);
else printf("pasv mode failed failed\n");
break;
case UNKNOW:
printf("command unknow \n");
break;
case GET:
pasv( &c);
get( &c);
break;
case PUT:
pasv( &c);
put( &c);
break;
case QUIT:
printf("bye\n");
flag = 1;
break;
case CWD:
cwd( &c);
pasv( &c);
list( &c);
break;
case D:
get_d(&c);
break;
case U:
get_local_d(&c);
break;
case PRINT:
print_list( &c);
break;
default:
printf("unknow error \n");
exit(1);
};
}
close(c.protocol);
close(c.data);
exit(0);
}