Remove trailing whitespace.
[dockapps.git] / wmnotify / src / configfile.c
blob1600f24eb3c755d3ff8a0dbb51482032f6d76579
1 /*
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.
21 #if HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <sys/stat.h>
28 #include <stdlib.h>
29 #include <stdbool.h>
31 #if STDC_HEADERS
32 # include <string.h>
33 #elif HAVE_STRINGS_H
34 # include <strings.h>
35 #endif
37 #include <pwd.h>
39 #include "common.h"
40 #include "wmnotify.h"
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";
52 static void
53 CreateDefaultConfigurationFile( char *file )
55 int status;
56 FILE *fp;
58 fp = fopen( file, "w" );
59 if( fp == NULL ) {
60 fprintf( stderr, "%s: Can't create file \"%s\"\n", PACKAGE, file );
61 exit( EXIT_FAILURE );
64 /* Changing permissions so that only the user can read/modify the file. */
65 status = chmod( file, S_IRUSR | S_IWUSR );
66 if( status < 0 ) {
67 fprintf( stderr, "%s: Can't set permission bits on file \"%s\"\n", PACKAGE, file );
68 exit( EXIT_FAILURE );
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 "
78 "disabled).\n" );
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 "
95 "disabled).\n" );
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 );
114 static void
115 ParseCommand( char *line, /*@out@*/ char *argv[] )
117 int argc = 0;
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 ... */
128 argc++;
130 if( argc == ARGV_LIMIT ) {
131 fprintf( stderr, "%s: Too much arguments for external command\n",
132 PACKAGE );
133 exit( EXIT_FAILURE );
137 *argv = NULL; /* mark the end of argument list */
141 static char *
142 GetArguments( char *parameter, bool single_argument )
144 char *token;
146 if( single_argument ) {
147 token = strtok( NULL, delimiter_single_arg );
149 else {
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
152 character '\n'. */
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 );
162 return token;
166 static int
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 );
177 return atoi( temp );
181 static void
182 ParseConfigurationFile( FILE *file )
184 char line[LINE_BUFFER_LEN];
185 char *token;
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
206 the buffer. */
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;
222 else {
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" ) ){
235 int number;
237 token = GetArguments( "use_ssl", true );
238 number = GetNumber( token, "use_ssl" );
239 if( number == 0 ) {
240 wmnotify_infos.use_ssl = false;
242 else if( number == 1 ) {
243 #if HAVE_SSL
244 wmnotify_infos.use_ssl = true;
245 #else
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 );
249 #endif
251 else {
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 );
260 server_found = true;
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" );
283 if( delay == 0 ) {
284 fprintf( stderr, "%s: Mail check interval must be greater than '0'\n",
285 PACKAGE );
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" ) ){
297 int number;
299 token = GetArguments( "enablebeep", true );
300 number = GetNumber( token, "enablebeep" );
301 if( number == 0 ) {
302 wmnotify_infos.audible_notification = false;
304 else if( number == 1 ) {
305 wmnotify_infos.audible_notification = true;
307 else {
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" );
322 else {
323 fprintf( stderr, "%s: invalid parameter in configuration file: %s\n", PACKAGE,
324 token );
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,
331 token );
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";
348 else {
349 return; /* success */
352 /* Failure. */
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 ******************************************************************************/
362 void
363 ConfigurationFileInit( void )
365 FILE *fp;
366 int status;
367 size_t len;
369 /* Check if an optional configuration file was specified on the command
370 line. */
371 if( wmnotify_infos.optional_config_file != NULL ) {
372 /* Trying to open the file. */
373 fp = fopen( wmnotify_infos.optional_config_file, "r" );
374 if( fp == NULL ) {
375 perror( PACKAGE );
376 ErrorLocation( __FILE__, __LINE__ );
377 exit( EXIT_FAILURE );
380 else {
381 /* Using the default configuration file. */
382 char *home_dir;
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() );
390 if( pw != NULL ) {
391 home_dir = pw->pw_dir;
393 else {
394 fprintf( stderr, "%s: Couldn't determine user's home directory path\n",
395 PACKAGE );
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 )
402 + 1;
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" );
408 if( fp == NULL ) {
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 );