426 lines
8.8 KiB
C
426 lines
8.8 KiB
C
/*
|
|
* binkleyforce -- unix FTN mailer project
|
|
*
|
|
* Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11
|
|
*
|
|
* 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.
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#include "includes.h"
|
|
#include "confread.h"
|
|
#include "logger.h"
|
|
#include "util.h"
|
|
|
|
#define COMMENTCHR '#'
|
|
#define PREPROCCHR '$'
|
|
#define ESCAPECHR '\\'
|
|
|
|
int conf_postreadcheck(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
const char *conf_getconfname(void)
|
|
{
|
|
const char *name = getenv("BFCONFIG");
|
|
if( name == NULL || *name == '\0' ) name = BFORCE_CFGFILE;
|
|
return(name);
|
|
}
|
|
|
|
/*int conf_readpasswdlist(s_falist **pwdlist, char *fname)
|
|
{
|
|
return(0);
|
|
} */
|
|
|
|
/*
|
|
* Prepare config string for parsing, check for comments
|
|
* Return: zero - good string, non-zero - .. (you know)
|
|
*/
|
|
static int conf_checkstr(char *str)
|
|
{
|
|
int rc = 0;
|
|
char *p = NULL;
|
|
|
|
ASSERT(str != NULL);
|
|
|
|
if( isspace(*str) ) string_trimleft(str);
|
|
if( *str == '\0' || *str == COMMENTCHR )
|
|
{ rc = 1; }
|
|
|
|
if( (p = strrchr(str, COMMENTCHR)) && *(p-1) != ESCAPECHR )
|
|
{ *p = '\0'; }
|
|
|
|
string_trimright(str);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* Parse config string on: keyword, expression and value
|
|
* Return: zero - no errors, non-zero - incorrect syntax
|
|
*/
|
|
static void conf_parsestr(char *str, char **key, char **expr, char **value)
|
|
{
|
|
char *k = NULL; /* Keyword */
|
|
char *e = NULL; /* Expression */
|
|
char *v = NULL; /* Value */
|
|
char *p = NULL;
|
|
int brackets = 0;
|
|
|
|
ASSERT(str != NULL && key != NULL && expr != NULL && value != NULL);
|
|
|
|
*key = NULL; *expr = NULL; *value = NULL;
|
|
|
|
/* Get config keyword */
|
|
k = str;
|
|
while( isspace(*k) ) k++;
|
|
p = k;
|
|
while( !isspace(*p) && *p ) p++;
|
|
if( *p == '\0' )
|
|
{ *key = k; return; }
|
|
*p++ = '\0';
|
|
|
|
while( isspace(*p) ) p++;
|
|
v = p;
|
|
|
|
/* Get config expression (if specified) */
|
|
if( *p == '(' )
|
|
{
|
|
++p;
|
|
while( isspace(*p) ) p++;
|
|
for( e = p, brackets = 1; brackets > 0 && *p; )
|
|
{
|
|
if( *(p-1) != ESCAPECHR )
|
|
{
|
|
switch( *p ) {
|
|
case '(':
|
|
++brackets; break;
|
|
case ')':
|
|
--brackets; break;
|
|
}
|
|
}
|
|
if( brackets > 0 ) ++p;
|
|
}
|
|
if( *p != ')' ) return; /* No closing bracket */
|
|
/* Remove trailing spaces */
|
|
v = p--;
|
|
while( p > e && isspace(*p) ) *p-- = '\0';
|
|
*v++ = '\0';
|
|
}
|
|
|
|
/* Get config value */
|
|
while( isspace(*v) ) v++;
|
|
if( *v == '\0' )
|
|
{ *key = k; *expr = e; return; }
|
|
/* Remove trailing spaces */
|
|
p = v + strlen(v+1);
|
|
while( p > v && isspace(*p) ) *p-- = '\0';
|
|
|
|
/* Return information to function caller */
|
|
*key = k;
|
|
*expr = e;
|
|
*value = v;
|
|
|
|
return;
|
|
}
|
|
|
|
int conf_readconf(const char *confname, int inclevel, bool earlydbg)
|
|
{
|
|
if (earlydbg)
|
|
fprintf(stderr,"BF-DEBUG: Parsing config file: %s %d\n", confname, inclevel);
|
|
|
|
FILE *fp = NULL;
|
|
char tmp[BF_MAXCFGLINE + 1];
|
|
int rc, maxrc = 0;
|
|
int line = 0;
|
|
char *fullstr = NULL; /* Result of strings concatenation */
|
|
char *value = NULL;
|
|
char *expr = NULL;
|
|
char *p_key = NULL;
|
|
char *p_expr = NULL;
|
|
char *p_value = NULL;
|
|
char *p = NULL;
|
|
char *ifexpr = NULL; /* Pointer to the `common' block expression */
|
|
bool isappend = FALSE; /* Append new string to the previous? */
|
|
bool isifexpr = FALSE; /* We are in `common' config block! */
|
|
|
|
if( inclevel == 0 )
|
|
{
|
|
int i;
|
|
|
|
/* Check config table correctness */
|
|
for( i = 0; bforce_config[i].name; i++ )
|
|
{
|
|
if( i != (int)bforce_config[i].real_key )
|
|
{
|
|
if (earlydbg)
|
|
fprintf(stderr,"BF-DEBUG: invalid config table: found %d instead of %d\n",
|
|
bforce_config[i].real_key, i);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( (fp = file_open(confname,"r")) == NULL )
|
|
{
|
|
if (earlydbg)
|
|
fprintf(stderr,"BF-DEBUG: can't open config file \"%s\"\n", confname);
|
|
return(PROC_RC_ABORT);
|
|
}
|
|
if (earlydbg)
|
|
fprintf(stderr,"BF-DEBUG: start reading config \"%s\"\n", confname);
|
|
|
|
while( fgets(tmp, sizeof(tmp), fp) )
|
|
{
|
|
++line;
|
|
string_chomp(tmp);
|
|
|
|
if( conf_checkstr(tmp) )
|
|
{
|
|
if( isifexpr )
|
|
{
|
|
if (earlydbg)
|
|
fprintf(stderr,"BF-DEBUG: warning: automatically close expression at empty line %d\n", line);
|
|
|
|
if( ifexpr ) { free(ifexpr); ifexpr = NULL; }
|
|
isifexpr = FALSE;
|
|
}
|
|
|
|
if( !isappend )
|
|
continue;
|
|
|
|
if (earlydbg)
|
|
fprintf(stderr,"BF-DEBUG: warning: appending empty or comment line %d\n", line);
|
|
|
|
|
|
isappend = FALSE;
|
|
}
|
|
|
|
p = tmp + strlen(tmp+1);
|
|
|
|
if( *p == '\\' && *(p-1) != ESCAPECHR )
|
|
{
|
|
*p = '\0';
|
|
if( fullstr && isappend )
|
|
{
|
|
fullstr = xstrcat(fullstr, tmp);
|
|
}
|
|
else
|
|
{
|
|
if( fullstr ) free(fullstr);
|
|
fullstr = xstrcpy(tmp);
|
|
isappend = TRUE;
|
|
}
|
|
continue;
|
|
}
|
|
else if( isappend )
|
|
{
|
|
if( fullstr )
|
|
{ fullstr = xstrcat(fullstr, tmp); }
|
|
else
|
|
{ ASSERT_MSG(); }
|
|
isappend = FALSE;
|
|
}
|
|
|
|
/*
|
|
* Now we have string without comments
|
|
* and trailing/leading spaces in:
|
|
* - if single string than in $tmp[]
|
|
* - if concatanated strings than look $fullstr
|
|
*/
|
|
|
|
p_key = NULL;
|
|
p_expr = NULL;
|
|
p_value = NULL;
|
|
|
|
conf_parsestr(fullstr ? fullstr : tmp, &p_key, &p_expr, &p_value);
|
|
if (earlydbg)
|
|
fprintf(stderr, "BF-DEBUG: conf_readconf: [%d] key \"%s\" expr \"%s\" value \"%s\"\n",
|
|
line, p_key, p_expr, p_value);
|
|
|
|
|
|
if( p_value )
|
|
{
|
|
value = xstrcpy(p_value);
|
|
string_dequote(value, p_value);
|
|
}
|
|
|
|
if( p_expr )
|
|
{
|
|
expr = xstrcpy(p_expr);
|
|
string_dequote(expr, p_expr);
|
|
}
|
|
|
|
if( p_key && *p_key == PREPROCCHR )
|
|
{
|
|
/* Preprocessor directives */
|
|
|
|
rc = PROC_RC_OK;
|
|
|
|
if( strcasecmp(p_key+1, "include") == 0 )
|
|
{
|
|
if( value == NULL || expr )
|
|
{
|
|
if (earlydbg)
|
|
fprintf(stderr, "BF-DEBUG: incorrect usage of `%s' directive\n", p_key);
|
|
|
|
rc = PROC_RC_IGNORE;
|
|
}
|
|
else if( inclevel < MAXINCLUDELEVEL )
|
|
{
|
|
if (earlydbg)
|
|
fprintf(stderr, "BF-DEBUG: conf_readconf: process inlude file \"%s\"\n", value);
|
|
|
|
rc = conf_readconf(value, inclevel + 1, earlydbg);
|
|
if( rc ) rc = PROC_RC_IGNORE;
|
|
}
|
|
else
|
|
{
|
|
if (earlydbg)
|
|
fprintf(stderr, "BF-DEBUG: conf_readconf: too deep include\n");
|
|
|
|
rc = PROC_RC_IGNORE;
|
|
}
|
|
}
|
|
else if( strcasecmp(p_key+1, "ifexp") == 0 )
|
|
{
|
|
if( value || isifexpr )
|
|
{
|
|
if (earlydbg)
|
|
fprintf(stderr, "BF-DEBUG: incorrect usage of `%s' directive\n", p_key);
|
|
|
|
rc = PROC_RC_ABORT;
|
|
}
|
|
else
|
|
{
|
|
if( ifexpr )
|
|
{ free(ifexpr); ifexpr = NULL; }
|
|
if( expr )
|
|
ifexpr = xstrcpy(expr);
|
|
isifexpr = TRUE;
|
|
}
|
|
}
|
|
else if( strcasecmp(p_key+1, "endif") == 0 )
|
|
{
|
|
if( value || expr || !isifexpr )
|
|
{
|
|
if (earlydbg)
|
|
fprintf(stderr, "BF-DEBUG: incorrect usage of `%s' directive\n", p_key);
|
|
|
|
rc = PROC_RC_IGNORE;
|
|
}
|
|
else
|
|
{
|
|
if( ifexpr ) { free(ifexpr); ifexpr = NULL; }
|
|
isifexpr = FALSE;
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
if (earlydbg)
|
|
fprintf(stderr, "BF-DEBUG: unknown directive `%s'\n", p_key);
|
|
|
|
rc = PROC_RC_IGNORE;
|
|
}
|
|
}
|
|
else if( p_key && value )
|
|
{
|
|
if( isifexpr && expr )
|
|
{
|
|
if (earlydbg)
|
|
fprintf(stderr, "BF-DEBUG: can't use expressions inside $ifexpr block\n");
|
|
|
|
rc = PROC_RC_IGNORE;
|
|
}
|
|
else if( isifexpr )
|
|
{
|
|
rc = proc_configline(p_key, ifexpr, value);
|
|
}
|
|
else
|
|
{
|
|
rc = proc_configline(p_key, expr, value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (earlydbg)
|
|
fprintf(stderr, "BF-DEBUG: incorrect config string %s\n", fullstr);
|
|
|
|
rc = PROC_RC_IGNORE;
|
|
}
|
|
|
|
if( fullstr )
|
|
{ free(fullstr); fullstr = NULL; }
|
|
if( value )
|
|
{ free(value); value = NULL; }
|
|
if( expr )
|
|
{ free(expr); expr = NULL; }
|
|
|
|
switch(rc) {
|
|
case PROC_RC_OK:
|
|
break;
|
|
case PROC_RC_WARN:
|
|
if (earlydbg)
|
|
fprintf(stderr, "BF-DEBUG: warning in config \"%s\" line %d\n", confname, line);
|
|
|
|
break;
|
|
case PROC_RC_IGNORE:
|
|
if (earlydbg)
|
|
fprintf(stderr, "BF-DEBUG: ignore line %d in config \"%s\"\n", line, confname);
|
|
|
|
break;
|
|
case PROC_RC_ABORT:
|
|
if (earlydbg)
|
|
fprintf(stderr, "BF-DEBUG: fatal error in config \"%s\" in line %d\n", confname, line);
|
|
|
|
break;
|
|
default:
|
|
ASSERT_MSG();
|
|
break;
|
|
}
|
|
if( rc == PROC_RC_ABORT ) { maxrc = 1; break; }
|
|
} /* end of while */
|
|
|
|
file_close(fp);
|
|
|
|
if( isifexpr )
|
|
{
|
|
maxrc = 1;
|
|
if (earlydbg)
|
|
fprintf(stderr, "BF-DEBUG: unterminated directive `#ifexp'\n");
|
|
|
|
}
|
|
|
|
if( fullstr )
|
|
free(fullstr);
|
|
if( ifexpr )
|
|
free(ifexpr);
|
|
|
|
if (earlydbg)
|
|
fprintf(stderr, "BF-DEBUG: readconfig: exit with maxrc = %d\n", maxrc);
|
|
|
|
|
|
/* update subsystems */
|
|
if (inclevel==0) { // end of main config
|
|
if( log_reopen(log_getfilename(LOG_FILE_SESSION), NULL, NULL) )
|
|
{
|
|
if (earlydbg)
|
|
fprintf(stderr, "BF-DEBUG: can't continue without logging\n");
|
|
|
|
exit(-1);
|
|
}
|
|
#ifdef DEBUG
|
|
debug_configure();
|
|
#endif
|
|
}
|
|
|
|
return maxrc;
|
|
}
|
|
|