/*
**	config.c	- 
**
**
** Copyright (c) 1993-95  David J. Hughes
** Copyright (c) 1995   Hughes Technologies Pty Ltd
**
** Permission to use, copy, and distribute for non-commercial purposes,
** is hereby granted without fee, providing that the above copyright
** notice appear in all copies and that both the copyright notice and this
** permission notice appear in supporting documentation.
**
** This software is provided "as is" without any expressed or implied warranty.
**
**
*/



#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>

#include "common/portability.h"

#define	_MSQL_SERVER_SOURCE
#include "msql.h"



typedef struct {
	char	*section,
		*handle,
		*charVal;
	int	type,
		intVal,
		allowNull;
} Mconf;


/* section	  element	char def	   type	     int def   NULL */
Mconf conf_table [] = {
{"general",	"msql_user",	"msql",		CHAR_TYPE,	0, 	0},
{"general",	"admin_user",	"root",		CHAR_TYPE,	0,	0},
{"general",	"pid_file",	"%I/msql2.pid",	CHAR_TYPE,	0,	0},
{"general",	"inst_dir",	INST_DIR,	CHAR_TYPE,	0,	0},
{"general",	"tcp_port",	NULL,		INT_TYPE,	1114,	0},
{"general",	"unix_port",	"%I/msql2.sock",CHAR_TYPE,	0,	0},
{"system",	"msync_timer",	NULL,		INT_TYPE,	30,	0},
{"system",	"host_lookup",	NULL,		INT_TYPE,	1,	0},
{"system",	"read_only",	NULL,		INT_TYPE,	0,	0},
{"w3-msql",	"auth_host",	NULL,		CHAR_TYPE,	0,	1},
{"w3-msql",	"footer",	NULL,		INT_TYPE,	1,	0},
{"w3-msql",	"force_private",NULL,		INT_TYPE,	0,	0},
{ NULL,		NULL,				0,		0,	0}
};


#define skipWhite(cp) while(*cp=='\t' || *cp==' '){cp++;}
#define getLine(b,s,f)	fgets(b,s,f); curLine++


#define SEC_GENERAL	1
#define SEC_ACL		2
#define SEC_SECURITY	3
#define	SEC_SYSTEM	4
#define	SEC_W3MSQL	5


char	*strdup();
char	*strtok();

int	curLine = 0;

int 	msqlConfigLoaded = 0;

static char * expandConf(str)
	char	*str;
{
	static	char buf[200];
	char	*cp,*cp2;

	if (!str)
		return(NULL);	
	bzero(buf,sizeof(buf));
	cp = str;
	cp2 = buf;
	while(*cp)
	{
		if (*cp == '%')
		{
			switch(*(cp+1))
			{
				case 'I':
					strcpy(cp2, msqlGetCharConf("general",
						"inst_dir"));
					while(*cp2)
						cp2++;
					cp+=2;
					break;

				default:
					*cp2++ = *cp++;
					*cp2++ = *cp++;
					break;
			}
			continue;
		}
		*cp2++ = *cp++;
	}
	return(buf);
}



static void confErr(str)
	char	*str;
{
	fprintf(stderr,"\nConfig Error : %s at line %d\n\n",str,curLine);
	exit(1);
}


static int checkIntVal(str)
	char	*str;
{
	char 	*cp = str;

	while(*cp)
	{
		if (!isdigit(*cp))
			return(-1);
		cp++;
	}
	return(0);
}



