]> sjero.net Git - linphone/blob - coreapi/lpconfig.c
Add the linphone_core_new_with_config() function to instantiate a LinphoneCore given...
[linphone] / coreapi / lpconfig.c
1 /***************************************************************************
2  *            lpconfig.c
3  *
4  *  Thu Mar 10 11:13:44 2005
5  *  Copyright  2005  Simon Morlat
6  *  Email simon.morlat@linphone.org
7  ****************************************************************************/
8
9 /*
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.
14  *
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.
19  *
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.
23  */
24
25 #define MAX_LEN 16384
26
27 #include "linphonecore.h"
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <assert.h>
33 #if !defined(_WIN32_WCE)
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #endif /*_WIN32_WCE*/
38
39
40
41 #define lp_new0(type,n) (type*)calloc(sizeof(type),n)
42
43 #include "lpconfig.h"
44
45
46 typedef struct _LpItem{
47         char *key;
48         char *value;
49 } LpItem;
50
51 typedef struct _LpSection{
52         char *name;
53         MSList *items;
54 } LpSection;
55
56 struct _LpConfig{
57         FILE *file;
58         char *filename;
59         MSList *sections;
60         int modified;
61         int readonly;
62 };
63
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);
68         return item;
69 }
70
71 LpSection *lp_section_new(const char *name){
72         LpSection *sec=lp_new0(LpSection,1);
73         sec->name=ortp_strdup(name);
74         return sec;
75 }
76
77 void lp_item_destroy(void *pitem){
78         LpItem *item=(LpItem*)pitem;
79         free(item->key);
80         free(item->value);
81         free(item);
82 }
83
84 void lp_section_destroy(LpSection *sec){
85         free(sec->name);
86         ms_list_for_each(sec->items,lp_item_destroy);
87         ms_list_free(sec->items);
88         free(sec);
89 }
90
91 void lp_section_add_item(LpSection *sec,LpItem *item){
92         sec->items=ms_list_append(sec->items,(void *)item);
93 }
94
95 void lp_config_add_section(LpConfig *lpconfig, LpSection *section){
96         lpconfig->sections=ms_list_append(lpconfig->sections,(void *)section);
97 }
98
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);
102 }
103
104 static bool_t is_first_char(const char *start, const char *pos){
105         const char *p;
106         for(p=start;p<pos;p++){
107                 if (*p!=' ') return FALSE;
108         }
109         return TRUE;
110 }
111
112 LpSection *lp_config_find_section(const LpConfig *lpconfig, const char *name){
113         LpSection *sec;
114         MSList *elem;
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);*/
120                         return sec;
121                 }
122         }
123         return NULL;
124 }
125
126 LpItem *lp_section_find_item(const LpSection *sec, const char *name){
127         MSList *elem;
128         LpItem *item;
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);*/
134                         return item;
135                 }
136         }
137         return NULL;
138 }
139
140 void lp_config_parse(LpConfig *lpconfig, FILE *file){
141         char tmp[MAX_LEN]= {'\0'};
142         LpSection *cur=NULL;
143
144         if (file==NULL) return;
145
146         while(fgets(tmp,MAX_LEN,file)!=NULL){
147                 tmp[sizeof(tmp) -1] = '\0';
148                 char *pos1,*pos2;
149                 pos1=strchr(tmp,'[');
150                 if (pos1!=NULL && is_first_char(tmp,pos1) ){
151                         pos2=strchr(pos1,']');
152                         if (pos2!=NULL){
153                                 int nbs;
154                                 char secname[MAX_LEN];
155                                 secname[0]='\0';
156                                 /* found section */
157                                 *pos2='\0';
158                                 nbs = sscanf(pos1+1,"%s",secname);
159                                 if (nbs == 1 ){
160                                         if (strlen(secname)>0){
161                                                 cur=lp_config_find_section (lpconfig,secname);
162                                                 if (cur==NULL){
163                                                         cur=lp_section_new(secname);
164                                                         lp_config_add_section(lpconfig,cur);
165                                                 }
166                                         }
167                                 }else{
168                                         ms_warning("parse error!");
169                                 }
170                         }
171                 }else {
172                         pos1=strchr(tmp,'=');
173                         if (pos1!=NULL){
174                                 char key[MAX_LEN];
175                                 key[0]='\0';
176
177                                 *pos1='\0';
178                                 if (sscanf(tmp,"%s",key)>0){
179
180                                         pos1++;
181                                         pos2=strchr(pos1,'\r');
182                                         if (pos2==NULL)
183                                                 pos2=strchr(pos1,'\n');
184                                         if (pos2==NULL) pos2=pos1+strlen(pos1);
185                                         else {
186                                                 *pos2='\0'; /*replace the '\n' */
187                                         }
188                                         /* remove ending white spaces */
189                                         for (; pos2>pos1 && pos2[-1]==' ';pos2--) pos2[-1]='\0';
190
191                                         if (pos2-pos1>=0){
192                                                 /* found a pair key,value */
193                                                 
194                                                 if (cur!=NULL){
195                                                         LpItem *item=lp_section_find_item(cur,key);
196                                                         if (item==NULL){
197                                                                 lp_section_add_item(cur,lp_item_new(key,pos1));
198                                                         }else{
199                                                                 ms_free(item->value);
200                                                                 item->value=strdup(pos1);
201                                                         }
202                                                         /*ms_message("Found %s=%s",key,pos1);*/
203                                                 }else{
204                                                         ms_warning("found key,item but no sections");
205                                                 }
206                                         }
207                                 }
208                         }
209                 }
210         }
211 }
212
213 LpConfig * lp_config_new(const char *filename){
214         return lp_config_new_with_factory(filename, NULL);
215 }
216
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));
233                                 }
234                         }
235 #endif /*_WIN32_WCE*/
236                         lpconfig->file=NULL;
237                         lpconfig->modified=0;
238                 }
239         }
240         if (factory_config_filename != NULL) {
241                 lp_config_read_file(lpconfig, factory_config_filename);
242         }
243         return lpconfig;
244 }
245
246 int lp_config_read_file(LpConfig *lpconfig, const char *filename){
247         FILE* f=fopen(filename,"r");
248         if (f!=NULL){
249                 ms_message("Reading config information from %s", filename);
250                 lp_config_parse(lpconfig,f);
251                 fclose(f);
252                 return 0;
253         }
254         ms_warning("Fail to open file %s",filename);
255         return -1;
256 }
257
258 void lp_item_set_value(LpItem *item, const char *value){
259         free(item->value);
260         item->value=ortp_strdup(value);
261 }
262
263
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);
268         free(lpconfig);
269 }
270
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);
274 }
275
276 const char *lp_config_get_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_string){
277         LpSection *sec;
278         LpItem *item;
279         sec=lp_config_find_section(lpconfig,section);
280         if (sec!=NULL){
281                 item=lp_section_find_item(sec,key);
282                 if (item!=NULL) return item->value;
283         }
284         return default_string;
285 }
286
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);
289         if (str != NULL) {
290                 char *minusptr = strchr(str, '-');
291                 if ((minusptr == NULL) || (minusptr == str)) {
292                         *min = default_min;
293                         *max = default_max;
294                         return FALSE;
295                 }
296                 *min = atoi(str);
297                 *max = atoi(minusptr + 1);
298                 return TRUE;
299         } else {
300                 *min = default_min;
301                 *max = default_max;
302                 return TRUE;
303         }
304 }
305
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);
308         if (str!=NULL) {
309                 int ret=0;
310                 if (strstr(str,"0x")==str){
311                         sscanf(str,"%x",&ret);
312                 }else ret=atoi(str);
313                 return ret;
314         }
315         else return default_value;
316 }
317
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);
320         if (str!=NULL) {
321 #ifdef WIN32
322                 return (int64_t)_atoi64(str);
323 #else
324                 return atoll(str);
325 #endif
326         }
327         else return default_value;
328 }
329
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);
335         return ret;
336 }
337
338 void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value){
339         LpItem *item;
340         LpSection *sec=lp_config_find_section(lpconfig,section);
341         if (sec!=NULL){
342                 item=lp_section_find_item(sec,key);
343                 if (item!=NULL){
344                         if (value!=NULL)
345                                 lp_item_set_value(item,value);
346                         else lp_section_remove_item(sec,item);
347                 }else{
348                         if (value!=NULL)
349                                 lp_section_add_item(sec,lp_item_new(key,value));
350                 }
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));
355         }
356         lpconfig->modified++;
357 }
358
359 void lp_config_set_range(LpConfig *lpconfig, const char *section, const char *key, int min_value, int max_value) {
360         char tmp[30];
361         snprintf(tmp, sizeof(tmp), "%i-%i", min_value, max_value);
362         lp_config_set_string(lpconfig, section, key, tmp);
363 }
364
365 void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value){
366         char tmp[30];
367         snprintf(tmp,sizeof(tmp),"%i",value);
368         lp_config_set_string(lpconfig,section,key,tmp);
369 }
370
371 void lp_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value){
372         char tmp[30];
373         snprintf(tmp,sizeof(tmp),"0x%x",value);
374         lp_config_set_string(lpconfig,section,key,tmp);
375 }
376
377 void lp_config_set_int64(LpConfig *lpconfig,const char *section, const char *key, int64_t value){
378         char tmp[30];
379         snprintf(tmp,sizeof(tmp),"%lli",(long long)value);
380         lp_config_set_string(lpconfig,section,key,tmp);
381 }
382
383
384 void lp_config_set_float(LpConfig *lpconfig,const char *section, const char *key, float value){
385         char tmp[30];
386         snprintf(tmp,sizeof(tmp),"%f",value);
387         lp_config_set_string(lpconfig,section,key,tmp);
388 }
389
390 void lp_item_write(LpItem *item, FILE *file){
391         fprintf(file,"%s=%s\n",item->key,item->value);
392 }
393
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);
397         fprintf(file,"\n");
398 }
399
400 int lp_config_sync(LpConfig *lpconfig){
401         FILE *file;
402         if (lpconfig->filename==NULL) return -1;
403         if (lpconfig->readonly) return 0;
404 #ifndef WIN32
405         /* don't create group/world-accessible files */
406         (void) umask(S_IRWXG | S_IRWXO);
407 #endif
408         file=fopen(lpconfig->filename,"w");
409         if (file==NULL){
410                 ms_warning("Could not write %s ! Maybe it is read-only. Configuration will not be saved.",lpconfig->filename);
411                 lpconfig->readonly=1;
412                 return -1;
413         }
414         ms_list_for_each2(lpconfig->sections,(void (*)(void *,void*))lp_section_write,(void *)file);
415         fclose(file);
416         lpconfig->modified=0;
417         return 0;
418 }
419
420 int lp_config_has_section(const LpConfig *lpconfig, const char *section){
421         if (lp_config_find_section(lpconfig,section)!=NULL) return 1;
422         return 0;
423 }
424
425 void lp_config_for_each_section(const LpConfig *lpconfig, void (*callback)(const char *section, void *ctx), void *ctx) {
426         LpSection *sec;
427         MSList *elem;
428         for (elem=lpconfig->sections;elem!=NULL;elem=ms_list_next(elem)){
429                 sec=(LpSection*)elem->data;
430                 callback(sec->name, ctx);
431         }
432 }
433
434 void lp_config_for_each_entry(const LpConfig *lpconfig, const char *section, void (*callback)(const char *entry, void *ctx), void *ctx) {
435         LpItem *item;
436         MSList *elem;
437         LpSection *sec=lp_config_find_section(lpconfig,section);
438         if (sec!=NULL){
439                 for (elem=sec->items;elem!=NULL;elem=ms_list_next(elem)){
440                         item=(LpItem*)elem->data;
441                         callback(item->key, ctx);
442                 }
443         }
444 }
445
446 void lp_config_clean_section(LpConfig *lpconfig, const char *section){
447         LpSection *sec=lp_config_find_section(lpconfig,section);
448         if (sec!=NULL){
449                 lp_config_remove_section(lpconfig,sec);
450         }
451         lpconfig->modified++;
452 }
453
454 int lp_config_needs_commit(const LpConfig *lpconfig){
455         return lpconfig->modified>0;
456 }