PageRenderTime 264ms CodeModel.GetById 80ms RepoModel.GetById 10ms app.codeStats 1ms

/tags/release-1-1-2/noffle/src/configfile.c

#
C | 932 lines | 845 code | 68 blank | 19 comment | 126 complexity | 02bda738b366b1914664ac4b2038b4cb MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. configfile.c
  3. The following macros must be set, when compiling this file:
  4. CONFIGFILE
  5. SPOOLDIR
  6. VERSION
  7. $Id: configfile.c 341 2001-12-09 11:32:31Z bears $
  8. */
  9. #if HAVE_CONFIG_H
  10. #include <config.h>
  11. #endif
  12. #include <ctype.h>
  13. #include <limits.h>
  14. #include <regex.h>
  15. #include "configfile.h"
  16. #include "filter.h"
  17. #include "itemlist.h"
  18. #include "log.h"
  19. #include "util.h"
  20. #include "portable.h"
  21. #include "wildmat.h"
  22. typedef struct
  23. {
  24. int numGroup;
  25. int maxGroup;
  26. char **groups;
  27. }
  28. GroupEntry;
  29. struct GroupEnum
  30. {
  31. GroupEntry *groupEntry;
  32. int groupIdx;
  33. };
  34. typedef struct
  35. {
  36. char *name;
  37. char *user;
  38. char *pass;
  39. GroupEntry getgroups;
  40. GroupEntry omitgroups;
  41. }
  42. ServEntry;
  43. typedef struct
  44. {
  45. char *pattern;
  46. int days;
  47. }
  48. ExpireEntry;
  49. typedef struct
  50. {
  51. char *pattern;
  52. char *mode;
  53. }
  54. AutoSubscribeModeEntry;
  55. struct
  56. {
  57. /* Compile time options */
  58. const char *spoolDir;
  59. const char *version;
  60. /* Options from the config file */
  61. int maxFetch;
  62. int autoUnsubscribeDays;
  63. int threadFollowTime;
  64. int connectTimeout;
  65. Bool autoSubscribe;
  66. Bool autoUnsubscribe;
  67. Bool infoAlways;
  68. Bool replaceMsgId;
  69. Str hostnameMsgId;
  70. Bool postLocal;
  71. Str defaultAutoSubscribeMode;
  72. Str mailTo;
  73. int defaultExpire;
  74. int numServ;
  75. int maxServ;
  76. ServEntry *serv;
  77. int servIdx; /* for server enumeration */
  78. int numExpire;
  79. int maxExpire;
  80. ExpireEntry *expire;
  81. int numAutoSubscribeMode;
  82. int maxAutoSubscribeMode;
  83. AutoSubscribeModeEntry *autoSubscribeMode;
  84. Str pathHeader;
  85. Str fromDomain;
  86. Str organization;
  87. } config =
  88. {
  89. SPOOLDIR, /* spoolDir */
  90. VERSION, /* version */
  91. 300, /* maxFetch */
  92. 30, /* autoUnsubscribeDays */
  93. 7, /* threadFollowTime */
  94. 30, /* connectTimeout */
  95. FALSE, /* autoSubscribe */
  96. FALSE, /* autoUnsubscribe */
  97. TRUE, /* infoAlways */
  98. FALSE, /* replaceMsgId */
  99. "", /* hostnameMsgId */
  100. FALSE, /* postLocal */
  101. "over", /* defaultAutoSubscribeMode */
  102. "", /* mailTo */
  103. 14, /* defaultExpire */
  104. 0, /* numServ */
  105. 0, /* maxServ */
  106. NULL, /* serv */
  107. 0, /* servIdx */
  108. 0, /* numExpire */
  109. 0, /* maxExpire */
  110. NULL, /* expire */
  111. 0, /* numAutoSubscribeMode */
  112. 0, /* maxAutoSubscribeMode */
  113. NULL, /* autoSubscribeMode */
  114. "", /* pathHeader */
  115. "", /* fromDomain */
  116. "" /* organization */
  117. };
  118. const char * Cfg_spoolDir( void ) { return config.spoolDir; }
  119. const char * Cfg_version( void ) { return config.version; }
  120. int Cfg_maxFetch( void ) { return config.maxFetch; }
  121. int Cfg_autoUnsubscribeDays( void ) { return config.autoUnsubscribeDays; }
  122. int Cfg_threadFollowTime( void ) { return config.threadFollowTime; }
  123. int Cfg_connectTimeout( void ) { return config.connectTimeout; }
  124. Bool Cfg_autoUnsubscribe( void ) { return config.autoUnsubscribe; }
  125. Bool Cfg_autoSubscribe( void ) { return config.autoSubscribe; }
  126. Bool Cfg_infoAlways( void ) { return config.infoAlways; }
  127. Bool Cfg_replaceMsgId( void ) { return config.replaceMsgId; }
  128. const char * Cfg_hostnameMsgId( void ) { return config.hostnameMsgId; }
  129. Bool Cfg_postLocal( void ) { return config.postLocal; }
  130. const char * Cfg_defaultAutoSubscribeMode( void ) {
  131. return config.defaultAutoSubscribeMode; }
  132. const char * Cfg_mailTo( void ) { return config.mailTo; }
  133. int Cfg_defaultExpire( void ) { return config.defaultExpire; }
  134. const char * Cfg_pathHeader( void ) { return config.pathHeader; }
  135. const char * Cfg_fromDomain( void ) { return config.fromDomain; }
  136. const char * Cfg_organization( void ) { return config.organization; }
  137. void
  138. Cfg_beginServEnum( void )
  139. {
  140. config.servIdx = 0;
  141. }
  142. Bool
  143. Cfg_nextServ( Str name )
  144. {
  145. if ( config.servIdx >= config.numServ )
  146. return FALSE;
  147. strcpy( name, config.serv[ config.servIdx ].name );
  148. ++config.servIdx;
  149. return TRUE;
  150. }
  151. static Bool
  152. searchServ( const char *name, int *idx )
  153. {
  154. int i;
  155. for ( i = 0; i < config.numServ; ++i )
  156. if ( strcmp( name, config.serv[ i ].name ) == 0 )
  157. {
  158. *idx = i;
  159. return TRUE;
  160. }
  161. return FALSE;
  162. }
  163. Bool
  164. Cfg_servListContains( const char *name )
  165. {
  166. int idx;
  167. return searchServ( name, &idx );
  168. }
  169. Bool
  170. Cfg_servIsPreferential( const char *name1, const char *name2 )
  171. {
  172. Bool exists1, exists2;
  173. int idx1, idx2;
  174. exists1 = searchServ( name1, &idx1 );
  175. exists2 = searchServ( name2, &idx2 );
  176. if ( exists1 && exists2 )
  177. return ( idx1 < idx2 );
  178. if ( exists1 && ! exists2 )
  179. return TRUE;
  180. /* ( ! exists1 && exists2 ) || ( ! exists1 && ! exists2 ) */
  181. return FALSE;
  182. }
  183. void
  184. Cfg_authInfo( const char *name, Str user, Str pass )
  185. {
  186. int idx;
  187. if ( searchServ( name, &idx ) )
  188. {
  189. strcpy( user, config.serv[ idx ].user );
  190. strcpy( pass, config.serv[ idx ].pass );
  191. }
  192. else
  193. {
  194. user[ 0 ] = '\0';
  195. pass[ 0 ] = '\0';
  196. }
  197. }
  198. int
  199. Cfg_expire( const char *grp )
  200. {
  201. int i, res;
  202. for ( i = 0; i < config.numExpire; i++ )
  203. if ( Wld_match( grp, config.expire[ i ].pattern ) )
  204. {
  205. res = config.expire[ i ].days;
  206. Log_dbg( LOG_DBG_CONFIG,
  207. "Custom expire period %d for group %s",
  208. res, grp );
  209. return res;
  210. }
  211. return Cfg_defaultExpire();
  212. }
  213. const char *
  214. Cfg_autoSubscribeMode( const char *grp )
  215. {
  216. int i;
  217. const char *res;
  218. for ( i = 0; i < config.numAutoSubscribeMode; i++ )
  219. if ( Wld_match( grp, config.autoSubscribeMode[ i ].pattern ) )
  220. {
  221. res = config.autoSubscribeMode[ i ].mode;
  222. Log_dbg( LOG_DBG_CONFIG,
  223. "Custom auto subscribe mode %s for group %s",
  224. res, grp );
  225. return res;
  226. }
  227. return Cfg_defaultAutoSubscribeMode();
  228. }
  229. GroupEnum *
  230. new_GetGrEn( const char *name )
  231. {
  232. GroupEnum *res;
  233. int servIdx;
  234. res = (GroupEnum *) malloc( sizeof( GroupEnum ) );
  235. if ( res == NULL )
  236. {
  237. Log_err( "Malloc of GroupEnum failed." );
  238. exit( EXIT_FAILURE );
  239. }
  240. if ( ! searchServ( name, &servIdx ) )
  241. res->groupEntry = NULL;
  242. else
  243. res->groupEntry = &config.serv[ servIdx ].getgroups;
  244. GrEn_first( res );
  245. return res;
  246. }
  247. GroupEnum *
  248. new_OmitGrEn( const char *name )
  249. {
  250. GroupEnum *res;
  251. int servIdx;
  252. res = (GroupEnum *) malloc( sizeof( GroupEnum ) );
  253. if ( res == NULL )
  254. {
  255. Log_err( "Malloc of GroupEnum failed." );
  256. exit( EXIT_FAILURE );
  257. }
  258. if ( ! searchServ( name, &servIdx ) )
  259. res->groupEntry = NULL;
  260. else
  261. res->groupEntry = &config.serv[ servIdx ].omitgroups;
  262. GrEn_first( res );
  263. return res;
  264. }
  265. void
  266. del_GrEn( GroupEnum *ge )
  267. {
  268. free(ge);
  269. }
  270. void
  271. GrEn_first( GroupEnum *ge )
  272. {
  273. ge->groupIdx = 0;
  274. }
  275. const char *
  276. GrEn_next( GroupEnum *ge )
  277. {
  278. if ( ge->groupEntry == NULL ||
  279. ge->groupIdx >= ge->groupEntry->numGroup )
  280. return NULL;
  281. return ge->groupEntry->groups[ ge->groupIdx++ ];
  282. }
  283. static void
  284. logSyntaxErr( const char *line )
  285. {
  286. Log_err( "Syntax error in config file: %s", line );
  287. }
  288. static void
  289. getBool( Bool *variable, const char *line )
  290. {
  291. Str value, name, lowerLn;
  292. strcpy( lowerLn, line );
  293. Utl_toLower( lowerLn );
  294. if ( sscanf( lowerLn, "%s %s", name, value ) != 2 )
  295. {
  296. logSyntaxErr( line );
  297. return;
  298. }
  299. if ( strcmp( value, "yes" ) == 0 )
  300. *variable = TRUE;
  301. else if ( strcmp( value, "no" ) == 0 )
  302. *variable = FALSE;
  303. else
  304. Log_err( "Error in config file %s must be yes or no", name );
  305. }
  306. static void
  307. getInt( int *variable, int min, int max, const char *line )
  308. {
  309. int value;
  310. Str name;
  311. if ( sscanf( line, "%s %d", name, &value ) != 2 )
  312. {
  313. logSyntaxErr( line );
  314. return;
  315. }
  316. if ( value < min || value > max )
  317. {
  318. Log_err( "Range error in config file %s [%d,%d]", name, min, max );
  319. return;
  320. }
  321. *variable = value;
  322. }
  323. static void
  324. getStr( char *variable, const char *line )
  325. {
  326. Str dummy;
  327. if ( sscanf( line, "%s %s", dummy, variable ) != 2 )
  328. {
  329. logSyntaxErr( line );
  330. return;
  331. }
  332. }
  333. static void
  334. getText( Str variable, const char *line )
  335. {
  336. const char *l;
  337. /* Skip command */
  338. l = Utl_restOfLn( line, 1 );
  339. Utl_cpyStr( variable, l );
  340. }
  341. static void
  342. getServ( const char *line )
  343. {
  344. Str dummy, name, user, pass;
  345. int r, len;
  346. ServEntry entry;
  347. memset( &entry, 0, sizeof( entry ) );
  348. user[ 0 ] = pass[ 0 ] = '\0';
  349. r = sscanf( line, "%s %s %s %s",
  350. dummy, name, user, pass );
  351. if ( r < 2 )
  352. {
  353. logSyntaxErr( line );
  354. return;
  355. }
  356. len = strlen( name );
  357. /* To make server name more definit, it is made lowercase and
  358. port is removed, if it is the default port */
  359. if ( len > 4 && strcmp( name + len - 4, ":119" ) == 0 )
  360. name[ len - 4 ] = '\0';
  361. Utl_toLower( name );
  362. Utl_allocAndCpy( &entry.name, name );
  363. Utl_allocAndCpy( &entry.user, user );
  364. Utl_allocAndCpy( &entry.pass, pass );
  365. if ( config.maxServ < config.numServ + 1 )
  366. {
  367. if ( ! ( config.serv = realloc( config.serv,
  368. ( config.maxServ + 5 )
  369. * sizeof( ServEntry ) ) ) )
  370. {
  371. Log_err( "Could not realloc server list" );
  372. exit( EXIT_FAILURE );
  373. }
  374. config.maxServ += 5;
  375. }
  376. config.serv[ config.numServ++ ] = entry;
  377. }
  378. static void
  379. getExpire( const char *line )
  380. {
  381. Str dummy, pattern;
  382. ExpireEntry entry;
  383. int days;
  384. if ( sscanf( line, "%s %s %d", dummy, pattern, &days ) != 3 )
  385. {
  386. logSyntaxErr( line );
  387. return;
  388. }
  389. else
  390. {
  391. if ( days < 0 )
  392. {
  393. Log_err( "Expire days error in '%s': must be integer > 0",
  394. line, days );
  395. return;
  396. }
  397. Utl_toLower( pattern );
  398. Utl_allocAndCpy( &entry.pattern, pattern );
  399. entry.days = days;
  400. if ( config.maxExpire < config.numExpire + 1 )
  401. {
  402. if ( ! ( config.expire = realloc( config.expire,
  403. ( config.maxExpire + 5 )
  404. * sizeof( ExpireEntry ) ) ) )
  405. {
  406. Log_err( "Could not realloc expire list" );
  407. exit( EXIT_FAILURE );
  408. }
  409. config.maxExpire += 5;
  410. }
  411. config.expire[ config.numExpire++ ] = entry;
  412. }
  413. }
  414. static void
  415. getGroups( char *line, Bool isGet )
  416. {
  417. const char *name;
  418. ItemList *patterns;
  419. const char *pattern;
  420. if ( config.numServ == 0 )
  421. {
  422. Log_err( "No current server in %s", line );
  423. return;
  424. }
  425. name = line;
  426. /* Skip over name and terminate it */
  427. while ( line[ 0 ] != '\0' && ! isspace( line[ 0 ] ) )
  428. line++;
  429. if ( line[ 0 ] == '\0' )
  430. {
  431. logSyntaxErr( name );
  432. return;
  433. }
  434. line[ 0 ] = '\0';
  435. line++;
  436. patterns = new_Itl( line, " ," );
  437. for( pattern = Itl_first( patterns );
  438. pattern != NULL;
  439. pattern = Itl_next( patterns ) )
  440. {
  441. GroupEntry *g;
  442. if ( isGet )
  443. g = &config.serv[ config.numServ - 1 ].getgroups;
  444. else
  445. g = &config.serv[ config.numServ - 1 ].omitgroups;
  446. if ( g->maxGroup < g->numGroup + 1 )
  447. {
  448. if ( ! ( g->groups = realloc( g->groups,
  449. ( g->maxGroup + 5 )
  450. * sizeof( char * ) ) ) )
  451. {
  452. Log_err( "Could not realloc group list" );
  453. exit( EXIT_FAILURE );
  454. }
  455. g->maxGroup += 5;
  456. }
  457. Utl_allocAndCpy( &g->groups[ g->numGroup++ ], pattern );
  458. }
  459. del_Itl( patterns) ;
  460. }
  461. static void
  462. getDebugMask( char *line )
  463. {
  464. const char *name;
  465. ItemList *maskNames;
  466. const char *maskName;
  467. unsigned mask;
  468. name = line;
  469. /* Skip over name and terminate it */
  470. while ( line[ 0 ] != '\0' && ! isspace( line[ 0 ] ) )
  471. line++;
  472. if ( line[ 0 ] == '\0' )
  473. {
  474. logSyntaxErr( name );
  475. return;
  476. }
  477. line[ 0 ] = '\0';
  478. line++;
  479. mask = LOG_DBG_NONE;
  480. maskNames = new_Itl( line, " ," );
  481. for( maskName = Itl_first( maskNames );
  482. maskName != NULL;
  483. maskName = Itl_next( maskNames ) )
  484. {
  485. if ( strcmp( maskName, "all" ) == 0 )
  486. mask = LOG_DBG_ALL;
  487. else if ( strcmp( maskName, "none" ) == 0 )
  488. mask = LOG_DBG_NONE;
  489. else if ( strcmp( maskName, "config" ) == 0 )
  490. mask |= LOG_DBG_CONFIG;
  491. else if ( strcmp( maskName, "control" ) == 0 )
  492. mask |= LOG_DBG_CONTROL;
  493. else if ( strcmp( maskName, "expire" ) == 0 )
  494. mask |= LOG_DBG_EXPIRE;
  495. else if ( strcmp( maskName, "fetch" ) == 0 )
  496. mask |= LOG_DBG_FETCH;
  497. else if ( strcmp( maskName, "filter" ) == 0 )
  498. mask |= LOG_DBG_FILTER;
  499. else if ( strcmp( maskName, "newsbase" ) == 0 )
  500. mask |= LOG_DBG_NEWSBASE;
  501. else if ( strcmp( maskName, "noffle" ) == 0 )
  502. mask |= LOG_DBG_NOFFLE;
  503. else if ( strcmp( maskName, "post" ) == 0 )
  504. mask |= LOG_DBG_POST;
  505. else if ( strcmp( maskName, "protocol" ) == 0 )
  506. mask |= LOG_DBG_PROTOCOL;
  507. else if ( strcmp( maskName, "requests" ) == 0 )
  508. mask |= LOG_DBG_REQUESTS;
  509. else if ( strcmp( maskName, "server" ) == 0 )
  510. mask |= LOG_DBG_SERVER;
  511. else
  512. logSyntaxErr( line );
  513. }
  514. del_Itl( maskNames) ;
  515. Log_setDbgMask( mask );
  516. }
  517. static Bool
  518. isValidAutoSubscribeMode( const char *mode )
  519. {
  520. return strcmp( mode, "full" ) == 0
  521. || strcmp( mode, "thread" ) == 0
  522. || strcmp( mode, "over" ) == 0
  523. || strcmp( mode, "off" ) == 0;
  524. }
  525. static void
  526. getAutoSubscribeMode( const char *line )
  527. {
  528. Str dummy, pattern, mode;
  529. AutoSubscribeModeEntry entry;
  530. int items;
  531. items = sscanf( line, "%s %s %s", dummy, pattern, mode );
  532. if ( items == 2 )
  533. {
  534. /* Backwards compat. default-auto-subscribe-mode */
  535. Utl_cpyStr( mode, pattern );
  536. Utl_toLower( mode );
  537. if ( ! isValidAutoSubscribeMode( mode ) )
  538. {
  539. logSyntaxErr( line );
  540. return;
  541. }
  542. strcpy( config.defaultAutoSubscribeMode, mode );
  543. return;
  544. }
  545. else if ( items != 3 )
  546. {
  547. logSyntaxErr( line );
  548. return;
  549. }
  550. Utl_toLower( mode );
  551. if ( ! isValidAutoSubscribeMode( mode ) )
  552. {
  553. logSyntaxErr( line );
  554. return;
  555. }
  556. Utl_toLower( pattern );
  557. Utl_allocAndCpy( &entry.pattern, pattern );
  558. Utl_allocAndCpy( &entry.mode, mode );
  559. if ( config.maxAutoSubscribeMode < config.numAutoSubscribeMode + 1 )
  560. {
  561. if ( ! ( config.autoSubscribeMode =
  562. realloc( config.autoSubscribeMode,
  563. ( config.maxAutoSubscribeMode + 5 )
  564. * sizeof( AutoSubscribeModeEntry ) ) ) )
  565. {
  566. Log_err( "Could not realloc auto subscribe mode list" );
  567. exit( EXIT_FAILURE );
  568. }
  569. config.maxAutoSubscribeMode += 5;
  570. }
  571. config.autoSubscribeMode[ config.numAutoSubscribeMode++ ] = entry;
  572. }
  573. static const char *
  574. getToken( const char *line, Str value )
  575. {
  576. Bool isQuoted;
  577. char quoteChar;
  578. Bool seenEscape;
  579. char *maxVal;
  580. while ( *line != '\0' && isspace( *line ) )
  581. line++;
  582. if ( *line == '\0' )
  583. return NULL;
  584. maxVal = &value[ MAXCHAR ];
  585. isQuoted = ( *line == '\'' || *line == '"' );
  586. if ( isQuoted )
  587. {
  588. quoteChar = *line;
  589. line++;
  590. seenEscape = FALSE;
  591. while ( *line != '\0'
  592. && ( *line != quoteChar || seenEscape )
  593. && value < maxVal )
  594. {
  595. if ( seenEscape )
  596. {
  597. *value++ = *line;
  598. seenEscape = FALSE;
  599. }
  600. else
  601. {
  602. if ( *line == '\\' )
  603. seenEscape = TRUE;
  604. else
  605. *value++ = *line;
  606. }
  607. line++;
  608. }
  609. if ( *line == quoteChar )
  610. line++;
  611. }
  612. else
  613. {
  614. while ( *line != '\0' && ! isspace( *line ) && value < maxVal )
  615. *value++ = *line++;
  616. }
  617. *value = '\0';
  618. return line;
  619. }
  620. static void
  621. getFilter( const char *line )
  622. {
  623. Str ruleBuf, value;
  624. const char *l;
  625. char *p, *ruleName;
  626. Filter *f;
  627. FilterRule rule;
  628. Bool seenAction;
  629. f = new_Filter();
  630. /* Skip "filter" */
  631. l = Utl_restOfLn( line, 1 );
  632. seenAction = FALSE;
  633. for(;;)
  634. {
  635. while ( *l != '\0' && isspace( *l ) )
  636. l++;
  637. if ( *l == '\0' )
  638. break;
  639. /* Get the rule title */
  640. p = ruleBuf;
  641. while ( *l != '\0' && *l != '=' && *l != '<' && *l != '>' )
  642. *p++ = *l++;
  643. *p = '\0';
  644. ruleName = Utl_stripWhiteSpace( ruleBuf );
  645. Utl_toLower( ruleName );
  646. if ( *ruleName == '\0' )
  647. goto synErr;
  648. /* Do we know this rule? */
  649. if ( strcmp( ruleName, "group" ) == 0 )
  650. rule.type = RULE_NEWSGROUP;
  651. else if ( strcmp( ruleName, "subject" ) == 0 )
  652. rule.type = RULE_SUBJECT;
  653. else if ( strcmp( ruleName, "from" ) == 0 )
  654. rule.type = RULE_FROM;
  655. else if ( strcmp( ruleName, "msgid" ) == 0 )
  656. rule.type = RULE_MSGID;
  657. else if ( strcmp( ruleName, "bytes" ) == 0 )
  658. rule.type = RULE_BYTES_LT;
  659. else if ( strcmp( ruleName, "lines" ) == 0 )
  660. rule.type = RULE_LINES_LT;
  661. else if ( strcmp( ruleName, "refs" ) == 0 )
  662. rule.type = RULE_NOREFS_LT;
  663. else if ( strcmp( ruleName, "xposts" ) == 0 )
  664. rule.type = RULE_XPOSTS_LT;
  665. else if ( strcmp( ruleName, "post-status" ) == 0 )
  666. rule.type = RULE_POST_STATUS;
  667. else if ( strcmp( ruleName, "action" ) != 0 )
  668. goto synErr;
  669. if ( rule.type == RULE_BYTES_LT ||
  670. rule.type == RULE_LINES_LT ||
  671. rule.type == RULE_NOREFS_LT ||
  672. rule.type == RULE_XPOSTS_LT )
  673. {
  674. if ( *l == '=' )
  675. rule.type += 1;
  676. else if ( *l == '>' )
  677. rule.type += 2;
  678. else if ( *l != '<' )
  679. goto synErr;
  680. }
  681. else if ( *l != '=' )
  682. goto synErr;
  683. /* Skip past '=' (or '>' or '<') */
  684. l++;
  685. /* OK, we now have a valid rule. What value? */
  686. l = getToken( l, value );
  687. if ( l == NULL )
  688. goto synErr;
  689. if ( strcmp( ruleName, "action" ) == 0 )
  690. {
  691. if ( seenAction )
  692. goto synErr;
  693. Utl_toLower( value );
  694. if ( strcmp( value, "full" ) == 0 )
  695. f->action = FILTER_FULL;
  696. else if ( strcmp( value, "over" ) == 0 )
  697. f->action = FILTER_XOVER;
  698. else if ( strcmp( value, "thread" ) == 0 )
  699. f->action = FILTER_THREAD;
  700. else if ( strcmp( value, "discard" ) == 0 )
  701. f->action = FILTER_DISCARD;
  702. else if ( strcmp( value, "default" ) == 0 )
  703. f->action = FILTER_DEFAULT;
  704. seenAction = TRUE;
  705. }
  706. else if ( rule.type == RULE_NEWSGROUP )
  707. Utl_allocAndCpy( &rule.data.grp, value );
  708. else if ( rule.type >= RULE_SUBJECT && rule.type <= RULE_MSGID )
  709. {
  710. if ( regcomp( &rule.data.regex, value, REG_EXTENDED ) != 0 )
  711. goto synErr;
  712. }
  713. else if (rule.type == RULE_POST_STATUS )
  714. if ( ( strcmp( value, "yes" ) == 0 ) || \
  715. ( strcmp( value, "no" ) == 0 ) || \
  716. ( strncmp( value, "mod", 3 ) == 0 ) )
  717. /* no need to type out "moderated" */
  718. rule.data.postAllow = value[0]; /* 'y','n' or 'm' */
  719. else
  720. goto synErr;
  721. else
  722. {
  723. char * endVal;
  724. int suffix;
  725. rule.data.amount = strtoul( value, &endVal, 0 );
  726. suffix = tolower( *endVal );
  727. if ( suffix == 'k' || suffix == 'm' )
  728. {
  729. rule.data.amount *= 1024;
  730. if ( suffix == 'm' )
  731. rule.data.amount *= 1024;
  732. endVal++;
  733. }
  734. if ( *endVal != '\0' && ! isspace( *endVal ) )
  735. goto synErr;
  736. }
  737. if ( strcmp( ruleName, "action" ) != 0 )
  738. {
  739. Log_dbg( LOG_DBG_CONFIG,
  740. "Adding rule type %d value %s",
  741. rule.type, value );
  742. Flt_addRule( f, rule );
  743. }
  744. }
  745. Log_dbg( LOG_DBG_CONFIG, "Adding filter, action %d", f->action );
  746. Flt_addFilter( f );
  747. return;
  748. synErr:
  749. logSyntaxErr( line );
  750. return;
  751. }
  752. void
  753. Cfg_read( void )
  754. {
  755. char *p;
  756. FILE *f;
  757. Str file, line, lowerLine, name, s;
  758. snprintf( file, MAXCHAR, CONFIGFILE );
  759. if ( ! ( f = fopen( file, "r" ) ) )
  760. {
  761. Log_err( "Cannot read %s", file );
  762. return;
  763. }
  764. while ( fgets( line, MAXCHAR, f ) )
  765. {
  766. p = Utl_stripWhiteSpace( line );
  767. Utl_stripComment( p );
  768. Utl_cpyStr( lowerLine, p );
  769. Utl_toLower( lowerLine );
  770. p = lowerLine;
  771. if ( *p == '\0' )
  772. continue;
  773. if ( sscanf( p, "%s", name ) != 1 )
  774. Log_err( "Syntax error in %s: %s", file, line );
  775. else if ( strcmp( "max-fetch", name ) == 0 )
  776. getInt( &config.maxFetch, 0, INT_MAX, p );
  777. else if ( strcmp( "auto-unsubscribe-days", name ) == 0 )
  778. getInt( &config.autoUnsubscribe, -1, INT_MAX, p );
  779. else if ( strcmp( "thread-follow-time", name ) == 0 )
  780. getInt( &config.threadFollowTime, 0, INT_MAX, p );
  781. else if ( strcmp( "connect-timeout", name ) == 0 )
  782. getInt( &config.connectTimeout, 0, INT_MAX, p );
  783. else if ( strcmp( "default-expire", name ) == 0 )
  784. getInt( &config.defaultExpire, 0, INT_MAX, p );
  785. else if ( strcmp( "auto-subscribe", name ) == 0 )
  786. getBool( &config.autoSubscribe, p );
  787. else if ( strcmp( "auto-unsubscribe", name ) == 0 )
  788. getBool( &config.autoUnsubscribe, p );
  789. else if ( strcmp( "info-always-unread", name ) == 0 )
  790. getBool( &config.infoAlways, p );
  791. else if ( strcmp( "replace-messageid", name ) == 0 )
  792. getBool( &config.replaceMsgId, p );
  793. else if ( strcmp( "hostname", name ) == 0 )
  794. /* use line, do not change to lowercase */
  795. getStr( config.hostnameMsgId, line );
  796. else if ( strcmp( "post-locally", name ) == 0 )
  797. getBool( &config.postLocal, p );
  798. else if ( strcmp( "default-auto-subscribe-mode", name ) == 0 )
  799. {
  800. getStr( s, p );
  801. if ( ! isValidAutoSubscribeMode( s ) )
  802. {
  803. logSyntaxErr( line );
  804. return;
  805. }
  806. else
  807. strcpy( config.defaultAutoSubscribeMode, s );
  808. }
  809. else if ( strcmp( "mail-to", name ) == 0 )
  810. getStr( config.mailTo, p );
  811. else if ( strcmp( "expire", name ) == 0 )
  812. getExpire( p );
  813. else if ( strcmp( "auto-subscribe-mode", name ) == 0 )
  814. getAutoSubscribeMode( p );
  815. else if ( strcmp( "log-debug", name ) == 0 )
  816. getDebugMask( p );
  817. else if ( strcmp( "getgroups", name ) == 0 )
  818. getGroups( p, TRUE );
  819. else if ( strcmp( "omitgroups", name ) == 0 )
  820. getGroups( p, FALSE );
  821. else if ( strcmp( "path-header", name ) == 0 )
  822. getStr( config.pathHeader, p );
  823. else if ( strcmp( "from-domain", name ) == 0 )
  824. getStr( config.fromDomain, p );
  825. /* The following need line because they may have uppercase data */
  826. else if ( strcmp( "organization", name ) == 0 )
  827. getText( config.organization, line );
  828. else if ( strcmp( "server", name ) == 0 )
  829. getServ( line );
  830. else if ( strcmp( "filter", name ) == 0 )
  831. getFilter( line );
  832. else
  833. Log_err( "Unknown config option: %s", name );
  834. }
  835. fclose( f );
  836. if ( ! config.numServ )
  837. {
  838. Log_err( "Config file contains no server" );
  839. exit( EXIT_FAILURE );
  840. }
  841. }