/*
Copyright (C) 1999-2004 IC & S dbmail@ic-s.nl
This program 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.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* $Id: config.c 1550 2005-01-07 12:23:02Z paul $
* \file config.c
* \brief read configuration values from a config file
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "dbmail.h"
#include "list.h"
#include "debug.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#define LINESIZE 1024
/* list of all config lists. Every item in this list holds a list for
* the specific service [SERVICE NAME]
*/
static struct list config_list;
/**
*/
struct service_config_list {
char *service_name;
struct list *config_items;
};
/**
* static local function which gets config items for one service.
* \param[in] name name of field to look for
* \param[in] config_items list of configuration items for a service
* \param[out] value will hold value of configuration item
*/
static int GetConfigValueConfigList(const field_t name, struct list *cfg_items,
field_t value);
/*
* ReadConfig()
*
* builds up a linked list of configuration item name/value pairs based upon
* the content of the file cfilename.
* items are given in "name=value" pairs, separated by newlines.
*
* a single config file can contain values for multiple services, each service
* has to be started by "[SERVICE NAME]" and ended by an empty line.
*
* empty lines other than ending ones are ignored as is everything after a '#'
*
* returns 0 on succes, -1 on error unless CONFIG_ERROR_LEVEL is set TRACE_FATAL/TRACE_STOP;
* if so the function will not return upon error but call exit().
*/
int ReadConfig(const char *serviceName, const char *cfilename)
{
struct service_config_list *service_config;
item_t item;
char line[LINESIZE], *tmp, *value, service[LINESIZE];
FILE *cfile = NULL;
int serviceFound = 0, isCommentline;
trace(TRACE_DEBUG, "ReadConfig(): starting procedure");
if (!(service_config =
dm_malloc(sizeof(struct service_config_list)))) {
trace(CONFIG_ERROR_LEVEL, "%s,%s: error allocating memory "
"for config list", __FILE__, __func__);
return -1;
}
if (!(service_config->config_items =
dm_malloc(sizeof(struct list)))) {
trace(TRACE_ERROR, "%s,%s: unable to allocate memory "
"for config items", __FILE__, __func__);
dm_free(service_config);
return -1;
}
service_config->service_name = dm_strdup(serviceName);
(void) snprintf(service, LINESIZE, "[%s]", serviceName);
list_init(service_config->config_items);
if (!(cfile = fopen(cfilename, "r"))) {
trace(CONFIG_ERROR_LEVEL,
"ReadConfig(): could not open config file [%s]",
cfilename);
list_freelist(&(service_config->config_items->start));
dm_free(service_config->config_items);
dm_free(service_config->service_name);
dm_free(service_config);
return -1;
}
do {
if (fgets(line, LINESIZE, cfile) == NULL)
break;
if (feof(cfile) || ferror(cfile))
break;
/* chop whitespace front */
for (tmp = line; (*tmp != '\0') && isspace(*tmp); tmp++);
memmove(line, tmp, strlen(tmp));
if (strncasecmp(line, service, strlen(service)) == 0) {
/* ok entering config block */
serviceFound = 1;
trace(TRACE_DEBUG, "ReadConfig(): found %s tag",
service);
memset(&item, 0, sizeof(item));
while (1) {
isCommentline = 0;
if (fgets(line, LINESIZE, cfile) == NULL)
break;
if (feof(cfile) || ferror(cfile)
|| strlen(line) == 0)
break;
if ((tmp = strchr(line, '#'))) { /* remove comments */
isCommentline = 1;
*tmp = '\0';
}
/* chop whitespace front */
for (tmp = line; ((*tmp != '\0') &&
isspace(*tmp));
tmp++);
memmove(line, tmp, strlen(tmp));
/* chop whitespace at end */
for (tmp = &line[strlen(line) - 1];
tmp >= line && isspace(*tmp); tmp--)
*tmp = '\0';
if (strlen(line) == 0 && !isCommentline)
break; /* empty line specifies ending */
if (!(tmp = strchr(line, '='))) {
trace(TRACE_INFO,
"ReadConfig(): no value specified for service item [%s].",
line);
continue;
}
*tmp = '\0';
value = tmp + 1;
strncpy(item.name, line, FIELDSIZE);
strncpy(item.value, value, FIELDSIZE);
if (!list_nodeadd
(service_config->config_items, &item,
sizeof(item))) {
trace(CONFIG_ERROR_LEVEL,
"ReadConfig(): could not add node");
list_freelist(
&(service_config->
config_items->start));
dm_free(service_config->config_items);
dm_free(service_config->service_name);
dm_free(service_config);
return -1;
}
trace(TRACE_DEBUG,
"ReadConfig(): item [%s] value [%s] added",
item.name, item.value);
}
trace(TRACE_DEBUG,
"ReadConfig(): service %s added", service);
}
/* skip otherwise */
} while (!serviceFound);
trace(TRACE_DEBUG,
"ReadConfig(): config for %s read, found [%ld] config_items",
service, service_config->config_items->total_nodes);
if (fclose(cfile) != 0)
trace(TRACE_ERROR, "%s,%s: error closing file: [%s]",
__FILE__, __func__, strerror(errno));
if (!list_nodeadd(&config_list, service_config,
sizeof(struct service_config_list))) {
trace(CONFIG_ERROR_LEVEL,
"%s,%s: could not add config list",
__FILE__, __func__);
list_freelist(&(service_config->config_items->start));
dm_free(service_config->config_items);
dm_free(service_config->service_name);
dm_free(service_config);
return -1;
}
/* list_nodeadd makes a shallow copy of the service_config_list
struct. So, we need to clean that up.*/
dm_free(service_config);
return 0;
}
void config_free()
{
struct element *el;
struct element *next_el;
struct service_config_list *scl;
/* first free all "sublists" */
el = list_getstart(&config_list);
while(el) {
scl = (struct service_config_list *) el->data;
next_el = el->nextnode;
list_freelist(&(scl->config_items->start));
dm_free(scl->config_items);
dm_free(scl->service_name);
list_nodedel(&config_list, el->data);
el = next_el;
}
/* free global list */
list_freelist(&(config_list.start));
}
int GetConfigValue(const field_t field_name, const char *service_name,
field_t value) {
struct element *el;
struct service_config_list *scl;
el = list_getstart(&config_list);
while(el) {
scl = (struct service_config_list *) el->data;
if (!scl || strlen(scl->service_name) == 0)
trace(TRACE_INFO, "%s,%s: NULL config_list on "
"config list", __FILE__, __func__);
else {
if (strcmp(scl->service_name, service_name) == 0) {
/* found correct list */
GetConfigValueConfigList(field_name,
scl->config_items,
value);
return 0;
}
}
el = el->nextnode;
}
trace(TRACE_DEBUG, "%s,%s config for service %s not found",
__FILE__, __func__, service_name);
return 0;
}
int GetConfigValueConfigList(const field_t name, struct list *config_items,
field_t value)
{
item_t *item;
struct element *el;
assert(config_items);
value[0] = '\0';
trace(TRACE_DEBUG,
"GetConfigValue(): searching value for config item [%s]",
name);
el = list_getstart(config_items);
while (el) {
item = (item_t *) el->data;
if (!item || strlen(item->name) == 0 ||
strlen(item->value) == 0) {
trace(TRACE_INFO,
"GetConfigValue(): NULL item %s in item-list",
item ? (strlen(item->name) > 0?
" value" : " name") : "");
el = el->nextnode;
continue;
}
if (strcasecmp(item->name, name) == 0) {
trace(TRACE_DEBUG,
"GetConfigValue(): found value [%s]",
item->value);
strncpy(value, item->value, FIELDSIZE);
return 0;
}
el = el->nextnode;
}
trace(TRACE_DEBUG, "GetConfigValue(): item not found");
return 0;
}
void SetTraceLevel(const char *service_name)
{
field_t val;
if (GetConfigValue("trace_level", service_name, val) < 0)
trace(TRACE_FATAL, "%s,%s: error getting config!",
__FILE__, __func__);
if (strlen(val) == 0)
configure_debug(TRACE_ERROR, 1, 0);
else
configure_debug(atoi(val), 1, 0);
}
void GetDBParams(db_param_t * db_params)
{
field_t port_string;
field_t sock_string;
if (GetConfigValue("host", "DBMAIL", db_params->host) < 0)
trace(TRACE_FATAL, "%s,%s: error getting config!",
__FILE__, __func__);
if (GetConfigValue("db", "DBMAIL", db_params->db) < 0)
trace(TRACE_FATAL, "%s,%s: error getting config!",
__FILE__, __func__);
if (GetConfigValue("user", "DBMAIL", db_params->user) < 0)
trace(TRACE_FATAL, "%s,%s: error getting config!",
__FILE__, __func__);
if (GetConfigValue("pass", "DBMAIL", db_params->pass) < 0)
trace(TRACE_FATAL, "%s,%s: error getting config!",
__FILE__, __func__);
if (GetConfigValue("sqlport", "DBMAIL", port_string) < 0)
trace(TRACE_FATAL, "%s,%s: error getting config!",
__FILE__, __func__);
if (GetConfigValue("sqlsocket", "DBMAIL", sock_string) < 0)
trace(TRACE_FATAL, "%s,%s: error getting config!",
__FILE__, __func__);
/* check if port_string holds a value */
if (strlen(port_string) != 0) {
db_params->port =
(unsigned int) strtoul(port_string, NULL, 10);
if (errno == EINVAL || errno == ERANGE)
trace(TRACE_FATAL,
"%s,%s: wrong value for sqlport in "
"config file", __FILE__, __func__);
} else
db_params->port = 0;
/* same for sock_string */
if (strlen(sock_string) != 0)
strncpy(db_params->sock, sock_string, FIELDSIZE);
else
db_params->sock[0] = '\0';
}
syntax highlighted by Code2HTML, v. 0.9.1