/****************************************************************************
*
* (C) 2001 by Beck IPC GmbH
*
*  Beck IPC GmbH
*  Garbenheimerstr. 36-38
*  D-35578 Wetzlar
*
*  Phone : (49)-6441-905-240
*  Fax   : (49)-6441-905-245
*
* ---------------------------------------------------------------------------
* Module        : ftp.c
*
* Function      : FTP API functions
*                 Use memory model large!!
*
* Compiler		: Tested with Borland C 5.02
*
* Author        : Detlef Gerhardt
* Date          : 20.01.01
* ---------------------------------------------------------------------------

$Header: ftp.c, 3, 16.01.2002 11:51:54, Christoph Stoidner$


$Log:
 3    IPC@CHIP  1.2         16.01.2002 11:51:54  Christoph Stoidner add starteam
      directives
 2    IPC@CHIP  1.1         08.03.2001 15:44:03  Christoph Stoidner
 1    IPC@CHIP  1.0         08.03.2001 15:30:02  Christoph Stoidner
$


* History       :
*
*  Vx.yy                   Author  Changes
*
*             11.01.01      dg    create
*             20.01.01      dg    error handling, malloc ftp connection desc.
/****************************************************************************/

#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alloc.h>
#include "ftp.h"
#include "tcpip.h"
#include "rtos.h"

/****************************************************************************/

//#define FTP_DEBUG

#define BYTE unsigned char
#define WORD unsigned int

#define FTP_BUF_LEN 512
char ftp_buf[FTP_BUF_LEN+1];

/****************************************************************************/

char *strip_crlf(char *s)
{
	int i;

	for (i=strlen(s)-1; i>=0; i--)
	{
		if (s[i]=='\r' || s[i]=='\n')
			s[i] = 0;
		else
			break;
	}
	return s;

}	// strip_crlf()

/****************************************************************************/

int ftp_send(int sd, char *buffer, int buflen)
{
	int cnt,error;

	//printf("ftp_send: %s\r\n",buffer);
	cnt = send(sd,buffer,buflen,0,&error);
	if (error!=0)
	{
		//printf("ftp_send: send error %d\r\n",error);
		return -1;
	}
	return cnt;

}	// ftp_send()

/****************************************************************************/

int ftp_recv(int sd, char *recv_buf, int recv_len, int *error)
{
	int cnt;

	cnt = recv(sd,recv_buf,recv_len,MSG_TIMEOUT,10000l,error);
	//printf("ftp_recv: sd=%d, cnt=%4d, error=%d\r\n",sd,cnt,*error);
	return cnt;

}	// ftp_recv()

/****************************************************************************/

int ftp_recv_msg(int sd, char *buffer, int buflen, int *error)
{
	int idx,cnt;

	buffer[0] = 0;
	idx = 0;
	do
	{
		cnt = recv(sd,buffer+idx,buflen-idx,MSG_TIMEOUT,5000l,error);
		if (*error!=0)
		{
#ifdef FTP_DEBUG
			//printf("ftp_recv_msg: cnt=%d, error=%d\r\n",cnt,*error);
#endif
			return -1;
		}
		else
		{
			//printf("ftp_recv_msg: cnt=%d\r\n",cnt);
			if (cnt>0)
			{
				idx = idx + cnt;
				buffer[idx] = 0;
			}
		}
	} while( GetWaitingBytes(sd,error)>0 );

	return idx;

}	// ftp_recv_msg()

/****************************************************************************/

int ftp_command(int sd, char *cmd, char *response, int resp_len, int *error)
{
	int stat;

	if (strlen(cmd)>0)
	{
		stat = ftp_send(sd,cmd,strlen(cmd));
		if (stat<0)
			return -1;
	}
	stat = ftp_recv_msg(sd,response,resp_len,error);
	strip_crlf(response);
	if (stat<0)
		return -2;
	stat = atoi(ftp_buf);
	return stat;

}	// ftp_command()

/*****************************************************************************
*
*	open a tcp connection
*
*	DestIPStr: destionation IP address format xxx.xxx.xxx.xxx
*	ClientPort: local port (0=random port)
*	HostPort: remote port
*	error: TCP/IP error
*
*	return: socket descriptor (-1 = error)
*/

