2 * configfile.c -- Parsing the configuration file
4 * Copyright (C) 2003 Hugo Villeneuve <hugo@hugovil.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
41 #include "configfile.h"
44 #define LINE_BUFFER_LEN 256
46 /* Name of configuration file in user's home directory. */
47 const static char default_config_filename
[] = ".wmnotifyrc";
48 const static char delimiter_single_arg
[] = " \n";
49 const static char delimiter_multiple_arg
[] = "#\n";
53 CreateDefaultConfigurationFile( char *file
)
58 fp
= fopen( file
, "w" );
60 fprintf( stderr
, "%s: Can't create file \"%s\"\n", PACKAGE
, file
);
64 /* Changing permissions so that only the user can read/modify the file. */
65 status
= chmod( file
, S_IRUSR
| S_IWUSR
);
67 fprintf( stderr
, "%s: Can't set permission bits on file \"%s\"\n", PACKAGE
, file
);
71 fprintf( fp
, "# ~/.wmnotifyrc -- Default configuration file for wmnotify\n\n" );
72 fprintf( fp
, "# Replace all 'xxxxxxxx' fields with your own settings.\n\n" );
73 fprintf( fp
, "# Parameters preceded by a '#' character are optional.\n" );
74 fprintf( fp
, "# You can set their values by removing the leading '#'.\n\n" );
75 fprintf( fp
, "# Mail Protocol: POP3 or IMAP4.\n" );
76 fprintf( fp
, "protocol POP3\n\n" );
77 fprintf( fp
, "# Use SSL encrytion: 0=disable, 1=enable (optional, default is "
79 fprintf( fp
, "use_ssl 0\n\n" );
80 fprintf( fp
, "# Mail Server Name.\n" );
81 fprintf( fp
, "server xxxxxxxx\n\n" );
82 fprintf( fp
, "# Mail Server Port Number (optional, default is 110).\n" );
83 fprintf( fp
, "port 110\n\n" );
84 fprintf( fp
, "# Username.\n" );
85 fprintf( fp
, "username xxxxxxxx\n\n" );
86 fprintf( fp
, "# Password.\n" );
87 fprintf( fp
, "password xxxxxxxx\n\n" );
88 fprintf( fp
, "# IMAP folder name (optional, default is INBOX).\n" );
89 fprintf( fp
, "# folder INBOX.some_folder\n\n" );
90 fprintf( fp
, "# Mail Check Interval (in minutes, default is 5 minutes).\n" );
91 fprintf( fp
, "#mailcheckdelay 5\n\n" );
92 fprintf( fp
, "# Default mail client (optional).\n" );
93 fprintf( fp
, "#mailclient sylpheed\n\n" );
94 fprintf( fp
, "# Audio notification, 0=disable, 1=enable (optional, default is "
96 fprintf( fp
, "enablebeep 0\n\n" );
97 fprintf( fp
, "# Location of sound file for audio notification. If no sound file is\n" );
98 fprintf( fp
, "# specified, the console beep will be used instead.\n" );
99 fprintf( fp
, "audiofile /usr/local/share/sounds/halmsgs.wav\n\n" );
100 fprintf( fp
, "# Volume (0 to 100%%).\n" );
101 fprintf( fp
, "volume 100\n" );
103 fprintf( stderr
, "%s: A default configuration file has been created in your "
104 "home directory: \"%s\"\n", PACKAGE
, file
);
105 fprintf( stderr
, "You must edit it before running %s.\n", PACKAGE
);
107 status
= fclose( fp
);
108 if( status
!= EXIT_SUCCESS
) {
109 fprintf( stderr
, "%s: Error closing file \"%s\"\n", PACKAGE
, file
);
115 ParseCommand( char *line
, /*@out@*/ char *argv
[] )
119 while( *line
!= '\0' ) { /* if not the end of line ....... */
120 while( *line
== ' ' || *line
== '\t' || *line
== '\n' ) {
121 *line
++ = '\0'; /* replace white spaces with 0 */
123 *argv
++ = line
; /* save the argument position */
124 while( *line
!= '\0' && *line
!= ' ' && *line
!= '\t' && *line
!= '\n' ) {
125 line
++; /* skip the argument until ... */
130 if( argc
== ARGV_LIMIT
) {
131 fprintf( stderr
, "%s: Too much arguments for external command\n",
133 exit( EXIT_FAILURE
);
137 *argv
= NULL
; /* mark the end of argument list */
142 GetArguments( char *parameter
, bool single_argument
)
146 if( single_argument
) {
147 token
= strtok( NULL
, delimiter_single_arg
);
150 /* We search for a string terminated by either a '#' character (the rest of
151 the line is then a comment, which is simply ignored ), or the end of line
153 token
= strtok( NULL
, delimiter_multiple_arg
);
156 if( token
== NULL
) {
157 fprintf( stderr
, "%s: Missing argument for \"%s\" parameter in "
158 "configuration file.\n", PACKAGE
, parameter
);
159 exit( EXIT_FAILURE
);
167 GetNumber( char *token
, char *parameter
)
169 char temp
[32]; /* Check size ??? */
171 if( sscanf( token
, "%[0123456789]", temp
) == 0 ) {
172 fprintf( stderr
, "%s: Invalid argument for \"%s\" parameter in "
173 "configuration file.\n", PACKAGE
, parameter
);
174 exit( EXIT_FAILURE
);
182 ParseConfigurationFile( FILE *file
)
184 char line
[LINE_BUFFER_LEN
];
186 bool protocol_found
= false;
187 bool server_found
= false;
188 bool username_found
= false;
189 bool password_found
= false;
190 const char *err_string
= NULL
;
192 /* Default values for optional parameters. */
193 strcpy( wmnotify_infos
.imap_folder
, "INBOX"); /* Default IMAP folder. */
194 wmnotify_infos
.port
= 110;
195 wmnotify_infos
.mail_check_interval
= 60; /* 1 minute interval. */
196 wmnotify_infos
.audible_notification
= false; /* Disabled. */
197 wmnotify_infos
.use_ssl
= false; /* Disabled. */
198 wmnotify_infos
.mail_client_argv
[0] = NULL
; /* No default command. */
199 wmnotify_infos
.audiofile
[0] = '\0'; /* No default audio file. */
200 wmnotify_infos
.volume
= 100; /* 100% volume. */
202 /* Reading one line of data from the configuration file. */
203 /* char *fgets(char *s, int size, FILE *stream);
204 Reading stops after an EOF or a newline. If a newline is read, it is
205 stored into the buffer. A '\0' is stored after the last character in
207 while( fgets( line
, LINE_BUFFER_LEN
, file
) != NULL
) {
208 token
= strtok( line
, delimiter_single_arg
);
210 if( ( token
== NULL
) || ( token
[0] == '#' ) ) {
211 continue; /* Next iteration of the while() loop (next line). */
214 if( STREQ( token
, "protocol" ) ) {
215 token
= GetArguments( "protocol", true );
216 if( STREQ( token
, "POP3" ) == true ) {
217 wmnotify_infos
.protocol
= POP3_PROTOCOL
;
219 else if( STREQ( token
, "IMAP4" ) == true ) {
220 wmnotify_infos
.protocol
= IMAP4_PROTOCOL
;
223 fprintf( stderr
, "%s: protocol must be POP3 or IMAP4.\n", PACKAGE
);
224 exit( EXIT_FAILURE
);
227 protocol_found
= true;
229 else if( STREQ( token
, "imap_folder" ) ) {
230 token
= GetArguments( "imap_folder", true );
231 /* Should check size before using strcpy(), or use strncopy() instead. */
232 strcpy( wmnotify_infos
.imap_folder
, token
);
234 else if( STREQ( token
, "use_ssl" ) ){
237 token
= GetArguments( "use_ssl", true );
238 number
= GetNumber( token
, "use_ssl" );
240 wmnotify_infos
.use_ssl
= false;
242 else if( number
== 1 ) {
244 wmnotify_infos
.use_ssl
= true;
246 fprintf( stderr
, "%s error: You must compile %s with SSL support to\n" \
247 "set parameter 'use_ssl' to true in configuration file\n", PACKAGE
, PACKAGE
);
248 exit( EXIT_FAILURE
);
252 fprintf( stderr
, "%s: Invalid value for parameter 'use_ssl' in\n" \
253 "configuration file (must be 0 or 1): %d\n", PACKAGE
, number
);
254 exit( EXIT_FAILURE
);
257 else if( STREQ( token
, "server" ) ) {
258 token
= GetArguments( "server", true );
259 strncpy( wmnotify_infos
.server_name
, token
, MAX_STR_LEN
);
262 else if( STREQ( token
, "port" ) ) {
263 token
= GetArguments( "port", true );
264 wmnotify_infos
.port
= (u_int16_t
) GetNumber( token
, "port" );
267 else if( STREQ( token
, "username" ) ) {
268 token
= GetArguments( "username", true );
269 strncpy( wmnotify_infos
.username
, token
, MAX_STR_LEN
);
270 username_found
= true;
272 else if( STREQ( token
, "password" ) ) {
273 token
= GetArguments( "password", true );
274 strncpy( wmnotify_infos
.password
, token
, MAX_STR_LEN
);
275 password_found
= true;
277 else if( STREQ( token
, "mailcheckdelay" ) ) {
278 int delay
; /* delay in minutes. */
280 token
= GetArguments( "mailcheckdelay", true );
281 /* GetNumber() will exit if a negative number is entered. */
282 delay
= GetNumber( token
, "mailcheckdelay" );
284 fprintf( stderr
, "%s: Mail check interval must be greater than '0'\n",
286 exit( EXIT_FAILURE
);
288 wmnotify_infos
.mail_check_interval
= (unsigned int) delay
* 60;
290 else if( STREQ( token
, "mailclient" ) ) {
291 token
= GetArguments( "mailclient", false ); /* Multiple arguments */
292 strcpy( wmnotify_infos
.mail_client_command
, token
);
293 ParseCommand( wmnotify_infos
.mail_client_command
,
294 wmnotify_infos
.mail_client_argv
);
296 else if( STREQ( token
, "enablebeep" ) ){
299 token
= GetArguments( "enablebeep", true );
300 number
= GetNumber( token
, "enablebeep" );
302 wmnotify_infos
.audible_notification
= false;
304 else if( number
== 1 ) {
305 wmnotify_infos
.audible_notification
= true;
308 fprintf( stderr
, "%s: Invalid value for for parameter 'enablebeep' in\n" \
309 "configuration file (must be 0 or 1): %d\n", PACKAGE
, number
);
310 exit( EXIT_FAILURE
);
313 else if( STREQ( token
, "audiofile" ) ) {
314 token
= GetArguments( "audiofile", true );
315 /* Should check size before using strcpy(), or use strncopy() instead. */
316 strcpy( wmnotify_infos
.audiofile
, token
);
318 else if( STREQ( token
, "volume" ) ) {
319 token
= GetArguments( "volume", true );
320 wmnotify_infos
.volume
= GetNumber( token
, "volume" );
323 fprintf( stderr
, "%s: invalid parameter in configuration file: %s\n", PACKAGE
,
325 exit( EXIT_FAILURE
);
328 token
= strtok( NULL
, delimiter_single_arg
);
329 if( ( token
!= NULL
) && ( token
[0] != '#' ) ) {
330 fprintf( stderr
, "%s: Garbage at end of line in configuration file: %s\n", PACKAGE
,
332 exit( EXIT_FAILURE
);
336 if( protocol_found
== false ) {
337 err_string
= "protocol";
339 else if( server_found
== false ) {
340 err_string
= "server";
342 else if( username_found
== false ) {
343 err_string
= "username";
345 else if( password_found
== false ) {
346 err_string
= "password";
349 return; /* success */
353 fprintf( stderr
, "%s: Mandatory parameter \"%s\" missing from configuration "
354 "file.\n", PACKAGE
, err_string
);
355 exit( EXIT_FAILURE
);
359 /*******************************************************************************
360 * Read and parse the configuration file in the user's home directory
361 ******************************************************************************/
363 ConfigurationFileInit( void )
369 /* Check if an optional configuration file was specified on the command
371 if( wmnotify_infos
.optional_config_file
!= NULL
) {
372 /* Trying to open the file. */
373 fp
= fopen( wmnotify_infos
.optional_config_file
, "r" );
376 ErrorLocation( __FILE__
, __LINE__
);
377 exit( EXIT_FAILURE
);
381 /* Using the default configuration file. */
383 char *default_config_file
;
385 home_dir
= getenv("HOME");
386 if( home_dir
== NULL
) {
387 /* We're trying to expand ~/, but HOME isn't set. */
388 struct passwd
*pw
= getpwuid( getuid() );
391 home_dir
= pw
->pw_dir
;
394 fprintf( stderr
, "%s: Couldn't determine user's home directory path\n",
396 exit( EXIT_FAILURE
);
400 /* We add 1 to the length for the terminating character '\0'. */
401 len
= strlen( home_dir
) + strlen( "/" ) + strlen( default_config_filename
)
403 default_config_file
= xmalloc( len
, __FILE__
, __LINE__
);
405 sprintf( default_config_file
, "%s/%s", home_dir
, default_config_filename
);
407 fp
= fopen( default_config_file
, "r" );
409 /* If we cannot open the default configuration file, it probably means
410 it is missing, so we create it. */
411 CreateDefaultConfigurationFile( default_config_file
);
412 free( default_config_file
);
413 exit( EXIT_FAILURE
);
416 free( default_config_file
);
419 ParseConfigurationFile( fp
);
421 status
= fclose( fp
);
422 if( status
!= EXIT_SUCCESS
) {
423 fprintf( stderr
, "%s: Error closing configuration file.\n", PACKAGE
);
424 ErrorLocation( __FILE__
, __LINE__
);
425 exit( EXIT_FAILURE
);