#include "ftp.h"


/************* Global Variables ****************/
int ftp_cmd_sock=-1;
int ftp_data_cli_sock=-1;
struct timeval ftp_tm;


/***********Private Functions *****************/
int checkRlyCode(char *src,char *needle);
int put_pasv(char *localpath,char *filename,char *recvbuf);
int put_port(char *localpath,char *filename);
int get_pasv(char *localpath,char *filename,char *recvbuf);
int get_port(char *localpath,char *filename);
void logMessage(char *fmt,...);


fd_set ftp_set;
int ftp_retcode;
char ftp_retmsg[513];

int	ftp_read_reply();
int ftp_gets(void);

int	ftp_read_reply()
{
	//int nRet;
	char tmp[5]="xxx ";

	ftp_retcode=0;

	memset(ftp_retmsg, 0, 513);
	
	if(ftp_gets() == -1){
		return 1;
	}	    
		    

	if(ftp_retmsg[3] == '-') 
	{  /* multiline response */
    strncpy(tmp, ftp_retmsg, 3);
    do{
			memset(ftp_retmsg, 0, 513);
      if(ftp_gets() == -1){
      	return 1;
      }
    }while(strncmp(tmp,ftp_retmsg, 4) != 0);
  }
	
	return 0;
}

int ftp_gets(void)
{
	int i=0;
	int nRet;
	char c;
			  
	ftp_retmsg[0] = 0;	
	while(1) 
	{
		ftp_tm.tv_sec  = FTP_TIME_OUT;
		ftp_tm.tv_usec = 0;			
		FD_ZERO(&ftp_set);
		FD_SET(ftp_cmd_sock, &ftp_set);	     	
		if( select(ftp_cmd_sock+1, &ftp_set, NULL, NULL, &ftp_tm) <= 0)
		{
			memset(ftp_retmsg,0,513);
			strcpy(ftp_retmsg,"Connect Server TimeOut.\n");
			return -1;
		}
				
		nRet = recv(ftp_cmd_sock,&c,1,0);        
		if(nRet<=0)
		{
			memset(ftp_retmsg,0,513);
			strcpy(ftp_retmsg,"Server has closed control connection.\n");
			return -1;        	
		}
		if(c == EOF) 
		{
			memset(ftp_retmsg,0,513);
			strcpy(ftp_retmsg,"Server has closed control connection.\n");
			return -1;
		}
		else if(c == '\r') 
		{
			if( select(ftp_cmd_sock+1, &ftp_set, NULL, NULL, &ftp_tm) <= 0)
			{
				memset(ftp_retmsg,0,513);
				strcpy(ftp_retmsg,"Connect Server TimeOut.\n");		    	
				return -1;
			}        	
			nRet = recv(ftp_cmd_sock,&c,1,0);
			if(nRet<=0)
			{
				memset(ftp_retmsg,0,513);
				strcpy(ftp_retmsg,"Server has closed control connection.\n");
				return -1;        	
			}            
			if(c == 0)
				c = '\r';
			else if(c == '\n') 
			{
				ftp_retmsg[i++] = (char)c;
				break;
			} 
			else if(c == EOF)
				/* do nothing */ ;
		}
		else if(c == '\n')
			break;
		if(i < 512)
			ftp_retmsg[i++] = (char)c;
	}

	if(i >= 512) 
	{
		strcpy(ftp_retmsg,"Reply too long (truncated)\n");
		i = 512;
	}

	ftp_retmsg[i] = '\0';
	ftp_retcode = atoi(ftp_retmsg);

	return ftp_retcode;
}



