/tags/release-1-2-0-rc1/noffle/src/configfile.c
C | 1020 lines | 932 code | 69 blank | 19 comment | 129 complexity | 196d59d5bec0cfb6b0a1afe15f345b0c MD5 | raw file
Possible License(s): GPL-2.0
- /*
- configfile.c
- The following macros must be set, when compiling this file:
- CONFIGFILE
- SPOOLDIR
- VERSION
- $Id: configfile.c 620 2003-11-29 23:42:33Z bears $
- */
- #if HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <ctype.h>
- #include <limits.h>
- #include <sys/types.h>
- #include <regex.h>
- #include "configfile.h"
- #include "filter.h"
- #include "itemlist.h"
- #include "log.h"
- #include "util.h"
- #include "portable.h"
- #include "wildmat.h"
- typedef struct
- {
- int numGroup;
- int maxGroup;
- char **groups;
- }
- GroupEntry;
- struct GroupEnum
- {
- GroupEntry *groupEntry;
- int groupIdx;
- };
- typedef struct
- {
- char *name;
- char *user;
- char *pass;
- GroupEntry getgroups;
- GroupEntry omitgroups;
- }
- ServEntry;
- typedef struct
- {
- char *pattern;
- int days;
- }
- ExpireEntry;
- typedef struct
- {
- char *pattern;
- char *mode;
- }
- AutoSubscribeModeEntry;
- struct
- {
- /* Compile time options */
- const char *spoolDir;
- const char *version;
- /* Options from the config file */
- int maxFetch;
- int autoUnsubscribeDays;
- int threadFollowTime;
- int connectTimeout;
- Bool autoSubscribe;
- Bool autoUnsubscribe;
- Bool infoAlways;
- Bool appendReplyTo;
- Bool replaceMsgId;
- Str hostnameMsgId;
- Bool postLocal;
- Bool clientAuth;
- Str defaultAutoSubscribeMode;
- Str mailTo;
- int defaultExpire;
- int numServ;
- int maxServ;
- ServEntry *serv;
- int servIdx; /* for server enumeration */
- int numExpire;
- int maxExpire;
- ExpireEntry *expire;
- int numAutoSubscribeMode;
- int maxAutoSubscribeMode;
- AutoSubscribeModeEntry *autoSubscribeMode;
- Str pathHeader;
- Str fromDomain;
- Str organization;
- Str noffleUser;
- Str noffleGroup;
- } config =
- {
- SPOOLDIR, /* spoolDir */
- VERSION, /* version */
- 300, /* maxFetch */
- 30, /* autoUnsubscribeDays */
- 7, /* threadFollowTime */
- 30, /* connectTimeout */
- FALSE, /* autoSubscribe */
- FALSE, /* autoUnsubscribe */
- TRUE, /* infoAlways */
- TRUE, /* appendReplyTo */
- FALSE, /* replaceMsgId */
- "", /* hostnameMsgId */
- FALSE, /* postLocal */
- FALSE, /* clientAuth */
- "over", /* defaultAutoSubscribeMode */
- "", /* mailTo */
- 14, /* defaultExpire */
- 0, /* numServ */
- 0, /* maxServ */
- NULL, /* serv */
- 0, /* servIdx */
- 0, /* numExpire */
- 0, /* maxExpire */
- NULL, /* expire */
- 0, /* numAutoSubscribeMode */
- 0, /* maxAutoSubscribeMode */
- NULL, /* autoSubscribeMode */
- "", /* pathHeader */
- "", /* fromDomain */
- "", /* organization */
- "news", /* user Noffle runs as */
- "news" /* group Noffle runs as */
- };
- const char * Cfg_spoolDir( void ) { return config.spoolDir; }
- const char * Cfg_version( void ) { return config.version; }
- int Cfg_maxFetch( void ) { return config.maxFetch; }
- int Cfg_autoUnsubscribeDays( void ) { return config.autoUnsubscribeDays; }
- int Cfg_threadFollowTime( void ) { return config.threadFollowTime; }
- int Cfg_connectTimeout( void ) { return config.connectTimeout; }
- Bool Cfg_autoUnsubscribe( void ) { return config.autoUnsubscribe; }
- Bool Cfg_autoSubscribe( void ) { return config.autoSubscribe; }
- Bool Cfg_infoAlways( void ) { return config.infoAlways; }
- Bool Cfg_appendReplyTo ( void ) { return config.appendReplyTo; }
- Bool Cfg_replaceMsgId( void ) { return config.replaceMsgId; }
- const char * Cfg_hostnameMsgId( void ) { return config.hostnameMsgId; }
- Bool Cfg_postLocal( void ) { return config.postLocal; }
- Bool Cfg_needClientAuth( void ) { return config.clientAuth; }
- const char * Cfg_defaultAutoSubscribeMode( void ) {
- return config.defaultAutoSubscribeMode; }
- const char * Cfg_mailTo( void ) { return config.mailTo; }
- int Cfg_defaultExpire( void ) { return config.defaultExpire; }
- const char * Cfg_pathHeader( void ) { return config.pathHeader; }
- const char * Cfg_fromDomain( void ) { return config.fromDomain; }
- const char * Cfg_organization( void ) { return config.organization; }
- const char * Cfg_noffleUser( void ) { return config.noffleUser; }
- const char * Cfg_noffleGroup( void ) { return config.noffleGroup; }
- void Cfg_setClientAuth( Bool needsAuth )
- {
- config.clientAuth = needsAuth;
- }
- void
- Cfg_beginServEnum( void )
- {
- config.servIdx = 0;
- }
- Bool
- Cfg_nextServ( Str name )
- {
- if ( config.servIdx >= config.numServ )
- return FALSE;
- Utl_cpyStr( name, config.serv[ config.servIdx ].name );
- ++config.servIdx;
- return TRUE;
- }
- static Bool
- searchServ( const char *name, int *idx )
- {
- int i;
- for ( i = 0; i < config.numServ; ++i )
- if ( strcmp( name, config.serv[ i ].name ) == 0 )
- {
- *idx = i;
- return TRUE;
- }
- return FALSE;
- }
- Bool
- Cfg_servListContains( const char *name )
- {
- int idx;
- return searchServ( name, &idx );
- }
- Bool
- Cfg_servIsPreferential( const char *name1, const char *name2 )
- {
- Bool exists1, exists2;
- int idx1, idx2;
- exists1 = searchServ( name1, &idx1 );
- exists2 = searchServ( name2, &idx2 );
- if ( exists1 && exists2 )
- return ( idx1 < idx2 );
- if ( exists1 && ! exists2 )
- return TRUE;
- /* ( ! exists1 && exists2 ) || ( ! exists1 && ! exists2 ) */
- return FALSE;
- }
- void
- Cfg_authInfo( const char *name, Str user, Str pass )
- {
- int idx;
- if ( searchServ( name, &idx ) )
- {
- Utl_cpyStr( user, config.serv[ idx ].user );
- Utl_cpyStr( pass, config.serv[ idx ].pass );
- }
- else
- {
- user[ 0 ] = '\0';
- pass[ 0 ] = '\0';
- }
- }
- int
- Cfg_expire( const char *grp )
- {
- int i, res;
- for ( i = 0; i < config.numExpire; i++ )
- if ( Wld_match( grp, config.expire[ i ].pattern ) )
- {
- res = config.expire[ i ].days;
- Log_dbg( LOG_DBG_CONFIG,
- "Custom expire period %d for group %s",
- res, grp );
- return res;
- }
- return Cfg_defaultExpire();
- }
- const char *
- Cfg_autoSubscribeMode( const char *grp )
- {
- int i;
- const char *res;
- for ( i = 0; i < config.numAutoSubscribeMode; i++ )
- if ( Wld_match( grp, config.autoSubscribeMode[ i ].pattern ) )
- {
- res = config.autoSubscribeMode[ i ].mode;
- Log_dbg( LOG_DBG_CONFIG,
- "Custom auto subscribe mode %s for group %s",
- res, grp );
- return res;
- }
- return Cfg_defaultAutoSubscribeMode();
- }
- GroupEnum *
- new_GetGrEn( const char *name )
- {
- GroupEnum *res;
- int servIdx;
- res = (GroupEnum *) malloc( sizeof( GroupEnum ) );
- if ( res == NULL )
- Log_fatal( "Malloc of GroupEnum failed." );
- if ( ! searchServ( name, &servIdx ) )
- res->groupEntry = NULL;
- else
- res->groupEntry = &config.serv[ servIdx ].getgroups;
- GrEn_first( res );
- return res;
- }
- GroupEnum *
- new_OmitGrEn( const char *name )
- {
- GroupEnum *res;
- int servIdx;
- res = (GroupEnum *) malloc( sizeof( GroupEnum ) );
- if ( res == NULL )
- Log_fatal( "Malloc of GroupEnum failed." );
- if ( ! searchServ( name, &servIdx ) )
- res->groupEntry = NULL;
- else
- res->groupEntry = &config.serv[ servIdx ].omitgroups;
- GrEn_first( res );
- return res;
- }
- void
- del_GrEn( GroupEnum *ge )
- {
- free(ge);
- }
- void
- GrEn_first( GroupEnum *ge )
- {
- ge->groupIdx = 0;
- }
- const char *
- GrEn_next( GroupEnum *ge )
- {
- if ( ge->groupEntry == NULL ||
- ge->groupIdx >= ge->groupEntry->numGroup )
- return NULL;
- return ge->groupEntry->groups[ ge->groupIdx++ ];
- }
- static void
- logSyntaxErr( const char *line )
- {
- Log_err( "Syntax error in config file: %s", line );
- }
- static void
- getBool( Bool *variable, const char *line )
- {
- Str value, name, lowerLn;
- Utl_cpyStr( lowerLn, line );
- Utl_toLower( lowerLn );
- if ( sscanf( lowerLn, MAXCHAR_FMT " " MAXCHAR_FMT, name, value ) != 2 )
- {
- logSyntaxErr( line );
- return;
- }
-
- if ( strcmp( value, "yes" ) == 0 )
- *variable = TRUE;
- else if ( strcmp( value, "no" ) == 0 )
- *variable = FALSE;
- else
- Log_err( "Error in config file %s must be yes or no", name );
- }
- static void
- getInt( int *variable, int min, int max, const char *line )
- {
- int value;
- Str name;
- if ( sscanf( line, MAXCHAR_FMT " %d", name, &value ) != 2 )
- {
- logSyntaxErr( line );
- return;
- }
- if ( value < min || value > max )
- {
- Log_err( "Range error in config file %s [%d,%d]", name, min, max );
- return;
- }
- *variable = value;
- }
- static void
- getStr( char *variable, const char *line )
- {
- Str dummy;
- if ( sscanf( line, MAXCHAR_FMT " " MAXCHAR_FMT, dummy, variable ) != 2 )
- {
- logSyntaxErr( line );
- return;
- }
- }
- static void
- getText( Str variable, const char *line )
- {
- const char *l;
-
- /* Skip command */
- l = Utl_restOfLn( line, 1 );
- Utl_cpyStr( variable, l );
- }
- static void
- getServ( const char *line )
- {
- Str dummy, name, user, pass;
- int r, len;
- ServEntry entry;
- memset( &entry, 0, sizeof( entry ) );
- user[ 0 ] = pass[ 0 ] = '\0';
- r = sscanf( line,
- MAXCHAR_FMT " " MAXCHAR_FMT " " MAXCHAR_FMT " " MAXCHAR_FMT,
- dummy, name, user, pass );
- if ( r < 2 )
- {
- logSyntaxErr( line );
- return;
- }
- len = strlen( name );
- /* To make server name more definit, it is made lowercase and
- port is removed, if it is the default port */
- if ( len > 4 && strcmp( name + len - 4, ":119" ) == 0 )
- name[ len - 4 ] = '\0';
- Utl_toLower( name );
- Utl_allocAndCpy( &entry.name, name );
- Utl_allocAndCpy( &entry.user, user );
- Utl_allocAndCpy( &entry.pass, pass );
- if ( config.maxServ < config.numServ + 1 )
- {
- if ( ! ( config.serv = realloc( config.serv,
- ( config.maxServ + 5 )
- * sizeof( ServEntry ) ) ) )
- Log_fatal( "Could not realloc server list" );
- config.maxServ += 5;
- }
- config.serv[ config.numServ++ ] = entry;
- }
- static void
- getExpire( const char *line )
- {
- Str dummy, pattern;
- ExpireEntry entry;
- int days;
- if ( sscanf( line, MAXCHAR_FMT " " MAXCHAR_FMT " %d",
- dummy, pattern, &days ) != 3 )
- {
- logSyntaxErr( line );
- return;
- }
- else
- {
- if ( days < 0 )
- {
- Log_err( "Expire days error in '%s': must be integer > 0",
- line, days );
- return;
- }
- Utl_toLower( pattern );
- Utl_allocAndCpy( &entry.pattern, pattern );
- entry.days = days;
- if ( config.maxExpire < config.numExpire + 1 )
- {
- if ( ! ( config.expire = realloc( config.expire,
- ( config.maxExpire + 5 )
- * sizeof( ExpireEntry ) ) ) )
- Log_fatal( "Could not realloc expire list" );
- config.maxExpire += 5;
- }
- config.expire[ config.numExpire++ ] = entry;
- }
- }
- static void
- getGroups( char *line, Bool isGet )
- {
- const char *name;
- ItemList *patterns;
- const char *pattern;
- if ( config.numServ == 0 )
- {
- Log_err( "No current server in %s", line );
- return;
- }
-
- name = line;
- /* Skip over name and terminate it */
- while ( line[ 0 ] != '\0' && ! isspace( line[ 0 ] ) )
- line++;
- if ( line[ 0 ] == '\0' )
- {
- logSyntaxErr( name );
- return;
- }
- line[ 0 ] = '\0';
- line++;
-
- patterns = new_Itl( line, " ," );
- for( pattern = Itl_first( patterns );
- pattern != NULL;
- pattern = Itl_next( patterns ) )
- {
- GroupEntry *g;
- if ( isGet )
- g = &config.serv[ config.numServ - 1 ].getgroups;
- else
- g = &config.serv[ config.numServ - 1 ].omitgroups;
- if ( g->maxGroup < g->numGroup + 1 )
- {
- if ( ! ( g->groups = realloc( g->groups,
- ( g->maxGroup + 5 )
- * sizeof( char * ) ) ) )
- Log_fatal( "Could not realloc group list" );
- g->maxGroup += 5;
- }
- Utl_allocAndCpy( &g->groups[ g->numGroup++ ], pattern );
- }
- del_Itl( patterns) ;
- }
- static void
- getDebugMask( char *line )
- {
- const char *name;
- ItemList *maskNames;
- const char *maskName;
- unsigned mask;
- name = line;
- /* Skip over name and terminate it */
- while ( line[ 0 ] != '\0' && ! isspace( line[ 0 ] ) )
- line++;
- if ( line[ 0 ] == '\0' )
- {
- logSyntaxErr( name );
- return;
- }
- line[ 0 ] = '\0';
- line++;
- mask = LOG_DBG_NONE;
- maskNames = new_Itl( line, " ," );
- for( maskName = Itl_first( maskNames );
- maskName != NULL;
- maskName = Itl_next( maskNames ) )
- {
- if ( strcmp( maskName, "all" ) == 0 )
- mask = LOG_DBG_ALL;
- else if ( strcmp( maskName, "none" ) == 0 )
- mask = LOG_DBG_NONE;
- else if ( strcmp( maskName, "config" ) == 0 )
- mask |= LOG_DBG_CONFIG;
- else if ( strcmp( maskName, "control" ) == 0 )
- mask |= LOG_DBG_CONTROL;
- else if ( strcmp( maskName, "expire" ) == 0 )
- mask |= LOG_DBG_EXPIRE;
- else if ( strcmp( maskName, "fetch" ) == 0 )
- mask |= LOG_DBG_FETCH;
- else if ( strcmp( maskName, "filter" ) == 0 )
- mask |= LOG_DBG_FILTER;
- else if ( strcmp( maskName, "newsbase" ) == 0 )
- mask |= LOG_DBG_NEWSBASE;
- else if ( strcmp( maskName, "noffle" ) == 0 )
- mask |= LOG_DBG_NOFFLE;
- else if ( strcmp( maskName, "post" ) == 0 )
- mask |= LOG_DBG_POST;
- else if ( strcmp( maskName, "protocol" ) == 0 )
- mask |= LOG_DBG_PROTOCOL;
- else if ( strcmp( maskName, "requests" ) == 0 )
- mask |= LOG_DBG_REQUESTS;
- else if ( strcmp( maskName, "server" ) == 0 )
- mask |= LOG_DBG_SERVER;
- else if ( strcmp( maskName, "auth" ) == 0 )
- mask |= LOG_DBG_AUTH;
- else
- logSyntaxErr( line );
- }
- del_Itl( maskNames) ;
- Log_setDbgMask( mask );
- }
- static Bool
- isValidAutoSubscribeMode( const char *mode )
- {
- return strcmp( mode, "full" ) == 0
- || strcmp( mode, "thread" ) == 0
- || strcmp( mode, "over" ) == 0
- || strcmp( mode, "off" ) == 0;
- }
- static void
- getAutoSubscribeMode( const char *line )
- {
- Str dummy, pattern, mode;
- AutoSubscribeModeEntry entry;
- int items;
- items = sscanf( line, MAXCHAR_FMT " " MAXCHAR_FMT " " MAXCHAR_FMT,
- dummy, pattern, mode );
- if ( items == 2 )
- {
- /* Backwards compat. default-auto-subscribe-mode */
- Utl_cpyStr( mode, pattern );
- Utl_toLower( mode );
- if ( ! isValidAutoSubscribeMode( mode ) )
- {
- logSyntaxErr( line );
- return;
- }
- Utl_cpyStr( config.defaultAutoSubscribeMode, mode );
- return;
- }
- else if ( items != 3 )
- {
- logSyntaxErr( line );
- return;
- }
- Utl_toLower( mode );
- if ( ! isValidAutoSubscribeMode( mode ) )
- {
- logSyntaxErr( line );
- return;
- }
- Utl_toLower( pattern );
- Utl_allocAndCpy( &entry.pattern, pattern );
- Utl_allocAndCpy( &entry.mode, mode );
- if ( config.maxAutoSubscribeMode < config.numAutoSubscribeMode + 1 )
- {
- if ( ! ( config.autoSubscribeMode =
- realloc( config.autoSubscribeMode,
- ( config.maxAutoSubscribeMode + 5 )
- * sizeof( AutoSubscribeModeEntry ) ) ) )
- Log_fatal( "Could not realloc auto subscribe mode list" );
- config.maxAutoSubscribeMode += 5;
- }
- config.autoSubscribeMode[ config.numAutoSubscribeMode++ ] = entry;
- }
- static const char *
- getToken( const char *line, Str value )
- {
- Bool isQuoted;
- char quoteChar;
- Bool seenEscape;
- char *maxVal;
-
- while ( *line != '\0' && isspace( *line ) )
- line++;
- if ( *line == '\0' )
- return NULL;
- maxVal = &value[ MAXCHAR ];
- isQuoted = ( *line == '\'' || *line == '"' );
- if ( isQuoted )
- {
- quoteChar = *line;
- line++;
- seenEscape = FALSE;
- while ( *line != '\0'
- && ( *line != quoteChar || seenEscape )
- && value < maxVal )
- {
- if ( seenEscape )
- {
- *value++ = *line;
- seenEscape = FALSE;
- }
- else
- {
- if ( *line == '\\' )
- seenEscape = TRUE;
- else
- *value++ = *line;
- }
- line++;
- }
- if ( *line == quoteChar )
- line++;
- }
- else
- {
- while ( *line != '\0' && ! isspace( *line ) && value < maxVal )
- *value++ = *line++;
- }
- *value = '\0';
- return line;
- }
- /* very simple date parser.
- * examples:
- * now+
- */
- static Bool
- get_simpledate( time_t *timeoffsetp, FilterRuleDateEnumType *vartimep, const char *val)
- {
- float timef;
- if ( ! strncasecmp( val, "invalid", 7 ) )
- {
- *vartimep = INVALID;
- return TRUE;
- }
- else if ( ! strncasecmp( val, "now", 3 ) )
- {
- val += 3;
- *vartimep = NOW;
- }
- else if ( ! strncasecmp( val, "lastupdate", 10 ) )
- {
- val += 10;
- *vartimep = LASTUPDATE;
- }
- else
- {
- *vartimep = FIXED;
- *timeoffsetp = Utl_parseNewsDate( val );
- if ( *timeoffsetp == (time_t) -1 )
- return FALSE;
- else
- return TRUE;
- }
- /* NOW, LASTUPDATE +/- number of days. */
- timef = atof( val ) * 86400.0 ; /* 24 * 60 * 60 == 86400 */
- /* let's assume more than 10 years of timeoffset are a mistake. */
- if ( timef > 31536000.0 || timef < -31536000.0 )
- return FALSE;
- *timeoffsetp = (time_t) timef;
- /* Todo: check if any garbage follows. */
- return TRUE;
- }
- static void
- getFilter( const char *line )
- {
- Str ruleBuf, value;
- const char *l;
- char *p, *ruleName;
- Filter *f;
- FilterRule rule;
- Bool seenAction;
- f = new_Filter();
-
- /* Skip "filter" */
- l = Utl_restOfLn( line, 1 );
- seenAction = FALSE;
-
- for(;;)
- {
- while ( *l != '\0' && isspace( *l ) )
- l++;
- if ( *l == '\0' )
- break;
-
- /* Get the rule title */
- p = ruleBuf;
- while ( *l != '\0' && *l != '=' && *l != '<' && *l != '>' )
- *p++ = *l++;
- *p = '\0';
- ruleName = Utl_stripWhiteSpace( ruleBuf );
- Utl_toLower( ruleName );
- if ( *ruleName == '\0' )
- goto synErr;
- /* Do we know this rule? */
- if ( strcmp( ruleName, "group" ) == 0 )
- rule.type = RULE_NEWSGROUP;
- else if ( strcmp( ruleName, "subject" ) == 0 )
- rule.type = RULE_SUBJECT;
- else if ( strcmp( ruleName, "reference" ) == 0 )
- rule.type = RULE_REFERENCE;
- else if ( strcmp( ruleName, "from" ) == 0 )
- rule.type = RULE_FROM;
- else if ( strcmp( ruleName, "msgid" ) == 0 )
- rule.type = RULE_MSGID;
- else if ( strcmp( ruleName, "bytes" ) == 0 )
- rule.type = RULE_BYTES_EQ;
- else if ( strcmp( ruleName, "lines" ) == 0 )
- rule.type = RULE_LINES_EQ;
- else if ( strcmp( ruleName, "refs" ) == 0 )
- rule.type = RULE_NOREFS_EQ;
- else if ( strcmp( ruleName, "xposts" ) == 0 )
- rule.type = RULE_XPOSTS_EQ;
- else if ( strcmp( ruleName, "post-status" ) == 0 )
- rule.type = RULE_POST_STATUS;
- else if ( strcmp( ruleName, "date" ) == 0 )
- rule.type = RULE_DATE_EQ;
- /* date<lastupdate-12 equals older=lastupdate-12
- * date>now+1.5 equals newer=now+1.5
- * date=now equals older=now+1 AND newer=now-1
- * Stupid people like Mirko keep making mistakes
- * if they're forced using date< or date>.
- */
- else if ( strcmp( ruleName, "older" ) == 0 )
- rule.type = RULE_DATE_LT;
- else if ( strcmp( ruleName, "newer" ) == 0 )
- rule.type = RULE_DATE_GT;
- else if ( strcmp( ruleName, "action" ) != 0 )
- goto synErr;
- if ( rule.type == RULE_BYTES_EQ ||
- rule.type == RULE_LINES_EQ ||
- rule.type == RULE_NOREFS_EQ ||
- rule.type == RULE_XPOSTS_EQ ||
- rule.type == RULE_DATE_EQ )
- {
- if ( *l == '<' )
- rule.type--;
- else if ( *l == '>' )
- rule.type++;
- else if ( *l != '=' )
- goto synErr;
- }
- else if ( *l != '=' )
- goto synErr;
- /* Skip past '=' (or '>' or '<') */
- l++;
-
- /* OK, we now have a valid rule. What value? */
- l = getToken( l, value );
- if ( l == NULL )
- goto synErr;
- if ( strcmp( ruleName, "action" ) == 0 )
- {
- if ( seenAction )
- goto synErr;
-
- Utl_toLower( value );
- if ( strcmp( value, "full" ) == 0 )
- f->action = FILTER_FULL;
- else if ( strcmp( value, "over" ) == 0 )
- f->action = FILTER_XOVER;
- else if ( strcmp( value, "thread" ) == 0 )
- f->action = FILTER_THREAD;
- else if ( strcmp( value, "discard" ) == 0 )
- f->action = FILTER_DISCARD;
- else if ( strcmp( value, "default" ) == 0 )
- f->action = FILTER_DEFAULT;
- seenAction = TRUE;
- }
- else if ( rule.type == RULE_NEWSGROUP )
- Utl_allocAndCpy( &rule.data.grp, value );
- else if ( rule.type >= RULE_SUBJECT && rule.type <= RULE_MSGID )
- {
- if ( regcomp( &rule.data.regex, value, REG_EXTENDED ) != 0 )
- goto synErr;
- }
- else if (rule.type == RULE_POST_STATUS )
- {
- if ( ( strcmp( value, "yes" ) == 0 ) || \
- ( strcmp( value, "no" ) == 0 ) || \
- ( strncmp( value, "mod", 3 ) == 0 ) )
- /* no need to type out "moderated" */
- rule.data.postAllow = value[0]; /* 'y','n' or 'm' */
- else
- goto synErr;
- }
- else if ( rule.type == RULE_DATE_LT ||
- rule.type == RULE_DATE_EQ ||
- rule.type == RULE_DATE_GT )
- {
- if ( !get_simpledate( &rule.data.reftime.timeoffset, &rule.data.reftime.vartime, value ) )
- goto synErr;
- if ( rule.type != RULE_DATE_EQ &&
- rule.data.reftime.vartime == INVALID )
- goto synErr;
- }
- else
- {
- char * endVal;
- int suffix;
- rule.data.amount = strtoul( value, &endVal, 0 );
- suffix = tolower( *endVal );
- if ( suffix == 'k' || suffix == 'm' )
- {
- rule.data.amount *= 1024;
- if ( suffix == 'm' )
- rule.data.amount *= 1024;
- endVal++;
- }
- if ( *endVal != '\0' && ! isspace( *endVal ) )
- goto synErr;
- }
- if ( strcmp( ruleName, "action" ) != 0 )
- {
- Log_dbg( LOG_DBG_CONFIG,
- "Adding rule type %d value %s",
- rule.type, value );
- Flt_addRule( f, rule );
- }
- }
- Log_dbg( LOG_DBG_CONFIG, "Adding filter, action %d", f->action );
- Flt_addFilter( f );
- return;
-
- synErr:
- logSyntaxErr( line );
- return;
- }
- void
- Cfg_read( void )
- {
- char *p;
- FILE *f;
- Str file, line, lowerLine, name, s;
- Utl_cpyStr( file, CONFIGFILE );
- if ( ! ( f = fopen( file, "r" ) ) )
- {
- Log_err( "Cannot read %s", file );
- return;
- }
- while ( fgets( line, MAXCHAR, f ) )
- {
- p = Utl_stripWhiteSpace( line );
- Utl_stripComment( p );
- Utl_cpyStr( lowerLine, p );
- Utl_toLower( lowerLine );
- p = lowerLine;
- if ( *p == '\0' )
- continue;
- if ( sscanf( p, MAXCHAR_FMT, name ) != 1 )
- Log_err( "Syntax error in %s: %s", file, line );
- else if ( strcmp( "max-fetch", name ) == 0 )
- getInt( &config.maxFetch, 0, INT_MAX, p );
- else if ( strcmp( "auto-unsubscribe-days", name ) == 0 )
- getInt( &config.autoUnsubscribe, -1, INT_MAX, p );
- else if ( strcmp( "thread-follow-time", name ) == 0 )
- getInt( &config.threadFollowTime, 0, INT_MAX, p );
- else if ( strcmp( "connect-timeout", name ) == 0 )
- getInt( &config.connectTimeout, 0, INT_MAX, p );
- else if ( strcmp( "default-expire", name ) == 0 )
- getInt( &config.defaultExpire, 0, INT_MAX, p );
- else if ( strcmp( "auto-subscribe", name ) == 0 )
- getBool( &config.autoSubscribe, p );
- else if ( strcmp( "auto-unsubscribe", name ) == 0 )
- getBool( &config.autoUnsubscribe, p );
- else if ( strcmp( "info-always-unread", name ) == 0 )
- getBool( &config.infoAlways, p );
- else if ( strcmp( "append-reply-to", name ) == 0 )
- getBool( &config.appendReplyTo, p);
- else if ( strcmp( "replace-messageid", name ) == 0 )
- getBool( &config.replaceMsgId, p );
- else if ( strcmp( "hostname", name ) == 0 )
- /* use line, do not change to lowercase */
- getStr( config.hostnameMsgId, line );
- else if ( strcmp( "post-locally", name ) == 0 )
- getBool( &config.postLocal, p );
- #if USE_AUTH
- /*
- * Don't recognise this unless we have some sort of auth
- * built in. A small sanity check on the config.
- */
- else if ( strcmp( "authenticate-client", name ) == 0 )
- getBool( &config.clientAuth, p );
- #endif
- else if ( strcmp( "default-auto-subscribe-mode", name ) == 0 )
- {
- getStr( s, p );
- if ( ! isValidAutoSubscribeMode( s ) )
- {
- logSyntaxErr( line );
- return;
- }
- else
- Utl_cpyStr( config.defaultAutoSubscribeMode, s );
- }
- else if ( strcmp( "mail-to", name ) == 0 )
- getStr( config.mailTo, p );
- else if ( strcmp( "expire", name ) == 0 )
- getExpire( p );
- else if ( strcmp( "auto-subscribe-mode", name ) == 0 )
- getAutoSubscribeMode( p );
- else if ( strcmp( "log-debug", name ) == 0 )
- getDebugMask( p );
- else if ( strcmp( "getgroups", name ) == 0 )
- getGroups( p, TRUE );
- else if ( strcmp( "omitgroups", name ) == 0 )
- getGroups( p, FALSE );
- else if ( strcmp( "path-header", name ) == 0 )
- getStr( config.pathHeader, p );
- else if ( strcmp( "from-domain", name ) == 0 )
- getStr( config.fromDomain, p );
- /* The following need line because they may have uppercase data */
- else if ( strcmp( "organization", name ) == 0 )
- getText( config.organization, line );
- else if ( strcmp( "noffle-user", name ) == 0 )
- getText( config.noffleUser, line );
- else if ( strcmp( "noffle-group", name ) == 0 )
- getText( config.noffleGroup, line );
- else if ( strcmp( "server", name ) == 0 )
- getServ( line );
- else if ( strcmp( "filter", name ) == 0 )
- getFilter( line );
- else
- Log_err( "Unknown config option: %s", name );
- }
- fclose( f );
- if ( ! config.numServ )
- Log_fatal( "Config file contains no server" );
- }