/*
* POP3Lite - 3lite POP3 Daemon
* Copyright (C) 2000, 2001 Gergely Nagy <8@free.bsd.hu>
*
* This file is part of POP3Lite.
*
* POP3Lite 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.
*
* POP3Lite 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "main.h"
#include <pop3lite.h>
#include <glib.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <syslog.h>
#include <unistd.h>
#include "cfg.h"
static const char rcsid[]="$Id: cfg.c,v 1.8 2001/01/24 14:01:47 algernon Exp $";
static char *cfg_strip_str ( char *str );
static char *cfg_strip_quote ( char *str );
/**
* cfg_strip_quote: strip leading & trailing quotes
* @str: the victim
*
* Strips the leading & trailing quotes if BOTH are
* present.
*
* Returns: the bare truth ;)
**/
static char *
cfg_strip_quote ( char *str )
{
char *mystr;
if ( str[0] == '"' && str[strlen(str)-1] == '"' )
{
mystr = &str[1];
mystr[strlen(mystr)-1] = '\0';
} else
mystr = str;
return mystr;
}
/**
* cfg_strip_str: strips leading & trailing whitespace
* @str: the victim
*
* Strips spaces and tabs from the beggining and from
* the end of a string.
*
* Returns: a stripped string
**/
static char *
cfg_strip_str ( char *str )
{
int i = 0;
char *mystr;
while ( str[i] == ' ' || str[i] == '\t' )
i++;
mystr = &str[i];
i = strlen(mystr)-1;
while ( mystr[i] == ' ' || mystr[i] == '\t' )
i--;
mystr[i+1] = '\0';
return mystr;
}
/**
* cfg_parse_line: parse a configuration file line
* @control: the control to insert result into
* @line: the line itself
* @linecnt: the line number, for error message generation
* @prev: previous key
*
* Parses a configuration file line.
*
* Returns: the config key
**/
char *
cfg_parse_line ( P3LControl *control,
const char *ln, unsigned long linecnt,
const char *prev, GHashTable *table )
{
long j, i = 0;
int seen_eq = -1;
char *args, *carg, *lv1, *cmd = NULL, *line;
gboolean ows = TRUE;
gboolean is_cont = FALSE, to_cont = FALSE;
GList *arglist = NULL;
GList *arglist_c = NULL;
GList *arglist_a = NULL;
if ( ln == NULL )
return g_strdup ( prev );
if ( ! strcmp ( ln, "" ) )
return g_strdup ( prev );
line = g_strdup ( ln );
/*
* Strip \r, \n and comments
*/
while ( 1 )
{
switch ( line[i] )
{
case '\r':
case '\n':
line[i]='\0';
break;
case '#':
/* Escaped # is not a comment */
if ( line [i-1] != '\\' )
line[i] = '\0';
break;
case '=':
if ( seen_eq < 0 )
seen_eq = i;
break;
default:
break;
}
if ( line[i] == '\0' )
break;
i++;
}
/*
* Detect if we must do anything about this...
* RATIONALE: a line that only contains whitespace,
* is ignored. a line with no euqation signs, is
* considered an error.
*/
i=0;
while ( i < strlen ( line ) )
{
if ( line[i] != ' ' )
{
if ( line [i] == '=' )
seen_eq = -2;
ows = FALSE;
break;
}
i++;
}
/*
* Whitespace only lines are ignored.
* FIXME: if it is continued...
*/
if ( ows )
{
g_free ( line );
return g_strdup ( prev );
}
/*
* If it is non-whitespace, and has no =, it is
* an error. However, if it is a continued line...
*/
if ( seen_eq == -1 && prev == NULL )
{
control->system->log ( control, LOG_CRIT,
"CFG: Syntax error on line %lu (no equation sign).", linecnt );
exit ( 1 );
}
/*
* A line that begins with [\t ]*= is illegal
*/
if ( seen_eq == -2 )
{
control->system->log ( control, LOG_CRIT,
"CFG: Syntax error on line %lu (no field name).", linecnt );
exit ( 1 );
}
/*
* Now we split it into two...
* The first equation sign is marked by seen_eq, so use it!
*/
if ( prev == NULL )
{
cmd = g_strndup ( line, seen_eq );
args = g_strdup ( &line[seen_eq+1] );
}
else
{
is_cont = TRUE;
cmd = g_strdup ( prev );
args = g_strdup ( line );
}
/*
* Strip whitespace...
*/
args = cfg_strip_str ( args );
cmd = cfg_strip_str ( cmd );
g_strup ( cmd );
/*
* Here comes a hard part...
* We have to split up the args by [\t ,], but only if
* they aren't inside quotes
*/
i = 0;
carg = g_strdup("");
while ( i < strlen ( args ) )
{
switch ( args[i] )
{
case '"':
/* Escaped quotes are treated specially. */
if ( args[i-1] == '\\' )
{
carg = g_strdup_printf ( "%s%c", carg, args[i] );
break;
}
/* Find matching quote ... */
j=i;
i++;
while ( args[i] != '"' && args[i-1] != '\\' && i < strlen(args) )
i++;
if ( i == strlen (args) && args[i] != '"' )
{
control->system->log ( control, LOG_CRIT,
"CFG: Syntax error on line %lu (unmatched quotes)",
linecnt );
exit ( 1 );
}
/* ... and copy it */
carg = g_strdup_printf ( "%s%s", carg, g_strndup ( &args[j], i-j+1 ) );
break;
case ' ':
case ',':
case '\t':
/*
* These are separators, they cannot be escaped,
* only quoted, and that is captured above.
*/
if ( strlen ( carg ) > 0 )
arglist = g_list_append ( arglist,
cfg_strip_quote ( g_strdup ( carg ) ) );
g_free ( carg );
carg = g_strdup ( "" );
break;
default:
/* Everything else gets appended */
carg = g_strdup_printf ( "%s%c", carg, args[i] );
break;
}
i++;
}
/*
* If there are pending things, append them too
*/
if ( strlen ( carg ) > 0 )
arglist = g_list_append ( arglist, cfg_strip_quote ( g_strdup ( carg ) ) );
g_free ( carg );
/*
* If the value ends with \, it will be
* continued
*/
lv1 = (char *) g_list_nth_data ( arglist, g_list_length ( arglist ) - 1 );
if ( lv1 && ! strcmp ( lv1, "\\" ) )
{
to_cont = 1;
g_list_remove_link ( arglist, g_list_last ( arglist ) );
}
if ( is_cont == TRUE )
{
arglist_c = g_hash_table_lookup ( table, cmd );
for ( i = 0; i < g_list_length ( arglist_c ); i++ )
arglist_a = g_list_append ( arglist_a,
g_list_nth_data ( arglist_c, i ) );
arglist = g_list_concat ( arglist_a, arglist );
}
/*
* And finally add it to the hash.
*/
g_hash_table_insert ( table, cmd, arglist );
g_free ( line );
return ( to_cont ) ? cmd : NULL;
}
/**
* p3l_load_config: load configuration
* @control: the usual control struct
* @filename: where to load configuration from
* @table: destination
*
* This loads the a configuration file.
*
* Returns: nothing
**/
void
p3l_load_config ( P3LControl *control, const char *filename,
GHashTable *table )
{
char *fn, *line, *buffer, *prev=NULL;
P3LString **lines;
int i = 0;
size_t size, linenum;
fn = ( filename != NULL ) ?
g_strdup ( filename ) : g_strdup ( SYSCONFDIR "/pop3lite.conf" );
buffer = (char *) p3l_read_file ( fn, &size );
if ( !buffer )
{
g_free ( fn );
return;
}
lines = p3l_split_lines ( buffer, size, &linenum );
for ( i = 0; i < linenum; i++ )
{
line = (char *) g_malloc ( lines[i]->length + 1 );
memcpy ( line, lines[i]->str, lines[i]->length );
line[lines[i]->length]=0;
prev = cfg_parse_line ( control, line, i, prev, table );
g_free ( line );
}
g_free ( buffer );
g_free ( fn );
}
syntax highlighted by Code2HTML, v. 0.9.1