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 "private.h"
28 #include "bctoolbox/vfs.h"
29 #include "belle-sip/object.h"
30 #include "xml2lpc.h"
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <assert.h>
36 #if !defined(_WIN32_WCE)
37 #include <errno.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #if _MSC_VER
41 #include <io.h>
42 #endif
43 #endif /*_WIN32_WCE*/
44
45 #ifdef _MSC_VER
46 #ifdef LINPHONE_WINDOWS_DESKTOP
47 #include <Shlwapi.h>
48 #else
49 #include <stdlib.h>
50 #endif
51 #else
52 #include <libgen.h>
53 #endif
54
55 #ifdef _WIN32
56 #define RENAME_REQUIRES_NONEXISTENT_NEW_PATH 1
57 #endif
58
59 #define lp_new0(type,n) (type*)calloc(sizeof(type),n)
60
61 #include "linphone/lpconfig.h"
62 #include "lpc2xml.h"
63
64 typedef struct _LpItem{
65 char *key;
66 char *value;
67 int is_comment;
68 bool_t overwrite; // If set to true, will add overwrite=true when converted to xml
69 bool_t skip; // If set to true, won't be dumped when converted to xml
70 } LpItem;
71
72 typedef struct _LpSectionParam{
73 char *key;
74 char *value;
75 } LpSectionParam;
76
77 typedef struct _LpSection{
78 char *name;
79 bctbx_list_t *items;
80 bctbx_list_t *params;
81 bool_t overwrite; // If set to true, will add overwrite=true to all items of this section when converted to xml
82 bool_t skip; // If set to true, won't be dumped when converted to xml
83 } LpSection;
84
85 struct _LpConfig{
86 belle_sip_object_t base;
87 bctbx_vfs_file_t* pFile;
88 char *filename;
89 char *tmpfilename;
90 bctbx_list_t *sections;
91 bool_t modified;
92 bool_t readonly;
93 bctbx_vfs_t* g_bctbx_vfs;
94 };
95
96 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneConfig);
97 BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneConfig);
98
99
lp_realpath(const char * file,char * name)100 char* lp_realpath(const char* file, char* name) {
101 #if defined(_WIN32) || defined(__QNX__) || defined(__ANDROID__)
102 return ms_strdup(file);
103 #else
104 char * output = realpath(file, name);
105 char * msoutput = ms_strdup(output);
106 free(output);
107 return msoutput;
108 #endif
109 }
110
lp_item_new(const char * key,const char * value)111 LpItem * lp_item_new(const char *key, const char *value){
112 LpItem *item=lp_new0(LpItem,1);
113 item->key=ortp_strdup(key);
114 item->value=ortp_strdup(value);
115 return item;
116 }
117
lp_comment_new(const char * comment)118 LpItem * lp_comment_new(const char *comment){
119 LpItem *item=lp_new0(LpItem,1);
120 char* pos = NULL;
121 item->value=ortp_strdup(comment);
122
123 pos=strchr(item->value,'\r');
124 if (pos==NULL)
125 pos=strchr(item->value,'\n');
126
127 if(pos) {
128 *pos='\0'; /*replace the '\n' */
129 }
130 item->is_comment=TRUE;
131 return item;
132 }
133
lp_section_param_new(const char * key,const char * value)134 LpSectionParam *lp_section_param_new(const char *key, const char *value){
135 LpSectionParam *param = lp_new0(LpSectionParam, 1);
136 param->key = ortp_strdup(key);
137 param->value = ortp_strdup(value);
138 return param;
139 }
140
lp_section_new(const char * name)141 LpSection *lp_section_new(const char *name){
142 LpSection *sec=lp_new0(LpSection,1);
143 sec->name=ortp_strdup(name);
144 return sec;
145 }
146
lp_item_destroy(void * pitem)147 void lp_item_destroy(void *pitem){
148 LpItem *item=(LpItem*)pitem;
149 if (item->key) ortp_free(item->key);
150 ortp_free(item->value);
151 free(item);
152 }
153
lp_section_param_destroy(void * section_param)154 void lp_section_param_destroy(void *section_param){
155 LpSectionParam *param = (LpSectionParam*)section_param;
156 ortp_free(param->key);
157 ortp_free(param->value);
158 free(param);
159 }
160
lp_section_destroy(LpSection * sec)161 void lp_section_destroy(LpSection *sec){
162 ortp_free(sec->name);
163 bctbx_list_for_each(sec->items,lp_item_destroy);
164 bctbx_list_for_each(sec->params,lp_section_param_destroy);
165 bctbx_list_free(sec->items);
166 free(sec);
167 }
168
lp_section_add_item(LpSection * sec,LpItem * item)169 void lp_section_add_item(LpSection *sec,LpItem *item){
170 sec->items=bctbx_list_append(sec->items,(void *)item);
171 }
172
linphone_config_add_section(LpConfig * lpconfig,LpSection * section)173 void linphone_config_add_section(LpConfig *lpconfig, LpSection *section){
174 lpconfig->sections=bctbx_list_append(lpconfig->sections,(void *)section);
175 }
176
linphone_config_add_section_param(LpSection * section,LpSectionParam * param)177 void linphone_config_add_section_param(LpSection *section, LpSectionParam *param){
178 section->params = bctbx_list_append(section->params, (void *)param);
179 }
180
linphone_config_remove_section(LpConfig * lpconfig,LpSection * section)181 void linphone_config_remove_section(LpConfig *lpconfig, LpSection *section){
182 lpconfig->sections=bctbx_list_remove(lpconfig->sections,(void *)section);
183 lp_section_destroy(section);
184 }
185
lp_section_remove_item(LpSection * sec,LpItem * item)186 void lp_section_remove_item(LpSection *sec, LpItem *item){
187 sec->items=bctbx_list_remove(sec->items,(void *)item);
188 lp_item_destroy(item);
189 }
190
is_first_char(const char * start,const char * pos)191 static bool_t is_first_char(const char *start, const char *pos){
192 const char *p;
193 for(p=start;p<pos;p++){
194 if (*p!=' ') return FALSE;
195 }
196 return TRUE;
197 }
198
is_a_comment(const char * str)199 static int is_a_comment(const char *str){
200 while (*str==' '){
201 str++;
202 }
203 if (*str=='#') return 1;
204 return 0;
205 }
206
linphone_config_find_section(const LpConfig * lpconfig,const char * name)207 LpSection *linphone_config_find_section(const LpConfig *lpconfig, const char *name){
208 LpSection *sec;
209 bctbx_list_t *elem;
210 /*printf("Looking for section %s\n",name);*/
211 for (elem=lpconfig->sections;elem!=NULL;elem=bctbx_list_next(elem)){
212 sec=(LpSection*)elem->data;
213 if (strcmp(sec->name,name)==0){
214 /*printf("Section %s found\n",name);*/
215 return sec;
216 }
217 }
218 return NULL;
219 }
220
lp_section_find_param(const LpSection * sec,const char * key)221 LpSectionParam *lp_section_find_param(const LpSection *sec, const char *key){
222 bctbx_list_t *elem;
223 LpSectionParam *param;
224 for (elem = sec->params; elem != NULL; elem = bctbx_list_next(elem)){
225 param = (LpSectionParam*)elem->data;
226 if (strcmp(param->key, key) == 0) {
227 return param;
228 }
229 }
230 return NULL;
231 }
232
lp_section_find_comment(const LpSection * sec,const char * comment)233 LpItem *lp_section_find_comment(const LpSection *sec, const char *comment){
234 bctbx_list_t *elem;
235 LpItem *item;
236 /*printf("Looking for item %s\n",name);*/
237 for (elem=sec->items;elem!=NULL;elem=bctbx_list_next(elem)){
238 item=(LpItem*)elem->data;
239 if (item->is_comment && strcmp(item->value,comment)==0) {
240 /*printf("Item %s found\n",name);*/
241 return item;
242 }
243 }
244 return NULL;
245 }
246
lp_section_find_item(const LpSection * sec,const char * name)247 LpItem *lp_section_find_item(const LpSection *sec, const char *name){
248 bctbx_list_t *elem;
249 LpItem *item;
250 /*printf("Looking for item %s\n",name);*/
251 for (elem=sec->items;elem!=NULL;elem=bctbx_list_next(elem)){
252 item=(LpItem*)elem->data;
253 if (!item->is_comment && strcmp(item->key,name)==0) {
254 /*printf("Item %s found\n",name);*/
255 return item;
256 }
257 }
258 return NULL;
259 }
260
linphone_config_parse_line(LpConfig * lpconfig,const char * line,LpSection * cur)261 static LpSection* linphone_config_parse_line(LpConfig* lpconfig, const char* line, LpSection* cur) {
262 LpSectionParam *params = NULL;
263 char *pos1,*pos2;
264 int nbs;
265 size_t size=strlen(line)+1;
266 char *secname=ms_malloc(size);
267 char *key=ms_malloc(size);
268 char *value=ms_malloc(size);
269 LpItem *item;
270
271 pos1=strchr(line,'[');
272 if (pos1!=NULL && is_first_char(line,pos1) ){
273 pos2=strchr(pos1,']');
274 if (pos2!=NULL){
275 secname[0]='\0';
276 /* found section */
277 *pos2='\0';
278 nbs = sscanf(pos1+1, "%s", secname);
279 if (nbs >= 1) {
280 if (strlen(secname) > 0) {
281 cur = linphone_config_find_section (lpconfig,secname);
282 if (cur == NULL) {
283 cur = lp_section_new(secname);
284 linphone_config_add_section(lpconfig, cur);
285 }
286
287 if (pos2 > pos1 + 1 + strlen(secname)) {
288 /* found at least one section param */
289 pos2 = pos1 + 1 + strlen(secname) + 1; // Remove the white space after the secname
290 pos1 = strchr(pos2, '=');
291 while (pos1 != NULL) {
292 /* for each section param */
293 key[0] = '\0';
294 value[0] = '\0';
295 *pos1 = ' ';
296 if (sscanf(pos2, "%s %s", key, value) == 2) {
297 params = lp_section_param_new(key, value);
298 linphone_config_add_section_param(cur, params);
299
300 pos2 += strlen(key) + strlen(value) + 2; // Remove the = sign + the white space after each param
301 pos1 = strchr(pos2, '=');
302 } else {
303 ms_warning("parse section params error !");
304 pos1 = NULL;
305 }
306 }
307 }
308 }
309 } else {
310 ms_warning("parse error!");
311 }
312 }
313 }else {
314 if (is_a_comment(line)){
315 if (cur){
316 LpItem *comment=lp_comment_new(line);
317 item=lp_section_find_comment(cur,comment->value);
318 if (item!=NULL) {
319 lp_section_remove_item(cur, item);
320 }
321 lp_section_add_item(cur,comment);
322 }
323 }else{
324 pos1=strchr(line,'=');
325 if (pos1!=NULL){
326 key[0]='\0';
327
328 *pos1='\0';
329 if (sscanf(line,"%s",key)>0){
330
331 pos1++;
332 pos2=strchr(pos1,'\r');
333 if (pos2==NULL)
334 pos2=strchr(pos1,'\n');
335 if (pos2==NULL) pos2=pos1+strlen(pos1);
336 else {
337 *pos2='\0'; /*replace the '\n' */
338 }
339 /* remove ending white spaces */
340 for (; pos2>pos1 && pos2[-1]==' ';pos2--) pos2[-1]='\0';
341
342 if (pos2-pos1>0){
343 /* found a pair key,value */
344
345 if (cur!=NULL){
346 item=lp_section_find_item(cur,key);
347 if (item==NULL){
348 lp_section_add_item(cur,lp_item_new(key,pos1));
349 }else{
350 ortp_free(item->value);
351 item->value=ortp_strdup(pos1);
352 }
353 /*ms_message("Found %s=%s",key,pos1);*/
354 }else{
355 ms_warning("found key,item but no sections");
356 }
357 }
358 }
359 }
360 }
361 }
362 ms_free(key);
363 ms_free(value);
364 ms_free(secname);
365 return cur;
366 }
367
linphone_config_parse(LpConfig * lpconfig,bctbx_vfs_file_t * pFile)368 void linphone_config_parse(LpConfig *lpconfig, bctbx_vfs_file_t* pFile){
369 char tmp[MAX_LEN]= {'\0'};
370 LpSection* current_section = NULL;
371 int size =0;
372 if (pFile==NULL) return;
373 while(( size = bctbx_file_get_nxtline(pFile, tmp, MAX_LEN)) > 0){
374 //tmp[size] = '\0';
375 current_section = linphone_config_parse_line(lpconfig, tmp, current_section);
376 }
377 }
378
linphone_config_new(const char * filename)379 LpConfig * linphone_config_new(const char *filename){
380 return linphone_config_new_with_factory(filename, NULL);
381 }
382
_linphone_config_init_from_buffer(LinphoneConfig * conf,const char * buffer)383 static void _linphone_config_init_from_buffer(LinphoneConfig *conf, const char *buffer) {
384 LpSection* current_section = NULL;
385
386 char* ptr = ms_strdup(buffer);
387 char* strtok_storage = NULL;
388 char* line = strtok_r(ptr, "\n", &strtok_storage);
389
390 while( line != NULL ){
391 current_section = linphone_config_parse_line(conf,line,current_section);
392 line = strtok_r(NULL, "\n", &strtok_storage);
393 }
394
395 ms_free(ptr);
396 }
397
linphone_config_new_from_buffer(const char * buffer)398 LpConfig * linphone_config_new_from_buffer(const char *buffer){
399 LpConfig* conf = belle_sip_object_new(LinphoneConfig);
400 _linphone_config_init_from_buffer(conf, buffer);
401 return conf;
402 }
403
_linphone_config_init_from_files(LinphoneConfig * lpconfig,const char * config_filename,const char * factory_config_filename)404 static int _linphone_config_init_from_files(LinphoneConfig *lpconfig, const char *config_filename, const char *factory_config_filename) {
405 lpconfig->g_bctbx_vfs = bctbx_vfs_get_default();
406
407 if (config_filename!=NULL){
408 if(ortp_file_exist(config_filename) == 0) {
409 lpconfig->filename=lp_realpath(config_filename, NULL);
410 if(lpconfig->filename == NULL) {
411 ms_error("Could not find the real path of %s: %s", config_filename, strerror(errno));
412 goto fail;
413 }
414 } else {
415 lpconfig->filename = ms_strdup(config_filename);
416 }
417 lpconfig->tmpfilename=ortp_strdup_printf("%s.tmp",lpconfig->filename);
418 ms_message("Using (r/w) config information from %s", lpconfig->filename);
419
420 #if !defined(_WIN32)
421 {
422 struct stat fileStat;
423 if ((stat(lpconfig->filename,&fileStat) == 0) && (S_ISREG(fileStat.st_mode))) {
424 /* make existing configuration files non-group/world-accessible */
425 if (chmod(lpconfig->filename, S_IRUSR | S_IWUSR) == -1) {
426 ms_warning("unable to correct permissions on "
427 "configuration file: %s", strerror(errno));
428 }
429 }
430 }
431 #endif /*_WIN32*/
432
433 /*open with r+ to check if we can write on it later*/
434 lpconfig->pFile = bctbx_file_open(lpconfig->g_bctbx_vfs,lpconfig->filename, "r+");
435 #ifdef RENAME_REQUIRES_NONEXISTENT_NEW_PATH
436 if (lpconfig->pFile == NULL){
437 lpconfig->pFile = bctbx_file_open(lpconfig->g_bctbx_vfs,lpconfig->tmpfilename, "r+");
438 if (lpconfig->pFile == NULL){
439 ms_warning("Could not open %s but %s works, app may have crashed during last sync.",lpconfig->filename,lpconfig->tmpfilename);
440 }
441 }
442 #endif
443 if (lpconfig->pFile != NULL){
444 linphone_config_parse(lpconfig, lpconfig->pFile);
445 bctbx_file_close(lpconfig->pFile);
446 lpconfig->pFile = NULL;
447 lpconfig->modified = FALSE;
448 }
449 }
450 if (factory_config_filename != NULL) {
451 linphone_config_read_file(lpconfig, factory_config_filename);
452 }
453 return 0;
454
455 fail:
456 return -1;
457 }
458
linphone_config_new_with_factory(const char * config_filename,const char * factory_config_filename)459 LpConfig *linphone_config_new_with_factory(const char *config_filename, const char *factory_config_filename) {
460 LpConfig *lpconfig=belle_sip_object_new(LinphoneConfig);
461 if (_linphone_config_init_from_files(lpconfig, config_filename, factory_config_filename) == 0) {
462 return lpconfig;
463 } else {
464 ms_free(lpconfig);
465 return NULL;
466 }
467 }
468
linphone_config_read_file(LpConfig * lpconfig,const char * filename)469 LinphoneStatus linphone_config_read_file(LpConfig *lpconfig, const char *filename){
470 char* path = lp_realpath(filename, NULL);
471 bctbx_vfs_file_t* pFile = bctbx_file_open(lpconfig->g_bctbx_vfs, path, "r");
472 if (pFile != NULL){
473 ms_message("Reading config information from %s", path);
474 linphone_config_parse(lpconfig, pFile);
475 bctbx_file_close(pFile);
476 ms_free(path);
477 return 0;
478 }
479 ms_warning("Fail to open file %s",path);
480 ms_free(path);
481 return -1;
482 }
483
484 static const char *xml_to_lpc_failed = "xml to lpc failed";
485 static const char *invalid_xml = "invalid xml";
486 static const char *empty_xml = "empty provisioning file";
487
_linphone_config_xml_convert(LpConfig * lpc,xml2lpc_context * context,int result)488 static const char* _linphone_config_xml_convert(LpConfig *lpc, xml2lpc_context *context, int result) {
489 const char* error_msg = NULL;
490 if (result == 0) {
491 result = xml2lpc_convert(context, lpc);
492 if (result == 0) {
493 // if the remote provisioning added a proxy config and none was set before, set it
494 if (lp_config_has_section(lpc, "proxy_0") && lp_config_get_int(lpc, "sip", "default_proxy", -1) == -1){
495 lp_config_set_int(lpc, "sip", "default_proxy", 0);
496 }
497 lp_config_sync(lpc);
498 } else {
499 error_msg = xml_to_lpc_failed;
500 }
501 } else {
502 error_msg = invalid_xml;
503 }
504 return error_msg;
505 }
506
linphone_config_load_from_xml_file(LinphoneConfig * lpc,const char * filename)507 const char* linphone_config_load_from_xml_file(LinphoneConfig *lpc, const char *filename) {
508 xml2lpc_context *context = NULL;
509 char* path = lp_realpath(filename, NULL);
510 const char* error_msg = NULL;
511
512 if (path) {
513 context = xml2lpc_context_new(NULL, NULL);
514 error_msg = _linphone_config_xml_convert(lpc, context, xml2lpc_set_xml_file(context, path));
515 }
516 if (context) xml2lpc_context_destroy(context);
517 return error_msg;
518 }
519
xml2lpc_callback(void * ctx,xml2lpc_log_level level,const char * fmt,va_list list)520 static void xml2lpc_callback(void *ctx, xml2lpc_log_level level, const char *fmt, va_list list) {
521 BctbxLogLevel bctbx_level;
522 switch(level) {
523 case XML2LPC_DEBUG: bctbx_level = BCTBX_LOG_DEBUG; break;
524 case XML2LPC_MESSAGE: bctbx_level = BCTBX_LOG_MESSAGE;break;
525 case XML2LPC_WARNING: bctbx_level = BCTBX_LOG_WARNING;break;
526 case XML2LPC_ERROR:
527 default:
528 bctbx_level = BCTBX_LOG_ERROR;break;
529 }
530 bctbx_logv(BCTBX_LOG_DOMAIN, bctbx_level,fmt,list);
531 }
532
_linphone_config_load_from_xml_string(LpConfig * lpc,const char * buffer)533 const char* _linphone_config_load_from_xml_string(LpConfig *lpc, const char *buffer) {
534 xml2lpc_context *context = NULL;
535 const char* error_msg = NULL;
536
537 if (buffer != NULL) {
538 context = xml2lpc_context_new(xml2lpc_callback, NULL);
539 error_msg = _linphone_config_xml_convert(lpc, context, xml2lpc_set_xml_string(context, buffer));
540 }else{
541 error_msg = empty_xml;
542 }
543 if (context) xml2lpc_context_destroy(context);
544 return error_msg;
545 }
546
linphone_config_load_from_xml_string(LpConfig * lpc,const char * buffer)547 LinphoneStatus linphone_config_load_from_xml_string(LpConfig *lpc, const char *buffer) {
548 const char *status;
549 if ((status =_linphone_config_load_from_xml_string(lpc,buffer))) {
550 ms_error("%s",status);
551 return -1;
552 } else
553 return 0;
554 }
555
lp_item_set_value(LpItem * item,const char * value)556 void lp_item_set_value(LpItem *item, const char *value){
557 if (item->value != value) {
558 char *prev_value=item->value;
559 item->value=ortp_strdup(value);
560 ortp_free(prev_value);
561 }
562 }
563
564
_linphone_config_uninit(LpConfig * lpconfig)565 static void _linphone_config_uninit(LpConfig *lpconfig){
566 if (lpconfig->filename!=NULL) ortp_free(lpconfig->filename);
567 if (lpconfig->tmpfilename) ortp_free(lpconfig->tmpfilename);
568 bctbx_list_for_each(lpconfig->sections,(void (*)(void*))lp_section_destroy);
569 bctbx_list_free(lpconfig->sections);
570 }
571
linphone_config_ref(LpConfig * lpconfig)572 LpConfig *linphone_config_ref(LpConfig *lpconfig){
573 return (LinphoneConfig *)belle_sip_object_ref(BELLE_SIP_OBJECT(lpconfig));
574 }
575
linphone_config_unref(LpConfig * lpconfig)576 void linphone_config_unref(LpConfig *lpconfig){
577 belle_sip_object_unref(BELLE_SIP_OBJECT(lpconfig));
578 }
579
linphone_config_destroy(LpConfig * lpconfig)580 void linphone_config_destroy(LpConfig *lpconfig){
581 linphone_config_unref(lpconfig);
582 }
583
linphone_config_get_section_param_string(const LpConfig * lpconfig,const char * section,const char * key,const char * default_value)584 const char *linphone_config_get_section_param_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_value){
585 LpSection *sec;
586 LpSectionParam *param;
587 sec = linphone_config_find_section(lpconfig, section);
588 if (sec != NULL) {
589 param = lp_section_find_param(sec, key);
590 if (param != NULL) return param->value;
591 }
592 return default_value;
593 }
594
linphone_config_get_string(const LpConfig * lpconfig,const char * section,const char * key,const char * default_string)595 const char *linphone_config_get_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_string){
596 LpSection *sec;
597 LpItem *item;
598 sec=linphone_config_find_section(lpconfig,section);
599 if (sec!=NULL){
600 item=lp_section_find_item(sec,key);
601 if (item!=NULL) return item->value;
602 }
603 return default_string;
604 }
605
linphone_config_get_string_list(const LpConfig * lpconfig,const char * section,const char * key,bctbx_list_t * default_list)606 bctbx_list_t * linphone_config_get_string_list(const LpConfig *lpconfig, const char *section, const char *key, bctbx_list_t *default_list) {
607 LpItem *item;
608 LpSection *sec = linphone_config_find_section(lpconfig, section);
609 if (sec != NULL) {
610 item = lp_section_find_item(sec, key);
611 if (item != NULL) {
612 bctbx_list_t *l = NULL;
613 char *str;
614 char *ptr;
615 str = ptr = ms_strdup(item->value);
616 while (ptr != NULL) {
617 char *next = strstr(ptr, ",");
618 if (next != NULL) {
619 *(next++) = '\0';
620 }
621 l = bctbx_list_append(l, ms_strdup(ptr));
622 ptr = next;
623 }
624 ms_free(str);
625 return l;
626 }
627 }
628 return default_list;
629 }
630
linphone_config_get_range(const LpConfig * lpconfig,const char * section,const char * key,int * min,int * max,int default_min,int default_max)631 bool_t linphone_config_get_range(const LpConfig *lpconfig, const char *section, const char *key, int *min, int *max, int default_min, int default_max) {
632 const char *str = linphone_config_get_string(lpconfig, section, key, NULL);
633 if (str != NULL) {
634 char *minusptr = strchr(str, '-');
635 if ((minusptr == NULL) || (minusptr == str)) {
636 *min = default_min;
637 *max = default_max;
638 return FALSE;
639 }
640 *min = atoi(str);
641 *max = atoi(minusptr + 1);
642 return TRUE;
643 } else {
644 *min = default_min;
645 *max = default_max;
646 return TRUE;
647 }
648 }
649
650
linphone_config_get_int(const LpConfig * lpconfig,const char * section,const char * key,int default_value)651 int linphone_config_get_int(const LpConfig *lpconfig,const char *section, const char *key, int default_value){
652 const char *str=linphone_config_get_string(lpconfig,section,key,NULL);
653 if (str!=NULL) {
654 int ret=0;
655
656 if (strstr(str,"0x")==str){
657 sscanf(str,"%x",&ret);
658 }else
659 sscanf(str,"%i",&ret);
660 return ret;
661 }
662 else return default_value;
663 }
664
linphone_config_get_int64(const LpConfig * lpconfig,const char * section,const char * key,int64_t default_value)665 int64_t linphone_config_get_int64(const LpConfig *lpconfig,const char *section, const char *key, int64_t default_value){
666 const char *str=linphone_config_get_string(lpconfig,section,key,NULL);
667 if (str!=NULL) {
668 #ifdef _WIN32
669 return (int64_t)_atoi64(str);
670 #else
671 return atoll(str);
672 #endif
673 }
674 else return default_value;
675 }
676
linphone_config_get_float(const LpConfig * lpconfig,const char * section,const char * key,float default_value)677 float linphone_config_get_float(const LpConfig *lpconfig,const char *section, const char *key, float default_value){
678 const char *str=linphone_config_get_string(lpconfig,section,key,NULL);
679 float ret=default_value;
680 if (str==NULL) return default_value;
681 sscanf(str,"%f",&ret);
682 return ret;
683 }
684
linphone_config_get_overwrite_flag_for_entry(const LpConfig * lpconfig,const char * section,const char * key)685 bool_t linphone_config_get_overwrite_flag_for_entry(const LpConfig *lpconfig, const char *section, const char *key) {
686 LpSection *sec;
687 LpItem *item;
688 sec = linphone_config_find_section(lpconfig, section);
689 if (sec != NULL){
690 item = lp_section_find_item(sec, key);
691 if (item != NULL) return item->overwrite;
692 }
693 return FALSE;
694 }
695
linphone_config_get_overwrite_flag_for_section(const LpConfig * lpconfig,const char * section)696 bool_t linphone_config_get_overwrite_flag_for_section(const LpConfig *lpconfig, const char *section) {
697 LpSection *sec;
698 sec = linphone_config_find_section(lpconfig, section);
699 if (sec != NULL){
700 return sec->overwrite;
701 }
702 return FALSE;
703 }
704
linphone_config_get_skip_flag_for_entry(const LpConfig * lpconfig,const char * section,const char * key)705 bool_t linphone_config_get_skip_flag_for_entry(const LpConfig *lpconfig, const char *section, const char *key) {
706 LpSection *sec;
707 LpItem *item;
708 sec = linphone_config_find_section(lpconfig, section);
709 if (sec != NULL){
710 item = lp_section_find_item(sec, key);
711 if (item != NULL) return item->skip;
712 }
713 return FALSE;
714 }
715
linphone_config_get_skip_flag_for_section(const LpConfig * lpconfig,const char * section)716 bool_t linphone_config_get_skip_flag_for_section(const LpConfig *lpconfig, const char *section) {
717 LpSection *sec;
718 sec = linphone_config_find_section(lpconfig, section);
719 if (sec != NULL){
720 return sec->skip;
721 }
722 return FALSE;
723 }
724
linphone_config_set_string(LpConfig * lpconfig,const char * section,const char * key,const char * value)725 void linphone_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value){
726 LpItem *item;
727 LpSection *sec=linphone_config_find_section(lpconfig,section);
728 if (sec!=NULL){
729 item=lp_section_find_item(sec,key);
730 if (item!=NULL){
731 if ((value != NULL) && (value[0] != '\0')) {
732 if (strcmp(value, item->value) == 0) return;
733 lp_item_set_value(item, value);
734 } else {
735 lp_section_remove_item(sec, item);
736 }
737 }else{
738 if (value!=NULL && value[0] != '\0')
739 lp_section_add_item(sec,lp_item_new(key,value));
740 }
741 }else if (value!=NULL && value[0] != '\0'){
742 sec=lp_section_new(section);
743 linphone_config_add_section(lpconfig,sec);
744 lp_section_add_item(sec,lp_item_new(key,value));
745 }
746 lpconfig->modified = TRUE;
747 }
748
linphone_config_set_string_list(LpConfig * lpconfig,const char * section,const char * key,const bctbx_list_t * value)749 void linphone_config_set_string_list(LpConfig *lpconfig, const char *section, const char *key, const bctbx_list_t *value) {
750 char *strvalue = NULL;
751 char *tmp = NULL;
752 const bctbx_list_t *elem;
753 for (elem = value; elem != NULL; elem = elem->next) {
754 if (strvalue) {
755 tmp = ms_strdup_printf("%s,%s", strvalue, (const char *)elem->data);
756 ms_free(strvalue);
757 strvalue = tmp;
758 }
759 else strvalue = ms_strdup((const char *)elem->data);
760 }
761 linphone_config_set_string(lpconfig, section, key, strvalue);
762 if (strvalue) ms_free(strvalue);
763 }
764
linphone_config_set_range(LpConfig * lpconfig,const char * section,const char * key,int min_value,int max_value)765 void linphone_config_set_range(LpConfig *lpconfig, const char *section, const char *key, int min_value, int max_value) {
766 char tmp[30];
767 snprintf(tmp, sizeof(tmp), "%i-%i", min_value, max_value);
768 linphone_config_set_string(lpconfig, section, key, tmp);
769 }
770
linphone_config_set_int(LpConfig * lpconfig,const char * section,const char * key,int value)771 void linphone_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value){
772 char tmp[30];
773 snprintf(tmp,sizeof(tmp),"%i",value);
774 linphone_config_set_string(lpconfig,section,key,tmp);
775 }
776
linphone_config_set_int_hex(LpConfig * lpconfig,const char * section,const char * key,int value)777 void linphone_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value){
778 char tmp[30];
779 snprintf(tmp,sizeof(tmp),"0x%x",value);
780 linphone_config_set_string(lpconfig,section,key,tmp);
781 }
782
linphone_config_set_int64(LpConfig * lpconfig,const char * section,const char * key,int64_t value)783 void linphone_config_set_int64(LpConfig *lpconfig,const char *section, const char *key, int64_t value){
784 char tmp[30];
785 snprintf(tmp,sizeof(tmp),"%lli",(long long)value);
786 linphone_config_set_string(lpconfig,section,key,tmp);
787 }
788
789
linphone_config_set_float(LpConfig * lpconfig,const char * section,const char * key,float value)790 void linphone_config_set_float(LpConfig *lpconfig,const char *section, const char *key, float value){
791 char tmp[30];
792 snprintf(tmp,sizeof(tmp),"%f",value);
793 linphone_config_set_string(lpconfig,section,key,tmp);
794 }
795
linphone_config_set_overwrite_flag_for_entry(LpConfig * lpconfig,const char * section,const char * key,bool_t value)796 void linphone_config_set_overwrite_flag_for_entry(LpConfig *lpconfig, const char *section, const char *key, bool_t value) {
797 LpSection *sec;
798 LpItem *item;
799 sec = linphone_config_find_section(lpconfig, section);
800 if (sec != NULL) {
801 item = lp_section_find_item(sec, key);
802 if (item != NULL) item->overwrite = value;
803 }
804 }
805
linphone_config_set_overwrite_flag_for_section(LpConfig * lpconfig,const char * section,bool_t value)806 void linphone_config_set_overwrite_flag_for_section(LpConfig *lpconfig, const char *section, bool_t value) {
807 LpSection *sec;
808 sec = linphone_config_find_section(lpconfig, section);
809 if (sec != NULL) {
810 sec->overwrite = value;
811 }
812 }
813
linphone_config_set_skip_flag_for_entry(LpConfig * lpconfig,const char * section,const char * key,bool_t value)814 void linphone_config_set_skip_flag_for_entry(LpConfig *lpconfig, const char *section, const char *key, bool_t value) {
815 LpSection *sec;
816 LpItem *item;
817 sec = linphone_config_find_section(lpconfig, section);
818 if (sec != NULL) {
819 item = lp_section_find_item(sec, key);
820 if (item != NULL) item->skip = value;
821 }
822 }
823
linphone_config_set_skip_flag_for_section(LpConfig * lpconfig,const char * section,bool_t value)824 void linphone_config_set_skip_flag_for_section(LpConfig *lpconfig, const char *section, bool_t value) {
825 LpSection *sec;
826 sec = linphone_config_find_section(lpconfig, section);
827 if (sec != NULL) {
828 sec->skip = value;
829 }
830 }
831
lp_item_write(LpItem * item,LpConfig * lpconfig)832 void lp_item_write(LpItem *item, LpConfig *lpconfig){
833 int ret =-1 ;
834 if (item->is_comment){
835 ret =bctbx_file_fprintf(lpconfig->pFile, 0, "%s\n",item->value);
836
837 }
838 else if (item->value && item->value[0] != '\0' ){
839 ret =bctbx_file_fprintf(lpconfig->pFile, 0, "%s=%s\n",item->key,item->value);
840 }
841
842 else {
843 ms_warning("Not writing item %s to file, it is empty", item->key);
844 }
845 if (ret < 0){
846 ms_error("lp_item_write : not writing item to file" );
847 }
848 }
849
lp_section_param_write(LpSectionParam * param,LpConfig * lpconfig)850 void lp_section_param_write(LpSectionParam *param, LpConfig *lpconfig){
851 if( param->value && param->value[0] != '\0') {
852 bctbx_file_fprintf(lpconfig->pFile, 0, " %s=%s", param->key, param->value);
853
854 } else {
855 ms_warning("Not writing param %s to file, it is empty", param->key);
856 }
857 }
858
lp_section_write(LpSection * sec,LpConfig * lpconfig)859 void lp_section_write(LpSection *sec,LpConfig *lpconfig){
860
861 if (bctbx_file_fprintf(lpconfig->pFile, 0, "[%s",sec->name) < 0) ms_error("lp_section_write : write error on %s", sec->name);
862 bctbx_list_for_each2(sec->params, (void (*)(void*, void*))lp_section_param_write, (void *)lpconfig);
863
864 if (bctbx_file_fprintf(lpconfig->pFile, 0, "]\n")< 0) ms_error("lp_section_write : write error ");
865 bctbx_list_for_each2(sec->items, (void (*)(void*, void*))lp_item_write, (void *)lpconfig);
866
867 if (bctbx_file_fprintf(lpconfig->pFile, 0, "\n")< 0) ms_error("lp_section_write : write error");
868
869 }
870
linphone_config_sync(LpConfig * lpconfig)871 LinphoneStatus linphone_config_sync(LpConfig *lpconfig){
872 bctbx_vfs_file_t *pFile = NULL;
873 if (lpconfig->filename==NULL) return -1;
874 if (lpconfig->readonly) return 0;
875
876 #ifndef _WIN32
877 /* don't create group/world-accessible files */
878 (void) umask(S_IRWXG | S_IRWXO);
879 #endif
880 pFile = bctbx_file_open(lpconfig->g_bctbx_vfs,lpconfig->tmpfilename, "w");
881 lpconfig->pFile = pFile;
882 if (pFile == NULL){
883 ms_warning("Could not write %s ! Maybe it is read-only. Configuration will not be saved.",lpconfig->filename);
884 lpconfig->readonly = TRUE;
885 return -1;
886 }
887
888 bctbx_list_for_each2(lpconfig->sections,(void (*)(void *,void*))lp_section_write,(void *)lpconfig);
889 bctbx_file_close(pFile);
890
891 #ifdef RENAME_REQUIRES_NONEXISTENT_NEW_PATH
892 /* On windows, rename() does not accept that the newpath is an existing file, while it is accepted on Unix.
893 * As a result, we are forced to first delete the linphonerc file, and then rename.*/
894 if (remove(lpconfig->filename)!=0){
895 ms_error("Cannot remove %s: %s",lpconfig->filename, strerror(errno));
896 }
897 #endif
898 if (rename(lpconfig->tmpfilename,lpconfig->filename)!=0){
899 ms_error("Cannot rename %s into %s: %s",lpconfig->tmpfilename,lpconfig->filename,strerror(errno));
900 }
901 lpconfig->modified = FALSE;
902 return 0;
903 }
904
linphone_config_has_section(const LpConfig * lpconfig,const char * section)905 int linphone_config_has_section(const LpConfig *lpconfig, const char *section){
906 if (linphone_config_find_section(lpconfig,section)!=NULL) return 1;
907 return 0;
908 }
909
linphone_config_for_each_section(const LpConfig * lpconfig,void (* callback)(const char * section,void * ctx),void * ctx)910 void linphone_config_for_each_section(const LpConfig *lpconfig, void (*callback)(const char *section, void *ctx), void *ctx) {
911 LpSection *sec;
912 bctbx_list_t *elem;
913 for (elem=lpconfig->sections;elem!=NULL;elem=bctbx_list_next(elem)){
914 sec=(LpSection*)elem->data;
915 callback(sec->name, ctx);
916 }
917 }
918
linphone_config_for_each_entry(const LpConfig * lpconfig,const char * section,void (* callback)(const char * entry,void * ctx),void * ctx)919 void linphone_config_for_each_entry(const LpConfig *lpconfig, const char *section, void (*callback)(const char *entry, void *ctx), void *ctx) {
920 LpItem *item;
921 bctbx_list_t *elem;
922 LpSection *sec=linphone_config_find_section(lpconfig,section);
923 if (sec!=NULL){
924 for (elem=sec->items;elem!=NULL;elem=bctbx_list_next(elem)){
925 item=(LpItem*)elem->data;
926 if (!item->is_comment)
927 callback(item->key, ctx);
928 }
929 }
930 }
931
linphone_config_clean_section(LpConfig * lpconfig,const char * section)932 void linphone_config_clean_section(LpConfig *lpconfig, const char *section){
933 LpSection *sec=linphone_config_find_section(lpconfig,section);
934 if (sec!=NULL){
935 linphone_config_remove_section(lpconfig,sec);
936 }
937 lpconfig->modified = TRUE;
938 }
939
linphone_config_needs_commit(const LpConfig * lpconfig)940 bool_t linphone_config_needs_commit(const LpConfig *lpconfig){
941 return lpconfig->modified;
942 }
943
944 static const char *DEFAULT_VALUES_SUFFIX = "_default_values";
945
linphone_config_get_default_int(const LpConfig * lpconfig,const char * section,const char * key,int default_value)946 int linphone_config_get_default_int(const LpConfig *lpconfig, const char *section, const char *key, int default_value) {
947 char default_section[MAX_LEN];
948 strcpy(default_section, section);
949 strcat(default_section, DEFAULT_VALUES_SUFFIX);
950
951 return linphone_config_get_int(lpconfig, default_section, key, default_value);
952 }
953
linphone_config_get_default_int64(const LpConfig * lpconfig,const char * section,const char * key,int64_t default_value)954 int64_t linphone_config_get_default_int64(const LpConfig *lpconfig, const char *section, const char *key, int64_t default_value) {
955 char default_section[MAX_LEN];
956 strcpy(default_section, section);
957 strcat(default_section, DEFAULT_VALUES_SUFFIX);
958
959 return linphone_config_get_int64(lpconfig, default_section, key, default_value);
960 }
961
linphone_config_get_default_float(const LpConfig * lpconfig,const char * section,const char * key,float default_value)962 float linphone_config_get_default_float(const LpConfig *lpconfig, const char *section, const char *key, float default_value) {
963 char default_section[MAX_LEN];
964 strcpy(default_section, section);
965 strcat(default_section, DEFAULT_VALUES_SUFFIX);
966
967 return linphone_config_get_float(lpconfig, default_section, key, default_value);
968 }
969
linphone_config_get_default_string(const LpConfig * lpconfig,const char * section,const char * key,const char * default_value)970 const char* linphone_config_get_default_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_value) {
971 char default_section[MAX_LEN];
972 strcpy(default_section, section);
973 strcat(default_section, DEFAULT_VALUES_SUFFIX);
974
975 return linphone_config_get_string(lpconfig, default_section, key, default_value);
976 }
977
978 /*
979 * WARNING: this function is very dangerous.
980 * Read carefuly the folowing notices:
981 * 1. The 'path' parameter may be modify by
982 * the function. Be care to keep a copy of
983 * the original string.
984 * 2. The return pointer may points on a part of
985 * 'path'. So, be care to not free the string
986 * pointed by 'path' before the last used of
987 * the returned pointer.
988 * 3. Do not feed it after midnight
989 */
_linphone_config_dirname(char * path)990 static const char *_linphone_config_dirname(char *path) {
991 #ifdef _MSC_VER
992 char drive[_MAX_DRIVE];
993 char dir[_MAX_DIR];
994 char fname[_MAX_FNAME];
995 char ext[_MAX_EXT];
996 static char dirname[_MAX_DRIVE + _MAX_DIR];
997 _splitpath(path, drive, dir, fname, ext);
998 snprintf(dirname, sizeof(dirname), "%s%s", drive, dir);
999 return dirname;
1000 #else
1001 return dirname(path);
1002 #endif
1003 }
1004
linphone_config_relative_file_exists(const LpConfig * lpconfig,const char * filename)1005 bool_t linphone_config_relative_file_exists(const LpConfig *lpconfig, const char *filename) {
1006 bctbx_vfs_file_t *pFile;
1007 if (lpconfig->filename == NULL) {
1008 return FALSE;
1009 } else {
1010 char *conf_path = ms_strdup(lpconfig->filename);
1011 const char *dir = _linphone_config_dirname(conf_path);
1012 char *filepath = ms_strdup_printf("%s/%s", dir, filename);
1013 char *realfilepath = lp_realpath(filepath, NULL);
1014
1015 ms_free(conf_path);
1016 ms_free(filepath);
1017
1018 if(realfilepath == NULL) return FALSE;
1019
1020 pFile = bctbx_file_open(lpconfig->g_bctbx_vfs,realfilepath, "r");
1021 ms_free(realfilepath);
1022 if (pFile != NULL) {
1023 bctbx_file_close(pFile);
1024 }
1025 return pFile != NULL;
1026 }
1027 }
1028
linphone_config_write_relative_file(const LpConfig * lpconfig,const char * filename,const char * data)1029 void linphone_config_write_relative_file(const LpConfig *lpconfig, const char *filename, const char *data) {
1030 char *dup_config_file = NULL;
1031 const char *dir = NULL;
1032 char *filepath = NULL;
1033 char *realfilepath = NULL;
1034 bctbx_vfs_file_t *pFile;
1035
1036 if (lpconfig->filename == NULL) return;
1037
1038 if(strlen(data) == 0) {
1039 ms_warning("%s has not been created because there is no data to write", filename);
1040 return;
1041 }
1042
1043 dup_config_file = ms_strdup(lpconfig->filename);
1044 dir = _linphone_config_dirname(dup_config_file);
1045 filepath = ms_strdup_printf("%s/%s", dir, filename);
1046 realfilepath = lp_realpath(filepath, NULL);
1047 if(realfilepath == NULL) {
1048 ms_error("Could not resolv %s: %s", filepath, strerror(errno));
1049 goto end;
1050 }
1051
1052 pFile = bctbx_file_open(lpconfig->g_bctbx_vfs,realfilepath, "w");
1053 if(pFile == NULL) {
1054 ms_error("Could not open %s for write", realfilepath);
1055 goto end;
1056 }
1057 bctbx_file_fprintf(pFile, 0, "%s",data);
1058 bctbx_file_close(pFile);
1059
1060 end:
1061 ms_free(dup_config_file);
1062 ms_free(filepath);
1063 if(realfilepath) ms_free(realfilepath);
1064 }
1065
linphone_config_read_relative_file(const LpConfig * lpconfig,const char * filename,char * data,size_t max_length)1066 LinphoneStatus linphone_config_read_relative_file(const LpConfig *lpconfig, const char *filename, char *data, size_t max_length) {
1067 char *dup_config_file = NULL;
1068 const char *dir = NULL;
1069 char *filepath = NULL;
1070 bctbx_vfs_file_t* pFile = NULL;
1071
1072 char* realfilepath = NULL;
1073
1074 if (lpconfig->filename == NULL) return -1;
1075
1076 dup_config_file = ms_strdup(lpconfig->filename);
1077 dir = _linphone_config_dirname(dup_config_file);
1078 filepath = ms_strdup_printf("%s/%s", dir, filename);
1079 realfilepath = lp_realpath(filepath, NULL);
1080 if(realfilepath == NULL) {
1081 ms_error("Could not resolv %s: %s", filepath, strerror(errno));
1082 goto err;
1083 }
1084
1085 pFile = bctbx_file_open(lpconfig->g_bctbx_vfs,realfilepath,"r");
1086 if (pFile == NULL) {
1087 ms_error("Could not open %s for read.", realfilepath);
1088 goto err;
1089 }
1090
1091 if(bctbx_file_read(pFile, data, 1, (off_t)max_length) < 0){
1092 ms_error("%s could not be loaded.", realfilepath);
1093 goto err;
1094
1095 }
1096
1097 bctbx_file_close(pFile);
1098
1099 ms_free(dup_config_file);
1100 ms_free(filepath);
1101 ms_free(realfilepath);
1102 return 0;
1103
1104 err:
1105 ms_free(dup_config_file);
1106 ms_free(filepath);
1107 if(realfilepath) ms_free(realfilepath);
1108 return -1;
1109 }
1110
linphone_config_get_sections_names(LpConfig * lpconfig)1111 const char** linphone_config_get_sections_names(LpConfig *lpconfig) {
1112 const char **sections_names;
1113 const bctbx_list_t *sections = lpconfig->sections;
1114 size_t ndev;
1115 int i;
1116
1117 ndev = bctbx_list_size(sections);
1118 sections_names = ms_malloc((ndev + 1) * sizeof(const char *));
1119
1120 for (i = 0; sections != NULL; sections = sections->next, i++) {
1121 LpSection *section = (LpSection *)sections->data;
1122 sections_names[i] = ms_strdup(section->name);
1123 }
1124
1125 sections_names[ndev] = NULL;
1126 return sections_names;
1127 }
1128
linphone_config_dump_as_xml(const LpConfig * lpconfig)1129 char* linphone_config_dump_as_xml(const LpConfig *lpconfig) {
1130 char *buffer;
1131
1132 lpc2xml_context *ctx = lpc2xml_context_new(NULL, NULL);
1133 lpc2xml_set_lpc(ctx, lpconfig);
1134 lpc2xml_convert_string(ctx, &buffer);
1135 lpc2xml_context_destroy(ctx);
1136
1137 return buffer;
1138 }
1139
1140 struct _entry_data {
1141 const LpConfig *conf;
1142 const char *section;
1143 char** buffer;
1144 };
1145
dump_entry(const char * entry,void * data)1146 static void dump_entry(const char *entry, void *data) {
1147 struct _entry_data *d = (struct _entry_data *) data;
1148 const char *value = linphone_config_get_string(d->conf, d->section, entry, "");
1149 *d->buffer = ms_strcat_printf(*d->buffer, "\t%s=%s\n", entry, value);
1150 }
1151
dump_section(const char * section,void * data)1152 static void dump_section(const char *section, void *data) {
1153 struct _entry_data *d = (struct _entry_data *) data;
1154 d->section = section;
1155 *d->buffer = ms_strcat_printf(*d->buffer, "[%s]\n", section);
1156 linphone_config_for_each_entry(d->conf, section, dump_entry, d);
1157 }
1158
linphone_config_dump(const LpConfig * lpconfig)1159 char* linphone_config_dump(const LpConfig *lpconfig) {
1160 char* buffer = NULL;
1161 struct _entry_data d = { lpconfig, NULL, &buffer };
1162 linphone_config_for_each_section(lpconfig, dump_section, &d);
1163
1164 return buffer;
1165 }
1166
linphone_config_clean_entry(LpConfig * lpconfig,const char * section,const char * key)1167 void linphone_config_clean_entry(LpConfig *lpconfig, const char *section, const char *key) {
1168 LpSection *sec;
1169 LpItem *item;
1170 sec=linphone_config_find_section(lpconfig,section);
1171 if (sec!=NULL){
1172 item=lp_section_find_item(sec,key);
1173 if (item!=NULL)
1174 lp_section_remove_item(sec,item);
1175 }
1176 return ;
1177 }
linphone_config_has_entry(const LpConfig * lpconfig,const char * section,const char * key)1178 int linphone_config_has_entry(const LpConfig *lpconfig, const char *section, const char *key) {
1179 LpSection *sec;
1180 sec=linphone_config_find_section(lpconfig,section);
1181 if (sec!=NULL){
1182 return lp_section_find_item(sec,key) != NULL;
1183 } else
1184 return FALSE;
1185
1186 }
1187
1188 BELLE_SIP_INSTANCIATE_VPTR(
1189 LinphoneConfig,
1190 belle_sip_object_t,
1191 _linphone_config_uninit, // uninit
1192 NULL, // copy
1193 NULL, // marshal
1194 FALSE
1195 );
1196