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