#include <Winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>

void MakeSocket (int *);
void ftp_cwd (int *, char *);
void ftp_activelist (int *, int *);
void ftp_passivelist (int *);
int ftp_login (int *, char *, char *);
void ftp_pasv (int *);
void ftp_pwd (int *);
void ftp_port (int *, int *);
void ftp_quit (int *);
void ftp_rest (int *);
void ftp_syst (int *controlC);
void ftp_type (int *);
void GetReply (int *);

char buffer[512];
char prova[1024*30];

void main (int argc, char * argv[])
{
	WSADATA wsadata;
	int controlC, rendezVouz;
	struct sockaddr_in server;
	char ip[16], user[128], pass[128], path[2048];
	int port;

	memset (ip,   0, sizeof (ip));
	strcat (ip, argv[1]);

	port = atoi (argv[2]);

	memset (user, 0, sizeof (user));
	strcat (user, argv[3]);

	memset (pass, 0, sizeof (pass));
	strcat (pass, argv[4]);

	memset (path, 0, sizeof (path));
	strcat (path, argv[5]);

	WSAStartup (2, &wsadata);
	
	MakeSocket (&controlC);

	server.sin_addr.s_addr = inet_addr (ip);
	server.sin_port = htons (port);
	server.sin_family = AF_INET;

	if (connect (controlC, (struct sockaddr *)&server, sizeof (server)) < 0)
	{
		printf ("Pub down");
		return;
	};
	GetReply (&controlC);
	printf ("\n\n");

	if (ftp_login (&controlC, user, pass) < 0)
		return;
	printf ("\n\n");

	ftp_syst (&controlC);
	printf ("\n\n");

	ftp_cwd (&controlC, path);
	printf ("\n\n");

	ftp_pwd (&controlC);
	printf ("\n\n");

	ftp_rest (&controlC);
	printf ("\n\n");

	ftp_type (&controlC);
	printf ("\n\n");

//	ftp_port (&controlC, &rendezVouz);
	ftp_pasv (&controlC);
	printf ("\n\n");

//	ftp_activelist (&controlC, &rendezVouz);
	ftp_passivelist (&controlC);
	printf ("\n\n");

	ftp_quit (&controlC);

#if (!defined( _WIN32 ) || !defined( WIN32 )) 
	close (controlC);
#else
	closesocket (controlC);
	WSACleanup ();
#endif
}