int ftp_connect(char *DestIPStr, unsigned int ClientPort, unsigned int HostPort, int *error)
{
	struct sockaddr_in addr;
	unsigned long DestIPAddr;
	int sd; // socket descriptor

#ifdef FTP_DEBUG
	printf("ftp_connect %u -> %s:%u\r\n",ClientPort,DestIPStr,HostPort);
#endif

	// open socket
	sd = opensocket(SOCK_STREAM,error);
	if (sd==-1 || *error!=0)
	{
#ifdef FTP_DEBUG
		printf("ftp_connect: error: open socket failed, error=%d\r\n",*error);
#endif
		return -1;
	}

	addr.sin_family = PF_INET;
	addr.sin_port = htons(ClientPort);	// convert byte order
	addr.sin_addr.s_addr =  0;
	if (ClientPort!=0)
	{	// force client port
		bind(sd, (struct sockaddr*)&addr,error);
		if (*error!=0)
		{
#ifdef FTP_DEBUG
			printf("ftp_connect: error: socket bind failed, error=%d\r\n",*error);
#endif
			return -1;
		}
	}
	addr.sin_port = htons(HostPort);	// convert byte order

	// convert server IP address string to binary
	*error = inet_addr(DestIPStr,&DestIPAddr);
	if (*error!=0)
	{
#ifdef FTP_DEBUG
		printf("ftp_connect: error: ip address convert failed ('%s'), error=%d)\r\n",DestIPStr,*error);
#endif
		return -1;
	}
	addr.sin_addr.s_addr = DestIPAddr;

	// establish a connection to the FTP server
	connect(sd,(struct sockaddr*)&addr,error);
	if (*error!=0)
	{
#ifdef FTP_DEBUG
		printf("ftp_connect: error: TCP connect failed, error=%d\r\n",*error);
#endif
		return -1;
	};

#ifdef FTP_DEBUG
	printf("ftp_connect: connection established\r\n");
#endif
	*error = 0;
	return sd;

}	// ftp_connect()

/*****************************************************************************
*
*	open ftp connection
*	creates ftp descriptor entry and returns pointer to it
*
*	DestIPStr: destination ip address, format: xxx.xxxx.xxx.xxx
*	ClientCtrlPort: local port for control connection (0=use random port)
*	ClientDataPort: local port for data connection (0=use random port)
*	HostCtrlPort: server port for control connection (standard ftp port = 21)
*	stat: return code from ftp server
*	error: TCP/IP error
*
*	return: pointer to ftp connection descriptor (NULL = error)
*/

