Mercurial > noffle
view src/configfile.c @ 96:988cacc01470 noffle
[svn] Preserve group last number if last article(s) cancelled
author | bears |
---|---|
date | Fri, 19 May 2000 16:18:05 +0100 |
parents | 1fcdced0246e |
children | 402300614185 |
line wrap: on
line source
/* configfile.c The following macros must be set, when compiling this file: CONFIGFILE SPOOLDIR VERSION $Id: configfile.c 100 2000-05-18 12:17:23Z bears $ */ #if HAVE_CONFIG_H #include <config.h> #endif #include "configfile.h" #include <ctype.h> #include <limits.h> #include "itemlist.h" #include "log.h" #include "util.h" #include "portable.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; 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 replaceMsgId; Bool postLocal; Str autoSubscribeMode; Str mailTo; int defaultExpire; int numServ; int maxServ; ServEntry *serv; int servIdx; /* for server enumeration */ int numExpire; int maxExpire; ExpireEntry *expire; int expireIdx; } config = { SPOOLDIR, /* spoolDir */ VERSION, /* version */ 300, /* maxFetch */ 30, /* autoUnsubscribeDays */ 7, /* threadFollowTime */ 30, /* connectTimeout */ FALSE, /* autoSubscribe */ FALSE, /* autoUnsubscribe */ TRUE, /* infoAlways */ TRUE, /* replaceMsgId */ FALSE, /* postLocal */ "over", /* autoSubscribeMode */ "", /* mailTo */ 14, /* defaultExpire */ 0, /* numServ */ 0, /* maxServ */ NULL, /* serv */ 0, /* servIdx */ 0, /* numExpire */ 0, /* maxExpire */ NULL, /* expire */ 0 /* expireIdx */ }; 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_replaceMsgId( void ) { return config.replaceMsgId; } Bool Cfg_postLocal( void ) { return config.postLocal; } const char * Cfg_autoSubscribeMode( void ) { return config.autoSubscribeMode; } const char * Cfg_mailTo( void ) { return config.mailTo; } int Cfg_expire( void ) { return config.defaultExpire; } void Cfg_beginServEnum( void ) { config.servIdx = 0; } Bool Cfg_nextServ( Str name ) { if ( config.servIdx >= config.numServ ) return FALSE; strcpy( 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 ) ) { strcpy( user, config.serv[ idx ].user ); strcpy( pass, config.serv[ idx ].pass ); } else { user[ 0 ] = '\0'; pass[ 0 ] = '\0'; } } void Cfg_beginExpireEnum( void ) { config.expireIdx = 0; } int Cfg_nextExpire( Str pattern ) { if ( config.expireIdx >= config.numExpire ) return -1; strcpy( pattern, config.expire[ config.expireIdx ].pattern ); return config.expire[ config.expireIdx++ ].days; } GroupEnum * new_GetGrEn( const char *name ) { GroupEnum *res; int servIdx; res = (GroupEnum *) malloc( sizeof( GroupEnum ) ); if ( res == NULL ) { Log_err( "Malloc of GroupEnum failed." ); exit( EXIT_FAILURE ); } 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_err( "Malloc of GroupEnum failed." ); exit( EXIT_FAILURE ); } 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; strcpy( lowerLn, line ); Utl_toLower( lowerLn ); if ( sscanf( lowerLn, "%s %s", 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, "%s %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, "%s %s", dummy, variable ) != 2 ) { logSyntaxErr( line ); return; } } static void getServ( const char *line ) { Str dummy, name, user, pass; int r, len; ServEntry entry; memset( &entry, 0, sizeof( entry ) ); r = sscanf( line, "%s %s %s %s", 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_err( "Could not realloc server list" ); exit( EXIT_FAILURE ); } config.maxServ += 5; } config.serv[ config.numServ++ ] = entry; } static void getExpire( const char *line ) { Str dummy, pattern; ExpireEntry entry; int days; /* The line is either "expire <num>" or "expire <pat> <num>". The former updates the overall default. */ if ( sscanf( line, "%s %s %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_err( "Could not realloc exipre list" ); exit( EXIT_FAILURE ); } 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_err( "Could not realloc group list" ); exit( EXIT_FAILURE ); } g->maxGroup += 5; } Utl_allocAndCpy( &g->groups[ g->numGroup++ ], pattern ); } del_Itl( patterns) ; } void Cfg_read( void ) { char *p; FILE *f; Str file, line, lowerLine, name, s; snprintf( file, MAXCHAR, 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 ); if ( *p == '\0' ) continue; if ( sscanf( p, "%s", 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( "replace-messageid", name ) == 0 ) getBool( &config.replaceMsgId, p ); else if ( strcmp( "post-locally", name ) == 0 ) getBool( &config.postLocal, p ); else if ( strcmp( "auto-subscribe-mode", name ) == 0 ) { getStr( s, p ); Utl_toLower( s ); if ( strcmp( s, "full" ) != 0 && strcmp( s, "thread" ) != 0 && strcmp( s, "over" ) != 0 && strcmp( s, "off" ) != 0 ) { Log_err( "Syntax error in config file: %s", line ); return; } else strcpy( config.autoSubscribeMode, s ); } else if ( strcmp( "server", name ) == 0 ) /* Server needs line not p, because password may contain uppercase */ getServ( line ); else if ( strcmp( "mail-to", name ) == 0 ) getStr( config.mailTo, p ); else if ( strcmp( "expire", name ) == 0 ) getExpire( p ); else if ( strcmp( "getgroups", name ) == 0 ) getGroups( p, TRUE ); else if ( strcmp( "omitgroups", name ) == 0 ) getGroups( p, FALSE ); else Log_err( "Unknown config option: %s", name ); } fclose( f ); if ( ! config.numServ ) { Log_err( "Config file contains no server" ); exit( EXIT_FAILURE ); } }