336 lines
8.6 KiB
C
336 lines
8.6 KiB
C
/*
|
|
* Mbuni - Open Source MMS Gateway
|
|
*
|
|
* MMS Config file reader functions
|
|
*
|
|
* Copyright (C) 2003 - 2005, Digital Solutions Ltd. - http://www.dsmagic.com
|
|
*
|
|
* Paul Bagyenda <bagyenda@dsmagic.com>
|
|
*
|
|
* This program is free software, distributed under the terms of
|
|
* the GNU General Public License, with a few exceptions granted (see LICENSE)
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include "mms_cfg.h"
|
|
|
|
|
|
/* config file representation.
|
|
* 'grps' var is indexed by group name.
|
|
* for multi the value is a list of groups,
|
|
* for single it is a struct
|
|
*/
|
|
struct mCfg {
|
|
Octstr *file;
|
|
Dict *grps;
|
|
};
|
|
|
|
struct mCfgGrp {
|
|
Octstr *name;
|
|
Dict *fields;
|
|
};
|
|
|
|
static void fixup_value(Octstr *value, int lineno)
|
|
{
|
|
Octstr *tmp;
|
|
int i,n;
|
|
|
|
octstr_strip_blanks(value);
|
|
|
|
if (octstr_get_char(value, 0) != '"')
|
|
return;
|
|
if (octstr_get_char(value, octstr_len(value) - 1) != '"')
|
|
error(0, "Missing enclosing '\"' at line %d in conf file", lineno);
|
|
|
|
octstr_delete(value, 0,1); /* strip quotes. */
|
|
octstr_delete(value, octstr_len(value) - 1, 1);
|
|
|
|
tmp = octstr_duplicate(value);
|
|
octstr_delete(value, 0, octstr_len(value));
|
|
|
|
for (i = 0, n = octstr_len(tmp); i < n; i++) {
|
|
int ch = octstr_get_char(tmp, i);
|
|
|
|
if (ch != '\\') {
|
|
octstr_append_char(value, ch);
|
|
continue;
|
|
}
|
|
|
|
i++; /* skip forward. */
|
|
ch = octstr_get_char(tmp,i);
|
|
switch(ch) {
|
|
case '"':
|
|
case '\\':
|
|
default:
|
|
octstr_append_char(value, ch);
|
|
break;
|
|
case 'n':
|
|
octstr_append_char(value, '\n');
|
|
break;
|
|
case 't':
|
|
octstr_append_char(value, '\t');
|
|
break;
|
|
|
|
}
|
|
}
|
|
octstr_destroy(tmp);
|
|
}
|
|
|
|
static int is_multigroup(Octstr *grpname)
|
|
{
|
|
#define OCTSTR(x)
|
|
#define SINGLE_GROUP(name, fields) \
|
|
if (octstr_case_compare(grpname, octstr_imm(#name)) == 0) return 0;
|
|
#define MULTI_GROUP(name, fields) \
|
|
if (octstr_case_compare(grpname, octstr_imm(#name)) == 0) return 1;
|
|
#include "mms_cfg.def"
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int valid_in_group(Octstr *grp, Octstr *field)
|
|
{
|
|
/* first validate whether field is permitted in the group. */
|
|
#define OCTSTR(parm) else if (octstr_case_compare(field,octstr_imm(#parm)) == 0) return 1;
|
|
#define SINGLE_GROUP(grpname, fields) \
|
|
else if (octstr_case_compare(grp, octstr_imm(#grpname)) == 0) { \
|
|
if (0) (void)0; \
|
|
fields \
|
|
}
|
|
#define MULTI_GROUP(name, fields) SINGLE_GROUP(name, fields)
|
|
|
|
if (0)
|
|
(void)0;
|
|
#include "mms_cfg.def"
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void check_and_add_field(mCfgGrp *grp, Octstr *field, Octstr *value, int lineno)
|
|
{
|
|
if (!valid_in_group(grp->name, field))
|
|
info(0, "field `%s' is not expected within group `%s' at line %d in conf file - skipped",
|
|
octstr_get_cstr(field), octstr_get_cstr(grp->name), lineno);
|
|
else if (dict_put_once(grp->fields, field, octstr_duplicate(value)) == 0)
|
|
panic(0, "Duplicate field `%s' at line %d in conf file",
|
|
octstr_get_cstr(field), lineno);
|
|
}
|
|
|
|
mCfg *mms_cfg_read(Octstr *file)
|
|
{
|
|
Octstr *sf;
|
|
List *lines;
|
|
int i, n;
|
|
mCfg *cfg;
|
|
mCfgGrp *grp = NULL;
|
|
int skip = 0;
|
|
|
|
gw_assert(file);
|
|
|
|
if ((sf = octstr_read_file(octstr_get_cstr(file))) == NULL) {
|
|
error(errno, "failed to read config from `%s'", octstr_get_cstr(file));
|
|
return NULL;
|
|
}
|
|
|
|
cfg = gw_malloc(sizeof *cfg);
|
|
cfg->file = octstr_duplicate(file);
|
|
cfg->grps = dict_create(7, NULL);
|
|
|
|
lines = octstr_split(sf, octstr_imm("\n"));
|
|
for (i = 0, n = list_len(lines); i < n; i++) {
|
|
Octstr *current = list_get(lines,i);
|
|
int pos;
|
|
|
|
octstr_strip_blanks(current);
|
|
|
|
if (octstr_len(current) == 0) { /* end of group. */
|
|
grp = NULL;
|
|
skip = 0;
|
|
continue;
|
|
} else if (skip || octstr_get_char(current, 0) == '#')
|
|
continue;
|
|
|
|
if ((pos = octstr_search_char(current, '=',0)) > 0) {
|
|
/* a field name. first see if start of grp */
|
|
Octstr *field = octstr_copy(current,0,pos);
|
|
Octstr *value = octstr_copy(current,pos+1,octstr_len(current));
|
|
|
|
octstr_strip_blanks(field);
|
|
fixup_value(value, i+1);
|
|
#if 0
|
|
info(0, "field/value: [%s - %s]", octstr_get_cstr(field),
|
|
octstr_get_cstr(value));
|
|
#endif
|
|
|
|
if (octstr_case_compare(field, octstr_imm("group")) == 0)
|
|
if (grp == NULL) { /* grp name. */
|
|
int ismulti = is_multigroup(value);
|
|
|
|
if (ismulti < 0) {
|
|
info(0, "Skipping unknown group `%s' at line %d of conf file",
|
|
octstr_get_cstr(value), i+1);
|
|
skip = 1;
|
|
} else {
|
|
grp = gw_malloc(sizeof *grp);
|
|
grp->name = octstr_duplicate(value);
|
|
grp->fields = dict_create(23, (void (*)(void *))octstr_destroy);
|
|
|
|
if (ismulti) {
|
|
List *l = dict_get(cfg->grps, value);
|
|
|
|
if (l == NULL) {
|
|
l = list_create();
|
|
dict_put(cfg->grps, value, l);
|
|
}
|
|
list_append(l, grp);
|
|
} else if (dict_put_once(cfg->grps, value, grp) == 0)
|
|
panic(0, "Group `%s' [at line %d] cannot appear more "
|
|
"than once in config!",
|
|
octstr_get_cstr(value), i+1);
|
|
}
|
|
} else
|
|
panic(0,"`group' is an illegal field name "
|
|
"within a group at line %d in config file!",
|
|
i+1);
|
|
else if (grp) /* an ordinary field name. */
|
|
check_and_add_field(grp, field, value,i+1);
|
|
else
|
|
panic(0, "A group must begin with a `group = group_name' "
|
|
"clause [at line %d in config file]", i+1);
|
|
|
|
octstr_destroy(field);
|
|
octstr_destroy(value);
|
|
} else
|
|
panic(0, "mal-formed entry in conf file at line %d!", i+1);
|
|
}
|
|
|
|
list_destroy(lines, (list_item_destructor_t *)octstr_destroy);
|
|
octstr_destroy(sf);
|
|
return cfg;
|
|
}
|
|
|
|
static void mGrp_destroy(mCfgGrp *grp)
|
|
{
|
|
octstr_destroy(grp->name);
|
|
dict_destroy(grp->fields);
|
|
gw_free(grp);
|
|
}
|
|
|
|
void mms_cfg_destroy(mCfg *cfg)
|
|
{
|
|
List *l;
|
|
int i, n;
|
|
|
|
gw_assert(cfg);
|
|
|
|
for (i = 0, l = dict_keys(cfg->grps), n = list_len(l); i < n; i++) {
|
|
Octstr *grpname = list_get(l, i);
|
|
void *val = dict_get(cfg->grps, grpname);
|
|
if (is_multigroup(grpname)) {
|
|
List *gl = val;
|
|
int j, m = list_len(gl);
|
|
for (j = 0; j < m; j++)
|
|
mGrp_destroy(list_get(gl, j));
|
|
} else
|
|
mGrp_destroy(val);
|
|
}
|
|
list_destroy(l, (list_item_destructor_t *)octstr_destroy);
|
|
dict_destroy(cfg->grps);
|
|
octstr_destroy(cfg->file);
|
|
gw_free(cfg);
|
|
}
|
|
|
|
mCfgGrp *mms_cfg_get_single(mCfg *cfg, Octstr *name)
|
|
{
|
|
gw_assert(name);
|
|
gw_assert(is_multigroup(name) == 0);
|
|
|
|
return dict_get(cfg->grps, name);
|
|
}
|
|
|
|
List *mms_cfg_get_multi(mCfg *cfg, Octstr *name)
|
|
{
|
|
List *l = NULL, *r;
|
|
int i;
|
|
|
|
gw_assert(name);
|
|
gw_assert(is_multigroup(name) == 1);
|
|
|
|
r = dict_get(cfg->grps, name);
|
|
|
|
if (r)
|
|
for (i = 0, l = list_create(); i < list_len(r); i++)
|
|
list_append(l, list_get(r,i));
|
|
return l;
|
|
}
|
|
|
|
Octstr *mms_cfg_get(mCfgGrp *grp, Octstr *name)
|
|
{
|
|
Octstr *val;
|
|
|
|
gw_assert(grp);
|
|
|
|
if (!valid_in_group(grp->name, name))
|
|
panic(0, "Request for invalid field/variable `%s' in group `%s', unexpected!",
|
|
octstr_get_cstr(name), octstr_get_cstr(grp->name));
|
|
|
|
val = dict_get(grp->fields, name);
|
|
|
|
if (!val)
|
|
return NULL;
|
|
else
|
|
return octstr_duplicate(val);
|
|
}
|
|
|
|
int mms_cfg_get_int(mCfgGrp *grp, Octstr *name, long *n)
|
|
{
|
|
Octstr *val = mms_cfg_get(grp, name);
|
|
int ret;
|
|
if (!val)
|
|
return -1;
|
|
ret = octstr_parse_long(n, val, 0, 0);
|
|
octstr_destroy(val);
|
|
return (ret == -1) ? -1 : 0;
|
|
}
|
|
|
|
|
|
int mms_cfg_get_bool(mCfgGrp *grp, Octstr *name, int *bool)
|
|
{
|
|
Octstr *val = mms_cfg_get(grp, name);
|
|
int ret = 0;
|
|
if (!val)
|
|
return -1;
|
|
|
|
if (octstr_case_compare(val, octstr_imm("yes")) == 0 ||
|
|
octstr_case_compare(val, octstr_imm("true")) == 0 ||
|
|
octstr_case_compare(val, octstr_imm("1")) == 0)
|
|
*bool = 1;
|
|
else if (octstr_case_compare(val, octstr_imm("no")) == 0 ||
|
|
octstr_case_compare(val, octstr_imm("false")) == 0 ||
|
|
octstr_case_compare(val, octstr_imm("0")) == 0)
|
|
*bool = 0;
|
|
else {
|
|
error(0, "Unable to convert value `%s' to boolean for field `%s' in group `%s'",
|
|
octstr_get_cstr(val), octstr_get_cstr(name), octstr_get_cstr(grp->name));
|
|
ret = -1;
|
|
}
|
|
|
|
octstr_destroy(val);
|
|
return ret;
|
|
}
|
|
|
|
List *mms_cfg_get_list(mCfgGrp *grp, Octstr *name)
|
|
{
|
|
Octstr *val = mms_cfg_get(grp, name);
|
|
List *l;
|
|
|
|
if (val == NULL)
|
|
return NULL;
|
|
l = octstr_split_words(val);
|
|
octstr_destroy(val);
|
|
return l;
|
|
}
|