wmail: use AC_CONFIG_HEADERS to generate config.h.
[dockapps.git] / wmail / src / config.c
blob7671f15c5ac62699d72f23ca4f4686c11fc939cb
1 ///////////////////////////////////////////////////////////////////////////////
2 // config.c
3 // configuration file parser, part of wmail
4 //
5 // Copyright 2000~2002, Sven Geisenhainer <sveng@informatik.uni-jena.de>.
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions
10 // are met:
11 // 1. Redistributions of source code must retain the above copyright
12 // notice, this list of conditions, and the following disclaimer.
13 // 2. Redistributions in binary form must reproduce the above copyright
14 // notice, this list of conditions, and the following disclaimer in the
15 // documentation and/or other materials provided with the distribution.
16 // 3. The name of the author may not be used to endorse or promote products
17 // derived from this software without specific prior written permission.
19 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 // IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #ifdef HAVE_CONFIG_H
32 #ifndef CONFIG_H_INCLUDED
33 #include "../config.h"
34 #define CONFIG_H_INCLUDED
35 #endif
36 #endif
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <limits.h>
43 #include "common.h"
44 #include "config.h"
47 ///////////////////////////////////////////////////////////////////////////////
48 // wmailrc file format
50 // # - comment-lines
51 // Window.Display = "string"
52 // Window.NonShaped = On|Off
53 // Window.Button.Command = "string"
54 // Mail.MailBox = "string"
55 // Mail.ChecksumFile = "string"
56 // Mail.CheckIntervall = number
57 // Mail.ShowOnlyNew = On|Off
58 // Mail.SkipSender = "string"
59 // Mail.OnNew.Command = "string"
60 // Mail.UseStatusField = On|Off
61 // Ticker.Mode = Address|NickName|FamilyName
62 // Ticker.Frames = number
63 // Ticker.BoldFont = On|Off
64 // Ticker.X11Font = "string"
65 // Colors.Symbols = "string"
66 // Colors.Font = "string"
67 // Colors.Backlight = "string"
68 // Colors.OffLight = "string"
69 // Colors.NonShapedFrame = "string"
73 ///////////////////////////////////////////////////////////////////////////////
74 // typedefs
77 // list of enum-identifiers and their associated values
78 typedef struct { char *id; int value; } enumList_t;
82 ///////////////////////////////////////////////////////////////////////////////
83 // local prototypes
86 static bool ReadString( const char *from, unsigned int line, char **to );
87 static bool ReadEnum( const char *from, unsigned int line, int *to,
88 const enumList_t *enumList );
89 static bool ReadBool( const char *from, unsigned int line, bool *to );
90 static bool ReadInt( const char *from, unsigned int line, int *to );
91 static bool IsWhiteSpace( const char *chr );
92 static const char *SkipWhiteSpaces( const char *str );
94 // current configuration
95 config_t config = {
96 NULL,
97 NULL, // use $MAIL environment-variable
98 NULL,
99 NULL,
100 NULL,
101 NULL,
102 NULL,
103 NULL,
104 NULL,
105 WMAIL_CHECK_INTERVAL,
106 WMAIL_FPS,
107 false,
108 false,
109 TICKER_ADDRESS,
110 NULL,
111 NULL,
112 false,
113 NULL,
118 // enumeration names for ticker mode
119 static enumList_t tickerEnum[] =
121 { "address", TICKER_ADDRESS },
122 { "familyname", TICKER_FAMILYNAME },
123 { "nickname", TICKER_NICKNAME },
124 { NULL, 0 }
127 static bool Tokenize( const char *line, const char **id, const char **value )
129 int len;
130 const char *token1, *token2;
132 if( line != NULL )
134 token1 = SkipWhiteSpaces( line );
136 if(( len = strlen( token1 )) != 0 && token1[0] != '#' )
138 token2 = strchr( token1, '=' );
139 if( token2 != NULL )
140 token2 = SkipWhiteSpaces( token2+1 );
142 if( !IsWhiteSpace( token2 ))
144 *id = token1;
145 *value = token2;
147 return true;
152 return false;
155 static void AddSenderToSkipList( char *sender )
157 int numNames, i;
158 char **skipName, **newList;
160 for( skipName = config.skipNames, numNames = 0;
161 skipName != NULL && *skipName != NULL; skipName++ )
163 if( !strcmp( *skipName, sender ))
164 return;
166 numNames++;
169 TRACE( "adding \"%s\" to skip-list of currently %d names\n", sender, numNames );
170 newList = malloc( sizeof(char *) * (numNames + 2) );
172 for( i = 0; i < numNames; ++i )
173 newList[i] = config.skipNames[i];
175 newList[i] = strdup( sender );
176 newList[i+1] = NULL;
177 free( config.skipNames );
178 config.skipNames = newList;
181 void ResetConfigStrings( void )
183 if( !( config.givenOptions & CL_MAILBOX )) {
184 free( config.mailBox );
185 config.mailBox = NULL;
188 if( !( config.givenOptions & CL_RUNCMD )) {
189 free( config.runCmd );
190 config.runCmd = NULL;
193 if( !( config.givenOptions & CL_SYMBOLCOLOR )) {
194 free( config.symbolColor );
195 config.symbolColor = NULL;
198 if( !( config.givenOptions & CL_FONTCOLOR )) {
199 free( config.fontColor );
200 config.fontColor = NULL;
203 if( !( config.givenOptions & CL_BACKCOLOR )) {
204 free( config.backColor );
205 config.backColor = NULL;
208 if( !( config.givenOptions & CL_OFFLIGHTCOLOR )) {
209 free( config.offlightColor );
210 config.offlightColor = NULL;
213 if( !( config.givenOptions & CL_BACKGROUNDCOLOR )) {
214 free( config.backgroundColor );
215 config.backgroundColor = NULL;
218 if( !( config.givenOptions & CL_CHECKSUMFILENAME )) {
219 free( config.checksumFileName );
220 config.checksumFileName = NULL;
223 if( !( config.givenOptions & CL_CMDONMAIL )) {
224 free( config.cmdOnMail );
225 config.cmdOnMail = NULL;
228 if( !( config.givenOptions & CL_USEX11FONT )) {
229 free( config.useX11Font );
230 config.useX11Font = NULL;
234 static void PostProcessConfiguration( void )
236 if( config.display == NULL )
237 config.display = strdup( WMAIL_DISPLAY );
239 if( config.runCmd == NULL )
240 config.runCmd = strdup( WMAIL_CLIENT_CMD );
242 if( config.mailBox == NULL )
244 char *envMBox = getenv( "MAIL" );
245 if( envMBox != NULL )
246 config.mailBox = strdup( envMBox );
250 void ReadConfigFile( bool resetConfigStrings )
252 char *usersHome;
254 // free all config strings and reset their pointers if required
255 if( resetConfigStrings )
256 ResetConfigStrings();
258 if(( usersHome = getenv( "HOME" )) != NULL )
260 char *fileName;
261 if(( fileName = MakePathName( usersHome, WMAIL_RC_FILE )) != NULL )
263 FILE *f = fopen( fileName, "rt" );
265 if( f != NULL )
267 char buf[1024];
268 int line = 1;
270 for( ; !feof( f ); ++line )
272 const char *id, *value;
273 unsigned int len;
275 if( fgets( buf, 1024, f ) == NULL )
276 break;
278 // first eliminate the trailing whitespaces
279 for( len = strlen( buf );
280 len > 0 && IsWhiteSpace(buf+(--len)); )
281 *(buf+len) = '\0';
283 if( !Tokenize( buf, &id, &value ))
284 continue;
286 if( !strncasecmp( id, "Window.Display", 14 )) {
287 if( !( config.givenOptions & CL_DISPLAY ))
288 ReadString( value, line, &config.display );
289 } else if( !strncasecmp( id, "Window.NonShaped", 16 )) {
290 if( !( config.givenOptions & CL_NOSHAPE ))
291 ReadBool( value, line, &config.noshape );
292 } else if( !strncasecmp( id, "Window.Button.Command", 21 )) {
293 if( !( config.givenOptions & CL_RUNCMD ))
294 ReadString( value, line, &config.runCmd );
295 } else if( !strncasecmp( id, "Mail.MailBox", 12 )) {
296 if( !( config.givenOptions & CL_MAILBOX ))
297 ReadString( value, line, &config.mailBox );
298 } else if( !strncasecmp( id, "Mail.ChecksumFile", 17 )) // no corresponding cmdline option
299 ReadString( value, line, &config.checksumFileName );
300 else if( !strncasecmp( id, "Mail.CheckIntervall", 19 )) {
301 if( !( config.givenOptions & CL_CHECKINTERVAL ))
302 ReadInt( value, line, &config.checkInterval );
303 } else if( !strncasecmp( id, "Mail.ShowOnlyNew", 16 )) {
304 if( !( config.givenOptions & CL_NEWMAILONLY ))
305 ReadBool( value, line, &config.newMailsOnly );
306 } else if( !strncasecmp( id, "Ticker.Mode", 11 )) {
307 if( !( config.givenOptions & CL_TICKERMODE ))
308 ReadEnum( value, line, (int *)&config.tickerMode, tickerEnum );
309 } else if( !strncasecmp( id, "Ticker.Frames", 13 )) {
310 if( !( config.givenOptions & CL_FPS ))
311 ReadInt( value, line, &config.fps );
312 } else if( !strncasecmp( id, "Colors.Symbols", 14 )) {
313 if( !( config.givenOptions & CL_SYMBOLCOLOR ))
314 ReadString( value, line, &config.symbolColor );
315 } else if( !strncasecmp( id, "Colors.Font", 11 )) {
316 if( !( config.givenOptions & CL_FONTCOLOR ))
317 ReadString( value, line, &config.fontColor );
318 } else if( !strncasecmp( id, "Colors.Backlight", 16 )) {
319 if( !( config.givenOptions & CL_BACKCOLOR ))
320 ReadString( value, line, &config.backColor );
321 } else if( !strncasecmp( id, "Colors.OffLight", 15 )) {
322 if( !( config.givenOptions & CL_OFFLIGHTCOLOR ))
323 ReadString( value, line, &config.offlightColor );
324 } else if( !strncasecmp( id, "Colors.NonShapedFrame", 21 )) {
325 if( !( config.givenOptions & CL_NOSHAPE ))
326 ReadString( value, line, &config.backgroundColor );
327 } else if( !strncasecmp( id, "Ticker.X11Font", 14 )) {
328 if( !( config.givenOptions & CL_USEX11FONT ))
329 ReadString( value, line, &config.useX11Font );
330 } else if( !strncasecmp( id, "Mail.SkipSender", 15 )) { // no corresponding cmdline options
331 char *skip;
332 if( ReadString( value, line, &skip ))
333 AddSenderToSkipList( skip );
334 } else if( !strncasecmp( id, "Mail.OnNew.Command", 18 )) {
335 if( !( config.givenOptions & CL_CMDONMAIL ))
336 ReadString( value, line, &config.cmdOnMail );
337 } else if( !strncasecmp( id, "Mail.UseStatusField", 19 )) {
338 if( !( config.givenOptions & CL_CONSIDERSTATUSFIELD ))
339 ReadBool( value, line, &config.considerStatusField );
340 } else if( !strncasecmp( id, "Mail.ReadStatus", 15 )) {
341 if( !( config.givenOptions & CL_READSTATUS ))
342 ReadString( value, line, &config.readStatus );
343 } else
344 WARNING( "cfg-file(%i): unrecognized: \"%s\"\n", line, buf );
347 fclose( f );
348 } else {
349 TRACE( "unable to open config-file \"%s\"\n", fileName );
352 free( fileName );
353 } else {
354 TRACE( "unable to allocate config-file\n" );
356 } else {
357 TRACE( "no $HOME defined - config-file not read\n" );
360 PostProcessConfiguration();
363 static bool ReadString( const char *from, unsigned int line, char **to )
365 if( *from++ == '"' ) {
366 const char *trailingQuote;
368 for( trailingQuote = strchr( from, '"' );
369 trailingQuote != NULL;
370 trailingQuote = strchr( trailingQuote, '"' ))
372 if( *(trailingQuote-1) != '\\' )
373 break;
375 ++trailingQuote;
378 if( trailingQuote != NULL ) {
379 // valid string found, copy and translate escape sequences
380 const char *c;
381 char *to_c;
383 // disposing of "to" is up to the caller...
384 *to = malloc( trailingQuote - from + 1 );
385 to_c = *to;
387 for( c = from; c != trailingQuote; ++c ) {
388 if( *c == '\\' ) {
389 switch( *(++c) ) {
390 case 'n': *to_c = '\n'; break;
391 case 'b': *to_c = '\b'; break;
392 case '\\': *to_c = '\\'; break;
393 case 'r': *to_c = '\r'; break;
394 case 't': *to_c = '\t'; break;
395 case '"': *to_c = '"'; break;
396 default: {
397 int value, i;
398 for( i = 0, value = 0; i < 3; ++i ) {
399 if( c+i == NULL || *(c+i) < '0' || *(c+i) > '9' )
400 break;
401 value = value * 10 + *(c+i) - '0';
403 if( value == 0 )
404 WARNING( "cfg-file(%i): '\\0' in string or unknown escape sequence found\n", line );
405 else {
406 *to_c = (char)value;
407 c += i-1;
411 } else
412 *to_c = *c;
414 ++to_c;
417 *to_c = '\0';
418 TRACE( "ReadString read \"%s\"\n", *to );
420 return true;
424 WARNING( "cfg-file(%i): invalid string\n" );
425 return false;
428 static bool ReadBool( const char *from, unsigned int line, bool *to )
430 if( !strcasecmp( from, "on" ) || !strcasecmp( from, "yes" ) || !strcasecmp( from, "true" ))
431 *to = true;
432 else if( !strcasecmp( from, "off" ) || !strcasecmp( from, "no" ) || !strcasecmp( from, "false" ))
433 *to = false;
434 else {
435 WARNING( "cfg-file(%i): invalid boolean value: \"%s\"\n", line, from );
436 return false;
439 TRACE( "ReadBool read \"%s\"\n", *to ? "True" : "False" );
441 return true;
444 static bool ReadInt( const char *from, unsigned int line, int *to )
446 int value = 0;
448 if( *from == '0' && (*(from+1) == 'x' || *(from+1) == 'X') ) {
449 for( from += 2; *from != '\0' && !IsWhiteSpace( from ); ++from )
451 if( value > (INT_MAX - 0xf) / 0x10 ) {
452 WARNING( "cfg-file(%i): hexadecimal-number too large: \">%x\"\n", line, INT_MAX );
453 return false;
456 if( *from >= '0' && *from <= '9')
457 value = value * 16 + *from - '0';
458 else if( *from >= 'a' && *from >= 'f' )
459 value = value * 16 + *from - 'a' + 10;
460 else if( *from >= 'A' && *from >= 'F' )
461 value = value * 16 + *from - 'A' + 10;
462 else {
463 WARNING( "cfg-file(%i): invalid hex-digit: \"%c\"\n", line, *from );
464 return false;
467 } else for( ; *from != '\0' && !IsWhiteSpace( from ); ++from ) {
468 if( value > (INT_MAX - 9) / 10 ) {
469 WARNING( "cfg-file(%i): decimal-number too large: \">%i\"\n", line, INT_MAX );
470 return false;
472 if( *from >= '0' && *from <= '9' )
473 value = value * 10 + *from - '0';
474 else {
475 WARNING( "cfg-file(%i): invalid decimal-digit: \"%c\"\n", line, *from );
476 return false;
480 *to = value;
482 TRACE( "ReadInt read \"%i\"\n", *to );
484 return true;
487 static bool ReadEnum( const char *from, unsigned int line, int *to,
488 const enumList_t *enumList )
490 int index;
492 for( index = 0; enumList[index].id != NULL; ++index )
493 if( !strcasecmp( enumList[index].id, from )) {
494 *to = enumList[index].value;
496 TRACE( "ReadEnum read \"%i\"\n", *to );
498 return true;
501 WARNING( "cfg-file(%i): unknown modifier: \"%s\"\n", line, from );
503 return false;
506 static bool IsWhiteSpace( const char *chr )
508 return ( chr != NULL && ( *chr == ' ' || *chr == '\t' || *chr == '\n' )) ? true : false;
511 static const char *SkipWhiteSpaces( const char *str )
513 const char *c;
515 for( c = str; IsWhiteSpace( c ); ++c )
518 return c;