/*
 * Copyright 2006 Pascal Gloor <pascal.gloor@spale.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "config.h"
#include "debug.h"

NFS_conf *load_config(char *file)
{
	char buf[1000];
	static NFS_conf conf;
	FILE *fh = NULL;
	int lno = 0;

	conf.peer = 0;

	if ( file == NULL )
	{
		fprintf(stderr,"impossible case. bug!? please report.\n");
		goto fail;
	}

	if ( ( fh = fopen(file,"r") ) == NULL )
	{
		perror("fopen");
		goto fail;
	}

	while(fgets(buf, sizeof(buf), fh)!=NULL)
	{
		char *token,*sip,*sp,*dip,*dp;
		long int tmp;

		lno++;

		if ( buf[0] == '#' || buf[0] == ';' || buf[0] == '\r' || buf[0] == '\n' )
			continue;

		if ( ( token = strtok(buf,":") ) == NULL ) goto parse_err;

		if ( strcmp(token,"flow") == 0 )
		{
			if ( conf.peer == MAXFLOW )
			{
				fprintf(stderr,"too many sources, please increase MAXFLOW !\n");
				goto parse_err;
			}
			if ( ( sip = strtok(NULL,":") ) == NULL ) goto parse_err; 
			if ( ( sp  = strtok(NULL,":") ) == NULL ) goto parse_err;  
			if ( ( dip = strtok(NULL,":") ) == NULL ) goto parse_err;  
			if ( ( dp  = strtok(NULL,":\r\n\t ") ) == NULL ) goto parse_err;

			conf.src[conf.peer].sin_family = AF_INET;
			conf.dst[conf.peer].sin_family = AF_INET;

			#ifdef inet_aton
			if ( inet_aton(sip, &conf.src[conf.peer].sin_addr) == 0 ) goto parse_err;
			if ( inet_aton(dip, &conf.dst[conf.peer].sin_addr) == 0 ) goto parse_err;
			#else
			if ( ( conf.src[conf.peer].sin_addr.s_addr = inet_addr(sip) ) == 0 ) goto parse_err;
			if ( ( conf.dst[conf.peer].sin_addr.s_addr = inet_addr(dip) ) == 0 ) goto parse_err;
			#endif

			tmp = strtol(sp, NULL, 10);
			if ( tmp < 0 || tmp > 65535 ) goto parse_err;
			conf.srcif[conf.peer] = tmp;

			tmp = strtol(dp, NULL, 10);
			if ( tmp < 1 || tmp > 65535 ) goto parse_err;
			conf.dst[conf.peer].sin_port = htons(tmp);

			debug(printf("config: peer %i: input from device %s interface %i",conf.peer,inet_ntoa(conf.src[conf.peer].sin_addr), conf.srcif[conf.peer]));
			debug(printf("config: peer %i: output to %s:%i",conf.peer,inet_ntoa(conf.dst[conf.peer].sin_addr), ntohs(conf.dst[conf.peer].sin_port)));

			conf.peer++;
		}
		else if ( strcmp(buf,"local") == 0 )
		{
			if ( ( dip = strtok(NULL,":")  ) == NULL ) goto parse_err; 
			if ( ( dp  = strtok(NULL,":\r\n\t ") ) == NULL ) goto parse_err;

			#ifdef inet_aton
			if ( inet_aton(dip, &conf.sock.sin_addr) == 0 ) goto parse_err;
			#else
			if ( ( conf.sock.sin_addr.s_addr = inet_addr(dip) ) == 0 ) goto parse_err;
			#endif

			tmp = strtol(dp, NULL, 10);
			if ( tmp < 1 || tmp > 65535 ) goto parse_err;
			conf.sock.sin_port = htons(tmp);

			debug(printf("config: listener %s:%i",inet_ntoa(conf.sock.sin_addr),ntohs(conf.sock.sin_port)));
		}
		else
			goto parse_err;
	}

	if ( !feof(fh) )
	{
		fprintf(stderr,"I/O error while reading config.\n");
		goto fail;
	}

	goto ok;

	parse_err:

	fprintf(stderr,"config parse error at line %i.\n",lno);

	fail:

	if ( fh != NULL ) fclose(fh);
	return NULL;

	ok:

	fclose(fh);
	return &conf;
}