/* $Id: conffile.c,v 1.11 2003/09/23 19:20:28 doug Exp $
 * 
 * This file is part of EXACT.
 *
 * EXACT is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * EXACT is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with EXACT; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

/* conffile: a simple set of functions to parse and maintain configuration
 * file data.
 *
 * the configuration file consists of lines of name value pairs, separated 
 * by one or more whitespace characters.  comments are indicated by a hash 
 * ('#') symbol.
 */

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <regex.h>
#include <stdlib.h>
#include <string.h>

#include "conffile.h"
#include "apconf.h"
#include "logger.h"

typedef struct {
	char *name;
	char *value;
} param_t;

param_t param[16];
int param_max=0;

char filename[2048]; //arbitrary length for configuration filename
int filename_set=0;

void zap_comments(char *s) {
	while(*s!='\0') {
		if(*s=='#') {
			*s='\0';
			return;
		}
		s++;
	}
}

void conffile_free() {
	int i;
	for(i=0;i<param_max;++i) {
		free(param[i].name);
		free(param[i].value);
	}
	param_max=0;
}

void conffile_reload(int s) {
	conffile_free();
	conffile_read();
	conffile_check();
	logger(LOG_NOTICE, "configuration file reloaded");
	signal(1,conffile_reload);
}

void server_check() {
    apconf *a;
    section *s;
    char *fn;
    char *serverdefs;

    fn=conffile_param("serverdefs");
    serverdefs=strdup(fn);
    logger(LOG_DEBUG, "Reading serverdefs from '%s'\n", serverdefs);
    a = apconf_read(serverdefs);
    if(!a) {
        logger(LOG_ERR, "Fatal Error: cannot read serverdefs file %s\n", 
                conffile_param("serverdefs"));
        exit(4);
    }
    s=apconf_getsec(a, conffile_param("server"));
    if(!s) {
        logger(LOG_ERR, "Server section %s not found in serverdefs file\n",
                conffile_param("server"));
        exit(4);
    }
    param[param_max].name="order";
    param[param_max].value=strdup(s->order);
    param_max++;
    param[param_max].name="match";
    param[param_max].value=strdup(s->match);
    param_max++;
    if(strcmp(conffile_param("order"), "username,address") && 
        strcmp(conffile_param("order"), "address,username")) {
            logger(LOG_ERR, "Fatal Error: order %s incorrect\n", conffile_param("order"));
            exit(4);
    }
    if(strcmp(conffile_param("authtype"), "db") &&
            strcmp(conffile_param("authtype"), "text")) {
        logger(LOG_ERR, "Fatal Error: authtype %s incorrect\n", conffile_param("authtype"));
        exit(4);
    }
}

void conffile_check() {
	char *required_s[]={"pidfile", "maillog", "serverdefs", "server", 
                            "authfile","dumpfile","authtemp","logging","logfile"};
	char *required_i[]={"timeout","flush","suspicious"};
	int i;
	logger(LOG_DEBUG, "checking configuration file\n");
	for(i=0;i<6;++i) {
		if(!conffile_param(required_s[i])) {
			logger(LOG_ERR,"Fatal Error: missing parameter %s\n", required_s[i]);
			exit(4);
		}
	}
	for(i=0;i<3;++i) {
		if(!conffile_param(required_i[i])) {
			logger(LOG_ERR,"Fatal Error: missing parameter %s\n", required_i[i]);
			exit(4);
		}
		if(conffile_param_int(required_i[i])==0) {
			logger(LOG_ERR,"Fatal Error: parameter %s should be an int, but i can't parse %s\n", required_i[i],conffile_param(required_i[i]));
			exit(4);
		}
	}
    server_check();
	logger(LOG_DEBUG, "checking configuration file finished\n");
}

void conffile_setname(char *s) {
	logger(LOG_NOTICE, "Using configuration file %s\n", s);
	strncpy(filename,s,2047);
	filename_set=1;
}

char *conffile_name() {
	if(!filename_set) {
		sprintf(filename, "%s/exact.conf", CONFDIR);
		filename_set=1;
	}
	return filename;
}

void conffile_read() {
	FILE *f;
	char s[1024];
	regex_t rx;
	regmatch_t pm[16];

	regcomp(&rx,"\\([^\t ]*\\)[ \t]*\\(.*\\)",0);
	logger(LOG_DEBUG, "Opening configuration file %s\n", conffile_name());
	f=fopen(conffile_name(),"r");
	if(!f) {
		logger(LOG_ERR, "Cannot read configuration file %s\n", conffile_name());
		exit(5);
	}
	while(fgets(s,1023,f)!=NULL) {
		s[strlen(s)-1]='\0';
		//logger(LOG_DEBUG, "Read from conf file: %s\n", s);
		zap_comments(s);
		
		if(strlen(s)>0 && regexec(&rx,s,16,pm,0)==0 && 
				pm[1].rm_so!=-1 && pm[1].rm_eo!=-1 && pm[2].rm_so!=-1 && pm[2].rm_eo!=-1) {
			param[param_max].name=(char *)malloc(pm[1].rm_eo-pm[1].rm_so+1);
			param[param_max].value=(char *)malloc(pm[2].rm_eo-pm[2].rm_so+1);
			strncpy(param[param_max].name, s+pm[1].rm_so, pm[1].rm_eo-pm[1].rm_so);
			strncpy(param[param_max].value, s+pm[2].rm_so, pm[2].rm_eo-pm[2].rm_so);
			param[param_max].name[pm[1].rm_eo-pm[1].rm_so]=0;
			param[param_max].value[pm[2].rm_eo-pm[2].rm_so]=0;
			logger(LOG_DEBUG, "Config name: [%s] value: [%s]\n", 
					param[param_max].name, param[param_max].value);
			param_max++;
		}
	}
	fclose(f);
	logger(LOG_DEBUG,"Finished reading configuration file\n");
}

char *conffile_param(char *name) {
	int i;
	for(i=0;i<param_max;i++) {
		if(!strcmp(name,param[i].name))
			return(param[i].value);
	}
	return NULL;
}

int conffile_param_int(char *name) {
	char *s=conffile_param(name);
	if(!s) {
		fprintf(stderr, "ERROR: parameter %s does not exist\n", name);
		exit(52);
	}
	return(atoi(s));
}


syntax highlighted by Code2HTML, v. 0.9.1