/*
 * Copyright (c) 1996-2007, OpenFWTK Development Group
 * All rights reserved. See LICENSE.
 */

/* $Id: smftp.c,v 1.6 2007/09/10 02:49:13 arkenoi Exp $ */
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <strings.h>

#include <syslog.h>

#include "smftp.h"

#include "firewall2.h"

#define DIG(a)	((ln)[(a)] - '0')
#define	NUMSIZE	64

int	strwritev(int ofd, int count, ...);
int	trim_eol(char *s);

extern unsigned int	buf_limit;


/* Responses */
int ____read_smftp_response(int ifd, int *cont, char *ln, int maxsize, read_actor *reader)
{
	int	res = 0, len;

	*cont = 0;
	while((len = reader(ifd, ln, maxsize, 0))) {
		/* basically, ignore everything until we get a /^\d{3} / */

		if(len < 4) continue;
		if(!isdigit((ln)[0])) continue;
		if(!isdigit((ln)[1])) continue;
		if(!isdigit((ln)[2])) continue;

		res = (DIG(0)*10 + DIG(1))*10 + DIG(2);
		break;
	}
	*cont = ((ln)[3] != ' ');
	trim_eol(ln);
	return res;
}


int __read_smftp_response(int ifd, char *ln, int maxsize,  read_actor *reader)
{
	int	res = 0, cont;

	do {
		res = ____read_smftp_response(ifd, &cont, ln, maxsize, reader);
	} while(cont);
	return res;
}

int read_smftp_response(int ifd, read_actor *reader)
{
	int	res;
	char	server_resp[1024];

	res = __read_smftp_response(ifd, server_resp, buf_limit, reader);
	return res;
}


void __send_msg(int fd, int num, const char *sep, const char *text, const char *endl)
{
	char	numbuf[NUMSIZE+1];

	if((num > 1000) || (num < 100)) {
		syslog(LOG_ERR,"securityalert: ftp message code %d is out of range", num);
		send_msg(0,500, 0, "ftp message code is out of range");
		proxy_exit();
	}

	snprintf(numbuf, NUMSIZE, "%03d", num);

	strwritev(fd, 4, numbuf, sep, text, endl);
}

void send_msg(int fd, int num, int cont, const char *text)
{
	__send_msg(fd, num, (cont ? "-" : " "), text, "\r\n");
}

void relay_msg(int fd, int num, int cont, const char *text)
{
	__send_msg(fd, num, (cont ? "-(" : " ("), text, ")\r\n");
}



/* Commands */
int ____send_noarg(int ofd, const char *cmd)
{
	if(strwritev(ofd, 2, cmd, "\r\n") < 0) {
		syslog(LOG_ERR, "strwritev(%d) failed: %s", ofd, strerror(errno));
		return -1;
	}
	return 0;
}

int ____handle_noarg(int ofd, const char *cmd, int (*retr)(int fd))
{
	if(____send_noarg(ofd, cmd))
		return 999;
	return retr(ofd);
}

int ____handle_noarg_resp(int ofd, const char *cmd, int (*retr)(int fd, char *, int), char *resp, int max_size)
{
	if(____send_noarg(ofd, cmd))
		return 999;
	return retr(ofd, resp, max_size);
}

int ____send_1str(int ofd, const char *cmd, const char *arg)
{
	if(strwritev(ofd, 4, cmd, " ", arg, "\r\n") < 0) {
		syslog(LOG_ERR, "strwritev(%d) failed: %s", ofd, strerror(errno));
		return -1;
	}
	return 0;
}

int ____handle_1str(int ofd, const char *cmd, const char *arg, int (*retr)(int fd))
{
	if(____send_1str(ofd, cmd, arg))
		return 999;
	return retr(ofd);
}

int ____handle_1str_resp(int ofd, const char *cmd, const char *arg, int (*retr)(int fd, char *, int), char *resp, int max_size)
{
	if(____send_1str(ofd, cmd, arg))
		return 999;
	return retr(ofd, resp, max_size);
}


