1 /***************************************************************************
4 * Thu Mar 10 11:13:44 2005
5 * Copyright 2005 Simon Morlat
6 * Email simon.morlat@linphone.org
7 ****************************************************************************/
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 #include "linphonecore.h"
33 #if !defined(_WIN32_WCE)
35 #include <sys/types.h>
41 #define lp_new0(type,n) (type*)calloc(sizeof(type),n)
46 typedef struct _LpItem{
51 typedef struct _LpSection{
64 LpItem * lp_item_new(const char *key, const char *value){
65 LpItem *item=lp_new0(LpItem,1);
66 item->key=ortp_strdup(key);
67 item->value=ortp_strdup(value);
71 LpSection *lp_section_new(const char *name){
72 LpSection *sec=lp_new0(LpSection,1);
73 sec->name=ortp_strdup(name);
77 void lp_item_destroy(void *pitem){
78 LpItem *item=(LpItem*)pitem;
84 void lp_section_destroy(LpSection *sec){
86 ms_list_for_each(sec->items,lp_item_destroy);
87 ms_list_free(sec->items);
91 void lp_section_add_item(LpSection *sec,LpItem *item){
92 sec->items=ms_list_append(sec->items,(void *)item);
95 void lp_config_add_section(LpConfig *lpconfig, LpSection *section){
96 lpconfig->sections=ms_list_append(lpconfig->sections,(void *)section);
99 void lp_config_remove_section(LpConfig *lpconfig, LpSection *section){
100 lpconfig->sections=ms_list_remove(lpconfig->sections,(void *)section);
101 lp_section_destroy(section);
104 static bool_t is_first_char(const char *start, const char *pos){
106 for(p=start;p<pos;p++){
107 if (*p!=' ') return FALSE;
112 LpSection *lp_config_find_section(const LpConfig *lpconfig, const char *name){
115 /*printf("Looking for section %s\n",name);*/
116 for (elem=lpconfig->sections;elem!=NULL;elem=ms_list_next(elem)){
117 sec=(LpSection*)elem->data;
118 if (strcmp(sec->name,name)==0){
119 /*printf("Section %s found\n",name);*/
126 LpItem *lp_section_find_item(const LpSection *sec, const char *name){
129 /*printf("Looking for item %s\n",name);*/
130 for (elem=sec->items;elem!=NULL;elem=ms_list_next(elem)){
131 item=(LpItem*)elem->data;
132 if (strcmp(item->key,name)==0) {
133 /*printf("Item %s found\n",name);*/
140 void lp_config_parse(LpConfig *lpconfig, FILE *file){
141 char tmp[MAX_LEN]= {'\0'};
144 if (file==NULL) return;
146 while(fgets(tmp,MAX_LEN,file)!=NULL){
147 tmp[sizeof(tmp) -1] = '\0';
149 pos1=strchr(tmp,'[');
150 if (pos1!=NULL && is_first_char(tmp,pos1) ){
151 pos2=strchr(pos1,']');
154 char secname[MAX_LEN];
158 nbs = sscanf(pos1+1,"%s",secname);
160 if (strlen(secname)>0){
161 cur=lp_config_find_section (lpconfig,secname);
163 cur=lp_section_new(secname);
164 lp_config_add_section(lpconfig,cur);
168 ms_warning("parse error!");
172 pos1=strchr(tmp,'=');
178 if (sscanf(tmp,"%s",key)>0){
181 pos2=strchr(pos1,'\r');
183 pos2=strchr(pos1,'\n');
184 if (pos2==NULL) pos2=pos1+strlen(pos1);
186 *pos2='\0'; /*replace the '\n' */
188 /* remove ending white spaces */
189 for (; pos2>pos1 && pos2[-1]==' ';pos2--) pos2[-1]='\0';
192 /* found a pair key,value */
195 LpItem *item=lp_section_find_item(cur,key);
197 lp_section_add_item(cur,lp_item_new(key,pos1));
199 ms_free(item->value);
200 item->value=strdup(pos1);
202 /*ms_message("Found %s=%s",key,pos1);*/
204 ms_warning("found key,item but no sections");
213 LpConfig * lp_config_new(const char *filename){
214 return lp_config_new_with_factory(filename, NULL);
217 LpConfig *lp_config_new_with_factory(const char *config_filename, const char *factory_config_filename) {
218 LpConfig *lpconfig=lp_new0(LpConfig,1);
219 if (config_filename!=NULL){
220 ms_message("Using (r/w) config information from %s", config_filename);
221 lpconfig->filename=ortp_strdup(config_filename);
222 lpconfig->file=fopen(config_filename,"r+");
223 if (lpconfig->file!=NULL){
224 struct stat fileStat;
225 lp_config_parse(lpconfig,lpconfig->file);
226 fclose(lpconfig->file);
227 #if !defined(_WIN32_WCE)
228 if ((stat(config_filename,&fileStat) == 0) && (S_ISREG(fileStat.st_mode))) {
229 /* make existing configuration files non-group/world-accessible */
230 if (chmod(config_filename, S_IRUSR | S_IWUSR) == -1) {
231 ms_warning("unable to correct permissions on "
232 "configuration file: %s", strerror(errno));
235 #endif /*_WIN32_WCE*/
237 lpconfig->modified=0;
240 if (factory_config_filename != NULL) {
241 lp_config_read_file(lpconfig, factory_config_filename);
246 int lp_config_read_file(LpConfig *lpconfig, const char *filename){
247 FILE* f=fopen(filename,"r");
249 ms_message("Reading config information from %s", filename);
250 lp_config_parse(lpconfig,f);
254 ms_warning("Fail to open file %s",filename);
258 void lp_item_set_value(LpItem *item, const char *value){
260 item->value=ortp_strdup(value);
264 void lp_config_destroy(LpConfig *lpconfig){
265 if (lpconfig->filename!=NULL) free(lpconfig->filename);
266 ms_list_for_each(lpconfig->sections,(void (*)(void*))lp_section_destroy);
267 ms_list_free(lpconfig->sections);
271 void lp_section_remove_item(LpSection *sec, LpItem *item){
272 sec->items=ms_list_remove(sec->items,(void *)item);
273 lp_item_destroy(item);
276 const char *lp_config_get_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_string){
279 sec=lp_config_find_section(lpconfig,section);
281 item=lp_section_find_item(sec,key);
282 if (item!=NULL) return item->value;
284 return default_string;
287 bool_t lp_config_get_range(const LpConfig *lpconfig, const char *section, const char *key, int *min, int *max, int default_min, int default_max) {
288 const char *str = lp_config_get_string(lpconfig, section, key, NULL);
290 char *minusptr = strchr(str, '-');
291 if ((minusptr == NULL) || (minusptr == str)) {
297 *max = atoi(minusptr + 1);
306 int lp_config_get_int(const LpConfig *lpconfig,const char *section, const char *key, int default_value){
307 const char *str=lp_config_get_string(lpconfig,section,key,NULL);
310 if (strstr(str,"0x")==str){
311 sscanf(str,"%x",&ret);
315 else return default_value;
318 int64_t lp_config_get_int64(const LpConfig *lpconfig,const char *section, const char *key, int64_t default_value){
319 const char *str=lp_config_get_string(lpconfig,section,key,NULL);
322 return (int64_t)_atoi64(str);
327 else return default_value;
330 float lp_config_get_float(const LpConfig *lpconfig,const char *section, const char *key, float default_value){
331 const char *str=lp_config_get_string(lpconfig,section,key,NULL);
332 float ret=default_value;
333 if (str==NULL) return default_value;
334 sscanf(str,"%f",&ret);
338 void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value){
340 LpSection *sec=lp_config_find_section(lpconfig,section);
342 item=lp_section_find_item(sec,key);
345 lp_item_set_value(item,value);
346 else lp_section_remove_item(sec,item);
349 lp_section_add_item(sec,lp_item_new(key,value));
351 }else if (value!=NULL){
352 sec=lp_section_new(section);
353 lp_config_add_section(lpconfig,sec);
354 lp_section_add_item(sec,lp_item_new(key,value));
356 lpconfig->modified++;
359 void lp_config_set_range(LpConfig *lpconfig, const char *section, const char *key, int min_value, int max_value) {
361 snprintf(tmp, sizeof(tmp), "%i-%i", min_value, max_value);
362 lp_config_set_string(lpconfig, section, key, tmp);
365 void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value){
367 snprintf(tmp,sizeof(tmp),"%i",value);
368 lp_config_set_string(lpconfig,section,key,tmp);
371 void lp_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value){
373 snprintf(tmp,sizeof(tmp),"0x%x",value);
374 lp_config_set_string(lpconfig,section,key,tmp);
377 void lp_config_set_int64(LpConfig *lpconfig,const char *section, const char *key, int64_t value){
379 snprintf(tmp,sizeof(tmp),"%lli",(long long)value);
380 lp_config_set_string(lpconfig,section,key,tmp);
384 void lp_config_set_float(LpConfig *lpconfig,const char *section, const char *key, float value){
386 snprintf(tmp,sizeof(tmp),"%f",value);
387 lp_config_set_string(lpconfig,section,key,tmp);
390 void lp_item_write(LpItem *item, FILE *file){
391 fprintf(file,"%s=%s\n",item->key,item->value);
394 void lp_section_write(LpSection *sec, FILE *file){
395 fprintf(file,"[%s]\n",sec->name);
396 ms_list_for_each2(sec->items,(void (*)(void*, void*))lp_item_write,(void *)file);
400 int lp_config_sync(LpConfig *lpconfig){
402 if (lpconfig->filename==NULL) return -1;
403 if (lpconfig->readonly) return 0;
405 /* don't create group/world-accessible files */
406 (void) umask(S_IRWXG | S_IRWXO);
408 file=fopen(lpconfig->filename,"w");
410 ms_warning("Could not write %s ! Maybe it is read-only. Configuration will not be saved.",lpconfig->filename);
411 lpconfig->readonly=1;
414 ms_list_for_each2(lpconfig->sections,(void (*)(void *,void*))lp_section_write,(void *)file);
416 lpconfig->modified=0;
420 int lp_config_has_section(const LpConfig *lpconfig, const char *section){
421 if (lp_config_find_section(lpconfig,section)!=NULL) return 1;
425 void lp_config_for_each_section(const LpConfig *lpconfig, void (*callback)(const char *section, void *ctx), void *ctx) {
428 for (elem=lpconfig->sections;elem!=NULL;elem=ms_list_next(elem)){
429 sec=(LpSection*)elem->data;
430 callback(sec->name, ctx);
434 void lp_config_for_each_entry(const LpConfig *lpconfig, const char *section, void (*callback)(const char *entry, void *ctx), void *ctx) {
437 LpSection *sec=lp_config_find_section(lpconfig,section);
439 for (elem=sec->items;elem!=NULL;elem=ms_list_next(elem)){
440 item=(LpItem*)elem->data;
441 callback(item->key, ctx);
446 void lp_config_clean_section(LpConfig *lpconfig, const char *section){
447 LpSection *sec=lp_config_find_section(lpconfig,section);
449 lp_config_remove_section(lpconfig,sec);
451 lpconfig->modified++;
454 int lp_config_needs_commit(const LpConfig *lpconfig){
455 return lpconfig->modified>0;