/*
 * Copyright (c) 2002-2003 3APA3A
 *
 * please read License Agreement
 *
 * $Id: ftp.c,v 1.3 2003/10/16 13:12:38 vlad Exp $
 */

#include "proxy.h"

int ftplogin(struct clientparam *param) {
	char buf[1024];
	int i;

	while((i = sockgetline(param->remsock, buf, sizeof(buf) - 1, '\n', timeouts[STRING_L])) > 3 && (!isnumber(*buf) || buf[3] == '-'));
	if(i < 3) return 701;
	buf[3] = 0;
	if(atoi(buf)/100 != 2) return 702;
	sprintf(buf, "USER %.32s\r\n", param->extusername?param->extusername:(unsigned char *)"anonymous");
	if((int)send(param->remsock, buf, strlen(buf), 0) != (int)strlen(buf)){
		return 703;
	}
	param->statscli+=strlen(buf);
	while((i = sockgetline(param->remsock, buf, sizeof(buf) - 1, '\n', timeouts[STRING_L])) > 3 && (!isnumber(*buf) || buf[3] == '-')){
		param->statssrv += i;
	}
	if(i < 3) return 704;
	param->statssrv += i;
	buf[3] = 0;
	if(atoi(buf)/100 == 3){
		sprintf(buf, "PASS %.64s\r\n", 
			param->extusername?
				(param->extpassword?
					param->extpassword:(unsigned char *)"")
				:(unsigned char *)"ftp@security.nnov.ru");
		if((int)send(param->remsock, buf, strlen(buf), 0) != (int)strlen(buf)){
			return 705;
		}
		param->statscli+=strlen(buf);
		while((i = sockgetline(param->remsock, buf, sizeof(buf) - 1, '\n', timeouts[STRING_L])) > 3 && (!isnumber(*buf) || buf[3] == '-')){
			param->statssrv += i;
		}
		if(i < 3) return 706;
		param->statssrv += i;
		buf[3] = 0;
	}
	if(atoi(buf)/100 != 2) return 700;
	return 0;
}

int ftpcd(struct clientparam *param, unsigned char* path){
	char buf[1024];
	int i;

	sprintf(buf, "CWD %.512s\r\n", path);
	if((int)send(param->remsock, buf, strlen(buf), 0) != (int)strlen(buf)){
		return 711;
	}
	param->statscli+=strlen(buf);
	while((i = sockgetline(param->remsock, buf, sizeof(buf) - 1, '\n', timeouts[STRING_L])) > 3 && (!isnumber(*buf) || buf[3] == '-')){
		param->statssrv += i;
	}
	if(i < 3) return 712;
	param->statssrv += i;
	buf[3] = 0;
	if(atoi(buf)/100 != 2) return 710;
	return 0;
}

int ftpres(struct clientparam *param){
	char buf[1024];
	int i;

	while((i = sockgetline(param->remsock, buf, sizeof(buf) - 1, '\n', timeouts[STRING_L])) > 3 && (!isnumber(*buf) || buf[3] == '-')){
		param->statssrv += i;
	}
	if(i < 3) return 751;
	param->statssrv += i;
	buf[3] = 0;
	if(atoi(buf)/100 != 2) return 750;
	return 0;
}

int ftpsyst(struct clientparam *param, unsigned char *buf, unsigned len){
	int i;

	if(send(param->remsock, "SYST\r\n", 6, 0) != 6){
		return 721;
	}
	param->statscli+=6;
	while((i = sockgetline(param->remsock, buf, len - 1, '\n', timeouts[STRING_L])) > 3 && (!isnumber(*buf) || buf[3] == '-')){
		param->statssrv += i;
	}
	if(i < 7) return 722;
	param->statssrv += i;
	buf[3] = 0;
	if(atoi(buf)/100 != 2) return 723;
	buf[i-2] = 0;
	strcpy(buf, buf+4);
	return 0;
}