static int setConfigEntry(handle,section,value)
	char	*handle,
		*section,
		*value;
{
	Mconf	*cur;
	char	buf[200],
		*cp;

	cur = conf_table;
	while(cur->handle)
	{
		if (strcmp(cur->handle,handle) == 0 &&
		    strcmp(cur->section,section) == 0)
		{
			if (cur->type == CHAR_TYPE)
			{
				if (strcmp(value,"NULL") == 0)
					cur->charVal = NULL;
				else
					cur->charVal = (char *)strdup(value);
			}
			else
			{
				if (checkIntVal(value) == 0)
				{
					cur->intVal = atoi(value);
				}
				else
				{
					cp = value;
					while(*cp)
					{
						*cp = tolower(*cp);
						cp++;
					}
					if(strcmp(value,"true") == 0)
					{
						cur->intVal = 1;
					}
					else 
					{
					if(strcmp(value,"false") == 0)
					{
						cur->intVal = 0;
					}
					else
					{
						confErr("Invalid value");
					}
					}
				}
					
			}
			return(0);
		}
		cur++;
	}
	snprintf(buf,sizeof(buf),
		"Unknown section '%s' or element '%s'",section,handle);
	confErr(buf);
	return(-1);
}



int msqlGetIntConf(section, handle)
	char	*section,
		*handle;
{
	Mconf	*cur;

	cur = conf_table;
	while(cur->handle)
	{
		if (strcmp(cur->section,section)==0 && 
		    strcmp(cur->handle,handle) == 0)
		{
			return(cur->intVal);
		}
		cur++;
	}
	return(-1);
}



char *msqlGetCharConf(section,handle)
	char	*section,
		*handle;
{
	Mconf	*cur;
	static	char nullVal[] = "NULL";

	cur = conf_table;
	while(cur->handle)
	{
		if (strcmp(cur->section,section)==0 && 
		    strcmp(cur->handle,handle) == 0)
		{
			if (cur->charVal == NULL)
			{
				if (cur->allowNull)
					return(NULL);
				else
					return(nullVal);
			}
			return(expandConf(cur->charVal));
		}
		cur++;
	}
	return(NULL);
}






static void processDirective(sec, dir, val)
	char	*sec,
		*dir,
		*val;
{
	char	*cp;

	/*
	** Map to lower case
	*/
	cp = dir;
	while(*cp)
	{
		*cp = tolower(*cp);
		cp++;
	}

	/*
	** Do your thing
	*/
	setConfigEntry(dir,sec,val);
}





int msqlLoadConfigFile(file)
	char	*file;
{
	FILE	*fp;
	char	buf[160],
		*cp,
		*directive,
		*value,
		*path,
		curSection[80];


	/*
	** Find and open the config file
	*/
	msqlConfigLoaded = 1;
	if (file)
	{
		snprintf(buf,sizeof(buf),"%s/%s", INST_DIR, file);
		fp = fopen(buf,"r");
		if (!fp)
		{
			snprintf(buf,sizeof(buf),"%s/%s.conf",INST_DIR,file);
			fp = fopen(buf,"r");
		}
		if (!fp)
		{
			fp = fopen(file,"r");
		}
		if (!fp)
		{
			printf("Load of %s failed\n",file);
			return(-1);
		}
	}
	else
	{
		snprintf(buf,sizeof(buf),"%s/msql.conf", INST_DIR);
		fp = fopen(buf,"r");
	}
	if (!fp)
	{
		path = getenv("MSQL_CONF_FILE");
		if (path)
		{
			fp = fopen(path,"r");
		}
		if (!fp)
		{
			return(-1);
		}
	}


	/*
	** Read and parse the file
	*/
	getLine(buf,160,fp);
	while(!feof(fp))
	{
		/*
		** Dodge blanks
		*/
		cp = buf;
		skipWhite(cp);
		if (*cp == '#' || *cp == '\n')
		{
			getLine(buf,160,fp);
			continue;
		}

		/*
		** Look for a start of section
		*/
		if (*cp == '[')
		{
			directive = (char *)strtok(cp+1," \t]");
			strcpy(curSection,directive);
			getLine(buf,160,fp);
			continue;
		}

		/*
		** Handle directives
		*/
		if (!curSection)
		{
			confErr("Directive prior to section header");
		}

		directive = (char *)strtok(cp, " \t=");
		value = (char *)strtok(NULL, " =\t\n");

		processDirective(curSection, directive,value);

		getLine(buf,160,fp);
	}
	return(0);
}