ftp_desc *ftp_open(char *DestIPStr, unsigned int ClientCtrlPort,
				unsigned int ClientDataPort, unsigned int HostCtrlPort,
				int *stat, int *error)
{
	unsigned long DestIPAddr;
	int sd;
	ftp_desc *fd;	// pointer to ftp connection descriptor

	*stat = 0;
#ifdef FTP_DEBUG
	printf("ftp_open %u,%u -> %s:%u\r\n",
		ClientCtrlPort,ClientDataPort,DestIPStr,HostCtrlPort);
#endif

	// set ftp connection descriptor
	fd = malloc(sizeof(ftp_desc));
	if (fd==NULL)
	{
#ifdef FTP_DEBUG
		printf("ftp_open: error: malloc failed\r\n");
#endif
		return NULL;
	}

	sd = ftp_connect(DestIPStr,ClientCtrlPort,HostCtrlPort,error);
	if (sd<=0)
	{
#ifdef FTP_DEBUG
		printf("ftp_open: error: no ftp connection, error=%d\r\n",sd,*error);
#endif
		return 0;
	}
#ifdef FTP_DEBUG
	printf("ftp_open: connected\r\n");
#endif

	// Server is connected - wait a bit to receive the first sign on message string from the email server
	api_sleep(300);

	// receive connect message from ftp server
	*stat = ftp_command(sd,"",ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_open: %s\r\n",ftp_buf);
#endif
	if (*stat!=FTP_MSG_SERVER_READY)
	{
		closesocket(sd,error);
		return 0;
	}

	// set ftp connection descriptor
	inet_addr(DestIPStr,&DestIPAddr);
	fd->sd_ctrl = sd; // socket descriptor for control connection
	fd->sd_data = 0; // no data connection
	fd->local_ctrl_port = ClientCtrlPort;
	fd->local_data_port = ClientDataPort;
	fd->host_ctrl_port = HostCtrlPort;
	fd->host_data_port = 0; // no data port
	fd->HostIPAddr = DestIPAddr;
	strcpy(fd->HostIPStr,DestIPStr);
#ifdef FTP_DEBUG
	printf("ftp_open: ftp connection established\r\n");
#endif
	return fd;

}	// ftp_open()

/*****************************************************************************
*
*	close ftp connection
*
*	ftp_desc: pointer to ftp connection descriptor
*	error: tcp/ip error
*
*	return: 1=ok, 0=error
*/

int ftp_close(ftp_desc *fd, int *error)
{
	int sd;

	sd = fd->sd_ctrl;	// get socket descriptor from ftp connection descriptor
	closesocket(sd,error);

	// remove ftp connection descriptor
	free(fd);

#ifdef FTP_DEBUG
	printf("ftp_close: connection closed\r\n",fd);
#endif
	return 1;

}	// ftp_close()

/*****************************************************************************
*
*	ftp login (USER, PASS)
*
*	ftp_desc: pointer to ftp connection descriptor
*	user: username
*	pass: password
*	stat: return code of ftp server
*	error: error code from tcp/ip
*
*	return: 1=ok, 0=error
*/

int ftp_login(ftp_desc *fd, char *user, char *pass, int *stat, int *error)
{
	int sd;

#ifdef FTP_DEBUG
	//printf("ftp_login: ftp descriptor=%d",fd);
#endif

	sd = fd->sd_ctrl;	// get socket descriptor from ftp connection descriptor

	strcpy(ftp_buf,"USER ");
	strncat(ftp_buf,user,50);
	ftp_buf[5+50] = 0;
	strcat(ftp_buf,"\r\n");
#ifdef FTP_DEBUG
	printf("ftp_login: %s",ftp_buf);
#endif
	*stat = ftp_command(sd,ftp_buf,ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_login: %s\r\n",ftp_buf);
#endif
	if (*stat!=FTP_MSG_USERNAME_OK && *stat!=FTP_MSG_USER_LOGGED_IN)
		return 0;	// error

	strcpy(ftp_buf,"PASS ");
	strncat(ftp_buf,pass,50);
	ftp_buf[5+50] = 0;
	strcat(ftp_buf,"\r\n");
#ifdef FTP_DEBUG
	printf("ftp_login: %s",ftp_buf);
#endif
	*stat = ftp_command(sd,ftp_buf,ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_login: %s\r\n",ftp_buf);
#endif
	if (*stat==FTP_MSG_USER_LOGGED_IN)
		return 1;	// ok
	else
		return 0;	// error

}	// ftp_login()

/*****************************************************************************
*
*	ftp logout (QUIT)
*
*	ftp_desc: pointer to ftp connection descriptor
*	stat: return code of ftp server
*	error: error code from tcp/ip
*
*	return: 1=ok, 0=error
*/

int ftp_logout(ftp_desc *fd, int *stat, int *error)
{
	int sd;

	sd = fd->sd_ctrl;

#ifdef FTP_DEBUG
	printf("ftp_logout: QUIT\r\n",fd);
#endif
	*stat = ftp_command(sd,"QUIT\r\n",ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_logout: %s\r\n",ftp_buf);
#endif
	if (*stat!=FTP_MSG_USERNAME_OK)
		return 1;
	else
		return 0;

}	// ftp_logout()

/*****************************************************************************
*
*	get current directory (PWD)
*
*	ftp_desc: pointer to ftp connection descriptor
*	dirstr: directory string
*	dirlen: max. length for dirstr
*	stat: return code of ftp server
*	error: error code from tcp/ip
*
*	return: 1=ok, 0=error
*
*	reports '/...' or  '\...' depending on the ftp server software and
*	server operating system
*/

int ftp_pwd(ftp_desc *fd, char *dirstr, int dirlen, int *stat, int *error)
{
	char *p1,*p2;
	int sd,n;

	sd = fd->sd_ctrl;

#ifdef FTP_DEBUG
	printf("ftp_pwd: PWD\r\n",fd);
#endif
	*stat = ftp_command(sd,"PWD\r\n",ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_pwd: %s\r\n",ftp_buf);
#endif
	if (*stat!=FTP_MSG_CURRENT_DIRECTORY)
		return 0;
	p1 = strchr(ftp_buf,'"');
	p2 = strchr(p1+1,'"');
	n = (int) (p2-p1-1);
	if (n>dirlen)
		n = dirlen;
	strncpy(dirstr,p1+1,n);
	dirstr[n] = 0;
	return 1;

}	// ftp_pwd()

/*****************************************************************************
*
*	change current directory (CWD)
*
*	fd: pointer to ftp connection descriptor
*	cwdstr: directory string
*	stat: return code of ftp server
*	error: error code from tcp/ip
*
*	return: 1=ok, 0=error
*
*	be sure to use  '/' or  '\' depending on the ftp server software and
*	server operating system
*/

int ftp_cwd(ftp_desc *fd, char *cwdstr, int *stat, int *error)
{
	int sd;

	sd = fd->sd_ctrl;

	strcpy(ftp_buf,"CWD ");
	strncat(ftp_buf,cwdstr,128);
	ftp_buf[4+128] = 0;
	strcat(ftp_buf,"\r\n");
#ifdef FTP_DEBUG
	printf("ftp_cwd: %s",ftp_buf);
#endif
	*stat = ftp_command(sd,ftp_buf,ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_pwd: %s\r\n",ftp_buf);
#endif
	if (*stat==FTP_MSG_REQ_FILE_ACTION_OK)
		return 1;	// ok
	else
		return 0;	// error

}	// ftp_cwd()

/*****************************************************************************
*
*	make directory (MKD)
*
*	fd: pointer to ftp connection descriptor
*	mkdstr: directory string
*	stat: return code of ftp server
*	error: error code from tcp/ip
*
*	return: 1=ok, 0=error
*
*	be sure to use  '/' or  '\' depending on the ftp server software and
*	server operating system
*/

int ftp_mkd(ftp_desc *fd, char *mkdstr, int *stat, int *error)
{
	int sd;

	sd = fd->sd_ctrl;

	strcpy(ftp_buf,"MKD ");
	strncat(ftp_buf,mkdstr,128);
	ftp_buf[4+128] = 0;
	strcat(ftp_buf,"\r\n");
#ifdef FTP_DEBUG
	printf("ftp_mkd: %s",ftp_buf);
#endif
	*stat = ftp_command(sd,ftp_buf,ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_mkd: %s\r\n",ftp_buf);
#endif
	if (*stat==FTP_MSG_DIRECTORY_CREATED)
		return 1;	// ok
	else
		return 0;	// error

}	// ftp_mkd()

/*****************************************************************************
*
*	remove directory (RMD)
*
*	fd: pointer to ftp connection descriptor
*	rmdstr: directory string
*	stat: return code of ftp server
*	error: error code from tcp/ip
*
*	return: 1=ok, 0=error
*
*	be sure to use  '/' or  '\' depending on the ftp server software and
*	server operating system
*/

int ftp_rmd(ftp_desc *fd, char *rmdstr, int *stat, int *error)
{
	int sd;

	sd = fd->sd_ctrl;

	strcpy(ftp_buf,"RMD ");
	strncat(ftp_buf,rmdstr,128);
	ftp_buf[4+128] = 0;
	strcat(ftp_buf,"\r\n");
#ifdef FTP_DEBUG
	printf("ftp_rmd: %s",ftp_buf);
#endif
	*stat = ftp_command(sd,ftp_buf,ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_rmd: %s\r\n",ftp_buf);
#endif
	if (*stat==FTP_MSG_REQ_FILE_ACTION_OK)
		return 1;	// ok
	else
		return 0;	// error

}	// ftp_rmd()

/*****************************************************************************
*
*	delete file (DELE)
*
*	fd: pointer to ftp connection descriptor
*	rmdstr: directory string
*	stat: return code of ftp server
*	error: error code from tcp/ip
*
*	return: 1=ok, 0=error
*/

int ftp_dele(ftp_desc *fd, char *filename, int *stat, int *error)
{
	int sd;

	sd = fd->sd_ctrl;

	strcpy(ftp_buf,"DELE ");
	strncat(ftp_buf,filename,128);
	ftp_buf[4+128] = 0;
	strcat(ftp_buf,"\r\n");
#ifdef FTP_DEBUG
	printf("ftp_delete: %s",ftp_buf);
#endif
	*stat = ftp_command(sd,ftp_buf,ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_delete: %s\r\n",ftp_buf);
#endif
	if (*stat==FTP_MSG_REQ_FILE_ACTION_OK)
		return 1;	// ok
	else
		return 0;	// error

}	// ftp_dele()

/*****************************************************************************
*
*	Send a file to ftp server in ascii or binary mode (passiv)
*
*	fd: pointer to ftp connection discriptor
*	LocalName: local filename
*	RemoteName: remote filename
*	mode: 0 = ascii, 1=binary
*	stat: return code of ftp server
*	error: error code from tcp/ip
*
*	return: 1=ok, 0=error
*
*	Please consider that the FTP protocol often causes trouble with local
*	firewalls because it uses a seperate data connection for file transfer.
*
*	This procedure uses passiv mode to open the data connection. This means
*	that the server determines the host port for the data connection.
*	This can possibly cause trouble with a local firewall, because you can not
*	ask your network administrator to enable a fixed port for your ftp
*	communication.
*	To handle this we will implement active mode in one of the next versions of
*	this example. In active mode the client can tell the server, which port to
*	use for the data connection.
*
*	Another work-around is to ask your network administrator to enable outgoing
*	ftp connections on all ports.
*/

int ftp_sendfile(ftp_desc *fd, char *LocalName, char *RemoteName, int mode,
					int *stat, int *error)
{
	int sd_ctrl,sd_data,i;
	char *p;
	unsigned int i1,i2,host_data_port;
	long trans;
	FILE *fp;

#ifdef FTP_DEBUG
	printf("ftp_sendfile: %s -> %s, fd=%d, mode=%d\r\n",LocalName,RemoteName,fd,mode);
#endif
	sd_ctrl = fd->sd_ctrl;

	// set transfer mode ascii/binary
	if (mode==FTP_ASCII)
		strcpy(ftp_buf,"TYPE A\r\n");
	else
		strcpy(ftp_buf,"TYPE I\r\n");
#ifdef FTP_DEBUG
	printf("ftp_sendfile: %s",ftp_buf);
#endif
	*stat = ftp_command(sd_ctrl,ftp_buf,ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_sendfile: %s\r\n",ftp_buf);
#endif
	if (*stat!=FTP_MSG_TYPE_COMMAND_OK)
		return 0;

	// set passiv mode
#ifdef FTP_DEBUG
	printf("ftp_sendfile: PASV\r\n");
#endif
	*stat = ftp_command(sd_ctrl,"PASV\r\n",ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_sendfile: %s\r\n",ftp_buf);
#endif
	if (*stat!=FTP_MSG_ENTERING_PASSIV_MODE)
		return 0;

	// retrieve portnumber for data connection from response string
	// format: "227 Entering Passiv Mode (ip1,ip2,ip3,ip4,highbyte,lowbyte)."
	// ip1..ip4: ftp server ip-address
	// highbyte,lowbyte: portnumber for data connection
	p = strchr(ftp_buf,'(') + 1;
	if (p==NULL) return 0;
	for (i=0; i<4; i++)
	{
		p = strchr(p,',') + 1;
		if (p==NULL) return 0;
	}
	i1 = atoi(p);
	p = strchr(p,',') + 1;
	if (p==NULL) return 0;
	i2 = atoi(p);
	p = strchr(p,')');
	if (p==NULL) return 0;
	host_data_port = i1*256+i2;

#ifdef FTP_DEBUG
	printf("ftp_sendfile: Open data connection: %u -> %s:%u\r\n",
		fd->local_data_port,fd->HostIPStr,host_data_port);
#endif
	// open data connection to port host_data_port
	sd_data = ftp_connect(fd->HostIPStr,fd->local_data_port,host_data_port,error);
	if (sd_data==-1)
		return 0;
	fd->sd_data = sd_data;
	fd->host_data_port = host_data_port;
#ifdef FTP_DEBUG
	printf("ftp_sendfile: data connection established\r\n");
#endif

	// send STOR command
	strcpy(ftp_buf,"STOR ");
	strncat(ftp_buf,RemoteName,128);
	ftp_buf[5+128] = 0;
	strcat(ftp_buf,"\r\n");
#ifdef FTP_DEBUG
	printf("ftp_sendfile: %s",ftp_buf);
#endif
	*stat = ftp_command(sd_ctrl,ftp_buf,ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_sendfile: %s\r\n",ftp_buf);
#endif
	if (*stat!=FTP_MSG_FILE_STATUS_OK &&
		*stat!=FTP_MSG_DATA_CONNECTION_ALREADY_OPEN)
	{
#ifdef FTP_DEBUG
		printf("ftp_sendfile: error STOR %s (%d)\r\n",RemoteName,*stat);
#endif
		error = 0;	// error !
		goto close_data_conn;
	}

	// send file
	fp = fopen(LocalName,"rb");
	if (fp==NULL)
	{
		printf("ftp_sendfile: error opening %s\r\n",LocalName);
		error = 0;	// error !
		goto close_data_conn;
	}
	trans = 0;
	while (!feof(fp))
	{
		i = fread(ftp_buf,1,FTP_BUF_LEN,fp);
		if (i==0)
			break;
		i = ftp_send(sd_data,ftp_buf,i);
		trans = trans + i;
#ifdef FTP_DEBUG
		printf("ftp_sendfile: %6ld\r",trans);
#endif
	}
#ifdef FTP_DEBUG
	printf("\r\n");
#endif
	fclose(fp);


close_data_conn:
	closesocket(sd_data,error);
#ifdef FTP_DEBUG
	printf("ftp_sendfile: closesocket error=%d\r\n",*error);
#endif
	fd->sd_data = 0;
	fd->host_data_port = 0;

	// receive status message from ftp server
	*stat = ftp_command(sd_ctrl,"",ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_sendfile: %s\r\n",ftp_buf);
#endif
	if (*stat!=FTP_MSG_TRANSFER_COMPLETED)
		return 0;	// error
	else
		return 1;	// ok

}	// ftp_sendfile()

/*****************************************************************************
*
*	receive a file from ftp server in ascii or binary mode (passiv)
*
*	fd: pointer to ftp connection discriptor
*	RemoteName: remote filename
*	LocalName: local filename
*	mode: 0 = ascii, 1=binary
*	stat: return code of ftp server
*	error: error code from tcp/ip
*
*	return: 1=ok, 0=error
*
*	Please consider that the FTP protocol often causes trouble with local
*	firewalls because it uses a seperate data connection for file transfer.
*
*	This procedure uses passiv mode to open the data connection. This means
*	that the server determines the host port for the data connection.
*	This can possibly cause trouble with a local firewall, because you can not
*	ask your network administrator to enable a fixed port for your ftp
*	communication.
*	To handle this we will implement active mode in one of the next versions of
*	this example. In active mode the client can tell the server, which port to
*	use for the data connection.
*
*	Another work-around is to ask your network administrator to enable outgoing
*	ftp connections on all ports.
*/

int ftp_recvfile(ftp_desc *fd, char *RemoteName, char *LocalName, int mode,
					int *stat, int *error)
{
	int sd_ctrl,sd_data,i;
	char *p;
	unsigned int i1,i2,host_data_port;
	long trans;
	FILE *fp;

#ifdef FTP_DEBUG
	printf("ftp_recvfile: %s -> %s, fd=%d, mode=%d\r\n",RemoteName,LocalName,fd,mode);
#endif
	sd_ctrl = fd->sd_ctrl;

	// set transfer mode ascii/binary
	if (mode==FTP_ASCII)
		strcpy(ftp_buf,"TYPE A\r\n");
	else
		strcpy(ftp_buf,"TYPE I\r\n");
#ifdef FTP_DEBUG
	printf("ftp_recvfile: %s",ftp_buf);
#endif
	*stat = ftp_command(sd_ctrl,ftp_buf,ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_recvfile: %s\r\n",ftp_buf);
#endif
	if (*stat!=FTP_MSG_TYPE_COMMAND_OK)
		return 0;

	// set passiv mode
#ifdef FTP_DEBUG
	printf("ftp_recvfile: PASV\r\n");
#endif
	*stat = ftp_command(sd_ctrl,"PASV\r\n",ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_recvfile: %s\r\n",ftp_buf);
#endif
	if (*stat!=FTP_MSG_ENTERING_PASSIV_MODE)
		return 0;

	// retrieve portnumber for data connection from response string
	// format: "227 Entering Passiv Mode (ip1,ip2,ip3,ip4,highbyte,lowbyte)."
	// ip1..ip4: ftp server ip-address
	// highbyte,lowbyte: portnumber for data connection
	p = strchr(ftp_buf,'(') + 1;
	if (p==NULL) return 0;
	for (i=0; i<4; i++)
	{
		p = strchr(p,',') + 1;
		if (p==NULL) return 0;
	}
	i1 = atoi(p);
	p = strchr(p,',') + 1;
	if (p==NULL) return 0;
	i2 = atoi(p);
	p = strchr(p,')');
	if (p==NULL) return 0;
	host_data_port = i1*256+i2;

#ifdef FTP_DEBUG
	printf("ftp_recvfile: Open data connection: %u -> %s:%u\r\n",
		fd->local_data_port,fd->HostIPStr,host_data_port);
#endif
	// open data connection to port host_data_port
	sd_data = ftp_connect(fd->HostIPStr,fd->local_data_port,host_data_port,error);
	fd->sd_data = sd_data;
	fd->host_data_port = host_data_port;
#ifdef FTP_DEBUG
	printf("ftp_recvfile: data connection established\r\n");
#endif

	// send RETR command
	strcpy(ftp_buf,"RETR ");
	strncat(ftp_buf,RemoteName,128);
	ftp_buf[5+128] = 0;
	strcat(ftp_buf,"\r\n");
#ifdef FTP_DEBUG
	printf("ftp_recvfile: %s",ftp_buf);
#endif
	*stat = ftp_command(sd_ctrl,ftp_buf,ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_recvfile: %s\r\n",ftp_buf);
#endif
	if (*stat!=FTP_MSG_FILE_STATUS_OK &&
		*stat!=FTP_MSG_DATA_CONNECTION_ALREADY_OPEN)
	{
#ifdef FTP_DEBUG
		printf("ftp_recvfile: error RETR %s (%d)\r\n",RemoteName,*stat);
#endif
		goto close_data_conn;
	}

	// receive file
	fp = fopen(LocalName,"wb");
	if (fp==NULL)
	{
#ifdef FTP_DEBUG
		printf("ftp_recvfile: error opening %s\r\n",LocalName);
#endif
		error = 0;	// error !
		goto close_data_conn;
	}
	trans = 0;
	do
	{
		i = ftp_recv(sd_data,ftp_buf,512,error);
		if (i==0)
			break;
		if (fwrite(ftp_buf,1,i,fp)!=i)
		{
#ifdef FTP_DEBUG
			printf("ftp_recvfile: error writing file to local drive\r\n");
#endif
			break;		
		}
		trans = trans + i;
#ifdef FTP_DEBUG
		printf("ftp_recvfile: %6ld\r",trans);
#endif
		api_sleep(50);
	} while (i>0);

#ifdef FTP_DEBUG
	printf("\r\n");
#endif
	fclose(fp);


close_data_conn:
	closesocket(sd_data,error);
#ifdef FTP_DEBUG
	printf("ftp_recvfile: closesocket error=%d\r\n",error);
#endif
	fd->sd_data = 0;
	fd->host_data_port = 0;
	*stat = ftp_command(sd_ctrl,"",ftp_buf,FTP_BUF_LEN,error);
#ifdef FTP_DEBUG
	printf("ftp_recvfile: %s\r\n",ftp_buf);
#endif
	if (*stat!=FTP_MSG_TRANSFER_COMPLETED)
		return 0;	// error
	else
		return 1;	// ok

}	// ftp_recvfile()

/*****************************************************************************
*	end of file
*****************************************************************************/