/* 1-failed, 0-success */
int ftp_open(char *remoteip)
{
	struct sockaddr_in addr;
	//char recvbuf[512];
	int nRet;
	
	if(remoteip == NULL || ftp_cmd_sock != -1)
		return 1;
		
	addr.sin_family=AF_INET;
	addr.sin_port=htons(FTP_PORT);
	addr.sin_addr.s_addr=inet_addr(remoteip);
	bzero(&(addr.sin_zero),8);
	
	if((ftp_cmd_sock=socket(AF_INET,SOCK_STREAM,0))==-1)
	{
		logMessage("\tsocket error\n");
		ftp_cmd_sock=-1;
		return 1;
	}
	
	ftp_tm.tv_sec  = FTP_TIME_OUT;
	ftp_tm.tv_usec = 0;
	if(setsockopt(ftp_cmd_sock,SOL_SOCKET,SO_SNDTIMEO,&ftp_tm,sizeof(ftp_tm))==-1)
	{
		logMessage("\tsetsockopt error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	if(setsockopt(ftp_cmd_sock,SOL_SOCKET,SO_RCVTIMEO,&ftp_tm,sizeof(ftp_tm))==-1)
	{
		logMessage("\tsetsockopt error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	if(connect(ftp_cmd_sock,(struct sockaddr*)&addr,sizeof(struct sockaddr))==-1)
	{
		logMessage("\tconnect error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	//memset(recvbuf,0,512);
	//recv(ftp_cmd_sock,recvbuf,512,0);
	//if(checkRlyCode(recvbuf,"220") == 1)
	nRet=ftp_read_reply();
	if(ftp_retcode != 220 || nRet)
	{	
		logMessage("\trecv 220 error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	logMessage("recv:%s\n",ftp_retmsg);
	//close(ftp_cmd_sock);
	return 0;
}

/* 1-failed, 0-success */
int ftp_login(char *username,char *userpass)
{
	int nRet;
	char sendcmd[512];
	char recvbuf[512];
	
	
	if(ftp_cmd_sock == -1)
	{
		return 1;
	}	
	sprintf(sendcmd,"USER %s\r\n",username);
	
	nRet=send(ftp_cmd_sock,sendcmd,strlen(sendcmd),0);
	logMessage("send:%s\n",sendcmd);
	if(nRet == -1)
	{
		logMessage("send name error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}	
	
	memset(recvbuf,0,512);
	recv(ftp_cmd_sock,recvbuf,512,0);
	logMessage("recv:%s\n",recvbuf);
	if(checkRlyCode(recvbuf,"331") == 1)
	{	
		logMessage("\trecv 331 error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	sprintf(sendcmd,"PASS %s\r\n",userpass);
	nRet=send(ftp_cmd_sock,sendcmd,strlen(sendcmd),0);
	logMessage("send:%s\n",sendcmd);
	if(nRet == -1)
	{
		logMessage("\tsend pass error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}	
	memset(recvbuf,0,512);
	recv(ftp_cmd_sock,recvbuf,512,0);
	logMessage("recv:%s\n",recvbuf);
	if(checkRlyCode(recvbuf,"230") == 1)
	{	
		logMessage("\trecv 230 error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	return 0;
}

/* 1-failed, 0-success */
int ftp_cwd(char *remotepath)
{
	int nRet;
	char sendcmd[512];
	char recvbuf[512];
	
	if(ftp_cmd_sock == -1)
	{
		return 1;
	}
	sprintf(sendcmd,"CWD %s\r\n",remotepath);
	nRet=send(ftp_cmd_sock,sendcmd,strlen(sendcmd),0);
	logMessage("send:%s\n",sendcmd);
	if(nRet == -1)
	{
		logMessage("send cwd error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	memset(recvbuf,0,512);
	recv(ftp_cmd_sock,recvbuf,512,0);
	logMessage("recv:%s\n",recvbuf);
	if(checkRlyCode(recvbuf,"250") == 1)
	{	
		logMessage("\trecv 250 error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	return 0;
}

/* 1-failed, 0-success */
int ftp_putfile(char *localpath,char *filename)
{
	int nRet;
	char sendcmd[512];
	char recvbuf[512];
	
	
	if(ftp_cmd_sock == -1 || ftp_data_cli_sock != -1)
	{
		return 1;
	}	
	
	sprintf(sendcmd,"PASV\r\n");
	nRet=send(ftp_cmd_sock,sendcmd,strlen(sendcmd),0);
	logMessage("send:%s\n",sendcmd);
	if(nRet == -1)
	{
		logMessage("send pasv error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	memset(recvbuf,0,512);
	recv(ftp_cmd_sock,recvbuf,512,0);
	logMessage("recv:%s\n",recvbuf);
	//The passive mode is not supported,try use port mode
	//sprintf(recvbuf,"222 test");
	if(checkRlyCode(recvbuf,"227") == 1)
	{
		
		logMessage("\trecv 227 error,try use port mode\n");
		nRet=put_port(localpath,filename);
		if(nRet == 1)
		{
			close(ftp_cmd_sock);
			ftp_cmd_sock=-1;
			return 1;
		}	
	
	}
	//The passive mode is supported
	else
	{
		nRet=put_pasv(localpath,filename,recvbuf);
		if(nRet == 1)
		{
			logMessage("\tput_pasv error\n");
			close(ftp_cmd_sock);
			ftp_cmd_sock=-1;
			return 1;
		}	
	}	
	
	
	return nRet;
}

/* 1-failed, 0-success */
int ftp_getfile(char *localpath,char *filename)
{
	int nRet;
	char sendcmd[512];
	char recvbuf[512];
	
	
	if(ftp_cmd_sock == -1 || ftp_data_cli_sock != -1)
	{
		return 1;
	}
	
	sprintf(sendcmd,"PASV\r\n");
	nRet=send(ftp_cmd_sock,sendcmd,strlen(sendcmd),0);
	logMessage("send:%s\n",sendcmd);
	if(nRet == -1)
	{
		logMessage("send pasv error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	memset(recvbuf,0,512);
	recv(ftp_cmd_sock,recvbuf,512,0);
	logMessage("recv:%s\n",recvbuf);
	//The passive mode is not supported,try use port mode
	if(checkRlyCode(recvbuf,"227") == 1)
	{
		
		logMessage("\trecv 227 error,try use port mode\n");
		nRet=get_port(localpath,filename);
		if(nRet == 1)
		{
			close(ftp_cmd_sock);
			ftp_cmd_sock=-1;
			return 1;
		}	
	
	}
	//The passive mode is supported
	else
	{
		nRet=get_pasv(localpath,filename,recvbuf);
		if(nRet == 1)
		{
			logMessage("\tget_pasv error\n");
			close(ftp_cmd_sock);
			ftp_cmd_sock=-1;
			return 1;
		}	
	}	
	
	
	return nRet;
}

/* 1-failed, 0-success */
int ftp_quit()
{
	int nRet;
	char sendcmd[512];
	char recvbuf[512];
	
	if(ftp_cmd_sock == -1)
	{
		return 1;
	}	
	sprintf(sendcmd,"QUIT\r\n");
	nRet=send(ftp_cmd_sock,sendcmd,strlen(sendcmd),0);
	logMessage("send:%s\n",sendcmd);
	if(nRet == -1)
	{
		logMessage("send quit error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}	
	
	memset(recvbuf,0,512);
	recv(ftp_cmd_sock,recvbuf,512,0);
	logMessage("recv:%s\n",recvbuf);
	if(checkRlyCode(recvbuf,"221") == 1)
	{	
		logMessage("\trecv 221 error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	close(ftp_cmd_sock);
	ftp_cmd_sock=-1;
	
	return 0;
}


/***************** Private Function ******************/
int checkRlyCode(char *src,char *needle)
{
	int i;
	int len;
	int tryagain;
	
	len=strlen(needle);
	
	if(strlen(src) < len)
	{
		return 1;
	}
	
	tryagain=0;
	for(i=0;i<len;i++)
	{
		if(src[i] != needle[i])
		{	
			tryagain=1;
			break;
		}	
	}
	
	if(tryagain)
	{
		if(strstr(src,needle) == NULL)
			return 1;
		else
			return 0;
	}
	return 0;
}

int put_pasv(char *localpath,char *filename,char *recvbuf)
{
	char *pstr;
	int i;
	int portnum;
	char remoteipstr[16];
	char tmpstr[512];
	char *p1,*p2;
	

	char fullfilename[512];
	struct sockaddr_in addr;
	FILE *fp;
	char cbuf[FTP_BUFSIZE];
	char sendcmd[512];
	int nRet;
	size_t numsent,numread;
	
	//get the ip of the remote server
	sprintf(tmpstr,"%s",recvbuf);
	p1=strchr(tmpstr,'(');
	p1++;
	p2=p1;
	for(i=0;i<4;i++)
	{
		p1=strchr(p1,',');
		if(p1 == NULL)
			return 1;
		*p1='.';
	}
	memset(remoteipstr,0,16);
	strncpy(remoteipstr,p2,(int)(p1-p2));
	//logMessage("remoteipstr=%s\n",remoteipstr);
	
	//get the port num of the remote server
	pstr=strchr(recvbuf,'(');
	if(pstr == NULL)
		return 1;
	
	for(i=0;i<4;i++)
	{
		pstr=strchr(pstr,',');
		if(pstr == NULL)
			return 1;
		pstr++;	
	}
	p1=pstr;
	portnum=atoi(p1);	
	p2=strchr(p1,',');
	if(p2 == NULL)
		return 1;
	p2++;
	portnum=portnum*256+atoi(p2);
	//logMessage("portnum=%d\n",portnum);
	
	//connect the server
	addr.sin_family=AF_INET;
	addr.sin_port=htons(portnum);
	addr.sin_addr.s_addr=inet_addr(remoteipstr);
	bzero(&(addr.sin_zero),8);
	
	if((ftp_data_cli_sock=socket(AF_INET,SOCK_STREAM,0))==-1)
	{
		logMessage("\tdata socket error\n");
		ftp_data_cli_sock=-1;
		return 1;
	}
	
	ftp_tm.tv_sec  = FTP_TIME_OUT;
	ftp_tm.tv_usec = 0;
	if(setsockopt(ftp_data_cli_sock,SOL_SOCKET,SO_RCVTIMEO,&ftp_tm,sizeof(ftp_tm))==-1)
	{
		logMessage("\tdata setsockopt error\n");
		close(ftp_data_cli_sock);
		ftp_data_cli_sock=-1;
		return 1;
	}
	if(setsockopt(ftp_data_cli_sock,SOL_SOCKET,SO_SNDTIMEO,&ftp_tm,sizeof(ftp_tm))==-1)
	{
		logMessage("\tdata setsockopt error\n");
		close(ftp_data_cli_sock);
		ftp_data_cli_sock=-1;
		return 1;
	}
	
	if(connect(ftp_data_cli_sock,(struct sockaddr*)&addr,sizeof(struct sockaddr))==-1)
	{
		logMessage("\tdata connect error\n");
		close(ftp_data_cli_sock);
		ftp_data_cli_sock=-1;
		return 1;
	}
	
	memset(fullfilename,0,512);
	sprintf(fullfilename,"%s",localpath);
	strcat(fullfilename,filename);

	//logMessage("fullfilename=%s\n",fullfilename);
	
	memset(sendcmd,0,512);
	sprintf(sendcmd,"STOR %s\r\n",filename);
	nRet=send(ftp_cmd_sock,sendcmd,strlen(sendcmd),0);
	logMessage("send:%s\n",sendcmd);
	if(nRet == -1)
	{
		logMessage("send stor error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	if((fp=fopen(fullfilename,"rb"))==NULL)
	{	
		close(ftp_data_cli_sock);
		ftp_data_cli_sock=-1;
		logMessage("open %s failed\n",fullfilename);
		return 1;
	}
	
	while(1)
	{
		numread = fread(cbuf, sizeof(char), FTP_BUFSIZE, fp);
		if(numread <= 0) 
			break; 
		if((numsent = send(ftp_data_cli_sock, cbuf, numread, 0))==-1) 
			break;
		if(numread != numsent) 
		{
			logMessage("read failed\n");
			close(ftp_data_cli_sock);
			ftp_data_cli_sock=-1;
			fclose(fp);
			return	1;
		}
	}
	fclose(fp);
	close(ftp_data_cli_sock);
	ftp_data_cli_sock=-1;
	
	memset(recvbuf,0,512);
	recv(ftp_cmd_sock,recvbuf,512,0);
	logMessage("recv:%s\n",recvbuf);
	
	if(checkRlyCode(recvbuf,"150") == 1 && checkRlyCode(recvbuf,"125") == 1)
	{	
		logMessage("\trecv 150 & 125 error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	if(strstr(recvbuf,"226") == NULL)
	{	
		memset(recvbuf,0,512);
		recv(ftp_cmd_sock,recvbuf,512,0);
		logMessage("recv:%s\n",recvbuf);
		if(checkRlyCode(recvbuf,"226") == 1)
		{	
			logMessage("\trecv 226 error\n");
			close(ftp_cmd_sock);
			ftp_cmd_sock=-1;
			return 1;
		}
	}
	
	return 0;
}

int put_port(char *localpath,char *filename)
{
	char fullfilename[512];
	FILE *fp;
	char cbuf[FTP_BUFSIZE];
	char sendcmd[512];
	int nRet;
	size_t numsent,numread;
	
	int sockfd_remote;
	int sockfd_local;
	socklen_t addr_size;
	char recvbuf[512];
	char localip[32]={'\0'};
  	struct hostent* host;  
  	int param[6];
  	
  	struct sockaddr_in saSrc;
	struct sockaddr_in saDest;
  	unsigned long arg = 0;
  	char olddir[256];

  	
	//Get local ip
  	memset(localip,0,32);   
  	gethostname(localip,32);   
  	host=gethostbyname(localip);   
  	if(host->h_addr)   
  		sprintf(localip,"%s",inet_ntoa(*((struct in_addr*)host->h_addr)));   
	
	sscanf(localip,"%d.%d.%d.%d",&param[0],&param[1],&param[2],&param[3]);

	addr_size = sizeof(struct sockaddr_in);
	memset(&saSrc,0,addr_size);
	nRet=getsockname(ftp_cmd_sock, (struct sockaddr *)&saSrc, &addr_size);
	if(nRet == -1)
	{
		return 1;
	}
	
	sockfd_local = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd_local==-1) 
	{
		return 1;
	}
	
	memset(&saSrc, 0, addr_size);
	saSrc.sin_family = AF_INET;
	saSrc.sin_port = htons(0);
	nRet = bind(sockfd_local,(struct sockaddr *)&saSrc,addr_size);
	if (nRet == -1) 
	{
		close(sockfd_local);
		return 1;
	}	
	
	nRet = listen(sockfd_local,2);
	if (nRet == -1) 
	{
		close(sockfd_local);
		return 1;
	}
	
	memset(&saSrc, 0, addr_size);
	nRet = getsockname(sockfd_local,(struct sockaddr *)&saSrc,&addr_size);
	if(nRet == -1)
	{
		close(sockfd_local);
		return 1;
	}

	param[4] = ntohs(saSrc.sin_port)/256;
	param[5] = ntohs(saSrc.sin_port)%256;
	
	memset(sendcmd,0,512);
	sprintf(sendcmd,"PORT %d,%d,%d,%d,%d,%d\r\n",param[0],param[1],param[2],
		param[3],param[4],param[5]);
	nRet=send(ftp_cmd_sock,sendcmd,strlen(sendcmd),0);
	logMessage("send:%s\n",sendcmd);
	
	if(nRet == -1)
	{
		logMessage("send port error\n");
		close(sockfd_local);
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	
	memset(recvbuf,0,512);
	recv(ftp_cmd_sock,recvbuf,512,0);
	logMessage("recv:%s\n",recvbuf);
	if(checkRlyCode(recvbuf,"200") == 1)
	{
		logMessage("\trecv 200 error\n");
		close(sockfd_local);
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	getcwd(olddir,256);
	if(chdir(localpath) == -1)
	{
		logMessage("open local dir error\n");
		close(sockfd_local);
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		chdir(olddir);
		return 1;
	}
	
	memset(fullfilename,0,512);
	sprintf(fullfilename,"%s",localpath);
	//strcat(fullfilename,filename);
	sprintf(sendcmd,"STOR %s\r\n",filename);
	nRet=send(ftp_cmd_sock,sendcmd,strlen(sendcmd),0);
	logMessage("send:%s\n",sendcmd);
	if(nRet == -1)
	{
		logMessage("send stor error\n");
		close(sockfd_local);
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	memset(&saDest,0,addr_size);
	sockfd_remote = accept(sockfd_local,(struct sockaddr *)&saDest,&addr_size);
	if(sockfd_remote==-1)
	{
		close(sockfd_local);
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	if((0 != ioctl (sockfd_remote, FIONBIO, &arg)))
	{
		close(sockfd_remote);
		close(sockfd_local);
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}

	if((fp=fopen(filename,"rb"))==NULL)
	{	
		close(sockfd_remote);
		close(sockfd_local);
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		logMessage("open failed\n");
		return 1;
	}
	
	while(1)
	{
		numread = fread(cbuf, sizeof(char), FTP_BUFSIZE, fp);
		if(numread <= 0) 
			break; 
		if((numsent = send(sockfd_remote, cbuf, numread, 0))==-1) 
			break;
		if(numread != numsent) 
		{
			logMessage("read failed\n");
			close(sockfd_remote);
			close(sockfd_local);
			close(ftp_cmd_sock);
			ftp_cmd_sock=-1;
			fclose(fp);
			return	1;
		}
	}
	chdir(olddir);
	fclose(fp);
	close(sockfd_remote);
	
	memset(recvbuf,0,512);
	recv(ftp_cmd_sock,recvbuf,512,0);
	logMessage("recv:%s\n",recvbuf);
	if(checkRlyCode(recvbuf,"150") == 1 && checkRlyCode(recvbuf,"125") == 1)
	{
		logMessage("\trecv 150 & 125 error\n");
		close(sockfd_local);
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	if(strstr(recvbuf,"226") == NULL)
	{	
		memset(recvbuf,0,512);
		recv(ftp_cmd_sock,recvbuf,512,0);
		logMessage("recv:%s\n",recvbuf);
		if(checkRlyCode(recvbuf,"226") == 1)
		{
			logMessage("\trecv 226 error\n");
			close(sockfd_local);
			close(ftp_cmd_sock);
			ftp_cmd_sock=-1;
			return 1;
		}
	}
	return 0;
}

int get_pasv(char *localpath,char *filename,char *recvbuf)
{
	char *pstr;
	int i;
	int portnum;
	char remoteipstr[16];
	char tmpstr[512];
	char *p1,*p2;
	

	char fullfilename[512];
	struct sockaddr_in addr;
	FILE *fp;
	char cbuf[FTP_BUFSIZE];
	char sendcmd[512];
	int nRet;
	size_t numread,numwrite;
	
	//get the ip of the remote server
	sprintf(tmpstr,"%s",recvbuf);
	p1=strchr(tmpstr,'(');
	p1++;
	p2=p1;
	for(i=0;i<4;i++)
	{
		p1=strchr(p1,',');
		if(p1 == NULL)
			return 1;
		*p1='.';
	}
	memset(remoteipstr,0,16);
	strncpy(remoteipstr,p2,(int)(p1-p2));
	//logMessage("remoteipstr=%s\n",remoteipstr);
	
	//get the port num of the remote server
	pstr=strchr(recvbuf,'(');
	if(pstr == NULL)
		return 1;
	
	for(i=0;i<4;i++)
	{
		pstr=strchr(pstr,',');
		if(pstr == NULL)
			return 1;
		pstr++;	
	}
	p1=pstr;
	portnum=atoi(p1);	
	p2=strchr(p1,',');
	if(p2 == NULL)
		return 1;
	p2++;
	portnum=portnum*256+atoi(p2);
	//logMessage("portnum=%d\n",portnum);
	
	
	//connect the server
	addr.sin_family=AF_INET;
	addr.sin_port=htons(portnum);
	addr.sin_addr.s_addr=inet_addr(remoteipstr);
	bzero(&(addr.sin_zero),8);
	
	if((ftp_data_cli_sock=socket(AF_INET,SOCK_STREAM,0))==-1)
	{
		logMessage("\tdata socket error\n");
		ftp_data_cli_sock=-1;
		return 1;
	}
	ftp_tm.tv_sec  = FTP_TIME_OUT;
	ftp_tm.tv_usec = 0;
	if(setsockopt(ftp_data_cli_sock,SOL_SOCKET,SO_RCVTIMEO,&ftp_tm,sizeof(ftp_tm))==-1)
	{
		logMessage("\tdata setsockopt error\n");
		close(ftp_data_cli_sock);
		ftp_data_cli_sock=-1;
		return 1;
	}
	if(setsockopt(ftp_data_cli_sock,SOL_SOCKET,SO_SNDTIMEO,&ftp_tm,sizeof(ftp_tm))==-1)
	{
		logMessage("\tdata setsockopt error\n");
		close(ftp_data_cli_sock);
		ftp_data_cli_sock=-1;
		return 1;
	}
	if(connect(ftp_data_cli_sock,(struct sockaddr*)&addr,sizeof(struct sockaddr))==-1)
	{
		logMessage("\tdata connect error\n");
		close(ftp_data_cli_sock);
		ftp_data_cli_sock=-1;
		return 1;
	}
	memset(fullfilename,0,512);
	sprintf(fullfilename,"%s",localpath);
	strcat(fullfilename,filename);

	//logMessage("fullfilename=%s\n",fullfilename);
	
	memset(sendcmd,0,512);
	sprintf(sendcmd,"RETR %s\r\n",filename);
	nRet=send(ftp_cmd_sock,sendcmd,strlen(sendcmd),0);
	logMessage("send:%s\n",sendcmd);
	if(nRet == -1)
	{
		logMessage("send stor error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	if((fp=fopen(fullfilename,"wb"))==NULL)
	{	
		close(ftp_data_cli_sock);
		ftp_data_cli_sock=-1;
		logMessage("open failed\n");
		return 1;
	}
	
	while(1)
	{
		if(!(numread=recv(ftp_data_cli_sock,cbuf,FTP_BUFSIZE,0)) || numread == -1)
		{
			break;
		}
		else
		{
			numwrite=fwrite(cbuf,sizeof(char),numread,fp);
		}
		//logMessage("numwrite=%d,numread=%d\n",numwrite,numread);
		if(numwrite != numread)
		{
			close(ftp_data_cli_sock);
			ftp_data_cli_sock=-1;
			fclose(fp);
			return 1;
		}
	}
	fclose(fp);
	close(ftp_data_cli_sock);
	ftp_data_cli_sock=-1;
	
	memset(recvbuf,0,512);
	recv(ftp_cmd_sock,recvbuf,512,0);
	logMessage("recv:%s\n",recvbuf);
	if(checkRlyCode(recvbuf,"150") == 1 && checkRlyCode(recvbuf,"125") == 1)
	{	
		logMessage("\trecv 150 & 125 error\n");
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	if(strstr(recvbuf,"226") == NULL)
	{	
		memset(recvbuf,0,512);
		recv(ftp_cmd_sock,recvbuf,512,0);
		logMessage("recv:%s\n",recvbuf);
		if(checkRlyCode(recvbuf,"226") == 1)
		{	
			logMessage("\trecv 226 error\n");
			close(ftp_cmd_sock);
			ftp_cmd_sock=-1;
			return 1;
		}
	}
	
	return 0;
}

int get_port(char *localpath,char *filename)
{
	char fullfilename[512];
	FILE *fp;
	char cbuf[FTP_BUFSIZE];
	char sendcmd[512];
	int nRet;
	size_t numwrite,numread;
	
	int sockfd_remote;
	int sockfd_local;
	socklen_t addr_size;
	char recvbuf[512];
	char localip[32]={'\0'};
  	struct hostent* host;  
  	int param[6];
  	
  	struct sockaddr_in saSrc;
	struct sockaddr_in saDest;
  	unsigned long arg = 0;
  	char olddir[256];
  	
  	//Get local ip
  	memset(localip,0,32);   
  	gethostname(localip,32);   
  	host=gethostbyname(localip);   
  	if(host->h_addr)   
  		sprintf(localip,"%s",inet_ntoa(*((struct in_addr*)host->h_addr)));   
	
	sscanf(localip,"%d.%d.%d.%d",&param[0],&param[1],&param[2],&param[3]);
	//logMessage("localip=%s\n",localip);
	
	addr_size = sizeof(struct sockaddr_in);
	memset(&saSrc,0,addr_size);
	nRet=getsockname(ftp_cmd_sock, (struct sockaddr *)&saSrc, &addr_size);
	if(nRet == -1)
	{
		return 1;
	}
	
	sockfd_local = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd_local==-1) 
	{
		return 1;
	}
	
	memset(&saSrc, 0, addr_size);
	saSrc.sin_family = AF_INET;
	saSrc.sin_port = htons(0);
	nRet = bind(sockfd_local,(struct sockaddr *)&saSrc,addr_size);
	if (nRet == -1) 
	{
		close(sockfd_local);
		return 1;
	}	
	
	nRet = listen(sockfd_local,2);
	if (nRet == -1) 
	{
		close(sockfd_local);
		return 1;
	}
	
	memset(&saSrc, 0, addr_size);
	nRet = getsockname(sockfd_local,(struct sockaddr *)&saSrc,&addr_size);
	if(nRet == -1)
	{
		close(sockfd_local);
		return 1;
	}

	param[4] = ntohs(saSrc.sin_port)/256;
	param[5] = ntohs(saSrc.sin_port)%256;
	
	memset(sendcmd,0,512);
	sprintf(sendcmd,"PORT %d,%d,%d,%d,%d,%d\r\n",param[0],param[1],param[2],
		param[3],param[4],param[5]);
		
	nRet=send(ftp_cmd_sock,sendcmd,strlen(sendcmd),0);
	logMessage("send:%s\n",sendcmd);
	if(nRet == -1)
	{
		logMessage("send port error\n");
		close(sockfd_local);
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	memset(recvbuf,0,512);
	recv(ftp_cmd_sock,recvbuf,512,0);
	logMessage("recv:%s\n",recvbuf);
	if(checkRlyCode(recvbuf,"200") == 1)
	{
		logMessage("\trecv 200 error\n");
		close(sockfd_local);
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	getcwd(olddir,256);
	if(chdir(localpath) == -1)
	{
		logMessage("open local dir error\n");
		close(sockfd_local);
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		chdir(olddir);
		return 1;
	}
	
	memset(fullfilename,0,512);
	sprintf(fullfilename,"%s",localpath);
	//strcat(fullfilename,filename);
	sprintf(sendcmd,"RETR %s\r\n",filename);
	nRet=send(ftp_cmd_sock,sendcmd,strlen(sendcmd),0);
	logMessage("send:%s\n",sendcmd);
	if(nRet == -1)
	{
		logMessage("send retr error\n");
		close(sockfd_local);
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
  	
  	memset(&saDest, 0, addr_size);
	sockfd_remote = accept(sockfd_local,(struct sockaddr *)&saDest,&addr_size);
	if(sockfd_remote==-1)
	{
		close(sockfd_local);
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	if((0 != ioctl (sockfd_remote, FIONBIO, &arg)))
	{
		close(sockfd_remote);
		close(sockfd_local);
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}

	if((fp=fopen(filename,"wb"))==NULL)
	{	
		close(sockfd_remote);
		close(sockfd_local);
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		logMessage("open failed\n");
		return 1;
	}
	
	while(1)
	{
		if(!(numread=recv(sockfd_remote,cbuf,FTP_BUFSIZE,0)) || numread == -1)
		{
			break;
		}
		else
		{
			numwrite=fwrite(cbuf,sizeof(char),numread,fp);
		}
		//logMessage("numwrite=%d,numread=%d\n",numwrite,numread);
		if(numwrite != numread)
		{
			close(sockfd_remote);
			sockfd_remote=-1;
			fclose(fp);
			return 1;
		}
	}
	chdir(olddir);
	fclose(fp);
	close(sockfd_remote);
	
	memset(recvbuf,0,512);
	recv(ftp_cmd_sock,recvbuf,512,0);
	logMessage("recv:%s\n",recvbuf);
	if(checkRlyCode(recvbuf,"150") == 1 && checkRlyCode(recvbuf,"125") == 1)
	{
		logMessage("\trecv 150 & 125 error\n");
		close(sockfd_local);
		close(ftp_cmd_sock);
		ftp_cmd_sock=-1;
		return 1;
	}
	
	if(strstr(recvbuf,"226") == NULL)
	{	
		memset(recvbuf,0,512);
		recv(ftp_cmd_sock,recvbuf,512,0);
		logMessage("recv:%s\n",recvbuf);
		if(checkRlyCode(recvbuf,"226") == 1)
		{
			logMessage("\trecv 226 error\n");
			close(sockfd_local);
			close(ftp_cmd_sock);
			ftp_cmd_sock=-1;
			return 1;
		}
	}
  	
	return 0;
}


void logMessage(char *fmt,...)
{
#if FTP_DEBUG
	va_list arg_ptr;
	va_start(arg_ptr,fmt);
	vprintf(fmt,arg_ptr);
	va_end(arg_ptr);
#endif	
}