void MakeSocket (int *fd)
{
	int timeout = 5000;

	*fd = socket (AF_INET, SOCK_STREAM, 0);

	setsockopt (*fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
	setsockopt (*fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
}

int ftp_login (int *fd, char *user, char *pass)
{
	char command[300];

	memset (command, 0, sizeof (command));

	strcat (user, "\r\n");
	strcat (pass, "\r\n");

	strcat (command, "USER ");
	strcat (command, user);

	send (*fd, command, strlen (command), 0);
	GetReply (fd);

	if (buffer[0] == '5')
	{
		printf ("Error 5yz\n");
		return -1;
	}

	memset (command, 0, sizeof (command));
	strcat (command, "PASS ");
	strcat (command, pass);

	send (*fd, command, strlen (command), 0);
	GetReply (fd);

	if ((buffer[0] == '4') || (buffer[0] == '5'))
	{
		printf ("Error 5yz\n");
		return -1;
	}
	return 1;
}

void ftp_quit (int *fd)
{
	memset (buffer, 0, sizeof (buffer));

	strcat (buffer, "QUIT\r\n");

	send (*fd, buffer, strlen (buffer), 0);

	GetReply (fd);
}

void GetReply (int *fd)
{
	int n;
	char c;

	do
	{
		memset (buffer, 0, sizeof (buffer));

		n = 0;

		do
		{
			recv (*fd, &c, 1, 0);
			buffer[n] = c;

			n++;
		}
		while (c != '\n');

		buffer[n] = '\0';

		printf ("%s", buffer);
	}
	while (buffer[3] == '-');
}

void ftp_port (int *fd, int *rendezVouz)
{
	char command[300], *port, *ipaddr;
	struct sockaddr_in client, tempIP, tempIP2;
	int len;

	MakeSocket (rendezVouz);

	client.sin_addr.s_addr = htonl (INADDR_ANY);
	client.sin_family = AF_INET;
	client.sin_port = htons (0); //let the PC choose :)
	
	bind (*rendezVouz, (struct sockaddr *)&client, sizeof(client));

	len = sizeof(tempIP);
	getsockname (*rendezVouz, (struct sockaddr *)&tempIP, &len);

	len = sizeof(tempIP);
	getsockname (*fd, (struct sockaddr *)&tempIP2, &len);

	ipaddr = (char *)&tempIP2.sin_addr;
	port   = (char *)&tempIP.sin_port;

	sprintf (command, "PORT %d,%d,%d,%d,%d,%d\r\n", (((int)ipaddr[0]) & 0xff),
													(((int)ipaddr[1]) & 0xff),
													(((int)ipaddr[2]) & 0xff),
													(((int)ipaddr[3]) & 0xff),
													(((int)port[0]) & 0xff),
													(((int)port[1]) & 0xff));

	listen (*rendezVouz, 1);

	printf ("--> %s", command);

	send (*fd, command, strlen (command), 0);
	GetReply (fd);
}

void ftp_syst (int *fd)
{
	send (*fd, "SYST \r\n", 7, 0);
	GetReply (fd);
}

void ftp_activelist (int *fd, int *rendezVouz)
{
	struct sockaddr_in client;
	int dataC;

	send (*fd, "LIST \r\n", 7, 0);
//	GetReply (fd);

	if ((dataC = accept (*rendezVouz, (struct sockaddr *)&client, NULL)) < 0)
		printf ("\naccept fallita\n");

#if (!defined( _WIN32 ) || !defined( WIN32 )) 
	close (*rendezVouz);
#else
	closesocket(*rendezVouz);
#endif

	while (recv (dataC, buffer, sizeof (buffer), 0) > 0)
		printf ("%s", buffer);

	printf ("\n\n");

	GetReply (fd);
}

void ftp_pasv (int *fd)
{
	send (*fd, "PASV \r\n", 7, 0);
	GetReply (fd);
}

void ftp_passivelist (int *fd)
{
	struct sockaddr_in server;
	int p1 = 0, p2 = 0;
	int dataC;

	MakeSocket (&dataC);

	memset (&server, 0, sizeof (server));

	sscanf (buffer, "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)", &server.sin_addr.S_un.S_un_b.s_b1,
																	 &server.sin_addr.S_un.S_un_b.s_b2,
																	 &server.sin_addr.S_un.S_un_b.s_b3,
																	 &server.sin_addr.S_un.S_un_b.s_b4,
																	 &p1, &p2);

	printf ("--> (%d,%d,%d,%d,%d,%d)",	server.sin_addr.S_un.S_un_b.s_b1,
										server.sin_addr.S_un.S_un_b.s_b2,
										server.sin_addr.S_un.S_un_b.s_b3,
										server.sin_addr.S_un.S_un_b.s_b4,
										p1, p2);

	server.sin_port = htons ((p1 * 256) + p2);
	server.sin_family = AF_INET;

	printf (" --> %d\n\n", (p1 * 256) + p2);

	send (*fd, "LIST \r\n", 7, 0);

//	Sleep (3000);

	if (connect (dataC, (struct sockaddr *)&server, sizeof (server)) < 0)
		printf ("error connect");

	GetReply (fd);

	int a;

	while ((a = recv (dataC, buffer, sizeof (buffer), 0)) > 0)
	{
		printf ("%s", buffer);
	}

#if (defined (_WIN32) || defined (WIN32)) 
	closesocket (dataC);
#else
	close (dataC);
#endif

	printf ("\n\n");

	GetReply (fd);
}

void ftp_cwd (int *fd, char *path)
{
	char command[1024];

	memset (&command, 0, sizeof (command));

	strcat (command, "CWD ");
	strcat (command, path);
	strcat (command, " \r\n");

//	printf ("%s", command);

	send (*fd, command, strlen (command), 0);
	GetReply (fd);
}

void ftp_pwd (int *fd)
{
	send (*fd, "PWD \r\n", 6, 0);
	GetReply (fd);
}

void ftp_type (int *fd)
{
	send (*fd, "TYPE A \r\n", 9, 0);
	GetReply (fd);
}

void ftp_rest (int *fd)
{
	send (*fd, "REST 100 \r\n", 11, 0);
	GetReply (fd);

	send (*fd, "REST 0 \r\n", 9, 0);
	GetReply (fd);
}