int ftppwd(struct clientparam *param, unsigned char *buf, unsigned len){
	int i;
	char *b, *e;

	if(send(param->remsock, "PWD\r\n", 5, 0) != 5){
		return 731;
	}
	param->statscli += 5;
	while((i = sockgetline(param->remsock, buf, len - 1, '\n', timeouts[STRING_L])) > 3 && (!isnumber(*buf) || buf[3] == '-')){
		param->statssrv += i;
	}
	if(i < 7) return 732;
	param->statssrv += i;
	buf[3] = 0;
	if(atoi(buf)/100 != 2) return 733;
	buf[i-2] = 0;
	b = buf+4;
	if(*b == '\"' && (e = strchr(b+1, '\"'))){
		b++;
		*e = 0;
	}
	strcpy(buf, b);
	return 0;
}

int ftptype(struct clientparam *param, unsigned char* f_type){
	char buf[1024];
	int i;

	sprintf(buf, "TYPE %.512s\r\n", f_type);
	if((int)send(param->remsock, buf, strlen(buf), 0) != (int)strlen(buf)){
		return 741;
	}
	param->statscli+=strlen(buf);
	while((i = sockgetline(param->remsock, buf, sizeof(buf) - 1, '\n', timeouts[STRING_L])) > 3 && (!isnumber(*buf) || buf[3] == '-')){
		param->statssrv += i;
	}
	if(i < 3) return 742;
	param->statssrv += i;
	buf[3] = 0;
	if(atoi(buf)/100 != 2) return 740;
	return 0;
}


SOCKET ftpdata(struct clientparam *param){
	char buf[1024];
	int i;
	char *sb, *se;
	SOCKET s = INVALID_SOCKET;
	unsigned long b1, b2, b3, b4;
	unsigned short b5, b6;
	struct sockaddr_in sa;

	if(send(param->remsock, "PASV\r\n", 6, 0) != 6){
		return INVALID_SOCKET;
	}
	param->statscli+=6;
	while((i = sockgetline(param->remsock, buf, sizeof(buf) - 1, '\n', timeouts[STRING_L])) > 3 && (!isnumber(*buf) || buf[3] == '-')){
		param->statssrv += i;
	}
	if(i < 7) return INVALID_SOCKET;
	param->statssrv += i;
	buf[3] = 0;
	if(atoi(buf)/100 != 2) return INVALID_SOCKET;
	buf[i-2] = 0;
	if(!(sb = strchr(buf+4, '(')) || !(se= strchr(sb, ')'))) return INVALID_SOCKET;
	if(sscanf(sb+1, "%lu,%lu,%lu,%lu,%hu,%hu", &b1, &b2, &b3, &b4, &b5, &b6)!=6) return INVALID_SOCKET;
	sa.sin_family = AF_INET;
	sa.sin_port = htons((unsigned short)((b5<<8)^b6));
	sa.sin_addr.s_addr = htonl((b1<<24)^(b2<<16)^(b3<<8)^b4);
	if ((s=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) return INVALID_SOCKET;
	if(connect(s, (struct sockaddr *)&sa, sizeof(sa))) return INVALID_SOCKET;
	return s;
}

SOCKET ftpcommand(struct clientparam *param, unsigned char * command, unsigned char  *arg) {
	char buf[1024];
	int i;
	SOCKET s;


	s = ftpdata(param);
	if(s==INVALID_SOCKET) return INVALID_SOCKET;
	sprintf(buf, "%.15s%s%.512s\r\n", command, arg?
		(unsigned char *)" ":(unsigned char *)"", 
		arg?arg:(unsigned char *)"");
	if((int)send(param->remsock, buf, strlen(buf), 0) != (int)strlen(buf)){
		close(s);
		return INVALID_SOCKET;
	}
	param->statscli+=strlen(buf);
	while((i = sockgetline(param->remsock, buf, sizeof(buf) - 1, '\n', timeouts[STRING_L])) > 3 && (!isnumber(*buf) || buf[3] == '-')){
		param->statssrv += i;
	}
	if(i < 3) {
		close(s);
		return INVALID_SOCKET;
	}
	param->statssrv += i;
	buf[3] = 0;
	if(atoi(buf)/100 != 1) {
		close(s);
		return INVALID_SOCKET;
	}
	return s;
}
