/*
 * mxallowd
 * (c) 2007-2009 Michael Stapelberg
 * 
 * See mxallowd.c for description, website and license information
 *
 */
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>

#include "mxallowd.h"
#include "log.h"
#ifdef PF
#include "pf.h"
#endif

#define INT_LENGTH 10

/*
 * Checks if the given string can be converted to an integer
 *
 */
bool isInteger(char *str) {
	/* 
	 * If the string has no content, it can't be an integer.
	 * If it is too long to handle for our int, better return
	 * false also... (7 bits because one is used for sign)
	 *
	 */
	if (strlen(str) == 0 || strlen(str) > INT_LENGTH)
		return false;
	
	char *c;
	for (c = str; *c != 0; c++)
		if (*c < '0' || *c > '9')
			return false;
	return true;
}


/*
 * Loads configuration from configfile
 *
 */
void getNextConfigEntry(FILE *config, char **destName, char **destValue, char *wholeBuffer, int wholeBufferSize) {
	if (fgets(wholeBuffer, wholeBufferSize, config) == wholeBuffer) {
		char *c = wholeBuffer;
		/* Skip whitespaces in the beginning */
		while ((*c == ' ' || *c == '\t') && *c != 0)
			c++;
		*destName = c;
		while (*c != 0 && *c != '\r' && *c != '\n' && *c != ' ' && *c != '\t')
			c++;
		/* Terminate string as soon as whitespaces begin or it's terminated anyway */
		*c = 0;
		c++;

		/* Same for the value: strip whitespaces */
		while ((*c == ' ' || *c == '\t') && *c != 0)
			c++;
		*destValue = c;
		while (*c != 0 && *c != '\r' && *c != '\n' && *c != ' ' && *c != '\t')
			c++;
		*c = 0;
	}
}

/*
 * Checks if the given value is not null and an integer and logs to syslog/stdout
 * if not
 *
 */
bool checkConfigValue(char *value, char *name) {
	if (value == NULL)
		slog("Option \"%s\" requires argument\n", name);
	else
		if (isInteger(value))
			return true;
		else slog("Argument for \"%s\" is not an integer (%s)\n", value, name);
	return false;
}

/*
 * Reads the configuration from the given file
 *
 */
bool read_configuration(char *configfile) {
	FILE *config = fopen(configfile, "r");
	if (config == NULL) {
		slogerror("Could not open configfile");
		return false;
	}
	char *destName = NULL, *destValue = NULL, wholeBuffer[1024];
	while (!feof(config)) {
		getNextConfigEntry(config, &destName, &destValue, wholeBuffer, 1024);
		/* No more entries? We're done! */
		if (destName == NULL)
			break;
		/* Skip comments and empty lines */
		if (destName[0] == '#' || strlen(destName) < 3)
			continue;

		if (strcasecmp(destName, "fake-mailserver") == 0) {
			if (destValue != NULL)
				add_mailserver(&fake_mailservers, destValue);
			else slog("Error: Option \"fake-mailserver\" requires an argument\n");
		} else if (strcasecmp(destName, "real-mailserver") == 0) {
			if (destValue != NULL)
				add_mailserver(&real_mailservers, destValue);
			else slog("Error: Option \"real-mailserver\" requires an argument\n");
		} else if (strcasecmp(destName, "whitelist-time") == 0) {
			if (checkConfigValue(destValue, destName))
				allow_time = atoi(destValue);
#ifdef NFQUEUE
		} else if (strcasecmp(destName, "queue-num") == 0) {
			if (checkConfigValue(destValue, destName))
				queue_num = atoi(destValue);
#else
		} else if (strcasecmp(destName, "pflog-interface") == 0) {
			pflogif = strdup(destValue);
		} else if (strcasecmp(destName, "pcap-filter") == 0) {
			pcap_filter = strdup(destValue);
#endif
		} else if (strcasecmp(destName, "no-rdns-whitelist") == 0) {
			rdns_whitelist = false;
		} else if (strcasecmp(destName, "stdout") == 0) {
			to_stdout = true;
		} else if (strcasecmp(destName, "quiet") == 0) {
			quiet = true;
		} else slog("Unknown configfile option: %s\n", destName);
		destName = destValue = NULL;
	}
	fclose(config);
	return true;
}
